用stm32控制舵机

您所在的位置:网站首页 维宏仿真软件能用在控制中吗为什么呢 用stm32控制舵机

用stm32控制舵机

2024-07-13 21:44| 来源: 网络整理| 查看: 265

舵机是一种位置(角度)伺服的驱动器,适用于那些需要角度不断变化并可以保持的控制系统。使用stm32控制机器时,经常要用到舵机,如使某个部位转到特定的角度,或者在行进过程中的方向控制,这篇文章将以stm32F103C8T6为例,从分析舵机的原理出发,到介绍使用stm的TIM功能输出PWM波,掌握理论后进行实战,先控制一个舵机上手,然后控制多个舵机。

一、舵机的原理

在这里插入图片描述 如图所示,一个舵机由变速齿轮箱,电位器,电路板与直流电机组成。电机的高速、短周期运动由齿轮箱转换为慢速、长周期的运动,最终到最外端的齿轮,齿轮的转动带动电位器转动,电位器的电位与信号线进行比较,从而实现转动到特定角度的功能。 伺服电机由信号线输入的PWM信号控制。信号的频率应为50Hz,周期为20ms,PWM的占空比决定了舵机旋转到的角度。

二、如何控制一个舵机

舵机的控制由一个脉冲宽度调制信号(PWM波)来实现,该信号在这个实验里使用stm32来发出。 通常来说,1ms的脉宽对应0度位置,1.5ms对应90度,2ms对应180度。这一数据会由于舵机型号不同而略有差异。 通常来说,1ms的脉宽对应0度位置,1.5ms对应90度,2ms对应180度。这一数据会由于舵机型号不同而略有差异。

三、使用stm32TIM功能输出PWM波来控制舵机

根据STM32F10xxx参考手册, 通用TIM 定时器与高级TIM功能包括: ● 16位向上、向下、向上/向下自动装载计数器 ● 16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为1~65536之间的任意 数值 ● 4个独立通道: ─ 输入捕获 ─ 输出比较 ─ PWM生成(边缘或中间对齐模式) ─ 单脉冲模式输出 ● 使用外部信号控制定时器和定时器互连的同步电路 ● 如下事件发生时产生中断/DMA: ─ 更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发) ─ 触发事件(计数器启动、停止、初始化或者由内部/外部触发计数) ─ 输入捕获 ─ 输出比较 ● 支持针对定位的增量(正交)编码器和霍尔传感器电路 ● 触发输入作为外部时钟或者按周期的电流管理 在这里使用4个独立通道:PWM生成,要注意的是,基本定时器并不具备该功能。 不同型号的芯片包含的TIM模块可能不同,使用时建议先查询数据手册。

配置时基单元 要使用该功能,首先要配置时基单元,时基单元可以理解为定时器的心脏,它主要包含: ● 计数器寄存器(TIMx_CNT) ● 预分频器寄存器 (TIMx_PSC) ● 自动装载寄存器 (TIMx_ARR) 之间的关系是: 在这里插入图片描述 驱动定时器的时钟:CK_CNT=CK_INT/(PSC+1),CNT开始计数,由ARR决定产生更新事件。

预分频器 预分频器可以将计数器的时钟频率按1到65536之间的任意值进行分频,选中的时钟由分频器分频后进行计数,在这里使用内部时钟INT,经过分频后CK_CNT=CK_INT/(PSC+1) 在这里插入图片描述 那么如何得知内部时钟的频率呢?参考时钟树,可以发现: 在STM32F10xxx中,TIM1和TIM8挂载在APB2总线上,其他都挂载到APB1总线上 在这里插入图片描述 在这里插入图片描述 定时器时钟频率分配由硬件按以下2种情况自动设置: 1. 如果相应的APB预分频系数是1,定时器的时钟频率与所在APB总线频率保持一致2. 否则,定时器的时钟频率被设为与其相连的APB总线频率的2倍。 在标准库中,APB1与APB2预分频系数是2,所以定时器时钟TIMxCLK=36MHz*2=72MHz

计数器模式

向上计数模式

在向上计数模式中,计数器CNT从0计数到自动加载值(ARR中的内容),然后重新从0开始计数并且产生一个计数器溢出事件。 这里还有一个自动加载影子寄存器,简单来说就是当写入新数据至影子计数器时,若ARPE=0,则ARR寄存器值立即装入,若ARPE=1,要等到下一个更新事件才会写入。

向下计数模式

在向下计数模式中,计数器从自动加载值开始向下计数到0,然后从自动装入的值重新开始并且产生一个计数器向下溢出的事件。

中央对齐模式

在这里使用向上或者向下计数模式

** 在PWM模式(模式1或模式2)下,TIMx_CNT和TIMx_CCRx始终在进行比较。 PWM模式1与PWM模式2的描述如下:(见STM32F10xxx参考手册) PWM模式1——在向上计数时,一旦TIMx_CNTTIMx_CCR1时通道1为无效电平(OC1REF=0),否则为有效电平(OC1REF=1)。 PWM模式2- 在向上计数时,一旦TIMx_CNTTIMx_CCR1时通道1为有效电平,否则为无效电平。

综上所述,产生PWM波的步骤如下: 1.配置预分频寄存器PSC的值为(7200-1),内部时钟为72MHz,则计数一次的时间为(7200/72000000)s=0.1ms; 2.配置自动装载寄存器ARR的值为(200-1),那么产生一次计数中断的周期为20ms,与驱动舵机需要的周期相符 3.使用输出比较功能的PWM模式,更改CCR寄存器的值即可改变占空比,如前面所说的,脉宽为1ms对应0°,2ms对应180°

四、实战——先从控制一个舵机入手

在这里,将以十分常见的SG90舵机为例(下图),使用stm32C8T6驱动 长这个样子 在这里插入图片描述 首先,我们新建bsp_servo.h与bsp_servo.c文件

本实验使用TIM3的输出通道1,在bsp_servo.h文件中定义宏

/*先使用TIM1的通道1*/ #define GENERAL_TIM TIM3 #define GENERAL_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd #define GENERAL_TIM_CLK RCC_APB1Periph_TIM3 //配置预分频寄存器PSC的值为(7200-1),内部时钟为72MHz,则计数一次的时间为(7200/72000000)s=0.1ms; #define GENERAL_TIM_Prescaler (72000-1) //配置自动装载寄存器ARR的值为(200-1),那么产生一次计数中断的周期为20ms,与驱动舵机需要的周期相符 #define GENERAL_TIM_Period (20-1) // TIM3 输出比较通道1 #define GENERAL_TIM_CH1_GPIO_CLK RCC_APB2Periph_GPIOA #define GENERAL_TIM_CH1_PORT GPIOA #define GENERAL_TIM_CH1_PIN GPIO_Pin_6

之后来到bsp_servo.c文件,配置GPIO端口为复用,输出端口为PA6,具体使用哪个端口可以参考对应型号的data sheet。

static void GENERAL_TIM_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; // 输出比较通道1 GPIO 初始化 RCC_APB2PeriphClockCmd(GENERAL_TIM_CH1_GPIO_CLK, ENABLE); GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH1_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GENERAL_TIM_CH1_PORT, &GPIO_InitStructure); } 使用TIM功能的PWM模式 static void GENERAL_TIM_Mode_Config(void) { // 开启定时器时钟,即内部时钟CK_INT=72M GENERAL_TIM_APBxClock_FUN(GENERAL_TIM_CLK,ENABLE); /*--------------------时基结构体初始化-------------------------*/ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; // 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断 TIM_TimeBaseStructure.TIM_Period=GENERAL_TIM_Period; // 驱动CNT计数器的时钟 = Fck_int/(psc+1) TIM_TimeBaseStructure.TIM_Prescaler= GENERAL_TIM_Prescaler; // 时钟分频因子 ,配置死区时间时需要用到 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; // 计数器计数模式,设置为向上计数 TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; // 重复计数器的值,没用到不用管 TIM_TimeBaseStructure.TIM_RepetitionCounter=0; // 初始化定时器 TIM_TimeBaseInit(GENERAL_TIM, &TIM_TimeBaseStructure); /*--------------------输出比较结构体初始化-------------------*/ TIM_OCInitTypeDef TIM_OCInitStructure; // 配置为PWM模式1 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // 输出使能 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 输出通道电平极性配置 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 输出比较通道 1 TIM_OCInitStructure.TIM_Pulse = 0; TIM_OC1Init(GENERAL_TIM, &TIM_OCInitStructure); TIM_OC1PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable); // 使能计数器 TIM_Cmd(GENERAL_TIM, ENABLE); } 定义一个初始化函数,同时初始化时基与输出比较 void GENERAL_TIM_Init(void) { GENERAL_TIM_GPIO_Config(); GENERAL_TIM_Mode_Config(); }

这样初始化配置就完成了,接下来来到main.c使用TIM_SetComparex(TIMx, Compare);来配置占空比。

首先定义一个延时函数,使舵机有时间转动特定的角度

void Delay(__IO uint32_t nCount) //简单的延时函数 { for(; nCount != 0; nCount--); }

为了方便使用定义一个宏

#define SOFT_DELAY Delay(0x0FFFFF);

前面将TIM3配置为PWM模式1,即为向上计数,CNT



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3