• Revista PROGRAMAR: Já está disponível a edição #53 da revista programar. Faz já o download aqui!

elcsat

ajuda assembly atmega48

31 mensagens neste tópico

ola, eu tenho o programa a trablhar para o atmega 128, mas agora tenho que o alterar para o 48, e tou com alguns problemas. se alguem me poder ajudar ficava grato.

aqui segue o codigo

.include<m48def.inc>

.cseg

.org 0

rjmp main

.org 0x6E

rjmp int_TC0

.org 0x46

inic:

ldi r17,0x01

ldi r19,100

ldi r16,77

out OCR1BH,r16

ldi r16,0b00001111

out TCNT0,r16

ldi r16,0x01

out DDRB,r16

out PORTB,r16

in r16,TIMSK0

ori r16,2

out TIMSK0,r16

sei

ret

int_TC0:

dec r19

breq led

rjmp fim

led:

ldi r16,0

out PORTB,r16

lsl r17

out DDRB,r17

ldi r19,100

rjmp fim

fim:

reti

main:

ldi r16,0x10

out SPH,r16

ldi r16,0xff

out SPL,r16

rcall inic

aqui:

rjmp aqui

tem alguns erros que me aprecem estes

C:\Users\santos\Documents\nuno.asm(1): Including file 'C:\Program Files\Atmel\AVR Tools\AvrAssembler2\Appnotes\m48def.inc'

C:\Users\santos\Documents\nuno.asm(14): error: Operand 1 out of range: 0x8b

C:\Users\santos\Documents\nuno.asm(22): error: Operand 2 out of range: 0x6e

C:\Users\santos\Documents\nuno.asm(24): error: Operand 1 out of range: 0x6e

C:\Users\santos\Documents\nuno.asm(56): No EEPROM data, deleting C:\Users\santos\Documents\nuno.eep

eu acho que é problema de endereços, que deviam ser diferentes.

:P:D

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

As intruções IN/OUT só funcionam com endereços até 63. Tens que trocar essas instruções por outras de acesso à memória, como LDS/STS.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

este programa e pra meter um led a piscar, so que quando meto um 0 na entrada do reset o led desliga completamente, eu tou agora no desktop e nao posso testar. mas amanha eu digote o que me acontece. se quiseres ate posso deixar aqui o esquema que desenhei para veres.

Tenho que fazer o led ta acesso 500ms e 500ms desligado

obrigada

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

É normal que o LED desligue quando fazes RESET ao microcontrolador. No reset ele configura os pinos todos como entradas.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

eu sei, mas eu nao vou fazer reset por software, é um esquema que desenhei que vai fazer o reset.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

codigo alterado

.include<m48def.inc>

.cseg

.org 0

rjmp main

.org 0x6e

rjmp int_TC0

.org 0x46

;*****ROTINA DE INICIALIZAÇÂO DO uC********

inic:

ldi r16,1;valor do contador

ldi r19,0

ldi r17, 0b00000010

ldi r18, 0b00000101

sts TCCR0A,r17; Modo 2 (CTC)

sts TCCR0B, r18; Modo 2,prescaler 1024

ldi r17,0b00000110

sts TIMSK0,r17; (autoriza interrupção do TC0)

ldi r17, 0b00000001

sts DDRB,r17; (bit 0 da PORTB como saida de dados)

ldi r17,53

sts OCR0A,r17

ldi r17,0b00000001

sts DDRB,r17; programa bit 0 do PORTB como saída de dado

;*********ROTINA DE INTERRUPÇÃO************

int_TC0:

dec r16 ;(decrementa o contador)

cpse r16,r19; compara r16 com r19. s forem iguais salta próx. instrução

rjmp fim_tc0

ldi r16,100

lds r20,PINB ;(lê valor lógico de PINB)

andi r20,0b00000001; operação "e"

cpse r20,r19

rjmp off

rjmp on

on:

ldi r18,0b00000000

sts PORTB,r18

rjmp fim_TC0

off:

ldi r18,0b00000001

sts PORTB,r18

rjmp fim_TC0

fim_TC0:

reti

;**********Programa principal**************

main:

ldi r16, 0x10

sts SPH, r16

ldi r16,0xff

sts SPL, r16

rcall inic

o programa ta compilar mas nao ta a trablhar como pretendido, o cristal que tou a usar é de 11,0952M, o contador corre sempre nao para e eu pretende 500ms acesso 500ms desligado

quando é para acender ou apagar o comando sts nao funciona, alguma sugestao

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Tens que colocar um loop infinito no final da main(), caso contrário ele não pára aí a execução e continua a executar pelo espaço de memória fora, até eventualmente dar a volta ao espaço de endereçamento e voltar ao endereço 0 e é como se estivesses a recomeçar o programa.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Não sabes o que é um loop (ciclo) infinito? É um ciclo vazio; não faz nada, a não ser "prender" a execução nesse ponto. Em assembly pode ser um salto incondicional para a própria instrução de salto, a colocar como última instrução da main().

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

sei o que é um loop infinito mas nao entendo a funcionalidade neste caso pra me resolver o problema, ja que o programa tem que ta sempre a correr, ora o portb ta activo ora ta desactivo, ora ta activo ora ta desactivo, por isso e que quando

chega ao fim faço rcall inic, e tou sempre a ver se ele ta on ou off para variar..

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Não vi o te programa com atenção, não sei de cor o que fazem os registos. Mas pareceu-me que estavas a fazer o toggle do LED na rotina de interrupção do timer, e que "inic" seria a rotina de "inicialização". Daí que depois de inicializar a interrupção do timer basta prender a execução do fio de execução principal com um loop infinito, e tudo o resto corre "em background" na rotina de interrupção. Mas agora estou a ver que tens aí outros problemas, como por exemplo não tens um ret no final da rotina inic, nem estás a habilitar as interrupções, ... explica lá que algoritmo é que pretendes implementar para fazer o LED piscar.

Uma boa ajuda é fazeres download do AVR Studio do site da ATMEL e simulares o programa; ficas logo a saber o que é que ele faz sem ter que o gravar no AVR e experimentar.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

ja consegui meter a trablhar, so que nao csg meter o ciclo para 500ms,

ao mudar o OCR0A o tempo k o bixo demora a fazer a rotina num muda e devia mudar

portanto isso do contador ,o TCCR0A e B e o OCR0 num ta bem d certeza

alguma sugestao?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

OCR0A não existe nesse AVR. O timer 0 limita-se a fazer o TCNT0 avançar e gerar uma interrupção quando faz overflow. Vê a datasheet.

Tens que configurar o prescaler,

habilitar a interrupção de overflow,

ligar os timers (se bem lembro há um bit que liga o "power" para os timers),

e depois na rotina de interrupção vais colocando o TCNT0 a um valor apropriado para a frequência que queres para as interrupções (ao meteres um valor X no TCNT0, ele já não vai contar de 0 a 255, vai contar de X a 255).

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
boa noite, sera que me podias ajudar é que tenho que entregar isso na terça feira a trablhar so que eu nunca trabalhei em atmega:(, e eu nao sei fazer isso que me tas a dizer. o programa atualmente ta assim

.include<m48def.inc>

.cseg

.org 0

  rjmp main

.org 0x00E

  rjmp int_TC0

.org 0x46

;*****ROTINA DE INICIALIZAÇÂO DO uC********

inic:

  ldi r16,200;valor do contador

  ldi r19,0

  ldi r17, 0b00000010

  ldi r18, 0b00000101

  sts TCCR0A,r17; Modo 2 (CTC)

  out TCCR0B, r18; Modo 2,prescaler 1024

    ldi r17,0b00000010

  sts TIMSK0,r17; (autoriza interrupção do TC0)

  ;ldi r17,TIMSK0

  ;ori r17,2

  ;sts TIMSK0,r17

  ldi r17, 0b00000000

  sts DDRB,r17; (bit 0 da PORTB como saida de dados)

  ldi r17,28

  out OCR0A,r17

  ldi r17,0b00000001

  sts DDRB,r17; programa bit 0 do PORTB como saída de dado

  ldi r17,0b00000000

  out PORTB,r17

  ;ldi r17,0b10000000

  ;out SREG,r17

  sei

  ret

 

  ;*********ROTINA DE INTERRUPÇÃO************

  int_TC0:

      dec r16 ;(decrementa o contador)

      cpse r16,r19; compara r16 com r19. s forem iguais salta próx. instrução

      rjmp fim_TC0

      ldi r16,100

      in r20,PORTB ;(lê valor lógico de PINB)

      andi r20,0b00000001; operação "e"

      cpse r20,r19

      rjmp off

      rjmp on

  on:

      ldi r18,0b00000001

      out PORTB,r18

      rjmp fim_TC0

  off:

      ldi r18,0b00000000

      out PORTB,r18

      rjmp fim_TC0

  fim_TC0:

      reti

;**********Programa principal**************

  main:

      ldi r16, 0x10

      sts SPH, r16

      ldi r16,0xff

      sts SPL, r16

      rcall inic

  aqui:

      rjmp aqui

podes-me fazer a alteraçao no programa.

se quiseres falar comigo no msn pdes adicionar xxxx@xxxxxxxxxx

desde ja agradeço pela ajuda.

cumps

Pelas razões óbvias não respondo a perguntas por email, muito menos quando são para trabalhos de casa.

Mesmo em assembly convém colocar o código com fonte monoespaçada, senão fica tudo meio esquisito.

Tens algumas coisas de base mal:

1) Estás a colocar a pilha num local inválido. O atmega48 tem menos RAM do que o 128. A maneira tradicional e correcta de inicializar o ponteiro da pilha é usando uma constante pré-definida do ficheiro "include", assim:

      ldi r16, HIGH(RAMEND)

      out SPH, r16

      ldi r16, LOW(RAMEND)

      out SPL, r16

HIGH e LOW dão-te, respectivamente, os bytes high e low do endereço (que é de 16 bits).

2) O sts/lds só pode ser usado para os registos que não podem ser acedidos por in/out. Se usares sts/lds para lidar com um registo que podes aceder com in/out, vais escrever outro local qualquer e não nos registos que queres. Por exemplo, não podes STS para escrever para TCCR0A; quando fazes isto, estás a escrever no DDRB. Isto tem a ver com os endereços das constantes dos nomes dos registos; com in/out, os endereços da área de registos começam em 0, com sts/lds eles começam em 32 (os endereços 0 a 31 é onde estão mapeados os registos do processador). Tens que mudar isso no teu código. No ficheiro m48def.inc está indicado quais são os registos que são "MEMORY MAPPED" (os únicos a usar com sts/lds) (também tens este problema ao inicializar a pilha, repara que o código exemplo que deixei está a usar out/in).

Quanto a não haver OCR0A eu estava enganado, vi na datasheet errada. Estava a olhar para a do ATmega8 a pensar que o ATmega48 era a versão "económica" deste, mas não é, o ATmega48 é a versão económica da geração seguinte (ATmega88). Portanto acho que fica igual, daqui para a frente já te deves safar.

Por fim, se tivesses usado o AVR Studio como te recomendei, tinhas logo detectado pelo menos metade destes problemas. Ainda vais a tempo de o instalar para correres simulações, é fácil, e consegues por o teu programa todo a funcionar sem teres que o gravar no AVR, e podes fazer debugging step-by-step no teu código, tudo em simulação.

Boa sorte!

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

eu desde do inicio tou a trablhar no avr studio 4, e o programa na primeira vez dava-me erros desde que tu dizeste para mudar para o lds e o sts porque o in e o out so funcionavam ate ao endereço 63, ele passou a compilar sem da nenhum erro :wallbash:

vou tentar da uma vista de olhos nisso, obrigada

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Se já estás a usar o AVR Studio óptimo, mas tens estado a usar a simulação ou estás a usá-lo só para assemblar?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

sim tenho estado a usar a  simulaçao, tou aqui por volta disto mas ainda nao conseguir meter em condiçoes

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

podes-me da uma dica como fazer sem usar interrupçoes em assembly??

e agora em c como se chama  intererrupçao a usar é esta ISR(TIMER0_COMP_vect)??

aqui segue o codigo em c

#include<io.h>
#include<interrupt.h>

unsigned char count=100;
unsigned char flag=0;

void inic(void)

{

DDRC=0b00000001;// programa bit 0 como saída de dados
PORTC=0b00000001;// apaga led
OCR0A=53;
//OCR0B=53;
TCCR0A=0b00000010; //modo 2 (CTC)
TCCR0B=0b00000101; //prescaler 1024
TIMSK0=0b00000010; //autoriza interrupção do contador
SREG=0b10000000;
TIFR0=0b00000111;
}

//**********************Rotina de interrupção*********************


ISR(TIMER0_COMP_vect)
{

count--;
if(count==0)

	{
		count=100;
		flag=1;
	}
}



void main(void)
{

inic();

while(1)


{
	while(flag==0); //fica aqui parado até count=0 =>flag=1

	if(PORTC==0b00000000)
		{

			PORTC=0b00000001;//apaga o led
			flag=0;
		}


	else
		{

			PORTC=0b00000000;//acende o led
			flag=0;
		}
}
}

se poderes da uma vista de olhos e da a tua opniao.

e desde ja obrigado as tuas dicas tem sido muito uteis.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Sem usar interrupções tens que fazer uma rotina "delay", é só um ciclo que "queima tempo" sem fazer nada até que passe o tempo desejado (isto é sem usar o timer). Se queres usar o timer mas sem interrupções, então fazes a configuração toda como já tens mas não habilitas as interrupções no CPU; a flag OCF0A (output compare match) é actualizada à mesma. Portanto basta-te carregar o TCNT0 com zero, limpar a flag OCF0A (no TIFR0, similar ao que já tás a fazer na inic()) e depois fazer um loop à espera que ela levante (o que indica que TCNT0 "deu a volta"). Colocas isto numa rotina à parte e passa a ser a tua função "delay". O mesmo pode ser feito em C.

Em C, supondo que estejas a usar o GCC-AVR, tens no util/delay.h funções para fazer delays em us ou ms (lê a descrição das funções). Consulta o avr-libc-user-manual, vem com o WINAVR (ele cria links no desktop quando é instalado). Na documentação do include avr/interrupt.h tens a lista dos nomes das interrupções e os AVRs que são suportados. Para o teu caso, as que podem ser de interesse são

TIMER0_COMPA_vect TimerCounter0 Compare Match A

TIMER0_COMPB_vect Timer Counter 0 Compare Match B

TIMER0_OVF_vect   Timer/Counter0 Overflow

TIMER0_COMP_vect é para o mega128, o equivalente para o teu caso no mega48 será o TIMER0_COMPA_vect.

No avr-gcc tens a função sei() para habilitar interrupções, cli() para deshabilitar.

Neste meu tutorial tens um exemplo em C que pisca um LED, usando delays.

http://embeddeddreams.com/site/2008/10/05/starting-up-programming-avr-microcontrollers/

O código como está escrito funciona praticamente em qualquer AVR, mas há um detalhe: a função _delay_ms() só consegue fazer delays até 262.14ms / freq-cpu-em-MHz. Como tens o teu a mais de 11MHz (digamos 12 MHz), terias que invocar vários delays de 262.14/12~21.8ms até fazer 500ms. Isto está escrito na documentação da libc.

Mais uma dica, da datasheet: The PRTIM0 bit in “Minimizing Power Consumption” on page 42 must be written to zero to enable Timer/Counter0 module.

Quanto à temporização em si, para chegares aos 500ms com o timer tens que perceber como é que ele funciona e depois fazer umas contas, tendo em conta a frequência de sistema (11.092MHz como referiste). Como estás a colocar 53 no OCR0A, e há uma interrupção "compare match A" quando TCNT0 vai a zero depois de ter atingido OCR0A (no modo CTC, o TCNT0 é zerado no "timer clock" (= F_CPU / PRESCALER) seguinte a ter atingido o valor em OCR0A, ou seja, conta de 0 a OCR0A inclusivé, volta a zero e repete ciclicamente), tens uma interrupção periódica com uma frequência de F_CPU / PRESCALER / (OCR0A+1). No teu caso, 11092000 / 1024 / (53+1) ~ 200.59Hz (só li os teus comentários no código, não verifiquei se os campos dos registos estão a ser bem escritos). Como na interrupção estás a contar até 100, que a ~200Hz é o mesmo que esperar ~500ms, parece-me estar bem.

Não sei se sabes, mas também podes simular programas compilados em C com o AVR Studio, basta-te abrir o ficheiro .ELF no AVR Studio. Ele permite-te fazer debug step-by-step ao nível do código C.

Boa sorte!

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Não sei, mas diz lá que é suportado no AVR Studio, portanto é ligá-lo ao PC e depois ir a Tools -> Program AVR -> Connect, escolher lá o programador e depois há lá outras opções para gravar o programa (program flash).

Mas não tou a perceber, isso é um trabalho pá escola e não te ensinaram a fazer isso? É que se é a 1ª vez que tás a fazer isso vais ter outros problemas. Se o AVR é "virgem", tens que lhe programar os "fuses" para usar um cristal ou clock externos. Depois tens também que fazer uma montagem com o AVR, o cristal e 2 condensadores ou, se a usar clock externo, esse clock tem que vir de algum lado. Isto tá-me a parecer muito estranho...

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!


Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.


Entrar Agora