嵌入式开发之STM32学习笔记day10
STM32F103C8T6 TIM定时器输出比较
1 定时器输出比较基础概念
- OC(Output Compare)输出比较
- 输出比较可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形
- 每个高级定时器和通用定时器都拥有4个输出比较通道
- 高级定时器的前3个通道额外拥有死区生成和互补输出的功能
2 PWM 的基本概念
PWM(Pulse Width Modulation,脉宽调制)是一种通过调节脉冲信号的占空比来控制模拟信号的技术。其核心是通过快速开关数字信号,改变高电平与低电平的时间比例,从而模拟不同的电压或功率输出。
2.1 PWM 的工作原理
- 占空比:高电平时间与整个周期的比值,通常以百分比表示。例如,50%占空比表示高电平和低电平时间相等。
- 频率:单位时间内脉冲信号的周期数(Hz)。高频 PWM 可减少输出波动,但可能受硬件限制。
- PWM参数:
公式: 频率 = 1 / TS 占空比 = TON / TS 分辨率 = 占空比变化步距
描述:这是一个简单的PWM原理图,假设定时器工作模式是向上计数,当计数值小于阈值时,就会输出一个电平状态,比如高电平,反之输出低电平。高电平持续时间(脉冲宽度)和周期时间的比值为占空比,范围是0-100%。上图是生成的是占空比为40%的pwm波。
案例场景分析:在智能家居的客厅中,一盏嵌入式LED灯正通过PWM(脉冲宽度调制)技术展现出细腻的光影魔法。通过微控制器精准调节PWM的占空比,灯光从清晨的柔和暖黄渐变为午后的明亮白光,仿佛自然光线在室内流动。当夜晚观影模式开启时,灯光瞬间调至10%的暗调,既营造出沉浸式氛围,又避免了直视光源的刺眼。PWM的高频脉冲控制让亮度变化丝滑无频闪,配合智能系统还能联动音乐节奏,让灯光随着旋律明暗起伏,如同无声的舞者用光影演绎科技与艺术的交融。
3 输出比较通道(高级)
4 输出比较通道(通用)
5 输出比较模式
模式 | 描述 |
---|---|
冻结 | CNT=CCR时,REF保持为原状态 |
匹配时置有效电平 | CNT=CCR时,REF置有效电平 |
匹配时置无效电平 | CNT=CCR时,REF置无效电平 |
匹配时电平翻转 | CNT=CCR时,REF电平翻转 |
强制为无效电平 | CNT与CCR无效,REF强制为无效电平 |
强制为有效电平 | CNT与CCR无效,REF强制为有效电平 |
PWM模式1 | 向上计数:CNT<CCR时,REF置有效电平,CNT≥CCR时,REF置无效电平 向下计数:CNT>CCR时,REF置无效电平,CNT≤CCR时,REF置有效电平 |
PWM模式2 | 向上计数:CNT<CCR时,REF置无效电平,CNT≥CCR时,REF置有效电平 向下计数:CNT>CCR时,REF置有效电平,CNT≤CCR时,REF置无效电平 |
6 PWM基本结构
分析说明:
这张图展示了一个定时器PWM信号输出的内部工作机制,其主要流程如下:
时基单元:
-
包括 PSC(预分频器)、CNT(计数器) 和 ARR(自动重装器),它们共同决定了PWM的周期。
-
PSC将主时钟频率进行分频,决定了CNT计数的速度。
-
CNT是计数器,按设定频率进行计数,从0开始递增到ARR设置的最大值,然后重新从0计数。
-
ARR决定了PWM的周期(CNT最大值)。
输出比较单元(CCR):
-
CCR(捕获/比较寄存器) 用于设定PWM的占空比,即高电平的持续时间。
-
当CNT小于CCR时,输出为高电平;CNT大于等于CCR时,输出为低电平。
REF极性与GPIO输出:
-
通过设置极性选择器,可以决定输出为正向PWM(高电平有效)还是反向PWM(低电平有效)。
-
最终的PWM信号通过GPIO引脚输出。
图示解读:
-
上方折线图表示CNT计数器从0到ARR(如9)不断循环计数。
-
红线是CCR的值,例如3。
-
下方绿色方波表示PWM输出波形:当计数值小于CCR时为高电平,超过后为低电平。
简要概括:
STM32定时器通过PSC分频后由CNT计数器递增计数,周期由ARR设置决定。当计数器CNT的值小于CCR时,输出为高电平,否则为低电平,从而形成PWM波形。通过调整CCR值可以控制PWM的占空比。极性选择电路还可以决定PWM信号的有效电平方向,最终由GPIO口输出PWM信号,实现对外设的精确控制。
7 PWM参数计算
- PWM频率: Freq = CK_PSC / (PSC + 1) / (ARR + 1)
- PWM占空比: Duty = CCR / (ARR + 1)
- PWM分辨率: Reso = 1 / (ARR + 1)
8 使用PWM精准控制LED亮度:从原理到代码实现
本文将手把手教你通过PWM(脉冲宽度调制)技术控制LED灯的亮度,涵盖硬件连接、代码编写及原理分析,适用于STM32等常见开发板。通过调节占空比,实现灯光从暗到亮的平滑过渡,并附赠呼吸灯效果代码!
所需材料
开发板(STM32)
LED灯(不同颜色需注意正向电压)
220Ω限流电阻
杜邦线若干
接线方式
LED正极 → PWM引脚(如STM32的PA0)
LED负极 → 电阻 → GND
8.1 PWM初始化
8.1.1 开启时钟
/*开启时钟*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //开启TIM2的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
8.1.2 GPIO初始化
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA0引脚初始化为复用推挽输出 //受外设控制的引脚,均需要配置为复用模式
8.1.3 配置时钟源
在这里外面选择时钟源为内部时钟TIM2
/*配置时钟源*/
TIM_InternalClockConfig(TIM2); //选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟
8.1.4 时基单元初始化
/*时基单元初始化*/
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定义结构体变量
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数
TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; //计数周期,即ARR的值
TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; //预分频器,即PSC的值
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器,高级定时器才会用到
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); //将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元
8.1.5 输出比较初始化
/*输出比较初始化*/
TIM_OCInitTypeDef TIM_OCInitStructure; //定义结构体变量
TIM_OCStructInit(&TIM_OCInitStructure); //结构体初始化,若结构体没有完整赋值 //则最好执行此函数,给结构体所有成员都赋一个默认值 //避免结构体初值不确定的问题
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //输出比较模式,选择PWM模式1
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性,选择为高,若选择极性为低,则输出高低电平取反
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //输出使能
TIM_OCInitStructure.TIM_Pulse = 0; //初始的CCR值
TIM_OC1Init(TIM2, &TIM_OCInitStructure);//将结构体变量交给TIM_OC1Init,配置TIM2的输出比较通道1
8.1.6 TIM使能——重要
/*TIM使能*/
TIM_Cmd(TIM2, ENABLE); //使能TIM2,定时器开始运行
8.2 占空比设置
/*** 函 数:PWM设置CCR* 参 数:Compare 要写入的CCR的值,范围:0~100* 返 回 值:无* 注意事项:CCR和ARR共同决定占空比,此函数仅设置CCR的值,并不直接是占空比* 占空比Duty = CCR / (ARR + 1)*/
void PWM_SetCompare1(uint16_t Compare)
{TIM_SetCompare1(TIM2, Compare); //设置CCR1的值
}
这里,我们可以通过上面的PWM_SetCompare1函数来设置GPIO输出占空比为Compare的信号。因为我们起初设置ARR为100-1 , PSC为720-1,从而可以通过以下公式计算:
- PWM频率: Freq = CK_PSC / (PSC + 1) / (ARR + 1) = 72*10^6 / 720000 = 100
- PWM占空比: Duty = CCR / (ARR + 1) = CCR%
- PWM分辨率: Reso = 1 / (ARR + 1) = 0.01
8.3 main主函数
int main(void)
{/*模块初始化*/OLED_Init(); //OLED初始化PWM_Init(); //PWM初始化OLED_ShowString(1, 1, "PWM contral led0");while (1){for (i = 0; i <= 100; i++){PWM_SetCompare1(i); //依次将定时器的CCR寄存器设置为0~100,PWM占空比逐渐增大,LED逐渐变亮Delay_ms(10); //延时10ms}for (i = 0; i <= 100; i++){PWM_SetCompare1(100 - i); //依次将定时器的CCR寄存器设置为100~0,PWM占空比逐渐减小,LED逐渐变暗Delay_ms(10); //延时10ms}}
}
分析:
这里,我们就使用两个for循环,先将led占空比从0到100递增,然后又从100到0递减,我们就可以清晰的看见led亮度由暗变亮,由亮变暗,循环往复。
关注我:
-
CSDN博客:小程同学>o<-CSDN博客