很早以前,在某个论坛上就看到下面的题目:
用单片机的 I/O 口控制 8 个 LED,要求编写程序,实现下面的功能。
1.第 1、3、5、7 个灯半亮,其余的全亮。
2.第1个亮1/8、第2个亮2/8、第3个亮3/8、第4个亮4/8、第5个亮5/8、第6个亮6/8、第7个亮7/8、第8个全亮。
3.所有的灯逐渐从暗到全亮,再由全亮到暗。
4.8 个灯从第一个开始依次渐亮,直到最后一个。再从最后一个起渐暗,直到第一个。如此循环。
好像是用来搞竞赛的,只是没有看到像样的结果。
这些个要求,都是要使用 PWM 来解决。下面,做而论道依次写出程序,大家看看是否能够满足题目的要求。
------------------------------------------
1.第 1、3、5、7 个灯半亮,其余的全亮。
这就太简单了。就是要求 LED 如下显示:
程序,都没有什么好编的,就是下面的几行就行。
;-----------------------------------------
ORG 0000H
START:
MOV P0, #0
XRL P0, #55H ;第 1、3、5、7 取反
DJNZ R7, $ ;延时
SJMP $ - 5 ;再去取反
END
;-----------------------------------------
------------------------------------------
2.第1个亮1/8、第2个亮2/8、第3个亮3/8、第4个亮4/8、第5个亮5/8、第6个亮6/8、第7个亮7/8、第8个全亮。
这个小题,要求 LED 的显示如下:
程序的思路也不难,只要按照下面的形式,输出数据到接口就行了。
○○○○○○○○ 全亮
○○○○○○○● D0灭
○○○○○○●● D1又灭了
○○○○○●●●
○○○○●●●●
○○○●●●●●
○○●●●●●●
○●●●●●●● D6~D0都灭了
反复循环的输出上述 8 个数据,那么 D7 就永远是亮的,D6 有 7/8 的时间是亮的,... D0 只亮了 1/8 的时间。
程序如下:
;-----------------------------------------
ORG 0000H
JMP START
ORG 000BH
JMP T0_INT
ORG 0030H
START:
MOV TH0, #220 ;1250us@11.0592MHz, T0定时方式0
SETB TR0
MOV IE, #82H
MOV 30H, #00H ;准备数据
MOV 31H, #03H
MOV 32H, #0FH ;这些数据是交错存放的
MOV 33H, #3FH ;类似“隔行扫描”
MOV 34H, #01H ;显示起来就显得平滑、稳定
MOV 35H, #07H
MOV 36H, #1FH
MOV 37H, #7FH
/*
○○○○○○○○
○○○○○○●●
○○○○●●●●
○○●●●●●●
○○○○○○○●
○○○○○●●●
○○○●●●●●
○●●●●●●●
*/
MOV R0, #30H ;设定指针
SJMP $
;-----------------------------------------
T0_INT: ;1.25ms中断一次
MOV TH0, #220 ;220: 1250us@11.0592MHz
MOV P0, @R0 ;输出一个数据
INC R0 ;修改指针
CJNE R0, #38H, $ + 5
MOV R0, #30H
RETI
;-----------------------------------------
END
;-----------------------------------------
------------------------------------------
3.所有的灯逐渐从暗到全亮,再由全亮到暗。
这个就是呼吸灯,看看做而论道的前一篇博文吧,这里就不重复了。
------------------------------------------
4.8 个灯从第一个开始依次渐亮,直到最后一个。再从最后一个起渐暗,直到第一个。如此循环。
这个才是真正的流水灯。LED 显示的一部分截图如下:
程序也不长,全部的代码,都在下面:
;-----------------------------------------
ORG 0000H
JMP START
ORG 000BH
JMP T0_INT
ORG 0030H
START:
MOV TH0, #220 ;1250us@11.0592MHz, T0定时方式0
SETB TR0
MOV IE, #82H
MOV R2, #100
MOV R3, #0
MOV R4, #0
SJMP $ ;此处可以编写主程序
;-----------------------------------------
T0_INT: ;1.25ms中断一次
MOV TH0, #220 ;220: 1250us@11.0592MHz
DJNZ R2, T0_2
MOV R2, #100
INC R3
CJNE R3, #33, T0_2
MOV R3, #0
T0_2:
MOV A, R3 ;R3:0~32
ADD A, R4 ;R4:0~7
ADD A, #TAB - $ - 3
MOVC A, @A + PC
MOV P0, A
INC R4
CJNE R4, #08H, $ + 5
MOV R4, #0
RETI ;本程序用不上 15us
;-----------------------------------------
TAB: DB 255,255,255,255,255,255,255,255
DB 127, 63, 31, 15, 7, 3, 1, 0
DB 0, 0, 0, 0, 0, 0, 0, 0
DB 0, 1, 3, 7, 15, 31, 63,127
DB 255,255,255,255,255,255,255,255
;-----------------------------------------
END
;-----------------------------------------
这个小题,做而论道是用查表的方法解决的,程序相当的简短,而且还比较通用,改成别的花样也很容易。
也有另外的方法,毕竟 LED 变化还是有明显的规律的,所以也可以用计算的方法来解决。
有网友确实是这样弄的,可以参考:http://www.eehome.cn/read-htm-tid-5208.html。
他这种编程的思路,编写起来就难多了,恐怕,几天也弄不出来。
------------------------------------------
上述各个程序,都在硬件系统中,通过了验证。图中的 8 个电容,做硬件试验时,就不用了。
上一篇:51 单片机扩充外部中断
下一篇:用 74HC595 把 LCD1602 改成串行数据接口
推荐阅读最新更新时间:2024-03-16 16:01