使用TMS320F28335控制360°数字舵机

目录

  • 前言
  • 舵机控制原理
    • PWM原理
    • 舵机相关知识
  • 实现过程
    • PWM模块配置
  • 初步效果
  • 转速、方向控制
  • 注意事项
  • 总结

前言

前两天用F28335控制四位共阳数码管玩了一下(链接在这),这两天换一个,用F28335来控制舵机。

舵机控制原理

PWM原理

PWM(Pulse Width Modulation),指脉冲宽度调制,是一种模拟控制方式。它的思想很简单,就是一种等效的思想:一个5V的信号作用0.5秒可以等效成一个2.5V的信号作用1秒。所以通过控制信号的通断时间,就可以在恒压信号的基础上输出不同大小的信号。

舵机相关知识

舵机由外壳、电机、控制电路以及减速器组成,因为常用于舵面(飞行器操纵面)的控制,所以叫舵机。根据转动范围,舵机可以分为90°、180°和360°舵机等。我手头上的这个是360°舵机,所以它可以做整圈转动。360°舵机和其他舵机不一样的是,其他舵机可以控制其转动角度,而360°舵机只能控制其转动速度和转动方向。使用TMS320F28335控制360°数字舵机_第1张图片
(图片来自网络,侵删)

舵机一般有三根线,分别是电源线、地线以及信号线。舵机的控制是通过在信号线上施加不同占空比的PWM信号而实现的。

实现过程

PWM模块配置

PWM信号的配置主要是周期以及占空比,和控制开关器件不一样,由于这里PWM是作为舵机的控制信号,不需要避免开关器件同时接通的问题,因此不需要对死区做出配置。
首先进行相关的宏定义,以便理解和后期修改,包括时钟频率、PWM频率和周期,代码如下:

#if (CPU_FRQ_150MHZ)
  #define CPU_CLK   	150e6  							// SYSCLK = 150MHz
#endif
#if (CPU_FRQ_100MHZ)
  #define CPU_CLK   	100e6  							// SYSCLK = 100MHz
#endif

#define TBCTLVAL  		0x200E      					// Up-down cnt, timebase = SYSCLKOUT 控制寄存器的值
#define SERVO_CLK		50								// SERVOCLK = 50Hz
#define SERVO_SP        CPU_CLK/(2*SERVO_CLK*8*12)		// 周期寄存器的值,由于采用增减计数,所以周期寄存器的值为系统时钟频率除PWM频率再除2

然后需要对PWM的输出管脚进行配置,用的是 InitEPwm1Gpio 函数,这个函数是自带的例程函数,位于 DSP2833x_EPwm.c 文件中,代码如下:

void InitEPwm1Gpio(void)
{
     
   EALLOW;
   
/* Enable internal pull-up for the selected pins */
// Pull-ups can be enabled or disabled by the user. 
// This will enable the pullups for the specified pins.
// Comment out other unwanted lines.

    GpioCtrlRegs.GPAPUD.bit.GPIO0 = 0;    // Enable pull-up on GPIO0 (EPWM1A)
    GpioCtrlRegs.GPAPUD.bit.GPIO1 = 0;    // Enable pull-up on GPIO1 (EPWM1B)   
   
/* Configure ePWM-1 pins using GPIO regs*/
// This specifies which of the possible GPIO pins will be ePWM1 functional pins.
// Comment out other unwanted lines.

    GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 1;   // Configure GPIO0 as EPWM1A
    GpioCtrlRegs.GPAMUX1.bit.GPIO1 = 1;   // Configure GPIO1 as EPWM1B
   
    EDIS;
}

最后,需要对PWM的各个模块进行配置,包括时基模块、比较计数模块、动作模块、死区模块、错误联防模块、事件触发模块以及斩波模块。不过由于我们这个是基础应用,因此死区模块、错误联防模块、事件触发模块和斩波模块我们实际上并没有涉及。配置代码如下:

void ePWM1Setup()
{
     
	// clear time-base submodule
	EPwm1Regs.TBSTS.all = 0;							// clear TBSTS
	EPwm1Regs.TBPHS.half.TBPHS = 0;						// set TBPHS to 0
	EPwm1Regs.TBCTR = 0;								// clear TB counter

	// configure counter-compare submodule
	EPwm1Regs.CMPCTL.all = 0x50;						// SHDWAMODE = 1, SHDWBMODE = 1, disable shadow mode
	EPwm1Regs.CMPCTL.bit.SHDWAMODE = 0;
	EPwm1Regs.CMPCTL.bit.SHDWBMODE = 0;					// enable shadow mode
	EPwm1Regs.CMPA.half.CMPA = SERVO_SP * (1 - 0.05);					// dutycycle of ePWMxA
	EPwm1Regs.CMPB = SERVO_SP / 8;							// dutycycle 0f ePWMxB

	// configure action-qualifier submodule
	EPwm1Regs.AQCTLA.all = 0x0060;						// CAD = 01: EPwm1A = 0 when CTR = CMPA and the counter is decrementing;
														// CAU = 10: EPwm1A = 1 when CTR = CMPA and the counter is incrementing;
	EPwm1Regs.AQCTLB.all = 0x0900;						// CBD = 10: EPwm1B = 1 when CTR = CMPB and the counter is decrementing;
	  													// CAU = 01: EPwm1A = 0 when CTR = CMPB and the counter is incrementing;
	EPwm1Regs.AQSFRC.all = 0;							// no effect under immediate mode
	EPwm1Regs.AQCSFRC.all = 0;							// continuous force disabled

	// configure dead-band submodule
	EPwm1Regs.DBCTL.all = 0x03;							// POSEL = 00: Neither EPWMxA nor EPWMxB is inverted (default);
														// OUT_MODE = 11: Dead-band is fully enabled for both rising-edge delay on output EPWMxA and falling-edge
														// 				  delay on output EPWMxB;
														// IN_MODE = 00: EPWMxA In is the source for both falling-edge and rising-edge delay.
	EPwm1Regs.DBRED = 0;
	EPwm1Regs.DBFED = 0;								// delay for rise-edge and fall-edge respectively

	// configure trip-zone submodule
	EPwm1Regs.TZSEL.all = 0;							// clear all TZ registers because we don't use it
	EPwm1Regs.TZCTL.all = 0;
	EPwm1Regs.TZEINT.all = 0;
	EPwm1Regs.TZFLG.all = 0;
	EPwm1Regs.TZCLR.all = 0;
	EPwm1Regs.TZFRC.all = 0;

	// configure event-trigger submodule
	EPwm1Regs.ETSEL.all = 0x000A;						// SOCBEN = 0 SOCAEN = 0: EPWMxSOCB EPWMxSOCA disabled;
								 	 	 	 	 	 	// INTEN = 1: interrupt enabled;
								 	 	 	 	 	 	// INTSEL = 010: interrupt when TBCTR = TBPRD
	EPwm1Regs.ETFLG.all = 0;
	EPwm1Regs.ETCLR.all = 0;
	EPwm1Regs.ETFRC.all = 0;
	EPwm1Regs.ETPS.bit.INTPRD = 11;

	// configure PWM-chopper submodule
	EPwm1Regs.PCCTL.all = 0;							// clear PCCTL register because we don't use it

	// configure time-base submodule
	EPwm1Regs.TBCTL.all = 0x2D8E;						// FREE,SOFT = 00: Stop after the next time-base counter increment or decrement;
	  													// PHSDIR = 1: Count up after the synchronization event
	  													// CLKDIV = 011 HSPCLKDIV = 011: TBCLK = SYSCLKOUT/8/6
														// SWFSYNC = 0: no effect
														// SYNCOSEL = 00: the source of the EPWMxSYNCO signal is set to EPWMxSYNCI
														// PRDLD = 1: shadow registers disabled
														// PHSEN = 1: Load the time-base counter with the phase register
														// CTRMODE = 10: Up-down-count mode
	EPwm1Regs.TBCTL.bit.CLKDIV = 100;
	EPwm1Regs.TBCTL.bit.HSPCLKDIV = 110;
	EPwm1Regs.TBPRD = SERVO_SP;
}

初步效果

360度舵机转动效果

转速、方向控制

在前面我们只是使舵机转起来了,但是我们还需要去控制它的转速以及方向。这要求我们清楚不同占空比所对应的舵机转速以及方向,所以在上面的基础上增添如下内容,每隔一定时间改变PWM信号的占空比,观察舵机的表现,代码如下:

cnt_PWM++;
if (duty_cycle_2 >= 0.1)
	duty_cycle_2 = 0;
if (cnt_PWM % 4 == 0)
	duty_cycle_2 += 0.01;
EPwm1Regs.CMPA.half.CMPA = SERVO_SP * (1 - duty_cycle_2);

实验过程如下面视频所示:

不同占空比下的舵机表现

根据实验过程,可以整理得下表:

占空比/% 舵机表现
0 不转
1 顺时针较快转动
2 同上
3 顺时针较慢转动
4 逆时针更慢转动
5 逆时针较快转动
6 同上
7 不转
8 同上
9 同上
10 同上

由上表可以清楚看到,作用不同占空比的PWM信号,舵机表现出不同的转速以及方向,不过这个只是作为参考的目测结果,具体的转速多少需要后期结合其他模块进一步测量。

注意事项

  1. 由于开发板能力有限,无法直接给舵机供电,所以我们这里采用开关电源给舵机供电。这个时候要注意将开关电源的COM端与开发板的地端相连,不然舵机无法正常运行。这应该是因为不相连的话就没有共地,会导致PWM信号与舵机内部的基准信号的比较出现问题。当时调试了很久都没反应,还以为是舵机坏了或者是PWM模块配置有问题。
  2. 另外,由于舵机控制所需的PWM信号频率较低,因此如果直接用系统时钟作为时钟源的话,周期值会超过周期寄存器的上限,因此需要设置时基控制寄存器TBCTL的CLKDIV位和HSPCLKDIV位来对系统时钟进行分频。

总结

至此,我们就成功利用F28335的PWM模块来产生控制信号,驱动舵机的旋转。同时,依然,由于本人水平有限,这个实验各个方面肯定都还有可以改进的地方;另外,文中的知识阐述可能也会有错误的地方,欢迎大家批评指正。还有的话,从视频可以看到,舵机运行过程中有抖动,没看出来是什么原因,希望大佬们可以提出宝贵意见orz

你可能感兴趣的:(我有一块F28335开发板系列,经验分享)