SCU 的电子信息学院的某个社团会每年举办船模大赛。
因为去年的船模比赛时候懒,所以就买了成品的遥控器(天地飞6)来参赛,控制自己制作的遥控船上面的电调和舵机。最近有心情想在今年的船模比赛中自己制作遥控器,先从第一步开始吧:使用单片机来控制舵机(控制电调的原理类似)。
0x01.什么是舵机?
其实舵机就是一种伺服电机,根据要求旋转一定的角度,在我看来,知道这些就够了~~
0x02.舵机有什么用?
就拿模型来说吧,船要转弯的话,可以采用的一种方式就是改变船后面舵片的角度来改变两侧对水的阻力,以此来让船转向,这个也是舵机一词的由来。
0x03.怎么控制?
PWM波,这是什么东西呢?其实就是一种方波,其频率为50Hz,周期就是20ms,在每个周期里面,高电平的占空比在0.5ms到2.5ms之间。而0.5ms代表的是0度,2.5ms代表的是180度。其他的度数可以直接按照比例换算过去*(这个有点想ARDUINO里面的map函数的意思)
0x04.如何实现PWM?
实现脉冲宽度调制波有很多种方法,很多单片机已经有“原生支持”的pwm输出引脚,用来输出pwm波形。
我采用比较土的一种方法,如下图:
就用这玩意输出了,他是STC公司生产的89C52RC型号的单片机,内核是51单片机,运用其中的定时器中断方式输出pwm波。
0x05.实现效果
是用单片机的P2^7引脚输出PWM波形,使用P2^4,P2^5引脚操作独立按键来控制舵机的角度
使用KEIL 4平台,代码如下:
主函数:
// GYZ
// 1路PWM波形输出,可以控制舵机和电调
#include<reg52.h>
//引脚位定义
sbit key1 = P2^5;
sbit key2 = P2^4; //独立按键引脚
sbit pwm1 = P2^7;
//全局变量定义
unsigned int target =6,percent = 0;
// 头文件包含
#include<Timer.h>
#include<interrupt.h>
#include<key.h>
//函数声明
void Timer0Initial();
void initial_Timer();
void delay(unsigned int x);
void keyscan();
void main()
{
initial();
while(1)
{
keyscan();
}
}
独立按键扫描
key.h
void keyscan()
{
if(key1 == 0)
{
delay(3);
if(key1 == 0)
{
if(target >= 7)
{
target -= 1;
}
while(key1 == 0)
{P1 = 0x00;}
}
P1 = 0xFF;
}
if(key2 == 0)
{
delay(3);
if(key2 == 0)
{
if(target <= 26)
{
target += 1;
}
while(key2 == 0)
{P1 = 0x00;}
}
P1 = 0xFF;
}
}//按键检测程序
void initial()
{
key1 = 1;
key2 = 1;
P1 = 0xff;
initial_Timer();
}
定时器程序
Timer.h
//Timer Configuration
//使用12Mhz晶振
//理论上,12Mhz晶振12分频之后
//应该是100次计数时间是100us
//通过示波器实测
//选用65次计数产生一次中断
void Timer0Initial()
{
TH0 = (65536-65)/256;
TL0 = (65536-65)%256;
} //该初值使每0.1ms产生一次中断
void initial_Timer()
{
EA = 1; //开启总中断
ET0 = 1; //允许T0中断
TMOD = 0x01; //定时器模式,T0使用工作方式1
Timer0Initial(); //装初值,0.1ms产生一次中断
TR0 = 1; //打开T0定时器
}
void delay(unsigned int x)
{
unsigned int i,j;
for(i = 0;i< x; ++i)
for(j = 120; j >0 ; --j)
;
}
最后,中断的程序
interrupt.h
void Timer0() interrupt 1 using 0
{
percent += 1;
if(percent == 200)
{
percent = 0;
pwm1 = 1;//拉高电平的引脚,来维持50hz的频率
}
if(percent == target)
{
pwm1 = 0;
}
Timer0Initial();
}