Exemplo detalhado de experimento de saída PWM

índice

Experiência de saída PWM

O princípio de funcionamento do PWM (considere a contagem como exemplo)

Experiência abrangente de remapeamento de pinos PWM e AFIO

Instruções de função da biblioteca

Pontos de conhecimento básico de configuração PWM

Remapeamento da função da porta GPIO

O significado da divisão do relógio

Quais são os dois modos de comparação de PWM?

A função do registro de pré-carga (TIMx_CCMR1)

Qual é a polaridade de saída do PWM?

Considerações de configuração PWM

Como definir o ciclo de trabalho?

Etapas de configuração da função de biblioteca

Etapa 1: Habilite o clock do barramento periférico de GPIO / AFIO / TIM

Etapa 2: configurar o remapeamento das funções dos pinos

Etapa 3: configurar as propriedades básicas do cronômetro

Etapa 4: configurar o modo de saída PWM

Etapa 5: configurar o registro de pré-carga

Etapa 6: habilitar formalmente a função TIM

Exemplo de código abrangente

Main.c

Led.c

Led.h.

Timer.c

Timer.h

resultado da operação


Experiência de saída PWM

O princípio de funcionamento do PWM (considere a contagem como exemplo)

 

O valor no registro CCRX é usado para comparar com o valor no contador Quando o valor no contador CNT é igual ao registro CCRX, o nível do sinal de saída do temporizador geral muda. Finalmente, quando o contador conta até MAX (o valor em ARR), (a "interrupção de atualização" também pode ser acionada) retorna imediatamente a 0 e reinicia a contagem progressiva.

Experiência abrangente de remapeamento de pinos PWM e AFIO

Instruções de função da biblioteca

Nome da função da biblioteca

Recursos

RCC_APB1PeriphClockCmd () / RCC_APB2PeriphClockCmd ()

Habilitar relógio periférico de barramento APB

GPIO_Init ()

Função de inicialização GPIO

GPIO_PinRemapConfig ()

Função de remapeamento de porta GPIO

TIM_ARRPreloadConfig ()

Habilite ou desabilite o registro de pré-carga do TIMx no ARR

 

TIM_TimeBaseInit ()

Inicializar cronômetro

TIM_OCInit ()

Inicializar parâmetros de comparação

TIM_Cmd ()

Ativar temporizador

TIM_SetCompare2 ()

Altere constantemente o valor de comparação CCRx para alcançar diferentes efeitos do ciclo de trabalho

Pontos de conhecimento básico de configuração PWM

Remapeamento da função da porta GPIO

Em primeiro lugar, devemos ser claros sobre para qual pino queremos remapear a função TIM:

 

 

Aprendemos com o remapeamento da função de multiplexação GPIO da AFIO que quando usamos a função "remapeamento parcial TIM3 parcial", podemos mapear o pino TIM3_CH3 de TIM3 para o pino PB5 e usá-lo para acionar o LED0 para exibir a função PWM .

Neste momento, os seguintes pontos devem ser observados:

① O modo de saída GPIO deve ser configurado como "saída push-pull multiplexada". Conforme mostrado na figura abaixo, apenas quando configurado como multiplexado os sinais de outras funções não IO podem ser emitidos por meio deste pino GPIO. Somente quando configurado como push-pull , Pode produzir níveis altos e baixos sem depender do nível externo, e a saída push-pull atende aos requisitos de saída da função TIM3.

 

 

② Configure a função de remapeamento dos pinos GPIO

Significado e função: A função de TIM3 não pertence ao PB5, mas podemos saber que "TIM3 pode remapear a função para o pino PB5" quando remapeamos a função TIM3 para o pino PB5, devemos habilitar Relógio AFIO e registro de remapeamento de configuração.

GPIO_InitTypeDef GPIO_InitStructure;  
  
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);    //使能定时器3时钟  
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB  | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟  
  
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射  TIM3_CH2->PB5      
  
  //设置该引脚为复用输出功能,输出TIM3 CH2的PWM脉冲波形 GPIOB.5  
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH2  
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出  
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO  

O significado da divisão do relógio

Ao configurarmos o TIM, chamaremos esta função: TIM_TimeBaseInit ();

Dentre eles, seu parâmetro de estrutura configurará o atributo "TIM_ClockDivision".

Vamos primeiro entender como TIMER3 é obtido como um relógio dividido por PSC:

 

 

Nosso experimento usa o clock do barramento APB1 (a frequência do clock AHB é 72 MHz). Notamos que em AHB-> APB1 divider-> APB1, se o fator de divisão do prescaler APB1 for 1, então a frequência do clock do TIMXCLK é " TIMCLK = APB1 = AHB ", se o fator de divisão do prescaler APB1 for N (N não é 1), então a frequência de clock de TIMXCLK é" TIMCLK = 2xAPB1 = 2xAHB / N ".

Mas quando chamamos a função de biblioteca de origem do relógio de inicialização fornecida por ST, o fator de divisão padrão do divisor APB1 é 2, então o TIMXCLK final = 2xAPB1 = 2xAHB / 2 = AHB.

A divisão do relógio aqui representa o coeficiente do prescaler de APB1.

Quais são os dois modos de comparação de PWM?

 

 

A função do registro de pré-carga (TIMx_CCMR1)

 

 

Quando atualizamos o valor de ARR durante a operação, se OC1PE no registro de pré-carga for definido como 1, o valor ARR será colocado no contador no próximo ciclo; se for definido como 0, o valor ARR será carregado no contador imediatamente.

Qual é a polaridade de saída do PWM?

 

 

Considerações de configuração PWM

Uma vez que emitimos o sinal PWM para o pino PB5, não precisamos configurar os atributos do pino GPIO como de costume e atribuir um nível específico ao PB5. Como PB5 não é um pino IO diferente, seu estado é determinado pelo nível de saída PWM que ele recebe.

Como definir o ciclo de trabalho?

Nós apenas definimos as seguintes partes em timer.c:

TIM_OC_InitStructure.TIM_OCMode = TIM_OCMode_PWM1; // 选择PWM输出模式1——当计数器值小于比较值时输出有效电平;当计数器值大于比较值时输出无效电平  
TIM_OC_InitStructure.TIM_OutputState = TIM_OutputState_Enable; // PWM输出模式使能  
TIM_OC_InitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; // 配置有效电平——高电平有效  
TIM_OC2Init(TIM3, &TIM_OC_InitStructure); // 配置PWM输出比较的属性  

 

Este código apenas explica "como definir as propriedades de saída PWM das 2 portas do TIMER3 (modo PWM, nível efetivo, habilitar ou desabilitar)", não definimos o "valor de comparação", então o ciclo de trabalho padrão é É 100%.

Precisamos definir o valor de comparação CCRx após configurar o PWM do temporizador. O código é o seguinte:

TIM_SetCompare2(TIM3, CompareValue);  // 用于修改CCRx的值进而修改PWM占空比

 

Aqui eu o configuro na função principal, que é usada para modificar continuamente o valor de comparação CCRx para produzir um efeito de luz LED com uma mudança gradual no brilho. Da mesma forma, também podemos modificar o valor de ARR para ajustar o período PWM. As funções de biblioteca correspondentes são as seguintes:

TIM_SetAutoreload(TIM3, NEW_ARR); // 用于修改ARR的值进而修改PWM周期  

 

Etapas de configuração da função de biblioteca

Etapa 1: Habilite o clock do barramento periférico de GPIO / AFIO / TIM

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能定时器3时钟  
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB  | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟  

 

Etapa 2: configurar o remapeamento das funções dos pinos

GPIO_InitTypeDef GPIO_InitStructure;  
PIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射  TIM3_CH2->PB5      
  
  //设置该引脚为复用输出功能,输出TIM3 CH2的PWM脉冲波形 GPIOB.5  
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH2  
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出  
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO

  

Etapa 3: configurar as propriedades básicas do cronômetro

  //初始化TIM3  
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值  
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值   
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim  
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式  
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

  

Etapa 4: configurar o modo de saída PWM

TIM_OC_InitStructure.TIM_OCMode = TIM_OCMode_PWM1; // 选择PWM输出模式1——当计数器值小于比较值时输出有效电平;当计数器值大于比较值时输出无效电平  
TIM_OC_InitStructure.TIM_OutputState = TIM_OutputState_Enable; // PWM输出模式使能  
TIM_OC_InitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 配置有效电平——高电平有效  
TIM_OC3Init(TIM3, &TIM_OC_InitStructure); // 配置PWM输出比较的属性  

 

Etapa 5: configurar o registro de pré-carga

TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable); // 使能比较值预加载寄存器  
TIM_ARRPreloadConfig(TIM3, ENABLE); // 使能预加载值寄存器  

 

TIM_OC3PreloadConfig ()

Usado para configurar o registro "usado para pré-carregar o valor CCRx"

TIM_ARRPreloadConfig ()

Usado para configurar o registro "usado para pré-carregar o valor ARR"

Etapa 6: habilitar formalmente a função TIM

 

Podemos ver no diagrama de blocos do fluxo de trabalho do registro que podemos habilitar oficialmente a função TIM após configurarmos todas as propriedades do temporizador.

TIM_Cmd(TIM3, ENABLE);  //使能TIM3  

 

Exemplo de código abrangente

Main.c

#include "led.h"  
#include "sys.h"  
#include "timer.h"  
  
 int main(void)  
 {        
    u16 CompareValue=0;  
    u8 Dir=1;       
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);      //设置NVIC中断分组2:2位抢占优先级,2位响应优先级  
    LED_InitConfig();                //LED端口初始化  
    TIMER_InitConfig(899,0);     //不分频。PWM频率=72000000/900=80Khz  
       
    while(1)  
    {  
        if(Dir == 1)   
        {  
            CompareValue++;  
        }  
        else   
        {  
            CompareValue--;  
        }  
          
        if(CompareValue >= 300)  
        {  
            Dir = 0;  
        }  
        else  
        {  
            Dir = 1;  
        }  
          
        TIM_SetCompare2(TIM3, CompareValue);  
    }      
 }  

 

Led.c

#include "led.h"  
#include "stm32f10x.h"  
  
void LED_InitConfig()  
{  
    GPIO_InitTypeDef GPIO_InitStructure;  
      
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE); // 使能LED1的外设时钟  
      
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;  
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
    GPIO_Init(GPIOE, &GPIO_InitStructure); // 配置LED1的输出属性  
      
    GPIO_SetBits(GPIOE, GPIO_Pin_5); // 配置初始引脚输出电平为低电平  
}  

 

Led.h.

#ifndef _LED_H  
#define _LED_H  
  
#include "sys.h"  
  
void LED_InitConfig();  
  
#define LED1 PEout(5)  
  
#endif  

 

Timer.c

#include "timer.h"  
#include "led.h"  
#include "stm32f10x.h"  
#include "delay.h"  
  
void TIMER_InitConfig(u16 ARR, u16 PR)  
{  
    GPIO_InitTypeDef GPIO_InitStructure;  
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;  
    TIM_OCInitTypeDef TIM_OC_InitStructure;  
    NVIC_InitTypeDef NVIC_InitStructure;  
      
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE); // 使能GPIOB的外设时钟  
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // 使能TIM3的外设时钟  
      
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 一定要选择“复用推挽输出”  
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;  
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
    GPIO_Init(GPIOB, &GPIO_InitStructure); // 配置GPIOB的引脚属性  
      
    GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); // 引脚重映射配置  
      
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; // AHB到TIMxCLK之间没有分频  
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式  
    TIM_TimeBaseInitStructure.TIM_Period = ARR; // 0x1388 = 5000  
    TIM_TimeBaseInitStructure.TIM_Prescaler = PR; // 0x1C20 = 7200  
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure); // 周期长度为1s  
      
    TIM_OC_InitStructure.TIM_OCMode = TIM_OCMode_PWM1; // 选择PWM输出模式1——当计数器值小于比较值时输出有效电平;当计数器值大于比较值时输出无效电平  
    TIM_OC_InitStructure.TIM_OutputState = TIM_OutputState_Enable; // PWM输出模式使能  
    TIM_OC_InitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; // 配置有效电平——高电平有效  
    TIM_OC2Init(TIM3, &TIM_OC_InitStructure); // 配置PWM输出比较的属性  
      
    TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); // 使能比较值预加载寄存器  
    TIM_ARRPreloadConfig(TIM3, ENABLE); // 使能预加载值寄存器  
      
    TIM_Cmd(TIM3, ENABLE); // TIM3使能  
      
    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;  
    NVIC_Init(&NVIC_InitStructure); // 配置NVIC嵌入式中断向量优先级  
      
    TIM_ITConfig(TIM3, TIM_IT_CC2, ENABLE); // 定时器具体中断模式配置  
}  
  
void TIM3_IRQHandler()  
{  
    delay_init();  
    if(TIM_GetITStatus(TIM3, TIM_IT_CC2) == SET)  
    {  
        delay_ms(500);  
        LED1 = !LED1;  
    }  
    TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);  
}  

 

Timer.h

#ifndef _TIMER_H  
#define _TIMER_H  
  
#include "sys.h"  
  
void TIMER_InitConfig(u16 ARR, u16 PR);  
  
#endif  

 

resultado da operação

Status LEDx

Posição de mudança de status

LED1 acende alternadamente

PWM comparar interrupção

O brilho do LED0 varia com o ciclo de trabalho

Nível de saída PWM

Como usei delay_ms (500) como atraso, você pode ver claramente que LED1 muda alternadamente devido ao estado de interrupção de comparação, mas como o valor de comparação PWM muda gradualmente em +1, você precisa de um período de tempo para observar cuidadosamente as mudanças de brilho do LED0.

 

Acho que você gosta

Origin blog.csdn.net/weixin_45590473/article/details/108062177
Recomendado
Clasificación