http://player.youku.com/player.php/sid/XMzM4MTYyODQw/v.swf
2011年最后一天,总算有点交待了。虽然走路不稳,但总算是手手脚脚,头颈都可以动了。舵机不稳,底部的舵机调零也不是很准,问题还不少,智能还没开始搞,留着2012年继续完善它吧~
顺便说明一下,我这里如果单片机和舵机共用一个电源,只能支持2个舵机,超过2个就不工作了。所以我是单片机和WR703N共用一组4个AA电池,6个舵机共用一组4个AA电池。经过测试,4个2500mAh的电池充满电,同时给WR703N和51单片机供电,开着mjpg-streamer(640X480),总共可以运行5个小时!
单片机还是用51,代码如下:
/*预处理命令*/
#include <reg52.h> //包含单片机寄存器的头文件
#define uchar unsigned char
#define uint unsigned int
uchar serVal[2];
uchar hightVotage1, hightVotage2, hightVotage3, hightVotage4, hightVotage5, hightVotage6;
uchar lowVotage1, lowVotage2, lowVotage3, lowVotage4, lowVotage5, lowVotage6;
uchar angleValue1, angleValue2, angleValue3, angleValue4, angleValue5, angleValue6;
sbit steeringGearSignal=P0^0;
sbit steeringGearSigna2=P0^1;
sbit steeringGearSigna3=P0^2;
sbit steeringGearSigna4=P0^3;
sbit steeringGearSigna5=P0^4;
sbit steeringGearSigna6=P0^5;
bit PWMCTL1=0;
bit PWMCTL2=0;
bit PWMCTL3=0;
bit PWMCTL4=0;
bit PWMCTL5=0;
bit PWMCTL6=0;
uchar c0=5;
uchar c90=15;
uchar c180=26;
uchar pwmWidth=205;
/********************************************************************
* 名称 : Com_Init()
* 功能 : 串口初始化,晶振11.0592,波特率9600,使能了串口中断
* 输入 : 无
* 输出 : 无
***********************************************************************/
void Com_Init()
{
TMOD=0x20; //用定时器设置串口波特率
TH1=0xFD; //256-11059200/(32*12*9600)=253 (FD)
TL1=0xFD;//同上
TR1=1;//定时器1开关打开
REN=1; //开启允许串行接收位
SM0=0;//串口方式,8位数据
SM1=1;//同上
EA=1; //开启总中断
ES=1; //串行口中断允许位
}
/********************************************************************
* 名称 : Timer0Init()
* 功能 : 舵机PWM中断初始化
* 输入 : 无
* 输出 : 无
***********************************************************************/
void Timer0Init()
{
//0度=0.5ms, 45度=1ms, 90度=1.5ms, 135度=2ms, 180度=2.5ms
//0.1ms初始值 FFA3, (12n/11059200=0.1/1000, n=92, X=65535-92=65443 > FFA3)
steeringGearSignal=0;
steeringGearSigna2=0;
steeringGearSigna3=0;
steeringGearSigna4=0;
steeringGearSigna5=0;
steeringGearSigna6=0;
angleValue1=c90;//初始90度
angleValue2=c90;
angleValue3=c90;
angleValue4=c90;
angleValue5=c90;
angleValue6=c90;
TMOD |= 0x01; //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
TH0=0xFF; //给定初值,0.1ms中断
TL0=0xA3;
EA=1; //总中断打开
ET0=1; //定时器0中断打开
TR0=1; //定时器0开关打开
}
/********************************************************************
* 名称 : SteeringGear()
* 功能 : 舵机PWM中断
* 输入 : 无
* 输出 : 无
***********************************************************************/
void SteeringGear() interrupt 1
{
TH0=0xFF; //重置计时器初始值
TL0=0xA3;//同上
//舵机信号1
if (PWMCTL1) //正在输出高电平
{
if(++hightVotage1>=angleValue1){//开始输出低电平
PWMCTL1=!PWMCTL1;
lowVotage1=0;
steeringGearSignal=0;
}
}else{ //正在输出低电平
if(++lowVotage1>=(pwmWidth-angleValue1)){//开始输出高电平
PWMCTL1=!PWMCTL1;
hightVotage1=0;
steeringGearSignal=1;
}
}
//舵机信号2
if (PWMCTL2) //正在输出高电平
{
if(++hightVotage2>=angleValue2){//开始输出低电平
PWMCTL2=!PWMCTL2;
lowVotage2=0;
steeringGearSigna2=0;
}
}else{ //正在输出低电平
if(++lowVotage2>=(pwmWidth-angleValue2)){//开始输出高电平
PWMCTL2=!PWMCTL2;
hightVotage2=0;
steeringGearSigna2=1;
}
}
//舵机信号3
if (PWMCTL3) //正在输出高电平
{
if(++hightVotage3>=angleValue3){//开始输出低电平
PWMCTL3=!PWMCTL3;
lowVotage3=0;
steeringGearSigna3=0;
}
}else{ //正在输出低电平
if(++lowVotage3>=(pwmWidth-angleValue3)){//开始输出高电平
PWMCTL3=!PWMCTL3;
hightVotage3=0;
steeringGearSigna3=1;
}
}
//舵机信号4
if (PWMCTL4) //正在输出高电平
{
if(++hightVotage4>=angleValue4){//开始输出低电平
PWMCTL4=!PWMCTL4;
lowVotage4=0;
steeringGearSigna4=0;
}
}else{ //正在输出低电平
if(++lowVotage4>=(pwmWidth-angleValue4)){//开始输出高电平
PWMCTL4=!PWMCTL4;
hightVotage4=0;
steeringGearSigna4=1;
}
}
//舵机信号5
if (PWMCTL5) //正在输出高电平
{
if(++hightVotage5>=angleValue5){//开始输出低电平
PWMCTL5=!PWMCTL5;
lowVotage5=0;
steeringGearSigna5=0;
}
}else{ //正在输出低电平
if(++lowVotage5>=(pwmWidth-angleValue5)){//开始输出高电平
PWMCTL5=!PWMCTL5;
hightVotage5=0;
steeringGearSigna5=1;
}
}
//舵机信号6
if (PWMCTL6) //正在输出高电平
{
if(++hightVotage6>=angleValue6){//开始输出低电平
PWMCTL6=!PWMCTL6;
lowVotage6=0;
steeringGearSigna6=0;
}
}else{ //正在输出低电平
if(++lowVotage6>=(pwmWidth-angleValue6)){//开始输出高电平
PWMCTL6=!PWMCTL6;
hightVotage6=0;
steeringGearSigna6=1;
}
}
}
/********************************************************************
* 名称 :
* 功能 : 舵机控制函数。
* 输入 : 无
* 输出 : 无
***********************************************************************/
uchar validateMinGearValue(uchar val)
{
if(val>c0)
val=val-1;
return val;
}
uchar validateMaxGearValue(uchar val)
{
if(val<c180)
val=val+1;
return val;
}
uchar validateGearValue(uchar val)
{
uchar angVal = val-60;
if(angVal<c0)
angVal=c0;
if(angVal>c180)
angVal=c180;
return angVal;
}
void SteeringGear1Up()
{
angleValue1=validateMinGearValue(angleValue1);
}
void SteeringGear1Down()
{
angleValue1=validateMaxGearValue(angleValue1);
}
void SteeringGear2Up()
{
angleValue2=validateMinGearValue(angleValue2);
}
void SteeringGear2Down()
{
angleValue2=validateMaxGearValue(angleValue2);
}
void SteeringGear3Up()
{
angleValue3=validateMinGearValue(angleValue3);
}
void SteeringGear3Down()
{
angleValue3=validateMaxGearValue(angleValue3);
}
void SteeringGear4Up()
{
angleValue4=validateMinGearValue(angleValue4);
}
void SteeringGear4Down()
{
angleValue4=validateMaxGearValue(angleValue4);
}
void SteeringGear5Up()
{
angleValue5=validateMinGearValue(angleValue5);
}
void SteeringGear5Down()
{
angleValue5=validateMaxGearValue(angleValue5);
}
void SteeringGear6Up()
{
angleValue6=validateMinGearValue(angleValue6);
}
void SteeringGear6Down()
{
angleValue6=validateMaxGearValue(angleValue6);
}
void SetSteeringGear1(uchar val)
{
angleValue1=validateGearValue(val);
}
void SetSteeringGear2(uchar val)
{
angleValue2=validateGearValue(val);
}
void SetSteeringGear3(uchar val)
{
angleValue3=validateGearValue(val);
}
void SetSteeringGear4(uchar val)
{
angleValue4=validateGearValue(val);
}
void SetSteeringGear5(uchar val)
{
angleValue5=validateGearValue(val);
}
void SetSteeringGear6(uchar val)
{
angleValue6=validateGearValue(val);
}
/********************************************************************
* 名称 : ser()
* 功能 : 串口中断接收数据
* 输入 : 无
* 输出 : 无
***********************************************************************/
void ser() interrupt 4
{
serVal[0]=serVal[1];
serVal[1]=SBUF;
RI=0;//串口中断清0
}
/*********************************************************************************
** 函数名称 : main(void)
** 函数功能 : 主函数
*********************************************************************************/
void main()
{
Com_Init();//串口初始化
Timer0Init();//舵机初始化
while(1)
{
if(serVal[0]=='!'){
switch(serVal[1])
{
case 'A': SteeringGear1Up(); break;
case 'B': SteeringGear1Down(); break;
case 'C': SteeringGear2Up(); break;
case 'D': SteeringGear2Down(); break;
case 'E': SteeringGear3Up(); break;
case 'F': SteeringGear3Down(); break;
case 'G': SteeringGear4Up(); break;
case 'H': SteeringGear4Down(); break;
case 'I': SteeringGear5Up(); break;
case 'J': SteeringGear5Down(); break;
case 'K': SteeringGear6Up(); break;
case 'L': SteeringGear6Down(); break;
default:break;
}
serVal[0]=0; //清除缓存
}else if(serVal[0]=='"'){
SetSteeringGear1(serVal[1]);
}else if(serVal[0]=='#'){
SetSteeringGear2(serVal[1]);
}else if(serVal[0]=='$'){
SetSteeringGear3(serVal[1]);
}else if(serVal[0]=='%'){
SetSteeringGear4(serVal[1]);
}else if(serVal[0]=='&'){
SetSteeringGear5(serVal[1]);
}else if(serVal[0]=='\''){
SetSteeringGear6(serVal[1]);
}
}
}
我曾经想将单片机的程序写的好看一点,代码少一点,重用多一点(程序员的通病),结果怎么调试都不行,后来换了一个“增强型51”的CPU(STC12C5A60S2)居然就跑起来了,可能是代码虽然少了,但效率反而低了,之前的STC89C52的速度比较低,就跑不起来。顺便贴出来,让别人也少走弯路。
STC12C5A60S2可用的单片机程序:
/*预处理命令*/
#include <reg52.h> //包含单片机寄存器的头文件
#define uchar unsigned char
#define uint unsigned int
uchar serVal[]={0,0};
uchar hiVot[]={0,0,0,0,0,0};
uchar loVot[]={0,0,0,0,0,0};
uchar ang[]={15,15,15,15,15,15}; //初始90度
uchar serCtl=0;
uchar code mask1[]={0x01,0x02,0x04,0x08,0x10,0x20};
uchar code mask0[]={0xFE,0xFD,0xFB,0xF7,0xEF,0xDF};
/********************************************************************
* 名称 : Com_Init()
* 功能 : 串口初始化,晶振11.0592,波特率9600,使能了串口中断
* 输入 : 无
* 输出 : 无
***********************************************************************/
void Com_Init()
{
TMOD |= 0x20; //用定时器设置串口波特率
TH1=0xFD; //256-11059200/(32*12*9600)=253 (FD)
TL1=0xFD;//同上
TR1=1;//定时器1开关打开
REN=1; //开启允许串行接收位
SM0=0;//串口方式,8位数据
SM1=1;//同上
EA=1; //开启总中断
ES=1; //串行口中断允许位*/
}
/********************************************************************
* 名称 : Timer0Init()
* 功能 : 舵机PWM中断初始化
* 输入 : 无
* 输出 : 无
***********************************************************************/
void Timer0Init()
{
//0度=0.5ms, 45度=1ms, 90度=1.5ms, 135度=2ms, 180度=2.5ms
//(估计)0.1ms初始值 FFA3, (12n/11059200=0.1/1000, n=92.16, X=65535-92=65443 > FFA3)
//(实际)每次中断的间隔是0.09765625ms,0.5ms计数是5,1.5ms计数是15,2.5ms计数是26,20ms计数是205
TMOD |= 0x01; //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
TH0=0xFF; //给定初值,0.09765625ms中断
TL0=0xA3;
EA=1; //总中断打开
ET0=1; //定时器0中断打开
TR0=1; //定时器0开关打开
}
/********************************************************************
* 名称 : SteeringGear()
* 功能 : 舵机PWM中断
* 输入 : 无
* 输出 : 无
***********************************************************************/
void SteeringGear() interrupt 1
{
uchar i;
bit ctl;
TH0=0xFF;//重置计时器初始值
TL0=0xA3;//同上
for (i = 0; i<6; i++){
ctl=serCtl&mask1[i];//取特定位
//舵机信号i
if (ctl)//正在输出高电平
{
hiVot[i]=hiVot[i]+1;
if(hiVot[i]>=ang[i]){//开始输出低电平
serCtl=serCtl&mask0[i];//特定位 置0
loVot[i]=0;
P0=P0&mask0[i];//特定位 置0
}
}else{//正在输出低电平
loVot[i]=loVot[i]+1;
if(loVot[i]>=(205-ang[i])){//开始输出高电平
serCtl=serCtl|mask1[i];//特定位 置1
hiVot[i]=0;
P0=P0|mask1[i];//特定位 置1
}
}
}
}
/********************************************************************
* 名称 :SetSteeringGear()
* 功能 : 设置舵机角度。
* 输入 : 无
* 输出 : 无
***********************************************************************/
void SetSteeringGear(uchar i, uchar val)
{
uchar angVal = val-60; //
if(angVal<5)
angVal=5;
if(angVal>26)
angVal=26;
ang[i]=angVal;
}
/********************************************************************
* 名称 :SteeringGearUp()
* 功能 : 舵机向上转。
* 输入 : 无
* 输出 : 无
***********************************************************************/
void SteeringGearUp(uchar i)
{
if(ang[i]>5)
ang[i]=ang[i]-1;
}
/********************************************************************
* 名称 :SteeringGearDown()
* 功能 : 舵机向下转。
* 输入 : 无
* 输出 : 无
***********************************************************************/
void SteeringGearDown(uchar i)
{
if(ang[i]<26)
ang[i]=ang[i]+1;;
}
/********************************************************************
* 名称 : ser()
* 功能 : 串口中断接收数据
* 输入 : 无
* 输出 : 无
***********************************************************************/
void ser() interrupt 4
{
serVal[0]=serVal[1];
serVal[1]=SBUF;
RI=0;//串口中断清0
}
/*********************************************************************************
** 函数名称 : main(void)
** 函数功能 : 主函数
*********************************************************************************/
void main()
{
Com_Init();//串口初始化
Timer0Init();//舵机初始化
while(1)
{
if(serVal[0]=='!'){
switch(serVal[1])
{
case 'A': SteeringGearUp(0); break;
case 'B': SteeringGearDown(0); break;
case 'C': SteeringGearUp(1); break;
case 'D': SteeringGearDown(1); break;
case 'E': SteeringGearUp(2); break;
case 'F': SteeringGearDown(2); break;
case 'G': SteeringGearUp(3); break;
case 'H': SteeringGearDown(3); break;
case 'I': SteeringGearUp(4); break;
case 'J': SteeringGearDown(4); break;
case 'K': SteeringGearUp(5); break;
case 'L': SteeringGearDown(5); break;
default:break;
}
serVal[0]=0; //清除缓存
}else if(serVal[0]=='"'){
SetSteeringGear(0,serVal[1]);
}else if(serVal[0]=='#'){
SetSteeringGear(1,serVal[1]);
}else if(serVal[0]=='$'){
SetSteeringGear(2,serVal[1]);
}else if(serVal[0]=='%'){
SetSteeringGear(3,serVal[1]);
}else if(serVal[0]=='&'){
SetSteeringGear(4,serVal[1]);
}else if(serVal[0]=='\''){
SetSteeringGear(5,serVal[1]);
}
}
}
上位机借用了网友的源代码,改成6个舵机控制,程序启动的时候就会自动开始socket连接,有几个参数CMD_Servo×_prefix懒得改界面了,直接改ini就得了。程序截图如下:
程序/工程文件/源代码下载:
http://bbs.igee.cn/read.php?tid=5582
http://download.csdn.net/detail/channel_z/4074612