找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5721|回复: 4
收起左侧

单片机超声波测距不到一米,超出50厘米就不准了,附源码

[复制链接]
ID:300215 发表于 2018-4-26 15:58 | 显示全部楼层 |阅读模式
超声波测距不到一米,超出50厘米就不准了
主程序
  1. #include "Ultrasonic.h"

  2. /*软件延时,延时时间(t*10)us*/
  3. void DelayX10us(unsigned char t)
  4. {
  5.     do {
  6.         _nop_();
  7.         _nop_();
  8.         _nop_();
  9.         _nop_();
  10.         _nop_();
  11.         _nop_();
  12.         _nop_();
  13.         _nop_();
  14.     } while (--t);
  15. }

  16. /* 获取测量数据,返回值:以毫米位单位的距离值 */
  17. unsigned int GetDistance()
  18. {
  19.     float time;
  20.     float result;

  21.     TH1 = 0;                  //定时器1清零,准备本次测距计数
  22.     TL1 = 0;
  23.     Trig = 1;                 //Trig输出高电平
  24.     DelayX10us(2);            //延时20us
  25.     Trig = 0;                 //Trig输出低电平,至此产生一个20us的脉冲信号以启动超声波模块
  26.     while(!Echo);             //等待回波信号,回波信号自动使能T1计数
  27.     while(Echo);              //等待回波信号结束,T1同时自动停止
  28.     if (TF1 == 1)             //TF1为1时说明定时器溢出了
  29.     {
  30.         TF1 = 0;              //清除标志位
  31.         time = 65535;         //溢出时,直接设置为最大计数值
  32.     }
  33.     else
  34.     {
  35.         time = TH1*256 + TL1; //未溢出时,读取其实际计数值
  36.     }
  37.     time = time * (12/11.0592) / 2;  //将计数周期转换为实际时间(us);超声波测得的是来回距离,需要除以2得到单程距离所对应的时间
  38.     result = (time/1000000) * 340;   // time(s)*速度 = 距离 ,340为声波在空气中的传播速度(m/s)
  39.     if (result > 4.0)        //判断是否超出模块的测量范围
  40.     {
  41.         result = 4.0;        //超出上限4m则设置为4m
  42.     }
  43.     else if (result < 0.02)
  44.     {
  45.         result = 0.02;       //低于下限0.02m则设置为0.02m
  46.     }
  47.     return (unsigned int)(result*1000);   //以无符号整形数返回测量结果,乘1000使其单位变为毫米
  48. }

  49. /*初始化超声波模块*/
  50. void InitUltrasonic()
  51. {
  52.     TMOD &= 0x0f;
  53.     TMOD |= 0x90;  //设置T1为方式1,GATE=1启用门控模式;
  54.     TH1 = 0;
  55.     TL1 = 0;
  56.     ET1 = 0;       //关闭T0中断
  57.     TR1 = 1;       //使能定时器,由于使用GATE位控制定时器启停,所以定时器必须打开,启停将由外部信号触发 详情参考 <手把手将你学51单片机> P59
  58.     Trig = 0;      //拉低模块触发引脚
  59. }



  60. #define  _LCD1602_C
  61. #include "Lcd1602.h"

  62. /* 等待液晶准备好 */
  63. void LcdWaitReady()
  64. {
  65.     unsigned char sta;

  66.     LCD1602_DB = 0xFF;
  67.     LCD1602_RS = 0;
  68.     LCD1602_RW = 1;
  69.     do {
  70.         LCD1602_E = 1;
  71.         sta = LCD1602_DB; //读取状态字
  72.         LCD1602_E = 0;
  73.     } while (sta & 0x80); //bit7等于1表示液晶正忙,重复检测直到其等于0为止
  74. }
  75. /* 向LCD1602液晶写入一字节命令,cmd-待写入命令值 */
  76. void LcdWriteCmd(unsigned char cmd)
  77. {
  78.     LcdWaitReady();
  79.     LCD1602_RS = 0;
  80.     LCD1602_RW = 0;
  81.     LCD1602_DB = cmd;
  82.     LCD1602_E  = 1;
  83.     LCD1602_E  = 0;
  84. }
  85. /* 向LCD1602液晶写入一字节数据,dat-待写入数据值 */
  86. void LcdWriteDat(unsigned char dat)
  87. {
  88.     LcdWaitReady();
  89.     LCD1602_RS = 1;
  90.     LCD1602_RW = 0;
  91.     LCD1602_DB = dat;
  92.     LCD1602_E  = 1;
  93.     LCD1602_E  = 0;
  94. }
  95. /* 设置显示RAM起始地址,亦即光标位置,(x,y)-对应屏幕上的字符坐标 */
  96. void LcdSetCursor(unsigned char x, unsigned char y)
  97. {
  98.     unsigned char addr;

  99.     if (y == 0)  //由输入的屏幕坐标计算显示RAM的地址
  100.     {
  101.         addr = 0x00 + x;  //第一行字符地址从0x00起始
  102.     }
  103.     else
  104.     {
  105.         addr = 0x40 + x;  //第二行字符地址从0x40起始
  106.     }
  107.     LcdWriteCmd(addr | 0x80);  //设置RAM地址
  108. }
  109. /* 在液晶上显示字符串,(x,y)-对应屏幕上的起始坐标,str-字符串指针 */
  110. void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str)
  111. {
  112.     LcdSetCursor(x, y);   //设置起始地址
  113.     while (*str != '\0')  //连续写入字符串数据,直到检测到结束符
  114.     {
  115.         LcdWriteDat(*str++);
  116.     }
  117. }

  118. /* 初始化1602液晶 */
  119. void InitLcd1602()
  120. {
  121.     LcdWriteCmd(0x38);  //16*2显示,5*7点阵,8位数据接口
  122.     LcdWriteCmd(0x0C);  //显示器开,光标关闭
  123.     LcdWriteCmd(0x06);  //文字不动,地址自动+1
  124.     LcdWriteCmd(0x01);  //清屏
  125. }




  126. #include "Ultrasonic.h"

  127. /*软件延时,延时时间(t*10)us*/
  128. void DelayX10us(unsigned char t)
  129. {
  130.     do {
  131.         _nop_();
  132.         _nop_();
  133.         _nop_();
  134.         _nop_();
  135.         _nop_();
  136.         _nop_();
  137.         _nop_();
  138.         _nop_();
  139.     } while (--t);
  140. }

  141. /* 获取测量数据,返回值:以毫米位单位的距离值 */
  142. unsigned int GetDistance()
  143. {
  144.     float time;
  145.     float result;

  146.     TH1 = 0;                  //定时器1清零,准备本次测距计数
  147.     TL1 = 0;
  148.     Trig = 1;                 //Trig输出高电平
  149.     DelayX10us(2);            //延时20us
  150.     Trig = 0;                 //Trig输出低电平,至此产生一个20us的脉冲信号以启动超声波模块
  151.     while(!Echo);             //等待回波信号,回波信号自动使能T1计数
  152.     while(Echo);              //等待回波信号结束,T1同时自动停止
  153.     if (TF1 == 1)             //TF1为1时说明定时器溢出了
  154.     {
  155.         TF1 = 0;              //清除标志位
  156.         time = 65535;         //溢出时,直接设置为最大计数值
  157.     }
  158.     else
  159.     {
  160.         time = TH1*256 + TL1; //未溢出时,读取其实际计数值
  161.     }
  162.     time = time * (12/11.0592) / 2;  //将计数周期转换为实际时间(us);超声波测得的是来回距离,需要除以2得到单程距离所对应的时间
  163.     result = (time/1000000) * 340;   // time(s)*速度 = 距离 ,340为声波在空气中的传播速度(m/s)
  164.     if (result > 4.0)        //判断是否超出模块的测量范围
  165.     {
  166.         result = 4.0;        //超出上限4m则设置为4m
  167.     }
  168.     else if (result < 0.02)
  169.     {
  170.         result = 0.02;       //低于下限0.02m则设置为0.02m
  171.     }
  172.     return (unsigned int)(result*1000);   //以无符号整形数返回测量结果,乘1000使其单位变为毫米
  173. }

  174. /*初始化超声波模块*/
  175. void InitUltrasonic()
  176. {
  177.     TMOD &= 0x0f;
  178.     TMOD |= 0x90;  //设置T1为方式1,GATE=1启用门控模式;
  179.     TH1 = 0;
  180.     TL1 = 0;
  181.     ET1 = 0;       //关闭T0中断
  182.     TR1 = 1;       //使能定时器,由于使用GATE位控制定时器启停,所以定时器必须打开,启停将由外部信号触发 详情参考 <手把手将你学51单片机> P59
  183.     Trig = 0;      //拉低模块触发引脚
  184. }
复制代码



回复

使用道具 举报

ID:213173 发表于 2018-4-26 20:57 | 显示全部楼层
这种低成本玩艺本来就是练练手的,别指望有多完美。要想性能好就买工业级的产品。
回复

使用道具 举报

ID:111634 发表于 2018-4-26 22:41 | 显示全部楼层
不是因为“低成本玩艺”,而是程序有问题。
回复

使用道具 举报

ID:317476 发表于 2018-4-26 23:50 | 显示全部楼层
没猜错的话,超过50厘米是因为定时器溢出了,建议你用双定时器,开始测量然后到收到回波,通过比较器得到精确计数,然后得到时间来算距离。
回复

使用道具 举报

ID:300215 发表于 2018-4-28 12:10 | 显示全部楼层
zzzy 发表于 2018-4-26 23:50
没猜错的话,超过50厘米是因为定时器溢出了,建议你用双定时器,开始测量然后到收到回波,通过比较器得到精 ...

能不能说的再清楚点
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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