卢骏 · 2020年07月17日

51单片机之流水灯

今天重温了下51单片机,先从流水灯做起。用的是proteus8.0来仿真。

首先是硬件电路:
1.jpg
左边的部分,是51的最小系统电路。包括时钟电路和复位电路。芯片的电源引脚和地引脚隐藏了,默认电源接VCC,地接GND。
2.jpg
在器件的属性,隐藏管脚中可以看到。
3.png
在design->configure power rails菜单中,可以设置电源和地引脚的默认电压值。一般VCC,VDD设置为5V,GND设置为0V。

在proteus中仿真,复位引脚和时钟引脚是没有用的。对于51,当RST复位引脚为高的时候,系统复位,程序重新从开头执行。时钟引脚接的晶振是决定51单片机运行时的时钟。但是在protues中,这两个引脚是没有用的。输入什么都不影响,即使时钟不接晶振,电路也正常工作。复位信号给高,电路也正常工作。所以这就是用软件模拟硬件仿真和实际的硬件仿真区别。不过对于学习51单片机的程序设计,就不要在乎这些细节。等要自己设计51单片机,要注意这些东西。

下面开始写程序:实现流水灯循环下移。
image.png

使用一个temp,变量来进行充当中间变量进行移位。

temp = (temp<<1)|((temp>>7)); 将temp8位数据向左移一位,然后在将temp 8位数据向右移7位,这样最高位就到最低位了,在用位或|操作,将两个数据拼接,这样就实现了循环左移功能。

感觉是没错,载入到proteus中仿真。

发现,最开始移位是正确的,流水灯循环向下移。但是当移到最后一个流水灯的时候,在移一次的时候,灯就全亮了。然后就没有移位了。这和设计的功能不一样啊。

然后找原因,使用keil的软件仿真,每次循环看temp的值。当移位到最后一位的时候,即temp=0x80的时候。查看temp<<1和temp>>7的值
4.png
发现,temp的值为0x80的时候,temp>>7的值,竟然变为0xff。而不是0x01。想了半天,想起,定义的temp为char型,而char型,这里51应该是认为有符号型数据(我认为),有符号移位,当向右移位时,最高位补符号位。所以temp为0x80,这时,最高位为1,则向右移位7位的话,补符号位,那么移位结果就是0xff了。

将char temp=0x01 改为unsigned char temp=0x01

然后在protues中仿真,发现结果对了。

发现这程序,多用了一个temp变量,何不把这变量去掉,直接就用P0移位操作了。

改改代码:
image.png
似乎也没有什么问题。将生成的hex文件在入到proteus中,运行。发现,就只有最开始亮了一次灯,下次的时候,灯就全灭了。

这不科学啊,这又是什么问题了。再来软件仿真,看结果:
5.png
6.png
第一次,结果是正确的,但是到第二次的时候,P0就全部变为全零了。这又是为什么了。查找下资料,原来P0是开漏输出的,外不接上拉电阻的话,输出都是低电平,软件仿真的时候,是认为P0是没有接上拉电阻,所以P0的输出都是0。所以在下一次移位,输出就全是0了。

将P0口改为P2口,输出就正确了。因为P2口是推免输出。可以输出高电平。
image.png
就一个简单的流水灯,也发现了这么多的问题。看来基础还是比较重要啊。不过,能发现问题是好事啊,最重要的是,能将这些问题都给解决。

系列其他篇

原文首发于骏的世界博客
作者:卢骏.
更多Arm技术相关的文章请关注Arm技术博客极术专栏,每日更新。
推荐阅读
关注数
23565
内容数
1018
Arm相关的技术博客,提供最新Arm技术干货,欢迎关注
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息