不会printf怎么打印红外遥控数据?| 初学者必看
预计阅读时间: 4 分钟
“现在还没学会串口打印功能,怎么调试啊?”
前段时间有位道友问我关于红外遥控数据接收的问题。接收数据的那部分代码因为用的开发板例程,所以一定程度上可以保证接收是没有问题的,但是他的主函数很简单,为什么还是出错了呢?
可以看到,很简单的一个程序,中断接收红外遥控,然后主程序判断接收的数据,如果是目标数据,就设置 LED 灯亮。并且这是一个死循环,意味着程序一直在判断接收的是什么数据,所以不存在数据接收有延时或者其它函数干扰的问题。
首先鱼鹰第一眼看到 0100 0101 的时候,就知道这位道友是想表达二进制数 0100 0101b (二进制数在文章中表示一般是在数字后面加 b,注意不是 B,大写 B 表示字节),但是在程序中你是没办法通过某种方式表示二进制的,通常数据的表示是十进制和十六进制,如果是十进制,没有任何特殊说明;如果是十六进制,就是在数据开头加上 0x 或者 0X,比如 0xBB、0XBB、0xBb,0xbb,0Xbb,都是表示同一个数据(对大小写不敏感),换算成十进制就是 187(如果不会换算就用计算器吧,计算器切换成程序员模式就可以了),而换算成二进制就是 1011 1011b(注意看我为什么要把二进制四位四位的分开,看看和十六进制有什么关系)。
根据上面的知识你就可以知道,上面语句实际表达的数据是十进制 1000101,换算成十六进制就是 0xF42A5。
而那位道友其实是想表达二进制 01000101b 的,换算成十六进制就是 0x45,十进制就是 69,这样一来,if判断肯定是不能成立的,也就不能通过红外遥控去点亮 LED 灯了。
因为鱼鹰并不能确定红外接收的数据到底是什么,所以就请那位道友打印出来,但是那位道友刚学单片机,并不知道该如何利用 printf 函数打印(输出)需要的数据,所以就问他是否有 8 个 LED 灯,刚好他有这样的硬件条件,所以明白我意思的他就自行测试了。
但是测试之后发现还是无法通过 if 判断,那又是怎么一回事呢?他给出了如下代码:
看到这份代码之后,鱼鹰首先怀疑的对象就是 0xA2 数据有误,所以为了验证我的猜想,需要这位道友进行配合。
首先我让他把当前解码的 LED 灯显示效果告诉我,得到如下结果:
(这里有一个小插曲,本来想让他拍视频的,但是发现 LED 显示乱码,最后发现应该是摄像头的问题,对红外遥控器产生了干扰。)
然后又叫他通过 LED 灯显示数据 0x55 的效果:
通过以上信息就可以知道红外的数据就是 0x45。
那么这是怎么分析出来的呢?首先,点亮 LED 有两种可能,第一种为低电平点亮,第二种为高电平点亮,通过道友的回复知道是低电平亮。然后我又要求给一个 0x55 的显示效果给我,这个 0x55 显示效果是用来干什么的呢?
判断数据的高低位。
我们知道一个字节有 8 位,也就有了高低位之分。如果按照左边为低位的情况:
bit0 | bit1 | bit2 | bit3 | bit4 | bit5 | bit6 | bit7 |
灭 | 亮 | 灭 | 亮 | 灭 | 亮 | 灭 | 亮 |
1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 |
那么得到的十六进制数是 0x55,如果按照左边为高位的情况分析:
bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | Bit0 |
灭 | 亮 | 灭 | 亮 | 灭 | 亮 | 灭 | 亮 |
1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 |
得到的数据就是 0xAA(十六进制左边的 A 为高四位,右边的 A 为低四位),因此可以判断出那位道友的 LED 连接情况属于第一种(实际上要判断属于哪一种情况,用 0x0F做测试更好)。因此需要根据第一种情况分析接收的遥控数据:
bit0 | bit1 | bit2 | bit3 | bit4 | bit5 | bit6 | bit7 |
D1 | D2 | D3 | D4 | D5 | D6 | D7 | D8 |
灭 | 亮 | 灭 | 亮 | 亮 | 亮 | 灭 | 亮 |
1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 |
因为数据是从低到高的显示的,而人一般从高到低的书写(比如十进制 100,左边首先是百位1,然后才是低位的 0),所以需要将以上数据换个方式书写:
bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | Bit0 |
D8 | D7 | D6 | D5 | D4 | D3 | D2 | D1 |
亮 | 灭 | 亮 | 亮 | 亮 | 灭 | 亮 | 灭 |
0 | 1 | 0 | 0 | 0 | 1 | 0 | 1 |
四位四位的分析,就得到 0x45 了。所以那位道友的 0xA2(你可以分析两个数据有何不同、相同)肯定是不对的,也就无法进入if判断了(其实这里还有一个小问题,他用了按位取反 ~ 这个运算符,测试的时候建议最好不要用可变的数据,原因有二:1、数据不明确,调试的时候尽可能的用已知的数据;2、有可能你进入if判断,点亮了 LED灯,然后出来,又再进入if判断,此时 LED 又熄灭了……这样你可能就看不多LED是否被点亮了,如果真要用的话,起码再加一个延时才对)。
这些东西看起来感觉很复杂,但真正理解了之后就很快了。重点就是要明白这其中的道理,这样你就能利用很多手段去解决你的 BUG 啦。
说回打印(输出)数据的事情,写代码的过程中必然会遇到很多问题,特别是嵌入式软件开发更是如此,因为你遇到的 BUG 可能不仅仅是软件上的,也有可能是硬件上的,在进行嵌入式开发时,你首先要确定硬件没有问题,然后才去分析软件是否有问题,如果你都不能确定硬件是否有问题就在那里盲调,那你的效率是很低下的(但有的时候你真没办法确定硬件是否有问题,比如自己新焊接的板子,供电正常,引脚连接正常,但是你又不能确定你的焊接(虚焊、焊接温度过高等)是否有问题,那么就要尽可能的保证你的代码没问题了)。总之你要尽可能的保证一方没有问题,再想办法缩小另一方的问题范围才是。
对于 51 单片机而言,在线调试功能很差(或者说没有),所以一般都会在程序中插入 printf 函数来打印你需要观察的数据,从而进行更深入的分析。但是有些初学者并没有学会串口这个知识点,或者说你没有引出串口线(对于开发中的产品而言,如果没有引出相应的调试接口或测试点是非常不好的事情,这会大大延长你的开发周期),又或者说你身边没有串口模块。总之就是不能使用 printf(或串口)打印数据,那怎么办?
那你可以看看开发板上有什么可以显示的东西,比如 LED(上面的例子就是用这个进行分析的)、点阵、或者数码管,甚至说你有一个万用表或示波器都可以(怎么做?通过 IO 输出你需要数据,然后使用万用表或者示波器一个一个引脚的检查并记录电平状态,当然这种方法效率很低,不得已的情况下再使用)。总之一句话,找那些能让你不管从听觉(蜂鸣器)、视觉(LED)还是触觉(加热、制冷模块)等能让你感觉的东西,这样你就知道单片机运行的数据到底是什么了。
其实说起来,串口是很简单的东西,printf 的使用也容易(注意添加这个函数后,会导致程序增加 1 K左右的代码量,如果你的单片机容量比较小,建议不要使用该函数)。现在就教你一招最简单使用串口的方法:
1、程序中添加 stdio.h 头文件
2、使用 STC 的下载软件配置你的初始化代码并复制到你的程序中:
如果你要使用 printf 函数,注意在初始化后加上这一条语句:
TI = 1; // 发送标志设置为1(好久没用了,应该是这个吧)
否则你无法使用 printf 函数打印数据的。
本来准备在这篇文章再说点的什么的,但因为这篇文章已经很长了,所以就放在了第二篇文章。看过小说的都知道,低境界的修炼者如果能近距离的观看强者的战斗,对以后的进阶是很有帮助的,我虽然不是什么高手,但毕竟有四年的开发经验,对初学者还是有一定的帮助的,所以第二篇有个小福利,感兴趣的进去看一看。
-THE END-
如果觉得文章对你有帮助,欢迎转发、分享给朋友,感谢你的支持!
微信公众号「鱼鹰谈单片机」
每周一更单片机知识
长按后识别图中二维码关注
如果对你有帮助,在这里点个好看再走呗