quarta-feira, 20 de maio de 2015

Ajustando a frequência dos PWMs do arduino Leonardo parte 2

Fazendo uma abordagem mais completa, esse post visa completar o anterior que fala sobre o mesmo assunto.

Desta vez, a intenção é definir a frequência de 4 pinos PWM. A motivação para este post vem para ser usado em projetos em que seja necessário ter uma frequência diferente da padrão dos pinos do arduino (490 Hz para os pinos 5, 6, 9, 10, 13 e 980 Hz para os pinos 3 e 11), como por exemplo o acionamento de motores DC sem que sejam gerados ruídos audíveis ou para gerar sons com certos tons, que são definidos cada um por uma certa frequência.

Nesse caso, usaremos os pinos 5, 6, 11 e 13 do arduino Leonardo. Cada pino na sua função de PWM, porém, é controlado por registradores comparadores diferentes, e esses registradores estão cada um vinculados a um dos timers do microcontrolador do arduino. Mas não temos um registrador apenas em cada pino, alguns deles possuem 2 registradores e podemos configurar com qual deles queremos trabalhar. Podemos ver essas informações observando no esquema elétrico do arduino Leonardo:

Peguemos o pino IO 11 do arduino, associado ao PB7 do microcontrolador ATMEGA 32u4 como exemplo. Nas suas características internas, temos as seguintes informações: (PCINT7 /OC0A /OC1C /#RTS). OC0A e OC1C são as saídas relacionadas aos registradores OCR0A e OCR1C, vinculados aos timer 0 e 1 respectivamente, logo então, podemos definir qual dos 2 definirá as características do PWM no pino 11, ou até fazê-los trabalharem juntos. A vantagem de podermos fazer essa escolha se dará pelo fato de não precisarmos editar os parâmetros do timer 0, pois as funções millis(), micros(), delay() e delayMicroseconds() estão atreladas a esse timer, e, ao mudar as configurações do timer 0, estaremos mudando os parâmetros de todas essas funções.

Também temos outras bibliotecas que utilizam os parâmetros dos timers, como a biblioteca Servo (que utiliza parâmetros do timer 1) e a biblioteca MsTimer2 (que utiliza parâmetros do timer 4). Logo, caso você precise utilizar alguma dessas bibliotecas, evite manusear os timers em questão.

Podemos configurar o PWM para trabalhar de duas formas: em sngle-slope ou em dual-slope.
Os timers trabalham como contadores, que vão somando valores nos seus registradores conforme o clock interno do microcontrolador, e o que ocorre quando o contador atinge o seu valor máximo é o que difere as duas formas de PWM.

Single-Slope: No caso do single-slope, quando o contador atinge o valor máximo, o mesmo é zerado e volta a contar do zero. Quando temos um valor de comparação no registrador, o valor de saída é alterado quando o valor do contador é igual ao valor do registrador e quando o contador volta a zero, como no exemplo abaixo:
Os valores do PWM 1 e 2 vão ao estado baixo quando o valor de referência é igual ao do contador e vão ao estado alto quando o contador volta para zero.

Double-Slope: No caso do double-slope, o contador ao chegar no valor máximo começa a decrescer, ao invés de voltar a zero, como no single-slope. Assim, os valores de saída são alterados quando o contador tem o mesmo valor dos registradores na subida e na descida.
Os valores de PWM 1 e 2 são alterados vão para o estado alto quando o contador atinge o valor do registrador na borda de descida, e vão para o estado baixo quando o contador atinge o valor do registrador na borda de subida.


Para o nosso exemplo, configuraremos os pinos 5, 6, 11 e 13 para trabalhar com uma frequência de 31,3 kHz, configurados no modo dual-slope. Os registradores usados para cada pino serão o OCR3A do timer 3 para o pino 5, o OCR4D do timer 4 para o pino 6, o OCR1C do timer 1 para o pino 11 e o OCR4A do timer 4 para o pino 13. Nota-se que para o pino 6 e 13 serão usados registradores relacionados ao mesmo timer, logo as configurações dos 2 são as mesmas.

Os timers 1 e 3 são idênticos em suas características, então as suas configurações serão relativamente parecidas.

Configurando timer 1 e 3:


Os nomes dos bits a seguir são relacionados ao timer 1, mas a nomenclatura para o timer 3 muda em detalhes como, por exemplo o bit WGM10 para o timer 1, será o WGM30 para o timer 3.
Abaixo temos em detalhes os registradores de controle do timer 1:




Para os valores COM1A0 e COM1A1,  COM1B0 e COM1B1 e COM1C0 e COM1C1 teremos as configurações para o registrador OCR1A, OCR1B e OCR1C respectivamente. As configurações são selecionadas conforme a tabela abaixo:



Os valores dos WGM10, WGM11, WGM12 e WGM13 definirão se trabalharemos em single-slope ou dual-slope, com 8, 9 ou 10 bits de contador ou em CTC (clear time on compare) conforme a tabela abaixo:


Os valores de CS10, CS11 e CS12 definirão a divisão do valor da frequência máxima escolhida, 31,3kHz para o modo dual-slope (PWM phase correct) e 62,5 kHz para o single-slope (fast PWM):



Configurando timer 4:


Usando o timer 4, podemos chegar a uma frequência de até 96 MHz, utilizando o registrador de controle PLL (PLLFRQ), mas no nosso caso esse registrador não será alterado. Caso for usar esse registrador, as comunicações USB podem ser comprometidas.

As configurações para o timer 4 são um pouco diferentes em comparação às dos timers 1 e 3. Teremos que configurar 4 registradores para esse timer. 
Começaremos pelos TCCR4A e TCCR4C:



Antes de tudo, temos que habilitar os bits PWM4A, PWM4B e PWM4C, dependendo dos registradores que queremos usar, e depois utilizar as configurações abaixo para habilitar os registradores:


Para habilitar os registradores OCR4B e OCR4D, é só usar a tabela acima, considerando a letra relacionada ao registrador.


No TCCR4B, escolheremos a divisão da frequência máxima escolhida conforme a tabela:



No TCCR4D, escolheremos a forma do PWM dos registradores ligados ao timer 4 conforme as opções abaixo:





Abaixo segue um exemplo de código, que acende 4 leds com sinal PWM com frequência de 31,5 kHz. O sinal PWM será definido de acordo com 2 entradas analógicas distintas na porta A0 e A1.

 /*****************************************
 Timers 1, 3 e 4 configurados para trabalhar com uma frequência de PWM de 31,3 kHz

 Os pinos 13, 11, 6 e 5 estão cada um ligados a um registrador um timer. O valor atribuido
 aos registradores será equivalente ao sinal de PWM da porta correspondente.

 Alguns pinos não trabalham tão bem com a função analogWrite() depois das alterações de 
 parâmetros dos timers, sendo assim melhor não utilizá-la.
Editado em 19/05/2015 
 *******************************************/
 
 #define PWM11  OCR1C //ALI-M2
 #define PWM13  OCR4A //BLI-M1
 #define PWM6  OCR4D //ALI-M1
 #define PWM5  OCR3A //BLI-M2
 #define frequencia  1 // 31,3 kHz

void setup() {
  // put your setup code here, to run once:
  pinMode(13, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(A0, INPUT);
  pinMode(A1, INPUT);
  
TCCR1A= 0x09; //Configurado canal OCR1C para funcionar como comparador e PWM com 8 bits de resolução
TCCR1B= frequencia; // frequencia definida no #define - 31,3 kHz

TCCR3A = 0x81; //Configurado canal OCR3A para funcionar como comparador e PWM com 8 bits de resolução
TCCR3B= frequencia; // frequencia definida no #define - 31,3 kHz 

TCCR4A = 0x82; //Configurado canal OCR4A para funcionar como comparador e habilita o mesmo
TCCR4B = frequencia; // frequencia definida no #define - 31,3 kHz
TCCR4C = 0x89; //Configurado canal OCR4D para funcionar como comparador e habilita o mesmo
TCCR4D = 1; //Configurada a forma de PWM (fast ou normal)

PWM13 = 0;
PWM11 = 0;
PWM6 = 0;
PWM5 = 0;
}

void loop() {
  // put your main code here, to run repeatedly:
    
  PWM13 = map(analogRead(A0), 0, 1023, 0, 255); 
  PWM11 = map(analogRead(A0), 0, 1023, 0, 255); 
  PWM6 = map(analogRead(A1), 0, 1023, 0, 255); 
  PWM5 = map(analogRead(A1), 0, 1023, 0, 255);  

}


Referências: Fast PWM on Arduino Leonardo e ATmega 32u4 Datasheet

quinta-feira, 14 de maio de 2015

Ajustando a frequência dos PWMs do arduino Leonardo

Usando o PWM dos pinos de arduino, podemos modular o duty cicle de um sinal de saída, mas, para algumas aplicações, também se torna necessária a mudança da frequência do sinal de saída (e.g. acionamento de um motor com uma frequência inaudível).

Para isso, precisamos mudar alguns parâmetros dos timers para conseguir mudar o valor da frequência de saída da porta desejada. No arduino Leonardo, temos as seguintes linhas de código e as frequências obtidas para cada pino com saída PWM.

Timer Configurado Código de programação Pino 13 Pino 11 Pino 10 Pino 9 Pino 6 Pino 5 Pino 3
Default - 490 Hz 980 Hz 490 Hz 490 Hz 490 Hz 490 Hz 980 Hz
Timer 0 TCCR0B = TCCR0B & 0xF8 | 0x01 490 Hz 625000 Hz 490 Hz 490 Hz 490 Hz 490 Hz 62500 Hz
Timer 1 TCCR1B = TCCR1B & 0xF8 | 0x01 490 Hz 980 Hz 31400 Hz 31400 Hz 490 Hz 490 Hz 980 Hz
Timer 3 TCCR3B = TCCR3B & 0xF8 | 0x01 490 Hz 980 Hz 490 Hz 490 Hz 490 Hz 31300 Hz 980 Hz
Timer 4 TCCR4B = TCCR4B & 0xF8 | 0x01 31400 Hz 980 Hz 490 Hz 490 Hz 31400 Hz 490 Hz 980 Hz
* valores aproximados obtidos por um osciloscópio.

Com isso conseguimos verificar qual timer é responsável pela frequência de cada pino.

Podemos conseguir outros valores de frequência para cada  pino alterando a parte final do código para cada timer (e.g. TCCRXB = TCCRXB & 0xF8 | 0x0N, onde X é o número do respectivo timer e N é o valor de divisão do prescaler do respectivo timer).


Valores 0x0N Pinos 5, 6, 9, 10 e 13 Pinos 3 e 11
0x01 31400 Hz 62500 Hz
0x02 15600 Hz 7810 Hz
0x03 7810 Hz 980 Hz
0x04 3910 Hz 245 Hz
0x05 1950 Hz 61,3 Hz
0x06 980 Hz 1,91 Hz
0x07 490 Hz 1,92 Hz
0x08 245 Hz -
0x09 123 Hz -
0x0A 61,7 Hz -
0x0B 30,5 Hz -
0x0C 15,3 Hz -
0x0D 7,63 Hz -
0x0E 3,81 Hz -
0x0F 1,92 Hz -
*valores aproximados obtidos por um osciloscópio.

Lembrando que os pinos citados são todos em relação ao arduino Leonardo, outros arduinos podem ter tabelas diferentes. 

quarta-feira, 13 de maio de 2015

Controlando um motor DC utilizando um módulo L298N pelo arduino Leonardo



Utilizando o módulo L298N como este aqui, podemos controlar o sentido e a velocidade de rotação de até dois motores DC com o mesmo módulo. Esta postagem mostra como fazer o controle de apenas um motor, mas o código pode ser usado como base para controlar 2 motores.


Primeiramente, montemos o hardware com um botão (para controlar o sentido da rotação) e um potenciômetro (para modular um sinal PWM para controlar a velocidade do motor).



Podem-ser escolhidos outros pinos diferentes do apresentado, desde que a entrada para o sinal do potenciômetro seja analógica e as saídas para o motor tenham a função de PWM (não esquecer de mudar a pinagem no código!).


A seguir temos o código para este projeto.