最近在做C52单片机智能小车的课设,要实现超声波测距功能时遇到了这个问题,于是绞尽脑汁想到了一个方法,可以实现以下功能:
当小车启动超声波模块,用计时器T1测量超声波经障碍物反弹回到接收端所用时间后,将计时器T1中的值(时间)乘以系数11H,并转换成用十进制的“个十百千万十万”位表示的值(距离),最终转化并存储在6个代表着十进制各位的单字节存储单元当中(每位都是BCD码)。
这是我的思路的手绘示意图,如对文字有疑问可参考该图
接下来是对全过程的大致描述。
首先,我们简单计算一下超声波往返的用时与对应距离之间的转化。
由《单片机及应用教程》教材可知,C52单片机的晶振频率是12MHz,计时器加1,相当于过去了1μs。所以,我们在发射超声波信号的同时开启T1,接收到有效返回信号的同时关闭T1,那么T1的值就是超声波信号往返的总时长,单位是μs。
已知超声波的速度是340m/s,那么超声波往返用时1μs就是走了0.034cm,单段距离就是0.017cm。也就是说,只要我们将代表超声波往返总时长的T1值乘以17,再进行单位换算,就得到我们想要的距离了。不过,我们在单片机的汇编程序设计中无需进行单位换算,只需将计算结果(十进制)的十万位,万位和千位拿出来定义成所谓距离(cm)的百,十和个位,并分别拎出来设计或执行操作就好了。
还需特别注意的是,我所用的超声波模块的测距范围最大是400cm,计算可得对应的最大用时T1值为5BE9H(μs),所以我后续所说的一些地方都是以此为数据边界。使用T1或T0都OK,我用的是T1的工作模式1。计时器溢出中断与本程序无关。
了解这些以后,我们便可以对测量得到的T1值进行如下操作:
首先,定义19个单字节存储单元:TH(high),TM(middle),TL(low),这三个用于第一步转换;TMH,TML,TLH,TLL,这四个用于第二步转换的过渡;W1~W6,这六个用于第二步转换;BW1~BW6,这六个用于最终转换。
然后,将TH1的值赋给TH,TL1的值赋给TL,并把TH1和TL1置0,以便下次计时使用。
先把TH的值乘以17(11H),用的是“MUL AB”指令,相乘后A的值(低8位)给TM,B的值(高8位)给TH。对TL进行类似操作,相乘后低8位给TL,而高8位给TM时要加上之前TM原有的值(即刚刚TH乘17后赋给TM的低8位的值)。这里TM加法运算后可能会溢出,若溢出要向TH进位(INC TH)。
因为TH不超过6,所以不需要分为THH和THL,而TM和TL要分开,这个后面再说。
接着,我们要把TH中的数分别乘以6、5、5、3、6。假设TH中的数是6,那么6乘6(万),则是36(万),我们将36这个数除以十,余数6(万)赋给代表万位的W5,商3(十万)赋给代表十万位的W6。以此类推,我们将TH中的数乘以65536,并映射给了代表十进制的六位中。因为这六位中每一位都是单字节存储单元,能存放最大为256的数,所以该阶段的任何一步都无需判断进位。
现在,我们完成了对TH的映射。下一步,我们先将TM和TL的高低4位分开,分别存放到TMH,TML,TLH,TLL中。这样一来,我们就可以参考上面处理TH的办法,如法炮制,分别对TMH,TML,TLH,TLL乘以4096,256,16和1,并一一映射到对应的十进制位数的存储单元(W1~W6)中。
需要注意的是,映射是各位不断累加的过程,不是直接赋值,否则之前的映射就会被覆盖掉。
完成以上步骤后,我们已经将T1值的17倍转化并映射到代表6个十进制位的单字节存储单元(W1~W6)中了。
最后,我们对每一位进行BCD码的转化就结束战斗了。只需从个位(W1)开始,对其中的数除以十,余数给BW1,商加到十位(W2)中,最后以此类推,把所有位都转化成BCD码存到BW1~BW6中,就大功告成了。
在这里,我作为一个大二入门汇编语言的本科生,将自己的思路分享给各位,希望对你有所帮助。我自知水平有限,如有不对之处或是有更好的转换方法,请多多指教🙏