JSN-SR0T4-2.0 超声波测距模块可提供 20cm-600cm 的非接触式距离感测功能,测距精度可达高到 2mm;模块包括收发一体的超声波传感器与控制电路组成。产品采用工业级一体化超声波探头设计,防水型,性能稳定,谦容市场上所有的 MCU 工作。
- 体积小,使用便捷
- 供电范围宽,低功耗
- 测量精度高,分辨率高
- 探测盲区小,距离更远
- 输出方式多样化,脉宽输出,串口输出。
产品提供三种工作模式:
这里我采用模式一,也就是默认模式下对该模块进行开发,模式一的用法与大学2期间常用的 HC-SR04 模块谦容。
-
基本工作原理:
(1)采用 IO 口 TRIG 触发测距,给最少 10us 的高电平信呈。
(2)模块自动发送 8 个 40khz 的方波,自动检测是否有信号返回;
(3)有信号返回,通过 IO 口 ECHO 输出一个高电平,高电平持续的时间就是超声波
从发射到返回的时间。测试距离=(高电平时间*声速(340M/S))/2;
(4)模块被触发测距后,如果接收不到回波(原因超过所测范围或是探头没有正对被测物),ECHO 口会在 60MS 后自动变为低电平,标志着此次测量结束,不论成功与否。 -
超声波时序图:
以上时序图表明你只需要提供一个 10uS 以上脉冲触发信号,该模块内部将发出8 个 40kHz 周期电平并检测回波。一旦检测到有回波信号则输出回响信号。回响信号的脉冲宽度与所测的距离成正比。由此通过发射信号到收到的回响信号时间间隔可以计算得到距离。公式:uS/58=厘米或者 uS/148=英寸;或是:距离=高电平时间*声速(340M/S)/2;建议测量周期为 60ms 以上,以防止发射信号对回响信号的影响。
这里我的做法分为以下两种,可供大家参考:
①使用定时器与外部中断。用外部中断去检测echo口电平变化,触发方式为上升沿,若产生中断,则开启定时器,直到echo变为低电平,利用定时器获取该段时间并关闭定时器,直到下次再次触发中断。
②只使用定时器,在定时器中断中不断判断echo引脚的电平,当echo引脚为高电平时,将计数器置0,直到echo降为低电平,提出计数器的值,进行距离计算。
我以第二种方式为例,在rt-thread具体操作如下:
- 1. 初始化引脚
#define ECHO_PIN GET_PIN(E, 1)
#define Trig_PIN GET_PIN(E, 5)
rt_pin_mode(Trig_PIN, PIN_MODE_OUTPUT);
rt_pin_mode(ECHO_PIN, PIN_MODE_INPUT_PULLDOWN);
rt_pin_write(Trig_PIN, PIN_LOW);
- 2. 初始化定时器
void Timer_Init(void)
{
// 使用前必须先手动打开时钟
__HAL_RCC_TIM3_CLK_ENABLE();
/* 查找定时器设备 */
hw_dev = rt_device_find(HWTIMER_DEV_NAME);
if (hw_dev == RT_NULL)
{
rt_kprintf("hwtimer sample run failed! can't find %s device!\n", HWTIMER_DEV_NAME);
}
/* 以读写方式打开设备 */
ret = rt_device_open(hw_dev, RT_DEVICE_OFLAG_RDWR);
if (ret != RT_EOK)
{
rt_kprintf("open %s device failed!\n", HWTIMER_DEV_NAME);
//return ret;
}
/* 设置超时回调函数 */
rt_device_set_rx_indicate(hw_dev, timeout_cb);
/* 设置计数频率(若未设置该项,默认为1Mhz 或 支持的最小计数频率) */
rt_device_control(hw_dev, HWTIMER_CTRL_FREQ_SET, &freq);
/* 设置模式为周期性定时器(若未设置,默认是HWTIMER_MODE_ONESHOT)*/
mode = HWTIMER_MODE_PERIOD;
ret = rt_device_control(hw_dev, HWTIMER_CTRL_MODE_SET, &mode);
if (ret != RT_EOK)
{
rt_kprintf("set mode failed! ret is :%d\n", ret);
}
/* 设置定时器超时值为1s并启动定时器 */
timeout_s.sec = 0; /* 秒 */
timeout_s.usec = 10; /* 微秒 */
if (rt_device_write(hw_dev, 0, &timeout_s, sizeof(timeout_s)) != sizeof(timeout_s))
{
rt_kprintf("set timeout value failed\n");
}
}
- 3. 发出起始信号
void SR04_Init(uint8_t time)
{
rt_pin_write(Trig_PIN, PIN_HIGH);
rt_thread_mdelay(time);
rt_pin_write(Trig_PIN, PIN_LOW);
}
- 4. 定时器溢出中断
static rt_err_t timeout_cb(rt_device_t dev, rt_size_t size) //10us
{
Timer_num++;
if(rt_pin_read(ECHO_PIN)==SET && flag==0)
{
Timer_num=0;
flag=1;
}
if(rt_pin_read(ECHO_PIN)==RESET && flag==1)
{
i++;
Distance = Timer_num*340/2000;
sum+=Distance;
flag=0;
}
return 0;
}
- 5. 数值选择
rt_uint32_t choose(rt_uint32_t num)
{
if(num<=20)
num=20;
if(num>=600)
num=600;
return num;
}