找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3168|回复: 3
收起左侧

51单片机三路超声波避障与仿真(proteus8.6)源码

[复制链接]
ID:728133 发表于 2020-4-13 13:12 | 显示全部楼层 |阅读模式
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
51hei.png 51hei.png

单片机源程序如下:
  1. //==============================================================================================================
  2. //程序标题:基于51单片机的三路超声波小车避障程序================================================================
  3. //定稿日期:-------                        ====================================================================================
  4. //作    者:-------                        ====================================================================================
  5. //更新日期:2020.3.8  23:51====================================================================================
  6. //最后撰写人:张 虎                        ==========================================================================================
  7. //功    能:三方向避障      ====================================================================================

  8. #include<reg51.h>               //头文件(定义了一些特殊的寄存器)
  9. #include<intrins.h>      
  10. #include<stdio.h>      
  11. //==========3个超声波模块定义================================
  12. sbit Trig_left    = P1^0;        //左边超声波模块端口定义
  13. sbit Echo_left    = P1^1;        
  14. sbit Trig_mid     = P1^2;        //中间超声波模块端口定义
  15. sbit Echo_mid     = P1^3;
  16. sbit Trig_right   = P1^4;        //右边超声波模块端口定义
  17. sbit Echo_right   = P1^5;
  18. //=========1个298模块2路电机控制端设置=============================
  19. sbit N1  = P2^0;              //L298N模块控制马达,通过N1N2和N3N4端口输出1、0控制电机正转,反转,急停
  20. sbit N2  = P2^1;
  21. sbit N3  = P2^2;
  22. sbit N4  = P2^3;
  23. sbit EN1 = P2^4;             //L298N模块使能端(利用PWM计数控制使能端可实现电机转速控制,在本程序中没有体现)
  24. sbit EN2 = P2^5;                         //
  25. //============定义全局变量=======================================
  26. unsigned int  time=0;                  //定义time为十进制无负号整型变量(0-65535),用于读取距离

  27. unsigned long S_left=0;       //左边障碍距离
  28. unsigned long S_mid=0;        //中间障碍距离
  29. unsigned long S_right=0;      //右边障碍距离
  30. //==============================================================================================
  31. void delayms(unsigned int ms)  //延时子函数
  32. {
  33.         unsigned char i;
  34.         while(ms--)
  35.         {
  36.                 for(i=0;i<113;i++);
  37.         }
  38. }
  39. void delay_15us(void)   //15us精准延时,误差 0us,用于启动超声波模块
  40. {
  41.     unsigned char a;
  42.     for(a=6;a>0;a--);
  43. }
  44. //=========转向函数=============================================================================
  45. void turn_down()                         //向前
  46. {
  47. N1=1;
  48. N2=0;
  49. N3=1;
  50. N4=0;
  51. delayms(500);
  52. }
  53. void turn_back()                         //向后
  54. {
  55. N1=0;
  56. N2=1;
  57. N3=0;
  58. N4=1;
  59. delayms(500);
  60. }
  61. void turn_left()                         //向左
  62. {
  63. N1=0;
  64. N2=1;
  65. N3=1;
  66. N4=0;
  67. delayms(500);
  68. }

  69. void turn_right()                         //向右
  70. {
  71. N1=1;
  72. N2=0;
  73. N3=0;
  74. N4=1;
  75. delayms(500);
  76. }
  77. //==========启动超声波模块完成测距并读取数值(cm)===================================================================
  78. void measure_left(void)                 //左模块
  79. {
  80. EA=0;                                                 //关闭总中断
  81.         Trig_left=1;                         //启动一次模块,信号时间应大于10us
  82.         delay_15us();
  83.         Trig_left=0;
  84.                               
  85.         TH1=0;                   //定时器1高8位寄存器清零
  86.     TL1=0;                   //定时器1低8位寄存器清零
  87.     TF1=0;                   //定时器1溢出位清零
  88.         while(Echo_left==0);         //当echo为零时等待变为高电平.等待波发出(Echo_lift为模块发送超声波到接受的时间标志,硬件自行设置,单片机检测即可)

  89. TR1=1;                      //波发出后立即启动定时器1,让TH1,TL1寄存器数值每1us增加1。
  90. EA=1;                                     //总中断允许,开启计数      
  91.     while(Echo_left);        // 等待反波Echo初始状态为0,模块声波发送后(声波离开发射器),硬件将其置位,当检测到有声波返回时(声波由障碍物反射回到模块,接收器已经接受到声波信号)硬件将其复位。Echo置位的时间的一半即超声波从模块发到障碍物止的时间S=Vt,将此时间乘以340m/s即可得到障碍物距离。
  92.         time=TH1*256+TL1;                  //取值读取测距数值到time 将16进制数转化为十进制
  93. TH1=0;                                             //清零
  94. TL1=0;
  95. TR1=0;                      //关闭定时器1
  96.         S_left=(time*17)/1000;    //转换,定时器每1us增加1,将数值取值到time中,若初始值为0也就是从定时器开到定时器关一共经过了time个us,微秒除1000是毫秒再除以1000是秒再乘以声速340m/s,理论上也就是:S=Vt=【(((time÷2)÷1000 000)×340)×100】厘米,即:[(time*170)÷10000]算出来是CM(厘米)                        
  97.         delayms(5);                                 //延时
  98. }
  99. //========右边距离测量(同左边一样)============================================================================================
  100. void measure_right(void)                 //左模块
  101. {
  102. EA=0;
  103.         Trig_right=1;                           //启动一次模块,信号时间应大于10us
  104.         delay_15us();
  105.         Trig_right=0;                       
  106.         TH1=0;                   //定时器1清零
  107. TL1=0;                   //定时器1清零
  108. TF1=0;                   //溢出位清零
  109.         while(Echo_right==0);          //当RX为零时等待变为高电平(Echo_lift为模块发送超声波到接受的时间标志,硬件自行设置,单片机检测即可)
  110. TR1=1;                   //启动定时器1
  111. EA=1;                                  //开启计数        Echo初始状态为0,模块声波发送后(声波离开发射器),硬件将其置位,当检测到有声波返回时(声波由障碍物反射回到模块,接收器已经接受到声波信号)硬件将其复位。Echo置位的时间的一半即超声波从模块发到障碍物止的时间S=Vt,将此时间乘以340m/s即可得到障碍物距离。
  112.         while(Echo_right);                 //当RX为1计数并等待
  113.         time=TH1*256+TL1;                  //取值读取测距数值 将16进制数转化为十进制
  114. TH1=0;                                          //清零
  115. TL1=0;
  116. TR1=0;          //关闭定时器1
  117.         S_right=(time*17)/1000;    //转换,定时器每1us增加1,将数值取值到time中,若初始值为0也就是从定时器开到定时器关一共经过了time个us,微秒除1000是毫秒再除以1000是秒再乘以声速340m/s,理论上也就是:S=Vt=【(((time÷2)÷1000 000)×340)×100】厘米,即:[(time*170)÷10000]算出来是CM(厘米)
  118.                                  
  119.         delayms(5);                                 //延时
  120. }
  121. //==============中间距离测量(同左边,右边一样)============================================================================
  122. void measure_mid(void)                 //左模块
  123. {
  124. EA=0;
  125.         Trig_mid=1;                           //启动一次模块,信号时间应大于10us
  126.         delay_15us();
  127.         Trig_mid=0;                       
  128.         TH1=0;                   //定时器1清零
  129. TL1=0;                   //定时器1清零
  130. TF1=0;                   //溢出位清零

  131.         while(Echo_mid==0);          //当RX为零时等待变为高电平(Echo_lift为模块发送超声波到接受的时间标志,硬件自行设置,单片机检测即可)
  132. TR1=1;                   //启动定时器1
  133. EA=1;                                  //开启计数        Echo初始状态为0,模块声波发送后(声波离开发射器),硬件将其置位,当检测到有声波返回时(声波由障碍物反射回到模块,接收器已经接受到声波信号)硬件将其复位。Echo置位的时间的一半即超声波从模块发到障碍物止的时间S=Vt,将此时间乘以340m/s即可得到障碍物距离。
  134.         while(Echo_mid);                 //当RX为1计数并等待
  135.         time=TH1*256+TL1;                  //取值读取测距数值 将16进制数转化为十进制
  136. TH1=0;                                          //清零
  137. TL1=0;
  138. TR1=0;          //关闭定时器1
  139.         S_mid=(time*17)/1000;    //转换,定时器每1us增加1,将数值取值到time中,若初始值为0也就是从定时器开到定时器关一共经过了time个us,微秒除1000是毫秒再除以1000是秒再乘以声速340m/s,理论上也就是:S=Vt=【(((time÷2)÷1000 000)×340)×100】厘米,即:[(time*170)÷10000]算出来是CM(厘米)
  140.         delayms(5);                                 //延时
  141. }
  142. //=========退出死区函数,===================================================================================================
  143. void move_left_or_right(void)             //设置左右转向函数
  144. {
  145.     turn_back();                 //退出死区
  146.         N1=N2=N3=N4=1;                 //前方有障碍物,立刻"急停"然后判断距离
  147.     delayms(100);                 //减速延迟
  148.         measure_left();      //重新检测左前方距离
  149.         measure_right();     //重新检测右前方距离

  150.         if(S_left>=S_right)  //左右距离不相等时,通过返回数据进行避障
  151.         {
  152.                  turn_left();         //左转
  153.                  
  154.         }
  155.         else                 //右边距离大于左边
  156.         {
  157.                  turn_right();         //右转
  158.         }
  159. }
  160. //=======判断障碍物,选择行进路线===================================================================================================
  161. void move(void)                           //设置前进函数
  162. {
  163.         if(S_mid>4)                            //判断中间障碍物的距离,单位CM(不一定准)
  164.                                                // 如果中间障碍物距离均大于4
  165.         {
  166.                 turn_down();                       //前进
  167.         }
  168.         else                                                                   //判断中间距离小于等于4,
  169.         {
  170.               N1=N2=N3=N4=1;                                   //前方有障碍物,立刻"急停"然后判断距离
  171.                   delayms(100);                                           //减速延时
  172.                  if(S_mid<=4&&S_right>4)           //判断右侧距离是否大于4
  173.               {
  174.                           turn_right();                //右转
  175.               }                                                                       
  176.                  else                                                           //即判断中间及其右侧距离均小于等于4
  177.                  {                                                                       
  178.                           if(S_mid<=4&&S_right<=4&&S_left>4) //判断左侧距离
  179.                                                    // 如果左侧障碍物距离大于4
  180.                       {
  181.                                 turn_left();                           //左转
  182.                       }
  183.                           else                                                   //否则 即三侧均小于等于4,进入死区模式
  184.                           {
  185.                               
  186.                             move_left_or_right();  //退出死区函数
  187.                           }
  188.                  }

  189.         }
  190. }

  191. //==========单片机定时器和计数器设置===============================================
  192. void set(void)
  193. {        delayms(10);           //上电延时
  194.         TMOD=0x10;                   //设T0为方式1,GATE=0;
  195.         TH1=0x00;                   //T1高8位重装初值
  196.         TL1=0x00;          //T1低8位重装初值
  197.         EA=1;                           //开启总中断(全局中断)
  198.         Trig_left =0;
  199.         Trig_mid =0;
  200.         Trig_right =0;
  201.     EN1=1;                           //298模块使能
  202.         EN2=1;
  203.         N1=N2=N3=N4=0;     //开机先制动
  204. }
  205. //============主函数===============================================================
  206. void main(void)
  207. {
  208.         set();                                      //单片机及其298初始化
  209.         while(1)
  210.         {
  211.                 measure_left();       //检测前方距离
  212.                 measure_mid();        //检测前方距离
  213.                 measure_right();      //检测前方距离
  214.                 move();               //根据检测结果,避障前进
  215.                 delayms(10);                  //延时
  216.         }      
  217. }
  218. //==========================================================
  219. //TH1=[(65536-设定中断时间)/(机器运行周期数/晶振频率MHZ)]/256;         高8位中断初值计算公式
  220. //TL1=[(65536-设定中断时间)/(机器运行周期数/晶振频率MHZ)]%256;         低8位中断初值计算公式
复制代码

所有资料51hei提供下载:
三路超声波避障(OK).7z (89.53 KB, 下载次数: 73)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:102963 发表于 2020-4-13 22:08 | 显示全部楼层
这状态是怎么变换的呢?怎么一直在空挡呢?
回复

使用道具 举报

ID:848219 发表于 2020-11-24 11:06 | 显示全部楼层
这个怎么改变状态
回复

使用道具 举报

ID:725587 发表于 2020-11-24 16:54 | 显示全部楼层
先点赞 再慢慢看
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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