赞
踩
任务简介
使用TIM3和TIM4,分别输出一个PWM波形,PWM的占空比随时间变化,去驱动你外接的一个LED以及最小开发板上已焊接的LED(固定接在 PC13 GPIO端口),实现两个 LED呼吸灯的效果。
实验工具:
(1)软件
- 标准库
- KEIL5:安装教程
- mcuisp(或者FlyMcu): mcuisp百度网盘链接提取码:h2xc
(2)硬件
- STM32F103C8T6的最小核心板
- LED小灯
- OC(Output Compare)输出比较
- 输出比较可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形
- 每个高级定时器和通用定时器(TIM)都拥有4个输出比较通道(CH1,CH2,CH3,CH4)
- *高级定时器的前3个通道额外拥有死区生成和互补输出的功能
- 具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速等领域。


①频率1/Ts:PWM频率等于TIM经过预分频后,计数器CNT随时间自增加到与自动重装器ARR值相等的频率。PWM频率越快,等效的模拟信号就越平稳但是性能开销就越大。
②占空比T(on)/T(s):高电平时间相当于整个周期时间的比例,占空比越大,等效模拟电压越趋近于高电平,占空比越小,等效模拟电压越趋近于低电平。
③分辨率:占空比变化步距,也就是变化的细腻程度(也就是占空比变化的最小数值,例如占空比最小只能从1%跳到2%,那么分辨率就是1%)。

这里先放图,下面解释工作流程
CNT计数器与CCR(自己设置的输出比较的一个参数值,后面会讲)。oc1的ref参考信号的值,这里给出PWM需要用到的输出控制的模式介绍。
- 注意
相当于可以由第二步的PWM输出模式和第三步的极性选择来灵活地控制,例如使用PWM1的正极性与PWM2的反极性最终的输出都是一样的

CCR是我们自己设置的用来调整占空比的捕获/比较器
占空比受CCR调控**,CCR设置得大一些,占空比就变大,CCR设置得低一些,占空比就变小**
这样输出的REF就是频率可调,占空比也可调的PWM波形,在经过极性选择和输出使能输出到GPIO口
PWM频率: Freq = CK_PSC / (PSC + 1) / (ARR + 1)

PWM占空比: Duty = CCR / (ARR + 1)

PWM分辨率: Reso = 1 / (ARR + 1)

- 第一步:RCC开启时钟,把要用的TIM外设和GPIO外设的时钟打开
- 第二步:配置时基单元
- 第三步:配置输出比较单元
- 第四步:配置GPIO,把PWM需要的GPIO口初始化为复用推挽的输出配置
- 第五步:运行控制
我们准备输出一个1KHz,占空比可任意调节,分辨率为1%的PWM波形
PWM频率: Freq = CK_PSC / (PSC + 1) / (ARR + 1)
这里CK_PSC是系统主频72MHz
即72M/(PSC+1)/(ARR+1)=1000
PWM占空比: Duty = CCR / (ARR + 1)
即CCR/(ARR+1)=50%
PWM分辨率: Reso = 1 / (ARR + 1)
即1/(ARR+1)=1%
CCR=50
PSC=719
ARR=99
我们可以调控CCR的值来控制占空比
为什么选择复用推挽输出?
如果选择普通开漏推挽输出,引脚的控制权来自于输出寄存器,如果想让定时器控制引脚,则选择复用推挽输出,这时候与输出寄存器断开,控制权移交给片上外设。这里就是CH1通道。
#include "stm32f10x.h" // Device header void PWM_Init(void) { //第一步开启TIM时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); //选择时基单元时钟,选择内部时钟 如果不调用也是默认调用 TIM_InternalClockConfig(TIM3); TIM_InternalClockConfig(TIM4); //第二步配置时基单元 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct1; TIM_TimeBaseInitStruct1.TIM_ClockDivision = TIM_CKD_DIV1;//这里的值关系不大 TIM_TimeBaseInitStruct1.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInitStruct1.TIM_Period = 100-1;//自动重装计时器的值 ARR TIM_TimeBaseInitStruct1.TIM_Prescaler = 7200-1; //预分频器的值 PSC TIM_TimeBaseInitStruct1.TIM_RepetitionCounter = 0; //重复计数器的值,高级定时器才有,这里直接给0 TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct1); //----------------------------------------------------------------------- TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct2; TIM_TimeBaseInitStruct2.TIM_ClockDivision = TIM_CKD_DIV1;//这里的值关系不大 TIM_TimeBaseInitStruct2.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInitStruct2.TIM_Period = 100-1;//自动重装计时器的值 ARR TIM_TimeBaseInitStruct2.TIM_Prescaler = 7200-1; //预分频器的值 PSC TIM_TimeBaseInitStruct2.TIM_RepetitionCounter = 0; //重复计数器的值,高级定时器才有,这里直接给0 TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStruct2); //第三步设置输出比较单元 TIM_OCInitTypeDef TIM_OCInitStruct1; TIM_OCStructInit(&TIM_OCInitStruct1);//先给这个结构体赋初值,如果不赋初值后面我们也不给所有成员变量赋值的话,会出现问题 TIM_OCInitStruct1.TIM_OCMode = TIM_OCMode_PWM1 ; //设置输出比较模式 TIM_OCInitStruct1.TIM_OCPolarity = TIM_OCPolarity_High; //设置输出比较的极性,High值高极性,极性不翻转,REF直接输出 TIM_OCInitStruct1.TIM_OutputState = TIM_OutputState_Enable; //设置输出使能 TIM_OCInitStruct1.TIM_Pulse =10; //设置CCR的寄存器值 TIM_OC1Init(TIM3,&TIM_OCInitStruct1); //-------------------------------------------------- TIM_OCInitTypeDef TIM_OCInitStruct2; TIM_OCStructInit(&TIM_OCInitStruct2);//献给这个结构体赋初值,如果不赋初值后面我们也不给所有成员变量赋值的话,会出现问题 TIM_OCInitStruct2.TIM_OCMode = TIM_OCMode_PWM1 ; //设置输出比较模式 TIM_OCInitStruct2.TIM_OCPolarity = TIM_OCPolarity_High; //设置输出比较的极性,High值高极性,极性不翻转,REF直接输出 TIM_OCInitStruct2.TIM_OutputState = TIM_OutputState_Enable; //设置输出使能 TIM_OCInitStruct2.TIM_Pulse =10; //设置CCR的寄存器值 TIM_OC1Init(TIM4,&TIM_OCInitStruct2); //第四步配置GPIO,把PWM需要的GPIO口初始化为复用推挽的输出配置 GPIO_InitTypeDef GPIO_InitStructure1; GPIO_InitStructure1.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure1.GPIO_Pin = GPIO_Pin_6; GPIO_InitStructure1.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure1); //--------------------------------------------------- GPIO_InitTypeDef GPIO_InitStructure2; GPIO_InitStructure2.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure2.GPIO_Pin = GPIO_Pin_6; GPIO_InitStructure2.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure2); //启动定时器 TIM_Cmd(TIM3,ENABLE); TIM_Cmd(TIM4,ENABLE); } //TIM3设置CH1通道的CCR的值 void PWM_SetCompare3(uint16_t Compare) { TIM_SetCompare1(TIM3,Compare); } //TIM4设置CH1通道的CCR的值 void PWM_SetCompare4(uint16_t Compare) { TIM_SetCompare1(TIM4,Compare); }
#ifndef _PWM_H
#define _PWM_H
void PWM_Init(void);
void PWM_SetCompare3(uint16_t Compare);
void PWM_SetCompare4(uint16_t Compare);
#endif
#include "stm32f10x.h" // Device header #include "Delay.h" #include "PWM.h" uint8_t i; int main(void) { PWM_Init(); while(1) { //循环调用修改CCR的值,可以通过调整延时函数的值来控制呼吸快慢 for(i = 0; i<=100;i++) { PWM_SetCompare3(i); PWM_SetCompare4(i); Delay_ms(5); } for(i = 0; i<=100;i++) { PWM_SetCompare3(100-i); PWM_SetCompare4(100-i); Delay_ms(5); } } }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。