整理基于PIC6F877的LED旋转时钟单片机设计实验报告.docx
《整理基于PIC6F877的LED旋转时钟单片机设计实验报告.docx》由会员分享,可在线阅读,更多相关《整理基于PIC6F877的LED旋转时钟单片机设计实验报告.docx(79页珍藏版)》请在冰豆网上搜索。
整理基于PIC6F877的LED旋转时钟单片机设计实验报告
2013年小学期单片机设计实验报告
题目:
基于PIC16F877单片机的LED旋转时钟
班级:
学号:
班内序号:
实验组号:
学生姓名:
指导教师:
期中检查
教师评语
指导教师签字:
年月日
基于PIC16F877单片机的LED旋转时钟
――班
实验摘要
本次我们制作的基于PIC16F877单片机的LED旋转时钟是能够输入、显示时间的时钟。
结构新颖,效果奇特。
加入了现代科技的元素,利用人眼的视觉暂留特性,解决了传统时钟结构单一,显示效果固定的缺陷,更好了满足了人们对美的追求。
整个系统中,微控制器采用了Microchip公司的PIC16F877,软件设计中涉及PORTA用作普通数字I/O脚控制按键输入,PORTB、PORTC控制灯的亮灭,PORTD向时钟芯片DS1302写入和读出时间。
概括来说,本实验就是用人眼的视觉暂留特性,用PIC16F877单片机作为主控芯片,采用电机带动发光二极管高速旋转,利用频闪显示原理呈现时钟画面。
Abstract
Inthisexperiment,wemadeaLEDrotatingclockbaseonPIC16F877MCU.Itcaninputandshowtime.Itsstructureisnovelanditseffectisamazing.It’sfullofmoderntechnologyelement.Withhumaneyes’persistenceofvision,itsolvestraditionalclock’sstructureandeffect’sdisadvantage,fitshumanpursueforbeautybetter.
ThesystemusestheproductionoftheMicrochipcord--PIC16F877.ThedesignincludesthedriveofPORTAasgeneraldigitalportstoinputtime,thedriveofPORTBandPORTCtocontroltheLED’son,thedriveofPORTDtowriteandreadtimeonDS1302.
Inconclusion,withhumaneyes’persistenceofvision,thisexperimentusesPIC16F877MCUasmasterchip,usesmotortodriveLEDrotateathighspeed,usesstrobedisplayprincipletoshowtheclock.
关键字
单片机——microcontroller芯片——CMOSchip
LED旋转时钟--LEDrotatingclock
一.实验论证与比较
1.LED显示模块
LED的特点非常明显,寿命长、光效高、无辐射与低功耗。
LED的光谱几乎全部集中于可见光频段,其发光效率可达80~90%。
将LED与普通白炽灯、螺旋节能灯及T5三基色荧光灯进行对比,结果显示:
普通白炽灯的光效为12lm/W,寿命小于2000小时,螺旋节能灯的光效为60lm/W,寿命小于8000小时,T5荧光灯则为96lm/W,寿命大约为10000小时,而直径为5毫米的白光LED为20~28lm/W,寿命可大于100000小时。
有人还预测,未来的LED寿命上限将无穷大。
由于LED的种种优势,使得其在现在的各个领域里运用越来越广泛,我们设计的旋转LED显示屏幕,具有结构新颖,节约材料的特点,一列16个LED灯旋转显示之后,可以代替显示近似于16x120像素的显示宽度和内容。
旋转时钟是利用视觉暂留效应设计出来的,物体在快速运动时,当人眼所看到的影像消失后,人眼仍能继续保留其影像0.1-0.4秒左右的图像,这种现象被称为视觉暂留现象。
是人眼具有的一种性质。
人眼观看物体时,成像于视网膜上,并由视神经输入人脑,感觉到物体的像。
但当物体移去时,视神经对物体的印象不会立即消失,而要延续0.1-0.4秒的时间,人眼的这种性质被称为“眼睛的视觉暂留”。
假设我们设定我们的眼睛的暂留时间是0.4秒,如果我们的16个LED旋转一周的时间快过0.4秒,那么我们看到的图像就是这一列LED在各个位置显示的图像的叠加,如右图,如果我们用定时器把LED旋转一周的各个位置分割出120分,让它在相应的位置显示相应的图像,那么我们就可以得到一个累加的图像效果了。
旋转LED时钟的实现方法是把一组LED(16个左右)紧密的排列成一条直线,组成一条LED列,每个LED都由PIC单片机来控制其点灭。
把整个电路板固定在电机上,使得紧密排列的LED条的一端固定在电机的旋转轴附近,如图所示。
电路板转过一圈的时间极短,远小于0.1秒。
通过单片机控制LED灯在一圈内转到不同位置时的亮灭,来显示图像或文字。
2.DS1302时钟模块
大多数的单片机没有实时时钟部件,一旦系统掉电时钟就不能运行,下次再运行,时间就不准确了。
即便使用备用电池,但要维持单片机系统的较大功耗也是坚持不了多久的。
而我所做的旋转时钟用到的单片机主要是来准确显示时间的,因此实时时钟部件必不可少,这里我用了MAXIM公司的DS1302时钟芯片作为实时时钟部件,保证时间的长久准确性。
DS1302有着很强的功能。
包括时钟/日历寄存器和31字节(8位)的数据暂存寄存器,数据通信仅通过一条串行输入输出口。
实时时钟/日历提供包括秒、分、时、日期、月份和年份信息。
闰年可自行调整,可选择AM/PM的12小时制或24小时制。
只通过三根线进行数据的控制和传递:
CE(输入信号,在读、写数据期间,必须为高。
该引脚有两个功能:
第一,CE开始控制字访问移位寄存器的控制逻辑;其次,CE提供结束单字节或多字节数据传输的方法。
);I/O(三线接口时的双向数据线);SCLK(串行时钟输入)。
通过备用电源可以让芯片在小于1MW的功率下运作。
对时钟寄存器初始化可以设定当前时间,控制芯片的运行,时间是用BCD码保存的,RAM可以用来存取用户数据,在用了备用电池后RAM内的数据在系统掉电时能够保持不丢失。
芯片采用了简单的I2C三线通信方式,便于节省芯片资源和与之接口的MCU的引脚。
芯片有着2.0~5.5V的宽供电电压范围,在5V供电时其接口与TTL电平兼容。
并且有着很低的功耗,在2.0V供电时仅耗300nA的电流。
引脚X1和X2连接32.768kHz晶体,与内部振荡器组成时钟。
晶体的精度直接影响着芯片时间的准确与否。
DS1302有两个电源引脚VCC1和VCC2,分别连接备用电池和电源VCC。
VCC2与主电源连接,VCC1接备用电池。
当VCC2低于VCC1时,芯片由VCC1供电;当VCC2-VCC1≥0.2V时,备用电池为芯片供电。
在VCC2供电时芯片能够对接在VCC1的备用电池充电,并且是否充电和充电电流都可以由芯片内地址为08H的时钟寄存器进行控制。
DS1302与单片机的硬件接线图如图三所示。
图三DS1302硬件接线图
在进行任何数据传输时,CE必须被制高电平(虽然CE被置为高电平,但内部时钟还是在晶振作用下不停地计时的),在每个SCLK上升沿时读入数据,下降沿时写出数据。
每个字节的传输都是由控制字节(如表1所示)指定的,控制字节的最高位Bit7必须是“1”,否则读写将会被禁止。
bit6为“0”则指定对时钟/日历寄存器进行读写操作,为“1”则对RAM区的数据进行读写操作,bit1-bit5指定相关寄存器进行输入输出操作,最低位bit0指定是输入还是输出,为“0”则为写,相反则为读,输入输出根据脉冲的上升沿和下降沿串行进行。
7
6
5
4
3
2
1
0
1
RAM/
用来表示相关寄存器的地址
RD/
表1DS1302控制字节
控制字总是从最低位开始输出。
在控制字指令输入后的下一个SCLK时钟的上升沿时,数据被写入DS1302,数据输入从最低位(0位)开始。
同样,在紧跟8位的控制字指令后的下一个SCLK脉冲的下降沿,读出DS1302的数据,读出的数据也是从最低位到最高位。
数据读写时序如图四所示。
图四DS1302数据读写时序
通过8个脉冲便可读取一个字节,从而实现串行输入与输出。
最初通过8个时钟周期载入控制字节到移位寄存器。
如果控制指令选择的是单字节模式,连续的8个时钟脉冲可以进行8位数据的读写操作。
8个脉冲便可读写一个字节。
载入控制字节后就可以对时钟/日历寄存器进行相应操作,时钟/日历寄存器如下表所示。
读寄存器
写寄存器
BIT7
BIT6
BIT5
BIT4
BIT3
BIT2-BIT0
范围
81h
80h
CH
16-59秒
0-15秒
00-59
83h
82h
16-59分
0-15分
00-59
85h
84h
12
0
20-23
15-19时
0-15时
1-12/
0-23
/PM
87h
86h
0
0
0
16-31日
0-15日
1-31
89h
88h
0
0
0
10月
月
1-12
8Bh
8Ah
0
0
0
0
0
1-7周
1-7
8Dh
8Ch
0
15-99年
0-15年
00-99
8Fh
8Eh
WP
0
—
秒寄存器(81h、80h)的位7定义为时钟暂停标志(CH)。
当该位置1时,时钟振荡器停止,DS1302处于低功耗状态;当该位置为0时,时钟开始运行。
小时寄存器(85h、84h)的位7用于定义DS1302是运行于12小时模式还是24小时模式。
当为高时,选择12小时模式。
在12小时模式下,位5为1时,表示PM。
在24小时模式时,位5是第二个10小时位(20-23时)。
控制寄存器(8Fh、8Eh)的位7是写保护位(WP),其它7位均置为0。
在任何的对时钟和RAM的写操作之前,WP位必须为0。
当WP位为1时,写保护位防止对任一寄存器的写操作。
二.系统总体设计
系统模块总体框图如下:
底座转动部分
程序总体框图:
输入时间模块框图
该模块利用两个按键sw1和sw2实现时间输入。
sw1按一次时间加1,sw2按一次切换时、分、秒的输入。
按完三次sw2结束。
通过八个LED灯显示输入的时间的二进制数。
程序框图如下:
否是
否是
否是
DS1302读写模块
写时间程序框图:
读时间程序框图:
4.LED显示模块
单片机转20圈(小于1秒)从DS1302读一次数。
将表盘分成120格,走一格计数器加1。
程序框图:
否
否是
否
三.硬件连接
两个按键sw1和sw2接PORTA0和PORTA1。
PORTB和PORTC接16个LED灯。
PORTD0接DS1302的SLCK(时钟),PORTD1接DS1302的I/O接口,PORTD2接DS1302的CE(使能端)。
马达上套一个轮子,用万能胶粘在电路板上。
PIC单片机和LED灯由电路板上两个纽扣电池供电。
实物连接图:
正面图:
背面图:
侧面图:
局部细节图:
效果图:
电路原理图:
四.调试过程
在此,列举几个调试过程中遇到的的问题。
1.RA端口的输入和输出问题
上述提到我们用RA0、RA1接上两个按键给单片机输入时间,但是,我在编写好程序进行单步调试时,发现尽管我用异步激励将这三个端口设置为高电平,在观察窗口中RA的值没有丝毫变化。
经过思考,并联系提高篇中讲到的RA端口兼备5条数/模转换器的模拟量输入通道,在将RA端口当作普通数字输入/输出端口时需要将其控制寄存器ADCON1的低四位送入011x(x取0或1均可)。
因此,修改程序后,再次编译和调试,问题得到解决。
2.DS1302的编码问题
开始我没有注意DS1302里存的是BCD码而不是普通二进制码,结果秒针一跳一跳的不能连续地走。
修改完后时间恢复正常。
3.读取时间的问题
单片机读取DS1302需要一定的时间。
每秒钟时钟大概转二十几转,每转一圈读一次时间没有必要,所以我设定转20圈(一秒钟内)读一次时间。
五.参考文献:
PIC单片机实用教程——基础篇(五号宋体)
李学海
北京航空航天大学出版社
使用说明:
的确是一本不可或缺的教材,本书列举了很多实用的具有实战意义的例子,单片机入门就是通过把这本书里的好例子一字一行敲进电脑去来实现的。
PIC单片机实用教程——提高篇
李学海
北京航空航天大学出版社
使用说明:
继承了前面基础篇的风格,例子也具有实战意义,主要讲RA、TMR2的使用和CCP模块的PWM脉宽调制功能。
六.实验心得体会
通过本次实验,我对单片机有了一个初步的认识,也能用汇编编写一些简单的程序。
这次的程序800行左右,不长,但绝大多数是我自己打的。
看着单片机能够实现自己编写的程序所设定的功能,还是很有自豪感的。
这次实验对我的动手实践能力是一次极大的考验,我也从中学到了很多东西。
除了动手能力有所提高外,得益于二人组队的形式,我也明白了团队协作的重要性,获得了许多与他人合作的经验。
在这里也要感谢我的两位老师和队友,他们在实验过程中给予了我非常大的帮助,没有他们,这个单片机很难完成。
我也非常希望能够在以后还能遇上这种动手实践的机会,这是一个很好的提升能力的机遇。
下附汇编代码:
注意,此代码有BUG,秒针会先用55秒走完60秒,然后消失5秒,再出现在0秒处。
去掉按键输入时间的模块,直接在程序里把时间打进去,秒针又恢复正常。
我研究了几个小时也没找到问题在哪。
#DEFINET_IOportd,1;1302I_O
#DEFINET_CLKportd,0;1302时钟
#DEFINET_RSTportd,2;1302使能位
#DEFINEDS1302_RX27H;保存接受的1个数据
#DEFINEDS1302_TX28H;准备写入到DS1302的一个数据
indfequ00h
statusequ03h
rp0equ5h
Cequ0h
Zequ2h
fsrequ04h
adcon1equ9fh
trisbequ86h
triscequ87h
trisdequ88h
portbequ06h
portcequ07h
portdequ08h
portaequ05h
trisaequ85h
nequ20h;延时循环变量
counterequ21h;指针位置计数器
secnequ22h;秒针列数
minnequ23h;分针列数
hournequ24h;时针列数
jumpdecequ25h;跳转判断,0位秒,1位分,2位时
hourcequ26h;d'10',时钟计数循环变量
counter1equ29h
temp_cntequ2ah
W_Secondequ2bh
W_Minuteequ2ch
W_Hourequ2dh
SecAddrequ2eh
secequ2fh
minequ30h
hourequ31h
readnequ32h
tr1equ33h
tr2equ34h
bcdnequ35h
data1equ36h
data2equ37h
n1equd'13'
n2equ0ffh
tb1equ38h;十位
tb2equ39h;个位
;----------------------------------------
;主程序
;----------------------------------------
;-------------------------------
;输入时间
;-------------------------------
org0000h
gotomain
org0005h
main
bsfstatus,rp0
clrftrisc;设置c口输出
clrftrisb;设置b口输出
clrftrisd;设置d口输出
movlw0ffh
movwftrisa;a口定义为输入
movlw06h
movwfadcon1;a口设为数字I/O
bcfstatus,rp0;体0
clrfsecn
clrfminn
clrfhourn
clrfjumpdec
clrfportb
clrfportc;c口灯灭
clrfportd
clrfW_Hour
clrfW_Minute
clrfW_Second
setW_Hourbtfssporta,1;sw2是否按下
gotosetW_Minute1
checkbtfscporta,0;测开关sw1按下否?
是,跳过下条指令
gotosetW_Hour;否!
则循环检测
calldelay
btfscporta,0;再次测开关sw1按下否?
是,跳过下条指令
gotocheck;否!
则循环检测
incfW_Hour,1;时针加1
movlwd'12'
subwfW_Hour,0;看是否等于12
btfscstatus,Z
clrfW_Hour
movfW_Hour,0
movwfportc
check1btfssporta,0;测开关sw1断开否?
是,跳过下条指令
gotocheck1;否!
则循环检测
calldelay
btfssporta,0;再次测开关sw1断开否?
是,跳过下条指令
gotocheck1;否!
则循环检测
gotosetW_Hour;返回
setW_Minute1btfssporta,1;sw2松开否
gotosetW_Minute1
calldelay
btfssporta,1
gotosetW_Minute1
setW_Minutebtfssporta,1;sw2是否按下
gotosetW_Second1
check2btfscporta,0;测开关sw1按下否?
是,跳过下条指令
gotosetW_Minute;否!
则循环检测
calldelay
btfscporta,0;再次测开关sw1按下否?
是,跳过下条指令
gotocheck2;否!
则循环检测
incfW_Minute,1;分针加1
movlwd'60'
subwfW_Minute,0;看是否等于60
btfscstatus,Z
clrfW_Minute
movfW_Minute,0
movwfportc
check3btfssporta,0;测开关sw1断开否?
是,跳过下条指令
gotocheck3;否!
则循环检测
calldelay
btfssporta,0;再次测开关sw1断开否?
是,跳过下条指令
gotocheck3;否!
则循环检测
gotosetW_Minute;返回
setW_Second1btfssporta,1
gotosetW_Second1
calldelay
btfssporta,1
gotosetW_Second1
setW_Secondbtfssporta,1;sw2是否按下
gotobegin
check4btfscporta,0;测开关sw1按下否?
是,跳过下条指令
gotosetW_Second;否!
则循环检测
calldelay
btfscporta,0;再次测开关sw1按下否?
是,跳过下条指令
gotocheck4;否!
则循环检测
incfW_Second,1;秒针加1
movlwd'60'
subwfW_Second,0;看是否等于60
btfscstatus,Z
clrfW_Second
movfW_Second,0
movwfportc
check5btfssporta,0;测开关sw1断开否?
是,跳过下条指令
gotocheck5;否!
则循环检测
calldelay
btfssporta,0;再次测开关sw1断开否?
是,跳过下条指令
gotocheck5;否!
则循环检测
gotosetW_Second;返回
begincalltbcd
;-------------------------------------------------
;显示时间
;-------------------------------------------------
callSet_DS1302
rsrnmovlwd'20'
movwfreadn;20圈读一次时间
showmovlwd'20'
subwfreadn,0
btfscstatus,Z
callGet_DS1302
callbcdt
decfreadn,1
clrfcounter;指针位置计数器清零
judgecallclearc;清表盘
movlwd'119'
subwfcounter,0
btfscstatus,Z
gotorsrn;判断指针位置计数器是否达到119
;***************是否显示刻度***************
movlwd'0'
subwfcounter,0
btfscstatus,Z
calldraw2_0
movlwd'1'
subwfcounter,0
btfscstatus,Z
calldraw2_1
movlwd'2'
subwfcounter,0
btfscstatus,Z
calldraw2_2
movlwd'3'
subwfcounter,0
btfscstatus,Z
calldraw2_3
movlwd'10'
subwfcounter,0
btfscstatus,Z
calldrawgra
movlwd'20'
subwfcounter,0
btfscstatus,Z
calldrawgra
movlwd'27'
subwfcount