Ejemplo detallado de experimento de salida PWM

Tabla de contenido

Experimento de salida PWM

El principio de funcionamiento de PWM (tome el conteo como ejemplo)

Experimento completo de reasignación de pines PWM y AFIO

Instrucciones de función de biblioteca

Puntos de conocimiento básico de la configuración de PWM

Reasignación de funciones de puerto GPIO

El significado de la división del reloj

¿Cuáles son los dos modos de comparación de PWM?

El papel del registro de precarga (TIMx_CCMR1)

¿Cuál es la polaridad de salida PWM?

Consideraciones sobre la configuración de PWM

¿Cómo configurar el ciclo de trabajo?

Pasos de configuración de la función de biblioteca

Paso 1: Habilite el reloj del bus periférico de GPIO / AFIO / TIM

Paso 2: configurar la reasignación de funciones de pin

Paso 3: configurar las propiedades básicas del temporizador

Paso 4: configurar el modo de salida PWM

Paso 5: configurar el registro de precarga

Paso 6: habilite formalmente la función TIM

Ejemplo de código completo

C Principal

Led.c

Led.h.

Temporizador.c

Temporizador.h

resultado de la operación


Experimento de salida PWM

El principio de funcionamiento de PWM (tome el conteo como ejemplo)

 

El valor en el registro CCRX se usa para comparar con el valor en el contador.Cuando el valor en el contador CNT es igual al registro CCRX, el nivel de la señal de salida del temporizador general cambia. Finalmente, cuando el contador cuenta hasta MAX (el valor en ARR), (la "interrupción de actualización" también se puede activar) vuelve inmediatamente a 0 y reinicia el conteo.

Experimento completo de reasignación de pines PWM y AFIO

Instrucciones de función de biblioteca

Nombre de la función de biblioteca

Caracteristicas

RCC_APB1PeriphClockCmd () / RCC_APB2PeriphClockCmd ()

Habilitación del reloj periférico del bus APB

GPIO_Init ()

Función de inicialización GPIO

GPIO_PinRemapConfig ()

Función de reasignación de puertos GPIO

TIM_ARRPreloadConfig ()

Habilite o deshabilite el registro de precarga de TIMx en ARR

 

TIM_TimeBaseInit ()

Inicializar temporizador

TIM_OCInit ()

Inicializar parámetros de comparación

TIM_Cmd ()

Activar temporizador

TIM_SetCompare2 ()

Cambie constantemente el valor de comparación CCRx para lograr diferentes efectos del ciclo de trabajo

Puntos de conocimiento básico de la configuración de PWM

Reasignación de funciones de puerto GPIO

En primer lugar, debemos tener claro a qué pin queremos reasignar la función TIM:

 

 

Aprendimos de la reasignación de la función de multiplexación GPIO de AFIO que cuando usamos la función de "reasignación parcial parcial de TIM3", podemos asignar el pin TIM3_CH3 de TIM3 al pin PB5, y usarlo para impulsar LED0 para mostrar la función PWM .

En este momento, deben tenerse en cuenta los siguientes puntos:

① El modo de salida GPIO debe configurarse como "salida push-pull multiplexada". Como se muestra en la figura siguiente, solo cuando se configura como multiplexado se pueden emitir señales de otras funciones no IO a través de este pin GPIO. Solo cuando se configura como push-pull , Puede generar niveles altos y bajos sin depender del nivel externo, y la salida push-pull cumple con los requisitos de salida de la función TIM3.

 

 

② Configure la función de reasignación de pines GPIO

Significado y función: La función de TIM3 no pertenece a PB5, pero podemos saber que "TIM3 puede reasignar la función al pin PB5" cuando reasignamos la función TIM3 al pin PB5, debemos habilitar Reloj AFIO y registro de reasignación de configuración.

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  

El significado de la división del reloj

Cuando configuramos TIM, llamaremos a esta función: TIM_TimeBaseInit ();

Entre ellos, su parámetro de estructura configurará el atributo "TIM_ClockDivision".

Primero entendamos cómo se obtiene TIMER3 como un reloj dividido por PSC:

 

 

Nuestro experimento usa el reloj del bus APB1 (la frecuencia del reloj AHB es 72MHz). Notamos que en AHB-> APB1 divisor-> APB1, si el factor de división del preescalador APB1 es 1, entonces la frecuencia de reloj de TIMXCLK es " TIMCLK = APB1 = AHB ", si el factor de división del preescalador APB1 es N (N no es 1), entonces la frecuencia de reloj de TIMXCLK es" TIMCLK = 2xAPB1 = 2xAHB / N ".

Pero cuando llamamos a la función de biblioteca de fuente de reloj de inicialización proporcionada por ST, el factor de división predeterminado del divisor APB1 es 2, por lo que el TIMXCLK final = 2xAPB1 = 2xAHB / 2 = AHB.

La división de reloj aquí representa el coeficiente de preescalador de APB1.

¿Cuáles son los dos modos de comparación de PWM?

 

 

El papel del registro de precarga (TIMx_CCMR1)

 

 

Cuando actualizamos el valor de ARR durante la operación, si OC1PE en el registro de precarga se establece en 1, entonces el valor de ARR se colocará en el contador en el siguiente ciclo; si se establece en 0, el valor de ARR se cargará en el contador inmediatamente.

¿Cuál es la polaridad de salida PWM?

 

 

Consideraciones sobre la configuración de PWM

Dado que enviamos la señal PWM al pin PB5, no es necesario configurar los atributos del pin GPIO como de costumbre y asignar un nivel específico a PB5. Debido a que PB5 no es un pin IO diferente, su estado está determinado por el nivel de salida PWM que recibe.

¿Cómo configurar el ciclo de trabajo?

Solo definimos las siguientes partes en 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 solo explica "cómo configurar las propiedades de salida PWM de los 2 puertos del TIMER3 (modo PWM, nivel efectivo, habilitar o deshabilitar)", no configuramos el "valor de comparación", por lo que el ciclo de trabajo predeterminado es Es 100%.

Necesitamos establecer el valor de comparación CCRx después de configurar el PWM del temporizador. El código es el siguiente:

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

 

Aquí lo configuro en la función principal, que se usa para modificar continuamente el valor de comparación CCRx para producir un efecto de luz LED con un cambio gradual de brillo. Del mismo modo, también podemos modificar el valor de ARR para ajustar el período de PWM. Las funciones de biblioteca correspondientes son las siguientes:

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

 

Pasos de configuración de la función de biblioteca

Paso 1: Habilite el reloj del bus periférico de GPIO / AFIO / TIM

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

 

Paso 2: configurar la reasignación de funciones de pin

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

  

Paso 3: configurar las propiedades básicas del temporizador

  //初始化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的时间基数单位

  

Paso 4: configurar el modo de salida 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输出比较的属性  

 

Paso 5: configurar el registro de precarga

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

 

TIM_OC3PreloadConfig ()

Se utiliza para configurar el registro "utilizado para precargar el valor CCRx"

TIM_ARRPreloadConfig ()

Se utiliza para configurar el registro "utilizado para precargar el valor ARR"

Paso 6: habilite formalmente la función TIM

 

Podemos ver en el diagrama de bloques del flujo de trabajo del registro que podemos habilitar oficialmente la función TIM después de configurar todas las propiedades del temporizador.

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

 

Ejemplo de código completo

C Principal

#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  

 

Temporizador.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);  
}  

 

Temporizador.h

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

 

resultado de la operación

Estado de LEDx

Posición de cambio de estado

LED1 se enciende alternativamente

Interrupción de comparación PWM

El brillo de LED0 varía con el ciclo de trabajo

Nivel de salida PWM

Dado que utilicé delay_ms (500) como retraso, puede ver claramente que LED1 cambia alternativamente debido al estado de interrupción de comparación, pero debido a que el valor de comparación de PWM cambia gradualmente en +1, necesita un período de tiempo para observar cuidadosamente los cambios de brillo de LED0.

 

Supongo que te gusta

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