历史上的今天
返回首页

历史上的今天

今天是:2025年08月06日(星期三)

正在发生

2021年08月06日 | STM32—TIMx输出PWM信号驱动MG996R舵机

2021-08-06 来源:eefocus

一.前言

利用STM32的TIM3的通道1、通道2,输出俩路PWM信号,驱动MG996R舵机。

涉及到:TIM定时器基本原理,TIM定时中断、TIM输出PWM信号、MG996R舵机驱动原理


二.MG996R舵机简介

MG996R舵机单线驱动,是一款360°舵机,180°舵机与360°舵机的区别就是:180°舵机可以直接控制舵机旋转的角度,但舵机只能够旋转180°;360°舵机无法直接控制其旋转角度,只能控制其转动方向和速度。


舵机的驱动信号由周期为20ms的脉冲来控制:

当高电平持续时间为0.5~1.5ms时,舵机正转,时间越小转动越快

当高电平持续时间为1.5~2.5ms时,舵机反转,时间越大转动越快

当高电平持续时间为1.5ms或者其他时间时,舵机停止转动

在这里插入图片描述

三.TIM定时器简介

STM32F1系列中,有8个定时器,分别为基本定时器(2个)、通用定时器(2个)、高级定时器(2个),如图:

在这里插入图片描述

这些定时器的相同点:

1.计数器的分辨率都是16位;

2.预分频系数都是16位(2的16次方),1-65535;

3.都可以产生DMA请求;


各自的特点:

1.基本定时器只可以向上计数,而通用定时器和高级定时器既可以向上计数也可以向下计数;

2.基本定时器没有输入捕获、输出比较功能;

3.高级定时器支持互补输出;

一般输出PWM信号只用通用定时器即可。


四.通用定时器TIMx

1.TIMx主要功能

通用TIMx定时器(TIM2、TIM3、TIM4和TIM5)功能主要包括如下:


16位向上、向下、向上/向下自动装载计数器

16位可编程(可以实时修改)预分频器,分频系数为1~65535

四种独立通道功能:

1.输入捕获

2.输出比较

3.PWM生成

4.单脉冲输出

使用外部信号控制定时器和定时器互连的同步电路

可以由如下事件触发中断或者DMA:

1.更新,即计数器溢出,或者计数器初始化

2.特定的触发事件,比如:计数器启动、停止、初始化等等

3.输入捕获

4.输出比较

支持针对定位的增量(正交)编码器和霍尔传感电路

触发输入作为外部时钟或者按周期的电流管理

看起来功能很多,实际做项目的时候都是一条龙服务,就是一套流水线操作就完成了TIMx的全部功能配置。


2.TIMx框图

TIMx的框图如下:

在这里插入图片描述

按照我个人的理解和实践中积累的经验,可以将框图从逻辑上分为四部分:

橙色:时基部分,负责选择时钟源

蓝色:计数部分,负责根据预分频后的时钟进行计数、自动装载工作

绿色:输入捕获部分

紫色:输出比较部分


在这里插入图片描述3.计数单元

可编程通用定时器的主要部分是一个16位计数器和其相关的自动装载寄存器,前面也说了,计数器可以向上、向下、双向计数。既然要计数,那就必须要知道计数的多少和每一次计数的时间。计数器的时钟由预分频器对时钟源分频得到。

时基单元包括:


计数器寄存器(TIMx_CNT)

预分频器寄存器(TIMx_PSC)

自动装载寄存器(TIMx_ARR)

计数器寄存器中存储的是当前计数的值,自动装载寄存器中存储的是目标计数值,当计数器溢出后,会重新装填目标计数值,而预分频器寄存器中的是对时钟的分频系数。


4.时钟选择

计数器的时钟可以由如下时钟源提供:


内部时钟(CK_INT)

外部时钟模式1:外部输入引脚(TIx)

外部时钟模式2:外部触发输入(ETR)

内部触发输入(ITRx):使用一个定时器作为另一个定时器的预分频器

我们主要使用内部时钟CK_INT,CK_INT是从APB1倍频来的,当APB1的时钟分频数为1时(36MHz),TIMx的时钟就是APB1的2倍,即72MHz。


5.输出比较PWM

有专门的三个寄存器来控制PWM:


捕获/比较模式寄存器(TIMx_CCMR1/2)

捕获/比较使能寄存器(TIMx_CCER)

捕获/比较寄存器(TIMx_CCR1~4)

五.TIM3输出双路PWM信号代码详解

1.TIMx初始化结构体详解

输出PWM用到的TIMx初始化结构体有:

1.时基初始化结构体TIM_TimeBaseInitTypeDef

2.输出比较初始化结构体TIM_OCInitTypeDef


1.时基结构体TIM_TimeBaseInitTypeDef

用于定时器基本参数的设置,使用void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)函数进行初始化:


typedef struct {

 uint16_t TIM_Prescaler;        // 预分频器

 uint16_t TIM_CounterMode;      // 计数模式

 uint32_t TIM_Period;           // 定时器周期

 uint16_t TIM_ClockDivision;    // 时钟分频

 uint8_t TIM_RepetitionCounter; // 重复计算器

 } TIM_TimeBaseInitTypeDef;


TIM_Prescaler:预分频器设置,只有经过预分频器后的时钟才是CK_CNT,计数器时钟频率 (fCK_CNT) 等于fCK_PSC / (PSC[15:0] + 1),可实现 1 至 65536 分频。

TIM_CounterMode:定时器计数模式,可设置向上计数、向下计数和中心对齐计数三种模式。

TIM_Period:设置的是自动重装寄存器ARR的值,ARR为要装载到影子寄存器的值,可设置 1 至 65536 。

TIM_ClockDivision:时钟分频,设置定时器时钟 CK_INT 频率与死区发生器以及数字滤波器采样时钟频率分频比。可以选择 1、 2、 4 分频。

TIM_RepetitionCounter:重复计数器,只有八位,只存在与高级定时器。


一般来讲,我们只需要设置


uint16_t TIM_Prescaler;        // 预分频器

 uint16_t TIM_CounterMode;      // 计数模式

 uint32_t TIM_Period;           // 定时器周期


这三个成员就可以实现定时器的基本参数设置。


2.输出比较初始化结构体TIM_OCInitTypeDef

使用输出比较模式时就需要配置此结构体,使用void TIM_OCxInit(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct)函数进行初始化:


typedef struct {

 uint16_t TIM_OCMode;         // 比较输出模式

 uint16_t TIM_OutputState;    // 比较输出使能

 uint16_t TIM_OutputNState;   // 比较互补输出使能

 uint32_t TIM_Pulse;          // 脉冲宽度

 uint16_t TIM_OCPolarity;     // 输出极性

 uint16_t TIM_OCNPolarity;    // 互补输出极性

 uint16_t TIM_OCIdleState;    // 空闲状态下比较输出状态

 uint16_t TIM_OCNIdleState;   // 空闲状态下比较互补输出状态

 } TIM_OCInitTypeDef;


TIM_OCMode:比较输出模式选择,总共有八种,常用的为 PWM1/PWM2。它设定

CCMRx 寄存器 OCxM[2:0]位的值。

TIM_OutputState:比较输出使能,决定最终的输出比较信号 OCx 是否通过外部引脚输

出。它设定 TIMx_CCER 寄存器 CCxE/CCxNE 位的值。

TIM_OutputNState:比较互补输出使能,决定 OCx 的互补信号 OCxN 是否通过外部引脚

输出。它设定 CCER 寄存器 CCxNE 位的值。

TIM_Pulse:比较输出脉冲宽度,实际设定比较寄存器 CCR 的值,决定脉冲宽度。可

设置范围为 0 至 65535。

TIM_OCPolarity:比较输出极性,可选 OCx 为高电平有效或低电平有效。它决定着定

时器通道有效电平。它设定 CCER 寄存器的 CCxP 位的值。

TIM_OCNPolarity:比较互补输出极性,可选 OCxN 为高电平有效或低电平有效。它

设定 TIMx_CCER 寄存器的 CCxNP 位的值。

TIM_OCIdleState:空闲状态时通道输出电平设置,可选输出 1 或输出 0,即在空闲状

态(BDTR_MOE 位为 0)时,经过死区时间后定时器通道输出高电平或低电平。它设定

CR2 寄存器的 OISx 位的值。

TIM_OCNIdleState:空闲状态时互补通道输出电平设置,可选输出 1 或输出 0,即在

空闲状态(BDTR_MOE 位为 0)时,经过死区时间后定时器互补通道输出高电平或低电

平,设定值必须与 TIM_OCIdleState 相反。它设定是 CR2 寄存器的 OISxN 位的值。


当要输出PWM信号时只需要配置如下成员即可:


 uint16_t TIM_OCMode;         // 比较输出模式

 uint16_t TIM_OCPolarity;     // 输出极性 

 uint16_t TIM_OutputState;    // 比较输出使能


PWM的模式:


PWM1:向上计数时CNTCCR 时为有效电平

PWM2:向上计数时CNTCCR 时为无效电平


输出极性决定了有效电平是高电平还是低电平。


2.TIM3输出俩路PWM初始化代码

/* 利用TIM3通道2输出PWM  PA6、PA7 输出极性高——高电平有效

ARR:预装载值(决定频率)

CCR:设定的比较值(决定占空比)

CNT:计数值

PWM1:向上计数时CNTCCR 时为有效电平

PWM2:向上计数时CNTCCR 时为无效电平

psc:时钟预分频数

*/

void TIM3_PWM_Init( uint16_t arr,uint16_t psc )

{

/* 初始化结构体 */

TIM_OCInitTypeDef TIM_OCInitStruct;

GPIO_InitTypeDef GPIO_InitStruct;

TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;

RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE );

RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM3, ENABLE );

/* PA7:复用推挽输出 */

GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7 ;

GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init( GPIOA, &GPIO_InitStruct );

/* PA6:复用推挽输出 */

GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 ;

GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init( GPIOA, &GPIO_InitStruct );

/* 初始化TIM3 基本配置 */

TIM_DeInit( TIM3 );

TIM_TimeBaseInitStruct.TIM_Period = arr;

TIM_TimeBaseInitStruct.TIM_Prescaler = psc;

TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;

TIM_TimeBaseInit( TIM3, &TIM_TimeBaseInitStruct );

/* 初始化TIM3通道2 PWM配置 */

/* TIM_OutputNState, TIM_OCNPolarity, TIM_OCIdleState 和 TIM_OCNIdleState 是

高级定时器 TIM1 和 TIM8 才用到的。 */

TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;//PWM模式1

TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;//输出极性——高极性

TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;//输出使能

TIM_OCInitStruct.TIM_Pulse = 199;//比较值CCR,可以不用配置,因为后期肯定要该

TIM_OC2Init( TIM3, &TIM_OCInitStruct );//PA7

TIM_OC1Init( TIM3, &TIM_OCInitStruct );//PA6


/* 使能预装载寄存器 */

TIM_OC2PreloadConfig( TIM3, TIM_OCPreload_Enable );

TIM_OC1PreloadConfig( TIM3, TIM_OCPreload_Enable );

/* 使能自动装载的预装载寄存器 */

TIM_ARRPreloadConfig( TIM3, ENABLE );

/* 使能TIM3 */

TIM_Cmd( TIM3, ENABLE );

/*

从这里开始TIM3已经开始输出PWM了

此时PWM输出的频率和占空比都是固定的,可以通过

void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2);

函数来调整比较值,从而调整占空比(通道2)

*/

}


传入函数的参数uint16_t arr,uint16_t psc确定了PWM信号的周期,使用void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2);函数改变ccr,从而改变PWM信号的占空比。


3.主函数

int main(void)

{

// uint8_t k=5;

// NVIC_PriorityGroupConfig( NVIC_PriorityGroup_2 );

//  TIM4_Delay_Init( 9999,7199 );

TIM3_PWM_Init( 199,7199 );//  频率为72000000/14400=5000Hz 20ms周期脉冲

// USART1_Config();

SysTick_Init();


/*                  

20ms脉冲  

5-14  正转,值越小,转的越快

16-25 反转,值越大,转的越快

*/

TIM_SetCompare1( TIM3, 14 );

TIM_SetCompare2( TIM3, 14 );

SysTick_Delay_Ms( 500);

TIM_SetCompare2( TIM3, 16 );

    TIM_SetCompare2( TIM3, 16 );

SysTick_Delay_Ms( 500);

TIM_SetCompare1( TIM3, 50);

TIM_SetCompare2( TIM3, 50);


}


可以控制俩个舵机的转动,因为是360°舵机,所以我采用控制舵机转动的速度和转动的时间来控制转动的角度,代码是我亲测可以使用的

推荐阅读

史海拾趣

DL Instruments LLC公司的发展小趣事

DL Instruments的成功离不开其领导层的智慧与远见。David Woolston先生作为公司的创始人之一,凭借其丰富的行业经验和敏锐的市场洞察力,带领公司不断突破自我、超越竞争对手。他注重人才培养和技术创新,为公司的发展奠定了坚实的基础。

BH Electronics公司的发展小趣事

近年来,随着环保意识的提高,BH Electronics积极响应国家绿色发展的号召,开始了绿色转型之路。公司加大了对环保技术的研发和应用力度,推出了一系列绿色环保产品。同时,BH Electronics还优化了生产流程,减少了能源消耗和废物排放。这些举措不仅提升了公司的环保形象,也为公司的可持续发展注入了新的动力。

这五个故事只是BH Electronics发展历程中的一部分,但它们却生动地展现了这家公司在电子行业中的崛起之路。从初创时期的筚路蓝缕,到技术创新的突破;从国际化战略的拓展,到品质管理的提升;再到绿色发展的转型,BH Electronics始终保持着敏锐的市场洞察力和不懈的创新精神。正是这些因素的共同作用,使得BH Electronics能够在激烈的市场竞争中脱颖而出,成为电子行业中的佼佼者。

亿宝科技(CNIBAO)公司的发展小趣事

随着环保意识的不断提高,亿宝科技积极响应国家绿色发展的号召。公司引进先进的环保设备和技术,减少生产过程中的污染物排放。同时,亿宝科技还注重产品的环保性能设计,推出了一系列绿色电子产品。这些产品不仅符合国家的环保标准,还赢得了消费者的青睐和认可。在绿色发展的道路上,亿宝科技展现了企业的责任和担当。

Dfx公司的发展小趣事

随着智能家居市场的不断发展,某智能家居企业面临着如何将各种智能设备无缝连接、实现高效协同的挑战。通过引入DFX的设计理念,该企业成功实现了智能家居产品的标准化、模块化和可扩展性设计。这种设计方式使得不同设备之间可以方便地进行连接和通信,提高了系统的整体性能和用户体验。同时,该企业还通过优化生产流程和加强质量控制等手段,确保了产品的稳定性和可靠性。

这些故事虽然基于虚构的情境,但融入了电子行业中常见的实际问题和发展趋势。通过引入DFX的设计理念,这些企业成功解决了面临的挑战,提升了产品竞争力并赢得了市场的认可。

宁波晨翔电子(CONNFLY)公司的发展小趣事

作为一家有社会责任感的企业,晨翔电子始终关注环保问题。公司在生产过程中积极采用环保材料和工艺,减少对环境的影响。同时,公司还积极参与社会公益活动,回馈社会。这些举措不仅体现了公司的环保意识和社会责任感,也为公司赢得了更多客户和社会的认可和支持。

ACCRETECH公司的发展小趣事

宁波晨翔电子有限公司(CONNFLY)成立于1998年(前身宁波正青电子有限公司),初创时期主要致力于连接器及线材产品的研发与生产。在创始团队的共同努力下,公司逐渐在电子连接器市场找到了自己的定位,通过不断的技术创新和品质提升,逐渐获得了市场的认可。

问答坊 | AI 解惑

吐血力作:TI系列硬件设计电路参考

我收藏的一些TI各个系列的电路,包括2000,5000,6000。不是很全,但对于一般的系统设计会够用的。 …

查看全部问答>

门禁基础资料

门禁系统根据和计算机通讯的方式分为 独立型门禁系统 和 联网型门禁系统。 独立型门禁系统 不能和计算机通讯,门禁权限的设置在本机的键盘或者母卡就行设置。也有一些独立门禁机是带液晶显示的辅助键盘等做卡片的授权。 独立型门禁系统的组成部 ...…

查看全部问答>

出租车计费器又闹内鬼了?

多地出租车计价器集体故障 日期成2012年 http://news.163.com/10/0102/02/5S07U1DH0001124J.html 核心提示:1月1日,沈阳、锦州数千辆出租车的计价器集体故障,屏幕出现“归零”问题,打印出来的发票日期大多为2012年1月1日,而且无论行驶多远价 ...…

查看全部问答>

bootloader是否需要传递启动参数

我自己谢了一个bootloader 已经拷贝NK至sdram 我想是否需要可以直接跳到sdram-NK的地址直接,启动还是需要....比如参数传递等等 thank u so much.…

查看全部问答>

改板后得优龙开发板跑wince得一些问题:再开一贴

运行优龙bootloader选择boot wince后bootloader加载wince结束后wince开始运行,但是到给flash挂载文件系统得时候就出错,直接崩溃了,原因是flash改成了1G的flash,BSP中flash驱动是支持1G得,挂载文件系统失败原因估计是参数配置出错(实在惭愧我 ...…

查看全部问答>

电源EMI滤波器

1 概述在电子设备供电电源上,存在有各种各样的外来干扰信号。很多电子设备本身,在完成其功能同时,也产生了形形色色的EMI信号,以及人为和大自然的EMI信号。这些EMI信号,通过传导和辐射的方式,影响着该环境里运行的电子设备。如图1.0是用示波器 ...…

查看全部问答>

研发人员的职业化与职业素养

2005年,在德国,我乘坐一辆德国司机开的大客车,车上装了GPS导航,有导航地图,也有一个领路人。在一段高速上,领路人说不对,不该在这个高速公路口出去,应该是下一个,司机坚持,固执的依靠导航仪,最后还是走错路了,原因是两个地方、同一个地 ...…

查看全部问答>

TI LM3S系列在TFT屏上显示波形或者柱状图的例程哪位大哥有?

求助:   TI LM3S系列在TFT屏上显示波形或者柱状图的例程哪位大哥有? 听说TI有的系列中有波形显示的程序,但我用的9B92中没有,哪位有这个例程的共享下,谢谢! 邮箱:zhangyao1213@126.com…

查看全部问答>

最小Linux系统制作例程

一,什么是BabyLinux   BabyLinux不是一个完整的发行版,他是利用原有的一套完整的linux系统的内核原代码和编译工具,利用busybox内建的强大功能,在一张软盘上做的一个很小的linux系统.他具备一个linux系统的基本特征,支持linux系统最常用的一百多 ...…

查看全部问答>