基于51单片机的机械臂控制系统研究
1控制系统所运用到的模块
所用到的模块有:pca9685控制多路舵机模块;矩阵按键模块;LCD1702显示模块;DS18B20温度检测模块;独立按键模块;步进电机;ULN2003步进电机控制模,DS1302时钟模块。
2控制系统工作模式的功能
上电将LCD1602显示初始化,温度测量初始化,定时器初始化,测量当前温度,显示当前所需要显示的字符;
工作模式一:显示当前年月日时分秒,显示步进电机开关状态,显示处于哪种工作模式,在此界面可通过矩阵按键模块调整时间,控制步进电机的开关。
工作模式二:显示密码锁界面,显示按键所输入的数值,在此界面可通过矩阵按键控制所输入的数值,如果输入密码正确跳转到工作模式三,否者返回工作模式一。
工作模式三:显示每个舵机的工作状态,在此界面可以通过独立按键和矩阵按键配合控制舵机工作;按下指定按键返回到工作模式一。
工作模式四:在此工作模式下机械臂由红外遥控器控制,LCD1602显示舵机状态
3控制系统所运用的协议以及基础知识
DS18B20控制所运用到的单线协议,实时时钟DS1302所运用到SPI协议;控制舵机所运用的IIC协议,矩阵键盘状态机写法;步进电机运动控制LCD1602显示,定时器中断配置,NEC协议,舵机控制中pwm控制等等。
4控制系统流程
5控制系统主要思路
LCD1602负责显示,按键负责控制。
最重要的是:pca9685模块控制舵机 舵机具体控制细节在 【SG90模拟舵机控制及PCA9685模块的使用】这篇博客有具体说明。
通过pca9685可以控制多个舵机,非常节约IO口。
6控制系统代码
主函数
#include <REGX52.H>
#include <ONEWIRE.H>
#include <LCD1602.H>
#include <INTERRUPT.H>
#include <DS18B20.H>
#include <DISPLAY.H>
#include <DS1302.H>
#include <KEY.H>
#include <MOTOR.H>
#include <SERVO.H>
#include <INIT_SYSTEM.H>
unsigned int display_count;//lcd1602中断时间控制
unsigned int key_count;//按键中断时间控制
unsigned char mode=1;//工作模式
unsigned char count0=90;//底部旋转舵机初始角度
unsigned char count1=125;//高度舵机初始角度
unsigned char count2=0;//前后舵机初始角度
unsigned char count3=90;//夹爪舵机初始角度
extern unsigned int hw_count;
extern bit work_mode;
extern bit motor_control;
extern unsigned int hw_count;
extern bit displaymode3_flag;
void main()
{
Init_process();//系统初始化
while(1)
{
display_process();//lcd1602显示画面
key_process();//按键操作函数
}
}
void timer0service() interrupt 1
{
TL0 = 0x66; //设置定时初值
TH0 = 0xFC; //设置定时初值
key_count++;
}
void timer1service() interrupt 3
{
TL1 = 0xCD; //设置定时初值
TH1 = 0xD4; //设置定时初值
if((mode==1)||(mode==2)||(mode==3))
{
display_count++;
}
if(mode==2)//当处于定时器模式一
{
if(work_mode==0)
{
if(motor_control)
{
motor_process();//启动步进电机
}
}
else
{
flag();
}
}
}
LCD1602显示函数
#include <REGX52.H>
#include <ONEWIRE.H>
#include <LCD1602.H>
#include <DS18B20.H>
#include <DS1302.H>
extern unsigned char mode;//模式一用来显示温度 模式二用来显示舵机开关和时间
extern unsigned int display_count;
extern unsigned char key_press;
extern unsigned char count0;//底部旋转舵机初始角度
extern unsigned char count1;//高度舵机初始角度
extern unsigned char count2;//前后舵机初始角度
extern unsigned char count3;//夹爪舵机初始角度
extern bit run;//控制舵机正转反转
extern bit key_flag;//控制是否跳转到舵机控制界面
unsigned char xq;
unsigned char nian=0;
unsigned char yue=0;
unsigned char ri=0;
unsigned char xq=3;
unsigned char shi;
unsigned char fen;
unsigned char miao;
unsigned char xingqi;
unsigned int keynumber;//密码输入
unsigned int real_number=123;//真实密码
bit work_mode=0;
bit ds1302_flag=0;
bit motor_control=0;//舵机开关状态0为关1为开
bit flag_show;
/*
此段代码用来显示模式一LCD1602所要显示的内容
*/
void display_mode1()
{
float temp;
DS18B20_ConvertT(); //上电先转换一次温度,防止第一次读数据错误
EA=0;
temp=DS18B20_ReadT();
EA=1;
LCD_ShowString(1,1,"Origin");
LCD_ShowString(1,7," Menu ");
LCD_ShowString(2,1,"Temp:");
LCD_ShowNum(2,6,temp,2); //显示温度整数部分
LCD_ShowChar(2,8,'.'); //显示小数点
LCD_ShowNum(2,9,(unsigned long)(temp*10000)%10000,4);//显示温度小数部分
write_du();
LCD_ShowChar(2,14,'C');
}
/*
以下函数在设置函数时0.5秒进行闪烁
*/
void flag()//设置时间每隔一秒闪烁
{
unsigned int flag_count;
flag_count++;
if(flag_count>50)
{
flag_count=0;
flag_show=~flag_show;
}
}
/*
此段代码用来显示模式二LCD1602所要显示的内容
*/
void display_mode2()
{
if(ds1302_flag==0)
{
DS1302_Init();//DS1302初始化
DS1302_SetTime();//设置时间
ds1302_flag=1;
}
if(work_mode==0)//处于时间显示模式
{
if(motor_control)
{
LCD_ShowString(2,10,"Open ");
}
else
{
LCD_ShowString(2,10,"Close ");
}
LCD_ShowString(1,15,"M1");//工作模式1
LCD_ShowChar(2,9,' ');
DS1302_ReadTime();//读取时间
LCD_ShowChar(1,3,'-');
LCD_ShowChar(1,6,'-');
LCD_ShowChar(1,9,' ');
LCD_ShowChar(2,3,':');
LCD_ShowChar(2,6,':');
LCD_ShowChar(2,9,' ');
LCD_ShowNum(1,1,DS1302_Time[0],2);//显示年
LCD_ShowNum(1,4,DS1302_Time[1],2);//显示月
LCD_ShowNum(1,7,DS1302_Time[2],2);//显示日
LCD_ShowNum(2,1,DS1302_Time[3],2);//显示时
LCD_ShowNum(2,4,DS1302_Time[4],2);//显示分
LCD_ShowNum(2,7,DS1302_Time[5],2);//显示秒
xingqi=DS1302_Time[6];
switch(xingqi)//用来选择星期
{
case 1:LCD_ShowString(1,10,"Mon ");break;
case 2:LCD_ShowString(1,10,"Tue ");break;
case 3:LCD_ShowString(1,10,"Wed ");break;
case 4:LCD_ShowString(1,10,"Thu ");break;
case 5:LCD_ShowString(1,10,"Fri ");break;
case 6:LCD_ShowString(1,10,"Sat ");break;
case 7:LCD_ShowString(1,10,"Sun ");break;
}
}
if(work_mode==1)// 处于时间设置界面
{
if(motor_control)
{
LCD_ShowString(2,10,"Open ");
}
else
{
LCD_ShowString(2,10,"Close ");
}
LCD_ShowChar(1,3,'-');
LCD_ShowChar(1,6,'-');
LCD_ShowChar(1,9,' ');
LCD_ShowChar(2,3,':');
LCD_ShowChar(2,6,':');
LCD_ShowChar(2,9,' ');
if(key_press==1)//按第一下
{
if(flag_show)
{
LCD_ShowNum(1,1,nian,2);//显示年
}
else
{
LCD_ShowChar(1,1,' ');
LCD_ShowChar(1,2,' ');
}
LCD_ShowNum(1,4,yue,2);//显示月
LCD_ShowNum(1,7,ri,2);//显示日
LCD_ShowNum(2,1,shi,2);//显示时
LCD_ShowNum(2,4,fen,2);//显示分
LCD_ShowNum(2,7,miao,2);//显示秒
switch(xq)
{
case 1:LCD_ShowString(1,10,"Mon ");break;
case 2:LCD_ShowString(1,10,"Tue ");break;
case 3:LCD_ShowString(1,10,"Wed ");break;
case 4:LCD_ShowString(1,10,"Thu ");break;
case 5:LCD_ShowString(1,10,"Fri ");break;
case 6:LCD_ShowString(1,10,"Sat ");break;
case 7:LCD_ShowString(1,10,"Sun ");break;
}
}
else if(key_press==2)//按第二下
{
if(flag_show)
{
LCD_ShowNum(1,4,yue,2);//显示月
}
else
{
LCD_ShowChar(1,4,' ');
LCD_ShowChar(1,5,' ');
}
LCD_ShowNum(1,1,nian,2);//显示年
LCD_ShowNum(1,7,ri,2);//显示日
LCD_ShowNum(2,1,shi,2);//显示时
LCD_ShowNum(2,4,fen,2);//显示分
LCD_ShowNum(2,7,miao,2);//显示秒
switch(xq)
{
case 1:LCD_ShowString(1,10,"Mon ");break;
case 2:LCD_ShowString(1,10,"Tue ");break;
case 3:LCD_ShowString(1,10,"Wed ");break;
case 4:LCD_ShowString(1,10,"Thu ");break;
case 5:LCD_ShowString(1,10,"Fri ");break;
case 6:LCD_ShowString(1,10,"Sat ");break;
case 7:LCD_ShowString(1,10,"Sun ");break;
}
}
else if(key_press==3)//按第三下
{
if(flag_show)
{
LCD_ShowNum(1,7,ri,2);//显示日
}
else
{
LCD_ShowChar(1,7,' ');
LCD_ShowChar(1,8,' ');
}
LCD_ShowNum(1,1,nian,2);//显示年
LCD_ShowNum(1,4,yue,2);//显示月
LCD_ShowNum(2,1,shi,2);//显示时
LCD_ShowNum(2,4,fen,2);//显示分
LCD_ShowNum(2,7,miao,2);//显示秒
switch(xq)
{
case 1:LCD_ShowString(1,10,"Mon ");break;
case 2:LCD_ShowString(1,10,"Tue ");break;
case 3:LCD_ShowString(1,10,"Wed ");break;
case 4:LCD_ShowString(1,10,"Thu ");break;
case 5:LCD_ShowString(1,10,"Fri ");break;
case 6:LCD_ShowString(1,10,"Sat ");break;
case 7:LCD_ShowString(1,10,"Sun ");break;
}
}
else if(key_press==4)//按第四下
{
if(flag_show)
{
switch(xq)
{
case 1:LCD_ShowString(1,10,"Mon ");break;
case 2:LCD_ShowString(1,10,"Tue ");break;
case 3:LCD_ShowString(1,10,"Wed ");break;
case 4:LCD_ShowString(1,10,"Thu ");break;
case 5:LCD_ShowString(1,10,"Fri ");break;
case 6:LCD_ShowString(1,10,"Sat ");break;
case 7:LCD_ShowString(1,10,"Sun ");break;
}
}
else
{
LCD_ShowChar(1,10,' ');
LCD_ShowChar(1,11,' ');
LCD_ShowChar(1,12,' ');
}
LCD_ShowNum(1,1,nian,2);//显示年
LCD_ShowNum(1,4,yue,2);//显示月
LCD_ShowNum(1,7,ri,2);//显示日
LCD_ShowNum(2,1,shi,2);//显示时
LCD_ShowNum(2,4,fen,2);//显示分
LCD_ShowNum(2,7,miao,2);//显示秒
}
else if(key_press==5)//按第五下
{
if(flag_show)
{
LCD_ShowNum(2,1,shi,2);//显示时
}
else
{
LCD_ShowChar(2,1,' ');
LCD_ShowChar(2,2,' ');
}
LCD_ShowNum(1,1,nian,2);//显示年
LCD_ShowNum(1,4,yue,2);//显示月
LCD_ShowNum(1,7,ri,2);//显示日
LCD_ShowNum(2,4,fen,2);//显示分
LCD_ShowNum(2,7,miao,2);//显示秒
switch(xq)
{
case 1:LCD_ShowString(1,10,"Mon ");break;
case 2:LCD_ShowString(1,10,"Tue ");break;
case 3:LCD_ShowString(1,10,"Wed ");break;
case 4:LCD_ShowString(1,10,"Thu ");break;
case 5:LCD_ShowString(1,10,"Fri ");break;
case 6:LCD_ShowString(1,10,"Sat ");break;
case 7:LCD_ShowString(1,10,"Sun ");break;
}
}
else if(key_press==6)//按第六下
{
if(flag_show)
{
LCD_ShowNum(2,4,fen,2);//显示分
}
else
{
LCD_ShowChar(2,4,' ');
LCD_ShowChar(2,5,' ');
}
LCD_ShowNum(1,1,nian,2);//显示年
LCD_ShowNum(1,4,yue,2);//显示月
LCD_ShowNum(1,7,ri,2);//显示日
LCD_ShowNum(2,1,shi,2);//显示时
LCD_ShowNum(2,7,miao,2);//显示秒
switch(xq)
{
case 1:LCD_ShowString(1,10,"Mon ");break;
case 2:LCD_ShowString(1,10,"Tue ");break;
case 3:LCD_ShowString(1,10,"Wed ");break;
case 4:LCD_ShowString(1,10,"Thu ");break;
case 5:LCD_ShowString(1,10,"Fri ");break;
case 6:LCD_ShowString(1,10,"Sat ");break;
case 7:LCD_ShowString(1,10,"Sun ");break;
}
}
else if(key_press==7)//按第七下
{
if(flag_show)
{
LCD_ShowNum(2,7,miao,2);//显示秒
}
else
{
LCD_ShowChar(2,7,' ');
LCD_ShowChar(2,8,' ');
}
LCD_ShowNum(1,1,nian,2);//显示年
LCD_ShowNum(1,4,yue,2);//显示月
LCD_ShowNum(1,7,ri,2);//显示日
LCD_ShowNum(2,4,fen,2);//显示分
LCD_ShowNum(2,1,shi,2);//显示时
switch(xq)
{
case 1:LCD_ShowString(1,10,"Mon ");break;
case 2:LCD_ShowString(1,10,"Tue ");break;
case 3:LCD_ShowString(1,10,"Wed ");break;
case 4:LCD_ShowString(1,10,"Thu ");break;
case 5:LCD_ShowString(1,10,"Fri ");break;
case 6:LCD_ShowString(1,10,"Sat ");break;
case 7:LCD_ShowString(1,10,"Sun ");break;
}
}
}
}
/*
密码输入显示界面
*/
void display_mode3()
{
LCD_ShowString(1,1,"Trick Lock");
LCD_ShowString(1,12," M2");
LCD_ShowString(2,1,"Password:");
LCD_ShowNum(2,10,keynumber,3);
LCD_ShowString(2,13," ");
}
void display_process()
{
if(display_count>10)
{
display_count=0;
switch(mode)
{
case 1:display_mode1();break;
case 2:display_mode2();break;
case 3:display_mode3();break;
}
}
}
LCD1602显示函数头文件
#ifndef __DSIPLAY_H
#define __DISPLAY_H
void flag();
void display_mode1();
void display_mode2();
void display_mode3();
void display_process();
#endif
LCD1602驱动函数
#include <REGX52.H>
//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0
//函数定义:
/**
* @brief LCD1602延时函数,12MHz调用可延时1ms
* @param 无
* @retval 无
*/
void LCD_Delay()
{
unsigned char i, j;
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
/**
* @brief LCD1602写命令
* @param Command 要写入的命令
* @retval 无
*/
void LCD_WriteCommand(unsigned char Command)
{
LCD_RS=0;
LCD_RW=0;
LCD_DataPort=Command;
LCD_EN=1;
LCD_Delay();
LCD_EN=0;
LCD_Delay();
}
/**
* @brief LCD1602写数据
* @param Data 要写入的数据
* @retval 无
*/
void LCD_WriteData(unsigned char Data)
{
LCD_RS=1;
LCD_RW=0;
LCD_DataPort=Data;
LCD_EN=1;
LCD_Delay();
LCD_EN=0;
LCD_Delay();
}
/**
* @brief LCD1602设置光标位置
* @param Line 行位置,范围:1~2
* @param Column 列位置,范围:1~16
* @retval 无
*/
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
if(Line==1)
{
LCD_WriteCommand(0x80|(Column-1));
}
else if(Line==2)
{
LCD_WriteCommand(0x80|(Column-1+0x40));
}
}
/**
* @brief LCD1602初始化函数
* @param 无
* @retval 无
*/
void LCD_Init()
{
LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
LCD_WriteCommand(0x01);//光标复位,清屏
}
/**
* @brief 在LCD1602指定位置上显示一个字符
* @param Line 行位置,范围:1~2
* @param Column 列位置,范围:1~16
* @param Char 要显示的字符
* @retval 无
*/
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
LCD_SetCursor(Line,Column);
LCD_WriteData(Char);
}
void write_du()
{
LCD_SetCursor(2,13);
LCD_WriteData(0xdf);
}
/**
* @brief 在LCD1602指定位置开始显示所给字符串
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param String 要显示的字符串
* @retval 无
*/
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=0;String[i]!='\0';i++)
{
LCD_WriteData(String[i]);
}
}
/**
* @brief 返回值=X的Y次方
*/
int LCD_Pow(int X,int Y)
{
unsigned char i;
int Result=1;
for(i=0;i<Y;i++)
{
Result*=X;
}
return Result;
}
/**
* @brief 在LCD1602指定位置开始显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~65535
* @param Length 要显示数字的长度,范围:1~5
* @retval 无
*/
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
}
}
/**
* @brief 在LCD1602指定位置开始以有符号十进制显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:-32768~32767
* @param Length 要显示数字的长度,范围:1~5
* @retval 无
*/
/*
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
unsigned char i;
unsigned int Number1;
LCD_SetCursor(Line,Column);
if(Number>=0)
{
LCD_WriteData('+');
Number1=Number;
}
else
{
LCD_WriteData('-');
Number1=-Number;
}
for(i=Length;i>0;i--)
{
LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
}
}
*/
/**
* @brief 在LCD1602指定位置开始以十六进制显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~0xFFFF
* @param Length 要显示数字的长度,范围:1~4
* @retval 无
*/
/*
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i,SingleNumber;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
SingleNumber=Number/LCD_Pow(16,i-1)%16;
if(SingleNumber<10)
{
LCD_WriteData(SingleNumber+'0');
}
else
{
LCD_WriteData(SingleNumber-10+'A');
}
}
}
*/
/**
* @brief 在LCD1602指定位置开始以二进制显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~1111 1111 1111 1111
* @param Length 要显示数字的长度,范围:1~16
* @retval 无
*/
/*
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
}
}
*/
LCD1602驱动函数头文件
#ifndef __LCD1602_H__
#define __LCD1602_H__
//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void write_du();
#endif
矩阵按键控制函数
#include <REGX52.H>
#include <LCD1602.H>
#include <DS1302.H>
#include <SERVO.H>
#include <DISPLAY.H>
sbit buzzer=P2^5;
#define NO_KEY 0XFF
#define KEY_STATE0 0
#define KEY_STATE1 1
#define KEY_STATE2 2
extern unsigned int key_count;
extern unsigned char mode;
extern unsigned char nian;
extern unsigned char yue;
extern unsigned char ri;
extern unsigned char xq;
extern unsigned char shi;
extern unsigned char fen;
extern unsigned char miao;
extern unsigned char count0;
extern unsigned char count1;
extern unsigned char count2;
extern unsigned char count3;
extern unsigned int keynumber;
extern unsigned int real_number;
extern bit motor_control;
extern bit work_mode;
bit run=1;//当run为1时++为0时--
bit displaymode3flag;
bit key_flag;
unsigned char key_press;//此函数用来统计按键按下的次数,按下选中数值进行闪烁
unsigned char num[6];
unsigned char press;
unsigned char number;
unsigned char keyscan()//按键扫描函数
{
static unsigned char key_state=KEY_STATE0;
unsigned char key_value=0,key_temp;
unsigned char key1,key2;
P1=0Xf0;
if(P1_7==0){key1=0x70;}
if(P1_6==0){key1=0xb0;}
if(P1_5==0){key1=0xd0;}
if(P1_4==0){key1=0xe0;}
if((P1_7==1)&&(P1_6==1)&&(P1_5==1)&&(P1_4==1)){key1=0xf0;}
P1=0X0f;
if(P1_3==0){key2=0x07;}
if(P1_2==0){key2=0x0b;}
if(P1_1==0){key2=0x0d;}
if(P1_0==0){key2=0x0e;}
if((P1_3==1)&&(P1_2==1)&&(P1_1==1)&&(P1_0==1)){key2=0x0f;}
key_temp=key1|key2;
switch(key_state)
{
case KEY_STATE0:
if(key_temp!=NO_KEY)
{
key_state=KEY_STATE1;
}
break;
case KEY_STATE1:
if(key_temp==NO_KEY)
{
key_state=KEY_STATE0;
}
else
{
switch(key_temp)
{
case 0x77:key_value=1;break;
case 0x7b:key_value=2;break;
case 0x7d:key_value=3;break;
case 0x7e:key_value=4;break;
case 0xb7:key_value=5;break;
case 0xbb:key_value=6;break;
case 0xbd:key_value=7;break;
case 0xbe:key_value=8;break;
case 0xd7:key_value=9;break;
case 0xdb:key_value=10;break;
case 0xdd:key_value=11;break;
case 0xde:key_value=12;break;
case 0xe7:key_value=13;break;
case 0xeb:key_value=14;break;
case 0xed:key_value=15;break;
case 0xee:key_value=16;break;
case 0xff:key_value=0;break;
}
key_state=KEY_STATE2;
}
break;
case KEY_STATE2:
if(key_temp==NO_KEY)
{
key_state=KEY_STATE0;
}
break;
}
return key_value;
}
/*
以下函数用按键控制舵机
*/
void engine_key()
{
if(displaymode3flag==0)
{
LCD_ShowString(1,1,"L2:");
LCD_ShowString(1,8,"L2:");
LCD_ShowString(1,15,"M3");
LCD_ShowString(2,1,"L3:");
LCD_ShowString(2,8,"L4:");
LCD_ShowChar(1,7,' ');
LCD_ShowChar(1,14,' ');
LCD_ShowChar(2,7,' ');
LCD_ShowChar(2,14,' ');
LCD_ShowNum(1,4,count0,3);
LCD_ShowNum(1,11,count1,3);
LCD_ShowNum(2,4,count2,3);
LCD_ShowNum(2,11,count3,3);
if(run)
{
LCD_ShowString(2,15,"++");
}
else
{
LCD_ShowString(2,15,"--");
}
displaymode3flag=1;
}
if(P3_0==0)//按键二
{
if(run==1)
{
if(count0<180)
{
count0++;
servo_control(4,count0);
LCD_ShowNum(1,4,count0,3);
}
}
else
{
if(count0>0)
{
count0--;
servo_control(4,count0);
LCD_ShowNum(1,4,count0,3);
}
}
if((count0==90)||(count0==180))
{
buzzer=~buzzer;
}
}
if(P3_2==0)//按键三
{
if(run==1)
{
if(count1<180)
{
count1++;
servo_control(1,count1);
LCD_ShowNum(1,11,count1,3);
}
}
else
{
if(count1>0)
{
count1--;
servo_control(1,count1);
LCD_ShowNum(1,11,count1,3);
}
}
if((count1==90)||(count1==180))
{
buzzer=~buzzer;
}
}
if((P3_3==0))//按键四
{
if(run==1)
{
if(count2<180)
{
count2++;
servo_control(2,count2);
LCD_ShowNum(2,4,count2,3);
}
}
else
{
if(count2>0)
{
count2--;
servo_control(2,count2);
LCD_ShowNum(2,4,count2,3);
}
}
if((count2==0)||(count2==180))
{
buzzer=~buzzer;
}
}
if((P1_4==0)&&(P1_3==0))//S13
{
if(run==1)
{
if(count3<180)
{
count3++;
servo_control(3,count3);
LCD_ShowNum(2,11,count3,3);
}
}
else
{
if(count3>90)
{
count3--;
servo_control(3,count3);
LCD_ShowNum(2,11,count3,3);
}
}
if((count3==90)||(count3==180))
{
buzzer=~buzzer;
}
}
}
/*
以下函数为按键处理函数
*/
void key_process()
{
unsigned char key_number;
if(key_count>=5)
{
key_count=0;
key_number=keyscan();
switch(key_number)
{
case 1:P2_0=0;
if(key_flag==0)
{
mode++;
}
if(mode==4)//当切换到工作模式2是关闭步进电机
{
key_flag=0;
keynumber=0;
displaymode3flag=0;
mode=2;
}
break;
case 2:
if(mode==2)//在时间设置界面下每按以后进行下一个变量设置
{
if(work_mode==1)
{
key_press++;
if(key_press==8)
{
key_press=0;
work_mode=0;
DS1302_Time[0]=nian;DS1302_Time[1]=yue;
DS1302_Time[2]=ri;DS1302_Time[3]=shi;
DS1302_Time[4]=fen;DS1302_Time[5]=miao;
DS1302_Time[6]=xq;DS1302_SetTime();//设置时间
}
}
}
if(mode==3)
{
number=1;
press++;
if(press<=3)
{
if(press==1)
{
keynumber=number*100+keynumber;
}
else if(press==2)
{
keynumber=number*10+keynumber;
}
else
{
keynumber=number*1+keynumber;
}
}
}
break;
case 3:
/*
以下代码在时间设置界面时进行时间累加
*/
if(mode==2)//处于工作模式1
{
if(work_mode==1)//处于时间设置界面,每次按下加一
{
if(key_press==1)//按第一次
{
if(nian<99)
{
nian++;
}
}
if(key_press==2)//按第二次
{
if(yue<12)
{
yue++;
}
}
if(key_press==3)//按第三次
{
if(ri<31)
{
ri++;
}
}
if(key_press==4)//按第四次
{
if(xq<7)
{
xq++;
}
}
if(key_press==5)//按第五次
{
if(shi<23)
{
shi++;
}
}
if(key_press==6)//按第六次
{
if(fen<59)
{
fen++;
}
}
if(key_press==7)//按第七次
{
if(miao<59)
{
miao++;
}
}
}
}
if(mode==3)
{
number=2;
press++;
if(press<=3)
{
if(press==1)
{
keynumber=number*100+keynumber;
}
else if(press==2)
{
keynumber=number*10+keynumber;
}
else
{
keynumber=number*1+keynumber;
}
}
}
break;
case 4:
/*
以下代码在时间设置界面时进行时间累减
*/
if(mode==2)//处于工作模式1
{
if(work_mode==1)//处于时间设置界面,每次按下加一
{
if(key_press==1)//按第一次
{
if(nian>0)
{
nian--;
}
}
if(key_press==2)//按第二次
{
if(yue>1)
{
yue--;
}
}
if(key_press==3)//按第三次
{
if(ri>1)
{
ri--;
}
}
if(key_press==4)//按第四次
{
if(xq>1)
{
xq--;
}
}
if(key_press==5)//按第五次
{
if(shi>0)
{
shi--;
}
}
if(key_press==6)//按第六次
{
if(fen>0)
{
fen--;
}
}
if(key_press==7)//按第七次
{
if(miao>0)
{
miao--;
}
}
}
}
if(mode==3)
{
number=3;
press++;
if(press<=3)
{
if(press==1)
{
keynumber=number*100+keynumber;
}
else if(press==2)
{
keynumber=number*10+keynumber;
}
else
{
keynumber=number*1+keynumber;
}
}
}
break;
case 5:
if(mode==2)
{
work_mode=1;
key_press=1;
}
if(mode==3)
{
keynumber=0;
press=0;
}
break;
case 6:
if(mode==3)
{
number=4;
press++;
if(press<=3)
{
if(press==1)
{
keynumber=number*100+keynumber;
}
else if(press==2)
{
keynumber=number*10+keynumber;
}
else
{
keynumber=number*1+keynumber;
}
}
}
break;
case 7:
if(mode==3)
{
number=5;
press++;
if(press<=3)
{
if(press==1)
{
keynumber=number*100+keynumber;
}
else if(press==2)
{
keynumber=number*10+keynumber;
}
else
{
keynumber=number*1+keynumber;
}
}
}
break;
case 8:
if(mode==3)
{
number=6;
press++;
if(press<=3)
{
if(press==1)
{
keynumber=number*100+keynumber;
}
else if(press==2)
{
keynumber=number*10+keynumber;
}
else
{
keynumber=number*1+keynumber;
}
}
}
break;
case 9:
if(mode==2)
{
if(work_mode==0)
{
motor_control=~motor_control;//用来控制步进电机开关
}
}
if(mode==3)
{
if(real_number==keynumber)
{
mode=4;
key_flag=1;
keynumber=0;
press=0;
P3_0=1;P3_1=1;P3_2=1;P3_3=1;
motor_control=0;
}
else
{
mode=2;
keynumber=0;
press=0;
}
}
break;
case 10:
if(mode==3)
{
number=7;
press++;
if(press<=3)
{
if(press==1)
{
keynumber=number*100+keynumber;
}
else if(press==2)
{
keynumber=number*10+keynumber;
}
else
{
keynumber=number*1+keynumber;
}
}
}
break;
case 11:
if(mode==3)
{
number=8;
press++;
if(press<=3)
{
if(press==1)
{
keynumber=number*100+keynumber;
}
else if(press==2)
{
keynumber=number*10+keynumber;
}
else
{
keynumber=number*1+keynumber;
}
}
}
break;
case 12:
if(mode==3)
{
number=9;
press++;
if(press<=3)
{
if(press==1)
{
keynumber=number*100+keynumber;
}
else if(press==2)
{
keynumber=number*10+keynumber;
}
else
{
keynumber=number*1+keynumber;
}
}
}
break;
case 13:
break;
case 14:
if(mode==4)
{
run=!run;
if(run)
{
LCD_ShowString(2,15,"++");
}
else
{
LCD_ShowString(2,15,"--");
}
}
break;
case 15:break;
case 16:break;
}
if(mode==4)
{
engine_key();
}
}
}
矩阵按键控制函数头文件
#ifndef __KEY_H
#define __KEY_H
unsigned char keyscan();
void key_process();
void engine_key();
#endif
系统初始化函数
#include <REGX52.H>
#include <ONEWIRE.H>
#include <LCD1602.H>
#include <INTERRUPT.H>
#include <DS18B20.H>
#include <SERVO.H>
/*
以下函数用于系统初始化
*/
void Init_process()
{
DS18B20_ConvertT(); //上电先转换一次温度,防止第一次读数据错误
Timer1Init();//定时器1初始化
Timer0Init();//定时器0初始化
LCD_Init();//LCD 初始化
init();
begin();
setPWMFreq(50);
/*
各舵机状态初始化
*/
servo_control(4,90);//底部舵机初始化0度
delayms(300);
servo_control(1,125);//高度调节舵机初始化
delayms(300);
servo_control(2,0);//前后舵机初始化
delayms(300);
servo_control(3,90);//抓取舵机初始化
delayms(300);
}
系统初始化函数头文件
#ifndef __INIT_SYSTEM_H
#define __INIT_SYSTEM_H
void Init_process();
#endif
DS18B20底层驱动函数
#include <REGX52.H>
//引脚定义
sbit OneWire_DQ=P3^7;
/**
* @brief 单总线初始化
* @param 无
* @retval 从机响应位,0为响应,1为未响应
*/
unsigned char OneWire_Init(void)
{
unsigned char i;
unsigned char AckBit;
OneWire_DQ=1;
OneWire_DQ=0;
i = 247;while (--i); //Delay 500us
OneWire_DQ=1;
i = 32;while (--i); //Delay 70us
AckBit=OneWire_DQ;
i = 247;while (--i); //Delay 500us
return AckBit;
}
/**
* @brief 单总线发送一位
* @param Bit 要发送的位
* @retval 无
*/
void OneWire_SendBit(unsigned char Bit)
{
unsigned char i;
OneWire_DQ=0;
i = 4;while (--i); //Delay 10us
OneWire_DQ=Bit;
i = 24;while (--i); //Delay 50us
OneWire_DQ=1;
}
/**
* @brief 单总线接收一位
* @param 无
* @retval 读取的位
*/
unsigned char OneWire_ReceiveBit(void)
{
unsigned char i;
unsigned char Bit;
OneWire_DQ=0;
i = 2;while (--i); //Delay 5us
OneWire_DQ=1;
i = 2;while (--i); //Delay 5us
Bit=OneWire_DQ;
i = 24;while (--i); //Delay 50us
return Bit;
}
/**
* @brief 单总线发送一个字节
* @param Byte 要发送的字节
* @retval 无
*/
void OneWire_SendByte(unsigned char Byte)
{
unsigned char i;
for(i=0;i<8;i++)
{
OneWire_SendBit(Byte&(0x01<<i));
}
}
/**
* @brief 单总线接收一个字节
* @param 无
* @retval 接收的一个字节
*/
unsigned char OneWire_ReceiveByte(void)
{
unsigned char i;
unsigned char Byte=0x00;
for(i=0;i<8;i++)
{
if(OneWire_ReceiveBit()){Byte|=(0x01<<i);}
}
return Byte;
}
DS18B20驱动函数头文件
#ifndef __DS18B20_H__
#define __DS18B20_H__
void DS18B20_ConvertT(void);
float DS18B20_ReadT(void);
#endif
DS1302驱动函数
#include <REGX52.H>
extern unsigned char nian;
extern unsigned char yue;
extern unsigned char ri;
extern unsigned char xq;
extern unsigned char shi;
extern unsigned char fen;
extern unsigned char miao;
//引脚定义
sbit DS1302_SCLK=P3^6;
sbit DS1302_IO=P3^4;
sbit DS1302_CE=P3^5;
//寄存器写入地址/指令定义
#define DS1302_SECOND 0x80
#define DS1302_MINUTE 0x82
#define DS1302_HOUR 0x84
#define DS1302_DATE 0x86
#define DS1302_MONTH 0x88
#define DS1302_DAY 0x8A
#define DS1302_YEAR 0x8C
#define DS1302_WP 0x8E
//时间数组,索引0~6分别为年、月、日、时、分、秒、星期,设置为有符号的便于<0的判断
char DS1302_Time[]={22,8,6,15,57,0,6};
/**
* @brief DS1302初始化
* @param 无
* @retval 无
*/
void DS1302_Init(void)
{
DS1302_CE=0;
DS1302_SCLK=0;
}
/**
* @brief DS1302写一个字节
* @param Command 命令字/地址
* @param Data 要写入的数据
* @retval 无
*/
void DS1302_WriteByte(unsigned char Command,Data)
{
unsigned char i;
DS1302_CE=1;
for(i=0;i<8;i++)
{
DS1302_IO=Command&(0x01<<i);
DS1302_SCLK=1;
DS1302_SCLK=0;
}
for(i=0;i<8;i++)
{
DS1302_IO=Data&(0x01<<i);
DS1302_SCLK=1;
DS1302_SCLK=0;
}
DS1302_CE=0;
}
/**
* @brief DS1302读一个字节
* @param Command 命令字/地址
* @retval 读出的数据
*/
unsigned char DS1302_ReadByte(unsigned char Command)
{
unsigned char i,Data=0x00;
Command|=0x01; //将指令转换为读指令
DS1302_CE=1;
for(i=0;i<8;i++)
{
DS1302_IO=Command&(0x01<<i);
DS1302_SCLK=0;
DS1302_SCLK=1;
}
for(i=0;i<8;i++)
{
DS1302_SCLK=1;
DS1302_SCLK=0;
if(DS1302_IO){Data|=(0x01<<i);}
}
DS1302_CE=0;
DS1302_IO=0; //读取后将IO设置为0,否则读出的数据会出错
return Data;
}
/**
* @brief DS1302设置时间,调用之后,DS1302_Time数组的数字会被设置到DS1302中
* @param 无
* @retval 无
*/
void DS1302_SetTime(void)
{
DS1302_WriteByte(DS1302_WP,0x00);
DS1302_WriteByte(DS1302_YEAR,DS1302_Time[0]/10*16+DS1302_Time[0]%10);//十进制转BCD码后写入
DS1302_WriteByte(DS1302_MONTH,DS1302_Time[1]/10*16+DS1302_Time[1]%10);
DS1302_WriteByte(DS1302_DATE,DS1302_Time[2]/10*16+DS1302_Time[2]%10);
DS1302_WriteByte(DS1302_HOUR,DS1302_Time[3]/10*16+DS1302_Time[3]%10);
DS1302_WriteByte(DS1302_MINUTE,DS1302_Time[4]/10*16+DS1302_Time[4]%10);
DS1302_WriteByte(DS1302_SECOND,DS1302_Time[5]/10*16+DS1302_Time[5]%10);
DS1302_WriteByte(DS1302_DAY,DS1302_Time[6]/10*16+DS1302_Time[6]%10);
DS1302_WriteByte(DS1302_WP,0x80);
nian=DS1302_Time[0];yue=DS1302_Time[1];
ri=DS1302_Time[2]; shi=DS1302_Time[3];
fen= DS1302_Time[4];miao=DS1302_Time[5];
xq= DS1302_Time[6];
}
/**
* @brief DS1302读取时间,调用之后,DS1302中的数据会被读取到DS1302_Time数组中
* @param 无
* @retval 无
*/
void DS1302_ReadTime(void)
{
unsigned char Temp;
Temp=DS1302_ReadByte(DS1302_YEAR);
DS1302_Time[0]=Temp/16*10+Temp%16;//BCD码转十进制后读取
Temp=DS1302_ReadByte(DS1302_MONTH);
DS1302_Time[1]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_DATE);
DS1302_Time[2]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_HOUR);
DS1302_Time[3]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_MINUTE);
DS1302_Time[4]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_SECOND);
DS1302_Time[5]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_DAY);
DS1302_Time[6]=Temp/16*10+Temp%16;
}
DS1302驱动头文件
#ifndef __DS1302_H__
#define __DS1302_H__
//外部可调用时间数组,索引0~6分别为年、月、日、时、分、秒、星期,设置为有符号的便于<0的判断
extern char DS1302_Time[];
void DS1302_Init(void);
void DS1302_WriteByte(unsigned char Command,Data);
unsigned char DS1302_ReadByte(unsigned char Command);
void DS1302_SetTime(void);
void DS1302_ReadTime(void);
#endif
定时器配置函数
#include <REGX52.H>
/*定时器0一毫秒中断函数*/
void Timer0Init() //1毫秒@11.0592MHz
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x66; //设置定时初值
TH0 = 0xFC; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1;
EA=1;
}
void Timer1Init() //1毫秒@11.0592MHz
{
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x10; //设置定时器模式
TL1 = 0xCD; //设置定时初值
TH1 = 0xD4; //设置定时初值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1=1;
EA=1;
}
定时器配置头文件
#ifndef __INTERRUPT_H
#define __INTERRUPT_H
void Timer0Init(); //1毫秒@11.0592MHz
void Timer1Init();
#endif
步进电机驱动文件
#include "reg52.h"
typedef unsigned int u16; //对系统默认数据类型进行重定义
typedef unsigned char u8;
extern bit motor_control;
//定义ULN2003控制步进电机管脚
sbit IN1_A=P3^0;
sbit IN2_B=P3^1;
sbit IN3_C=P3^2;
sbit IN4_D=P3^3;
/*******************************************************************************
* 函 数 名 : delay_ms
* 函数功能 : ms延时函数,ms=1时,大约延时1ms
* 输 入 : ten_us
* 输 出 : 无
*******************************************************************************/
void delay_ms(u16 ms)
{
u16 i,j;
for(i=ms;i>0;i--)
for(j=110;j>0;j--);
}
/*******************************************************************************
* 函 数 名 : step_motor_28BYJ48_send_pulse
* 函数功能 : 输出一个数据给ULN2003从而实现向步进电机发送一个脉冲
* 输 入 : step:指定步进序号,可选值0~7
dir:方向选择,1:顺时针,0:逆时针
* 输 出 : 无
*******************************************************************************/
void step_motor_28BYJ48_send_pulse(u8 step,u8 dir)
{
u8 temp=step;
if(dir==0) //如果为逆时针旋转
temp=7-step;//调换节拍信号
switch(temp)//8个节拍控制:A->AB->B->BC->C->CD->D->DA
{
case 0: IN1_A=1;IN2_B=0;IN3_C=0;IN4_D=0;break;
case 1: IN1_A=1;IN2_B=1;IN3_C=0;IN4_D=0;break;
case 2: IN1_A=0;IN2_B=1;IN3_C=0;IN4_D=0;break;
case 3: IN1_A=0;IN2_B=1;IN3_C=1;IN4_D=0;break;
case 4: IN1_A=0;IN2_B=0;IN3_C=1;IN4_D=0;break;
case 5: IN1_A=0;IN2_B=0;IN3_C=1;IN4_D=1;break;
case 6: IN1_A=0;IN2_B=0;IN3_C=0;IN4_D=1;break;
case 7: IN1_A=1;IN2_B=0;IN3_C=0;IN4_D=1;break;
default: IN1_A=0;IN2_B=0;IN3_C=0;IN4_D=0;break;//停止相序
}
}
u8 key=0;
u8 dir=0;//默认逆时针方向
u8 speed=0;
u8 step=0;
/*
以下函数通过矩阵按键配合控制步进电机
*/
void motor_process()
{
if(motor_control)
{
unsigned int motor_count;
motor_count++;
if(motor_count>300)
{
motor_count=0;
dir=!dir;
}
key=0;
step_motor_28BYJ48_send_pulse(step++,dir);
if(step==8)step=0;
delay_ms(speed);
}
}
步进电机驱动头文件
#ifndef __MOTOR_H
#define __MOTOR_H
typedef unsigned int u16; //对系统默认数据类型进行重定义
typedef unsigned char u8;
void delay_ms(u16 ms);
void step_motor_28BYJ48_send_pulse(u8 step,u8 dir);
void motor_process();
#endif
pca9685舵机函数
#include <reg52.h>
#include <intrins.h>
#include <stdio.h>
#include <math.h>
#define PCA9685_adrr 0x80// 1+A5+A4+A3+A2+A1+A0+w/r
#define PCA9685_SUBADR1 0x2
#define PCA9685_SUBADR2 0x3
#define PCA9685_SUBADR3 0x4
#define PCA9685_MODE1 0x00
#define PCA9685_PRESCALE 0xFE
#define LED0_ON_L 0x06
#define LED0_ON_H 0x07
#define LED0_OFF_L 0x08
#define LED0_OFF_H 0x09
#define ALLLED_ON_L 0xFA
#define ALLLED_ON_H 0xFB
#define ALLLED_OFF_L 0xFC
#define ALLLED_OFF_H 0xFD
//#define SERVO_ANGLE0 102 //0度对应4096的脉宽计数值
//#define SERVO_ANGLE180 476 //180度对应4096的脉宽计算值,根据不同舵机修改
typedef unsigned char uchar;
typedef unsigned int uint;
sbit scl=P2^0; //时钟输入线
sbit sda=P2^1; //数据输入/输出端
void delayms(uint z);
void delayus();
void init();
void start();
void stop();
void ACK();
void write_byte(uchar byte);
uchar PCA9685_read(uchar address);
uchar read_byte();
void PCA9685_write(uchar address,uchar date);
void reset(void) ;
void setPWMFreq(float freq);
void servo_control(uchar num, uchar angle);
/**********************函数的声明*********************************/
/*---------------------------------------------------------------
毫秒延时函数
----------------------------------------------------------------*/
void delayms(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=148;y>0;y--);
}
/*---------------------------------------------------------------
IIC总线所需的通用函数
----------------------------------------------------------------*/
/*---------------------------------------------------------------
微妙级别延时函数 大于4.7us
----------------------------------------------------------------*/
void delayus()
{
_nop_(); //在intrins.h文件里
_nop_();
_nop_();
_nop_();
_nop_();
}
/*---------------------------------------------------------------
IIC总线初始化函数
----------------------------------------------------------------*/
void init()
{
sda=1; //sda scl使用前总是被拉高
delayus();
scl=1;
delayus();
}
/*---------------------------------------------------------------
IIC总线启动信号函数
----------------------------------------------------------------*/
void start()
{
sda=1;
delayus();
scl=1; //scl拉高时 sda突然来个低电平 就启动了IIC总线
delayus();
sda=0;
delayus();
scl=0;
delayus();
}
/*---------------------------------------------------------------
IIC总线停止信号函数
----------------------------------------------------------------*/
void stop()
{
sda=0;
delayus();
scl=1; //scl拉高时 sda突然来个高电平 就停止了IIC总线
delayus();
sda=1;
delayus();
}
/*---------------------------------------------------------------
IIC总线应答信号函数
----------------------------------------------------------------*/
void ACK()
{
uchar i;
scl=1;
delayus();
while((sda=1)&&(i<255))
i++;
scl=0;
delayus();
}
/*---------------------------------------------------------------
写一个字节,无返回值,需输入一个字节值
----------------------------------------------------------------*/
void write_byte(uchar byte)
{
uchar i,temp;
temp=byte;
for(i=0;i<8;i++)
{
temp=temp<<1;
scl=0;
delayus();
sda=CY;
delayus();
scl=1;
delayus();
}
scl=0;
delayus();
sda=1;
delayus();
}
/*---------------------------------------------------------------
读一个字节函数,有返回值
----------------------------------------------------------------*/
uchar read_byte()
{
uchar i,j,k;
scl=0;
delayus();
sda=1;
delayus();
for(i=0;i<8;i++)
{
delayus();
scl=1;
delayus();
if(sda==1)
{
j=1;
}
else j=0;
k=(k<< 1)|j;
scl=0;
}
delayus();
return k;
}
/*---------------------------------------------------------------
有关PCA9685模块的函数
----------------------------------------------------------------*/
/*---------------------------------------------------------------
向PCA9685里写地址,数据
----------------------------------------------------------------*/
void PCA9685_write(uchar address,uchar date)
{
start();
write_byte(PCA9685_adrr); //PCA9685的片选地址
ACK();
write_byte(address); //写地址控制字节
ACK();
write_byte(date); //写数据
ACK();
stop();
}
/*---------------------------------------------------------------
从PCA9685里的地址值中读数据(有返回值)
----------------------------------------------------------------*/
uchar PCA9685_read(uchar address)
{
uchar date;
start();
write_byte(PCA9685_adrr); //PCA9685的片选地址
ACK();
write_byte(address);
ACK();
start();
write_byte(PCA9685_adrr|0x01); //地址的第八位控制数据流方向,就是写或读
ACK();
date=read_byte();
stop();
return date;
}
/*---------------------------------------------------------------
PCA9685复位
----------------------------------------------------------------*/
void reset(void)
{
PCA9685_write(PCA9685_MODE1,0x0);
}
void begin(void)
{
reset();
}
/*---------------------------------------------------------------
PCA9685修改频率函数
----------------------------------------------------------------*/
void setPWMFreq(float freq)
{
uint prescale,oldmode,newmode;
float prescaleval;
freq *= 0.92; // Correct for overshoot in the frequency setting
prescaleval = 25000000;
prescaleval /= 4096;
prescaleval /= freq;
prescaleval -= 1;
prescale = floor(prescaleval + 0.5);
oldmode = PCA9685_read(PCA9685_MODE1);
newmode = (oldmode&0x7F) | 0x10; // sleep
PCA9685_write(PCA9685_MODE1, newmode); // go to sleep
PCA9685_write(PCA9685_PRESCALE, prescale); // set the prescaler
PCA9685_write(PCA9685_MODE1, oldmode);
delayms(2);
PCA9685_write(PCA9685_MODE1, oldmode | 0xa1);
}
/*---------------------------------------------------------------
PCA9685修改角度函数
num:舵机PWM输出引脚0~15,on:PWM上升计数值0~4096,off:PWM下降计数值0~4096
一个PWM周期分成4096份,由0开始+1计数,计到on时跳变为高电平,继续计数到off时
跳变为低电平,直到计满4096重新开始。所以当on不等于0时可作延时,当on等于0时,
off/4096的值就是PWM的占空比。
----------------------------------------------------------------*/
void servo_control(uchar num, uchar angle)
{
uint off = 102.4+2.275555556*angle;
PCA9685_write(LED0_ON_L+4*num,0);
PCA9685_write(LED0_ON_H+4*num,0);
PCA9685_write(LED0_OFF_L+4*num,off);
PCA9685_write(LED0_OFF_H+4*num,off>>8);
}
pca9685舵机函数头文件
#ifndef __SERVO_H
#define __SERVO_H
sbit scl=P2^0; //时钟输入线
sbit sda=P2^1; //数据输入/输出端
typedef unsigned char uchar;
typedef unsigned int uint;
void begin(void);
void delayms(uint z);
void delayus();
void init();
void start();
void stop();
void ACK();
void write_byte(uchar byte);
uchar PCA9685_read(uchar address);
uchar read_byte();
void PCA9685_write(uchar address,uchar date);
void reset(void) ;
void setPWMFreq(float freq);
void servo_control(uchar num, uchar angle);
#endif
以下为红外遥控控制机械臂
主函数
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "IR.h"
#include "SERVO.h"
#include "CONTROL.h"
#include "INIT.h"
unsigned char count0=90;//初始化底部舵机角度
unsigned char count1=125;//初始化高度舵机角度
unsigned char count2=0;//初始化前后舵机角度
unsigned char count3=90;//初始化夹爪舵机角度
void main()
{
Init_system();//系统初始化
while(1)
{
control_process();//红外检测模式
}
}
Delay,c
void Delay(unsigned int xms)//自定义毫秒级延时
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
Delay.h
#ifndef __DELAY_H__
#define __DELAY_H__
void Delay(unsigned int xms);
#endif
LCD1602.C
#include <REGX52.H>
//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0
//函数定义:
/**
* @brief LCD1602延时函数,12MHz调用可延时1ms
* @param 无
* @retval 无
*/
void LCD_Delay()
{
unsigned char i, j;
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
/**
* @brief LCD1602写命令
* @param Command 要写入的命令
* @retval 无
*/
void LCD_WriteCommand(unsigned char Command)
{
LCD_RS=0;
LCD_RW=0;
LCD_DataPort=Command;
LCD_EN=1;
LCD_Delay();
LCD_EN=0;
LCD_Delay();
}
/**
* @brief LCD1602写数据
* @param Data 要写入的数据
* @retval 无
*/
void LCD_WriteData(unsigned char Data)
{
LCD_RS=1;
LCD_RW=0;
LCD_DataPort=Data;
LCD_EN=1;
LCD_Delay();
LCD_EN=0;
LCD_Delay();
}
/**
* @brief LCD1602设置光标位置
* @param Line 行位置,范围:1~2
* @param Column 列位置,范围:1~16
* @retval 无
*/
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
if(Line==1)
{
LCD_WriteCommand(0x80|(Column-1));
}
else if(Line==2)
{
LCD_WriteCommand(0x80|(Column-1+0x40));
}
}
/**
* @brief LCD1602初始化函数
* @param 无
* @retval 无
*/
void LCD_Init()
{
LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
LCD_WriteCommand(0x01);//光标复位,清屏
}
/**
* @brief 在LCD1602指定位置上显示一个字符
* @param Line 行位置,范围:1~2
* @param Column 列位置,范围:1~16
* @param Char 要显示的字符
* @retval 无
*/
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
LCD_SetCursor(Line,Column);
LCD_WriteData(Char);
}
/**
* @brief 在LCD1602指定位置开始显示所给字符串
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param String 要显示的字符串
* @retval 无
*/
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=0;String[i]!='\0';i++)
{
LCD_WriteData(String[i]);
}
}
/**
* @brief 返回值=X的Y次方
*/
int LCD_Pow(int X,int Y)
{
unsigned char i;
int Result=1;
for(i=0;i<Y;i++)
{
Result*=X;
}
return Result;
}
/**
* @brief 在LCD1602指定位置开始显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~65535
* @param Length 要显示数字的长度,范围:1~5
* @retval 无
*/
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
}
}
/**
* @brief 在LCD1602指定位置开始以有符号十进制显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:-32768~32767
* @param Length 要显示数字的长度,范围:1~5
* @retval 无
*/
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
unsigned char i;
unsigned int Number1;
LCD_SetCursor(Line,Column);
if(Number>=0)
{
LCD_WriteData('+');
Number1=Number;
}
else
{
LCD_WriteData('-');
Number1=-Number;
}
for(i=Length;i>0;i--)
{
LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
}
}
/**
* @brief 在LCD1602指定位置开始以十六进制显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~0xFFFF
* @param Length 要显示数字的长度,范围:1~4
* @retval 无
*/
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i,SingleNumber;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
SingleNumber=Number/LCD_Pow(16,i-1)%16;
if(SingleNumber<10)
{
LCD_WriteData(SingleNumber+'0');
}
else
{
LCD_WriteData(SingleNumber-10+'A');
}
}
}
/**
* @brief 在LCD1602指定位置开始以二进制显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~1111 1111 1111 1111
* @param Length 要显示数字的长度,范围:1~16
* @retval 无
*/
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
}
}
LCD1602.H
#ifndef __LCD1602_H__
#define __LCD1602_H__
//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
#endif
INT0.C
#include <REGX52.H>
/**
* @brief 外部中断0初始化
* @param 无
* @retval 无
*/
void Int0_Init(void)//定时器0初始化配置
{
IT0=1;
IE0=0;
EX0=1;
EA=1;
PX0=1;
}
/*外部中断0中断函数模板
void Int0_Routine(void) interrupt 0
{
}
*/
INT0.H
#ifndef __INT0_H__
#define __INT0_H__
void Int0_Init(void);
#endif
TIMER0.C
#include <REGX52.H>
/**
* @brief 定时器0初始化
* @param 无
* @retval 无
*/
void Timer0_Init(void)
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0; //设置定时初值
TH0 = 0; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 0; //定时器0不计时
}
/**
* @brief 定时器0设置计数器值
* @param Value,要设置的计数器值,范围:0~65535
* @retval 无
*/
void Timer0_SetCounter(unsigned int Value)
{
TH0=Value/256;
TL0=Value%256;
}
/**
* @brief 定时器0获取计数器值
* @param 无
* @retval 计数器值,范围:0~65535
*/
unsigned int Timer0_GetCounter(void)
{
return (TH0<<8)|TL0;
}
/**
* @brief 定时器0启动停止控制
* @param Flag 启动停止标志,1为启动,0为停止
* @retval 无
*/
void Timer0_Run(unsigned char Flag)
{
TR0=Flag;
}
TIMER0.H
#ifndef __TIMER0_H__
#define __TIMER0_H__
void Timer0_Init(void);
void Timer0_SetCounter(unsigned int Value);
unsigned int Timer0_GetCounter(void);
void Timer0_Run(unsigned char Flag);
#endif
IR.C
#include <REGX52.H>
#include "Timer0.h"
#include "Int0.h"
unsigned int IR_Time;
unsigned char IR_State;
unsigned char IR_Data[4];
unsigned char IR_pData;
unsigned char IR_DataFlag;
unsigned char IR_RepeatFlag;
unsigned char IR_Address;
unsigned char IR_Command;
/**
* @brief 红外遥控初始化
* @param 无
* @retval 无
*/
void IR_Init(void)
{
Timer0_Init();
Int0_Init();
}
/**
* @brief 红外遥控获取收到数据帧标志位
* @param 无
* @retval 是否收到数据帧,1为收到,0为未收到
*/
unsigned char IR_GetDataFlag(void)
{
if(IR_DataFlag)
{
IR_DataFlag=0;
return 1;
}
return 0;
}
/**
* @brief 红外遥控获取收到连发帧标志位
* @param 无
* @retval 是否收到连发帧,1为收到,0为未收到
*/
unsigned char IR_GetRepeatFlag(void)
{
if(IR_RepeatFlag)
{
IR_RepeatFlag=0;
return 1;
}
return 0;
}
/**
* @brief 红外遥控获取收到的地址数据
* @param 无
* @retval 收到的地址数据
*/
unsigned char IR_GetAddress(void)
{
return IR_Address;
}
/**
* @brief 红外遥控获取收到的命令数据
* @param 无
* @retval 收到的命令数据
*/
unsigned char IR_GetCommand(void)
{
return IR_Command;
}
//外部中断0中断函数,下降沿触发执行
void Int0_Routine(void) interrupt 0
{
if(IR_State==0) //状态0,空闲状态
{
Timer0_SetCounter(0); //定时计数器清0
Timer0_Run(1); //定时器启动
IR_State=1; //置状态为1
}
else if(IR_State==1) //状态1,等待Start信号或Repeat信号
{
IR_Time=Timer0_GetCounter(); //获取上一次中断到此次中断的时间
Timer0_SetCounter(0); //定时计数器清0
//如果计时为13.5ms,则接收到了Start信号(判定值在12MHz晶振下为13500,在11.0592MHz晶振下为12442)
if(IR_Time>12442-500 && IR_Time<12442+500)
{
IR_State=2; //置状态为2
}
//如果计时为11.25ms,则接收到了Repeat信号(判定值在12MHz晶振下为11250,在11.0592MHz晶振下为10368)
else if(IR_Time>10368-500 && IR_Time<10368+500)
{
IR_RepeatFlag=1; //置收到连发帧标志位为1
Timer0_Run(0); //定时器停止
IR_State=0; //置状态为0
}
else //接收出错
{
IR_State=1; //置状态为1
}
}
else if(IR_State==2) //状态2,接收数据
{
IR_Time=Timer0_GetCounter(); //获取上一次中断到此次中断的时间
Timer0_SetCounter(0); //定时计数器清0
//如果计时为1120us,则接收到了数据0(判定值在12MHz晶振下为1120,在11.0592MHz晶振下为1032)
if(IR_Time>1032-500 && IR_Time<1032+500)
{
IR_Data[IR_pData/8]&=~(0x01<<(IR_pData%8)); //数据对应位清0
IR_pData++; //数据位置指针自增
}
//如果计时为2250us,则接收到了数据1(判定值在12MHz晶振下为2250,在11.0592MHz晶振下为2074)
else if(IR_Time>2074-500 && IR_Time<2074+500)
{
IR_Data[IR_pData/8]|=(0x01<<(IR_pData%8)); //数据对应位置1
IR_pData++; //数据位置指针自增
}
else //接收出错
{
IR_pData=0; //数据位置指针清0
IR_State=1; //置状态为1
}
if(IR_pData>=32) //如果接收到了32位数据
{
IR_pData=0; //数据位置指针清0
if((IR_Data[0]==~IR_Data[1]) && (IR_Data[2]==~IR_Data[3])) //数据验证
{
IR_Address=IR_Data[0]; //转存数据
IR_Command=IR_Data[2];
IR_DataFlag=1; //置收到连发帧标志位为1
}
Timer0_Run(0); //定时器停止
IR_State=0; //置状态为0
}
}
}
IR.H
#ifndef __IR_H__
#define __IR_H__
#define IR_POWER 0x45
#define IR_MODE 0x46
#define IR_MUTE 0x47
#define IR_START_STOP 0x44
#define IR_PREVIOUS 0x40
#define IR_NEXT 0x43
#define IR_EQ 0x07
#define IR_VOL_MINUS 0x15
#define IR_VOL_ADD 0x09
#define IR_0 0x16
#define IR_RPT 0x19
#define IR_USD 0x0D
#define IR_1 0x0C
#define IR_2 0x18
#define IR_3 0x5E
#define IR_4 0x08
#define IR_5 0x1C
#define IR_6 0x5A
#define IR_7 0x42
#define IR_8 0x52
#define IR_9 0x4A
void IR_Init(void);
unsigned char IR_GetDataFlag(void);
unsigned char IR_GetRepeatFlag(void);
unsigned char IR_GetAddress(void);
unsigned char IR_GetCommand(void);
#endif
SERVO.C
#include <reg52.h>
#include <intrins.h>
#include <stdio.h>
#include <math.h>
#define PCA9685_adrr 0x80// 1+A5+A4+A3+A2+A1+A0+w/r
#define PCA9685_SUBADR1 0x2
#define PCA9685_SUBADR2 0x3
#define PCA9685_SUBADR3 0x4
#define PCA9685_MODE1 0x00
#define PCA9685_PRESCALE 0xFE
#define LED0_ON_L 0x06
#define LED0_ON_H 0x07
#define LED0_OFF_L 0x08
#define LED0_OFF_H 0x09
#define ALLLED_ON_L 0xFA
#define ALLLED_ON_H 0xFB
#define ALLLED_OFF_L 0xFC
#define ALLLED_OFF_H 0xFD
//#define SERVO_ANGLE0 102 //0度对应4096的脉宽计数值
//#define SERVO_ANGLE180 476 //180度对应4096的脉宽计算值,根据不同舵机修改
typedef unsigned char uchar;
typedef unsigned int uint;
sbit scl=P2^0; //时钟输入线
sbit sda=P2^1; //数据输入/输出端
void delayms(uint z);
void delayus();
void init();
void start();
void stop();
void ACK();
void write_byte(uchar byte);
uchar PCA9685_read(uchar address);
uchar read_byte();
void PCA9685_write(uchar address,uchar date);
void reset(void) ;
void setPWMFreq(float freq);
void servo_control(uchar num, uchar angle);
/**********************函数的声明*********************************/
/*---------------------------------------------------------------
毫秒延时函数
----------------------------------------------------------------*/
void delayms(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=148;y>0;y--);
}
/*---------------------------------------------------------------
IIC总线所需的通用函数
----------------------------------------------------------------*/
/*---------------------------------------------------------------
微妙级别延时函数 大于4.7us
----------------------------------------------------------------*/
void delayus()
{
_nop_(); //在intrins.h文件里
_nop_();
_nop_();
_nop_();
_nop_();
}
/*---------------------------------------------------------------
IIC总线初始化函数
----------------------------------------------------------------*/
void init()
{
sda=1; //sda scl使用前总是被拉高
delayus();
scl=1;
delayus();
}
/*---------------------------------------------------------------
IIC总线启动信号函数
----------------------------------------------------------------*/
void start()
{
sda=1;
delayus();
scl=1; //scl拉高时 sda突然来个低电平 就启动了IIC总线
delayus();
sda=0;
delayus();
scl=0;
delayus();
}
/*---------------------------------------------------------------
IIC总线停止信号函数
----------------------------------------------------------------*/
void stop()
{
sda=0;
delayus();
scl=1; //scl拉高时 sda突然来个高电平 就停止了IIC总线
delayus();
sda=1;
delayus();
}
/*---------------------------------------------------------------
IIC总线应答信号函数
----------------------------------------------------------------*/
void ACK()
{
uchar i;
scl=1;
delayus();
while((sda=1)&&(i<255))
i++;
scl=0;
delayus();
}
/*---------------------------------------------------------------
写一个字节,无返回值,需输入一个字节值
----------------------------------------------------------------*/
void write_byte(uchar byte)
{
uchar i,temp;
temp=byte;
for(i=0;i<8;i++)
{
temp=temp<<1;
scl=0;
delayus();
sda=CY;
delayus();
scl=1;
delayus();
}
scl=0;
delayus();
sda=1;
delayus();
}
/*---------------------------------------------------------------
读一个字节函数,有返回值
----------------------------------------------------------------*/
uchar read_byte()
{
uchar i,j,k;
scl=0;
delayus();
sda=1;
delayus();
for(i=0;i<8;i++)
{
delayus();
scl=1;
delayus();
if(sda==1)
{
j=1;
}
else j=0;
k=(k<< 1)|j;
scl=0;
}
delayus();
return k;
}
/*---------------------------------------------------------------
有关PCA9685模块的函数
----------------------------------------------------------------*/
/*---------------------------------------------------------------
向PCA9685里写地址,数据
----------------------------------------------------------------*/
void PCA9685_write(uchar address,uchar date)
{
start();
write_byte(PCA9685_adrr); //PCA9685的片选地址
ACK();
write_byte(address); //写地址控制字节
ACK();
write_byte(date); //写数据
ACK();
stop();
}
/*---------------------------------------------------------------
从PCA9685里的地址值中读数据(有返回值)
----------------------------------------------------------------*/
uchar PCA9685_read(uchar address)
{
uchar date;
start();
write_byte(PCA9685_adrr); //PCA9685的片选地址
ACK();
write_byte(address);
ACK();
start();
write_byte(PCA9685_adrr|0x01); //地址的第八位控制数据流方向,就是写或读
ACK();
date=read_byte();
stop();
return date;
}
/*---------------------------------------------------------------
PCA9685复位
----------------------------------------------------------------*/
void reset(void)
{
PCA9685_write(PCA9685_MODE1,0x0);
}
void begin(void)
{
reset();
}
/*---------------------------------------------------------------
PCA9685修改频率函数
----------------------------------------------------------------*/
void setPWMFreq(float freq)
{
uint prescale,oldmode,newmode;
float prescaleval;
freq *= 0.92; // Correct for overshoot in the frequency setting
prescaleval = 25000000;
prescaleval /= 4096;
prescaleval /= freq;
prescaleval -= 1;
prescale = floor(prescaleval + 0.5);
oldmode = PCA9685_read(PCA9685_MODE1);
newmode = (oldmode&0x7F) | 0x10; // sleep
PCA9685_write(PCA9685_MODE1, newmode); // go to sleep
PCA9685_write(PCA9685_PRESCALE, prescale); // set the prescaler
PCA9685_write(PCA9685_MODE1, oldmode);
delayms(2);
PCA9685_write(PCA9685_MODE1, oldmode | 0xa1);
}
/*---------------------------------------------------------------
PCA9685修改角度函数
num:舵机PWM输出引脚0~15,on:PWM上升计数值0~4096,off:PWM下降计数值0~4096
一个PWM周期分成4096份,由0开始+1计数,计到on时跳变为高电平,继续计数到off时
跳变为低电平,直到计满4096重新开始。所以当on不等于0时可作延时,当on等于0时,
off/4096的值就是PWM的占空比。
----------------------------------------------------------------*/
void servo_control(uchar num, uchar angle)
{
uint off = 102.4+2.275555556*angle;
PCA9685_write(LED0_ON_L+4*num,0);
PCA9685_write(LED0_ON_H+4*num,0);
PCA9685_write(LED0_OFF_L+4*num,off);
PCA9685_write(LED0_OFF_H+4*num,off>>8);
}
SERVO.H
#ifndef __SERVO_H
#define __SERVO_H
sbit scl=P2^0; //时钟输入线
sbit sda=P2^1; //数据输入/输出端
typedef unsigned char uchar;
typedef unsigned int uint;
void begin(void);
void delayms(uint z);
void delayus();
void init();
void start();
void stop();
void ACK();
void write_byte(uchar byte);
uchar PCA9685_read(uchar address);
uchar read_byte();
void PCA9685_write(uchar address,uchar date);
void reset(void) ;
void setPWMFreq(float freq);
void servo_control(uchar num, uchar angle);
#endif
CONTROL.C
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "IR.h"
#include "SERVO.h"
sbit Buzzer=P2^5;
unsigned char Command;
unsigned char Address;
extern unsigned char count0;
extern unsigned char count1;
extern unsigned char count2;
extern unsigned char count3;
void control_process()
{
if(IR_GetDataFlag() || IR_GetRepeatFlag()) //如果收到数据帧或者收到连发帧
{
Address=IR_GetAddress(); //获取遥控器地址码
Command=IR_GetCommand(); //获取遥控器命令码
/*
底部舵机
*/
if(Command==IR_VOL_MINUS) //如果遥控器VOL-按键按下
{
if(count0>0)
{
count0--; //Num自减
servo_control(4,count0);
LCD_ShowNum(1,4,count0,3); //显示舵机工作状态
}
if(count0==0)
{
Buzzer=~Buzzer;
}
}
if(Command==IR_VOL_ADD) //如果遥控器VOL+按键按下
{
if(count0<180)
{
count0++; //Num自增
servo_control(4,count0);
LCD_ShowNum(1,4,count0,3); //显示舵机工作状态
}
if(count0==180)
{
Buzzer=~Buzzer;
}
}
if(Command==IR_RPT ) //如果遥控器VOL-按键按下
{
if(count1>0)
{
count1--; //Num自减
servo_control(1,count1);
LCD_ShowNum(1,11,count1,3); //显示舵机工作状态
}
if(count1==0)
{
Buzzer=~Buzzer;
}
}
/*
高度舵机
*/
if(Command==IR_USD) //如果遥控器VOL+按键按下
{
if(count1<180)
{
count1++; //Num自增
servo_control(1,count1);
LCD_ShowNum(1,11,count1,3); //显示舵机工作状态
}
if(count1==180)
{
Buzzer=~Buzzer;
}
}
/*
前后舵机
*/
if(Command==IR_2 ) //如果遥控器VOL-按键按下
{
if(count2>0)
{
count2--; //Num自减
servo_control(2,count2);
LCD_ShowNum(2,4,count2,3); //显示舵机工作状态
}
if(count2==0)
{
Buzzer=~Buzzer;
}
}
if(Command==IR_3) //如果遥控器VOL+按键按下
{
if(count2<180)
{
count2++; //Num自增
servo_control(2,count2);
LCD_ShowNum(2,4,count2,3); //显示舵机工作状态
}
if(count2==180)
{
Buzzer=~Buzzer;
}
}
/*
夹爪舵机
*/
if(Command==IR_5 ) //如果遥控器VOL-按键按下
{
if(count3>90)
{
count3--; //Num自减
servo_control(3,count3);
LCD_ShowNum(2,11,count3,3); //显示舵机工作状态
}
if(count3==90)
{
Buzzer=~Buzzer;
}
}
if(Command==IR_6) //如果遥控器VOL+按键按下
{
if(count3<180)
{
count3++; //Num自增
servo_control(3,count3);
LCD_ShowNum(2,11,count3,3); //显示舵机工作状态
}
if(count3==180)
{
Buzzer=~Buzzer;
}
}
}
}
CONTROL.H
#ifndef __CONTROL_H__
#define __CONTROL__
void control_process();
#endif
INIT.C
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "IR.h"
#include "SERVO.h"
#include "CONTROL.h"
extern unsigned char count0;
extern unsigned char count1;
extern unsigned char count2;
extern unsigned char count3;
void Init_system()
{
LCD_Init();
LCD_ShowString(1,1,"L1: L2: M4");
LCD_ShowString(2,1,"L3: L4: IR");
LCD_ShowNum(1,4,count0,3); //显示舵机工作状态
LCD_ShowNum(1,11,count1,3); //显示舵机工作状态
LCD_ShowNum(2,4,count2,3); //显示舵机工作状态
LCD_ShowNum(2,11,count3,3); //显示舵机工作状态
IR_Init();
init();
begin();
setPWMFreq(50);
/*
各舵机状态初始化
*/
servo_control(4,90);//底部舵机初始化0度
delayms(300);
servo_control(1,125);//高度调节舵机初始化
delayms(300);
servo_control(2,0);//前后舵机初始化
delayms(300);
servo_control(3,90);//抓取舵机初始化
delayms(300);
}
INIT.H
#ifndef __INIT_H__
#define __INIT_H__
void Init_system();
#endif