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:
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 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