- O que é um sinal PWM?
- Programar PIC para gerar PWM em pinos GPIO
- Diagrama de circuito
- Simulação
- Configuração de hardware para controlar servo motor usando microcontrolador PIC
A geração de sinal PWM é uma ferramenta vital em todo arsenal de engenheiros embarcados, eles são muito úteis para muitas aplicações, como controlar a posição do servo motor, trocar alguns CIs eletrônicos de potência em conversores / inversores e até mesmo para um simples controle de brilho de LED. Em microcontroladores PIC, os sinais PWM podem ser gerados usando os módulos Compare, Capture e PWM (CCP) definindo os registros necessários, já aprendemos como fazer isso no tutorial PIC PWM. Mas há uma desvantagem considerável com esse método.
O PIC16F877A pode gerar sinais PWM apenas nos pinos RC1 e RC2, se usarmos os módulos CCP. Mas podemos encontrar situações em que precisamos de mais pinos para ter a funcionalidade PWM. Por exemplo, no meu caso, quero controlar 6 servo motores RC para meu projeto de braço robótico para o qual o módulo CCP é impossível. Nesses cenários, podemos programar os pinos GPIO para produzir sinais PWM usando módulos de temporizador. Desta forma, podemos gerar tantos sinais PWM com qualquer pino necessário. Existem também outros hacks de hardware como usar um IC multiplexador, mas por que investir em hardware quando o mesmo pode ser alcançado através da programação. Portanto, neste tutorial, aprenderemos como converter um pino PIC GPIO em um pino PWM e para testá-lo iremos simular em proteus com osciloscópio digital e tambémcontrole a posição do servo motor usando o sinal PWM e varie seu ciclo de trabalho variando um potenciômetro.
O que é um sinal PWM?
Antes de entrarmos em detalhes, vamos revisar um pouco o que são sinais PWM. A modulação por largura de pulso (PWM) é um sinal digital que é mais comumente usado em circuitos de controle. Este sinal é definido como alto (5v) e baixo (0v) em um tempo e velocidade predefinidos. O tempo durante o qual o sinal permanece alto é chamado de “tempo de ativação” e o tempo durante o qual o sinal permanece baixo é chamado de “tempo de desligamento”. Existem dois parâmetros importantes para um PWM, conforme discutido abaixo:
Ciclo de trabalho do PWM
A porcentagem de tempo em que o sinal PWM permanece ALTO (no tempo) é chamada de ciclo de serviço. Se o sinal estiver sempre LIGADO, ele está em 100% do ciclo de trabalho e se estiver sempre desligado, ele está em 0% do ciclo de trabalho.
Ciclo de trabalho = tempo para ligar / (tempo para ligar + tempo para desligar)
Nome variável |
Refere-se a |
PWM_Frequency |
Frequência do sinal PWM |
T_TOTAL |
Tempo total gasto para um ciclo completo de PWM |
TONELADA |
Na hora do sinal PWM |
T_OFF |
Tempo desligado do sinal PWM |
Duty_cycle |
Ciclo de trabalho do sinal PWM |
Então agora, vamos fazer as contas.
Esta é a fórmula padrão em que a frequência é simplesmente o recíproco do tempo. O valor da frequência deve ser decidido e definido pelo usuário com base nos requisitos de sua aplicação.
T_TOTAL = (1 / PWM_Frequency)
Quando o usuário altera o valor do ciclo de trabalho, nosso programa deve ajustar automaticamente o tempo T_ON e o tempo T_OFF de acordo com isso. Portanto, as fórmulas acima podem ser usadas para calcular T_ON com base no valor de Duty_Cycle e T_TOTAL.
T_ON = (Duty_Cycle * T_TOTAL) / 100
Já que o tempo total do sinal PWM para um ciclo completo será a soma do tempo de ativação e desativação. Podemos calcular o tempo desligado T_OFF conforme mostrado acima.
T_OFF = T_TOTAL - T_ON
Com essas fórmulas em mente, podemos começar a programar o microcontrolador PIC. O programa envolve o módulo de temporizador PIC e o módulo PIC ADC para criar um sinal PWM baseado em um ciclo de trabalho variável de acordo com o valor ADC do POT. Se você é novo no uso desses módulos, é altamente recomendável ler o tutorial apropriado clicando nos hiperlinks.
Programar PIC para gerar PWM em pinos GPIO
O programa completo para este tutorial pode ser encontrado na parte inferior do site, como sempre. Nesta seção, vamos entender como o programa é realmente escrito. Como todos os programas, começamos definindo os bits de configuração. Usei a opção de visualizações de memória para defini-la para mim.
// CONFIG #pragma config FOSC = HS // Bits de seleção do oscilador (oscilador HS) #pragma config WDTE = OFF // Bit de ativação do temporizador Watchdog (WDT desativado) #pragma config PWRTE = OFF // Bit de ativação do temporizador de inicialização (PWRT desabilitado) #pragma config BOREN = LIGADO // Bit de habilitação de redefinição de Brown-out (BOR habilitado) #pragma config LVP = DESLIGADO // Bit de habilitação de programação serial em circuito interno (RB3 é E / S digital), HV on MCLR deve ser usado para programação) #pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off) #pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; toda a memória do programa pode ser gravada pelo controle EECON) #pragma config CP = OFF // Bit de proteção de código de memória de programa Flash (proteção de código desativada) // #pragma config instruções devem preceder as inclusões de arquivos de projeto. // Use enums do projeto em vez de #define para ON e OFF. #incluir
Então mencionamos a frequência do clock usada no hardware, aqui meu hardware usa cristal de 20MHz, você pode inserir o valor baseado no seu hardware. Seguido por isso está o valor da frequência do sinal PWM. Uma vez que meu objetivo aqui é controlar um servo motor RC de hobby que requer uma frequência PWM de 50 Hz, eu configurei 0,05 KHz como o valor de frequência, você também pode alterar isso com base nos requisitos de sua aplicação.
#define _XTAL_FREQ 20000000 #define PWM_Frequency 0,05 // em KHz (50Hz)
Agora que temos o valor da frequência, podemos calcular o T_TOTAL usando as fórmulas discutidas acima. O resultado é mergulhado em 10 para obter o valor do tempo em milissegundos. No meu caso, o valor de T_TOTAL será de 2 milissegundos.
int T_TOTAL = (1 / PWM_Frequency) / 10; // calcula o tempo total a partir da frequência (em milissegundos)) // 2mseg
Em seguida, inicializamos os módulos ADC para ler a posição do potenciômetro, conforme discutido em nosso tutorial ADC PIC. A seguir temos a rotina de serviço Interrupt que será chamada todas as vezes, o temporizador estourou, voltaremos a isso mais tarde, por enquanto vamos verificar a função principal.
Dentro da função principal configuramos o módulo temporizador. Aqui, configurei o módulo Timer para estouro a cada 0,1 ms. O valor para o tempo pode ser calculado usando as fórmulas abaixo
RegValue = 256 - ((Atraso * Fosc) / (Prescalar * 4)) atraso em seg e Fosc em hz
No meu caso para um delay de 0,0001 segundos (0,1ms) com prescalar de 64 e Fosc de 20MHz o valor do meu registro (TMR0) deve ser 248. Então a configuração fica assim
/ ***** Configuração da porta para temporizador ****** / OPTION_REG = 0b00000101; // Timer0 com freq externa e 64 como prescalar // Também habilita PULL UPs TMR0 = 248; // Carrega o valor do tempo para 0,0001s; delayValue pode estar entre 0-256 somente TMR0IE = 1; // Habilita o bit de interrupção do temporizador no registro PIE1 GIE = 1; // Habilita a interrupção global PEIE = 1; // Habilite a interrupção periférica / *********** ______ *********** /
Em seguida, temos que definir a configuração de entrada e saída. Aqui, estamos usando o pino AN0 para ler o valor ADC e os pinos PORTD para emitir os sinais PWM. Portanto, inicie-os como pinos de saída e torne-os baixos usando as linhas de código abaixo.
/ ***** Configuração da porta para E / S ****** / TRISD = 0x00; // Instrui o MCU que todos os pinos na PORTA D têm saída PORTD = 0x00; // Inicialize todos os pinos para 0 / *********** ______ *********** /
Dentro do loop while infinito, temos que calcular o valor de on time (T_ON) do ciclo de trabalho. A no tempo e dever ciclo varia em função da posição da panela de modo que fazê-lo repetidamente dentro do tempo do circuito como mostrado abaixo. 0,0976 é o valor que deve ser multiplicado por 1024 para obter 100 e para calcular T_ON multiplicamos por 10 para obter o valor em milissegundos.
enquanto (1) { POT_val = (ADC_Read (0)); // Lê o valor de POT usando ADC Duty_cycle = (POT_val * 0,0976); // Mapeia 0 a 1024 a 0 a 100 T_ON = ((Ciclo_de_dutividade * T_TOTAL) * 10/100); // Calcular On Time usando a unidade das fórmulas em milissegundos __delay_ms (100); }
Uma vez que o cronômetro está definido para transbordar a cada 0,1 ms, a rotina de serviço de interrupção do cronômetro ISR será chamada a cada 0,1 ms. Dentro da rotina de serviço, usamos uma variável chamada contagem e a incrementamos a cada 0,1 ms. Dessa forma, podemos controlar o tempo. Para saber mais sobre interrupções no microcontrolador PIC, siga os links
if (TMR0IF == 1) // O sinalizador do temporizador foi acionado devido ao estouro do temporizador -> definido para estouro a cada 0,1 ms { TMR0 = 248; // Carrega o valor do temporizador TMR0IF = 0; // Limpa a contagem do sinalizador de interrupção do temporizador ++; // Contar incrementos para cada 0,1 ms -> contagem / 10 dará o valor da contagem em ms }
Finalmente, é hora de alternar o pino GPIO com base no valor de T_ON e T_OFF. Temos a variável de contagem que controla o tempo em milissegundos. Então usamos essa variável para verificar se o tempo está abaixo do tempo , se sim então mantemos o pino GPIO ligado, senão o desligamos e o mantemos desligado até que o novo ciclo comece. Isso pode ser feito comparando-o com o tempo total de um ciclo PWM. O código para fazer o mesmo é mostrado abaixo
if (count <= (T_ON)) // Se o tempo for menor do que no tempo RD1 = 1; // Liga o GPIO senão RD1 = 0; // Caso contrário, desligue o GPIO if (count> = (T_TOTAL * 10)) // Mantenha-o desligado até que um novo ciclo comece count = 0;
Diagrama de circuito
O diagrama de circuito para gerar PWM com pino GPIO do microcontrolador PIC é realmente simples, basta ligar o PIC com oscilador e conectar o potenciômetro ao pino AN0 e o servo motor ao pino RD1, podemos usar o pino GPIO para obter o sinal PWM, eu selecionei RD1 apenas fora do acaso. Tanto o potenciômetro quanto o servo motor são alimentados por 5 V, que é regulado a partir do 7805 conforme mostrado abaixo no diagrama do circuito.
Simulação
Para simular o projeto usei meu software proteus. Construa o circuito mostrado abaixo, vincule o código à sua simulação e execute-o. Você deve obter um sinal PWM no pino RD1 GPIO de acordo com nosso programa e o ciclo de trabalho do PWM deve ser controlado com base na posição do potenciômetro. O GIF abaixo mostra como o sinal PWM e o servo motor respondem quando o valor ADC é alterado através do potenciômetro.
Configuração de hardware para controlar servo motor usando microcontrolador PIC
Minha configuração completa de hardware é mostrada abaixo. Para as pessoas que estão seguindo meus tutoriais, esta placa deve parecer familiar, é a mesma que usei em todos os meus tutoriais até agora. Você pode consultar o tutorial LED piscando se estiver interessado em saber como eu o construo. Caso contrário, basta seguir o diagrama de circuito acima e tudo deve funcionar bem.
Carregue o programa e varie o potenciômetro e você deverá ver o servo mudando a posição com base na posição do potenciômetro. O funcionamento completo do projeto é mostrado no vídeo fornecido no final desta página. Espero que você tenha entendido o projeto e gostado de construir, se você tiver pedidos, fique à vontade para postá-los no fórum e eu tentarei o meu melhor para responder.
Estou planejando levar este projeto adiante adicionando opções para controlar vários servo motores e, assim, construir um braço robótico a partir dele, semelhante ao Arduino Robotic Arm que já construímos. Então, até então, até lá!