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 116534 vezes)

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

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 #120 em: 01 de Fevereiro de 2012, 19:59 »
Boas noites, hoje vamos falar um bocadinho sobre como gerar PWM usando os timers do nosso Atmega. PWM é um sigla que quer dizer pulse width modulation, ou em português modulação da largura do pulso, o que isto quer dizer é que recorrendo ao hardware do nosso timer( ou via software com algumas limitações, mas este tutorial só se foca em pwm usando o hardware dos timers) podemos controlar o tempo que um sinal está a 1(HIGH) e a 0(LOW), ao fazer-mos isto a voltagem/energia média que este sinal fornece pode ser variada e assim podemos controlar o brilho de um led, misturar cores num led RGB, controlar a velocidade de um motor DC, e até gerar áudio, podemos ainda usar sinais PWM para controlar os típicos servos tão úteis na robótica caseira, e usando um pequeno filtro RC podemos ainda converter o sinal PWM num sinal analógico com uma variação suave de voltagem e não apenas entre 0's e 1's, na imagem abaixo podem ver como se parece uma onda PWM com diferentes duty cycles, duty cycle é o nome que damos á relação de tempo que o sinal está a 1 ou a 0.



O nosso micro oferece-nos vários tipos de pwm, Fast PWM, Phase correct PWM e Phase and Frequency correct PWM, neste tutorial vou apenas abordar o Fast PWM, deixando o Phase correct PWM para o próximo. Temos também possibilidade de gerar pwm com 8, 9 ou 10 bits de resolução, mas mais de 8 bits precisamos de recorrer ao(s) timer(s) de 16 bits como é óbvio. Fast PWM é um modo bastante simples de se configurar e que permite frequências de pwm superiores á dos outros dois modos de operação, este modo não é aconselhado para fazer o controlo de motores, mas sim o phase correct PWM, podem ver na imagem abaixo a diferença em fast pwm e phase correct pwm.



Os dois sinais de cima são gerados por fast pwm e os dois de baixo são gerados usando phase correct pwm. A diferença principal entre os dois é que em fast pwm a parte a 1(HIHG) do sinal começa sempre no mesmo sitio,mas a transição para 0(LOW) é arbitrária(regira pelo valor definida por nós nos registos do pwm), isto leva a que o centro da onda enquanto a 1 não esteja por assim dizer centrado com o resto do sinal a 0, o que pode causar alguns problemas quando usada para controlar motores dc/pontes H.



Esta imagem acima mostra como o modo phase correct pwm funciona, o timer conta de BOTTOM para TOP, e depois de TOP para BOTTOM, e a onda de pwm é gerada comparando o valor dessa mesma contagem com o nosso duty cycle programado, ao contrário do fast pwm que conta de BOTTOM até TOP e depois recomeça do BOTTOM. Adicionalmente ainda temos o phase and frequency correct pwm que nos permite variar a frequência do pwm, este modo está apenas disponivel no timer 1 de 16 bits.

Deixando toda este teoria para trás vamos passar a um exemplo, neste vamos utilizar pwm para gradualmente ligar e desligar um led, algo simples que mostra perfeitamente o intuito do pwm.
Código: [Seleccione]
#include <avr/io.h>

int main(void){

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

for(;;){
//definir o novo valor do duty cycle
//pequeno delay se não vai parecer instanteneo
//pois o nosso micro está a correr a 16Mhz
}

return 0;
}

Neste exemplo vamos usar o timer 0, simplesmente por para fazer o fade-in/out do led não precisa-mos do timer de 16 bits, a primeira coisa que vamos aprender é como configurar/escolher os diferentes modos de funcionamento de um timer, esses modos estão descritos numa tabela chamada Waveform generation modes, que no caso do timer0 do Atmega328p estão na página 109 da datasheet.
Os bits que afectam os diferentes modos são o WGM02, WGM01 e WGM00 que se encontra nos registos TCCR0A e TCCR0B.



Para usar-mos Fast PWM temos dois modos á escolha, modo 3 e o modo 7, a diferença entre eles é que no modo 3 o TOP está fixo em 0xFF ou seja o timer conta até 255, enquanto que no modo 7 o TOP pode ser definido e assim pode-se alterar a frequência para além do duty-cycle, até agora numa precisei de o fazer, mas se precisarem de alterar a frequência já sabem que é possivel, para este exemplo não precisamos de o fazer por isso vamos antes escolher o modo 3, e como tal temos de colocar os bits WGM01 e WGM00 a 1 no registo TCCR0A.

Como queremos controlar os pinos do nosso micro através do timer para gerar o PWM temos tambem que configurar o modo como esses mesmos pinos reagem aos comandos do timer, como isto é feito em hardware não podemos escolher os pinos que queremos, por exemplo os pinos em que é gerado o pwm do timer 0 são os pinos PD6 e PD5. Vamos usar o pino PD6, e é neste pino que teremos de ligar o led, e teremos então de o configurar, os vários modos de funcionamento do pino quando usado no modo Fast PWM estão descritos na tabela 14-3 da página 106, que para simplificar fica aqui uma imagem da mesma:



Como podem ver pela tabela, podemos usar o pino normalmente como um pino digital, o pino pode fazer um toogle, ou pode ser usado como saida de pwm com o sinal invertido ou não, vamos usar o sinal normal pois, o cátodo do led vai ligar á massa e o anodo vai ser ligado ao pino PD6, se se usar pwm invertido o efeito de fade in fica trocado com o de fade out, mas o funcionamento em si é igual.
Neste caso vamos escolher o modo 3, ou seja teremos de colocar ambos os bits COM0A1 a 1.

para definir-mos um determinado duty cycle temos dois registos, um para cada pino em que cada timer pode gerar pwm, são esses registos os OCR0A e OCR0B para o timer 0, OCR é um sigla para Output Compare Register, o pwm é gerado comparando o valor que colocamos neste registo com a sua actual contagem.
Por ultimo, falta-nos escolher um prescaler para fornecer um sinal de relógio ao timer, não existe de todo uma regra para que frequência devem fazer pwm, mas tipicamente quanto mais elevada melhor, deixo-vos as diferentes frequências de PWM que são possíveis de obter com um timer de 8 bits:
Código: [Seleccione]
Fclk=16Mhz //Cristal do Atmega/Arduino

A formula:
 Fpwm = Fclk/(Prescaler*256)

 Prescaler Fout
     1 62.5Khz
     8 7812.5Hz
     64 976Hz
     256 244.141hz
     1024 61.03Hz

Como podem ver as frequências de pwm não são muuito elevadas, e se forem usadas por exemplo para controlo de motores, recomendo que usem apenas o prescaler de 1:1 pois todas as outras frequências vão ouvir os motores a "cantar", para o caso dos led's diria que o prescaler de 1:1024 também não deve ser usado pois podem notar flicker dos mesmos, vamos escolher um valor intermédio e usar o prescaler de 1:64, e vamos então juntar tudo isto num pedacinho de código.
Código: [Seleccione]
#include <avr/io.h>
#define F_CPU 16000000UL
#include <avr/delay.h>

int main(void){

unsigned char i=0; //Variavel para ser usada no for()

DDRD = (1<<PD6); //Coloca o pino do led/pwm como saida
//O PD6 é o digital 6 do Arduino

//Configuração do timer
TCCR0A = ((1<<COM0A1)|(1<<WGM01)|(1<<WGM00)); //Activar o pwm no pino PD e coloca o timer em modo Fast PWM
TCCR0B = ((1<<CS01)|(1<<CS00)); //Activar o timer com um prescaler de 1:64


for(;;){

//Fade up
for(i=0; i<255;i++){
OCR0A = i; //Define o novo valor do duty cycle
_delay_ms(50); //Um pequeno delay
}

//Fade down
for(i=255; i>0;i--){
OCR0A = i; //Define o novo valor do duty cycle
_delay_ms(50); //Um pequeno delay
}
}

return 0;
}


É só ligar um led, com o cátodo(pata mais comprida) á massa e a outra pata ligada através de uma resistência com 330 ou 380ohm liga ao pino PD6/Digital 6 do Arduino.
Já cá venho deixar um filme do que deverão ver, e de um mini projecto, uma mood light.
Avr fanboy

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Re: Introdução ao avr-gcc usando o AvrStudio [Mais timers/mood light]
« Responder #121 em: 02 de Fevereiro de 2012, 21:27 »
E para variar um bocadinho do típico tutorial com muito texto e pouca ação, vamos juntar o que já sabemos e usar isso para montar uma mood light, para que não sabe é basicamente um/vários led's RGB que vão percorrendo lentamente todas as cores do espectro visível, para isso vamos usar timers para gerar sinais pwm para poder-mos controlar a intensidade da cada cor e assim gerar-mos todas as cores do arco-íris e mais umas quantas, e para aproveitar juntar mais um pouco de funcionalidade vamos adicionar dois potenciómetros, um para controlar a intensidade do(s) led(s) e outro para controlar a velocidade a que os mesmos mudam de cor, e em vez de delays no nosso código vamos também tirar partido do nosso millis, assim já se pode dizer que temos um projeto com alguma complexidade, com um efeito prático bonito(toda a gente gosta de leds e muitas cores =) ).
Provavelmente a parte deste projeto que será mais estranha é o método como vamos gerar as cores, existem algumas fórmulas por ai que nos permitem gerar basicamente todas as cores do espectro visível,mas não oferecem um método simples de se controlar a intensidade da cor,por isso eu vou fazer isto de outra maneira, vou usar uma função que converte cores em HSV para RGB. HSV é um método de representar cores de um método diferente de RGB, basicamente RGB tem um valor em 0 e 255 (se pensar-mos uma resolução de 8 bits por cor) para cada um dos canais R (vermelho), G (verde) e B (azul), enquanto que o HSV representa as cores num cilindro, sendo H (hue) a cor que queremos escolher e que pode ser um valor entre 0 e 360º, S (saturação) é o quão intensas serão as cores, ou seja, quanto maior o valor da saturação mais intensa é a cor, e quanto menor é este valor mais branca é a cor, quando a saturação atinge o seu mínimo não importa o hue e obtemos sempre uma cor branca, e V (value) é a intensidade da cor, e é este parâmetro que nos permite variar a intensidade/luminosidade da nossa mood light, para converter de HSV para RGB's existem alguns métodos, eu vou usar uma fórmula que se encontra facilmente na internet, e se quiserem ler um pouco mais sobre este e outros espaços de cores, nada melhor como a Wikipédia:
http://en.wikipedia.org/wiki/HSL_and_HSV

Uma outra "novidade" será o uso de ponteiros, os meus tutoriais não são de todos um tutorial sobre programação C, e o uso de ponteiros é o que dá ao C a sua flexibilidade e poder, posso esclarecer duvidas sobre os mesmos nos comentários, e deixo aqui novamente um link para a Wikipédia sobre eles, mas podem sempre pesquisar mais sobre o assunto pois um tutorial sobre ponteiros seria algo extensivo e fora do intuito deste mini-projecto.
http://en.wikipedia.org/wiki/Pointer_%28computing%29

Como vimos no anterior tutorial cada timer só nos oferece 2 canais de pwm, e para um led RGB precisamos de 3, por isso iremos usar o timer 0 e o timer 2 que são ambos de 8 bits, usando 2 canais do timer 0 e um canal do timer 2 para gerar os três sinais de pwm necessários para um led RGB, se não tiverem um led RGB podem sempre usar 3 leds separados, um vermelho, um verde e um azul, a vantagem dos RGB é que as cores ficam mais bem misturadas e se forem leds foscos nem é preciso colocar um papel por cima por exemplo para misturar as cores numa só cor e não em spots das 3 cores fundamentais.
Iremos também usar o timer 1 como base de tempo para o millis, assim como dois pinos para ler os dois potenciómetros, no meu caso vou usar potenciómetros de 10Kohm's, podem usar de outros valores, mas entre 5 e 50Khom é o recomendado para usar com o ADC do micro-controlador, valores muito maiores podem causar oscilações nos valores lidos.

Vamos começar com um bocadinho de pseudo-código.

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

int main(void){

//Definir pinos dos leds como saida
//Configurar timer0 para gerar dois sinais pwm
//Configurar timer2 para gerar um sinal pwm
//Configurar timer1 para ser usado como base de tempo para o milis
//Configurar o ADC

for(;;){
//Ler o valor dos dois potenciometros
if(lastTime-milis() > timePotValue){ //Se tempo que passou > tempo definido pelo potenciometro, então
//Fazer update aos 3 duty-cycles para gerar a nova cor
}
}

return 0;
}

O código para inicialização e leitura do ADC basta simplesmente ir buscar as funções criadas no tutorial sobre o mesmo, e a configuração dos dois timers que vão gerar o pwm vai ser em tudo identica á feita no tutorial anterior, com o mesmo prescaler, apenas ativando os dois OCR no caso do timer0 e no caso do timer 2 apenas muda o nome dos registos que de resto é em tudo igual ao que foi feito no tutorial anterior, para o timer 2 irei usar o pino PD3, que corresponde ao OC2B.

Vamos então fazer umas continhas para que o timer 1  gere a base de tempo para o milis, o timer 1 como já referi é um timer especial, pois para além de ser de 16 bits ao invés dos outros dois timers, tem alguns extras, por exemplo pode ser alimentado por um sinal de relógio externo, pode ser usado para medir a frequência de um sinal externo ao micro-controlador com recurso a muito pouco código, tem um debouncer que lhe permite ler um botão sem necessitar de código para o debounce, pode gerar pwm até 10 bits e mais alguns extras.
Para o milis queremos gerar interrupções a 1000Hz, ou seja uma interrupção por cada mili-segundo, usando novamente formulas disponíveis na datasheet vamos calcular qual o valor que precisamos de colocar no registo de comparação que irá por sua vez gerar a interrupção.

Código: [Seleccione]
Target Timer Count = (((Input Frequency / Prescaler) / Target Frequency) - 1)
Input Frequency = 16Mhz
Target frequency = 1000Hz

Prescaler value | Target timer count
1 | 15999
8 | 1999
64 | 249
256 | 61.5
1024 | 14.625

Neste caso temos uma larga escolha de valores que podemos usar, tirando apenas os dois últimos que são fraccionários e que por isso vão acabar por introduzir erros na nossa contagem dos mili-segundos, podemos usar o primeiro valor pois cabe perfeitamente no timer de 16 bits, visto que o valor máximo que ele suporta é 65535, vamos então juntar todas estas coisas ao pseudo-código para o transformar num mood light funcional.

Código: [Seleccione]
#include <avr/io.h>
#include <avr/interrupt.h>
#include <math.h> //Necessário devido ao uso de floats/numeros de virgula flutuante

#define INTENSITY 0 //Potenciometro que controla a intensidade está ligado ao pino 0 do ADC,ou seja PC0
#define TIME 1 //Potencioetro que controla o delay entre transições está ligado no pino 1 do ADC, ou seja PC1

//Protótipos das funções
void timer0_init(void);
void timer1_init(void);
void timer2_init(void);
void adc_init(void);
void set_pwm(uint8_t red, uint8_t green, uint8_t blue);
void Hsv2Rgb( double *r, double *g, double *b, double h, double s, double v );
unsigned long milis(void);
uint16_t read_adc(uint8_t channel);

//Variaveis globais
volatile unsigned long milis_count = 0; //Variavel partilhada entre a interrupção do timer 1 e a função milis

int main(void){

//Variaveis locais
unsigned int delayTime = 10; //Variavel usada para guardar o valor de delay lido do potenciometro
uint16_t intensity = 0; //Variavel usada para guardar o valor de intensidade lido do potenciometro
unsigned long lastTime = 0; //Variavel usada para guardar o ultimo valor do milis
double red = 0.0; //Valor actual do vermelho, retornado pela função HSV->RGB, entre 0 e 1
double green = 0.0; //Valor actual do verde, retornado pela função HSV->RGB, entre 0 e 1
double blue = 0.0; //Valor actual do azul, retornado pela função HSV->RGB, entre 0 e 1
double hue = 0.0; //Valor actual do hue, ou seja define a cor actual
double saturation = 100; //Valor da saturação, está definido como 100(máximo), mas podem alterar
double value = 1.0; //Valor de intensidade, convertido para ser passado á função HSV->RGB

timer0_init(); //Chama inicialização do timer 0
timer1_init(); //Chama inicialização do timer 1
timer2_init(); //Chama inicialização do timer 2
adc_init(); //Chama inicialização do timer 0

sei(); //Activa as interrupções a nivel global, para que milis funcione
DDRB = (1<<PB5); //Pino PB5 como saida (led do Arduino), usado para ver-mos que o programa está a correr

for(;;){

//Leitura dos potenciometros que definem o delay e a intensidade
delayTime = read_adc(TIME) * 2; //Multipliquei a leitura por 2 para que o valor máximo entre cor seja de 2s
//mas podem alterar isto a vosso gosto
intensity = read_adc(INTENSITY); //Leitura do valor da intensidade

if(delayTime <= 10){ //Usado para que o valor do delay entre cores não seja menor que 10ms
delayTime = 10;
}

value = ((double)(intensity/1024.0)*255.0); //Isto é basicamente um map() do arduino, para garantir que o valor
//do value não passa de 255
if(value >= 255.0){ //Usado como teste de sanidade para garantir que o valor não passa de 255
value = 255.0; //devido a arredondamentos de floats
}

if(value <= 0.1){ //Para garantir que o value vai mesmo a 0, e desliga o led
value = 0.0;
}


if( (milis() - lastTime) >= delayTime){ //Se tempo que passou > tempo definido pelo potenciometro, então
//Fazer update aos 3 duty-cycles para gerar a nova cor

PORTB ^= (1<<PB5); //Faz toogle ao led, funciona como uma indicação de que o programa não bloqueou
lastTime = milis();


//Chama a função HSV->RGB e faz o update do duty-cycles

Hsv2Rgb(&red, &green, &blue, hue, saturation, value);

red = red * 255.0; //Os valores retornados pela função variam entre 0 e 1, então multiplicam-se
green = green * 255.0; //por 255 para os converter em valores 0-255
blue = blue * 255.0;

hue = hue + 0.5; //Este é o passo entre cores, podem tambem alterar este valor

if(hue > 360){ //Quando chega-mos ao limite das cores, volta-mos ao inicio
hue = 0;
}

//Aqui faz-se uma conversão de float para inteiro ao usar o (uint8_t), ou seja um cast para um valor de 8 bits
//Se tiverem leds de cátodo comum usem este código
OCR0A = (uint8_t)red; //Led vermelho está conectado no pino PD6/digital 6
OCR0B = (uint8_t)green; //Led verde está conectado no pino PD5/digital 5
OCR2B = (uint8_t)blue; //Led azul está conectado no pino PD3/digital pin 3

//Com leds de anodo comum é necessário inverter os valores, se tiverem leds de anodo comum
//comentem para fora as 3 linhas de cima e descomentem estas:
//OCR0A = 255-(uint8_t)red; //Led vermelho está conectado no pino PD6/digital 6
//OCR0B = 255-(uint8_t)green; //Led verde está conectado no pino PD5/digital 5
//OCR2B = 255-(uint8_t)blue; //Led azul está conectado no pino PD3/digital pin 3

}
}

return 0;
}

void adc_init(void){
ADCSRA |= ((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)); //16Mhz/128 = 125Khz como clock de referencia para o ADC
ADMUX |= (1<<REFS0); //Referencia de voltagem é 5V
ADCSRA |= (1<<ADEN); //Ligar o ADC
ADCSRA |= (1<<ADSC); //Fazer uma conversão, pois esta é que demora mais tempo
}

uint16_t read_adc(uint8_t channel){
ADMUX &= 0xF0; //Limpa o canal anteriormente lido
ADMUX |= channel; //Define o novo canal a ser lido
ADCSRA |= (1<<ADSC); //Inicia uma nova conversão
while(ADCSRA & (1<<ADSC)); //Espera que a conversão seja concluida
return ADCW; //Retorna o valor de 10 bits lido pelo ADC
}

void timer0_init(void){

DDRD = ((1<<PD5)|(1<<PD6)); //Define os pinos associados ao pwm do timer 0 como saidas
TCCR0A = ((1<<COM0A1)|(1<<WGM01)|(1<<WGM00)); //Activa o pwm no pino PD6 e coloca o timer em Fast pwm
TCCR0A |= (1<<COM0B1); //Activa o pwm no pino PD5
TCCR0B = ((1<<CS01)|(1<<CS00)); //Define prescaler para 64, timer activado
}

void timer2_init(void){

DDRD |= (1<<PD3); //Define o pino PD3/OC2B como saida
TCCR2A = ((1<<COM2B1)|(1<<WGM21)|(1<<WGM20)); ///Activa o pwm no pino PD3 e coloca o timer em Fast pwm
TCCR2B = ((1<<CS21)|(1<<CS20)); //Define prescaler para 64, timer activado
}


void timer1_init(void){

OCR1A = 15999; //Valor necessário para gerar interrupções ao ritmo de 1 a cada 1ms
TIMSK1 = (1<<OCIE1A); //Activa a interrupção quando a contagem do timer = OCR1A
TCCR1B = ((1<<WGM12)|(1<<CS10)); //Timer no modo CTC, prescaler de 1, timer activado
}

unsigned long milis(void){

cli(); //Desactivar as interrupções para que se faça uma cópia atómica da variavel
//Isto é para garantir que por exemplo estamos a ler o valor do milis, acontece outra
//interrupção e o resto do valor que vamos ler já não é utilizavel
unsigned long milis_value = milis_count; //Copia o valor de milis para uma variavel auxiliar para poder ser retornado
sei(); //Activar as interrupções de novo, se não o milis pára
return milis_value;

}

ISR(TIMER1_COMPA_vect){ //Interrupção associada ao timer 1
milis_count++; //Adiciona 1 á variavel para indicar que passo 1ms
}

void Hsv2Rgb( double *r, double *g, double *b, double h, double s, double v ) {
int i;
double f, p, q, t;

s/=100.0;
v/=255.0;

if( s == 0 ) {
// achromatic (grey)
*r = *g = *b = v;
return;
}

h /= 60;
i = (int)floor( h );
f = h - i;
p = v * ( 1.0 - s );
q = v * ( 1.0 - s * f );
t = v * ( 1.0 - s * ( 1 - f ) );

switch( i ) {
case 0:
*r = v;
*g = t;
*b = p;
break;
case 1:
*r = q;
*g = v;
*b = p;
break;
case 2:
*r = p;
*g = v;
*b = t;
break;
case 3:
*r = p;
*g = q;
*b = v;
break;
case 4:
*r = t;
*g = p;
*b = v;
break;
default:
*r = v;
*g = p;
*b = q;
break;
}
}


Como podem ver o programa é um pouco mais extenso que o normal, mas faz algo mais que piscar um led, e como está todo comentado espero que seja de facil compreensão. Como estamos a utilizar numeros em virgula flutuante(floats ou doubles para o compilador do avr são iguais), temos de dizer ao IDE para usar uma biblioteca de matemática feita especialmente para eles, pois a que standart do C gera código demasiado grande e lento, para isso precisam de ir primeiro menu Configuration Menu, desponivel na tab Project Manager, por exemplo neste pequeno exemplo se não incluir-mos a libm o código compilado tem cerca de 6.1Kbytes, enquanto que com a libm esse valor baixa para 3Kbytes sensivelmente.



Escolham a secção Libraries, escolham a libm.a e pressionem Add Library e deverá aparecer a libm.a na listagem Link with these Objects:



Por fim, montem numa breadboard os potenciometros e o led conforme este esquema, façam o upload do código e tudo deverá funcionar sem problemas:



E aqui fica um filme a mostra o funcionamento tipico:



Qualquer duvida que tenham ou erro que encontrem, deixem um post  ;D

Avr fanboy

Offline metRo_

  • Administrator
  • Mini Robot
  • *****
  • Mensagens: 3.753
Re: Introdução ao avr-gcc usando o AvrStudio [Mais timers/mood light]
« Responder #122 em: 03 de Fevereiro de 2012, 00:21 »
Muito bom, não conhecia a libm :)

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Re: Introdução ao avr-gcc usando o AvrStudio [Mais timers/mood light]
« Responder #123 em: 03 de Fevereiro de 2012, 00:26 »
E tens lá as bibliotecas optimizadas para usar printf's com floats, assim como os sprintf's que até é preciso adicionar mais umas coisas ao script do linker, ficam para um outro tutorial quando for preciso, para a semana é controlo de motores.
Avr fanboy

Offline souza_neto

  • Mini Robot
  • *
  • Mensagens: 7
Re: Introdução ao avr-gcc usando o AvrStudio [Mais timers/mood light]
« Responder #124 em: 14 de Fevereiro de 2012, 05:40 »
Cumprimentos,

Senso parabens pelos tutoriais eles tem me ensinado muito, como te falei antes eu sou iniciante no mundo dos microcontroladores em especial os AVR, na verdade eu tenho um contato maior com os velhos e bons 8051's, pisco alguns leds com PIC's mas estou muito interessado nos micros AVR. Sempre que posso estou aqui no LR e leio bastante sobre AVR's e afins.

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

Offline pmj_pedro

  • Mini Robot
  • *
  • Mensagens: 328
Re: Introdução ao avr-gcc usando o AvrStudio [Mais timers/mood light]
« Responder #125 em: 25 de Julho de 2012, 23:07 »
percisava de uma pequena ajuda para configurar o pwm do arduino, a uma frequenica superior a 20khz,e estava a tentar fazer com pwm com phase correction, mas nao estou a conseguir, nao percebo mt bem o que configurar, podias ver o que falta

Código: [Seleccione]
void setup(){
  TCCR0 = (1<<CS00);                            //set presscaler to 1
  TCNT0 = 0;                                    // initialize counter
  TCCR0A = (1<<COM0A1);                          // pwm non-inverted mode
  TCCR0A |= (1<<WGM00);                          // phase correct

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Re: Introdução ao avr-gcc usando o AvrStudio [Mais timers/mood light]
« Responder #126 em: 25 de Julho de 2012, 23:08 »
Tens de meter todos os registos a zero, porque o Arduino usa os timers, e se lhe mexeres podes perder algumas funcionalidades como por exemplo o milis().
Avr fanboy

Offline pmj_pedro

  • Mini Robot
  • *
  • Mensagens: 328
Re: Introdução ao avr-gcc usando o AvrStudio [Mais timers/mood light]
« Responder #127 em: 25 de Julho de 2012, 23:29 »
eu estou a tentar fazer o codigo segundo o datasheet, e sao mt os registo para configurar, mas quais sao os registos que tu dizes para por a zero, eu tinha a intençao de por dois pwm sobre o msm timer, ja vi que é possivel, o Pin5 e Pin6, mas nao estou a perceber mt das configuraçoes

Offline pmj_pedro

  • Mini Robot
  • *
  • Mensagens: 328
Re: Introdução ao avr-gcc usando o AvrStudio [Mais timers/mood light]
« Responder #128 em: 26 de Julho de 2012, 18:32 »
Decidi usar o timer2 por enquanto pk vou precisar de usar a funçao delay()

Código: [Seleccione]
void init_myPWM(){
  TCCR2A = (1<<COM1A1) | (1<<COM2B1) | (1<<WGM1) | (1<<WGM0); //non inverting pwm & fast pwm
  TCCR2B = (1<<WGM2) | (1<<CS21);  // variable TOP & prescaler 8
  OCRA =  100; // TOP
  TCNT2 = 0;  //clean counter
  OCR2A = 0;  //OC2A
  OCR2B = 0;  //0C2B 
  DDRD = (1<<DDD3);
  DDRB = (1<<DDB3);
}

mas o arduino ide esta a dar erro no OCRA

edit: quero limitir o contador ate 100, pk fazendo as contas assim fico com a frequencia do pwm a 20khz
« Última modificação: 26 de Julho de 2012, 18:38 por pmj_pedro »

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Re: Introdução ao avr-gcc usando o AvrStudio [Mais timers/mood light]
« Responder #129 em: 26 de Julho de 2012, 20:12 »
Mas assim o limite do pwm é 100, usa o timer só com prescaler e com a resolução completa é que assim nem 7 bits tens.
Dá erro porque é OCR2A e não OCRA.
Avr fanboy

Offline pmj_pedro

  • Mini Robot
  • *
  • Mensagens: 328
Re: Introdução ao avr-gcc usando o AvrStudio [Mais timers/mood light]
« Responder #130 em: 26 de Julho de 2012, 20:50 »
Mas assim o limite do pwm é 100, usa o timer só com prescaler e com a resolução completa é que assim nem 7 bits tens.
Dá erro porque é OCR2A e não OCRA.

Acho que nao entendeste o que queria, eu quero que o top seja 100, assim fico com o pwm de 0 ate 99
Com isto ja vou conseguir ter um pwm com frequencia de 20khz, que é para usar no motor e ser inaudivel

foc=fclk/(N*TOP)

Mas se dizes que o top é o meu OCR2A, entao qual é o valor para fazer varias o pwm, e qual para definir o top?

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Re: Introdução ao avr-gcc usando o AvrStudio [Mais timers/mood light]
« Responder #131 em: 26 de Julho de 2012, 20:54 »
Tens de ler a datasheet com atenção, quando defines o top, só o timer1 tem um registo separado para isso, que é o ICR, nos outros, o TOP é definido se não me engano pelo OCRxA e ficas só com variação de duty-cycle do pwm no OCRxB, e só tens um canal de pwm e não dois.
Por isso é que não uso Arduino e o seu IDE limitado, queres usar o timer1 e não podes, mas não precisas de ter uma frequencia certa, é um motor, não é audio, mete simplesmente o prescaler a 8 e não inventes com o TOP.
Avr fanboy

Offline pmj_pedro

  • Mini Robot
  • *
  • Mensagens: 328
Re: Introdução ao avr-gcc usando o AvrStudio [Mais timers/mood light]
« Responder #132 em: 26 de Julho de 2012, 21:37 »
Tens de ler a datasheet com atenção, quando defines o top, só o timer1 tem um registo separado para isso, que é o ICR, nos outros, o TOP é definido se não me engano pelo OCRxA e ficas só com variação de duty-cycle do pwm no OCRxB, e só tens um canal de pwm e não dois.
Por isso é que não uso Arduino e o seu IDE limitado, queres usar o timer1 e não podes, mas não precisas de ter uma frequencia certa, é um motor, não é audio, mete simplesmente o prescaler a 8 e não inventes com o TOP.

eu acho que nao gosto é do avr, tive umas aulas de pic na univ, e o datasheet parace me mais facil de perceber
mas tb estou a tentar abandonar o arduino, conprei um atmega1284p, ja consegui por o bootoloader, mas so consigo fazer upload dos programas pelo arduino, quando tento pelo avrdude,falha

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Re: Introdução ao avr-gcc usando o AvrStudio [Mais timers/mood light]
« Responder #133 em: 26 de Julho de 2012, 22:51 »
Se for o tipico pic16f é normal que a datasheet seja mais simples, o micro é muito mais antigo e com periféricos muito mais simplificados e com menos utilidade.
E depois estás a viver na pele o resultado de usar a simplicidade do Arduino e mal queres fazer alguma coisa diferente ficas a patinar por não estás habituado a usar o micro directamente, espero que não leves isto a mal, mas sim como um incentivo.

Que bootloader tens no atmega1284p?
Se for o bootloader do duemilanove usas uma linha de comando assim:
avrdude -p m328p -c avrisp -P com3 -b 57600 -U flash:w:N.hex

Se for bootloader Uno:
avrdude -p m328p -c arduino-P com3 -b 115200 -U flash:w:N.hex
Avr fanboy

Offline dropes

  • Mini Robot
  • *
  • Mensagens: 2.198
Re: Introdução ao avr-gcc usando o AvrStudio [Mais timers/mood light]
« Responder #134 em: 27 de Julho de 2012, 00:11 »
Há versões diferentes de micros que o avrdude não reconhece por a assinatura não ser igual ao do micro selecionado.
Então é possível gravar no micro ignorando a assinatura acrescentando "-F" na linha de comandos do avrdude mas na verificação já dá erro.
Neste caso tem de se editar o ficheiro "avrdude.conf" e alterar onde diz "signature=" do respectivo micro e colocar a assinatura que estava a ser mal reconhecida.

obs: convém fazer uma cópia deste ficheiro antes de qualquer alteração nele

@Senso, estás a fazer um excelente trabalho neste tutorial, parabéns  :)