【Follow me第二季第1期】任务3:接近检测
本帖最后由 eew_Ya3s2d 于 2024-10-12 10:02 编辑<p>大家好,我是郑工,尘世间一个迷途小工程师。</p>
<p> </p>
<p>最近家里比较忙,人到中年,忙忙碌碌的,正如张爱玲在《半生缘》里写的“中年以后的男人,时常会觉得孤独,因为他一睁开眼睛,周围都是要依靠他的人,却没有他可以依靠的人”。咦,等等,我们是工程师,回到正题,说说这次FM活动第一期的任务3,这个任务我也研究了一些时间,做了一些实验,我们先说说原理。</p>
<p> </p>
<p>电路图如下:</p>
<p> </p>
<p>红外发送的电路很简单就是用一个npn三极管去驱动红外发射管。</p>
<p> </p>
<p>红外接收电路就用了一个专用芯片VSOP383。在网上找到了原理图,框图如下</p>
<p> </p>
<p> </p>
<p>可以看到红外接收管如果的地方,有个bias偏置电路,所以在无发送的时候,也会有个偏置电压,用万用表测试了一下,这个电压是0.925v。用白光测试了一下,发现红外接收管对于白光是不敏感的。然后规格书上也说了,器件是对38kHz的红外光敏感,可以看到下图的频率响应。</p>
<p> </p>
<p>而在CPX的规格书里面说明了,可以用A10作为接近感应器的输入管脚。</p>
<p> </p>
<p>最后,进入REPL查询我们可以知道管脚定义并不是A10,而是IR_PROXIMITY</p>
<p>(附:进入REPL的办法,可以用mu,打开串口,使用ctr + c暂停程序,然后按回车进入REPL。REPL代表“读取-评估-打印-循环”(Read-Evaluate-Print Loop),它是一个交互式编程环境,允许用户输入代码并立即执行,然后显示结果。这非常有用,尤其是当你需要对代码进行故障排除或测试新想法时。)</p>
<p> </p>
<p>所以我们的程序思路其实就很明确了,就是使用IR_TX管脚,输入一个38khz的脉冲或者多个脉冲,然后立刻去读取IR_PROXIMITY的AD值。当有物体接近的时候,反射光会叠加到芯片的偏置上,接近得越近,AD的数值就越大。</p>
<p> </p>
<p>之前我些了一个简单的代码,程序也可以运行,跟我猜想的也一样,代码如下:</p>
<pre>
<code class="language-python">import analogio
import digitalio
import board
import time
ir_tx = digitalio.DigitalInOut(board.IR_TX)
ir_tx.direction = digitalio.Direction.OUTPUT
proximity = analogio.AnalogIn(board.IR_PROXIMITY)
delay_time = 0.00001
while True:
for i in range(2):
time.sleep(delay_time)
ir_tx.value = True
time.sleep(delay_time)
ir_tx.value = False
proximity_value = proximity.value
print("proximity Level: %d" % proximity_value)
time.sleep(0.1)</code></pre>
<p>延时的数值确定为10微秒是因为38khz方波的周期为26微秒,高电平,低电平的时间都为13微秒,粗略估计进入退出time.sleep函数的时间3微秒,函数是用于大致测试使用的,没有卡太准,我用示波器测试看到波形确实也是有的,波形如下:</p>
<p> </p>
<p>讲真这波形跟我想象中还是有些出入,可能这发射跟接收之间并没有严格隔离,所以其实可以看到发射期间IR_PROXIMITY的电压都有上升的,只是我接近的时候,在准备低电平那时候有个尖峰,没接近的时候,就没这个尖峰。在我正想研究这个到底有什么内在逻辑的时候,这个波形消失了。然而我单独测试发射或者接收,也是没问题的,搞了好久,都没理解到底哪里出问题了,搞得我一度很气馁,也研究过好多坛友的帖子,感觉也是大差不差,甚至我担心38k输入不准确,使用pwmio.PWMOut(board.IR_TX, frequency=38000, duty_cycle=35768)产生一个准确的38k方波,都是一点反应没有。不知道是不是被我用示波器捅的时候捅出什么问题了。</p>
<p> </p>
<p>加上生活工作上一些琐事,让我一直拖延到了现在,我想事情还是得解决的,既然这条路走不通,我们要创造条件完成任务,所以我买了一个超声波距离传感器</p>
<p> </p>
<p>由图可见使用的是CS100A超声波芯片。这个芯片的使用方式也很简单,在 TRIG 管脚输入一个 10US 以上的高电平(一般建议 50US 左右),芯片(TP,TN管脚)便可发出 8 个 40KHZ 的超声波脉冲,然后(RP,RN)检测回波信号。当检测到回波信号后,通过 ECHO 管脚输出。</p>
<p> </p>
<p>根据 ECHO 管脚输出高电平的持续时间可以计算距离值。即距离值为:(高电平时间*340m/s)/2。当测量距离超过测量范围时,CS100A 仍会通过 ECHO 管脚输出高电平的信号,高电<br />
平的宽度约为 33ms 。</p>
<p> </p>
<p>测量周期:当芯片通过 ECHO 管脚输出的高电平脉冲后,便可进行下一次测量,所以测量周期取决于测量距离,当测距很近时,ECHO 返回的脉冲宽度较窄,测量周期就很短;当测距较远时,ECHO 返回的脉冲宽度较宽,测量周期也就相应的变长。</p>
<p> </p>
<p>最坏情况下,被测物体超出测量范围,此时返回的脉冲宽度最长,约为 33ms,所以最坏情况下的测量周期大于 33ms 即可(比如测量周期可取 50ms)。 </p>
<p> </p>
<p> </p>
<p>这是正常时候的波形</p>
<p> </p>
<p> </p>
<p>这是超出范围的波形</p>
<p> </p>
<p>计算其实就比较简单,音波在空气中的传播速度是340m/s = 34000cm/1000ms = 34cm/ms。距离 = 时间 x 速度,考虑上一来一回,所以 距离 = 时间 x 速度 / 2。最后距离 = 时间 x 17,单位是厘米。由此可知,33ms也有500+m,显然是超出我们想侦测的范围。</p>
<p> </p>
<p>由此我写了以下的代码侦测距离</p>
<pre>
<code class="language-python"> # 发送出发信号,时间是500us,只要比需求长就可以了
ir_tx.value = True
time.sleep(0.0005)
ir_tx.value = False
rx_count = 0
# 等待回复的高电平
while ir_rx.value is False:
time.sleep(0.0001)
rx_count = rx_count + 1
if rx_count > 10000:# 发送高电平之后等待时间太长,认为是发送失败
break
start_time = time.monotonic_ns() #获取高电平开始的时间戳,单位是ns
while ir_rx.value is True:
pass
end_time = time.monotonic_ns() #获取高电平结束的时间戳,单位是ns
duration = round((end_time - start_time)/1000000, 2)
if duration < 0.05:# 时间太短
continue
print(f'duration time:{duration} ms')
distance = round(duration*17.0, 1) # 时间*340m/s(34cm/ms)/2
print(f'distance:{distance} cm')</code></pre>
<p>代码并不复杂,就是发送一个出发信号,然后等待回复,用time.monotonic_ns()函数获取时间戳,计算开始与结束的时间差。</p>
<p> </p>
<p>后面需要简单说一下的就是播放音频的代码。其实就是一些代码的参(复)考(制)</p>
<p><a href="https://learn.adafruit.com/adafruit-circuit-playground-express/circuitpython-audio-out">CircuitPython Audio Out | Adafruit Circuit Playground Express | Adafruit Learning System</a></p>
<p>简单说就是使用audioio库里面的AudioOut作为播放器,用audiocore或者audioio里的WaveFile加载音频文件,这样就可以播放音频文件了。</p>
<pre>
<code class="language-python">try:
from audiocore import WaveFile
except ImportError:
from audioio import WaveFile
try:
from audioio import AudioOut
except ImportError:
try:
from audiopwmio import PWMAudioOut as AudioOut
except ImportError:
pass# not always supported by every board!
def play_file(filename):
print("Playing file: " + filename)
wave_file = open(filename, "rb")
with WaveFile(wave_file) as wave:
with AudioOut(board.SPEAKER) as audio:
audio.play(wave)
while audio.playing:
pass
print("Finished")</code></pre>
<p>灯光警报就没什么好说的,之前就提过的内容,因为距离测试耗费的时间太长了,就没有整什么花活,可以参考我之前的帖子</p>
<p><a href="https://bbs.eeworld.com.cn/thread-1289057-1-1.html">【Follow me第二季第1期】任务1:控制板载炫彩LED,跑马灯点亮和颜色变换 - DigiKey得捷技术专区 - 电子工程世界-论坛 (eeworld.com.cn)</a></p>
<p>或者等我把任务代码提交了,直接拷贝一下。</p>
<p> </p>
<p>专业的超声波测距模块还是挺准的,我测试精确度都有厘米级别了。</p>
<p></p>
<p>用python写超声波代码这么简单的吗?{:1_113:}</p>
<p>一不小心,竟然碰到了一个文艺中年呀!!。。。。。。。。谢谢大哥分享!</p>
<p>老实讲没细看帖子,但帖子写得工整漂亮!让人心折不已<img height="48" src="https://bbs.eeworld.com.cn/static/editor/plugins/hkemoji/sticker/facebook/loveliness.gif" width="48" /></p>
wangerxian 发表于 2024-10-12 15:34
用python写超声波代码这么简单的吗?
<p>AS100S是个专用芯片,使用起来就是简单,现在好像都是用模块比较多</p>
eew_Ya3s2d 发表于 2024-10-14 23:13
AS100S是个专用芯片,使用起来就是简单,现在好像都是用模块比较多
<p>嗯嗯,一般都是先拿模块测试,没问题了就画板子了</p>
页:
[1]