collapse

* Posts Recentes

Emulador NES em ESP32 por dropes
[22 de Abril de 2024, 14:14]


Arame de Estendal por almamater
[18 de Abril de 2024, 16:16]


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]


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]

Autor Tópico: Introdução ao avr-gcc usando o AvrStudio [Mais timers/mood light]  (Lida 116638 vezes)

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

Offline Cynary

  • Mini Robot
  • *
  • Mensagens: 182
Re: Introdução ao avr-gcc usando o AvrStudio [Quinta parte - Conversor ADC]
« Responder #105 em: 06 de Fevereiro de 2011, 20:17 »
Desculpa a ignorância mas o que é uma ISR?

Uma ISR é uma interrupt service routine.
Basicamente é uma função que é accionada quando uma interrupção ocorre.
Se não sabes o que é uma ISR, vou assumir que não sabes ainda trabalhar com interrupções ...
Por isso anexo aqui um guia em PDF que escrevi (tenho isto num servidor, mas neste momento esse servidor está em baixo :/ deve voltar amanhã ou depois).

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Re: Introdução ao avr-gcc usando o AvrStudio [Quinta parte - Conversor ADC]
« Responder #106 em: 06 de Fevereiro de 2011, 22:30 »
É isso mesmo, podes sempre procurar no google que felizmente coisa que não falta são bons tutoriais sobre AVR e programação dos mesmos.
Avr fanboy

Offline SJD22

  • Mini Robot
  • *
  • Mensagens: 660
Re: Introdução ao avr-gcc usando o AvrStudio [Quinta parte - Conversor ADC]
« Responder #107 em: 06 de Fevereiro de 2011, 22:53 »
Obrigado.

Já agora, a função que o senso colocou no tutorial dos USART recebe apenas um char. Ou seja, para receber uma string por exemplo teria de invocar mais vezes a função receive?

Basicamente eu quero receber tudo o que o outro dispositivo tem para me dar...

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Re: Introdução ao avr-gcc usando o AvrStudio [Quinta parte - Conversor ADC]
« Responder #108 em: 06 de Fevereiro de 2011, 23:04 »
Recebes sempre char a char, ou seja 8 bits de cada vez, a melhor maneira de fazer isso é com um buffer circular, digamos de 64 caracteres, ou 32 conforme o teu main loop, e meter a recepção por interrupção tambem, assim não estás a fazer polling á recepção.
Avr fanboy

Offline souza_neto

  • Mini Robot
  • *
  • Mensagens: 7
Re: Introdução ao avr-gcc usando o AvrStudio [Quinta parte - Conversor ADC]
« Responder #109 em: 27 de Janeiro de 2012, 06:37 »
Cumprimento a todos,

Gostaria de lhes falar o seguinte. A algum tempo aqui no Brasil, antes de conhecer o LR eu comprei um livro: "Tecnicas de Projetos Eletronicos com os Microcontroladores AVR" Autor: Charles Borges de Lima. E me decepcionei com o livro. Para que tenham uma ideia, o livro na verdade deveria ter outro titulo: Exercicios Avancados Sobre AVR, porque digo isso. O autor nao usa de didatica, o livro é indicado para quem ja tem um bom e muito bom conhecimento tanto da linguagem C como do microAVR. No livro autor escreve varias macros usando operacoes logicas Bitwise, nao explica ou ensina como entende-las, isso é o minimo. Quando vai abordar um determinado assunto por exemplo, como fazer um bubo de led, um painel de mensagem eletronicas, protocolos de comunicacao etc, ele fala sobre o que é, quase nao tem exemplo e quando tem é bem generico e nao faz sentido pra quem esta aprendendo (iniciante) mas isso no prefacio nao foi dito. Em seguinda é pedido atraves de exercicios para executar varias tarefas que acredito que nem mesmo o auto consiga realiza-las. Ai depois eu encontrei o LR e a coisa mudou, os tutoriais do Senso realmente ensinam, quem nao tem nenhum conhecimento, se ler com calma ler novamente realmente aprende, principalmente sobre operacoes logicas Bitwise. Se os devidos autores dos tutoriais juntassem  todos esses tutoriais de forma bem organizada e distribuida daria um excelente bestseler, principalmente aqui para nos brasileiros que temos muita carencia em literatura sobre AVR em lingua portuguesa.

Fica ai o meu alerta sobre o livrinho, nao indico a ninguem.

E quanto aos tutoriais aqui do LR se estudar por eles aprende com certeza.

Att,

Ate uma proxima.

 
Disse Jesus: Eu sou o caminho, e a verdade e a vida. Ninguém vem ao pai, senão por mim.

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Re: Introdução ao avr-gcc usando o AvrStudio [Quinta parte - Conversor ADC]
« Responder #110 em: 27 de Janeiro de 2012, 14:23 »
Obrigado pelo comentário, ver se para a semana escrevo mais um ou dois tutoriais que sito ficou assim meio parado no tempo.
Avr fanboy

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Re: Introdução ao avr-gcc usando o AvrStudio [Quinta parte - Conversor ADC]
« Responder #111 em: 31 de Janeiro de 2012, 02:12 »
Boas noites caros colegas, hoje vamos iniciar o primeiro de três tutoriais sobre timers e o que podemos fazer com eles. Os timers têm diversos modos de operação, os 4 principais podem-se considerar como o modo normal em que funcionam como um simples contador que pode gerar interrupções, CTC(clear timer on compare match), fast pwm e phase correct pwm. No atmega328p e em quase todos os atmegas mais comuns temos acesso a 3 timers, 2 deles são de 8 bits e 1 é de 16 bits, e têm sub-modos/opções de funcionamento extra que os distinguem uns dos outros. Todos os timers têm associados a si 3 registos, TOP, BOTTOM e MAX, que podemos usar por exemplo para alterar o duty cycle quando estamos em modo pwm. TOP define o valor máximo até onde o timer pode contar, pode ser o máximo suportado pelo timer ( 255 para um timer de 8 bits ou 65535 para um timer de 16 bits) ou um valor definido pelo utilizador, BOTTOM é o valor mínimo que tipicamente é zero, existem aplicações em que é vantajoso alterar o BOTTOM mas são raras e é algo que não vou usar em nenhum destes timers e MAX é sempre o valor máximo até onde o timer pode contar.

Nesta primeira parte vamos falar apenas em usar o timer no modo normal e no modo CTC, a segunda parte será sobe um dos modos de pwm e controlar o brilho de uns quantos leds e terceiro será sobre phase correct pwm e controlo de motores.

Vamos então começar pelo modo normal e fazer mais um blinky deste vez baseado em timers e não com delays como o _delay_ms(), como estamos a usar timers temos primeiro de fazer algumas contas para fazer o setup dos mesmo para que contem o tempo que queremos. Este primeiro exemplo nem sequer vai usar interrupções, vamos simplesmente fazer um polling aos registos dos timers para sabermos quando atingimos o tempo que programa-mos inicialmente e fazemos um toogle ao led, e depois repetimos isto infinitamente.

Neste exemplo vamos fazer toogle do led a 2Hz, isto quer dizer que o led vai estar ligado 500ms e desligado 500ms, como o nosso clock é 16Mhz e o nosso maior timer só pode contar até 65535, isto quer dizer que colocando o timer a contar a 16Mhz só podemos contar até:
Código: [Seleccione]
1/16Mhz = 0,0000000625s //esta é a resolução do nosso timer por contagem
0,0000000625s * 65535 = 0,0040959375s // pouco mais que 4ms

Como podem ver o sinal de 16Mhz do clock é demasiado rápido para o que queremos teremos de usar prescalers para reduzir o sinal de relógio que é fornecido ao(s) timer(s), vamos fazer uma pequena tabela para ver-mos quais são as possíveis resoluções que obtemos dos timers usando os prescalers disponíveis no atmega328p:
Código: [Seleccione]
Resolução do timer = (Prescaler / Clock)
Os valores dos prescalers podem ser 1, 8, 64, 256 ou 1024
O clock é 16Mhz.

Valor prescaler  | Resolução do timer
1 | 0,0000000625s = 62,5 nS
8 | 0,0000005s = 0,5uS
64 | 0,000004s = 4uS
256 | 0,000016s = 16us
1024 | 0,000064s = 64uS

Como podem ver usando os prescalers temos uma grande variedade de frequências/resoluções disponíveis, por isso vamos agora fazer mais umas contas para vermos que valor temos de usar no timer para termos um delay exacto de 500ms(2Hz) para fazer o nosso novo blinky. Para o fazer-mos vamos usar uma pequena fórmula que pode ser facilmente derivada das formulas dadas na datasheet:
Código: [Seleccione]
Target Timer Count = (((Input Frequency / Prescaler) / Target Frequency) - 1)

Input frequency é 16Mhz
Target frequency é 2Hz

Prescaler value | Target timer count
1 | 7999999
8 | 999999
64 | 124999
256 | 31249
1024 | 7811,5

Como o valor máximo de um timer de 16 bits é de apenas 65535 os primeiros três valores podem ser excluídos pois o timer não conta até tão alto, o ultimo valor é inferior a 65535 mas é fracionário, pode ser usado mas vai acumular erros ao longo do tempo o que vai acabar por estragar a contagem e dar valores erróneos, ficamos assim com o quarto valor que nos vai dar um resultado de 500ms certinhos(mais ou menos o erro do nosso cristal, mas ai não temos controlo sobre isso), vamos então começar com pseudo-código:
Código: [Seleccione]
#include <avr/io.h>

int main(void){

//Definir pino do led como saida
//Configurar o timer

for(;;){
//Ler o valor do timer e conforme o mesmo fazer ou não o toogle do led
}

return 0;


Como temos estado a fazer todas as contas a pensar num timer de 16bits, temos de usar o timer 1 do Atmega, toda a informação sobre este timer começa na página 114 da datasheet do atmega328p.
Como vamos usar o timer no modo normal não temos muito que configurar, basta selecionar o prescaler que queremos, isso coloca automaticamente o timer a contar, depois é fazer poling ao registo que tem o valor da contagem e está basicamente o nosso novo blinky feito.
Código: [Seleccione]
#include <avr/io.h>

int main(void){

DDRB = (1<<PB5); //Pino PB5 configurado como saida

//Configuração do timer
TCCR1B = (1<<CS12); //1:256 prescaller

for(;;){
//Ler o valor do timer e actuar conforme
if(TCNT1 >= 31249){ //31249 é o valor que queremos para o delay de 500ms
PORTB ^= (1<<PB5); //Fazer toogle ao led
TCNT1 = 0; //Fazer reset ao timer
}
}

return 0;
}

Basta compilar e fazer o upload deste pequeno pedacinho de código para o vosso Arduino e verão o led que ele tem a piscar, como podem ver usar um timer no modo normal é muito muito simples a inicialização do timer custa-nos uma linha de código e depois basta um if para comparar o valor actual do timer com o nosso valor alvo.

No caso do timer 0 os bits do prescaler são configurados no registo TCCR1B e têm o nome de CS12, CS11, CS10 e representam os seguintes valores de prescaler:
Código: [Seleccione]

  CS12    CS11    CS10      Prescaler
    0       0       0       Timer desligado
    0       0       1       1:1 prescaler/é o mesmo que não ter um prescaler
    0       1       0       1:8 prescaler
    0       1       1       1:64 prescaler
    1       0       0       1:256 prescaler
    1       0       1       1:1024 prescaler
[code]

Como o nosso prescaler escolhido foi o de 1:256 basta colocar o bit CS12 a 1 e deixar todos os outros intocados. Um pequeno pormenor, o nosso micro-controlador é de 8 bits, ou seja o seu barramento de dados tem apenas 8 bits e como tal não podemos ler,escrever ou alterar uma variavel de 16 bits de uma só vez, e como podem ver no cógido não estou a usar variaveis de 8 bits para ler ou escrever valores no registo de contagem do timer, mas sim o TCNT1, que não é um registo verdadeiro mas um alias que o avr-gcc nos oferece para ler e escrever nos registos TCNT1L e TCNT1H sem termos de andar a fazer shifts e operações lógicas no código para colocar os valores de 16 bits nos dois registos de 8 bits, isto é feito pelo compilador e permite-nos criar um código mais limpo e legivel e tambem minimizar erros de programação, é um atalho identico ao ADCW que nos permite ler valores de 10 bits do ADC de uma só vez no nosso código em vez de ler o ACDH e ADCL e depois juntar o valor com operações lógicas num valor maior, mais uma vez para evitar erros e limpeza no código fonte.

Vamos agora usar o timer num outro modo, vamos usar interrupções em vez de estar a fazer constantemente polling á contagem do timer para decidir-mos se fazemos ou não toogle ao led. As interrupções permitem-nos libertar o micro-controlador para fazer outras tarefas enquanto o timer não atinge o valor esperado, e quando o timer atinge o valor programado, o processador pára o que estava a fazer, serve a interrupçõa e volta a fazer o que estava a fazer antes da interrupção, isto pode ser visto de uma maneira muito rudimentar de multi-tasking pois permite ao nosso micro-controlador correr um main pesado, complexo e cheio de cálculos e ao mesmo tempo ter um timer que gera uma interrupção por segundo por exemplo para actualizar um lcd, ou para fazer multiplexing a um array de leds com um tempo de refresh constante sem recorrer a delays, e para muitas outras coisas.

A interrupção é servida/atendida numa função especial chamada ISR(interrupt service routine), esta função não é chamada normalmente como uma qualquer outra função, mas sim por sinais que são gerados no micro-controlador, que são as requisições para interrupção, e tambem não é uma função criada do mesmo modo que as outras funções, é criada de uma maneira diferente que é para o nosso compilador saber que aquilo é uma interrupção. Mas existem algumas limitações em usar interrupções que devem ficar já a conhecer, NUNCA se usam delays em interrupções e devem evitar ao máximo chamar funções dentro de uma interrupção, delays dentro de uma interrupção vão praticamente contra o princpio de usar a interrupção em primeiro lugar, e chamar funções dentro de uma interrupção coloca um over-head bastante grande na entrada e saida da interrupção pois é necessário salva-guardar todos os registos do micro-controlador. O ponto a reter é que as interrupções são supostas de serem rápidas. Se quiserem por exemplo executar uma função complexa de 10 em 10ms, podem usar uma interrupção e nessa interrupção não chamam a função, mas sim uma flag que colocam a um sempre que passam os 10ms e no loop principal usam um if para ver se a flag foi ou não colocada a 1, e por ultimo, toda e qualquer variavel que é para ser partilhada entre o main/funções e uma interrupção tem de ser declarada volatile, o volatile diz ao compilador que esta variavel pode ser alterada numa interrupção e por isso sempre que é usada temos a garantia que é lida da ram e não armazenada num registo caso possivel para poupar um acesso á ram, o facto de não se declarar uma variavel como volatile pode causar um comportamento errático e por vezes dificil de se descobrir nos nossos programas, eis como delcaram uma variavel como volatile:
[code]
int variavel1 = 0; //isto é uma variavel normal
volatile int variavel2 = 0; //Isto é uma variavel declarada como volatile

Para criar-mos uma função de serviço para uma interrupção temos de o fazer de uma maneira diferente de quando criamos uma função, são criadas usando uma keyword especial que tem como argumento o nome do vector de interrupção, esses nomes podem ser encontrados na página 58 do datasheet do atmega328p, a esses nomes, substitui-mos os espaços por _ e adiciona-se _vect no fim deles, deixo a seguir um exemplo de um dos possiveis vectores de interrupção para o timer1. Se quiserem partilhar informação/variaveis entre o main e uma interrupção têm de usar variaveis declaradas como volatile porque as rotinas não têm nem argumentos de chamada nem têm um return.
Código: [Seleccione]
ISR(TIMER1_COMPA_vect){ //Esta é a rotina de serviço á interrupção para o vector TIMER1 COMPA
//código fica aqui
}

Para finalizar este mini crash-course sobre interrupções, não esquecer que como todos os outros periféricos presentes no micro-controlador, temos de configurar as interrupções para que se comportem do modo que queremos pois praticamente tudo o que está dentro do micro pode gerar interrupções, desde os 3 timers, ADC, UART, SPI, I2C, interrupções externas e mais, todos podem gerar interrupções. Temos ainda diga-mos que um interruptor mestre que activa ou desactiva as interrupções a nivel global, e que se nos esquecer-mos de o ligar nunca nenhuma interrupção será gerada, é uma unica linha de código que nos pode deixar a pensar por que razão algo não funciona como devia.

Vamos então passar á segunda parte deste tutorial e usar o timer no modo CTC, neste modo o timer conta até a um valor pré-programado, quando atinge esse valor gera uma interrupção e recomeça a contagem desde 0 (recomeça desde o BOTTOM e como este é 0 por defeito recomeça do 0, mas se alterarem o BOTTOM ele recomeça desde esse valor), tudo isto é feito em hardware, o que nos liberta o processador enquanto o timer conta até ao valor pré-programado. Mais uma vez vamos fazer o blinky com uma frequência de 2hz, vamos lá ao pseudo-código.
Código: [Seleccione]
#include <avr/io.h>
#include <avr/interrupt.h>

int main(void){

//Configurar o pino do led como saida
//Configurar o timer no modo CTC
//Ligar as interrupções globais, para a nossa ISR seja chamada
//Activar as interrupções do timer

for(;;){
//O nosso loop infinito, que vai ficar vazio, tudo é feito na ISR
}

return 0;
}

ISR(){ //Esta vai ser a nossa rotina de serviço á interrupção

//Fazer toogle ao led

}

Para começar podem notar que existe um novo include, que serve precisamente para incluir a tabela de vectores associados ás interrupções e assim como as macros ISR() que servem para criar as funções de serviço a interrupção, entre outras coisas. E agora um pouco mais sobre o modo CTC dos timers já que se configuram todos do mesmo modo, o modo especifico de funcionamento de cada timer é definido por 3 ou 4 bits, neste exemplo vamos continuar a usar o timer 1 que tem 16 bits, portanto teremos 4 bits para configurar qual o modo de funcionamento especifico de cada timer, são eles os bits WGM13, WGM12, WGM11 e WGM10 que estão presentes nos registos TCCR1A e TCCR1B, a tabela com todos os modos está localizada na página 137 do datasheet, como queremos o modo CTC podemos ver por essa tabela que basta-nos colocar o bit WGM12 a 1 no registo TCCR1B e colocar o nosso valor algo num dos dois registos de comparação disponveis no timer, estes registos aceitam valores de 16 bits, pois estamos a usar um timer de 16 bits e são os registos OCR1A e OCR1B, e é tambem através destes registos que se define o duty cycle quando usamos o timer no modo de pwm. Temos tambem de activar as interrupções do timer, neste exemplo basta-nos activar uma delas chamada OCIE1A (output compare interrupt enable A), isto diz ao nosso micro que queremos uma interrupção sempre que o valor de contagem do timer atinge o valor colocado em OCR1A, este bit encontra-se no registo TIMSK1 (timer 1 interrupt mask register).
Código: [Seleccione]
#include <avr/io.h>
#include <avr/interrupt.h>

int main(void){

DDRB = (1<<PB5); //Configurar o pino do led como saida


//Configurar o timer no modo CTC
TCCR1B = (1<<WGM12)|(1<<CS12); //Activar o modo CTC com um prescaler de 1:256
TIMSK1 = (1<<OCIE1A); //Activar as interrupções do timer

//Ligar as interrupções globais, para a nossa ISR seja chamada

for(;;){
//O nosso loop infinito, que vai ficar vazio, tudo é feito na ISR
}

return 0;
}


ISR(){ //Esta vai ser a nossa rotina de serviço á interrupção

PORTB ^= (1<<PB5); //Fazer toogle ao led

}

Mais uma vez, o nosso valor alvo vai ser colocado no registo OCR1A, podem comprovar isso mesmo pela tabela da página 137 no caso de duvida, e como estamos a usar esse registo a interrupção será tambem relacionada com ele, e o seu nome é TIMER1_COMPA_vect, COMPA para o OCR1A e COMPB para o caso de usarem o registo OCR1B.
Para activar as interrupções a nivel global temos de chamar uma pequena função chamada sei(), e para as desactivar-mos chama-mos uma função chamada cli(), os nomes derivam de sei -> SEt Interrups e cli -> CLear Interrupts, vamos então completar o nosso código:
Código: [Seleccione]
#include <avr/io.h>
#include <avr/interrupt.h>

int main(void){

DDRB = (1<<PB5); //Configurar o pino do led como saida


//Configurar o timer no modo CTC
TCCR1B = (1<<WGM12)|(1<<CS12); //Activar o modo CTC com um prescaler de 1:256
OCR1A = 31249; //O nosso valor alvo para termos interrupções a 2Hz
TIMSK1 = (1<<OCIE1A); //Activar as interrupções do timer

sei(); //Ligar as interrupções globais, para a nossa ISR seja chamada

for(;;){
//O nosso loop infinito, que vai ficar vazio, tudo é feito na ISR
}
return 0;
}


ISR(TIMER1_COMPA_vect){ //Esta vai ser a nossa rotina de serviço á interrupção

PORTB ^= (1<<PB5); //Fazer toogle ao led

}

Mais uma vez, o código deve compilar sem qualquer erro ou warning e após upload deverão ver o led a piscar, e sem qualquer código no loop infinito!

E já que estamos a brincar com timers que tal fazer ainda outro blinky! Mas desta vez criando algo de util, vamos re-criar a função millis() do Arduino que é bastante util para delays não bloqueantes e sem ser preciso andar a mexer com os timers sempre que querem adicionar mais uma função com uma temporização especial/rigida basta usar um if no main e uma chamada á millis() e bang, funções chamadas a intervalos regulares. Neste examplo vamos utilizar um timer de 8 bits, pois serve perfeitamente para o que queremos e deve-se sempre começar a usar os timers de 8 bits, pois o timer de 16 bits é um timer com mais funcionalidades e é melhor por exemplo para fazer controlo de motores via pwm pois oferece pwm de 10 bits ao invés do pwm de 8 bits que um timer de 8 bits oferece. Vamos então calcular qual o valor alvo e o prescaler que temos de usar para gerar-mos interrupções a um ciclo de 1000Hz ou de 1 em 1ms para incrementar a variavel que vai guardar os mili-segundos.
Código: [Seleccione]
Target Timer Count = (((Input Frequency / Prescaler) / Target Frequency) - 1)

Input frequency é 16Mhz
Target frequency é 1000Hz ou 1Khz

Prescaler value | Target timer count
1 | 15999
8 | 1999
64 | 249
256 | 61,5
1024 | 14,625

Como apenas o prescaler de 1:64 nos dá um valor inteiro inferior a 255(que é o valor máximo do timer de 8bits) vamos usar esse valor como o valor de comparação(compare) pois vamos usar novamente o timer no modo CTC, devido á simplicidade de uso, está presente em todos os timers e requer apenas uma configuração inicial, vamos então á datasheet ver como coloca-mos o timer 0 no modo CTC.
A secção do timer 0 é a numero 14 e começa na página 98, aconselho a leitura da datasheet para os bravos e para os curiosos mas é muito provavel que fiquem a coçar a cabeça, por vezes a datasheet é confusa e precisa de ser lida várias vezes até se entender, até porque o ingles que lá está nem sempre é o melhor, portanto vamos saltar directamente para a subsecção 9 que é onde está a descrição bit a bit de cada registo envolvido no controlo do timer 0. Tal como o timer 1 existe uma tabela com os diferentes modos de funcionamento, mas neste timer é muito mais pequena até porque este timer tem apenas 8 bits, mas mais uma vez basta colocar um bit a 1 para ligar o modo CTC, neste caso é o bit WGM01 no registo TCCR0A, e como o prescaler será de 1:64 temos de colocar os bits CS01 e o CS00 no registo TCCR0B a um, e o nosso valor alvo de 249 será colocado no registo OCR0A, mais uma vez temos de ir á tabela de interrupções ver o nome do vector de interrupção que como devem imaginar é muito parecido ao usado no timer 1, sendo ele TIMER0_COMPA_vect, e temos tambem de activar as interrupções do timer colocando o registo OCIE0A a um no registo TIMSK0, como podem ver muitos dos registos dos timers diferem apenas no numero do timer que usamos.
Deste vez não há pseudo-código pois não estou a introduzir nada de novo espero eu e o tutorial já vai longo e penso que está tudo explicado neste texto.
Avr fanboy

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Re: Introdução ao avr-gcc usando o AvrStudio [Quinta parte - Conversor ADC]
« Responder #112 em: 31 de Janeiro de 2012, 02:13 »
Código: [Seleccione]
#include <avr/io.h>
#include <avr/interrupt.h>

void timer0_init(void); //Protótipo da função

volatile unsigned long milis = 0; //Esta é a variavel volatile que vai ser partilhada pela função milis e pela interrupção
unsigned long now = 0;

int main(void){

DDRB = (1<<PB5); //Coloca o pino do led como saida
timer0_init();

for(;;){
if(milis-now >= 500){
now = milis;
PORTB ^= (1<<PB5); //Fazer toogle do led a cada 500ms/2Hz
}
}
return 0;
}


void timer0_init(void){
TCCR0A = (1<<WGM01); //Timer no modo CTC
TCCR0B = ((1<<CS01)|(1<<CS00)); //1:64 prescaler
OCR0A = 249; //Valor alvo para termos uma interrupção a cada 1ms
TIMSK0 = (1<<OCIE0A); //Activar interrupções do timer
sei(); //Activar interrupções globais
}

ISR(TIMER0_COMPA_vect){

milis++; //Aumentar a variavel milis em 1, para dizer que 1ms passou
}
Este código é igual ao exemplo Blinky without delay que se encontra no IDE do Arduino, mas feito bare-metal, a incialização do timer está numa função, pois se quiserem usar o código é mais simples de copiar.
Qualquer duvida deixem um post, e boas programações.

PS.: Tiver de dividir em duas partes pois excedia o limite de 20 mil caracteres por mensagem, dava jeito alterar esse limite para 25 mil, que os próximos tutoriais tambem são algo extensos.
Avr fanboy

Offline msr

  • Mini Robot
  • *
  • Mensagens: 798
Re: Introdução ao avr-gcc usando o AvrStudio [Sexta parte- timers]
« Responder #113 em: 31 de Janeiro de 2012, 04:10 »
senso, já fazias era um .pdf com todo este material. Com o LyX era só despejar texto e imagens :)

Offline metRo_

  • Administrator
  • Mini Robot
  • *****
  • Mensagens: 3.753
Re: Introdução ao avr-gcc usando o AvrStudio [Sexta parte- timers]
« Responder #114 em: 31 de Janeiro de 2012, 11:07 »
senso não há aí uma confusão? Em vez de 2Hz não querias dizer 1Hz?

De resto, estive a ler e está excelente :)

Offline tr3s

  • Administrator
  • Mini Robot
  • *****
  • Mensagens: 811
  • char x=1, y=5; x^=y^=x^=y;
Re: Introdução ao avr-gcc usando o AvrStudio [Sexta parte- timers]
« Responder #115 em: 31 de Janeiro de 2012, 11:27 »
Está muita bom Senso!  ;D
Tr3s
Daniel Gonçalves

Offline zordlyon

  • Mini Robot
  • *
  • Mensagens: 1.768
Re: Introdução ao avr-gcc usando o AvrStudio [Sexta parte- timers]
« Responder #116 em: 31 de Janeiro de 2012, 11:41 »
5*... parabéns e obrigado pelo trabalho que tives-te a disponibilizar isto...  ;)

Cumprimentos,
André Carvalho.
Cumprimentos,
André Carvalho.

Offline tr3s

  • Administrator
  • Mini Robot
  • *****
  • Mensagens: 811
  • char x=1, y=5; x^=y^=x^=y;
Re: Introdução ao avr-gcc usando o AvrStudio [Sexta parte- timers]
« Responder #117 em: 31 de Janeiro de 2012, 11:43 »
Na secção de tutoriais já conseguem encontrar esta entrada!  ;)
Tr3s
Daniel Gonçalves

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Re: Introdução ao avr-gcc usando o AvrStudio [Sexta parte- timers]
« Responder #118 em: 31 de Janeiro de 2012, 14:33 »
Eu penso que não, porque 1Hz é 1s, e 2Hz são 0.5s, o que pode levantar confusão é que é feito um toogle a 2Hz, e isso divide a frequência para 1Hz, mas não digo que não estou a pensar mal
Avr fanboy

Offline metRo_

  • Administrator
  • Mini Robot
  • *****
  • Mensagens: 3.753
Re: Introdução ao avr-gcc usando o AvrStudio [Sexta parte- timers]
« Responder #119 em: 31 de Janeiro de 2012, 21:09 »
Eu penso que não, porque 1Hz é 1s, e 2Hz são 0.5s, o que pode levantar confusão é que é feito um toogle a 2Hz, e isso divide a frequência para 1Hz, mas não digo que não estou a pensar mal

Eu li mal, realmente está correcto pois falas em toogle(não sei é se dizer que o toogle é feito a 2Hz e depois só o fazer a cada 500ms está muito correcto mas se calhar sim e estou a confundir-me) e eu estava a pensar em piscar à freq de 2Hz. Li logo que querias que ele esteja 500ms ligado e 500ms desligado, sendo assim um período é ele estar 500ms ligado e 500ms desligado, periodo=1s, f=1Hz, isto é, ele pisca a freq de 1Hz.