| **银杏科技有限公司旗下技术文档发布平台** |||| |技术支持电话|**0379-69926675-801**||| |技术支持邮件|Gingko@vip.163.com||| ^ 版本 ^ 日期 ^ 作者 ^ 修改内容 ^ | V1.0 | 2020-07-04 | gingko | 初次建立 | ===== 实验八:定时器PWM实验——呼吸灯 ===== ==== 一、实验目的与意义 ==== - 了解STM32 TIMER结构。 - 了解STM32 TIMER 特征。 - 掌握TIMER使用方法。 - 掌握STM32 HAL库中TIMER属性的配置方法。 - 掌握KEILMDK 集成开发环境使用方法。 二、实验设备及平台 - iCore4 双核心板[[https://item.taobao.com/item.htm?spm=a1z10.1-c-s.w4004-22598974120.15.5923532fsFrHiE&id=551864196684|点击购买]]。 - JLINK(或相同功能)仿真器[[https://item.taobao.com/item.htm?id=554869837940|点击购买]]。 - Micro USB线缆。 - Keil MDK 开发平台。 - STM32CubeMX开发平台。 - 装有WIN XP(及更高版本)系统的计算机。 ==== 三、实验原理 ==== === 1、PWM简介 === * PWM(Pulse Width Modulation)即脉冲宽度调制,是一种模拟控制方式,其根据相应载荷的变化来调制晶体管基极或MOS管栅极的偏置,来实现晶体管或MOS管导通时间的改变,从而实现开关稳压电源输出的改变。这种方式能使电源的输出电压在工作条件变化时保持恒定,是利用微处理器的数字信号对模拟电路进行控制的一种非常有效的技术。 * PWM的主要应用:在STM32中如调节屏幕亮度、音调等应用都可以通过PWM控制占空比进行实现。下面我们会为大家举例介绍如何利用PWM控制LED的亮暗,以实现呼吸灯的效果。 === 2、PWM的工作原理 === * 脉宽调制基本原理:其控制方式就是对电路开关器件的通断进行控制,使输出端得到一系列幅值相等的脉冲,用这些脉冲来代替正弦波或所需要的波形。也就是在输出波形的半个周期中产生多个脉冲,使各脉冲的等值电压为正弦波形,所获得的输出平滑且低次谐波少。按一定的规则对各脉冲的宽度进行调制,即可改变电路输出电压的大小,也可改变输出频率。 * **脉宽调制原理:** * 脉宽调制模式可以生产一个由TIMx_ARR寄存器确定频率,由TIMx_CCRx确定占空比的信号。如下图所示: {{ :icore4:icore4_arm_hal_8_1.png?direct |}} * 图中可知0到t2为一个周期时间,而占空比由CCRx值决定。一个周期时间可以由以下公式计算: * **T=(ARR+1)(PSC+1)/TCLK** * 其中:ARR为重新装载值;PSC为预分频系数;TCLK为定时器时钟频率。如本次实验中TCLk为84M,选择ARR为499,PSC为83,其一个周期为0.5ms。 * **PWM工作步骤解析:** * (1)CCR1捕获比较值寄存器设置比较值,将其与当前值寄存器的值比较,要说明的是修改TIM_CCMR1寄存器的OC1M[2:0]位可控制 PWM模式,方法如下: * 110:PWM模式1——向上计数时,一旦TIMx_CNTTIMx_CCR1时通道1为无效电平(OC1REF=0),否则有效电平(OC1REF=1)。 * 111:PWM模式2——在向上计数时,一旦TIMx_CNTTIMx_CCR1时通道1为有效电平,否则为无效电平。 * (2)经过输出控制器后,得到OC1ref电平还要经过一个选择,其由TIMx_CCRE寄存器的CC1P位控制:输入/捕获1输出极性。0:高 电平有效。1:低电平有效 * (3)选择完成后经过输出电路来输出,输出电路由TIM_xCCRE寄存器的CC1E位控制。 * 控制方式为0:关闭1:打开。 === 3、寄存器介绍 === * STM32F767的定时器都可以用来产生PWM输出。其中高级定时器TIM1和TIM8可以同时产生多达7路的PWM输出。而通用定时器也能同时产生多达4路的PWM输出,这里我们仅使用TIM1的CH2产生一路PWM输出。 * 要使STM32F767的定时器TIMx产生PWM输出,我们要用到几个寄存器来控制PWM。接下来我们简单介绍一下其中四个寄存器:捕获/比较模式寄存器(TIMx_CCMR1/2)、捕获/比较使能寄存器(TIMx_CCER)、捕获/比较寄存器(TIMx_CCR1~4)、断路和死区寄存器( TIMx_BDTR)。 * **(1)**捕获/比较模式寄存器(TIMx_CCMR1/2),该寄存器一般有2个:TIMx _CCMR1和 TIMx _CCMR2。 TIMx_CCMR1 控制 CH1 和2,而 TIMx_CCMR2 控制 CH3 和 4。TIM1_CCMR2寄存器各位描述如图。 {{ :icore4:icore4_arm_hal_8_2.png?direct |}} * 该寄存器的有些位在不同模式下,功能不一样,所以在图中,把寄存器分了2层,上面一层对应输出而下面的则对应输入。这里我们需要说明的是模式设置位OC4M,此部分由4位组成。总共可以配置成13种模式,我们使用的是PWM模式,所以这4位必须设置为0110/0111。这两种PWM模式的区别就是输出电平的极性相反。另外CC4S用于设置通道的方向(输入/输出)默认设置为0,就是设置通道作为输出使用。 * **(2)**捕获/比较使能寄存器(TIMx_CCER)该寄存器控制着各个输入输出通道的开关。该寄存器的各位描述如图所示: {{ :icore4:icore4_arm_hal_8_3.png?direct |}} * 该寄存器比较简单,我们这里只用到了CC4E位,该位是输入/捕获4输出使能位,要想PWM从IO口输出,这个位必须设置为1,所以我们需要设置该位为1。 * **(3)**捕获/比较寄存器(TIMx_CCR1~4),该寄存器总共有4个,对应4个通道CH1~4。我们使用的是通道2,TIM1_CCR2寄存器的各位描述如图所示: {{ :icore4:icore4_arm_hal_8_4.png?direct |}} * 在输出模式下,该寄存器的值与CNT的值比较,根据比较结果产生相应动作。利用这点,我们通过修改这个寄存器的值,就可以控制PWM的输出脉宽了。 * **(4)**断路和死区寄存器(TIMx_BDTR),如果是通用定时器,则配置以上三个寄存器就够了,但是我们使用的是高级定时器,则还需要配置:断路和死区寄存器(TIMx_BDTR),该寄存器各位描述如图所示: {{ :icore4:icore4_arm_hal_8_5.png?direct |}} * 该寄存器,我们只需要关注第15位:MOE位,要想高级定时器的PWM正常输出,则必须设置MOE位为1,否则不会有输出。 * 本实验中,iCore4的蓝色LED连接在定时器的输出接口上,可以通过定时器的PWM输出控制LED的亮度,从而实验呼吸灯的功能。 ==== 四、实验程序 ==== === 1、主函数 === int main(void) { int brightness = 0; float temp = 0.0; int data = 0; /* MCU 配置*/ /* 重置所有外围设备,初始化Flash接口和Systick */ HAL_Init(); /* 配置系统时钟 */ SystemClock_Config(); /* 初始化所有已配置的外围设备 */ MX_GPIO_Init(); MX_TIM1_Init(); /* 无限循环 */ while (1) { HAL_Delay(30); if(brightness == 100){ brightness = 0; } temp = 199 * (sin(2 * PI / 99.0 * brightness) * 0.5 + 0.5); data = (int)temp; set_compare(data); brightness ++; } } === 2、开启TIM3和GPIO时钟 === * 要使用TIM1,我们必须先开启TIM1 的时钟,这里我们还要配置PA9为复用输出,才可以实现TIM1_CH2的PWM经过PA9输出。HAL库中使能TIM1和GPIO的方法如下: void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef* tim_pwmHandle) { if(tim_pwmHandle->Instance==TIM1) { /* TIM1时钟使能*/ __HAL_RCC_TIM1_CLK_ENABLE(); } } void MX_GPIO_Init(void) { /* GPIO端口时钟使能 */ __HAL_RCC_GPIOH_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); } * 接下来便是要配置PA9复用映射为TIM1的PWM输出引脚。关于IO口复用映射,主要是通过函数HAL_GPIO_Init来实现的: void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle) { GPIO_InitTypeDef GPIO_InitStruct; if(timHandle->Instance==TIM1) { /**TIM1 GPIO 配置 PA9 ------> TIM1_CH2 */ GPIO_InitStruct.Pin = GPIO_PIN_9; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;//复用推挽输出 GPIO_InitStruct.Pull = GPIO_NOPULL;//上拉 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;//低速 GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;//PA9复用为 TIM1_CH2 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_2);//开始生成PWM信号 } } === 3、控制占空比 === * PWM 开始输出之后其占空比和频率都是固定的,而我们通过修改比较值TIM1_CCR2则可以控制CH2的输出占空比,继而控制LED的亮度。HAL库中并没有提供独立的修改占空比函数,这里我们可以编写这样一个函数如下: int set_compare(int temp) { __HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_2,temp); return 0; } ==== 五、实验步骤 ==== - 把仿真器与iCore4的SWD调试口相连(直接相连或者通过转接器相连); - 把iCore4通过Micro USB线与计算机相连,为iCore4供电; - 打开Keil MDK 开发环境,并打开本实验工程; - 烧写程序到iCore4上; - 也可以进入Debug 模式,单步运行或设置断点验证程序逻辑。 ==== 六、实验现象 ==== * iCore4双核心板蓝色LED灯亮度从亮到暗然后再从暗到亮,实现呼吸灯效果。