本文利用单片机普中STC89C52,独立按键输入,实现舵机的顺时针180°,多角度精确控制。
本代码目的在于练手及分享和复盘,作者水平有限,偏向入门级;如文中有错误以及更高效率的实现方法,欢迎讨论。
1,sg90舵机简介
产品参数
名称:9克舵机180度
尺寸:23mm X 12.2mm X 29mm
重量:9克
扭矩:1.5kg/cm
工作电压:4.2 - 6V
温度范围:0 - 55℃
运行速度:0.3s/60℃
死带宽:10ms
舵机需要接入三根线:棕色 GND | 黄色 信号线 | 红色 电源输入
普中单片机中需要只连着一个排插母线:可以利用公对母线进行插接,如下图所示
信号线可以连接任意io口;这里连接P2_1主要是因为P2_1同时也连接着DAC模块;调试舵机的时候可以根据DAC模块的led亮度判断程序运行情况。
2,PWM调制
本文采用定时器中断方式进行调制脉冲宽度,采用软件延时对时间会出现较大误差;笔者尝试过简单利用软件延时调制输入电平占空比,虽然能使舵机转起来但不能精确控制舵机加大了不可控性,故采用定时器模块;舵机的控制一般需要一个20ms左右的时基脉冲,该脉冲的高电平部分一般为0.5ms~2.5ms范围内的角度控制脉冲部分。以180度角度伺服为例,那么对应的控制关系是这样的:
0.5ms--------------0度;
1.0ms------------45度;
1.5ms------------90度;
2.0ms-----------135度;
2.5ms-----------180度;
#include <REGX52.H>
#include "INTRINS.h"
sbit Motor=P2^1;
unsigned char compare=4,counter;
void Delay(unsigned char xms) //1ms@11.0592MHz
{
while(xms--)
{
unsigned char i, j;
_nop_();
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
}
void MotorInit() //初始化电机
{
Motor=1;
compare=4;
}
void Timer0Init(void) //100微秒@11.0592MHz 0.1ms
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0xA4; //设置定时初值
TH0 = 0xFF; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
EA=1;
//PT0=1;
ET0=1;
}
unsigned char Key()//获取独立按键键码值
{
unsigned char Keynum1=0;
if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);Keynum1=1;}
if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);Keynum1=2;}
if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);Keynum1=3;}
if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);Keynum1=4;}
return Keynum1;
}
void main()
{
unsigned char Keynum=0,i=0;
Timer0Init();//初始化定时器0
while(1)
{
Keynum=Key(); //获取独立按键键码值
if(Keynum==1)
{
compare+=2; //每按一次独立按键加2个角度值
if(compare>=19) //转至极限位置复位
compare=4;
}//2500/100=25,500/100=5
if(Keynum==2)
{
for(i=0;i<15;i++) //从0°转至180°
{
compare=4+i;
P2_0=~P2_0;
Delay(10);
}
}
if(Keynum==4) //初始化
{
MotorInit();
}
}
}
void Timer0_Rountine() interrupt 1
{
TR0 = 0; //定时器暂停计时
TL0 = 0xA4; //设置定时初值
TH0 = 0xFF; //设置定时初值
if(counter<compare) //比较中断计数值和比较值
{Motor=1;}
else
{Motor=0;}
counter++; //每经过100us进入一次中断,记录进入中断次数
if(counter>=200)//每100us进入一次中断,20000/100=200次
{
Motor=1; //io口置高电平保持静止
counter=0; //中断记录次数清0
}
TR0 = 1;//定时器开始计时
}