collapse

* Posts Recentes

O que é isto ? por SerraCabo
[12 de Abril de 2024, 14:20]


Amplificador - Rockboard HA 1 In-Ear por almamater
[11 de Abril de 2024, 20:46]


Emulador NES em ESP32 por dropes
[10 de Abril de 2024, 15:30]


Meu novo robô por josecarlos
[29 de Março de 2024, 18:30]


Bateria - Portátil por almamater
[25 de Março de 2024, 22:14]


Escolher Osciloscópio por jm_araujo
[06 de Fevereiro de 2024, 23:07]


TP4056 - Dúvida por dropes
[31 de Janeiro de 2024, 14:13]


Leitura de dados por Porta Serie por jm_araujo
[22 de Janeiro de 2024, 14:00]


Distancia Cabo por jm_araujo
[08 de Janeiro de 2024, 16:30]


Laser Engraver - Alguém tem? por almamater
[16 de Dezembro de 2023, 14:23]

Autor Tópico: Blink led com Atmega88  (Lida 4117 vezes)

0 Membros e 1 Visitante estão a ver este tópico.

Offline DLM

  • Mini Robot
  • *
  • Mensagens: 115
Blink led com Atmega88
« em: 16 de Abril de 2013, 12:08 »
Boas!
Ando aqui a testar o atmega88 para o meu futuro projeto mas não estou a conseguir fazer funcionar um programa aparentemente simples.
O led acende mas não pisca como deveria de meio em meio segundo.
Não sei se terá a haver com os fuses porque não sei como estão configurados mas à partida a velocidade será de 1Mhz. Também testei substituir na primeira linha de código por 8Mhz o resultado foi o mesmo, acende mas não pisca.
Terei a fazer alguma coisa de mal?
Aqui fica o programa:
Código: [Seleccione]
#define F_CPU 1000000UL

#include<stdio.h>
#include<avr/interrupt.h>
#include<avr/io.h>
unsigned char flag_int=1, flag_500=100;

void inic(void)
{
DDRC=4;
PORTC=4;

TCCR0A=0b00000010;
TCCR0B=0b00000011;
OCR0A=77;
SREG|=0x80;
TIMSK0=2;
}

ISR(TIMER0_COMPA_vect)
{
flag_500--;
if(flag_500==0)
{
flag_int =0;
flag_500=100;
}
}
int main(void)
{
inic();
while(1)
{
if (flag_int ==0)
{
flag_int =1;
if(PORTC==4)
PORTC=0;
if(PORTC==0)
PORTC=4;
}
}
return 0;
}

Tenho ligada uma resistência de 220ohm ao pino PC2 (não tenho a certeza que seja o correto) e o led ligado entre a resistência e a massa, ele acende portanto à partida está bem ligado.
Alguma ajuda?
« Última modificação: 16 de Abril de 2013, 15:25 por DLM »

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.598
    • Tróniquices
Re: Blink led com Atmega88
« Responder #1 em: 16 de Abril de 2013, 15:14 »
> void inic(void)
> {
>    DDRC=4;
>    PORTC=4;

Isto não se usa pá. Assim é que é:

// Definir o PC2 como saída
DDRC = _BV(PC2);
// Meter o PC2 a high
PORTC = _BV(PC2);


Se tivesses feito assim nem tinhas nenhuma dúvida sobre o pino, tá ali escrito, é o PC2.

>    TCCR0A=0b00000010;
>    TCCR0B=0b00000011;

E isto? Alguém aqui sabe converter binário para bits de registo de cabeça? Feito de forma a facilitar a leitura é algo do género

TCCR0A = _BV(...) |           // prescaler a x vezes
         _BV(...)             // blá blá
         ...


>    OCR0A=77;

Nem um comentáriozinho sobre o porquê do 77?

>    SREG|=0x80;

Qué isto? Queres obrigar a malta a ir consultar a datasheet só para perceber que estás a habilitar as interrupções (é o que me parece assim de cabeça)? É para isso que existe isto:

sei();     // habilitar as interrupções

>    TIMSK0=2;

Outra vez números sem significado? Nem comentários? Mas alguém aqui pensa em números? Assim fica dificil ajudar-te, eu olho prái e só vejo chinês. Olha, faz uma simulação que ficas a perceber o que se passa.

Mais logo já meto aí um exemplo "como deve ser".

Offline DLM

  • Mini Robot
  • *
  • Mensagens: 115
Re: Blink led com Atmega88
« Responder #2 em: 16 de Abril de 2013, 15:19 »
Tens razão Njay foi falha minha mesmo.
Fica aqui então o código comentado (sem as tuas correções ainda):
Código: [Seleccione]
#define F_CPU 1000000UL

#include<stdio.h>
#include<avr/interrupt.h>
#include<avr/io.h>
unsigned char flag_int=1,flag_500=100;
void inic(void)
{
DDRC=4; // Coloca o Pino 2 do Porto C como saida
PORTC=4; // Coloca led pino 2,ON
TCCR0A=0b00000010; // CTC, Normal port operation, OC0A disconnected
TCCR0B=0b00000011; //Modo CTC, presclare=64, interrupção gerada de 5 em 5ms
OCR0A=77; //OCRO=78.125-1=77, ficando T=10ms e f=100hz
SREG|=0x80; //Activa as interrupções globais, coloca a 1 o bit 7 de SREG
TIMSK0=2; //Activa a interrupção do TC0
}
ISR(TIMER0_COMPA_vect) //funçao predefinida para Interrupção do TC0compare
{ match A
flag_500--; //Decrementa a variavel
if(flag_500==0) //Condição, se for igual a zero executa o codigo
{
flag_int =0; //Coloca a variavel flag_int a 0, atraso de 500ms verificado
flag_500=100; //Recarrega a variavel com o valor
} // 100, 100*5ms=500ms
}
int main(void) //Função principal do programa
{
inic(); //Chama a funçao inic
while(1) //Ciclo infinito
{
if (flag_int ==0) //Testa flag_int. Se for igual a 0, entao já ocorreu o
{ // atraso de 500ms
flag_int =1; //Coloca a variavel flag_int =1
if(PORTC==4) //Testa se LED esta on
PORTC=0; //Se estiver, desliga
if(PORTC==0)
PORTC=4; //Se nao estiver, liga
}
}
return 0;
}
« Última modificação: 16 de Abril de 2013, 15:26 por DLM »

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.598
    • Tróniquices
Re: Blink led com Atmega88
« Responder #3 em: 16 de Abril de 2013, 15:25 »
Nossa, o que é que aconteceu à indentação? Esses registos TCC só com o binário também não ajudam grande coisa, fica mais dificil verificar se os bits certos estão a ser activados.

De qualquer forma o teu problema deve ser porque não declaraste como "volatile" as variáveis que usas simultaneamente dentro e fora da interrupção.

Offline DLM

  • Mini Robot
  • *
  • Mensagens: 115
Re: Blink led com Atmega88
« Responder #4 em: 16 de Abril de 2013, 15:31 »
Também não percebi o que aconteceu vou tentar corrigir.

> void inic(void)
> {
>    DDRC=4;
>    PORTC=4;

Isto não se usa pá. Assim é que é:

// Definir o PC2 como saída
DDRC = _BV(PC2);
// Meter o PC2 a high
PORTC = _BV(PC2);


Se tivesses feito assim nem tinhas nenhuma dúvida sobre o pino, tá ali escrito, é o PC2.
Seguindo este principio como ficaria quando quisesse desligar o led? Não conhecia esta definição, estou agora a começar  ;D

Vou também experimentar declarar as variáveis como volatile, embora ele não apresente erros assim e o led realmente acende, só não pisca.

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.598
    • Tróniquices
Re: Blink led com Atmega88
« Responder #5 em: 16 de Abril de 2013, 15:42 »
Para desligar o LED fazes

PORTC &= ~_BV(PC2);     // mete a zero o bit correspondente ao PC2

Tudo isto tem a ver com operações de bits, procura por aí que há muita coisa na net sobre isto (aqui no fórum também).

Se não usares "volatile" da declaração dessas variáveis, o compilador optimiza o código colocando-as em registos do CPU. No ciclo principal apenas o registo é consultado, por isso o ciclo "não vê" a alteraçao efectuada ao valor da variável pela interrupção, pois essa alteração é efectuada na memória. Não sei se me tou a fazer entender. O "volatile" apenas diz ao compilador para não fazer optimizações que possam levar a que alterações à variável possam não ser vistas por todo o programa, ou seja, todos os acessos que o compilador gerar à variável vão sempre à memória.

O compilador faz este tipo de optimização porque aceder à variável em memória demora o dobro do tempo face a aceder a ela num registo (nos AVR é o dobro do tempo, noutras arquitecturas pode ser mais).
« Última modificação: 16 de Abril de 2013, 15:44 por Njay »

StarRider

  • Visitante
Re: Blink led com Atmega88
« Responder #6 em: 16 de Abril de 2013, 18:21 »
Para desligar o LED fazes

PORTC &= ~_BV(PC2);     // mete a zero o bit correspondente ao PC2


Onde ? Como ? Quando ? Porque ?

Esse _BV(xpto) é o que ? Um define ? Uma func ? Em que compilador ? Em que toolchain ?

Desculpa que te diga mas o código do DLM é MUITO mais legível e TOTALMENTE portável ... simplesmente porque
é "arduino free", e isso É MUITO bom ;)

Tanto quanto percebi este tópico era mesmo sobre AVR (aleluia !!) e não sobre o tal "arduino", e já agora aproveito
para lançar uma critica (no bom sentido claro) sobre o facto de terem criado uma pasta conjunta "Arduino / AVR", que
leva a estas confusões.

Abraços,
PA
« Última modificação: 16 de Abril de 2013, 18:24 por StarRider »

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.598
    • Tróniquices
Re: Blink led com Atmega88
« Responder #7 em: 16 de Abril de 2013, 18:36 »
Em GCC para AVR, é o mais usado em hobby e não só, uma vez que não é pago nem limitado e suportado pela própria ATMEL.

Quanto ao mais legível, discordo fortemente :)

E quanto à portabilidade... é muito discutivel neste contexto.

Onde ? Como ? Quando ? Porque ?

Esse _BV(xpto) é o que ? Um define ? Uma func ? Em que compilador ? Em que toolchain ?
« Última modificação: 16 de Abril de 2013, 18:43 por Njay »