找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 7039|回复: 8
打印 上一主题 下一主题
收起左侧

51单片机超声波测距Proteus仿真程序

  [复制链接]
跳转到指定楼层
楼主
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)


单片机源程序如下:
  1. #include <reg52.h>
  2. #include <intrins.h>

  3. #define uchar unsigned char    // 以后unsigned char就可以用uchar代替
  4. #define uint  unsigned int    // 以后unsigned int 就可以用uint 代替

  5. sfr ISP_DATA  = 0xe2;            // 数据寄存器
  6. sfr ISP_ADDRH = 0xe3;            // 地址寄存器高八位
  7. sfr ISP_ADDRL = 0xe4;            // 地址寄存器低八位
  8. sfr ISP_CMD   = 0xe5;            // 命令寄存器
  9. sfr ISP_TRIG  = 0xe6;            // 命令触发寄存器
  10. sfr ISP_CONTR = 0xe7;            // 命令寄存器


  11. sbit LcdRs_P   = P2^7;        // 1602液晶的RS管脚      
  12. sbit LcdRw_P   = P2^6;        // 1602液晶的RW管脚
  13. sbit LcdEn_P   = P2^5;        // 1602液晶的EN管脚
  14. sbit Trig_P    = P2^2;        // 超声波模块的Trig管脚
  15. sbit Echo_P    = P2^3;        // 超声波模块的Echo管脚
  16. sbit KeySet_P  = P3^2;        // “设置”按键的管脚
  17. sbit KeyDown_P = P3^3;        // “减”按键的管脚
  18. sbit KeyUp_P   = P3^4;        // “加”按键的管脚
  19. sbit Buzzer_P  = P2^1;        // 蜂鸣器的管脚
  20. sbit Led_P     = P2^0;        // LED报警灯的管脚


  21. uint gAlarm;                            // 报警距离变量



  22. /*********************************************************/
  23. // 单片机内部EEPROM不使能
  24. /*********************************************************/
  25. void ISP_Disable()
  26. {
  27.     ISP_CONTR = 0;
  28.     ISP_ADDRH = 0;
  29.     ISP_ADDRL = 0;
  30. }


  31. /*********************************************************/
  32. // 从单片机内部EEPROM读一个字节,从0x2000地址开始
  33. /*********************************************************/
  34. unsigned char EEPROM_Read(unsigned int add)
  35. {
  36.     ISP_DATA  = 0x00;
  37.     ISP_CONTR = 0x83;
  38.     ISP_CMD   = 0x01;
  39.     ISP_ADDRH = (unsigned char)(add>>8);
  40.     ISP_ADDRL = (unsigned char)(add&0xff);
  41.     // 对STC89C51系列来说,每次要写入0x46,再写入0xB9,ISP/IAP才会生效
  42.     ISP_TRIG  = 0x46;      
  43.     ISP_TRIG  = 0xB9;
  44.     _nop_();
  45.     ISP_Disable();
  46.     return (ISP_DATA);
  47. }


  48. /*********************************************************/
  49. // 往单片机内部EEPROM写一个字节,从0x2000地址开始
  50. /*********************************************************/
  51. void EEPROM_Write(unsigned int add,unsigned char ch)
  52. {
  53.     ISP_CONTR = 0x83;
  54.     ISP_CMD   = 0x02;
  55.     ISP_ADDRH = (unsigned char)(add>>8);
  56.     ISP_ADDRL = (unsigned char)(add&0xff);
  57.     ISP_DATA  = ch;
  58.     ISP_TRIG  = 0x46;
  59.     ISP_TRIG  = 0xB9;
  60.     _nop_();
  61.     ISP_Disable();
  62. }


  63. /*********************************************************/
  64. // 擦除单片机内部EEPROM的一个扇区
  65. // 写8个扇区中随便一个的地址,便擦除该扇区,写入前要先擦除
  66. /*********************************************************/
  67. void Sector_Erase(unsigned int add)      
  68. {
  69.     ISP_CONTR = 0x83;
  70.     ISP_CMD   = 0x03;
  71.     ISP_ADDRH = (unsigned char)(add>>8);
  72.     ISP_ADDRL = (unsigned char)(add&0xff);
  73.     ISP_TRIG  = 0x46;
  74.     ISP_TRIG  = 0xB9;
  75.     _nop_();
  76.     ISP_Disable();
  77. }



  78. /*********************************************************/
  79. // 毫秒级的延时函数,time是要延时的毫秒数
  80. /*********************************************************/
  81. void DelayMs(uint time)
  82. {
  83.     uint i,j;
  84.     for(i=0;i<time;i++)
  85.         for(j=0;j<112;j++);
  86. }


  87. /*********************************************************/
  88. // 1602液晶写命令函数,cmd就是要写入的命令
  89. /*********************************************************/
  90. void LcdWriteCmd(uchar cmd)
  91. {
  92.     LcdRs_P = 0;
  93.     LcdRw_P = 0;
  94.     LcdEn_P = 0;
  95.     P0=cmd;
  96.     DelayMs(2);
  97.     LcdEn_P = 1;   
  98.     DelayMs(2);
  99.     LcdEn_P = 0;   
  100. }


  101. /*********************************************************/
  102. // 1602液晶写数据函数,dat就是要写入的数据
  103. /*********************************************************/
  104. void LcdWriteData(uchar dat)
  105. {
  106.     LcdRs_P = 1;
  107.     LcdRw_P = 0;
  108.     LcdEn_P = 0;
  109.     P0=dat;
  110.     DelayMs(2);
  111.     LcdEn_P = 1;   
  112.     DelayMs(2);
  113.     LcdEn_P = 0;
  114. }


  115. /*********************************************************/
  116. // 1602液晶初始化函数
  117. /*********************************************************/
  118. void LcdInit()
  119. {
  120.     LcdWriteCmd(0x38);        // 16*2显示,5*7点阵,8位数据口
  121.     LcdWriteCmd(0x0C);        // 开显示,不显示光标
  122.     LcdWriteCmd(0x06);        // 地址加1,当写入数据后光标右移
  123.     LcdWriteCmd(0x01);        // 清屏
  124. }


  125. /*********************************************************/
  126. // 液晶光标定位函数
  127. /*********************************************************/
  128. void LcdGotoXY(uchar line,uchar column)
  129. {
  130.     // 第一行
  131.     if(line==0)        
  132.         LcdWriteCmd(0x80+column);
  133.     // 第二行
  134.     if(line==1)        
  135.         LcdWriteCmd(0x80+0x40+column);
  136. }



  137. /*********************************************************/
  138. // 液晶输出字符串函数
  139. /*********************************************************/
  140. void LcdPrintStr(uchar *str)
  141. {
  142.     while(*str!='\0')
  143.             LcdWriteData(*str++);
  144. }


  145. /*********************************************************/
  146. // 液晶输出数字
  147. /*********************************************************/
  148. void LcdPrintNum(uint num)
  149. {
  150.     LcdWriteData(num/100+0x30);                // 百位
  151.     LcdWriteData(num%100/10+0x30);        // 十位
  152.     LcdWriteData(num%10+0x30);                // 个位
  153. }


  154. /*********************************************************/
  155. // 计算测到的距离
  156. /*********************************************************/
  157. uint GetDistance(void)
  158. {
  159.     uint ss;                    // 用于记录测得的距离

  160.     TH0=0;
  161.     TL0=0;

  162.     Trig_P=1;                    // 给超声波模块一个开始脉冲
  163.     DelayMs(1);
  164.     Trig_P=0;

  165.     while(!Echo_P);        // 等待超声波模块的返回脉冲
  166.     TR0=1;                        // 启动定时器,开始计时
  167.     while(Echo_P);        // 等待超声波模块的返回脉冲结束
  168.     TR0=0;                        // 停止定时器,停止计时

  169.     ss=((TH0*256+TL0)*0.034)/2;        // 距离cm=(时间us * 速度cm/us)/2

  170.     return ss;
  171. }


  172. /*********************************************************/
  173. // 按键扫描
  174. /*********************************************************/
  175. void KeyScanf()
  176. {
  177.     uchar i;
  178.     uchar dat1,dat2;

  179.     if(KeySet_P==0)                    // 判断是否有按键按下
  180.     {
  181.         DelayMs(10);                                // 消除按键按下的抖动
  182.         while(!KeySet_P);                        // 等待按键释放
  183.         DelayMs(10);                                // 消除按键松开的抖动
  184.         
  185.         LcdGotoXY(1,2);                            // 液晶第二行刷新显示
  186.         LcdPrintStr("alarm=   cm");
  187.         LcdGotoXY(1,8);                            // 显示当前的报警值
  188.         LcdPrintNum(gAlarm);               

  189.         i=1;

  190.         while(i)
  191.         {                              
  192.             if(KeyDown_P==0)        // 报警值减的处理
  193.             {
  194.                 DelayMs(300);
  195.                 if(gAlarm>2)
  196.                     gAlarm--;
  197.                 LcdGotoXY(1,8);
  198.                 LcdPrintNum(gAlarm);   
  199.             }

  200.             if(KeyUp_P==0)            // 报警值加的处理
  201.             {
  202.                 DelayMs(300);
  203.                 if(gAlarm<400)
  204.                     gAlarm++;
  205.                 LcdGotoXY(1,8);
  206.                 LcdPrintNum(gAlarm);
  207.             }
  208.             
  209.             if(KeySet_P==0)            // 再次按下设置键的判断
  210.             {
  211.                 DelayMs(10);                          // 消除按键按下的抖动
  212.                 while(!KeySet_P);                    // 等待按键释放
  213.                 DelayMs(10);                          // 消除按键松开的抖动

  214.                 LcdGotoXY(1,0);                        // 液晶恢复测量时的内容显示
  215.                 LcdPrintStr("     S=   cm    ");

  216.                 i=0;
  217.             }               
  218.         }
  219.         
  220.         dat1=gAlarm/100;
  221.         dat2=gAlarm%100;
  222.         Sector_Erase(0x2000);
  223.         EEPROM_Write(0x2000,dat1);
  224.         EEPROM_Write(0x2001,dat2);
  225.     }   
  226. }


  227. /*********************************************************/
  228. // 报警判断
  229. /*********************************************************/
  230. void AlarmJudge(uint ss)
  231. {
  232.     uchar i;
  233.     float alr1,alr2,alr3,alr4;

  234.     alr1=gAlarm/4.00*1;
  235.     alr2=gAlarm/4.00*2;
  236.     alr3=gAlarm/4.00*3;
  237.     alr4=gAlarm/4.00*4;


  238.     // 报警频率最快
  239.     if(ss<alr1)            
  240.     {
  241.         for(i=0;i<10;i++)
  242.         {
  243.             Led_P=0;
  244.             Buzzer_P=0;
  245.             DelayMs(50);
  246.             Led_P=1;
  247.             Buzzer_P=1;
  248.             DelayMs(50);
  249.             KeyScanf();
  250.         }
  251.     }
  252.     // 报警频率第二快
  253.     else if(ss<alr2)        
  254.     {
  255.         for(i=0;i<5;i++)
  256.         {
  257.             Led_P=0;
  258.             Buzzer_P=0;
  259.             DelayMs(100);
  260.             Led_P=1;
  261.             Buzzer_P=1;
  262.             DelayMs(100);
  263.             KeyScanf();
  264.         }   
  265.     }
  266.     // 报警频率第三快
  267.     else if(ss<alr3)     
  268.     {
  269.         for(i=0;i<2;i++)
  270.         {
  271.             Led_P=0;
  272.             Buzzer_P=0;
  273.             DelayMs(200);
  274.             Led_P=1;
  275.             Buzzer_P=1;
  276.             DelayMs(200);
  277.             KeyScanf();
  278.         }   
  279.     }
  280.     // 报警频率最慢
  281.     else if(ss<alr4)   
  282.     {
  283.         for(i=0;i<2;i++)
  284.         {
  285.             Led_P=0;
  286.             Buzzer_P=0;
  287.             DelayMs(300);
  288.             Led_P=1;
  289.             Buzzer_P=1;
  290.             DelayMs(300);
  291.             KeyScanf();
  292.         }   
  293.     }
  294.     // 不报警
  295.     else
  296.     {
  297.         Led_P=1;
  298.         Buzzer_P=1;
  299.         for(i=0;i<100;i++)
  300.         {
  301.             KeyScanf();
  302.             DelayMs(10);
  303.         }   
  304.     }
  305. }


  306. /*********************************************************/
  307. // 主函数
  308. /*********************************************************/
  309. void main()
  310. {
  311.     uchar dat1,dat2;
  312.     uint dist;
  313.    
  314.     Trig_P=0;
  315.    
  316.     LcdInit();                                                // 执行液晶初始化
  317.     TMOD = 0x01;                                            // 选择定时器0,并且确定是工作方式1(为了超声波模块测量距离计时用的)

  318.     LcdGotoXY(0,0);                                    // 定位到第0行第0列
  319.     LcdPrintStr(" HC-SR04 System ");    // 第0行显示“HC-SR04 System”
  320.     LcdGotoXY(1,0);                                    // 定位到第1行第0列
  321.     LcdPrintStr("     S=   cm    ");    // 第1行显示“S=   cm”

  322.     dat1=EEPROM_Read(0x2000);                    // 从EEPROM读取报警值
  323.     dat2=EEPROM_Read(0x2001);
  324.     gAlarm=dat1*100+dat2;

  325.     if((gAlarm==0)||(gAlarm>400))            // 如果读取到的报警值异常(等于0或大于400则认为异常)
  326.     {
  327.         gAlarm=25;                                            // 重新赋值报警值为25
  328.     }

  329.     while(1)
  330.     {
  331.         dist=GetDistance();                            // 通过超声波模块获取距离

  332.         LcdGotoXY(1,7);                                // 定位到第1行第7列
  333.         LcdPrintNum(dist);                            // 将获取到的距离在液晶上面显示

  334.         AlarmJudge(dist);                                // 判断一下是否需要报警,是的话则报警   
  335.     }
  336. }
复制代码

所有资料51hei提供下载:
09、仿真图.rar (637.62 KB, 下载次数: 323)
07、单片机程序(先解压,后查看).rar (283.83 KB, 下载次数: 287)
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏8 分享淘帖 顶 踩
回复

使用道具 举报

来自 2#
ID:710713 发表于 2020-3-30 12:17 | 只看该作者
楼主,我想请问下这个超声波测距的设置参数是47厘米,那在哪个地方可以给他修改到100厘米呢?
回复

使用道具 举报

板凳
ID:280540 发表于 2019-10-20 13:20 | 只看该作者
为啥连接之后报警LED闪烁,但是1602显示上边一排黑格,没有数
回复

使用道具 举报

地板
ID:630346 发表于 2019-10-26 19:46 来自手机 | 只看该作者
为啥没有看到仿真图
回复

使用道具 举报

5#
ID:340288 发表于 2020-2-16 15:02 | 只看该作者
谢谢分享
回复

使用道具 举报

6#
ID:499645 发表于 2020-3-6 15:40 | 只看该作者
为啥没有资料包呢,上哪里去看那个视频呢
回复

使用道具 举报

7#
ID:715369 发表于 2020-4-7 09:12 来自手机 | 只看该作者
增加有光敏电阻那一块吗?
回复

使用道具 举报

8#
ID:893935 发表于 2021-3-25 16:33 | 只看该作者
为啥达到警报距离蜂鸣器不会响喃?
回复

使用道具 举报

9#
ID:922340 发表于 2021-5-16 23:54 | 只看该作者
请问如果想要不同的测量值怎么设置?这个系统的超声波信号是哪里模拟出来的?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表