新手发帖求救
时间:10-02
整理:3721RD
点击:
用51单片机控制舵机转动超声波测距,然后用1602显示。结果是角度显示了,距离也显示了,就是舵机SG90不转动,没办法定位障碍位置,想了好几天,都还搞不好,求大神帮助 PS:我不是伸手党,已经查了好多资料,我是确实做不了,以下是我的程序,新手上路,不喜勿喷
*时间:
*备注:
**************************************************
==============================================================
LCD1602模拟口线接线方式
连接线图:
---------------------------------------------------
|LCM-----51 | LCM-----51 | LCM------51 |
--------------------------------------------------|
|DB0-----P0.0 | DB4-----P0.4 | RW-------P3.4 |
|DB1-----P0.1 | DB5-----P0.5 | RS-------P3.3 |
|DB2-----P0.2 | DB6-----P0.6 | E--------P3.5 |
|DB3-----P0.3 | DB7-----P0.7 | VLCD接1K电阻到GND|
---------------------------------------------------
接线:模块TRIG接 P1.1 ECH0 接P1.2 蜂鸣器报警 P2.2
=============================================================*/
#include <reg52.H> //器件配置文件
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
uchar anglecount ,jd =1 ;
sbit TX = P1^1; //#define TX P1_1 超声波引脚配置
sbit RX = P1^2; //#define RX P1_2
sbit pwm = P1^3;
sbit beep = P2^1;
sbit LCM_RS = P2^4 ; //定义LCD引脚
sbit LCM_RW = P2^5 ;
sbit LCM_E = P2^6 ;
#define LCM_Data P0
sbit jia = P3^6 ;//定义Keyboard引脚
sbit jian = P3^7 ;
#define Busy 0x80 //用于检测LCM状态字中的Busy标识
void LCMInit(void);
void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData);
void DisplayListChar(unsigned char X, unsigned char Y, unsigned char code *DData);
void Delay5Ms(void);
void Delay400Ms(void);
void Decode(unsigned char ScanCode);
void WriteDataLCM(unsigned char WDLCM);
void WriteCommandLCM(unsigned char WCLCM,BuysC);
//void T1_time0_init(void);
unsigned char ReadDataLCM(void);
unsigned char ReadStatusLCM(void);
unsigned char code system[] ={"Warning systems "};
unsigned char code designer[] = {"Designed by Li "};
unsigned char code Cls[] = {" "};
unsigned char code ASCII[15] ={'0','1','2','3','4','5','6','7','8','9','.','-','M','*'};
static unsigned char DisNum = 0; //显示用指针
unsigned int time=0;
unsigned long S=0;
bit flag =0;
unsigned char disbuff[4] ={ 0,0,0,0,};
unsigned char angbuff[4] ={ 0,0,0,0,};
/***********************************************************************************************/
/*****************************************LCD1602设置程序***************************************/
/***********************************************************************************************/
//写数据
void WriteDataLCM(unsigned char WDLCM)
{
ReadStatusLCM(); //检测忙
LCM_Data = WDLCM;
LCM_RS = 1;
LCM_RW = 0;
LCM_E = 0; //若晶振速度太高可以在这后加小的延时
LCM_E = 0; //延时
LCM_E = 1;
}
//写指令
void WriteCommandLCM(unsigned char WCLCM,BuysC) //BuysC为0时忽略忙检测
{
if (BuysC) ReadStatusLCM(); //根据需要检测忙
LCM_Data = WCLCM;
LCM_RS = 0;
LCM_RW = 0;
LCM_E = 0;
LCM_E = 0;
LCM_E = 1;
}
//读数据
unsigned char ReadDataLCM(void)
{
LCM_RS = 1;
LCM_RW = 1;
LCM_E = 0;
LCM_E = 0;
LCM_E = 1;
return(LCM_Data);
}
//读状态
unsigned char ReadStatusLCM(void)
{
LCM_Data = 0xFF;
LCM_RS = 0;
LCM_RW = 1;
LCM_E = 0;
LCM_E = 0;
LCM_E = 1;
while (LCM_Data & Busy); //检测忙信号
return(LCM_Data);
}
void LCMInit(void) //LCM初始化
{
LCM_Data = 0;
WriteCommandLCM(0x38,0); //三次显示模式设置,不检测忙信号
Delay5Ms();
WriteCommandLCM(0x38,0);
Delay5Ms();
WriteCommandLCM(0x38,0);
Delay5Ms();
WriteCommandLCM(0x38,1); //显示模式设置,开始要求每次检测忙信号
WriteCommandLCM(0x08,1); //关闭显示
WriteCommandLCM(0x01,1); //显示清屏
WriteCommandLCM(0x06,1); // 显示光标移动设置
WriteCommandLCM(0x0F,1); // 显示开及光标设置
}
//按指定位置显示一个字符
void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData)
{
Y &= 0x1;
X &= 0xF; //限制X不能大于15,Y不能大于1
if (Y) X |= 0x40; //当要显示第二行时地址码+0x40;
X |= 0x80; //算出指令码
WriteCommandLCM(X, 1); //发命令字
WriteDataLCM(DData); //发数据
}
//按指定位置显示一串字符
void DisplayListChar(unsigned char X, unsigned char Y, unsigned char code *DData)
{
unsigned char ListLength;
ListLength = 0;
Y &= 0x1;
X &= 0xF; //限制X不能大于15,Y不能大于1
while (DData[ListLength]>0x19) //若到达字串尾则退出
{
if (X <= 0xF) //X坐标应小于0xF
{
DisplayOneChar(X, Y, DData[ListLength]); //显示单个字符
ListLength++;
X++;
}
}
}
/****************************************************************************************/
/**************************************延时程序***************************************/
/******************************************************************************************/
//5ms延时
void Delay5Ms(void)
{
unsigned int TempCyc = 5552;
while(TempCyc--);
}
//400ms延时
void Delay400Ms(void)
{
unsigned char TempCycA = 5;
unsigned int TempCycB;
while(TempCycA--)
{
TempCycB=7269;
while(TempCycB--);
};
}
void delay(uchar x)
{
uchar i,j;
for(i=x;i>0;i--)
for(j=125;j>0;j--);
}
void delayms(unsigned int ms)
{
unsigned char i=100,j;
for(;ms;ms--)
{
while(--i)
{
j=10;
while(--j);
}
}
}
/******************************************************************************************/
/********************************超声波距离显示*******************************************/
/*********************************************************************************************/
void Conut(void)
{
time=TH0*256+TL0;
TH0=0;
TL0=0;
S=(time*17)/1000; //算出来是M
if((S>=700)||flag==1) //超出测量范围显示“-”
{
flag=0;
DisplayOneChar(0, 1, ASCII[11]);
DisplayOneChar(1, 1, ASCII[10]); //显示点
DisplayOneChar(2, 1, ASCII[11]);
DisplayOneChar(3, 1, ASCII[11]);
DisplayOneChar(4, 1, ASCII[12]); //显示M
}
else
{
disbuff[0]=S%1000/100;
disbuff[1]=S%1000%100/10;
disbuff[2]=S%1000%10 %10;
DisplayOneChar(0, 1, ASCII[disbuff[0]]);
DisplayOneChar(1, 1, ASCII[10]); //显示点
DisplayOneChar(2, 1, ASCII[disbuff[1]]);
DisplayOneChar(3, 1, ASCII[disbuff[2]]);
DisplayOneChar( 4, 1, ASCII[12]); //显示M
DisplayOneChar(11, 1, ASCII[13]); //显示角度*
}
}
/***********************************************************************************************************/
/***********************************************角度按键控制扫描*********************************/
/************************************************************************************************************/
void keyscan()
{
if(jia==0)
{
delay(15); //消抖
if(jia==0)
{
jd++; //角度增加 1
anglecount=0; //按键按下则20ms周期重新开始计时
if(jd==6)
jd=5; //已经是180度,保持
while(jia==0);
}
}
if(jian==0)
{
delay(15); //消抖
if(jian==0)
{
jd--;
anglecount=0;
if(jd==0)
jd=1; //已经0度,保持
while(jian==0);
}
}
}
/*******************************************************************************************************/
/***********************************************角度显示函数************************************************/
/*********************************************************************************************************/
void display()
{
uchar bai ,shi,ge ;
switch(jd)
{
case 1:
bai=0;
shi=0;
ge=0;
break;
case 2:
bai=0;
shi=4;
ge=5;
break;
case 3:
bai=0;
shi=9;
ge=0;
break;
case 4:
bai=1;
shi=3;
ge=5;
break;
case 5:
bai=1;
shi=8;
ge=0;
break;
}
angbuff[0] = bai;
angbuff[1] = shi;
angbuff[2] = ge;
delay(5);
DisplayOneChar(8, 1, ASCII[angbuff[0]]); //bai
DisplayOneChar(9, 1, ASCII[angbuff[1]]); //shi
DisplayOneChar(10,1, ASCII[angbuff[2]]); //ge
}
/********************************************************/
void T0_time() interrupt 1 //T0中断用来计数器溢出,超过测距范围
{
flag=1; //中断溢出标志
}
/********************************************************/
/*void T1_time0_init()
{
TMOD=0x11; //定时器1工作方式1
IE=0x82;
TH0=0xfe;
TL0=0x33; //11.0592MHZ晶振,0.5ms
TR0=1;
}
*/
/*******************************************定时器1中断程序(角度控制)*************************/
void T1_time() interrupt 3
{ uchar anglecount ;
TH1=0xfe;
TL1=0x33;
if(anglecount<jd) //判断0.5ms次数是否小于角度标识
pwm=1; //是,pwm输出高电平
else
pwm=0; //否,输出低电平
anglecount=anglecount+1;
anglecount=anglecount%40; //次数始终保持为40,即保持周期为20ms
}
/*****************************************************************************************/
/*******************************超声波发射函数*************************/
/*********************************************************************************************/
void StartModule() //启动模块函数
{
TX=1; //启动一次模块
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
TX=0;
}
/*******************************报警函数****************************
void warning()
{
beep = 0 ;
if(S<=20)
{
beep = 1 ;
}
else
{
beep = 0 ;
}
}
/**********************************************************************************************/
/**********************************************************************************************/
/******************************************主函数***************************************************/
void main(void)
{
unsigned char TempCyc;
Delay400Ms(); //启动等待,等LCM讲入工作状态
LCMInit(); //LCM初始化
// beep = 0 ;
Delay5Ms(); //延时片刻(可不要)
DisplayListChar(0, 0, system);
DisplayListChar(0, 1, designer);
ReadDataLCM(); //测试用句无意义
for (TempCyc=0; TempCyc<10; TempCyc++)
Delay400Ms(); //延时
DisplayListChar(0, 1, Cls);
TMOD=0x11; //设T0,T1为方式1,GATE=1;
TH0=0;
TL0=0;
TH1=0xfe;
TL1=0x33; //11.0592MHZ晶振,0.5ms
IE = 0x09; //允许T0,T1中断
EA=1 ; //开启总中断
TR1=1;
anglecount=0;
while(1)
{
StartModule(); //启动模块
DisplayOneChar(4, 1, ASCII[12]); //距离显示
while(!RX); //当RX为零时等待
TR0=1; //开启计数
while(RX); //当RX为1计数并等待
TR0=0; //关闭计数
Conut(); //距离计算
delayms(20); //80MS延时
TR1=1;
keyscan();
// TR1=0;
// delayms(80);
display();
}
}
*时间:
*备注:
**************************************************
==============================================================
LCD1602模拟口线接线方式
连接线图:
---------------------------------------------------
|LCM-----51 | LCM-----51 | LCM------51 |
--------------------------------------------------|
|DB0-----P0.0 | DB4-----P0.4 | RW-------P3.4 |
|DB1-----P0.1 | DB5-----P0.5 | RS-------P3.3 |
|DB2-----P0.2 | DB6-----P0.6 | E--------P3.5 |
|DB3-----P0.3 | DB7-----P0.7 | VLCD接1K电阻到GND|
---------------------------------------------------
接线:模块TRIG接 P1.1 ECH0 接P1.2 蜂鸣器报警 P2.2
=============================================================*/
#include <reg52.H> //器件配置文件
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
uchar anglecount ,jd =1 ;
sbit TX = P1^1; //#define TX P1_1 超声波引脚配置
sbit RX = P1^2; //#define RX P1_2
sbit pwm = P1^3;
sbit beep = P2^1;
sbit LCM_RS = P2^4 ; //定义LCD引脚
sbit LCM_RW = P2^5 ;
sbit LCM_E = P2^6 ;
#define LCM_Data P0
sbit jia = P3^6 ;//定义Keyboard引脚
sbit jian = P3^7 ;
#define Busy 0x80 //用于检测LCM状态字中的Busy标识
void LCMInit(void);
void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData);
void DisplayListChar(unsigned char X, unsigned char Y, unsigned char code *DData);
void Delay5Ms(void);
void Delay400Ms(void);
void Decode(unsigned char ScanCode);
void WriteDataLCM(unsigned char WDLCM);
void WriteCommandLCM(unsigned char WCLCM,BuysC);
//void T1_time0_init(void);
unsigned char ReadDataLCM(void);
unsigned char ReadStatusLCM(void);
unsigned char code system[] ={"Warning systems "};
unsigned char code designer[] = {"Designed by Li "};
unsigned char code Cls[] = {" "};
unsigned char code ASCII[15] ={'0','1','2','3','4','5','6','7','8','9','.','-','M','*'};
static unsigned char DisNum = 0; //显示用指针
unsigned int time=0;
unsigned long S=0;
bit flag =0;
unsigned char disbuff[4] ={ 0,0,0,0,};
unsigned char angbuff[4] ={ 0,0,0,0,};
/***********************************************************************************************/
/*****************************************LCD1602设置程序***************************************/
/***********************************************************************************************/
//写数据
void WriteDataLCM(unsigned char WDLCM)
{
ReadStatusLCM(); //检测忙
LCM_Data = WDLCM;
LCM_RS = 1;
LCM_RW = 0;
LCM_E = 0; //若晶振速度太高可以在这后加小的延时
LCM_E = 0; //延时
LCM_E = 1;
}
//写指令
void WriteCommandLCM(unsigned char WCLCM,BuysC) //BuysC为0时忽略忙检测
{
if (BuysC) ReadStatusLCM(); //根据需要检测忙
LCM_Data = WCLCM;
LCM_RS = 0;
LCM_RW = 0;
LCM_E = 0;
LCM_E = 0;
LCM_E = 1;
}
//读数据
unsigned char ReadDataLCM(void)
{
LCM_RS = 1;
LCM_RW = 1;
LCM_E = 0;
LCM_E = 0;
LCM_E = 1;
return(LCM_Data);
}
//读状态
unsigned char ReadStatusLCM(void)
{
LCM_Data = 0xFF;
LCM_RS = 0;
LCM_RW = 1;
LCM_E = 0;
LCM_E = 0;
LCM_E = 1;
while (LCM_Data & Busy); //检测忙信号
return(LCM_Data);
}
void LCMInit(void) //LCM初始化
{
LCM_Data = 0;
WriteCommandLCM(0x38,0); //三次显示模式设置,不检测忙信号
Delay5Ms();
WriteCommandLCM(0x38,0);
Delay5Ms();
WriteCommandLCM(0x38,0);
Delay5Ms();
WriteCommandLCM(0x38,1); //显示模式设置,开始要求每次检测忙信号
WriteCommandLCM(0x08,1); //关闭显示
WriteCommandLCM(0x01,1); //显示清屏
WriteCommandLCM(0x06,1); // 显示光标移动设置
WriteCommandLCM(0x0F,1); // 显示开及光标设置
}
//按指定位置显示一个字符
void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData)
{
Y &= 0x1;
X &= 0xF; //限制X不能大于15,Y不能大于1
if (Y) X |= 0x40; //当要显示第二行时地址码+0x40;
X |= 0x80; //算出指令码
WriteCommandLCM(X, 1); //发命令字
WriteDataLCM(DData); //发数据
}
//按指定位置显示一串字符
void DisplayListChar(unsigned char X, unsigned char Y, unsigned char code *DData)
{
unsigned char ListLength;
ListLength = 0;
Y &= 0x1;
X &= 0xF; //限制X不能大于15,Y不能大于1
while (DData[ListLength]>0x19) //若到达字串尾则退出
{
if (X <= 0xF) //X坐标应小于0xF
{
DisplayOneChar(X, Y, DData[ListLength]); //显示单个字符
ListLength++;
X++;
}
}
}
/****************************************************************************************/
/**************************************延时程序***************************************/
/******************************************************************************************/
//5ms延时
void Delay5Ms(void)
{
unsigned int TempCyc = 5552;
while(TempCyc--);
}
//400ms延时
void Delay400Ms(void)
{
unsigned char TempCycA = 5;
unsigned int TempCycB;
while(TempCycA--)
{
TempCycB=7269;
while(TempCycB--);
};
}
void delay(uchar x)
{
uchar i,j;
for(i=x;i>0;i--)
for(j=125;j>0;j--);
}
void delayms(unsigned int ms)
{
unsigned char i=100,j;
for(;ms;ms--)
{
while(--i)
{
j=10;
while(--j);
}
}
}
/******************************************************************************************/
/********************************超声波距离显示*******************************************/
/*********************************************************************************************/
void Conut(void)
{
time=TH0*256+TL0;
TH0=0;
TL0=0;
S=(time*17)/1000; //算出来是M
if((S>=700)||flag==1) //超出测量范围显示“-”
{
flag=0;
DisplayOneChar(0, 1, ASCII[11]);
DisplayOneChar(1, 1, ASCII[10]); //显示点
DisplayOneChar(2, 1, ASCII[11]);
DisplayOneChar(3, 1, ASCII[11]);
DisplayOneChar(4, 1, ASCII[12]); //显示M
}
else
{
disbuff[0]=S%1000/100;
disbuff[1]=S%1000%100/10;
disbuff[2]=S%1000%10 %10;
DisplayOneChar(0, 1, ASCII[disbuff[0]]);
DisplayOneChar(1, 1, ASCII[10]); //显示点
DisplayOneChar(2, 1, ASCII[disbuff[1]]);
DisplayOneChar(3, 1, ASCII[disbuff[2]]);
DisplayOneChar( 4, 1, ASCII[12]); //显示M
DisplayOneChar(11, 1, ASCII[13]); //显示角度*
}
}
/***********************************************************************************************************/
/***********************************************角度按键控制扫描*********************************/
/************************************************************************************************************/
void keyscan()
{
if(jia==0)
{
delay(15); //消抖
if(jia==0)
{
jd++; //角度增加 1
anglecount=0; //按键按下则20ms周期重新开始计时
if(jd==6)
jd=5; //已经是180度,保持
while(jia==0);
}
}
if(jian==0)
{
delay(15); //消抖
if(jian==0)
{
jd--;
anglecount=0;
if(jd==0)
jd=1; //已经0度,保持
while(jian==0);
}
}
}
/*******************************************************************************************************/
/***********************************************角度显示函数************************************************/
/*********************************************************************************************************/
void display()
{
uchar bai ,shi,ge ;
switch(jd)
{
case 1:
bai=0;
shi=0;
ge=0;
break;
case 2:
bai=0;
shi=4;
ge=5;
break;
case 3:
bai=0;
shi=9;
ge=0;
break;
case 4:
bai=1;
shi=3;
ge=5;
break;
case 5:
bai=1;
shi=8;
ge=0;
break;
}
angbuff[0] = bai;
angbuff[1] = shi;
angbuff[2] = ge;
delay(5);
DisplayOneChar(8, 1, ASCII[angbuff[0]]); //bai
DisplayOneChar(9, 1, ASCII[angbuff[1]]); //shi
DisplayOneChar(10,1, ASCII[angbuff[2]]); //ge
}
/********************************************************/
void T0_time() interrupt 1 //T0中断用来计数器溢出,超过测距范围
{
flag=1; //中断溢出标志
}
/********************************************************/
/*void T1_time0_init()
{
TMOD=0x11; //定时器1工作方式1
IE=0x82;
TH0=0xfe;
TL0=0x33; //11.0592MHZ晶振,0.5ms
TR0=1;
}
*/
/*******************************************定时器1中断程序(角度控制)*************************/
void T1_time() interrupt 3
{ uchar anglecount ;
TH1=0xfe;
TL1=0x33;
if(anglecount<jd) //判断0.5ms次数是否小于角度标识
pwm=1; //是,pwm输出高电平
else
pwm=0; //否,输出低电平
anglecount=anglecount+1;
anglecount=anglecount%40; //次数始终保持为40,即保持周期为20ms
}
/*****************************************************************************************/
/*******************************超声波发射函数*************************/
/*********************************************************************************************/
void StartModule() //启动模块函数
{
TX=1; //启动一次模块
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
TX=0;
}
/*******************************报警函数****************************
void warning()
{
beep = 0 ;
if(S<=20)
{
beep = 1 ;
}
else
{
beep = 0 ;
}
}
/**********************************************************************************************/
/**********************************************************************************************/
/******************************************主函数***************************************************/
void main(void)
{
unsigned char TempCyc;
Delay400Ms(); //启动等待,等LCM讲入工作状态
LCMInit(); //LCM初始化
// beep = 0 ;
Delay5Ms(); //延时片刻(可不要)
DisplayListChar(0, 0, system);
DisplayListChar(0, 1, designer);
ReadDataLCM(); //测试用句无意义
for (TempCyc=0; TempCyc<10; TempCyc++)
Delay400Ms(); //延时
DisplayListChar(0, 1, Cls);
TMOD=0x11; //设T0,T1为方式1,GATE=1;
TH0=0;
TL0=0;
TH1=0xfe;
TL1=0x33; //11.0592MHZ晶振,0.5ms
IE = 0x09; //允许T0,T1中断
EA=1 ; //开启总中断
TR1=1;
anglecount=0;
while(1)
{
StartModule(); //启动模块
DisplayOneChar(4, 1, ASCII[12]); //距离显示
while(!RX); //当RX为零时等待
TR0=1; //开启计数
while(RX); //当RX为1计数并等待
TR0=0; //关闭计数
Conut(); //距离计算
delayms(20); //80MS延时
TR1=1;
keyscan();
// TR1=0;
// delayms(80);
display();
}
}
好长的代码!