当前位置: 首页 > news >正文

STM32定时器输出PWM波

1. STM32的定时器的结构

STM32的T1和T8是高级定时器,T2-T5是通用定时器,他们都可以输出PWM信号,用于驱动电机等负载。其中高级定时器的结构框图如图所示,其可以输出7路PWM信号;而通用定时器可以输出4个通道的PWM信号。

图1 高级定时器的PWM信号

每个定时器的通道通过STM32的GPIO向外输出PWM信号,其映射关系如下:

图2 定时器的通道和GPIO的映射关系

2. 实验设计

为了验证STM32输出PWM信号的使用方法,我们分别使用高级定时器T1和通用定时器T2的通道1,输出PWM信号。并通过按键改变所产生PWM信号的占空比。当按下按键时,示波器上的波形的占空比跟着变化。如图所示

图3 实验波形

3. 实验代码

基于ST公司的标准库配置芯片的寄存器,关键代码如下:

3.1 main函数代码

#include "OLED.h"
#include "Key.h"
#include "PWM.h"
#include "PWMt1.h"int duty =100;int main()
{
int duty_cur =0;//定义实时的占空比
OLED_Init();
PWM_Init();
Key_Init();
TIM1_PWM_Init();OLED_ShowString(1, 1, "Duty:00%");
while(1){duty_cur=Key_GetNum();//读取按键状态,获取占空比PWM_SetCompare1(duty_cur);//设置占空比OLED_ShowNum(1, 6, duty_cur, 2);//显示到OLED上}
}

3.2  按键代码

#include "stm32f10x.h"                  // Device header
#include "public.h"extern int duty;/*** 函    数:按键初始化* 参    数:无* 返 回 值:无*/
void Key_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;/*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);		//开启GPIOB的时钟/*GPIO初始化*/GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_13;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOC, &GPIO_InitStructure);						//将PB1和PB11引脚初始化为上拉输入
}/*** 函    数:按键获取键码* 参    数:无* 返 回 值:按下按键的键码值,范围:0~2,返回0代表没有按键按下* 注意事项:此函数是阻塞式操作,当按键按住不放时,函数会卡住,直到按键松手*/
uint8_t Key_GetNum(void)
{if (GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_1) == 0)			//读PB1输入寄存器的状态,如果为0,则代表按键1按下{Delay_ms(20);											//延时消抖while (GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_1) == 0);	//等待按键松手Delay_ms(20);											//延时消抖duty=duty+10;											//置键码为1if (duty>=90)duty=90;}if (GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_13) == 0)			//读PB11输入寄存器的状态,如果为0,则代表按键2按下{Delay_ms(20);											//延时消抖while (GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_13) == 0);	//等待按键松手Delay_ms(20);											//延时消抖duty=duty-10;											//置键码为1if (duty<0)duty=0;}return duty;			//返回键码值,如果没有按键按下,所有if都不成立,则键码为默认值0
}

3.3 定时器的配置方法

3.3.1 高级定时器的配置方法

#include "PWMt1.h"void TIM1_PWM_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_BDTRInitTypeDef TIM_BDTRStructure;// 1. 使能TIM1和GPIOA时钟  
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1 | RCC_APB2Periph_GPIOA, ENABLE);  // 2. 配置PA8为复用推挽输出  
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;  
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出  
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
GPIO_Init(GPIOA, &GPIO_InitStructure);  // 3. 配置时基单元  
TIM_TimeBaseStructure.TIM_Period = 99; // ARR = 1000 - 1,PWM频率 = 72MHz / (72 * 1000) = 1kHz  
TIM_TimeBaseStructure.TIM_Prescaler = 7199; // PSC = 7200 - 1,分频后计数器时钟为1MHz  
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;  
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数  
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);  // 4. 配置输出比较通道1  
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // PWM模式1  
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 使能输出  
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable; // 互补输出不使能(因为只用通道1)  
TIM_OCInitStructure.TIM_Pulse = 500; // CCR1 = 500,占空比50%  
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 高电平有效  
TIM_OC1Init(TIM1, &TIM_OCInitStructure);  
TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable); // 使能预装载  // 5. 配置刹车和死区(高级定时器需要)  
TIM_BDTRStructure.TIM_OSSRState = TIM_OSSRState_Disable;  
TIM_BDTRStructure.TIM_OSSIState = TIM_OSSIState_Disable;  
TIM_BDTRStructure.TIM_DeadTime = 0; // 死区时间设为0  
TIM_BDTRStructure.TIM_Break = TIM_Break_Disable;  
TIM_BDTRStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;  
TIM_BDTRStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Disable;  
TIM_BDTRConfig(TIM1, &TIM_BDTRStructure);  // 6. 使能TIM1和主输出  
TIM_Cmd(TIM1, ENABLE);  
TIM_CtrlPWMOutputs(TIM1, ENABLE); // 必须使能MOE
}

3.3.2 通用定时器的配置方法

#include "stm32f10x.h"                  // Device header/*** 函    数:PWM初始化* 参    数:无* 返 回 值:无*/
void PWM_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量TIM_OCInitTypeDef TIM_OCInitStructure;							//定义结构体变量/*开启时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			//开启TIM2的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟/*GPIO重映射*/
//	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);			//开启AFIO的时钟,重映射必须先开启AFIO的时钟
//	GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);			//将TIM2的引脚部分重映射,具体的映射方案需查看参考手册
//	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);		//将JTAG引脚失能,作为普通GPIO引脚使用/*GPIO初始化*/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引脚初始化为复用推挽输出	//受外设控制的引脚,均需要配置为复用模式		/*配置时钟源*/TIM_InternalClockConfig(TIM2);		//选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟/*时基单元初始化*/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 = 7200 - 1;				//预分频器,即PSC的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            //重复计数器,高级定时器才会用到TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);             //将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元/*输出比较初始化*/TIM_OCStructInit(&TIM_OCInitStructure);							//结构体初始化,若结构体没有完整赋值//则最好执行此函数,给结构体所有成员都赋一个默认值//避免结构体初值不确定的问题TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;				//输出比较模式,选择PWM模式1TIM_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/*TIM使能*/TIM_Cmd(TIM2, ENABLE);			//使能TIM2,定时器开始运行
}/*** 函    数:PWM设置CCR* 参    数:Compare 要写入的CCR的值,范围:0~100* 返 回 值:无* 注意事项:CCR和ARR共同决定占空比,此函数仅设置CCR的值,并不直接是占空比*           占空比Duty = CCR / (ARR + 1)*/
void PWM_SetCompare1(uint16_t Compare)
{TIM_SetCompare1(TIM1, Compare);		//设置CCR1的值
}/*** 函    数:PWM设置PSC* 参    数:Prescaler 要写入的PSC的值,范围:0~65535* 返 回 值:无* 注意事项:PSC和ARR共同决定频率,此函数仅设置PSC的值,并不直接是频率*           频率Freq = CK_PSC / (PSC + 1) / (ARR + 1)*/
void PWM_SetPrescaler(uint16_t Prescaler)
{TIM_PrescalerConfig(TIM2, Prescaler, TIM_PSCReloadMode_Immediate);		//设置PSC的值
}

3.3.3 关于定时器配置方法的小结

无论是通用定时器还是高级定时器都需要做以下几件事情:

(1)开启时钟

(2)配置GPIO

(3)配置时间基准单元

主要配置分频寄存器PSC,重装寄存器ARR,这决定了PWM的周期,CCR决定占空比

(4)配置输出比较通道

(5)使能定时器

http://www.dtcms.com/a/528993.html

相关文章:

  • 重庆做网站开发的公司天津市建设工程交易管理网站
  • 网站源码是用什么做的爱链接购买链接
  • 数学 - 基础线性代数
  • 蓝牙网关是什么?能做什么?
  • Python入门与MySQL数据库操作实践指南
  • 广东网站设计服务商服装在线设计平台
  • 网站 刷流量 SEO中山建网站多少钱
  • 启动中国蚁剑antsword
  • 建行移动门户网站首页齐齐哈尔电话黄页
  • FreeRTOS - 基于ESP32 串口数据收发
  • 【释义】摩尔定律性能收益在减弱
  • REFLECTOOL: Towards Reflection-Aware Tool-Augmented Clinical Agents
  • 基于android的体育馆预约使用系统
  • 免费psd模板网站商标注册申请需要什么材料
  • 【开题答辩全过程】以 查寝打卡系统为例,包含答辩的问题和答案
  • mvc 网站开发平度市城市建设局网站
  • 旅行社网站建设规划的内容wordpress 评论模板
  • EtherCAT转EtherNet/IP工业数据采集网关:保障编码器与工控机稳定交互的整合案例
  • 网络层网际协议IP
  • 凡科免费建站平台渭南定制网站建设公司
  • 哪款纳米研磨机能将药物颗粒做到≤100nm?需要多少小时?
  • 《C语言疑难点 --- 字符函数和字符串函数专题(上)》
  • 株洲网站建设联系方式知名的家居行业网站开发
  • 华为堡垒机
  • Wordpress做什么网站赚钱外贸英文网站建设
  • MyBatis注解与XML使用对比
  • Connector
  • 招标网免费查看什么是优化师
  • 商城网站开发哪家好室内装饰设计费收费标准
  • 自动驾驶中的传感器技术70——Navigation(7)