个人 备案 多个网站,免费ddns域名注册,怎么用网站做远控,最新军事新闻新浪网目录 前言 一 PWM介绍 1.1 PWM简介 1.2 STM32F103 PWM介绍 1.3 时钟周期与占空比 二.引脚映像关系 2.1引脚映像与寄存器 2.2 复用功能映像 三. PWM 配置步骤 3.1相关原理图 3.2配置流程 3.2.1 步骤一二#xff1a; 3.2.2 步骤三#xff1a; 3.2.3 步骤四五六七#xff1a; … 目录 前言 一 PWM介绍 1.1 PWM简介 1.2 STM32F103 PWM介绍 1.3 时钟周期与占空比 二.引脚映像关系 2.1引脚映像与寄存器 2.2 复用功能映像 三. PWM 配置步骤 3.1相关原理图 3.2配置流程 3.2.1 步骤一二 3.2.2 步骤三 3.2.3 步骤四五六七 3.2.4 步骤八 3.3 PWM 详细代码 3.3.1 PWM.C 3.3.2 main.c 四.PWM波形 4.1 波形查看 4.2 PWM更新频率 4.2.1不使用delay 4.2.2 使用delay 前言 步骤一通过配置ARR(自动重装载值寄存器)和PSC(预分频器)的值来设置CNT(计数器)的定时周期、计数频率。 步骤二再改变CCR(捕获/比较寄存器)的值通过CNT与CCR的比较可对PWM占空比进行调整。 经过步骤一和步骤二即可输出频率和占空比都可以调制的PWM波形 注 ARR(自动重装载值寄存器) PSC(预分频器) CNT(计数器) CCR(捕获/比较寄存器) 一 PWM介绍
1.1 PWM简介 脉冲宽度调制:PWM是一种数字信号控制技术其中数字信号的占空比被用来控制模拟信号的幅度。占空比是指在一个周期内信号处于高电平状态的时间与总周期时间的比例。 PWM是Pulse Width Modulation的缩写中文意思是“脉冲宽度调制”。这是一种模拟信号控制方法通过改变电信号的占空比来控制功率输出或模拟信号的幅度。PWM广泛应用于各种电子系统中包括但不限于以下几个领域 电机控制PWM用于控制电机的转速和力矩通过调整电机驱动器的输入电压或电流的占空比来实现。 LED调光在LED照明中PWM可以控制LED的亮度通过改变电流的占空比来调节亮度而不会改变LED的色温。 音频信号合成PWM也用于数字音频处理通过调制脉冲的宽度来合成模拟音频信号。 电源管理在开关电源中PWM用于控制开关元件的开关频率和占空比以调节输出电压和电流。 通信某些通信协议使用PWM来传输数据通过调制脉冲的宽度来编码信息。 测量和控制PWM信号可以用于测量距离、速度等物理量也可以用于控制各种执行器。 PWM信号的主要特点包括 周期性PWM信号是周期性重复的具有固定的频率。占空比PWM信号的占空比是指高电平状态在整个周期中所占的比例。分辨率PWM的分辨率取决于信号的周期和能够分辨的最小脉冲宽度高分辨率的PWM可以提供更平滑的模拟控制。易于生成和控制PWM信号可以通过数字电路或微控制器轻松生成和调整。 在实际应用中PWM信号通常由定时器或专用的PWM硬件生成然后通过数字到模拟转换器DAC或直接通过功率放大器输出到负载。通过精确控制PWM信号的频率和占空比可以实现对各种电子设备的精确控制。 1.2 STM32F103 PWM介绍 在STM32F103中除了基本定时器(定时器6和定时器7)通用和高级定时器都可以用来进行PWM输出。 1.3 时钟周期与占空比 在时基单元中我们通过对PSC、ARR 大小进行配置来设置计数器CNT的定时周期、计数频率。 因为前面的时基单元中已经设置完定时器时钟频率。可以通过TIMx_CCRx(捕获/比较寄存器也就是上面的CCR)输出占空比可调的PWM波形 注因为CNT在前面设置向上或向下计数模式后就不用更改了所以到这一步只需要对CRR的值进行设置也可以通过while()循环不断给TIMx_CCRx寄存器赋新的值来进行脉宽占空比的调整。 输出频率和占空比都可以调制的PWM波形 •PWM频率 Freq CK_PSC / (PSC 1) / (ARR 1) •PWM占空比 Duty CCR / (ARR 1) •PWM分辨率 Reso 1 / (ARR 1) 二.引脚映像关系
2.1引脚映像与寄存器 高级定时器TIM1和TIM8是高级定时器 通用定时器TIM2、TIM3、TIM4和TIM5是通用定时器 基本定时器TIM6和TIM7是基本的定时器 2.2 复用功能映像 引脚重映射比如当您需要将TIM3的某些通道映射到不同的GPIO引脚上时可以使用复用功能映像。例如当默认的TIM3通道引脚不能满足您的硬件设计需求或者您需要将多个通道映射到同一个引脚上时可以使用复用功能映像来改变引脚映射。 PWM输出到特定引脚如果您需要将PWM信号输出到特定的GPIO引脚而这个引脚不是TIM3的默认输出引脚您可以通过复用功能映像来实现。例如将TIM3的CH2映射到PB5或者将所有四个通道映射到PC6、PC7、PC8、PC9。 下面以TIM3为例 TIM3是STM32微控制器中的一个通用定时器它具有四个独立的通道分别是CH1、CH2、CH3和CH4。这些通道可以被配置为输入捕获、输出比较或PWM输出模式用于各种定时和控制应用。 每个通道都有自己的捕获/比较寄存器CCR可以独立设置以实现不同的定时和控制功能。例如TIM3_CH1默认引脚为PA6TIM3_CH1部分重映像引脚为PB4,TIM3_CH1完全重映像引脚为PC6。 三. PWM 配置步骤
3.1相关原理图 这里使用PWM控制LED呼吸灯。这里控制PC8的绿色LED灯实现呼吸灯的效果。 这里的PC8端口是TIM3的通道3使用完全重映射 //部分重映射GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE);//完全重映射GPIO_PinRemapConfig(GPIO_FullRemap_TIM3,ENABLE); 既GPIO_PinRemapConfig(GPIO_FullRemap_TIM3,ENABLE); 3.2配置流程 一使能定时器3和相关IO口时钟。 使能定时器3时钟RCC_APB1PeriphClockCmd(); 使能GPIOC时钟RCC_APB2PeriphClockCmd(); 二初始化IO口为复用功能输出。函数GPIO_Init(); GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; 三这里我们是要把PC8用作定时器的PWM输出引脚所以要重映射配置所以需要开启AFIO时钟。同时设置重映射。 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); 四初始化定时器ARR,PSC等TIM_TimeBaseInit(); 五初始化输出比较参数:TIM_OC3Init(); 六使能预装载寄存器 TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable); 七使能定时器TIM_Cmd(); 八不断改变比较值CCRx达到不同的占空比效果:TIM_SetCompare4(); 3.2.1 步骤一二 一使能定时器3和相关IO口时钟。 使能定时器3时钟RCC_APB1PeriphClockCmd(); 使能GPIOC时钟RCC_APB2PeriphClockCmd(); 二初始化IO口为复用功能输出。函数GPIO_Init(); GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_OCInitTypeDef TIM_OCInitStructure;GPIO_InitTypeDef GPIO_InitStructure;/* 步骤一使能定时器3和相关IO口时钟。开启时钟 */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);/* 步骤二初始化IO口为复用功能输出 */GPIO_InitStructure.GPIO_PinGPIO_Pin_8;GPIO_InitStructure.GPIO_SpeedGPIO_Speed_50MHz;GPIO_InitStructure.GPIO_ModeGPIO_Mode_AF_PP;//复用推挽输出GPIO_Init(GPIOC,GPIO_InitStructure); 3.2.2 步骤三 三这里我们是要把PC8用作定时器的PWM输出引脚所以要重映射配置所以需要开启AFIO时钟。同时设置重映射。 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); /* 步骤三设置重映射 */GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE);GPIO_PinRemapConfig(GPIO_FullRemap_TIM3,ENABLE);//改变指定管脚的映射 3.2.3 步骤四五六七 四初始化定时器ARR,PSC等TIM_TimeBaseInit(); 五初始化输出比较参数:TIM_OC3Init(); 六使能预装载寄存器 TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable); 七使能定时器TIM_Cmd(); /* 步骤四初始化定时器 */TIM_TimeBaseInitStructure.TIM_Periodper; //自动装载值TIM_TimeBaseInitStructure.TIM_Prescalerpsc; //分频系数TIM_TimeBaseInitStructure.TIM_ClockDivisionTIM_CKD_DIV1;TIM_TimeBaseInitStructure.TIM_CounterModeTIM_CounterMode_Up; //设置向上计数模式TIM_TimeBaseInit(TIM3,TIM_TimeBaseInitStructure); /* 步骤五初始化输出比较参数:TIM_OC3Init(); */TIM_OCInitStructure.TIM_OCModeTIM_OCMode_PWM1;TIM_OCInitStructure.TIM_OCPolarityTIM_OCPolarity_Low;//计数值与TIM_Pulse匹配输出低电平TIM_OCInitStructure.TIM_OutputStateTIM_OutputState_Enable;TIM_OC3Init(TIM3,TIM_OCInitStructure); //输出比较通道3初始化/* 步骤六使能预装载寄存器 */TIM_OC3PreloadConfig(TIM3,TIM_OCPreload_Enable);//使能TIMx在 CCR3 上的预装载寄存器TIM_ARRPreloadConfig(TIM3,ENABLE);//使能预装载寄存器/* 步骤七使能定时器3 */TIM_Cmd(TIM3,ENABLE); //使能定时器 3.2.4 步骤八 八不断改变比较值CCRx达到不同的占空比效果:TIM_SetCompare4(); int main()
{u16 i0; u8 fx0;delay_init();NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组 分2组LED_Init();TIM3_CH3_PWM_Init(500,72-1); //0.5毫秒(频率是2KHZ)while(1){if(fx0){i;if(i500){fx1;}}else{i--;if(i0){fx0;}}//可直接改变CCR的值(通道3也就是CCR3的值)TIM_SetCompare3(TIM3,i); //i值最大可以取499因为ARR最大值是499.delay_ms(5); }
} 3.3 PWM 详细代码
3.3.1 PWM.C pwm.c #include pwm.h
#include led.h/*******************************************************************************
* 函 数 名 : TIM3_CH3_PWM_Init
* 函数功能 : TIM3通道3 PWM初始化函数
* 输 入 : per:重装载值psc:分频系数
* 输 出 : 无
*******************************************************************************/
void TIM3_CH3_PWM_Init(u16 per,u16 psc)
{TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_OCInitTypeDef TIM_OCInitStructure;GPIO_InitTypeDef GPIO_InitStructure;/* 步骤一使能定时器3和相关IO口时钟。开启时钟 */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);/* 步骤二初始化IO口为复用功能输出 */GPIO_InitStructure.GPIO_PinGPIO_Pin_8;GPIO_InitStructure.GPIO_SpeedGPIO_Speed_50MHz;GPIO_InitStructure.GPIO_ModeGPIO_Mode_AF_PP;//复用推挽输出GPIO_Init(GPIOC,GPIO_InitStructure);/* 步骤三设置重映射 */GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE);GPIO_PinRemapConfig(GPIO_FullRemap_TIM3,ENABLE);//改变指定管脚的映射 /* 步骤四初始化定时器 */TIM_TimeBaseInitStructure.TIM_Periodper; //自动装载值TIM_TimeBaseInitStructure.TIM_Prescalerpsc; //分频系数TIM_TimeBaseInitStructure.TIM_ClockDivisionTIM_CKD_DIV1;TIM_TimeBaseInitStructure.TIM_CounterModeTIM_CounterMode_Up; //设置向上计数模式TIM_TimeBaseInit(TIM3,TIM_TimeBaseInitStructure); /* 步骤五初始化输出比较参数:TIM_OC3Init(); */TIM_OCInitStructure.TIM_OCModeTIM_OCMode_PWM1;TIM_OCInitStructure.TIM_OCPolarityTIM_OCPolarity_High;//计数值与TIM_Pulse匹配输出低电平TIM_OCInitStructure.TIM_OutputStateTIM_OutputState_Enable;TIM_OC3Init(TIM3,TIM_OCInitStructure); //输出比较通道3初始化/* 步骤六使能预装载寄存器 */TIM_OC3PreloadConfig(TIM3,TIM_OCPreload_Enable);//使能TIMx在 CCR3 上的预装载寄存器TIM_ARRPreloadConfig(TIM3,ENABLE);//使能预装载寄存器/* 步骤七使能定时器3 */TIM_Cmd(TIM3,ENABLE); //使能定时器} 3.3.2 main.c main.c #include sys.h
#include delay.h
#include usart.h
#include led.h
#include key.h
#include time.h
#include pwm.hint main()
{u16 i0; u8 fx0;delay_init();NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组 分2组LED_Init();TIM3_CH3_PWM_Init(500,72-1); //周期0.5毫秒(频率是2KHZ)/* PSC 72 ARR 500 周期 500/1000000 5/10000 0.0005秒 0.5毫秒 频率 2KHZ*//*LED亮灭时间2秒(亮1秒灭1秒),t 1000/500 2; */while(1){if(fx0){i;if(i500){fx1;}}else{i--;if(i0){fx0;}}//可直接改变CCR的值(通道3也就是CCR3的值)TIM_SetCompare3(TIM3,i); //i值最大可以取499因为ARR最大值是499.delay_ms(2); }
}四.PWM波形
4.1 波形查看 假设 CPU 的时钟频率为 1 MHz1 微秒/周期并且循环体内的指令执行需要 10 个周期这是一个粗略的估计下面实际测试是差不多的那么每次循环大约需要 10 微秒。因此一个完整的亮灭周期大约需要 这里的if(fx500),递增和递减共需500*2 1000次计算 1000×10 微秒10000 微秒10 毫秒1000×10微秒10000微秒10毫秒 所以LED 亮灭一次的周期大约为 10 毫秒。这意味着 LED 每 10 毫秒亮灭一次。但请注意这个估计值可能与实际值有所不同具体取决于 CPU 的执行速度和循环体内的指令数量。 波形大致为因为pwm周期 4.2 PWM更新频率 注意 更改delay_ms()延时函数的大小是修改LED灯亮灭的周期 LED亮灭周期是由频率(时基单元PSC ARR CNT)和占空比(CCR)控制的 dalay_ms()函数是为了控制PWM信号的更新速率在代码中delay_ms() 函数控制了 i 值更新的速率即控制了 PWM 信号占空比变化的速率。如果没有这个延迟i 的值会非常快地在 0 到 500 之间变化导致 PWM 信号的频率非常高这可能超出了人眼的感知范围使得 LED 的亮度看起来是恒定的。 4.2.1不使用delay 1 不使用delay_ms()函数 循环中没有包含任何延迟这意味着 i 的值会非常快速地在 0 到 500 之间变化没有任何停留。由于没有延迟i 的值变化得太快导致人眼无法察觉到 LED 的亮度变化看起来就像是 LED 一直亮着。 4.2.2 使用delay 2 使用delay_ms(1)函数后这里就是LED的亮灭周期为1秒 从 0 增加到 500 需要 500 次循环。从 500 减少到 0 也需要 500 次循环。因此一个完整的亮灭周期需要 1000 次循环。 每次循环的时间为 1 毫秒所以一个完整的亮灭周期的时间为 1000×1 毫秒1000 毫秒1 秒1000×1毫秒1000毫秒1秒 如下图