stm32定时器学习二——PWM设置
/* STM32 嵌入式学习入门(5)——PWM的实现 上一篇博文介绍了定时器和PWM的基本的原理,本篇博文从代码层面来介绍PWM的具体实现。同样,还是以博主所用的开发板——正点原子开发板STM32F103ZET6为例。 一、基于STM32的PWM输出配置步骤(初始化操作): 1. 操作步骤(基于STM32固件库、使用定时器3的PWM功能):
(1)使能相关时钟(定时器3和相关IO口时钟。):
//要使用什么外设就要先使能相关外设所挂载的时钟,这些内容在最开始GPIO那块就有提到STM32的GPIO介绍
①使能定时器3时钟:RCC_APB1PeriphClockCmd();
②使能GPIOB时钟:RCC_APB2PeriphClockCmd(); (2)初始化IO口为复用功能输出。函数:GPIO_Init();
//同样,IO口初始化的操作在STM32的GPIO介绍那篇文章里也说到了。
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
//这里我们是要把引脚用作定时器的PWM输出引脚,因此要重映射配置。所以需要开启AFIO时钟。同时设置重映射。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); (3)初始化定时器:ARR,PSC等:TIM_TimeBaseInit();ARR寄存器在上一篇文章讲原理时候已经说到了。PWM原理 (4)初始化输出比较参数:TIM_OC2Init();
(5)使能预装载寄存器: TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
(6)使能定时器。TIM_Cmd();
(7)不断改变比较值CCRx,达到不同的占空比效果:TIM_SetCompare2(); 2.初始化源代码:
(1)以STM32F103ZET6为芯片的开发板的PWM初始化,这里只是初始化一个通道用作PWM输出 */
//TIM3 PWM部分初始化
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM3_PWM_Init(u16 arr,u16 psc)//STM32F103ZET6
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能定时器3时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE); //使能GPIO外设和AFIO复用功能模块时钟 GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射 TIM3_CH2->PB5 //设置该引脚为复用输出功能,输出TIM3 CH2的PWM脉冲波形 GPIOB.5
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO //初始化TIM3
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = ; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位 //初始化TIM3 CH2 PWM模式
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
TIM_OC2Init(TIM3, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM3 OC2 TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIM3在CCR2上的预装载寄存器 TIM_Cmd(TIM3, ENABLE); //使能TIM3
}
/*
(2)下面的代码是博主做嵌入式循迹小车的项目中的PWM初始化,用了TIM1的两个通道(通道1和通道4)去分别控制两个驱动轮的转速,从而实现让小车转向的功能。和上面的初始化代码的不同主要在于小车项目中用了两个通道,同时项目使用的开发板的芯片是STM32F103RCT6。在这里贴出源代码,做一比较。 */
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM1_PWM_Init(u16 arr,u16 psc)//STM32F103RCT6
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能GPIOA外设时钟使能 //设置该引脚为复用输出功能,输出TIM1 CH1和CH4的PWM脉冲波形
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_11;//TIM_CH1
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure); TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 80K
TIM_TimeBaseStructure.TIM_Prescaler = psc; //设置用来作为TIMx时钟频率除数的预分频值 不分频
TIM_TimeBaseStructure.TIM_ClockDivision = ; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_Pulse = ; //设置待装入捕获比较寄存器的脉冲值
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高 TIM_OC1Init(TIM1, &TIM_OCInitStructure); //根据TIM_OC1InitStruct中指定的参数初始化外设TIM1的通道1
TIM_OC4Init(TIM1, &TIM_OCInitStructure); //根据TIM_OC2InitStruct中指定的参数初始化外设TIM1的通道4 TIM_CtrlPWMOutputs(TIM1,ENABLE); //MOE 主输出使能 TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable); //CH1预装载使能 通道1
TIM_OC4PreloadConfig(TIM1,TIM_OCPreload_Enable); //CH4预装载使能 通道4 TIM_ARRPreloadConfig(TIM1,ENABLE); //使能TIMx在ARR上的预装载寄存器(x==1) TIM_Cmd(TIM1,ENABLE); //使能TIM1 } /* 初始化函数在主函数的开头处调用,调用函数的两个参数根据自己需要去设定。 二、PWM的操作: 上面的初始化结束后就可以利用相关引脚输出PWM波了。这个输出过程简单说就是改变比较值CCRx的操作,就是往CCR寄存器里写值。这一点上一篇文章里有分析到。下面先介绍一下往CCRx寄存器里写值操作的函数(来自官方库函数):TIM_SetCompare1(); */
/**
* @brief Sets the TIMx Capture Compare1 Register value
* @param TIMx: where x can be 1 to 17 except 6 and 7 to select the TIM peripheral.
* @param Compare1: specifies the Capture Compare1 register new value.
* @retval None
*/
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1)
{
/* Check the parameters */
assert_param(IS_TIM_LIST8_PERIPH(TIMx));//有效性判断
/* Set the Capture Compare1 Register value */
TIMx->CCR1 = Compare1;
}
/* 说明:和这个函数类似的一共有四个:TIM_SetCompare1(); TIM_SetCompare2(); TIM_SetCompare3(); TIM_SetCompare4();其实现框架都是一样的,四个函数分别对应四个通道,使用哪个通道调用哪个函数,要对应起来。 下面先介绍还是以自己嵌入式循迹小车的项目为例,比如小车直行时就是在执行下面这个函数。 */
u8 Case_F_SIGN(void)//直行
{
while()
{
delay_ms();
pwmvalR=;
pwmvalL=;
TIM_SetCompare1(TIM1,pwmvalR);
TIM_SetCompare4(TIM1,pwmvalL);
t=SensorScan();
if(t!=F_SIGN)
return t;
}
}
/*
pwmvalR和pwmvalL是两个全局变量,它们的值是根据项目需要和小车硬件情况实际测出来的,然后调用两个函数,写入相关寄存器,,下面是调用SensorScan();看小车是不是还沿着轨迹在行驶,如果不是,那么跳出while(1)循环,否则,返回主调函数当前小车的状态。这段代码现在看写得不是特别好了,但是说明这个函数的用法还是没问题的。 高级控制定时器(TIM1 和TIM8) TIM1和TIM8定时器的功能包括:
● 16位向上、向下、向上/ 下自动装载计数器
● 16位可编程( 可以实时修改)预分频器,计数器时钟频率的分频系数为1~65535 之间的任意数值
● 多达4个独立通道:
─ 输入捕获
─ 输出比较
─ PWM生成(边缘或中间对齐模式)
─ 单脉冲模式输出
● 死区时间可编程的互补输出
● 使用外部信号控制定时器和定时器互联的同步电路
● 允许在指定数目的计数器周期之后更新定时器寄存器的重复计数器
● 刹车输入信号可以将定时器输出信号置于复位状态或者一个已知状态
● 如下事件发生时产生中断/DMA :
─ 更新:计数器向上溢出/ 向下溢出,计数器初始化(通过软件或者内部/ 外部触发)
─ 触发事件(计数器启动、停止、初始化或者由内部/ 外部触发计数)
─ 输入捕获
─ 输出比较
─ 刹车信号输入
● 支持针对定位的增量(正交)编码器和霍尔传感器电路
● 触发输入作为外部时钟或者按周期的电流管理 通用定时器(TIMx) 通用TIMx (TIM2、TIM3、TIM4和TIM5)定时器功能包括:
● 16位向上、向下、向上/ 向下自动装载计数器
● 16位可编程( 可以实时修改)预分频器,计数器时钟频率的分频系数为1~65536 之间的任意数值
● 4个独立通道:
─ 输入捕获
─ 输出比较
─ PWM生成(边缘或中间对齐模式)
─ 单脉冲模式输出
● 使用外部信号控制定时器和定时器互连的同步电路
● 如下事件发生时产生中断/DMA :
─ 更新:计数器向上溢出/ 向下溢出,计数器初始化(通过软件或者内部/ 外部触发)
─ 触发事件(计数器启动、停止、初始化或者由内部/ 外部触发计数)
─ 输入捕获
─ 输出比较
● 支持针对定位的增量(正交)编码器和霍尔传感器电路
● 触发输入作为外部时钟或者按周期的电流管理 基本定时器(TIM6 和TIM7) TIM6和TIM7定时器的主要功能包括:
● 16位自动重装载累加计数器
● 16位可编程( 可实时修改)预分频器,用于对输入的时钟按系数为1~65536 之间的任意数值
分频
● 触发DAC的同步电路
● 在更新事件(计数器溢出)时产生中断/DMA 请求 STM32的通用定时器是一个通过可编程预分频器(PSC)驱动的16 位自动装载计数器(CNT)构成。STM32的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和PWM)等。 使用定时器预分频器和RCC时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。STM32的每个通用定时器都是完全独立的,没有互相共享的任何资源。
脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。简单一点,就是对脉冲宽度的控制。STM32的定时器除了TIM6和7。其他的定时器都可以用来产生PWM输出。其中高级定时器TIM1和TIM8可以同时产生多达7路的PWM输出。而通用定时器也能同时产生多达4路的PWM输出,这样,STM32最多可以同时产生30路PWM输出! 要使STM32的通用定时器TIMx产生PWM输出,除了定时器介绍的寄存器外,我们还会用到3 个寄存器,来控制PWM 的。这三个寄存器分别是:捕获/比较模式寄存器(TIMx_CCMR1/2)、捕获/比较使能寄存器(TIMx_CCER)、捕获/比较寄存器(TIMx_CCR1~4)。 TIM3_CH2默认是接在PA7面的,而我们的DS0接在PB5上面,如果普通MCU,可能就只能用飞线把PA7飞到PB5上来实现了,不过,我们用的是STM32,它比较高级,可以通过重映射功能,把TIM3_CH2映射到PB5上。 STM32的重映射控制是由复用重映射和调试IO 配置寄存器(AFIO_MAPR)控制的。 1)开启TIM3时钟以及复用功能时钟,配置PB5为复用输出。 要使用TIM3,我们必须先开启TIM3的时钟,还要配置PB5为复用输出,这是因为TIM3_CH2通道将重映射到PB5上,此时,PB5属于复用功能输出。 库函数使能TIM3时钟的方法是:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能定时器3时钟 库函数设置AFIO时钟的方法是:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //复用时钟使能 设置PB5为复用功能输出的方法:GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 2)设置TIM3_CH2重映射到PB5上。 因为TIM3_CH2默认是接在PA7上的,所以我们需要设置TIM3_REMAP为部分重映射(通过AFIO_MAPR配置),让TIM3_CH2重映射到PB5上面。在库函数函数里面设置重映射的函数是:
void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState); STM32重映射只能重映射到特定的端口。第一个入口参数可以理解为设置重映射的类型,比如TIM3部分重映射入口参数为 GPIO_PartialRemap_TIM3,这点可以顾名思义了。所以TIM3部分重映射的库函数实现方法是: GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); 3)初始化TIM3,设置TIM3的ARR和PSC。 在开启了TIM3的时钟之后,我们要设置ARR和PSC两个寄存器的值来控制输出PWM的周期。当PWM周期太慢(低于50Hz)的时候,我们就会明显感觉到闪烁了。因此,PWM周期在这里不宜设置的太小。这在库函数是通过TIM_TimeBaseInit函数实现的,在上一节定时器中断章节我们已经有讲解,这里就不详细讲解,调用的格式为:
TIM_TimeBaseStructure.TIM_Period = arr; //设置自动重装载值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的 4)设置TIM3_CH2的PWM模式,使能TIM3的CH2输出。 接下来,我们要设置TIM3_CH2为PWM模式(默认是冻结的),因为我们的DS0是低电平亮,而我们希望当CCR2的值小的时候,DS0就暗,CCR2值大的时候,DS0就亮,所以我们要通过配置TIM3_CCMR1的相关位来控制TIM3_CH2的模式。在库函数中,PWM通道设置是通过函数TIM_OC1Init()~TIM_OC4Init()来设置的,不同的通道的设置函数不一样,这里我们使用的是通道2,所以使用的函数是TIM_OC2Init()。
void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct); 5)使能TIM3。 在完成以上设置了之后,我们需要使能TIM3。使能TIM3的方法前面已经讲解过: TIM_Cmd(TIM3, ENABLE); //使能TIM3
6)修改TIM3_CCR2来控制占空比。
最后,在经过以上设置之后,PWM其实已经开始输出了,只是其占空比和频率都是固定的,而我们通过修改TIM3_CCR2则可以控制CH2的输出占空比。继而控制DS0的亮度。 在库函数中,修改TIM3_CCR2占空比的函数是:
void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2); 理所当然,对于其他通道,分别有一个函数名字,函数格式为TIM_SetComparex(x=1,2,3,4)。
通过以上6个步骤,我们就可以控制TIM3的CH2输出PWM波了。
*/
stm32定时器学习二——PWM设置的更多相关文章
- STM32定时器学习---基本定时器
STM32F1系列的产品,除了互联网产品外,工作8个,3种定时器,其中一种就是基本定时器.那么STM32单片机的基本定时器如何操作以及编程呢? 下面我们就来详细的了解一下 STM32F1系列的产品,除 ...
- 用STM32定时器中断产生PWM控制步进电机
控制步进电机可以使用PWM.定时器中断.延时,这里用的就是定时器中断来让它转动. 一.硬件部分1.使用的硬件板子用的是正点原子的STM32F103 mini板,驱动器是DM420(DM420驱动器资料 ...
- beego框架学习(二) -路由设置
路由设置 什么是路由设置呢?前面介绍的 MVC 结构执行时,介绍过 beego 存在三种方式的路由:固定路由.正则路由.自动路由,接下来详细的讲解如何使用这三种路由. 基础路由 从beego1.2版本 ...
- stm32定时器输出移相PWM(非主从模式)
背景:由于项目需要,需要stm32输出任意相角度的PWM 前提知识: 1.stm32定时器的Tim,一般有多个OC.具体差别根据型号来定. 2.定时器的使能,理论上是多个通道同时使能 3.TIM_OC ...
- STM32定时器输出PWM频率和步进电机控制速度计算
1.STM32F4系列定时器输出PWM频率计算 第一步,了解定时器的时钟多少: 我们知道AHP总线是168Mhz的频率,而APB1和APB2都是挂在AHP总线上的. (1)高级定时器timer1, t ...
- Java开发学习(二十四)----SpringMVC设置请求映射路径
一.环境准备 创建一个Web的Maven项目 参考Java开发学习(二十三)----SpringMVC入门案例.工作流程解析及设置bean加载控制中环境准备 pom.xml添加Spring依赖 < ...
- 用STM32定时器测量信号频率——测频法和测周法[原创cnblogs.com/helesheng]
工业测试与控制系统中,经常需要对未知信号的频率进行测试.对于10MHz以下的信号,用单片机(MCU)定时器完成这项任务显然是最常见和最佳的选择.目前性价比最高的单片机STM32拥有功能强大且数量众多的 ...
- [ZigBee] 13、ZigBee基础阶段性回顾与加深理解——用定时器1产生PWM来控制LED亮度(七色灯)
引言:PWM对于很多软件工程师可能又熟悉又陌生,以PWM调节LED亮度为例,其本质是在每个周期都偷工减料一些,整体表现出LED欠压亮度不同的效果.像大家看到的七色彩灯其原理也类似,只是用3路PWM分别 ...
- STM32 定时器用于外部脉冲计数(转)
源:STM32 定时器用于外部脉冲计数 STM32 定时器(一)——定时器时间的计算 STM32的定时器是灰常NB的,也是灰常让人头晕的(当然是对于白菜来说的). STM32中的定时器有很多用法: ( ...
随机推荐
- Net Core应用,在CentOS上运行
Net Core应用,在CentOS上运行 本文主要介绍下运用docker虚拟技术打包Asp.net core应用. Docker作为一个开源的应用容器引擎,近几年得到广泛的应用,使用Docker我们 ...
- 转 MySQL权限管理
###sample: #####view all userSELECT user, host from mysql.user;mysql> SELECT user, host from mysq ...
- Spark Mllib里如何程序输出数据集的条数(图文详解)
不多说,直接上干货! 具体,见 Hadoop+Spark大数据巨量分析与机器学习整合开发实战的第17章 决策树多元分类UCI Covertype数据集
- Ubuntu下安装Yarm-PM2
首先打开yarm的官网.https://www.yarnpkg.com/zh-Hant/ (一)yarn的官方安装方法: 1.上通过 Debian 套件安裝 Yarn,粘贴以下命令 curl -sS ...
- MYSQL查询~ 存在一个表而不在另一个表中的数据
A.B两表,找出ID字段中,存在A表,但是不存在B表的数据.A表总共13w数据,去重后大约3W条数据,B表有2W条数据,且B表的ID字段有索引. 方法一 使用 not in ,容易理解,效率低 ~执 ...
- Aspose.word直接转pdf
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...
- Jquery each跳出循环
Jquery each跳出循环break--return false--跳出所有循环continue--return true--跳出当前循环
- Springboot优点总结
谈到 Spring Boot,就让我们先来了解它的优点 . 依据官方的文档, Spring Boot 的优点如下: --创建独立的 Spring 应用程序 : --嵌入的 Tomcat . Jetty ...
- 初学Vue.js(2.x版本)
首先肯定是打开官网查看文档了,没想到我太高估了自己,看的我头晕也不知道到底说了个啥.没办法,只能另寻他法,好在有菜鸟教程.然而我还是想多了,不稀饭一点点看下去,只想快点明白它到底说了个啥.嗯,找来找去 ...
- Brackets安装angularjs插件
Brackets是Adobe公司研发的一款开源WEB前端开发框架,界面清爽简约,代码提示功能比较强大,而且支持第三方插件,其提供的插件库中有大量的对Brackets感兴趣的开发人员所开发的插件,使用者 ...