#include"intrins.h"
#define uchar unsigned char//无符号8位
#define uint unsigned int//无符号16位
#define ulong unsigned long//无符号32位
sbit K1=P1^0 //按下K1后,开始测距
sbit LEDRed=P1^1//测距指示灯,亮表示正在测距,灭表示测距完成
//sbit BEEP=P1^2 //报警测量超出范围
sbit Trig=P2^5 //HC-SR04触发信号输入
sbit Echo=P2^6 //HC-SR04回响信号输出
float xdata DistanceValue=0.0//测量的距离值
float xdata SPEEDSOUND //声速
float xdata XTALTIME //单片机计数周期
uchar xdata stringBuf[6] //数值转字符串缓冲
//LCD1602提示信息
uchar code Prompts[][16]=
{
{"Measure Distance"}, //测量距离
{"- Out of Range -"}, //超出测量范围
{"MAX range 400cm "}, //测距最大值400cm
{"MIN range 2cm "}, //测距最小值2cm
{""}, //清屏
{" Press K1 Start "} //按键开始测量
}
uchar xdata DistanceText[]="Range: " //行亩测量结果字符串
uchar xdata TemperatureText[]="Temperature:"//测量温度值
extern void LCD_Initialize() //LCD初始化
extern void LCD_Display_String(uchar *, uchar)//字符串显示
extern void ReadTemperatureFromDS18B20() //从DS18B20读取温度值
extern int xdata CurTempInteger
//毫秒延时函数
void DelayMS(uint ms)
//20微秒延时函数
void Delay20us()
//HCSR04初始化
void HCSR04_Initialize()
//测量距亏差离
float MeasuringDistance()
//测距的数值排序求平均
float DistanceStatistics()
//输出距离值到LCD1602上
void DisplayDistanceValue(float dat)
//将无符号的整数转成字符串,返回字符串长度,不包括'\0'结束符
uchar UnsigedIntToString(uint value)
//蜂鸣器
//void Beep(uchar time)
//显示温度值
void DisplayTemperatureValue()
void main()
{
LCD_Initialize()//LCD1602初始化
LCD_Display_String(Prompts[0],0x00)
LCD_Display_String(Prompts[5],0x40)
ReadTemperatureFromDS18B20() //测温度
HCSR04_Initialize()//HC-SR04初始化
while(1)
{
if(K1==0)
{
DelayMS(5)
if(K1==0)
{
//Beep(1)
while(K1==0)
LEDRed=0
ReadTemperatureFromDS18B20()/销带皮/测温度
DisplayTemperatureValue()
if(CurTempInteger<14)
CurTempInteger=14
else if(CurTempInteger>26)
CurTempInteger=26
SPEEDSOUND=334.1+CurTempInteger*0.61//计算声速
DistanceValue=DistanceStatistics() //测距并返回距离值
DisplayDistanceValue(DistanceValue)//显示距离值
LEDRed=1
}
}
}
}
//测距的数值排序求平均
float DistanceStatistics()
{
uchar i,j
float disData[7],t
//连续测距
for(i=0i<7i++)
{
disData=MeasuringDistance()
DelayMS(80)
}
//排序
for(j=0j<=6j++)
{
for(i=0i<7-ji++)
{
if(disData>disData[i+1])
{
t=disData
disData=disData[i+1]
disData[i+1]=t
}
}
}
return (disData[2]+disData[3]+disData[4])/3
}
//测量距离
float MeasuringDistance()
{
//最大定时时间约65ms
TH0=0
TL0=0
//生成20us的脉冲宽度的触发信号
Trig=1
Delay20us()
Trig=0
//等待回响信号变高电平
while(!Echo)
TR0=1 //启动定时器0
//等待回响信号变低电平
while(Echo)
TR0=0 //关闭定时器0
//返回距离值(mm)
return (SPEEDSOUND*XTALTIME*((float)TH0*256+(float)TL0))/2000
}
//HCSR04初始化
void HCSR04_Initialize()
{
//计算单片机计数周期 晶振=11.953M 单位us
XTALTIME=12/11.953
//温度25度时声速的值
SPEEDSOUND=334.1+25*0.61
Trig=0
Echo=0
TMOD=0x01
}
//输出距离值到LCD1602上
void DisplayDistanceValue(float dat)
{
uchar i=0,j=0,len
uint value
value=(uint)dat
//范围检查大于4000mm和小于20mm都为超出测量范围
if(value>4000)
{
LCD_Display_String(Prompts[1],0x00)
LCD_Display_String(Prompts[2],0x40)
//Beep(2)
}
else if(value<20)
{
LCD_Display_String(Prompts[1],0x00)
LCD_Display_String(Prompts[3],0x40)
//Beep(2)
}
else
{
//将数值转换成字符串
len=UnsigedIntToString(value)
//保留1位小数
while(stringBuf!='\0')
{
if(len-j==1)
{
DistanceText[6+j]='.'
j++
}else
{
DistanceText[6+j]=stringBuf
i++
j++
}
}
DistanceText[6+j]='c'
j++
DistanceText[6+j]='m'
i=7+j
//剩余位置补空格
while(i<16)
{
DistanceText=' '
i++
}
//LCD_Display_String(Prompts[0],0x00)
LCD_Display_String(DistanceText,0x40)
}
}
//显示温度值
void DisplayTemperatureValue()
{
TemperatureText[13]=CurTempInteger/10+'0'
TemperatureText[14]=CurTempInteger+'0'
TemperatureText[15]='C'
LCD_Display_String(TemperatureText,0x00)
}
//将无符号的整数转成字符串,返回字符串长度
uchar UnsigedIntToString(uint value)
{
uchar i=0,t,length
//从个位开始转换
do
{
stringBuf='0'+value
value=value/10
i++
}while(value!=0)
length=i
//将字符串颠倒顺序
for(i=0i<(length/2)i++)
{
t=stringBuf
stringBuf=stringBuf[length-i-1]
stringBuf[length-i-1]=t
}
stringBuf[length]='\0'
return length
}
//蜂鸣器
//延时函数 毫秒 @12.000MHz
void DelayMS(uint ms)
{
uchar i, j
while(ms--)
{
_nop_()
i = 2
j = 239
do
{
while (--j)
}while (--i)
}
}
//延时函数 20微秒 @12.000MHz
void Delay20us()
{
uchar i
_nop_()
i = 7
while (--i)
}
//定时器0中断
void Timer0() interrupt 1
{
}
//DS18B20代码:
#include
#include
#define uchar unsigned char //无符号8位
#define uint unsigned int //无符号16位
//定义DS18B20端口DS18B20_DQ
sbit DS18B20_DQ = P2^7
//当前采集的温度值整数部分
int xdata CurTempInteger
//当前采集的温度值小数部分
int xdata CurTempDecimal
void Delayus(uint count)
{
while (--count)
}
uchar Reset_DS18B20()
{
uchar status
DS18B20_DQ=1
Delayus(1)
//开始复位过程
DS18B20_DQ=0 //数据线拉低
Delayus(100) //延时480us-960us
DS18B20_DQ=1 //数据线拉高
Delayus(10) //延时15us-60us
status=DS18B20_DQ//读取数据线上的状态
Delayus(120)
return status
}
void WriteByteToDS18B20(uchar dat)
{
uchar i
for(i=0i<8i++)
{
DS18B20_DQ=0
DS18B20_DQ=dat&0x01 //发送1位数据
Delayus(15) //延时60us以上
DS18B20_DQ=1 //释放总线,等待总线恢复
dat>>=1 //准备下一位数据
}
}
uchar ReadByteFromDS18B20()
{
uchar i,dat=0
for(i=0i<8i++)
{
DS18B20_DQ=0 //拉低总线,产生读信号
dat>>=1
DS18B20_DQ=1//释放总线,准备读1位数据
Delayus(2)//延时4us
if(DS18B20_DQ) dat|=0x80//合并每位数据
Delayus(15)//延时60us
DS18B20_DQ=1//拉高总线,准备读下1位数据
}
return dat
}
void ReadTemperatureFromDS18B20()
{
uchar flag=0//正负符号标志
//存储当前采集的温度值
uchar TempValue[]={0,0}
if(Reset_DS18B20())
{
CurTempInteger=255
CurTempDecimal=0
}
else
{
WriteByteToDS18B20(0xCC)//跳过ROM命令
WriteByteToDS18B20(0x44)//温度转换命令
Reset_DS18B20()//复位
WriteByteToDS18B20(0xCC)//跳过ROM命令
WriteByteToDS18B20(0xBE)//读取温度暂存器命令
TempValue[0]=ReadByteFromDS18B20()//先读低字节温度值
TempValue[1]=ReadByteFromDS18B20()//后读高字节温度值
Reset_DS18B20()//复位
//计算温度值
//先进行正温度与负温度判断,高5位全为1(0xF8)则为负数
if((TempValue[1]&0xF8)==0xF8)
{
//负温度计算:取反加1,低字节为0时,高字节取反加1,否则不需要。
TempValue[1]=~TempValue[1]
TempValue[0]=~TempValue[0]+1
if(TempValue[0]==0x00) TempValue[1]++
flag=1//负数标志
}
//将温度值分为整数和小数两部分存储(默认为12位精度)
CurTempInteger=((TempValue[1]&0x07)<<4)|((TempValue[0]&0xF0)>>4) if(flag) CurTempInteger=-CurTempInteger
CurTempDecimal=(TempValue[0]&0x0F)*625
}
}
//LCD1602程序代码:
#include
#include
#define uchar unsigned char
#define uint unsigned int
#define Delay4us(){_nop_()_nop_()_nop_()_nop_()}
sbit LCD_RS=P2^0
sbit LCD_RW=P2^1
sbit LCD_EN=P2^2
void LCDDelay(uint ms)
{
uchar i, j
while(ms--)
{
_nop_()
i = 2
j = 239
do
{
while (--j)
}while (--i)
}
}
bit LCD_Busy_Check()
{
bit result
LCD_RS=0LCD_RW=1LCD_EN=1
Delay4us()
result=(bit)(P0&0x80)
LCD_EN=0
return result
}
void Write_LCD_Command(uchar cmd)
{
while(LCD_Busy_Check())
LCD_RS=0LCD_RW=0 LCD_EN=0_nop_()_nop_()
P0=cmdDelay4us()
LCD_EN=1Delay4us()LCD_EN=0
}
void Write_LCD_Data(uchar dat)
{
while(LCD_Busy_Check())
LCD_RS=1LCD_RW=0LCD_EN=0
P0=datDelay4us()
LCD_EN=1Delay4us()LCD_EN=0
}
void LCD_Set_POS(uchar pos)
{
Write_LCD_Command(pos|0x80)
}
void LCD_Initialize()
{
Write_LCD_Command(0x01)LCDDelay(5)
Write_LCD_Command(0x38)LCDDelay(5)
Write_LCD_Command(0x0C)LCDDelay(5)
Write_LCD_Command(0x06)LCDDelay(5)
}
void LCD_Display_String(uchar *str, uchar LineNo)
{
uchar k
LCD_Set_POS(LineNo)
for(k=0k<16k++)
{
Write_LCD_Data(str[k])
}
}
void LCD_Display_OneChar(uchar Dat, uchar X, uchar Y)
{
Y &= 0x01//限制Y不能大于1(2行,0-1)
X &= 0x0F //限制X不能大于15(16个字符,0-15)
if(Y) {X |= 0x40} //当要在第二行显示时地址码+0x40
X |= 0x80//算出指令码
Write_LCD_Command(X)
Write_LCD_Data(Dat)
}
* 1、LCD第一行显示: www.saxmcu.com* LCD第二行显示: SP-28A--DIY
* 2、先将两行字符写入DDRAM中,然后从右至左逐字移出显毕仿示。
* 3、在指定位置停留1.6秒后,闪烁2次,清屏。
* 4、反复循环上述显示方手察纤式。
*******************************************************************
LCD_RS EQU P2.0
LCD_RW EQU P2.1
LCD_EN EQU P2.2
*******************************************************************
ORG 0000H
AJMP MAIN
ORG 0030H
*******************************************************************
MAIN:
MOV SP,#60H
ACALL LCD_INIT LCD初始化
MAIN1:
ACALL CLR_LCD 清LCD
MOV A,#90H在第一行第17列的位置
ACALL LCD_CMD
MOV DPTR,#LINE1 第一行字符串的起始地址没源送入DPTR。
ACALL WRITE
MOV A,#0D0H 在第二行第17列的位置
ACALL LCD_CMD
MOV DPTR,#LINE2 第二行字符串的起始地址送入DPTR。
ACALL WRITE
MOV R3,#10H 向左移动16格
LOOPA:
MOV A,#18H 字符同时左移一格
ACALL LCD_CMD
MOV R5,#03H 延时375MS
ACALL DELAY125MS
DJNZ R3,LOOPA
ACALL DELAY4延时1.6s
ACALL DELAY4
MOV R4,#02H设置闪烁次数
ACALL FLASH 开始闪烁
AJMP MAIN1
LINE1:
DB "www.saxmcu.com",00H
LINE2:
DB "SP-28A--DIY",00H
***************************************************************
LCD初始化设定子程序
***************************************************************
LCD_INIT:
ACALL DELAY5MS延时15MS
ACALL DELAY5MS等待LCD电源稳定
ACALL DELAY5MS
MOV A,#38H 16*2显示,5*7点阵,8位数据
ACALL LCD_CMD_NC 不进行LCD忙检测
ACALL DELAY5MS
MOV A,#38H 16*2显示,5*7点阵,8位数据
ACALL LCD_CMD_NC 不进行LCD忙检测
ACALL DELAY5MS
MOV A,#38H 16*2显示,5*7点阵,8位数据
ACALL LCD_CMD_NC 不进行LCD忙检测
ACALL DELAY5MS
MOV A,#08H 显示关
ACALL LCD_CMD进行LCD忙检测
MOV A,#01H 清除屏幕
ACALL LCD_CMD进行LCD忙检测
MOV A,#0CH显示开,关光标
ACALL LCD_CMD 进行LCD忙检测
RET
***************************************************************
清LCD子程序
***************************************************************
CLR_LCD:
MOV A,#01H清除屏幕
ACALL LCD_CMD 进行LCD忙检测
RET
***************************************************************
写指令数据到LCD
RS=L,RW=L,D0-D7=指令码,E=高脉冲
***************************************************************
LCD_CMD:
CALL CHECKBUSY
LCD_CMD_NC:
CLR LCD_RS
CLR LCD_RW
MOV P0,A
SETB LCD_EN
NOP
NOP
NOP
NOP
CLR LCD_EN
RET
***************************************************************
写显示数据到LCD
RS=H,RW=L,D0-D7=数据,E=高脉冲
***************************************************************
LCD_WDATA:
ACALL CHECKBUSY
SETB LCD_RS
CLR LCD_RW
MOV P0,A
SETB LCD_EN
NOP
NOP
NOP
NOP
CLR LCD_EN
RET
***************************************************************
检测LCD控制器忙状态
读数据
RS=L,RW=H,E=H,输出:D0-D7=数据
P0.7=1,LCD忙,等待。P0.7=0,LCD闲,可以进行读写 *** 作。
***************************************************************
CHECKBUSY:
PUSH ACC
MOV P0,#0FFH
CLR LCD_RS
SETB LCD_RW
SETB LCD_EN
BUSYLOOP:
NOP
JB P0.7,BUSYLOOP
CLR LCD_EN
POP ACC
RET
***************************************************************
发送字符串子程序
***************************************************************
WRITE:
PUSH ACC
WRITE1:
CLR A
MOVC A,@A+DPTR
JZ WRITE2
INC DPTR
ACALL LCD_WDATA
JMP WRITE1
WRITE2:
POP ACC
RET
***************************************************************
闪烁子程序
***************************************************************
FLASH:
MOV A,#08H关闭显示
ACALL LCD_CMD
ACALL DELAY4
MOV A,#0CH开显示,关闭光标
ACALL LCD_CMD
ACALL DELAY4
DJNZ R4,FLASH
RET
***************************************************************
延时5MS子程序
LCD初始化使用
***************************************************************
DELAY5MS:
MOV R6,#10
DL1:
MOV R7,#249
DL2:
DJNZ R7,DL2
DJNZ R6,DL1
RET
***************************************************************
延时125MS子程序
字符串移动时使用
***************************************************************
DELAY125MS:
DL3:
MOV R6,#250
DL4:
MOV R7,#249
DL5:
DJNZ R7,DL5
DJNZ R6,DL4
DJNZ R5,DL3
RET
***************************************************************
延时800MS子程序
闪烁时使用
***************************************************************
DELAY4:
MOV R5,#40
DL6:
MOV R6,#100
DL7:
MOV R7,#100
DL8:
DJNZ R7,DL8
DJNZ R6,DL7
DJNZ R5,DL6
RET
***************************************************************
END
可以吧?
1、首先我们打开Keil μVision编译器,新建一个工程,然后保存在硬盘上的位置,然后选择Atmel-AT89C51单片机为模型,并启动器添加STARTUP.A51文件,然后在当前目录下新建一个C文件,并将其添加入工作路径。
2、导入51单片机的头文件以及LCD1602的头文件。
3、创建一个延时函数,可以传入想要具体延时的时长,其内部实现是由一个二重循环,两个循环的次数悔知芦相乘积。
4、然后创建写命令的函数,指定RS和E同时为0时,才可以写入命令,设定完成后,将com写入输出端口,规定写命令时,E为正脉冲,然后空 *** 作一个机器周期等待机器反应。
5、然后创建写数据的函数,规定写数据时,E为正脉冲,规定当RS=1和RW=0时才可以写入数据,然后将数据从输出端口输出,最后让碧带E产生正跳变。
6、然后创建初始化LCD1602的函数,指定显示模式位两行显示,5*7,8位数据、整体显示,无光标,无闪烁、写入一个字符后地址指针加1,最后进行清屏 *** 作。
7、最后在主函数中首先执行LCD1602的初始化函数,首先创猛唤建一个无限循环,然后添加两个字符串,这里以两行显示百度经验的网址为例,再进行延时以及使用清屏函数进行刷新。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)