Temporizadores AVR – modo PWM-Parte II

série AVReste artigo está em continuação com o post PWM anterior. Aprenda a programar os temporizadores para operar no modo PWM! Então vamos começar!

Olá pessoal! Muito tempo não vejo! 🙂

no meu post anterior, discutimos os conceitos básicos de PWM. Vamos resumir primeiro:

  • PWM significa modulação por Largura De Pulso.
  • pode ser gerado comparando a forma de onda predeterminada com um nível de tensão de referência ou fazendo circuitos analógicos simples.
  • o ciclo de trabalho de uma forma de onda PWM é dado pela seguinte relação.
Ciclo de trabalho
  • Existem três modos de operação PWM – Rápido PWM, a Fase Correta PWM e de Frequência e de Fase Correta PWM
  • Como escolher temporizador, modo de funcionamento e comparar o modo de saída para gerar o desejado de PWM.
então agora, sem muito aborrecimento, vamos ver como implementá-lo usando os microcontroladores AVR. Antes de prosseguir, sugiro que você leia minhas postagens anteriores sobre temporizadores e PWM.

vamos fazer uma declaração de problema. Precisamos gerar um sinal PWM de 50 Hz com ciclo de trabalho de 45%.

Análise

Dado que

Frequency = 50 Hz

Em outras palavras, o período de tempo, T

T = T(on) + T(off) = 1/50 = 0.02 s = 20 ms

Também, dado que

Duty Cycle = 45%

Assim, a solução de acordo com a equação acima, obtemos

T(on) = 9 msT(off) = 11 ms

Agora, isto pode ser conseguido de duas maneiras:

  1. Utilizar o Temporizador no CTC Modo
  2. Utilizar o Temporizador no Modo PWM

Metodologia – CTC Modo

Ok, então eu não vou escrever qualquer código aqui (apenas o pseudo-código). Eu suponho que depois de ler meus posts anteriores, você é inteligente o suficiente para escrever um você mesmo! Vamos discutir apenas os conceitos.

em primeiro lugar, escolha um temporizador adequado. Para esta aplicação, podemos escolher qualquer um dos três temporizadores disponíveis no ATMEGA32. Escolha um prescaler adequado. Em seguida, configure o temporizador e prossiga como de costume. O problema está aqui é que você precisa atualizar o valor de comparação do ocrx register toda vez. Uma dessas maneiras é discutida no pseudo código fornecido abaixo.

isso é análogo ao tradicional Pisca-pisca LED, exceto o fato de que os tempos de ligar e desligar são diferentes.

Pseudo-Código

#include <avr/io.h>#include <avr/interrupt.h> uint8_t count = 0; // global counter // initialize timer, interrupt and variablevoid timerX_init(){ // set up timerX with suitable prescaler and CTC mode // initialize counter // initialize compare value // enable compare interrupt // enable global interrupts} // process the ISR that is firedISR (TIMERx_COMPA_vect){ // do whatever you want to do here // say, increment the global counter count++; // check for the global counter // if count == odd, delay required = 11 ms // if count == even, delay required = 9 ms // thus, the value of the OCRx should be constantly updated if (count % 2 == 0) OCRx = 9999; // calculate and substitute appropriate value else OCRx = 10999; // calculate and substitute appropriate value} int main(void){ // initialize the output pin, say PC0 DDRC |= (1 << 0); // initialize timerX timerX_init(); // loop forever while(1) { // do nothing }}

Agora, este é um método. E é muito ineficiente. Você pode aumentar sua eficiência escrevendo um código c melhor( em termos de sintaxe), no entanto, o conceito permanece o mesmo. Se você tiver qualquer outro método / conceito, você é muito bem-vindo para compartilhá-lo aqui! 🙂

UPDATE: um dos leitores de maxEmbedded, “coolpales” escreveu este código, e funcionou para ele.

observe que este código ainda não foi testado! Então, se algum de vocês está tentando, postar seus resultados aqui, eu ficaria feliz em vê-los! 🙂

metodologia-modo PWM

Ok, então agora vamos aprender sobre o modo PWM. O modo PWM no AVR é controlado por hardware. Isso significa que tudo, por tudo que quero dizer “tudo”, é feito pela CPU AVR. Tudo que você precisa fazer é inicializar e iniciar o temporizador, e definir o ciclo de trabalho! Fixe, não é?! Vamos aprender como!

aqui, eu usei Timer0 de ATMEGA32 para demonstração. Você pode escolher qualquer outro temporizador ou microcontrolador AVR também. Agora vamos dar uma olhada nos registros.

TCCR0-Timer / Counter0 Control Register

encontramos este registro no meu tutorial Timer0. Aqui, aprenderemos como definir bits apropriados para executar o temporizador no modo PWM.

 TCCR0 Register

TCCR0 Register

vamos discutir apenas os bits que são de interesse para nós agora.

  • Bit 6,3-WGM01: 0-Modo de Geração de formas de onda-esses bits podem ser definidos como “00” ou ” 01 ” dependendo do tipo de PWM que você deseja gerar. Aqui está a tabela look up.
     modo de Geração de forma de onda Descrição do Bit

    modo de Geração de forma de onda Descrição do Bit

  • Bit 5,4-COM01: 0-Compare o modo de saída de correspondência-esses bits são definidos para controlar o comportamento do pino de comparação de saída (OC0, pino 4 em ATMEGA32) de acordo com os bits WGM01:0. A tabela de consulta a seguir determina as operações do pino OC0 para o modo PWM rápido.
     Compare o modo de saída, modo PWM rápido

    Compare o modo de saída, modo PWM rápido

    agora vamos dar uma olhada nas formas de onda PWM rápidas. Explicação detalhada pode ser encontrada no meu tutorial anterior.

     rápido PWM

    rápido PWM

    agora deixe-me lembrá – lo que o AVR PWM é totalmente controlado por hardware, o que significa que até mesmo o temporizador comparar a operação é feita pela CPU AVR. Tudo o que precisamos fazer é dizer à CPU o que fazer quando ocorrer uma correspondência. Os pinos COM01: 0 entram em jogo aqui. Vemos que, definindo-o como “10” ou “11”, o pino de saída OC0 é definido ou limpo (em outras palavras, determina se o PWM está no modo invertido ou no modo não invertido).

    similarmente para PWM correto da fase, a tabela do olhar acima e as formas de onda vão como este.

    Comparar o Modo de Saída de Fase, Corrigir PWM Mode

    Comparar o Modo de Saída, Fase Correto Modo PWM

    Fase Correta PWM

    Fase Correta PWM

    Até aqui, a definição de COM01:0 para “10” e “11” determina o comportamento de OC0 pin. Como mostrado nas formas de onda, existem duas instâncias – uma durante a contagem ascendente e outra durante a contagem decrescente. O comportamento é claramente descrito na tabela de pesquisa.

    observe que OC0 é um pino de saída. Assim, os efeitos de WGM e COM não entrarão em jogo, a menos que o registro DDRx esteja definido corretamente. Consulte este tutorial para obter mais informações.

  • Bit 2: 0-CS02: 0-clock Select Bits – esses bits já são discutidos no tutorial Timer0.

OCR0 – Output Compare Register

encontramos até mesmo este registro no meu tutorial Timer0. Usamos esse registro para armazenar o valor de comparação. Mas quando usamos Timer0 no modo PWM, o valor armazenado nele atua como o ciclo de trabalho (obviamente!). Na declaração do problema, é dado que o ciclo de trabalho é de 45%, o que significa

OCR0 = 45% of 255 = 114.75 = 115

e é isso! Agora estamos prontos para escrever um código para isso! 🙂

Editar: Nota

o código a seguir discute como criar um sinal PWM de um ciclo de trabalho desejado. Se você deseja alterar sua frequência, você precisa alterar o valor superior, o que pode ser feito usando o registro ICRx (que não é suportado por Temporizadores de 8 bits). Para Timer1 de 16 bits, pode ser variado usando ICR1A. vou discutir sobre isso em breve quando discutirmos sobre servo controle.

Código

então aqui vai o código. Para saber mais sobre as operações de porta de E / S no AVR, veja isso. Para saber sobre manipulações de bits, veja isso. Para saber como usar o AVR Studio 5, Veja isso. Para saber como esse código está estruturado, veja a postagem anterior do TIMER0.

#include <avr/io.h>#include <util/delay.h>void pwm_init(){ // initialize TCCR0 as per requirement, say as follows TCCR0 |= (1<<WGM00)|(1<<COM01)|(1<<WGM01)|(1<<CS00); // make sure to make OC0 pin (pin PB3 for atmega32) as output pin DDRB |= (1<<PB3);} void main(){ uint8_t duty; duty = 115; // duty cycle = 45% of 255 = 114.75 = 115 // initialize timer in PWM mode pwm_init(); // run forever while(1) { OCR0 = duty; }}

Declaração de problema

então agora, vamos pegar outra declaração de problema. Este vai ser um material mais prático ao contrário do anterior!

vamos pegar o pisca-pisca LED tradicional onde precisamos piscar um LED em uma frequência específica. Mas Ei, espere, não discutimos isso há muito tempo neste post (role para baixo no final)? Hmm, então vamos modificá-lo para incorporar PWM. Ao contrário do tradicional Pisca-pisca LED (onde os LEDs estão ligados ou desligados), vamos fazê-lo brilhar no brilho máximo e, em seguida, diminuir lentamente seu brilho até atingir zero e, em seguida, aumentar novamente seu brilho lentamente até que se torne máximo.

análise e Código

então, como fazemos isso? Sim, você adivinhou certo! Diminua o ciclo de trabalho lentamente de 255 para zero e, em seguida, aumente-o de zero para 255. Dependendo do ciclo de trabalho, a tensão aplicada ao LED varia e, portanto, o brilho. A fórmula a seguir fornece a relação entre tensão e ciclo de trabalho.

 equação V_out

então aqui vai o código. Eu não vou explicar, você pode decodificá-lo sozinho. Para saber mais sobre as operações de porta de E / S no AVR, veja isso. Para saber sobre manipulações de bits, veja isso. Para saber como usar o AVR Studio 5, Veja isso. Para saber como esse código está estruturado, veja a postagem anterior do TIMER0.

// program to change brightness of an LED// demonstration of PWM #include <avr/io.h>#include <util/delay.h> // initialize PWMvoid pwm_init(){ // initialize timer0 in PWM mode TCCR0 |= (1<<WGM00)|(1<<COM01)|(1<<WGM01)|(1<<CS00); // make sure to make OC0 pin (pin PB3 for atmega32) as output pin DDRB |= (1<<PB3);} void main(){ uint8_t brightness; // initialize timer0 in PWM mode pwm_init(); // run forever while(1) { // increasing brightness for (brightness = 0; brightness < 255; ++brightness) { // set the brightness as duty cycle OCR0 = brightness; // delay so as to make the user "see" the change in brightness _delay_ms(10); } // decreasing brightness for (brightness = 255; brightness > 0; --brightness) { // set the brightness as duty cycle OCR0 = brightness; // delay so as to make the user "see" the change in brightness _delay_ms(10); } // repeat this forever }}

então aqui termina meu outro tutorial muito aguardado e longo! Proximo.. Comunicação Serial! Vemo-nos por aí!! 🙂

e sim, se você tiver alguma sugestão, dúvida, crítica construtiva, etc, Você é muito bem-vindo para soltar uma nota abaixo! Inscreva-se no meu blog ou pegue os Feeds RSS para ficar atualizado!

Write a Comment

O seu endereço de email não será publicado.