collapse

* Links de Robótica

* Posts Recentes

Recomendação de um opamp para um DAC r2r por jm_araujo
[Hoje às 10:48]


Feira de electricidade e eletrónica por beirao
[Hoje às 00:32]


RN42 e TP-Link MR3020 por doiga
[Ontem às 19:22]


Ajuda Projecto IR / RF por senso
[Ontem às 13:15]


Ideias para construir um quadrúpede simples por dropes
[21 de Novembro de 2017, 22:43]


Ajuda com TRIAC por senso
[17 de Novembro de 2017, 18:00]


TV LG White Screen por almamater
[15 de Novembro de 2017, 08:37]


Pergunta sobre prototipagem ( Pesquisa ) por luisjustin
[14 de Novembro de 2017, 23:22]


Medir Agua que está no Poço por Njay
[14 de Novembro de 2017, 13:28]


Amplificador audio por beirao
[12 de Novembro de 2017, 23:43]

Autor Tópico: Duvidas AVR-GCC  (Lida 1266 vezes)

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

Offline c3dr1c

  • Mini Robot
  • *
  • Mensagens: 847
Duvidas AVR-GCC
« em: 19 de Janeiro de 2013, 21:17 »
Boas.
Criei este topico para expor as minhas duvidas de principiante.

Ando a estudar alguns tutoriais que encontro por ai e ja entendo algumas coisas, mas poucas :P
O que ando a fazer encontrei-o aqui: http://netexplorers.org/AVR/AVR_C.pdf
Da autoria do Senso, do Cynary e do Njay

Agora experimentei este programa mas nao entendo certas coisas...

Código: [Seleccione]
#include <avr/io.h> // Iniciar o programa
#include <avr/interrupt.h>

char output = 0; // Estado do led.

int main(void) {

DDRD |= (1<<PD4); // Inicializar o pino digital 4 como output.

PORTD &= ~(1<<PD4); // Inicializar o pino digital 4 como desligado.

EICRA |= ((1<<ISC00) | (1<<ISC01)); // Configurar interrupção no pino INT0 para quando este transita para HIGH
EIMSK |= (1<<INT0); // Ligar interrupções particulares
sei();
for(;;);
}

ISR(INT0_vect) { // Definir o que fazer quando acontece esta interrupção

output = ~output; // Alterar o estado

PORTD &= ~(1<<PD4); // Desligar o pino, isto é necessário para quando o output é 0 se poder desligar.

PORTD |= ((output&1)<<PD4); // output&1 pois só nos interessa o primeiro bit, assim evitamos mexer nos outros pinos.

}


Segundo o que percebi o programa dentro do main corre infinitamente ate ocorrer uma interrupção. Quando é interrompido corre uma vez o ISR e depois volta a correr o main. É isto?

Agora nao entendo isto:
Código: [Seleccione]
PORTD &= ~(1<<PD4); // Inicializar o pino digital 4 como desligado.Assim sempre que fizesse um ciclo nao deveria meter a saida digital a 0? E sendo assim quando houvesse a interrupção e mudasse o estado para 1, ele voltaria de novo a 0?

Código: [Seleccione]
PORTD &= ~(1<<PD4); // Desligar o pino, isto é necessário para quando o output é 0 se poder desligar.Desligar o que? Se é 0 porque se tem de desligar?

Cumps
« Última modificação: 19 de Janeiro de 2013, 21:21 por c3dr1c »
"O único modo de descobrir os limites do possivel é aventurarmo-nos um pouco para além deles em direcção ao impossivel."

Uma das Três Leis de Arthur C. Clarke

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.141
    • Tróniquices
Re: Duvidas AVR-GCC
« Responder #1 em: 20 de Janeiro de 2013, 02:52 »
Nope cedric. Não entendeste bem o que é uma interrupção. Quando o chip arranca, a execução chega à main() que é executada até chegar ao fim; no fim, temos

for (;; );

Esta instrução acima é um ciclo infinito. Portanto o CPU fica ali "às voltas" sem sair do mesmo sítio. A função main() na prática nunca termina, a execução não sai de lá (do ciclo infinito). Se formos ver o código assembly deste for(;; );, é algo do género disto:

ciclo:
   jmp  ciclo

O CPU executa uma instrução de salto (jmp = jump) para o endereço da própria instrução, daí que a execução nunca mais sai dali. É dificil tentar explicar isto sem saber exactamente qual é o teu nível de conhecimentos em programação.

Agora as interrupções. Quando ocorre uma interrupção, o CPU pára o que está a fazer e faz uma chamada (subrotina) à rotina de interrupção. O que é que quer dizer "pára o que está a fazer?" Quer dizer que, quando o CPU detecta que há uma interrupção "a pedir para correr", ele não executa a próxima instrução que ia executar e em vez disso salta para rotina de interrupção, executa-a, e no final volta ao "código anterior" e continua a execução no ponto onde tinha ficado, como se nada tivesse acontecido. O CPU verifica se há interrupções para correr após cada instrução que executa (cada instrução máquina, e não cada instrução C).
Imagina que o CPU está a executar a seguinte função

void f ()
{
    a = 0;
    b = 1;
}

e que durante a execução da instrução a = 0; fica pronta para correr a interrupção

ISR(...)
{
    c = 2;
}

O que acontece é que a execução do CPU vai ser

a = 0;
    c = 2;     (dentro da interrupção)
b = 1;


Ou seja, quando há uma interrupção o CPU não pára de executar uma função, invoca a interrupção e volta ao inicio da função que estava a executar antes da interrupção; o que acontece é que o CPU pára a instrução que estava a executar, invoca a interrupção, e depois continua a executar a instrução que iria executar se a interrupção nunca tivesse ocorrido. O código que é interrompido nunca dá pela interrupção, é como se nada se tivesse passado.
Repara que a interrupção poderia pedir para correr em qualquer ponto da execução da função. Outros cenários possíveis seriam:

    c = 2;     (dentro da interrupção)
a = 0;
b = 1;

ou

a = 0;
b = 1;
    c = 2;     (dentro da interrupção)


Em geral não sabemos em que ponto do código é que uma interrupção vai ocorrer, pode ser em qualquer altura (desde que as interrupções estejam habilitadas).
Deu para entender melhor assim?
« Última modificação: 20 de Janeiro de 2013, 02:57 por Njay »

Offline c3dr1c

  • Mini Robot
  • *
  • Mensagens: 847
Re: Duvidas AVR-GCC
« Responder #2 em: 20 de Janeiro de 2013, 15:39 »
Ah ja entendi, acho eu  ;D

Ele corre o que está dentro do main e depois ao chegar ao for(;; ) fica la dentro. Como nao existe nenhuma condição de saida o programa fica sempre ali. La dentro quando ocorre a interrupção, ele faz toggle à saida 4 e volta ao for(;; ), certo?

Sendo assim ja percebo o uso disto para inicializar o pino 4 desligado :D
Código: [Seleccione]
PORTD &= ~(1<<PD4); // Inicializar o pino digital 4 como desligado.

Agora dentro da interrupção nao percebo isto na mesma:
Código: [Seleccione]
PORTD &= ~(1<<PD4); // Desligar o pino, isto é necessário para quando o output é 0 se poder desligar.
Então ele primeiro inverte o "output", depois desliga o pino e depois atribui o "output", ao bit de ligar/desligar o pino, do register PORTD.
 
Porque tem de ser assim? Porque tem de se desligar sempre o pino? Se o output  = 0 depois a ultima instrução nao atribui esse zero ao bit PD4 e desliga o pino?

Ou é devido à manipulação de bit's com |=, &=??


O meu nivel de programação é baixo... Sei labview, simatic step7,... que é tudo diferente disto :P
Quando era mais novo aprendi alguma coisa de pascal e fortran. Nem arduino sei.
Mas agora tou decidido aprender programar micros avr e há-de ser como deve de ser, em avr-gcc :D

Muito obrigado
Cumps
« Última modificação: 20 de Janeiro de 2013, 16:02 por c3dr1c »
"O único modo de descobrir os limites do possivel é aventurarmo-nos um pouco para além deles em direcção ao impossivel."

Uma das Três Leis de Arthur C. Clarke

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.141
    • Tróniquices
Re: Duvidas AVR-GCC
« Responder #3 em: 20 de Janeiro de 2013, 17:21 »
Essa forma de actuar n ovalor do pino foi apenas a técnica usada. Na verdade realmente estão a meter o pino a zero antes e depois metem a 1 se for para ficar a 1. É que a operação & só mete bits a zero e a operação | só mete bits a 1.
Há outras formas de fazer o mesmo sem fazer 2 escritas para o pino, sem causar "glitches", como por exemplo

PORTD = (PORTD & ~_BV(PD4)) | (output & _BV(PD4));

Se apenas queremos inverter o estado do pino, podemos ainda fazer uma destas 2

PORTD ^= _BV(PD4);

// isto funciona nos AVR de 3ª geração como o ATmega168/328 e
// é a forma mais rápida de inverter o estado de um pino num AVR:

PIND = _BV(PD4);

É uma questão de ganhar familiaridade com as operações "bitwise" e conhecer o sistema para o qual se está a programar.
« Última modificação: 20 de Janeiro de 2013, 17:24 por Njay »

Offline c3dr1c

  • Mini Robot
  • *
  • Mensagens: 847
Re: Duvidas AVR-GCC
« Responder #4 em: 20 de Janeiro de 2013, 19:28 »
Eu por acaso tinha experimentado algo parecido, mas o led ficou a piscar mt rapido

Código: [Seleccione]
#include <avr/io.h> // Iniciar o programa
#define F_CPU 16000000UL
#include <avr/interrupt.h>

int main(void) {

DDRD |= (1<<PD4); // Inicializar o pino digital 4 como output.
PORTD &= ~(1<<PD4); // Inicializar o pino digital 4 como desligado.
EICRA |= ((1<<ISC00) | (1<<ISC01)); // Configurar interrupção no pino INT0 para quando este transita para HIGH
EIMSK |= (1<<INT0); // Ligar interrupções particulares
sei();
for(;;);
}

ISR(INT0_vect) { // Definir o que fazer quando acontece esta interrupção
PORTD ^= (1<<PD4); // Fazer toggle do pino digital 4
}

Qual a diferença do PORTD ^=_BV(PD4) - que configura o pino como saida -  para o PORTD ^=(1<<PD4) - que faz o mesmo, penso eu.

Eu conheço os operadores logicos e codigo binario. Eu tive electronica digital no curso. Se calhar tenho de começar a olhar para isto como binário, não?
"O único modo de descobrir os limites do possivel é aventurarmo-nos um pouco para além deles em direcção ao impossivel."

Uma das Três Leis de Arthur C. Clarke

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.141
    • Tróniquices
Re: Duvidas AVR-GCC
« Responder #5 em: 20 de Janeiro de 2013, 19:39 »
DDRD |= _BV(PD4) é que configura o pino (PD4) como saída.
PORTD ^= _BV(PD4) inverte o estado do bit 4 (o pino PD4), desde que ele esteja configurado como saída, claro.

Eu prefiro usar _BV(x) do que (1<<x).

Em C lidamos mais com bytes e respectivos múltiplos, mas estamos nestas instruções a manipular bits individuais.
« Última modificação: 20 de Janeiro de 2013, 19:44 por Njay »

Offline c3dr1c

  • Mini Robot
  • *
  • Mensagens: 847
Re: Duvidas AVR-GCC
« Responder #6 em: 20 de Janeiro de 2013, 20:47 »
Enganei-me, queria dizer que inverte a saida  :P

Thanks

"O único modo de descobrir os limites do possivel é aventurarmo-nos um pouco para além deles em direcção ao impossivel."

Uma das Três Leis de Arthur C. Clarke