为什么要写这篇博客、因为我在调我的51单片机wifi小车的双舵机摄像头的时候。从一开始对PWM很陌生到完全理解PWM调节并调好了两个舵机加起来花费了整整一天的时间。也看了很多的资料。这里综合一下,希望能帮助到像我一样需要使用PWM调舵机的人。
我用的舵机是———-盛辉SG90舵机(标准版)
对就是上面这个东东
下面来简单的看一下它的工作原理:
三根线:
橙色—————————–信号线
红色—————————–VCC
棕色—————————–GND
首先、在这个舵机的内部有一个基准电压。如果我们想要控制这个舵机的转动。那么我们就要通过一定信号线给它一个一定周期的直流偏置电压。
最终舵机内部会根据直流偏置电压与内部基准电压进行比较,获得电压差输出。最后电压差的正负输出到电机驱动芯片决定电机的正反转。
经过这样一个简单的叙述我们大概知道了该怎么控制舵机的正反转。
下面我们了解一下该给它什么样周期的直流偏置电压呢?
下看一下占空比的概念(图示):
如上图:占空比 = t / T;
想要控制舵机,那么我们就需要一个周期T = 20ms。高电平小t等于0.5ms-2.5ms之间的这样一个方波。
为什么是这个参数呢?
因为 t (高电平在一个周期内持续时间)
t = 0.5ms——————-舵机会转动 0 °
t = 1.0ms——————-舵机会转动 45°
t = 1.5ms——————-舵机会转动 90°
t = 2.0ms——————-舵机会转动 135°
t = 2.5ms——————-舵机会转动180°
不要问我为什么,哈哈哈,因为这和舵机内部的基准电压有关,我们只要知道它到底如何用就可以了,里面的电路实现可以不用深究!
通过上面的一下基础概念性的知识我们已经大概了解了舵机的工作原理。接下来让我们来看一下如果用C51单片机PWM来调节控制它
对于T = 20ms 。我们可以定时器0(方式1)来计数。每次0.1ms。如果计数达到200则说明一个周期到了,计数清0
补充:
11.0592MHz晶振——0.1ms TH0 = 0xff,TL0 = 0xa3
12.0000MHz晶振——0.1ms TH0 = 0xff,TL0 = 0x9c
对于t = 0.5ms—–2.5ms我们可以采用全局变量。让全局变量等于5—25之间,因为我的舵机的一个计数周期是0.1ms,这样全局变量的5—25正好就是0.5ms—2.5ms
有了这个对应关系,那么程序变的简单起来
一起来看
/* 因为我是使用Android APP通过串口给单片机发送指令来控制两个舵机的转动
所以下列程序的参数在这里做个解释:
SEV_count 上文中提到的全局变量,它的改变能够改变占空比,也就是高电平持续时间,相信你们看了代码就会明白,SEV_COUNT控制电机左右转。
SEH_count 控制电机上下转
count定时器计数值
串口发送‘f’代表舵机向上转
串口发送'g'代表舵机向下转
串口发送‘h’代表舵机向左转
串口发送‘i’代表舵机向右转
sbit SEV_PWM = P0^0; //上下舵机信号位
sbit SEH_PWM = P0^1; //左右舵机信号位
*/
unsigned char count = 0;
unsigned char SEV_conut = 15;
unsigned char SEH_count = 15;
/* 串口初始化、定时器T0、T1初始化 */
void Com_Init()
{
IP = 0x08;
PCON &= 0x7F;
TMOD &= 0x00;
TMOD |= 0x21; //定时器0设置为16为定时器方式1,定时器1配置波特率为自动重载方式2
SCON= 0x50; //串口工作在方式1,8位异步通信
TH1 = 0xfd; //定时器1设置为在11.0592下波特率为9600
TL1 = 0xfd;
ES = 1; //打开串口中断
ET1 = 0; //关闭定时器1中断
TR1 = 1; //打开定时器1
TH0 = 0xff; //配置定时器0初值,溢出时间为0.1ms
TL0 = 0xa4;
ET0 = 1; //打开定时器0中断
TR0 = 1; //开启定时器0
}
/* 定时器0中断服务程序 */
void Time0_Int() interrupt 1
{
TR0 = 0; //关闭定时器0
TH0 = 0xff; //重装初值0.1ms
TL0 = 0xa4;
//舵机1
if(count <= SEH_count) //控制占空比左右
{
//如果count的计数小于(5-25)也就是0.5ms-2.5ms则这段小t周期持续高电平。产生方波
SEH_PWM = 1;
}
else
{
SEH_PWM = 0;
}
//舵机2
if(count <= SEV_count) //控制占空比上下
{
SEV_PWM = 1;
}
else
{
SEV_PWM = 0;
}
count++;
if (count >= 200) //T = 20ms则定时器计数变量清0
{
count = 0;
}
TR0 = 1; //开启定时器0
}
void main()
{
Com_Init();
while(1)
{
;
}
}
/* 串口中断函数 */
void uart_ser() interrupt 4
{
if (RI == 0)
{
return;
}
ES = 0;
RI = 0;
command = SBUF; //将接收到的数据传给command
switch(command)
{
case 'f': //舵机向上转
{
SEV_count++;
if(SEV_count >= 25)
{
SEV_count = 25;
}
count = 0; //占空比参数t改变,让定时器重新计数
break;
}
case 'g':
{
SEV_count--;
if(SEV_count <= 5)
{
SEV_count = 5;
}
count = 0;
break;
}
case 'h':
{
SEH_count++;
if(SEH_count >= 25)
{
SEH_count = 25; //保持角度180度。
}
count = 0;
break;
}
case 'i':
{
SEH_count--;
if(SEH_count <= 5) //保持角度0度
{
SEH_count = 5;
}
count = 0;
break;
}
case 'k': //舵机复位
{
SEH_count = 15;
SEV_count = 15;
count = 0;
break;
}
default:
{
break;
}
}
ES = 1; //打开串口
}
以上就是一个双舵机的PWM控制,其实原理很简单。只要明白了原理实现起来很快的。
嘿嘿、深夜写博客也就是我了,碎觉!!!!