Introdução
A técnica de Modulação por Largura de Pulso (PWM) é fundamental para o controle de dispositivos eletrônicos, como motores e LEDs. No contexto dos microcontroladores, o PWM se destaca por sua eficiência e precisão, sendo amplamente utilizado em aplicações que exigem controle de velocidade, intensidade luminosa, entre outros. Este artigo aborda o conceito de PWM e sua aplicação prática utilizando o microcontrolador Franzininho C0.
Através deste tutorial, você aprenderá a configurar e utilizar o PWM no STM32, explorando suas principais características e modos de operação, com foco no controle de LEDs. Vamos detalhar o funcionamento do PWM, sua configuração no ambiente STM32CubeIDE e como aplicar esses conhecimentos em um projeto prático.
O que é PWM?
PWM (Modulação por Largura de Pulso) é uma técnica usada para controlar a duração de sinal que está ligado ou desligado. Essa técnica é essencial para controlar dispositivos como motores e LEDs.
Componentes Principais do PWM
- Ciclo de Trabalho (Duty Cycle): É a porcentagem do tempo em que o sinal PWM permanece LIGADO durante um período completo. Por exemplo, um ciclo de trabalho de 50% significa que o sinal está ligado pela metade do tempo e desligado pela outra metade.
- Frequência: É a velocidade com que o sinal PWM alterna entre LIGADO e DESLIGADO. É medida em Hertz (Hz).
- Resolução: Refere-se ao número de bits usados para representar o ciclo de trabalho. Maior resolução significa mais níveis de controle entre 0% e 100% do ciclo de trabalho.
Fórmulas Básicas
- Frequência PWM:
- Ciclo de Trabalho PWM:
Modo PWM no STM32
Como discutimos no tutorial sobre TIMERS (https://embarcados.com.br/franzininho-c0-aprenda-a-trabalhar-com-timers/), os temporizadores do STM32 podem operar em vários modos, incluindo o modo PWM. Seu funcionamento segue as etapas:
- O temporizador conta até um valor predefinido no registro de auto-reload (ARR).
- Quando a contagem atinge o ARR, o pino de saída do canal é colocado em nível ALTO.
- O pino de saída permanece ALTO até que a contagem atinja o valor do registro de captura/comparação (CCR).
- Quando a contagem atinge o valor do CCR, o pino de saída é colocado em nível BAIXO.
- Este ciclo se repete continuamente.
A forma de onda resultante é o sinal PWM. A frequência do PWM é determinada pelo relógio interno, pelo preescaler e pelo valor do ARR. O ciclo de trabalho é determinado pelo valor do CCR.
Estrutura dos Canais de Saída PWM no STM32
Cada canal de captura/comparação nos temporizadores STM32 possui:
- Registro de Captura/Comparação (CCR): Armazena o valor para comparação.
- Estágio de Entrada: Inclui filtros digitais e preescaladores.
- Estágio de Saída: Gera a forma de onda PWM.
Observe o diagrama abaixo
Fórmulas para STM32
- Frequência PWM:
- Ciclo de Trabalho PWM:
- Resolução PWM:
Modos PWM no STM32
A geração do sinal PWM pode ser feita de diferentes modos, sendo os modos alinhado à borda e alinhados ao centro mais usados.
- Modo alinhado à borda:
- No modo alinhado à borda, o PWM começa a contagem do início (borda) do período e conta até o valor definido no ARR.
- A transição de BAIXO para ALTO (ou vice-versa) acontece sempre nas bordas do ciclo de contagem, ou seja, no início ou no final do ciclo.
- É o modo mais simples e comum de PWM podendo ser configurado como contagem crescente ou decrescente.
- Modo alinhado ao centro:
- No modo alinhado ao centro, também conhecido como modo de contagem para cima e para baixo, o temporizador conta até o valor do ARR e depois conta para trás até zero.
- A transição de nível (ALTO para BAIXO ou BAIXO para ALTO) ocorre no meio do ciclo, o que pode resultar em menos ruído e interferência em aplicações sensíveis.
- Esse modo é útil quando uma saída simétrica e menos ruidosa é desejada.
Controle PWM na Franzininho C0
Neste exemplo, vamos controlar os LEDs conectados aos pinos PB6 e PB7 conforme o pinout da Franzininho C0 mostrado abaixo. Utilizaremos PWM para que o brilho dos LEDs seja ajustado gradualmente. O PWM será configurado com uma frequência de 1 kHz e uma largura de pulso variando de 0 a 1000.
Calculando valor Prescaler:
Antes de iniciar a configuração no CubeMX, podemos calcular o valor do Prescaler necessário. Utilizando a fórmula da frequência PWM, podemos determinar o valor do parâmetro Prescaler. Considerando que vamos usar uma frequência de PWM de 1 kHz e escolher o valor de ARR como 48, é importante selecionar um valor que seja múltiplo da frequência do clock, que no nosso caso é 48 MHz.
Configurando CubeMX:
- Abra STM32Cube , crie um novo projeto e selecione o microcontrolador de destino “STM32C011F6P6”.
- Vá para a página de configurações de relógio e em HCLK digite 48 MHz para a frequência de saída desejada do sistema. Pressione a tecla “Enter”, depois volte para a página de configuração dos pinos, selecione “Trace and Debug” e habilite “Serial Wire.
- Clique sobre o pino “PB6” e selecione “TIM1_CH3”.
- Clique sobre o pino “PB7” e selecione “TIM1_CH4”.
- Em “Timers”, selecione “TIM1”. Habilite a fonte de clock como “Internal Clock”. Para o Channel 3 e Channel 4, selecione “PWM Generation”. Defina o valor do Prescaler para 48-1 e o Counter Period para 1000-1.
- Ainda em TIM1, em parameter settings, observe as configurações da geração de PWM. Para esse exemplo deixaremos a configuração padrão.
- Por fim, gere o código em “Project” > “Generate Code”.
Código para controle PWM na Franzininho C0
- Em Core > Src > main.c, na função principal, int main, adicionaremos a função HAL_TIM_PWM_Start responsável por iniciar a geração PWM.
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3); // Inicia Timer 1 para geração de PWM no canais 3 (PB6, LED1)
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_4); // Inicia Timer 1 para geração de PWM no canais 4 (PB7, LED2)
- Vamos criar uma função chamada atualiza_largura_puslo_LEDS para ajustar a largura do pulso dos sinais PWM.
void atualiza_largura_puslo_LEDS(int start, int end, int step) {
for (int i = start; i != end; i += step) {
int LED1_pulse = i;
int LED2_pulse = 1000 - i;
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, LED1_pulse); // (PB6, LED1)
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_4, LED2_pulse); // (PB7, LED2)
HAL_Delay(1);
}
}
Essa função recebe três parâmetros que determinam como a largura do pulso vai mudar ao longo do tempo:
- start – o valor inicial para a variação do pulso
- end – o valor final do pulso
- step – o incremento ou decremento aplicado a cada iteração.
Em cada passo do loop, duas variáveis são definidas: LED1_pulse, que é simplesmente o valor atual de i, e LED2_pulse, que é 1000 – i. Esses valores representam as larguras de pulso para os dois LEDs, fazendo com que, à medida que LED1_pulse aumenta, LED2_pulse diminua, e vice-versa.
Para ajustar os pulsos de PWM dos LEDs, utiliza-se __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, LED1_pulse) que ajusta a largura do pulso do canal 3 do temporizador htim1 para LED1_pulse e __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_4, LED2_pulse) que ajusta a largura do pulso do canal 4 para LED2_pulse.
Em resumo, essa função cria um efeito de variação de brilho nos LEDs. Se start for menor que end e step for positivo, LED1 aumentará seu brilho enquanto LED2 diminuirá, e vice-versa. Se start for maior que end e step for negativo, o comportamento será o oposto.
- Lembre-se de declarar o protótipo da função
atualiza_largura_puslo_LEDSjuntamente aos demais protótipos ao início do código.
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM1_Init(void);
void atualiza_largura_puslo_LEDS(int start, int end, int step);- Agora, no loop principal while, dentro de int main, adicione o seguinte:
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
// Aumenta gradualmente a largura de pulso no LED1 e diminui no LED2
atualiza_largura_puslo_LEDS(0, 1000, 1);
// Diminui gradualmente a largura de pulso no LED1 e aumenta no LED2
atualiza_largura_puslo_LEDS(1000, 0, -1);
}
/* USER CODE END 3 */
- Na imagem abaixo, você pode ver o código que foi modificado.
Gravação:
Ao finalizar o código, vamos para a gravação. Nessa etapa você pode utilizar o ST-Link ou utilizar um cabo USB como apresentado em demais tutoriais desta série de artigos.
https://embarcados.com.br/serie/franzininho-c0-com-stm32cubeide
Funcionamento do controle PWM na Franzininho C0
Abaixo temos um vídeo mostrando o funcionamento do código criado neste exemplo. Perceba que conforme um LED aumenta seu brilho, o outro diminui.
Conclusão
Neste artigo você aprendeu conceitos importantes sobre o funcionamento PWM e descobriu como configurá-lo no Franzininho C0 por meio de um exemplo prático para controle de brilho de LEDs.






