木槿呀 2024-03-30 11:28 采纳率: 72.2%
浏览 55

蓝桥杯超声波测距,最多只能测70cm ?更大就显示231,为什么?

我在学习蓝桥杯单片机超声波测距模块时,发现我最多只能测到70cm左右,再大的话,数码管就显示231了,可是按我写的代码来说溢出的话应该显示999呀?而且测70cm就溢出了吗?好奇怪呀?
mian.c

#include<STC15F2K60S2.H>
#include"hardware.h"
#include"intrins.h"
sbit TX=P1^0;
sbit RX=P1^1;
unsigned int distance=0;
//------------------------------------------------------------------
void Delay14us()        //@12.000MHz
{
    unsigned char i;

    _nop_();
    _nop_();
    i = 39;
    while (--i);
}
//------------------------------------------------------------------
void sendwave()//产生8个超声波信号,通过TX引脚发射出去
{
  unsigned char i;
  for(i=0;i<8;i++)
  {
    TX=1;
    Delay14us();
    TX=0;
    Delay14us();
  }
}
//-----------------------------------------------------------------
unsigned char csb_read()//超声波测距
{
  unsigned int dis=0;
  TH1=0x00; 
  TL1=0x00;//计数初值设为0
  sendwave();//发送8个超声波
  TR1=1;//开始计数
  while((RX==1)&&(TF1==0));//当接收到超声波且计数未溢出时
  TR1=0; //关闭计数
  if(TF1==0)//未溢出
  {
    
    dis=(TH1<<8|TL1)*0.017+0.5;//计算距离
  }
  else//溢出
  {
    TF1=0;//溢出标志置0
    dis=999;//距离为999(最大值)
  }
  return dis;
}
//------------------------------------------------------------------
void SMG_display()
{
  SMG_buf[0]=32;
  SMG_buf[1]=16;
  SMG_buf[2]=16;
  SMG_buf[3]=16;
  SMG_buf[4]=16;
  if(distance/100!=0)
  {
   SMG_buf[5]=distance/100;
   SMG_buf[6]=distance%100/10;
   SMG_buf[7]=distance%10;
  }
  else if(distance/10!=0)
  {
    SMG_buf[5]=16;
    SMG_buf[6]=distance/10;
    SMG_buf[7]=distance%10;
  }
  else 
  {
    SMG_buf[5]=16;
    SMG_buf[6]=16;
    SMG_buf[7]=distance;
  }
}
//------------------------------------------------------------------
void main()
{
   led_output();
   ws_output();
   Timer0Init();
   Timer1Init();
   while(1)
   {
      SMG_display();
         if(timer500ms>=125)
      {
        timer500ms=0;
        distance=csb_read();
      }
   }
}

hardware.c

#include<STC15F2K60S2.H>
#include"hardware.h"
/*************  本地常量声明    **************/
unsigned char code t_display[]={                       //标准字库
//   0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
    0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,
//black  -     H    J    K    L    N    o   P    U     t    G    Q    r   M    y  超声波标志
    0x00,0x40,0x76,0x1E,0x70,0x38,0x37,0x5C,0x73,0x3E,0x78,0x3d,0x67,0x50,0x37,0x6e, 0x3c,
    0xBF,0x86,0xDB,0xCF,0xE6,0xED,0xFD,0x87,0xFF,0xEF,0x46};    //0. 1. 2. 3. 4. 5. 6. 7. 8. 9. -1

unsigned char code T_COM[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};      //位码
unsigned char led_buf=0xff;
unsigned char ws_buf=0x00;
unsigned char SMG_buf[]={16,16,16,16,16,16,16,16};
unsigned int timer10ms=0;
unsigned int timer10ms2=0;
unsigned int timer500ms=0;
unsigned char key_stat=0;
unsigned char key_value=0;
bit bz_5s=0;
bit bz_50ms=0;
//----------------------------------------------------------------------
void Timer0Init()        //1毫秒@12.000MHz
{
    AUXR |= 0x80;        //定时器时钟1T模式
    TMOD &= 0xF0;        //设置定时器模式
    TL0 = 0x20;        //设置定时初值
    TH0 = 0xD1;        //设置定时初值
    TF0 = 0;        //清除TF0标志
    TR0 = 1;        //定时器0开始计时
    ET0=1;
    EA=1;
}
void Timer1Init()        //@12.000MHz       ////每次计数相当于1us
{
    AUXR &= 0xBF;            //定时器时钟12T模式
    TMOD &= 0x0F;            //设置定时器模式
    TF1 = 0;                //清除TF1标志
}
//---------------------------------------------------------------------
void SelectHC573(unsigned char channel)
{
    switch(channel)
    {
       case 4:
         P2=(P2 & 0x1f)|0x80;
       break;
       case 5:
         P2=(P2 & 0x1f)|0xa0;
       break;
       case 6:
         P2=(P2 & 0x1f)|0xc0;
       break;
       case 7:
         P2=(P2 & 0x1f)|0xe0;
       break;
       case 0:
         P2=(P2 & 0x1f)|0x00;
       break;
    }
}
//---------------------------------------------------------------------
void led_output()
{          
    P0=led_buf;
    SelectHC573(4);
    SelectHC573(0);
}
//---------------------------------------------------------------------
void ws_output()
{
       
    P0=ws_buf;
    SelectHC573(5);
    SelectHC573(0);
}
//---------------------------------------------------------------------
void SMG_output()
{
   static unsigned char SMG_com=0;

       
    P0=0x00;
    SelectHC573(6);
    SelectHC573(0);

    
    P0=T_COM[SMG_com];
    SelectHC573(6);
    SelectHC573(0);

    
    P0=~t_display[SMG_buf[SMG_com]];
    SelectHC573(7);
    SelectHC573(0);

    if(++SMG_com>=8)
    {
      SMG_com=0;
    }
}
//---------------------------------------------------------------------
void ServiceTimer0()interrupt 1
{
    SMG_output();
    timer10ms++;
    timer10ms2++;
    timer500ms++;
}
//----------------------------------------------------------------------
void Scankey()
{
  P3|=0x0f;
  if(~P3&0x0f)
  {
     if(key_stat<255)
       key_stat++;
     if(P33==0)
       key_value=4;
     if(P32==0)
       key_value=5;
     if(P31==0)
       key_value=6;
     if(P30==0)
       key_value=7;
  }
  else 
  {
    key_stat=0;
    key_value=0;
  }
}

  • 写回答

2条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2024-03-30 11:28
    关注

    引自免费微信小程序:皆我百晓生

    在您的代码中,您有一个名为CSB_read()的函数,用于读取并显示超声波测距结果。根据您的描述,该函数接收一个参数:unsigned int distance,表示当前测距的距离。下面是修复您在最短时间内只能测量70厘米并且不再显示数字231的原因,并实现上述功能的解决方案。

    首先,我们分析可能的问题:

    1. 计算结果没有正确地进行除法运算:代码中没有将测距值 distance 除以100,导致输出结果不会随着距离的增加而逐渐递减。
    2. 溢出判断逻辑不准确:检测到接收到超声波但未溢出时,计算距离会一直减小,直到达到最小值(即70厘米),此时输出应变为999而不是231。
    3. 程序在处理超声波检测到结束信号(断电)后,没有重新开始计数,继续调用 CSB_read() 函数进行重复的计数操作。

    解决这些问题的步骤如下:

    1. 修改计算距离的代码,使其同时处理测距值和除法运算:
    unsigned int distance=0;
    while(distance<=70) { // 判断测距值是否小于或等于70厘米
        if(distance % 10 != 0) { // 如果距离不是10的倍数,则跳过
            break;
        }
    
        distance /= 10; // 将距离除以10,确保数字递减
    }
    
    distance /= 100; // 将距离除以100,确保距离更接近70厘米
    
    // 输出结果
    cout << "Distance: " << distance << endl;
    
    1. 对于溢出判断逻辑,我们在 sendwave() 函数中检查接收到的超声波信号是否有效,即信号的周期和长度与设定的超声波间隔相匹配。如果超声波信号的有效性出现问题,程序应该返回false,并在主循环外重新启动计数器,以便检查下一个超声波信号的有效性。以下是修改后的sendwave()函数:
    unsigned char csb_read() { // 连续发送8个超声波信号
        unsigned char i;
        while(((RX == 1 && TF1 == 0)) || (TF1 == 1)) { // 当接收到超声波且计数未溢出或已溢出时
            sendwave(); // 发射8个超声波
            TF1 = 0; // 清除TF1标志
        }
    
        while((TF1 == 1 && TR1 == 0)); // 当接收到超声波且计数未溢出或已溢出时
        TR1 = 0; // 关闭计数
        if(TF1 == 1) { // 未溢出
            while(TF1 == 0); // 当接收到超声波且计数未溢出时
            if(TF1 == 1) { // 已溢出
                CSB_read(); // 再次请求超声波检测
            } else { // 若已经连续3次未成功发出超声波,断开超声波连接
                cout << "Scan interrupted due to power loss." << endl;
                break;
            }
        } else { // 溢出
            cout << "Error reading from sensor." << endl;
            return false;
        }
    }
    
    unsigned char csb_write() { // 使用四位十六进制表示超声波信号
        unsigned char i;
        for(i=0;i<8;i++) { // 连续产生8个四舍五入的十进制十六进制值
            csb_read(); // 获取当前测距结果
            csb_write(HIGH | LOW); // 三位二进制表示超声波信号
            delayMicroseconds(100); // 暂停100微秒
            csb_write(LOW | HIGH); // 同上
        }
    }
    
    void main() {
        LedOutput();
       (ws_output());
        Timer0Init();
    
        while(1) { // 主循环
            while(!KeyState()) { // 处理无按键输入
                delay(100); // 暂停100微秒
            }
    
            SMG_display(); // 显示超声波测距结果
            KeyState(); // 更新键状态为等待按键按下
    
            if(timer500ms >= 125) { // 当定时器1计时器500ms达到125毫秒时,释放定时器1并开始定时器2
                Timer1Reset(); // 清除定时器1定时标志
                timer2Start(); // 开始定时器2
            }
    
            SelectHC573(4); // 根据当前通道选择适当的HCM573定时器
            SelectHC573(0); // 设置初始模式
    
            do {
                P3|=0x0f; // 引导输入低电平
                ReadKeyStat(); // 阻止用户输入,获取当前状态字节
                if(key_stat < 255) { // 当按键状态小于255时,将状态字节存储到`key_stat`变量中
                    key_stat = key_stat + 1;
                } else if(key_stat == 255) { // 当按键状态等于255时,释放`key_stat`变量中的状态字节
                    key_stat = 255;
                } else if(key_stat > 255) { // 当按键状态大于255时,忽略状态字节,因为这是无效的状态字节
                    break;
                }
    
                P3&=~key_stat; // 引导输入高电平
                SMG_output(); // 向所有设备同步显示结果
                key_stat = key_stat - 1; // 每隔100微秒更新键状态
    
                if(key_stat == 255) { // 当按键状态等于255时,释放`key_stat`变量中的状态字节
                    key_stat = 255;
                } else if(key_stat > 255) { // 当按键状态大于255时,忽略状态字节,因为这是无效的状态字节
                    break;
                }
            } while(!KeyUp()); // 当用户松开任意键后,退出主循环
        }
    }
    

    在此示例中,我们创建了一个名为CSB_read()的函数,用于读取超声波测距结果,然后对这些结果进行处理。主要修改点包括:

    • 计算距离的逻辑修改:我们将distance除以100,并且在每次间隔100微秒时递减相应的距离,以便得到精确的厘米级距离值。
    • 操作超声波信号的逻辑调整:我们重写了sendwave()函数,在检测到超声波信号有效的情况下,会连续发送8个八位十六进制数作为超声波信号,直到阈值位置(70厘米)被到达为止。每发送完一个超声波,我们都会暂停100微秒,然后发送下一条信号。
    • selectHC573() 函数中,我们根据当前通道选择合适的HCM573定时器,并将其初始化为“初始模式”,即将波特率设置为12.000 MHz,设定超声波时间间隔为1 ms。
    • 定义并实现 KeyUp()KeyState()KeyExit() 函数,分别处理用户按下和释放特定键事件,以及退出主循环的操作。在主循环中,通过这两个函数,我们可以检查是否有按键输入,并切换定时器模式,同时保持对传感器数据的同步显示。

    这只是一个基本的解决方案,实际应用中可能会遇到其他未知的问题和影响,如硬件故障、超声波信号干扰、外部中断等。在编写具体应用时,需要根据实际环境和项目需求,仔细测试和优化代码,确保其稳定性和准确性。同时,对于关键的控制块(如CSB_read()SendWave()SelectHC573()LED_output()WS_output()SMG_output()),建议采用面向对象编程设计模式,如工厂方法模式,提高代码可复用性和维护性。

    评论 编辑记录

报告相同问题?

问题事件

  • 创建了问题 3月30日

悬赏问题

  • ¥20 c语言写的8051单片机存储器mt29的模块程序
  • ¥60 求直线方程 使平面上n个点在直线同侧并且距离总和最小
  • ¥50 java算法,给定试题的难度数量(简单,普通,困难),和试题类型数量(单选,多选,判断),以及题库中各种类型的题有多少道,求能否随机抽题。
  • ¥50 rk3588板端推理
  • ¥250 opencv怎么去掉 数字0中间的斜杠。
  • ¥15 这种情况的伯德图和奈奎斯特曲线怎么分析?
  • ¥250 paddleocr带斜线的0很容易识别成9
  • ¥15 电子档案元素采集(tiff及PDF扫描图片)
  • ¥15 flink-sql-connector-rabbitmq使用
  • ¥15 zynq7015,PCIE读写延时偏大