找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 6264|回复: 6
收起左侧

单片机汽车倒车防撞报警电路源程序与PCB设计 带温度补偿

  [复制链接]
ID:308674 发表于 2018-4-21 20:56 | 显示全部楼层 |阅读模式
给大家分享一个很全面的基于单片机的汽车倒车防撞报警电路设计
运用超声波测距原理,有led和蜂鸣器报警,报警频率随距离的越近越快。
带有protues仿真,pcb电路图,C语言源程序

Altium Designer画的汽车倒车防撞报警器原理图和PCB图如下:(51hei附件中可下载工程文件)
0.jpg 0.png

汽车倒车防撞报警仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
01、未上电.jpg

单片机源程序如下:
  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. sbit DQ        = P1^0;                // 温度传感器的引脚定义


  22. uint  gAlarm;                                                        // 报警距离变量
  23. float gSpeed;                                                        // 保存超声波的速度值



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


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


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


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



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


  89. /*********************************************************/
  90. // 延时15微秒
  91. /*********************************************************/
  92. void Delay15us(void)
  93. {
  94.         _nop_();
  95.         _nop_();
  96.         _nop_();
  97.         _nop_();
  98.         _nop_();
  99.         _nop_();
  100.         _nop_();
  101.         _nop_();
  102.         _nop_();
  103.         _nop_();
  104.         _nop_();
  105.         _nop_();
  106.         _nop_();
  107.         _nop_();
  108.         _nop_();
  109. }


  110. /*********************************************************/
  111. // 1602液晶写命令函数,cmd就是要写入的命令
  112. /*********************************************************/
  113. void LcdWriteCmd(uchar cmd)
  114. {
  115.         LcdRs_P = 0;
  116.         LcdRw_P = 0;
  117.         LcdEn_P = 0;
  118.         P0=cmd;
  119.         DelayMs(2);
  120.         LcdEn_P = 1;   
  121.         DelayMs(2);
  122.         LcdEn_P = 0;        
  123. }


  124. /*********************************************************/
  125. // 1602液晶写数据函数,dat就是要写入的数据
  126. /*********************************************************/
  127. void LcdWriteData(uchar dat)
  128. {
  129.         LcdRs_P = 1;
  130.         LcdRw_P = 0;
  131.         LcdEn_P = 0;
  132.         P0=dat;
  133.         DelayMs(2);
  134.         LcdEn_P = 1;   
  135.         DelayMs(2);
  136.         LcdEn_P = 0;
  137. }


  138. /*********************************************************/
  139. // 1602液晶初始化函数
  140. /*********************************************************/
  141. void LcdInit()
  142. {
  143.         LcdWriteCmd(0x38);        // 16*2显示,5*7点阵,8位数据口
  144.         LcdWriteCmd(0x0C);        // 开显示,不显示光标
  145.         LcdWriteCmd(0x06);        // 地址加1,当写入数据后光标右移
  146.         LcdWriteCmd(0x01);        // 清屏
  147. }


  148. /*********************************************************/
  149. // 液晶光标定位函数
  150. /*********************************************************/
  151. void LcdGotoXY(uchar line,uchar column)
  152. {
  153.         // 第一行
  154.         if(line==0)        
  155.                 LcdWriteCmd(0x80+column);
  156.         // 第二行
  157.         if(line==1)        
  158.                 LcdWriteCmd(0x80+0x40+column);
  159. }



  160. /*********************************************************/
  161. // 液晶输出字符串函数
  162. /*********************************************************/
  163. void LcdPrintStr(uchar *str)
  164. {
  165.         while(*str!='\0')
  166.                         LcdWriteData(*str++);
  167. }


  168. /*********************************************************/
  169. // 液晶输出数字
  170. /*********************************************************/
  171. void LcdPrintNum(uint num)
  172. {
  173.         LcdWriteData(num/100+0x30);                                // 百位
  174.         LcdWriteData(num%100/10+0x30);                // 十位
  175.         LcdWriteData(num%10+0x30);                                // 个位
  176. }


  177. /*********************************************************/
  178. // 在液晶上显示温度
  179. /*********************************************************/
  180. void LcdPrintTemp(int temp)
  181. {
  182.         if(temp<0)                                                                 
  183.         {
  184.                 LcdWriteData('-');                                                        // 负号        
  185.                 temp=0-temp;                                                                                // 负数转为正数
  186.         }
  187.         if(temp>999)                                                                  
  188.         {
  189.                 LcdWriteData(temp/1000+0x30);                // 百位        
  190.         }
  191.         LcdWriteData(temp%1000/100+0x30);        // 十位
  192.         LcdWriteData(temp%100/10+0x30);                // 个位
  193.         LcdWriteData('.');                                                                 // 小数点
  194.         LcdWriteData(temp%10+0x30);                                // 小数后一位
  195.         LcdWriteData(0xdf);                                                                // 摄氏度符号
  196.         LcdWriteData('C');
  197.         LcdWriteData(' ');
  198. }



  199. /*********************************************************/
  200. // 复位DS18B20(初始化)
  201. /*********************************************************/
  202. void DS18B20_ReSet(void)
  203. {
  204.         uchar i;
  205.         DQ=0;
  206.         i=240;
  207.         while(--i);
  208.         DQ=1;
  209.         i=30;
  210.         while(--i);
  211.         while(~DQ);
  212.         i=4;
  213.         while(--i);
  214. }


  215. /*********************************************************/
  216. // 向DS18B20写入一个字节
  217. /*********************************************************/
  218. void DS18B20_WriteByte(uchar dat)
  219. {
  220.         uchar j;
  221.         uchar btmp;
  222.         
  223.         for(j=0;j<8;j++)
  224.         {
  225.                 btmp=0x01;
  226.                 btmp=btmp<<j;
  227.                 btmp=btmp&dat;
  228.                
  229.                 if(btmp>0)                // 写1
  230.                 {
  231.                         DQ=0;
  232.                         Delay15us();
  233.                         DQ=1;
  234.                         Delay15us();
  235.                         Delay15us();
  236.                         Delay15us();
  237.                         Delay15us();
  238.                 }
  239.                 else                        // 写0
  240.                 {
  241.                         DQ=0;
  242.                         Delay15us();
  243.                         Delay15us();
  244.                         Delay15us();
  245.                         Delay15us();
  246.                         DQ=1;
  247.                         Delay15us();
  248.                 }
  249.         }
  250. }


  251. /*********************************************************/
  252. // 读取温度值
  253. /*********************************************************/
  254. int DS18B20_ReadTemp(void)
  255. {
  256.         uchar j;
  257.         int b,temp=0;        

  258.         DS18B20_ReSet();                                                        // 产生复位脉
  259.         DS18B20_WriteByte(0xcc);                        // 忽略ROM指令
  260.         DS18B20_WriteByte(0x44);                        // 启动温度转换指令

  261.         DS18B20_ReSet();                                                        // 产生复位脉
  262.         DS18B20_WriteByte(0xcc);                        // 忽略ROM指令
  263.         DS18B20_WriteByte(0xbe);                        // 读取温度指令

  264.         for(j=0;j<16;j++)                                                        // 读取温度数量
  265.         {                                                
  266.                 DQ=0;
  267.                 _nop_();
  268.                 _nop_();
  269.                 DQ=1;        
  270.                 Delay15us();
  271.                 b=DQ;
  272.                 Delay15us();
  273.                 Delay15us();
  274.                 Delay15us();
  275.                 b=b<<j;
  276.                 temp=temp|b;
  277.         }
  278.         
  279.         temp=temp*0.0625*10;                                        // 合成温度值并放大10倍                                       
  280.         return (temp);                                                                // 返回检测到的温度值
  281. }



  282. /*********************************************************/
  283. // 计算测到的距离
  284. /*********************************************************/
  285. uint GetDistance(void)
  286. {
  287.         uint ss;                                        // 用于记录测得的距离

  288.         TH0=0;
  289.         TL0=0;

  290.         Trig_P=1;                                        // 给超声波模块一个开始脉冲
  291.         DelayMs(1);
  292.         Trig_P=0;

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

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

  298.         if(ss>999)                                // 把检测结果限制999厘米内
  299.                 ss=999;
  300.         
  301.         return ss;
  302. }


  303. /*********************************************************/
  304. // 按键扫描
  305. /*********************************************************/
  306. void KeyScanf()
  307. {
  308.         uchar i;
  309.         uchar dat1,dat2;

  310.         if(KeySet_P==0)                                                                // 判断是否有按键按下
  311.         {
  312.                 LcdGotoXY(1,0);                                                        // 液晶第二行刷新显示
  313.                 LcdPrintStr("  alarm=   cm   ");
  314.                 LcdGotoXY(1,8);                                                        // 显示当前的报警值
  315.                 LcdPrintNum(gAlarm);                                
  316.                
  317.                 DelayMs(10);                                                                // 消除按键按下的抖动
  318.                 while(!KeySet_P);                                                // 等待按键释放
  319.                 DelayMs(10);                                                                // 消除按键松开的抖动

  320.                 i=1;

  321.                 while(i)
  322.                 {                                                         
  323.                         if(KeyDown_P==0)                // 报警值减的处理
  324.                         {
  325.                                 if(gAlarm>2)
  326.                                         gAlarm--;
  327.                                 LcdGotoXY(1,8);
  328.                                 LcdPrintNum(gAlarm);        
  329.                                 DelayMs(300);
  330.                         }

  331.                         if(KeyUp_P==0)                        // 报警值加的处理
  332.                         {
  333.                                 if(gAlarm<400)
  334.                                         gAlarm++;
  335.                                 LcdGotoXY(1,8);
  336.                                 LcdPrintNum(gAlarm);
  337.                                 DelayMs(300);
  338.                         }
  339.                         
  340.                         if(KeySet_P==0)                        // 再次按下设置键的判断
  341.                         {
  342.                                 LcdGotoXY(1,0);                                                // 液晶恢复测量时的内容显示
  343.                                 LcdPrintStr("  dist=   cm    ");
  344.                                 DelayMs(10);                                                  // 消除按键按下的抖动
  345.                                 while(!KeySet_P);                                        // 等待按键释放
  346.                                 DelayMs(10);                                                  // 消除按键松开的抖动
  347.                                 i=0;
  348.                         }                           
  349.                 }
  350.                
  351.                 dat1=gAlarm/100;
  352.                 dat2=gAlarm%100;
  353.                 Sector_Erase(0x2000);
  354.                 EEPROM_Write(0x2000,dat1);
  355.                 EEPROM_Write(0x2001,dat2);
  356.         }        
  357. }


  358. /*********************************************************/
  359. // 报警判断
  360. /*********************************************************/
  361. void AlarmJudge(uint ss)
  362. {
  363.         uchar i;
  364.         float alr1,alr2,alr3,alr4;

  365.         alr1=gAlarm/4.00*1;
  366.         alr2=gAlarm/4.00*2;
  367.         alr3=gAlarm/4.00*3;
  368.         alr4=gAlarm/4.00*4;


  369.         // 报警频率最快
  370.         if(ss<alr1)                        
  371.         {
  372.                 for(i=0;i<10;i++)
  373.                 {
  374.                         Led_P=0;
  375.                         Buzzer_P=0;
  376.                         DelayMs(50);
  377.                         Led_P=1;
  378.                         Buzzer_P=1;
  379.                         DelayMs(50);
  380.                         KeyScanf();
  381.                 }
  382.         }
  383.         // 报警频率第二快
  384.         else if(ss<alr2)               
  385.         {
  386.                 for(i=0;i<5;i++)
  387.                 {
  388.                         Led_P=0;
  389.                         Buzzer_P=0;
  390.                         DelayMs(100);
  391.                         Led_P=1;
  392.                         Buzzer_P=1;
  393.                         DelayMs(100);
  394.                         KeyScanf();
  395.                 }        
  396.         }
  397.         // 报警频率第三快
  398.         else if(ss<alr3)         
  399.         {
  400.                 for(i=0;i<2;i++)
  401.                 {
  402.                         Led_P=0;
  403.                         Buzzer_P=0;
  404.                         DelayMs(200);
  405.                         Led_P=1;
  406.                         Buzzer_P=1;
  407.                         DelayMs(200);
  408.                         KeyScanf();
  409.                 }        
  410.         }
  411.         // 报警频率最慢
  412.         else if(ss<alr4)        
  413.         {
  414.                 for(i=0;i<2;i++)
  415.                 {
  416.                         Led_P=0;
  417.                         Buzzer_P=0;
  418.                         DelayMs(300);
  419.                         Led_P=1;
  420.                         Buzzer_P=1;
  421.                         DelayMs(300);
  422.                         KeyScanf();
  423.                 }        
  424.         }
  425.         // 不报警
  426.         else
  427.         {
  428.                 Led_P=1;
  429.                 Buzzer_P=1;
  430.                 for(i=0;i<100;i++)
  431.                 {
  432.                         KeyScanf();
  433.                         DelayMs(10);
  434.                 }        
  435.         }
  436. }


  437. /*********************************************************/
  438. // 主函数
  439. /*********************************************************/
  440. void main()
  441. {
  442.         uchar dat1,dat2;
  443.         uint dist;                                                                                                // 保存超声波模块测量到的结果
  444.         int  temp;                                                                                                // 保存温度传感器测量到的结果

  445.         Trig_P=0;
  446.         
  447.         LcdInit();                                                                                                // 执行液晶初始化
  448.         TMOD = 0x01;                                                                                        // 选择定时器0,并且确定是工作方式1(为了超声波模块测量距离计时用的)
  449.         
  450.         LcdGotoXY(0,0);                                                                    // 定位到第0行第0列
  451.         LcdPrintStr("  temp=         ");        // 第0行显示“  temp=         ”
  452.         LcdGotoXY(1,0);                                                                    // 定位到第1行第0列
  453.         LcdPrintStr("  dist=   cm    ");        // 第1行显示“  dist=   cm    ”

  454.         while(DS18B20_ReadTemp()==850)                // 等待温度传感器初始化完成
  455.         {
  456.                 DelayMs(10);
  457.         }
  458.         
  459.         dat1=EEPROM_Read(0x2000);                                        // 从EEPROM读取报警值
  460.         dat2=EEPROM_Read(0x2001);
  461.         gAlarm=dat1*100+dat2;

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

  466.         while(1)
  467.         {
  468.                 temp=DS18B20_ReadTemp();                                // 获取温度传感器的温度值
  469.                 LcdGotoXY(0,7);                                                                        // 定位到第0行第7列
  470.                 LcdPrintTemp(temp);                                                        // 显示当前的温度值
  471.                
  472.                 gSpeed=0.607*(temp/10)+331.4;                // 根据公式 v=0.607T+331.4 计算出当前温度值对应的超声波速度,这时的单位是“米/秒”
  473.                 gSpeed=gSpeed/10000;                                                // 将超声波的速度从单位“m/s”转为“cm/us”,方便后面的计算
  474.                
  475.                 dist=GetDistance();                                                        // 通过超声波模块获取距离
  476.                 LcdGotoXY(1,7);                                                            // 光标定位
  477.                 LcdPrintNum(dist);                                                        // 将获取到的距离在液晶上面显示

  478.                 AlarmJudge(dist);                                                                // 判断一下是否需要报警,是的话则报警        
  479. ……………………

  480. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
0.png

所有资料51hei提供下载:

超声波测距.rar (562.6 KB, 下载次数: 212)

评分

参与人数 2黑币 +68 收起 理由
外星人11111 + 18
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:489394 发表于 2019-8-11 19:15 | 显示全部楼层
好帖子,终于找到一个能用的~
回复

使用道具 举报

ID:599361 发表于 2019-8-12 15:06 | 显示全部楼层
好帖,必须赞一个。
回复

使用道具 举报

ID:562609 发表于 2021-5-19 15:40 | 显示全部楼层
楼主分享的project.pdsprj仿真工程只能用Proteus8.8打开,有人能分享个7.5版本的吗?
回复

使用道具 举报

ID:315554 发表于 2021-5-21 17:00 | 显示全部楼层
谢谢分享,以前买了一只超声器,一直没用上,正好可以试试
回复

使用道具 举报

ID:28992 发表于 2021-5-22 08:39 | 显示全部楼层
Thank you Sir!
回复

使用道具 举报

ID:928437 发表于 2021-5-27 23:34 | 显示全部楼层
谢谢大牛的分享,很有用处
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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