找回密码
 立即注册

QQ登录

只需一步,快速开始

帖子
查看: 4971|回复: 0
打印 上一主题 下一主题
收起左侧

超声波测距仪原理图和单片机程序

[复制链接]
跳转到指定楼层
楼主


原理图下载:
PDF格式 模块超声波测距仪.pdf (123.7 KB, 下载次数: 11)

  1. #include <reg51.h>         
  2. #define uchar unsigned char  
  3. #define uint  unsigned int  
  4. #include <intrins.h>

  5. //数码管段选定义      0     1    2    3    4    5 6  7   8    9
  6. uchar code smg_du[]={0x28,0xee,0x32,0xa2,0xe4,0xa1,0x21,0xea,0x20,0xa0,
  7.         0x60,0x25,0x39,0x26,0x31,0x71,0xff};  //断码

  8. uchar dis_smg[8]   ={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8};
  9. //数码管位选定义
  10. sbit smg_we1 = P3^4;     //数码管位选定义
  11. sbit smg_we2 = P3^5;
  12. sbit smg_we3 = P3^6;
  13. sbit smg_we4 = P3^7;
  14. uint code wendu_buchang1[46] = {       //温度补偿表格
  15. 331,332,333,333,334,334,335,336,336,337, // 0-9度
  16. 337,338,339,339,340,341,341,342,342,343, //10-19度
  17. 343,344,345,345,346,346,347,348,348,349, //20-29度
  18. 349,350,351,351,352,352,353,354,354,355, //30-39度
  19. 355,356,357,357,358,358      //40-45度
  20. };

  21. sbit dq   = P2^4; //18b20 IO口的定义
  22. uint temperature ;  //

  23. sbit c_send   = P3^2;  //超声波发射
  24. sbit c_recive = P3^3;  //超声波接收
  25. sbit beep = P2^3;   //蜂鸣器IO口定义
  26. uchar smg_i = 3;    //显示数码管的个位数
  27. bit flag_300ms ;
  28. long distance;         //距离
  29. uint set_d;             //距离
  30. uchar flag_csb_juli;    //超声波超出量程
  31. uint  flag_time0;       //用来保存定时器0的时候的
  32. uchar menu_1;           //菜单设计的变量
  33. /*sfr WDT_CONTR=0xe1;*/   //看门狗(watch-dog-Timer)控制器

  34. /***********************小延时函数*****************************/
  35. void delay_uint(uint q)
  36. {
  37. while(q--);
  38. }

  39. /***********************1ms延时函数*****************************/
  40. void delay_1ms(uint q)
  41. {
  42. uint i,j;
  43. for(i=0;i<q;i++)
  44.   for(j=0;j<120;j++);
  45. }
  46. /***********************处理距离函数****************************/
  47. void smg_display()
  48. {
  49. dis_smg[0] = smg_du[distance % 10];
  50. dis_smg[1] = smg_du[distance / 10 % 10];
  51. dis_smg[2] = smg_du[distance / 100 % 10] & 0xdf; ;
  52. }
  53. /********************独立按键程序*****************/
  54. uchar key_can;  //按键值
  55. void key()  //独立按键程序
  56. {
  57. static uchar key_new;
  58. key_can = 20;                   //按键值还原
  59. P2 |= 0x07;
  60. if((P2 & 0x07) != 0x07)  //按键按下
  61. {
  62.   delay_1ms(1);       //按键消抖动
  63.   if(((P2 & 0x07) != 0x07) && (key_new == 1))
  64.   {      //确认是按键按下
  65.    key_new = 0;
  66.    switch(P2 & 0x07)
  67.    {
  68.     case 0x06: key_can = 3; break;    //得到k2键值
  69.     case 0x05: key_can = 2; break;    //得到k3键值
  70.     case 0x03: key_can = 1; break;    //得到k4键值
  71.    }
  72.   }   
  73. }
  74. else
  75.   key_new = 1;
  76. }
  77. /****************按键处理显示函数***************/
  78. void key_with()
  79. {
  80. if(key_can == 1)  //设置键
  81. {
  82.   menu_1 ++;
  83.   if(menu_1 >= 3)
  84.   {
  85.    menu_1 = 0;
  86.    smg_i = 3;  //只显示3位数码管
  87.   }
  88.   if(menu_1 == 1)
  89.   {
  90.    smg_i = 4;    //只显示4位数码管
  91.   }
  92. }
  93. if(menu_1 == 1)   //设置报警
  94. {
  95.   if(key_can == 2)
  96.   {
  97.    set_d ++ ;  //加1
  98.    if(set_d > 400)
  99.     set_d = 400;
  100.   }
  101.   if(key_can == 3)
  102.   {
  103.    set_d -- ;  //减1
  104.    if(set_d <= 1)
  105.     set_d = 1;
  106.   }
  107.   dis_smg[0] = smg_du[set_d % 10];            //取小数显示
  108.   dis_smg[1] = smg_du[set_d / 10 % 10] ;         //取个位显示
  109.   dis_smg[2] = smg_du[set_d / 100 % 10] & 0xdf ; //取十位显示
  110.   dis_smg[3] = 0x60;         //a
  111. }
  112. }  
  113. /***********************18b20初始化函数*****************************/
  114. void init_18b20()
  115. {
  116. bit q;
  117. dq = 1;    //把总线拿高
  118. delay_uint(1);     //15us
  119. dq = 0;    //给复位脉冲
  120. delay_uint(80);  //750us
  121. dq = 1;    //把总线拿高 等待
  122. delay_uint(10);  //110us
  123. q = dq;    //读取18b20初始化信号
  124. delay_uint(20);  //200us
  125. dq = 1;    //把总线拿高 释放总线
  126. }
  127. /*************写18b20内的数据***************/
  128. void write_18b20(uchar dat)
  129. {
  130. uchar i;
  131. for(i=0;i<8;i++)
  132. {      //写数据是低位开始
  133.   dq = 0;    //把总线拿低写时间隙开始
  134.   dq = dat & 0x01; //向18b20总线写数据了
  135.   delay_uint(5);  // 60us
  136.   dq = 1;    //释放总线
  137.   dat >>= 1;
  138. }
  139. }
  140. /*************读取18b20内的数据***************/
  141. uchar read_18b20()
  142. {
  143. uchar i,value;
  144. for(i=0;i<8;i++)
  145. {
  146.   dq = 0;    //把总线拿低读时间隙开始
  147.   value >>= 1;  //读数据是低位开始
  148.   dq = 1;    //释放总线
  149.   if(dq == 1)   //开始读写数据
  150.    value |= 0x80;
  151.   delay_uint(5);  //60us 读一个时间隙最少要保持60us的时间
  152. }
  153. return value;   //返回数据
  154. }
  155. /*************读取温度的值 读出来的是小数***************/
  156. uint read_temp()
  157. {
  158. uint value;
  159. uchar low;      //在读取温度的时候如果中断的太频繁了,就应该把中断给关了,否则会影响到18b20的时序
  160. init_18b20();     //初始化18b20
  161. write_18b20(0xcc);    //跳过64位ROM
  162. write_18b20(0x44);    //启动一次温度转换命令
  163. delay_uint(50);     //500us
  164. init_18b20();     //初始化18b20

  165. write_18b20(0xcc);    //跳过64位ROM
  166. write_18b20(0xbe);    //发出读取暂存器命令

  167. EA = 0;
  168. low = read_18b20();    //读温度低字节
  169. value = read_18b20();  //读温度高字节
  170. EA = 1;
  171. value <<= 8;     //把温度的高位左移8位
  172. value |= low;     //把读出的温度低位放到value的低八位中
  173. value *= 0.0625;        //转换到温度值
  174. return value;     //返回读出的温度
  175. }

  176. /****************报警函数***************/
  177. void clock_h_l()
  178. {
  179. static uchar value;
  180. if(distance <= set_d)
  181. {
  182.   value ++;  //消除实际距离在设定距离左右变化时的干扰
  183.   if(value >= 2)
  184.   {
  185.    beep = ~beep;    //蜂鸣器报警
  186.   }
  187. }
  188. else
  189. {
  190.   value = 0;
  191.   beep = 1;  //取消报警
  192. }
  193. }
  194. /***********************数码位选函数*****************************/
  195. void smg_we_switch(uchar i)
  196. {
  197. switch(i)
  198. {
  199.   case 0: smg_we1 = 0;  smg_we2 = 1; smg_we3 = 1;  smg_we4 = 1; break;
  200.   case 1: smg_we1 = 1;  smg_we2 = 0; smg_we3 = 1;  smg_we4 = 1; break;
  201.   case 2: smg_we1 = 1;  smg_we2 = 1; smg_we3 = 0;  smg_we4 = 1; break;
  202.   case 3: smg_we1 = 1;  smg_we2 = 1; smg_we3 = 1;  smg_we4 = 0; break;
  203. }
  204. }
  205. /***********************数码显示函数*****************************/
  206. void display()
  207. {
  208. static uchar i;   
  209. i++;
  210. if(i >= smg_i)
  211.   i = 0;
  212. smg_we_switch(i);   //位选
  213. P1 = dis_smg[i];   //段选         
  214. }
  215. /******************小延时函数*****************/
  216. void delay()
  217. {
  218. _nop_();              //执行一条_nop_()指令就是1us
  219. _nop_();
  220. _nop_();
  221. _nop_();
  222. _nop_();
  223. _nop_();
  224. _nop_();
  225. _nop_();
  226. _nop_();  
  227. _nop_();
  228. }

  229. /*********************超声波测距程序*****************************/
  230. void send_wave()
  231. {
  232. c_send = 1;             //10us的高电平触发
  233. delay();
  234. c_send = 0;  
  235. TH0 = 0;            //给定时器0清零
  236. TL0 = 0;
  237. TR0 = 0;      //关定时器0定时
  238. while(c_recive);    //当c_recive为1等待
  239. TR0=1;
  240. while(!c_recive)        //当c_recive为0等待
  241. {
  242.   flag_time0 = TH0 * 256 + TL0;
  243.   if((flag_time0 > 40000))      //当超声波超过测量范围时,显示3个888
  244.   {
  245.    TR0 = 0;
  246.    flag_csb_juli = 2;
  247.    distance = 888;
  248.    break ;  
  249.   }
  250.   else
  251.   {
  252.    flag_csb_juli = 1;
  253.   }
  254. }
  255. if(flag_csb_juli == 1)
  256. {
  257.   TR0=0;        //关定时器0定时
  258.   distance =flag_time0;    //读出定时器0的时间
  259.   if(temperature <= 45)
  260.    distance *= wendu_buchang1[temperature] / 2.0 * 0.0001;               // 0.017 = 340M / 2 = 170M = 0.017M 算出来是米
  261.   else
  262.    distance *= 358 / 2.0 * 0.0001;         // 0.017 = 340M / 2 = 170M = 0.017M 算出来是米
  263.   if((distance > 500))     //距离 = 速度 * 时间
  264.   {
  265.    distance = 888;     //如果大于5.0m就超出超声波的量程
  266.   }
  267. }  
  268. }

  269. /*********************定时器0、定时器1初始化******************/
  270. void time_init()   
  271. {
  272. EA  = 1;     //开总中断
  273. TMOD = 0X11;   //定时器0、定时器1工作方式1
  274. ET0 = 0;    //关定时器0中断
  275. TR0 = 1;    //允许定时器0定时
  276. ET1 = 1;    //开定时器1中断
  277. TR1 = 1;    //允许定时器1定时
  278. }

  279. /***************主函数*****************/
  280. void main()
  281. {
  282. beep = 0;   //开机叫一声   
  283. delay_1ms(150);
  284. P0 = P1 = P2 = P3 = 0xff;    //初始化单片机IO口为高电平
  285. time_init(); //定时器初始化程序
  286.     init_18b20();

  287. /*send_wave();
  288. smg_display(); //处理距离显示函数
  289. /*time_init(); //定时器初始化程序
  290. send_wave(); //测距离函数
  291. send_wave();*/ //测距离函数
  292. do
  293. {   
  294.   if(flag_300ms == 0)
  295.   {  
  296.    flag_300ms = 0;
  297.    clock_h_l();    //报警函数
  298.    temperature = read_temp(); //先读出温度的值
  299.    if(beep == 1)
  300.     send_wave(); //测距离函数
  301.    if(menu_1 == 0)
  302.     smg_display();  //处理距离显示函数
  303.    if(menu_1 == 2)   //显示温度   
  304.    {
  305.     dis_smg[0] = 0xf0;  
  306.     dis_smg[1] = smg_du[temperature % 10];             //取温度的个位显示
  307.     dis_smg[2] = smg_du[temperature / 10 % 10] ;    //取温度的十位显示  
  308.     dis_smg[3] = 0xFF;
  309.     smg_display();
  310.    }
  311.   }
  312.   key();      //按键函数
  313.   if(key_can < 10)
  314.   {
  315.    key_with();    //按键处理函数
  316.   }
  317. }while(1);
  318. }
  319. /*********************定时器1中断服务程序************************/
  320. void time1_int() interrupt 3
  321. {
  322. static uchar value;    //定时2ms中断一次
  323. TH1 = 0xf8;
  324. TL1 = 0x30;     //2ms
  325. display();  //数码管显示函数
  326. value++;
  327. if(value >= 150)
  328. {
  329.   value = 0;
  330.   flag_300ms = 1;
  331. }
  332. }
复制代码


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

举报

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

本版积分规则

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

Powered by 单片机教程网

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