Robotic arm control system based on 51 microcontroller

1 Modules used in the control system

The modules used are: pca9685 control multi-channel servo module; matrix button module; LCD1702 display module; DS18B20 temperature detection module; independent button module; stepper motor; ULN2003 stepper motor control module, DS1302 clock module.

2 Functions of controlling system working mode

After powering on, the LCD1602 display is initialized, the temperature measurement is initialized, the timer is initialized, the current temperature is measured, and the characters that need to be displayed are displayed;

Working mode one: Displays the current year, month, day, hour, minute and second, displays the stepper motor switch status, and shows which working mode it is in. In this interface, the time can be adjusted through the matrix button module and the stepper motor switch can be controlled.

Working mode two: Display the password lock interface and display the value entered by the button. In this interface, the entered value can be controlled through the matrix buttons. If the password is entered correctly, it will jump to working mode three, otherwise it will return to working mode one.

Working mode three: Display the working status of each servo. In this interface, you can control the work of the servo through independent buttons and matrix buttons; press the designated button to return to working mode one.

Working mode four: In this working mode, the robotic arm is controlled by the infrared remote control, and LCD1602 displays the status of the steering gear.

3Protocols and basic knowledge used in control systems

Single-wire protocol used in DS18B20 control, SPI protocol used in real-time clock DS1302; IIC protocol used in controlling servos, matrix keyboard state machine writing method; stepper motor motion control LCD1602 display, timer interrupt configuration, NEC protocol, rudder PWM control in machine control, etc.

4Control system process

 

5 Main ideas of control system

LCD1602 is responsible for display and the buttons are responsible for control.

The most important thing is: the pca9685 module controls the servo. The specific control details of the servo are detailed in this blog [SG90 Analog Servo Control and Use of PCA9685 Module].

Multiple servos can be controlled through pca9685, which saves IO ports.

6Control system code

main function

#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 display function

#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 display function header file

#ifndef __DSIPLAY_H
#define __DISPLAY_H

void flag();
void display_mode1();
void display_mode2();
void display_mode3();
void display_process();

#endif

LCD1602 driver function

#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 driver function header file

#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

Matrix key control function

#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();
					}
					
			}
}

Matrix button control function header file

#ifndef __KEY_H
#define __KEY_H


unsigned char keyscan();
void key_process();
void engine_key();

#endif

System initialization function

#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);
}

System initialization function header file

#ifndef __INIT_SYSTEM_H
#define __INIT_SYSTEM_H


void Init_process();

#endif

DS18B20 underlying driver function

#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 driver function header file

#ifndef __DS18B20_H__
#define __DS18B20_H__

void DS18B20_ConvertT(void);
float DS18B20_ReadT(void);

#endif

DS1302 driver function

#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 driver header file

#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

Timer configuration function

#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;
}

Timer configuration header file

#ifndef __INTERRUPT_H
#define __INTERRUPT_H

void Timer0Init();		//1毫秒@11.0592MHz
void Timer1Init();

#endif

Stepper motor driver file

#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);
			}
	   
}

Stepper motor driver header file

#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 servo function

#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 servo function header file

#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

The following is an infrared remote control robotic arm

main function

#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

Guess you like

Origin blog.csdn.net/qq_61134394/article/details/126199093