找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1631|回复: 0
收起左侧

带详细注释的单片机超声波测距源程序

[复制链接]
ID:424544 发表于 2018-11-11 16:11 | 显示全部楼层 |阅读模式
超声波单片机源程序如下:
  1. /*-----------------------------------------------
  2.   说明:
  3.         功能:超声波测距,DS18b20矫正;数码管显示
  4.         晶振:12MHz
  5.         测量范围:1CM - 500CM
  6.         温度显示:0.0 C - 99.9 C
  7.         警报范围设置:5CM - 400CM(可以永久存储设定值)
  8. ------------------------------------------------*/
  9. #include "reg52.h" //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
  10. #include "18b20.h"
  11. #include "eeprom.h"
  12. #include "delay.h"

  13. #define DataPort P0 //定义数据端口 程序中遇到DataPort 则用P1 替换
  14. sbit DUAN=P2^6;//定义锁存使能端口 段锁存
  15. sbit WEI=P2^7;//                 位锁存

  16. /***************超声波引脚定义******************/
  17. sbit Echo = P3 ^ 3;         //回波引脚
  18. sbit Trig = P1 ^ 5;         //触发引脚

  19. sbit buzzer = P1 ^ 0;    //蜂鸣器引脚
  20. /*****************按键定义**********************/
  21. uchar bdata key,key1,lastkey;
  22. bit key1Mark;//设置键标志

  23. /*****************测距变量**********************/
  24. uchar EchoTimeH,EchoTimeL;  //自定义寄存器存储8位回波时间
  25. uint Distance,EchoTime;            //测量距离,回波总时间
  26. uint Distance_Alarm;                                //报警距离通过自己设定(初始为0)
  27. bit succeed_flag;                              //测量成功标志

  28. uchar code Table[18] = //段码表
  29. {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};// 显示段码值0~9
  30. uchar code WeiMa[4]={0xfe,0xfd,0xfb,0xf7};         //分别对应相应的数码管点亮,即位码

  31. uint Temperature,temp;//读取温度
  32. bit flag200ms,flag300ms;//获取时间标志

  33. /*****************显示变量**********************/
  34. uint DispData;
  35. uchar TempData[4]; //存储显示值的全局变量
  36. uchar mod;//显示模式切换

  37. /*****************函数声明**********************/
  38. void delay_20us();                                                                //20us延迟
  39. void CountDat(uint ShowData);                        //显示数据处理
  40. void readkey();                                                                                //按键读取
  41. void CountKey();                                                                        //显示散转
  42. void CSBFunction();                                                                //超声波测距
  43. void Display();                                                                                //数码管显示函数
  44. void Init_Timer0(void);                                                //定时器0初始化

  45. /*------------------------------------------------
  46.                     主函数
  47. ------------------------------------------------*/
  48. void main (void)
  49. {                         
  50.         float speed = 0;

  51.         buzzer=1;     //初始化蜂鸣器引脚
  52.         Trig=0;       //首先拉低脉冲输入引脚
  53.         TMOD|=0x11;    //定时器0,定时器1,16位工作方式
  54.   IT1=0;        //低电平触发外部中断
  55.         EX1=0;        //关闭外部中断
  56.   Init_Timer0();
  57.         ISP_IAP_readData(0x2ff0,ReadBuf,2);
  58.         Distance_Alarm = ReadBuf[0] | (ReadBuf[1] << 8);//读取警报距离值
  59.         while (1)         //主循环
  60.   {
  61.                 CSBFunction();        //开始测距
  62.                 if(succeed_flag)
  63.     {
  64.                         succeed_flag=0; //清测量成功标志        
  65.                    EchoTime = (EchoTimeH << 8) | EchoTimeL;                //与低8位合并成为16位结果数据
  66.                         //公式说明: 1、V=(331.4+0.61*T)*D/2000000 CM;2、回波时间D是us单位,最终
  67.                         //距离以CM单位要除以20000,这里为了减小计算量转成uchar,先/200,再/100;
  68.                         speed = (331.4 + 0.61 * (TempData[0]*10+TempData[1])) / 200;
  69.                          Distance = (EchoTime * speed) / 100;     //算出来是CM
  70.                         CountDat(DispData);//计算需要显示数据的各个位
  71.     }
  72.                 if(mod != 2)
  73.                         readkey();//按键读取,警报时显示温度不能设定
  74.                 CountKey();//报警距离设置
  75.                 if(flag200ms)
  76.                 {
  77.                         flag200ms = 0;
  78.                         temp = ReadTemperature();//
  79.                         Temperature = temp * 6;//小数近似处理,采用中间变量temp是防止中断导致最终温度值异常
  80.                         if(Distance < Distance_Alarm)
  81.                         {
  82.                                 buzzer = 0;mod = 2;
  83.                         }
  84.                         else
  85.                         {
  86.                                 buzzer = 1;
  87.                                 if(!key1Mark)
  88.                                         mod = 0;
  89.                         }
  90.                 }                                                 //蜂鸣器产生300Hz频率
  91.                 if(flag300ms)
  92.                 {
  93.                         flag300ms = 0;
  94.                         if(Distance < Distance_Alarm)
  95.                         {
  96.                                 buzzer = 1;
  97.                         }
  98.                 }
  99.         }
  100. }

  101. /*------------------------------------------------

  102. 显示函数,用于动态扫描数码管

  103. ------------------------------------------------*/
  104. void Display()
  105. {
  106.         static unsigned char i=0;

  107.         DataPort=0;   //清空数据,防止有交替重影
  108.         DUAN=1;     //段锁存
  109.         DUAN=0;
  110.        
  111.         DataPort=WeiMa[i]; //取位码
  112.         WEI=1;     //位锁存
  113.         WEI=0;

  114.         if((i == 1) && (mod == 2))       
  115.         {
  116.                 DataPort = Table[TempData[i]] & 0xef;//温度显示点
  117.         }
  118.         else
  119.         {
  120.                 DataPort = Table[TempData[i]] ; //取显示数据,段码
  121.         }
  122.         DUAN=1;     //段锁存
  123.         DUAN=0;
  124.        
  125.         i ++;
  126.         if(i == 4)
  127.                 i = 0;
  128. }
  129. //******************************************************************
  130. //20us短延时
  131. void delay_20us()
  132. {   
  133.         uchar bt;
  134.         for(bt=0;bt<20;bt++);
  135. }
  136. /*
  137. 处理需要显示的数据
  138. 入口参数:ShowData
  139. */
  140. void CountDat(uint ShowData)
  141. {
  142.         EA=0;
  143.         TempData[0] =  ShowData / 1000 % 10;
  144.         TempData[1] =  ShowData / 100 % 10;
  145.         TempData[2] =  ShowData / 10 % 10;
  146.         TempData[3] =  ShowData % 10;
  147.         EA=1;
  148. }
  149. /*扫描K1 - K3*/
  150. void readkey()                 
  151. {
  152.         static uchar keycnt = 0;
  153.         uchar R0,R1;

  154.         P3 |= 0x07;                                                         //51单片机作为输入时先置相应位位1
  155.         R0 = (P3 ^ 0x07) & 0x07; //将键值转换成正逻辑
  156.         keycnt ++;          
  157.         if(R0)
  158.         {
  159.                 if(keycnt > 1) //用做延迟,根据MCU速度进行调整
  160.                 {
  161.                         keycnt = 0;
  162.                          key1 = R0;
  163.                 }
  164.                 else
  165.                 {
  166.                         key1 = key;
  167.                 }
  168.         }
  169.         else
  170.         {
  171.                 key1 = 0;                //无按键按下都为0
  172.                 keycnt = 0;
  173.         }  
  174.         R1 = key1;
  175.         key1 = key1 & (key ^ key1);//key^key1判断键值有0变1,或1变0;再&key1若key1不为0则有按键按下(由0变1)
  176.         key = R1;               
  177. }
  178. /*读取按键后,根据键值处理数据*/
  179. void CountKey()
  180. {
  181.         switch(key1)
  182.         {
  183.                 case 0x01:if(!key1Mark){mod = 1;key1Mark = 1;}
  184.                                                         else
  185.                                                         {
  186.                                                                 mod = 0;key1Mark = 0;
  187.                                                                 WriteBuf[0] = Distance_Alarm & 0xff; WriteBuf[1] = (Distance_Alarm >> 8) & 0xff;
  188.                                                                 ISP_IAP_sectorErase(0x2e00);//扇区擦除,一块512字节         
  189.                                                     ISP_IAP_writeData(0x2ff0,WriteBuf,2);  //写警报值到 EEPROM
  190.                                                         }
  191.                         break;
  192.                 case 0x02:if(mod == 1){Distance_Alarm += 5;if(Distance_Alarm > 400)Distance_Alarm=400;}                               
  193.                         break;
  194.                 case 0x04:if(mod == 1){Distance_Alarm -= 5;if(Distance_Alarm < 5)Distance_Alarm=5;}
  195.                         break;
  196.                 default : break;
  197.         }
  198.         switch(0)                 //数据显示模式散转
  199.         {
  200.                 case 0:DispData = Distance;        //正常默认下显示测得的距离
  201.                         break;
  202.                 case 1:DispData =  Distance_Alarm;        //设置模式下显示警报距离
  203.                         break;
  204.                 case 2:DispData = Temperature;        //警报下显示当前温度值
  205.                         break;
  206.                 default : break;
  207.         }
  208. }
  209. /*超声波测距*/
  210. void CSBFunction()
  211. {
  212.         EA=0;
  213.         Trig=1;
  214.         delay_20us();
  215.         Trig=0;         //产生一个20us的脉冲,在Trig引脚
  216.         while(Echo==0); //等待Echo回波引脚变高电平,高电平持续的时间就是超声波从发射到返回的时间
  217.         {
  218.           EX1=1;          //打开外部中断
  219.                 TH1=0;          //定时器1清零
  220.           TL1=0;          //定时器1清零
  221.           TF1=0;         
  222.           TR1=1;          //启动定时器1
  223.                 EA=1;
  224.         }
  225.         while(TH1 < 255);//等待测量的结果,周期65.535毫秒(可用中断实现),在这段时间内等待外部中断
  226.         {
  227.                 TR1=0;          //关闭定时器1
  228.           EX1=0;          //关闭外部中断
  229.         }
  230. }
  231. /*------------------------------------------------
  232.             定时器初始化子程序
  233. ------------------------------------------------*/
  234. void Init_Timer0(void)
  235. {
  236.         TMOD |= 0x01;          //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响                     
  237.         TH0=(65536-2000)/256;                  //给定初值 2ms
  238.         TL0=(65536-2000)%256;
  239.         EA=1;            //总中断打开
  240.         ET0=1;           //定时器中断打开
  241.         TR0=1;           //定时器开关打开
  242. }
  243. /*------------------------------------------------
  244.                  定时器中断子程序
  245. ------------------------------------------------*/
  246. void Timer0_isr(void) interrupt 1
  247. {
  248.         static unsigned char Cnt200ms,Cnt300ms;
  249.         TH0=(65536-2000)/256;                  //重新赋值 2ms
  250.         TL0=(65536-2000)%256;

  251.         Display();       // 调用数码管扫描
  252.         Cnt200ms ++;
  253.         if(Cnt200ms == 100)
  254.         {
  255.                 Cnt200ms = 0;
  256.                 flag200ms = 1;
  257.                 Cnt300ms ++;
  258.                 if(Cnt300ms == 3)
  259.                 {
  260.                         Cnt300ms = 0;
  261.                         flag300ms = 1;       
  262.                 }
  263.         }
  264. }
  265. //***************************************************************
  266. //外部中断1,用做判断回波电平,低电平引发中断,得到高电平的持续时间
  267. INT1_()  interrupt 2   // 外部中断
  268. {   
  269.         EchoTimeH = TH1;    //取出定时器的值
  270.         EchoTimeL = TL1;    //取出定时器的值
  271.         succeed_flag = 1;  //置成功测量的标志
  272.         EX1=0;             //关闭外部中断
  273. }
复制代码

所有资料51hei提供下载:
eeprom超声波.rar (57.28 KB, 下载次数: 15)
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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