51单片机配合超声波测距以及用1602液晶进行显示
2015-01-12 12:35
936 查看
自己写的一个小程序,给51入门的朋友们用一下,实测还行,没什么问题,但几米以上就不怎么准,主要是模块比较廉价,当练手用。注释也都比较清楚。
/*超声波测距程序,利用51单片机的外部中断,如果有时候发现不好使,建议直接使用杜邦线连接引脚*/ #include<reg52.h> #include <intrins.h> typedef unsigned char uchar; typedef unsigned int uint; /*超声波模块为HC-SR04,触发信号给一个至少10us的高电平,之后模块会自动发送8个40kHz的方波信号, 一旦模块收到回响信号,Echo引脚便输出高电平,直到接收不到。这里有个问题是关于时间计算的问题,说明书上说的是 按Echo引脚的高电平持续时间计算,但是声波的路程,不应该是从声波发出的时候就已经开始了吗?这个程序使按照 第二种计算的,如果要改动 ,请改动定时器0的启动时间。*/ sbit Echo=P3^2;//超声波模块的回响信号输出,P3^2也是51单片机外部中断0的输入端,利用下降沿来触发中断 sbit Trig=P1^4;//触发信号脚 sbit lcdrs=P1^0;//数据命令选择端,为0时写指令,为1时写数据 sbit lcdrw=P1^1;//读、写命令选择端,为0时写数据,为1时读数据,读状态时置1,其他时间都是0; sbit lcden=P2^5;//使能端 sbit dula=P2^6;//在这段程序里没有用处 sbit wela=P2^7; sbit STA7=P0^7;//D0~D7数据口对应P0^0~P0^7,当读液晶的数据时,STA7对应P0^7,STA7为1时表示液晶忙,无法接收数据 float dis;//距离的缓存 uchar flag;//中断标志位 char code table[]="distance:";//在规定位置显示字符 char code table1[]="cm"; void delayms(uchar x) { uint i,j; for(i=0;i<x;i++) { for(j=0;j<110;j++); } } void nops()//延时10.9us,每个机器周期约1.09us,在晶振为11.0592MHz时 { _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); } void distance()//计算距离的函数 { Trig=0;//首先将触发拉低 nops(); Trig=1;//给至少10us的高电平,启动模块 nops(); nops(); Trig=0;//此时已经触发了模块,接下来立刻开启定时器计数 TR0=1;//打开定时器0 EX0=1;//打开外部中断,外部中断输入为P3^2,下降沿有效,触发中断 delayms(1);//等待一下,一个机器周期约为1.09us,如果不等待,可能就错过计算dis,陷入死循环,永远无法得出值 if(flag==1)//如果标志位置1,表示Echo输出下降沿,即接收结束 { flag=0; } } void wait()//等待液晶空闲 { P0=0xff; do { lcdrs=0;//循环里的这些语句是读状态时的操作时序 lcdrw=1; lcden=0; lcden=1; }while(STA7==1);//等液晶空闲的时候再出循环 lcden=0;//使使能为0 } void write_com(uchar com)//写命令程序 { wait(); lcdrs=0;//使RS为0,发出的数据会被液晶当做命令而不是现实数据,这也是与写数据程序的唯一不同 P0=com; lcdrw=0;//总是写的,故为0 delayms(5);//使数据平稳,让液晶有时间读取 lcden=1;//根据操作时序,使能要输出高脉冲,这句与后面那句共同构成一个高脉冲 delayms(5); lcden=0; } void write_date(uchar date)//写数据程序 { wait(); lcdrs=1;//注意这是写数据 P0=date; lcdrw=0; delayms(5); lcden=1; delayms(5); lcden=0; } /*初始化函数*/ void init() { wait(); dula=0;//没用 wela=0; lcden=0; write_com(0x38);//设置16*2显示,5*7点阵,8位数据口。这句是不变的 write_com(0x0c);//根据操作时序设置的状态字。下面一样 write_com(0x06); TMOD=0x01;//16位计数器,这里不用开启定时器中断,因为定时器中断无事可做,只要定时器里的值就行,因此无需将TF0置1 TH0=0;//全部设为0 TL0=0; IT0=1;//设置外部中断下降沿有效 EA=1;//开总中断 } /*显示函数*/ void display(float dis) { uint bai,shi,ge,p1,p2;//分别是百位一次向下,到小数点后两位 bai=dis/100; shi=(dis-bai*100)/10; ge=dis-bai*100-shi*10; p1=(dis*10)-bai*1000-shi*100-ge*10; p2=(dis*100)-bai*10000-shi*1000-ge*100-p1*10; write_date(0x30+bai);//将数字转换为字符,必须+0x30,另外,1602液晶只能接收字符型的数据 write_date(0x30+shi); write_date(0x30+ge); write_date('.'); write_date(0x30+p1); write_date(0x30+p2); } void main()//主函数 { uchar i=0; init(); write_com(0x80);//设置地址,在第一行第一列显示distance:,0x80是第一行的起始地址 while(table[i]!='\0') { write_date(table[i]); i++; delayms(5); } i=0; write_com(0x80+0x40+6);//设置地址,在第二行第7位显示cm,0x80+0x40是第二行的起始地址 while(table1[i]!='\0') { write_date(table1[i]); i++; delayms(5); } while(1) { distance(); write_com(0x80+0x40);//设置数据的显示地址,为第二行的起始位,之后在进行循环时不断刷新在这个地方显示 display(dis); delayms(60); } } void ex() interrupt 0//外部中断的中断函数 { TR0=0;//一旦受到下降沿,立马停止定时器计数 dis=(TH0*256+TL0)*1.09/58;//先取出定时器里的时间值,之后再将定时器置0 flag=1;//将标志位置0 TH0=0; TL0=0; }
相关文章推荐
- 51单片机 1602液晶显示
- 51单片机-1602液晶显示的时钟代码
- 51单片机入门之六:1602液晶显示
- 基于51单片机的按键控制超声波测距及显示(带提示音)的实现
- C# form 窗口将X不显示出来以及点击X的时候,提示是否退出系统,进行确定和取消的选择
- Repeater进行模板设计以及实现数据的分页显示
- 51单片机,DS18B20,液晶,超声波
- 51单片机超声波测距程序(C调汇编)
- 收发一体超声波测距与多普勒应用以及实用电路图下载
- 51单片机 超声波测距组件
- 51单片机1602液晶显示移动显示
- 对页面制定区域进行打印,以及打印不显示页脚URL的方法
- 抓取网页中的内容、如何解决乱码问题、如何解决登录问题以及对所采集的数据进行处理显示的过程
- 1602液晶显示实验报告
- 使用Eclipse(以及intellij IDEA)配合JDWP对服务器上部署的代码进行调试
- 51单片机实现对24C02进行页写、顺序读取并显示验证
- 1602液晶静态显示
- 1602液晶显示
- Visio 2007中进行数据库建模时如何显示字段类型以及概念名称
- jQuery_review之table根据内容分组进行折叠显示以及,折叠之后高亮显示的实现