1602显示超声波测距的C语言程序和Proteus仿真图

1602显示超声波测距的C语言程序和Proteus仿真图,第1张

#include"reg52.h"

#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的初始化函数,首先创猛唤建一个无限循环,然后添加两个字符串,这里以两行显示百度经验的网址为例,再进行延时以及使用清屏函数进行刷新。


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/yw/12544410.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-26
下一篇 2023-05-26

发表评论

登录后才能评论

评论列表(0条)

保存