1602+电机控制+51单片机C编程+proteus仿真
/********************************************************************
* 文件名 : 液晶1602显示.c
* 描述 : 该程序实现了对液晶1602,电机 继电器的控制。
***********************************************************************/
#include<reg52.h>
#include <intrins.h>
#include <absacc.h>
#define uchar unsigned char
#define uint unsigned int
#define busy 0x80
#define lucheng 450
///*************************测速测距************************///////////
unsigned int SpeedDet_h,SpeedDet_v,flag,luchengstop_h=1,luchengstop_v=1; //高电平脉冲的个数
uchar count=0,j=0,Speed_second1=1,Speed_second2=1;
float Speed_h=0,Speed_v=0;
unsigned long distance_h=0,distance_v=0;
unsigned int V_lucheng[]={480,400,320,240,160,80,80,160,240,320,400,480}; //电机每次升降的高度表
//这三个引脚参考资料
sbit E=P2^7; //1602使能引脚
sbit RW=P2^6; //1602读写引脚
sbit RS=P2^5; //1602数据/命令选择引脚
sbit key_hz=P2^1;//定义按键位置 水平电机正转
sbit key_hf=P2^2;//定义按键位置 水平电机反转
sbit key_hstop=P2^3;//定义按键位置 水平电机停
sbit key_vz=P2^4;//定义按键位置 垂直电机正转
sbit key_vf=P3^0;//定义按键位置 垂直电机正转
sbit key_vstop=P3^1;//定义按键位置 垂直电机正转
sbit key_sz=P3^6;//定义按键位置 机械手电机正转
sbit key_sf=P3^7;//定义按键位置 机械手电机正转
sbit key_sstop=P1^7;//定义按键位置 机械手电机正转
sbit RELAY_HZ = P1^1;
sbit RELAY_HF = P1^2;
sbit RELAY_VZ = P1^3;
sbit RELAY_VF = P1^4;
sbit RELAY_SZ = P1^5;
sbit RELAY_SF = P1^6;
/********************************************************************
* 名称 : delay()
* 功能 : 延时,延时时间大概为140US。
* 输入 : 无
* 输出 : 无
***********************************************************************/
void delay(uchar k)
{
uint i,j;
for(i =0;i<k;i++)
for(j = 0;j<60;j++);
}
void DelayMs(uchar aa) //延时1ms
{
uchar i,j;
for(i=aa;i>0;i--)
for(j=110;j>0;j--);
}
void Speed_init()
{
TMOD=0x66; //计数器T0在模式2下工作 定时器T1在模式1下工作
TL0=0; //计数器T0计数初值
TH0=0;
TL1=0; //计数器T0计数初值
TH1=0;
TR0=1; //T0计数器开始计数
TR1=1; //T1定时器开始定时
ET0=0;
ET1=1; //定时器T1允许中断
RCAP2H=0xDB; //定时10ms常数
RCAP2L=0xF0;
TH2=RCAP2H; //定时器2赋初值
TL2=RCAP2L;
ET2=1; //开外定时器2中断
TR2=1; //启动定时器2
EA=1; //使能总中断
}
void test_1602busy() //读状态,输出状态字,检测LCD状态字DB7是否为1即忙,为1则LCD禁止
{
P0 = 0xFF;
E = 1;
RS = 0;
RW = 1;
_nop_();
_nop_();
while(P0&busy)
{
E = 0;
_nop_();
E = 1;
_nop_();
}
E = 0;
}
void write_1602Command(uchar co) //写命令,写状态字
{
test_1602busy(); //检测LCD是不是忙
RS = 0;
RW = 0;
E = 0;
_nop_();
P0 = co;
_nop_();
E = 1; // LCD使能,高电平有效
_nop_();
E = 0;
}
void write_1602Data(uchar Data) //写LCD数据函数
{
test_1602busy();
P0 = Data;
RS = 1;
RW = 0;
E = 1;
_nop_();
E = 0;
}
void initial_1602() //初始化函数
{
write_1602Command(0x38); //LCD功能设定,DL=1(8位)N=1(2行显示)
delay(5);
write_1602Command(0x01); //清除LCD的屏幕
delay(5);
write_1602Command(0x06); //LCD的模式设定,I/D=1(计数地址加1)
delay(5);
write_1602Command(0x0F); //显示屏幕
delay(5);
write_1602Command(0x0C); //消除光标
}
void displayonechar(uchar x,y,ddata) //在LCD上显示一个字符
{
uchar a;
if(y == 0) a = 0x80;
if(y == 1) a = 0xc0;
a = a + x - 1;
write_1602Command(a);
write_1602Data(ddata);
}
void display_1602(uchar *ddata,x,y) //在LCD上显示一行字符
{
uchar a;
if(y == 0) a = 0x80;
if(y == 1) a = 0xc0;
a = a + x - 1;
write_1602Command(a);
while(1)
{
if(*ddata == '\0') break;
write_1602Data(*ddata);
ddata++;
}
}
/**********************************************************
*转换显示子程序
**********************************************************/
void display(float Speed1,Speed2,unsigned long distance1,distance2)
{
uchar temp1[10]; //存放分解的数据
//************************速度显示**************//
Speed_second1=(unsigned char)(Speed1); //存放分解的数据
temp1[0] = (Speed_second1%100)/10+0x30; //取十位转换为ASCII 码
temp1[1] = (Speed_second1%100)%10+0x30; //取个位转换为ASCII 码
Speed_second2=(unsigned char)(Speed2); //存放分解的数据
temp1[5] = (Speed_second2%100)/10+0x30; //取十位转换为ASCII 码
temp1[6] = (Speed_second2%100)%10+0x30; //取个位转换为ASCII 码
displayonechar(5,0,temp1[0]); //十位
displayonechar(6,0,temp1[1]); //个位
displayonechar(5,1,temp1[5]); //十位
displayonechar(6,1,temp1[6]); //个位
//****************************总路程显示****************************//
temp1[2] = distance1/100+0x30; //取百位转换为ASCII 码
temp1[3] = (distance1%100)/10+0x30; //取十位转换为ASCII 码
temp1[4] = (distance1%100)%10+0x30; //取个位转换为ASCII 码
temp1[7] = distance2/100+0x30; //取百位转换为ASCII 码
temp1[8] = (distance2%100)/10+0x30; //取十位转换为ASCII 码
temp1[9] = (distance2%100)%10+0x30; //取个位转换为ASCII 码
if(temp1[2]==0x30)
displayonechar(13,0,'0'); //如果百位为0,显示0
else
{displayonechar(13,0,temp1[2]); } //否则正常显示百位
displayonechar(14,0,temp1[3]); //十位
displayonechar(15,0,temp1[4]); //个位 //个位
if(temp1[7]==0x30)
displayonechar(13,1,'0'); //如果百位为0,显示0
else
{displayonechar(13,1,temp1[7]); } //否则正常显示百位
displayonechar(14,1,temp1[8]); //十位
displayonechar(15,1,temp1[9]); //个位 //个位
}
void h_motorcontroler()
{
if(!luchengstop_h) //路程到时,电机停下,只等正键按下
{
RELAY_HF=1;
DelayMs(10);
RELAY_HZ=1;
if(! key_hz ) //按下相应的按键 水平电机正转
{
DelayMs(10);
if(! key_hz ) //去抖后是否按下相应的按键
{
luchengstop_h=1;
RELAY_HF=1;
DelayMs(10);
RELAY_HZ=0;
}
}
}
else if(! key_hz ) //按下相应的按键 水平电机正转
{
DelayMs(10);
if(! key_hz ) //去抖后是否按下相应的按键
{
RELAY_HF=1;
DelayMs(10);
RELAY_HZ=0;
}
}
else if(! key_hstop ) //按下相应的按键 水平电机停
{
DelayMs(10);
if(! key_hstop) //去抖后是否按下相应的按键
{
RELAY_HF=1;
DelayMs(10);
RELAY_HZ=1;
}
}
if(!luchengstop_h) //路程到时,电机停下,只等反键按下
{
RELAY_HF=1;
DelayMs(10);
RELAY_HZ=1;
if(! key_hf ) //按下相应的按键 水平电机反转
{
DelayMs(10);
if(! key_hf) //去抖后是否按下相应的按键
{
luchengstop_h=1;
RELAY_HZ=1;
DelayMs(10);
RELAY_HF=0;
}
}
}
else if(! key_hf ) //按下相应的按键 水平电机反转
{
DelayMs(10);
if(! key_hf) //去抖后是否按下相应的按键
{
RELAY_HZ=1;
DelayMs(10);
RELAY_HF=0;
}
}
else if(! key_hstop ) //按下相应的按键 水平电机停
{
DelayMs(10);
if(! key_hstop) //去抖后是否按下相应的按键
{
RELAY_HF=1;
DelayMs(10);
RELAY_HZ=1;
}
}
}
void v_motorcontroler()
{
if(!luchengstop_v) //路程到时,电机停下,只等正键按下
{
RELAY_VF=1;
DelayMs(10);
RELAY_VZ=1;
if(! key_vz ) //按下相应的按键 水平电机正转
{
DelayMs(10);
if(! key_vz ) //去抖后是否按下相应的按键
{
j++; //改变电机每次升降的高度
luchengstop_v=1;
RELAY_VF=1;
DelayMs(10);
RELAY_VZ=0;
}
}
}
else if(! key_vz ) //按下相应的按键 水平电机正转
{
DelayMs(10);
if(! key_vz ) //去抖后是否按下相应的按键
{
RELAY_VF=1;
DelayMs(10);
RELAY_VZ=0;
}
}
else if(! key_vstop ) //按下相应的按键 水平电机停
{
DelayMs(10);
if(! key_vstop) //去抖后是否按下相应的按键
{
RELAY_VF=1;
DelayMs(10);
RELAY_VZ=1;
}
}
if(!luchengstop_v) //路程到时,电机停下,只等反键按下
{
RELAY_VF=1;
DelayMs(10);
RELAY_VZ=1;
if(! key_vf ) //按下相应的按键 水平电机反转
{
DelayMs(10);
if(! key_vf) //去抖后是否按下相应的按键
{
j++; //改变电机每次升降的高度
luchengstop_v=1;
RELAY_VZ=1;
DelayMs(10);
RELAY_VF=0;
}
}
}
else if(! key_vf ) //按下相应的按键 水平电机反转
{
DelayMs(10);
if(! key_vf) //去抖后是否按下相应的按键
{
RELAY_VZ=1;
DelayMs(10);
RELAY_VF=0;
}
}
else if(! key_vstop ) //按下相应的按键 水平电机停
{
DelayMs(10);
if(! key_vstop) //去抖后是否按下相应的按键
{
RELAY_VF=1;
DelayMs(10);
RELAY_VZ=1;
}
}
}
void jixieshuo_motorcontroler()
{
if(! key_sz ) //按下相应的按键 水平电机正转
{
DelayMs(10);
if(! key_sz ) //去抖后是否按下相应的按键
{
RELAY_SF=1;
DelayMs(10);
RELAY_SZ=0;
}
}
else if(! key_sstop ) //按下相应的按键 水平电机停
{
DelayMs(10);
if(! key_sstop) //去抖后是否按下相应的按键
{
RELAY_SF=1;
DelayMs(10);
RELAY_SZ=1;
}
}
if(! key_sf ) //按下相应的按键 水平电机反转
{
DelayMs(10);
if(! key_sf) //去抖后是否按下相应的按键
{
RELAY_SZ=1;
DelayMs(10);
RELAY_SF=0;
}
}
else if(! key_sstop ) //按下相应的按键 水平电机停
{
DelayMs(10);
if(! key_sstop) //去抖后是否按下相应的按键
{
RELAY_SF=1;
DelayMs(10);
RELAY_SZ=1;
}
}
}
/********************************************************************
* 名称 : Main()
* 功能 : 主函数
* 输入 : 无
* 输出 : 无
***********************************************************************/
void Main()
{
RELAY_HZ = 0;
RELAY_HF = 0;
RELAY_VZ = 0;
RELAY_VF = 0;
RELAY_SZ = 0;
RELAY_SF = 0;
initial_1602();
Speed_init();
display_1602("sph:",1,0); //显示基本的字符
display_1602("dish:",8,0);
display_1602("spv:",1,1); //显示基本的字符
display_1602("disv:",8,1);
display(Speed_h,Speed_v,distance_h,distance_v);
while(1)
{
// display_1602("sph:",1,0); //显示基本的字符
// display_1602("dish:",8,0);
// display_1602("spv:",1,1); //显示基本的字符
// display_1602("disv:",8,1);
v_motorcontroler();
h_motorcontroler();
jixieshuo_motorcontroler();
display(Speed_h,Speed_v,distance_h,distance_v);
}
}
//**************************测速模块******************************//
//**************************测速模块******************************//
//***************************************************************************//
// (2)T2的中断标志位不能硬件自动清零,必须在中断服务程序软件清零,
// 为了定时的准确,在进入中断服务程序后第一步就使TF2=0 ;
// (3)T2工作在16位自动重装模式下,不需要在中断服务程序重新赋值,硬件会自动使TH2=RCAP2H,TL2=RCAP2L;
void timer2() interrupt 5 //定时器1中断子程序
{
TF2=0; //注意 T2的溢出标志位必须软件清零,硬件不能清零,这与T0和T1不同!!
count++;
if(count==10)
{
TR0=0; //T0停止计数
SpeedDet_h=TL0; //读取计数值
TL0=0; //重装TL0=0
TH0=0;
TR0=1; //T0开始计数
TR1=0; //T0停止计数
SpeedDet_v=TL1; //读取计数值
TL1=0; //重装TL0=0
TH1=0;
TR1=1; //T0开始计数
Speed_h= (SpeedDet_h)*20.7345/20*10; //轮子的周长
distance_h=distance_h+Speed_h/10;
Speed_v= (SpeedDet_v)*20.7345/20*10; //轮子的周长
distance_v=distance_v+Speed_v/10;
count=0;
}
if(distance_h>=lucheng)
{
distance_h= 0;
luchengstop_h=0;
}
if(distance_v>=V_lucheng[j])
{
if(j<12)
{
distance_v= 0;
luchengstop_v=0;
}
else
j = 0;
}
}
自强不息~