单片机日历时钟与键盘显示程序设计报告Word下载.docx
《单片机日历时钟与键盘显示程序设计报告Word下载.docx》由会员分享,可在线阅读,更多相关《单片机日历时钟与键盘显示程序设计报告Word下载.docx(25页珍藏版)》请在冰豆网上搜索。
图5共阴极LED数码管的内部结构原理图
LED数码管要正常显示,就要用驱动电路来驱动数码管的各个段码,从而显示出我们要的数位,因此根据LED数码管的驱动方式的不同,可以分为静态式和动态式两类。
A、静态显示驱动:
静态驱动也称直流驱动。
静态驱动是指每个数码管的每一个段码都由一个单片机的I/O埠进行驱动,或者使用如BCD码二-十进位*器*进行驱动。
静态驱动的优点是编程简单,显示亮度高,缺点是占用I/O埠多,如驱动5个数码管静态显示则需要5×
8=40根I/O埠来驱动,要知道一个89S51单片机可用的I/O埠才32个呢。
故实际应用时必须增加*驱动器进行驱动,增加了硬体电路的复杂性。
B、动态显示驱动:
数码管动态显示介面是单片机中应用最为广泛的一种显示方式之一,动态驱动是将所有数码管的8个显示笔划"
a,b,c,d,e,f,g,dp"
的同名端连在一起,另外为每个数码管的公共极COM增加位元选通控制电路,位元选通由各自独立的I/O线控制,当单片机输出字形码时,所有数码管都接收到相同的字形码,但究竟是那个数码管会显示出字形,取决于单片机对位元选通COM端电路的控制,所以我们只要将需要显示的数码管的选通控制打开,该位元就显示出字形,没有选通的数码管就不会亮。
透过分时轮流控制各个LED数码管的COM端,就使各个数码管轮流受控显示,这就是动态驱动。
在轮流显示过程中,每位元数码管的点亮时间为1~2ms,由于人的视觉暂留现象及发光二极体的余辉效应,尽管实际上各位数码管并非同时点亮,但只要扫描的速度足够快,给人的印象就是一组稳定的显示资料,不会有闪烁感,动态显示的效果和静态显示是一样的,能够节省大量的I/O埠,而且功耗更低。
(1)、HD7279程序
#include<
c8051f020.h>
sbitHD7279_DAT=P1^7;
//数据线SDA
sbitHD7279_CLK=P1^6;
//时钟线SCL
sbitHD7279_CS=P1^5;
//片选CS,低电平有效
/******信号设置宏定义******/
#defineNOSELECT7279P5|=0x80//片选置1,未选中
#defineSELECT7279P5&
=~(0x80)//片选清0,选中
#defineSet7279DATHD7279_DAT=1//数据线置1
#defineClr7279DATHD7279_DAT=0//数据线清0
#defineSet7279CLKHD7279_CLK=1//时钟线置1
#defineClr7279CLKHD7279_CLK=0//时钟线清0
/******函数的声明******/
voidDelay1ms(unsignedcharT);
//延时T毫秒
voidDelay1s(unsignedcharT);
//延时T秒
voidDelay1us(unsignedcharT);
//延时T微秒
/******仿真I2C总线时序发送一字节******/
voidSend7279Byte(unsignedcharch)
{
chari;
SELECT7279;
//使能HD7279A
Delay1us(50);
//延时50us
for(i=0;
i<
8;
i++)
{if(ch&
0x80)//按位输出字节数据
Set7279DAT;
else
Clr7279DAT;
Set7279CLK;
ch=ch<
<
1;
//待发数据左移
Delay1us(8);
Clr7279CLK;
}
//数据信号SDA清0
//******仿真I2C总线时序接收一字节******//
unsignedcharReceive7279Byte(void)
{
unsignedchari,ch=0;
//数据信号SDA置1
{Set7279CLK;
//接收数据左移1位
if(HD7279_DAT)
ch+=1;
//接收1位数据
returnch;
//******让第No位7段数码管闪烁******//
voidFlashLED(unsignedcharNo)
unsignedchari;
Send7279Byte(0x88);
//发送闪烁指令
i=0x01;
while(No)
{i=i<
//将1移到第No位
No--;
Send7279Byte(~i);
//0闪烁、1不闪烁
NOSELECT7279;
//******HD7279A左移命令******//
voidMoveLeft(void)
Send7279Byte(0xA1);
//发左移指令
//******采用不译码方式显示时数字0到F的段码******//
unsignedcharcodeBdSeg[]={
0x7e,0x30,0x6d,0x79,//0123
0x33,0x5d,0x5f,0x70,//4567
0x7f,0x7b,0x77,0x1f,//89ab
0x4e,0x3d,0x4f,0x47,//cdef
0x00,0x01};
//'
'
和'
_'
//******显示指针DispBuf所指6个单元数据******//
voidDispLED(unsignedchar*DispBuf,unsignedcharShowDot)
{
chari,ch;
ShowDot--;
6;
{ch=DispBuf[i];
//取一字符
if((ch>
='
a'
)&
&
(ch<
f'
))
{ch-='
;
ch+=0xa;
//转换成数组序号
A'
F'
}
Send7279Byte(0x90+5-i);
//发送显示命令及位置
if(ch=='
)//发送命令的第2字节
Send7279Byte(0x00);
Else
{
-'
)
Send7279Byte(0x01);
{//查表显示
if(ShowDot==i)//小数点处理
Send7279Byte(0x80|BdSeg[ch&
0x0f]);
Send7279Byte(BdSeg[ch&
//停止选中
/******读取按键值******/
unsignedcharGetKeyValue(void)
unsignedcharKeyValue;
if(P17==1)return-1;
//无键按下
Send7279Byte(0x15);
//发读键盘命令
KeyValue=Receive7279Byte();
returnKeyValue;
}
//***等待按键释放,此处采用比较器硬件检测,也可以用软件延时实现***//
voidWaitKeyOff(void)
while(!
(CPT1CN&
0x40));
//******显示任意长整型数据******//
voidDispValue(unsignedlongxx)
unsignedcharbuf[6];
buf[0]=(xx%1000000)/100000;
//最高位
buf[1]=(xx%100000)/10000;
buf[2]=(xx%10000)/1000;
buf[3]=(xx%1000)/100;
buf[4]=(xx%100)/10;
buf[5]=(xx%10);
//最低位
DispLED(buf,0);
//调用显示函数
//**从键盘读取6位数据,格式是HHMMSS,所读数据转换成长整型**//
unsignedlongInputNum(void)
unsignedlongNum=0;
unsignedchari=0,KeyValue,KeyValue1;
DispLED("
-"
0);
//输入提示
FlashLED(0);
//第一位闪烁
Delay1s
(1);
while
(1)
KeyValue=GetKeyValue();
if(i==6)
FlashLED(8);
//数据输入完成,关闪烁
returnNum;
if((KeyValue>
=0)&
(KeyValue<
=9))//只接收十进制的0到9
i++;
Send7279Byte(0xC8);
//发送方式1译码显示命令
Send7279Byte(KeyValue);
//发送命令第2字节
MoveLeft();
//显示左移
Send7279Byte(0x90);
WaitKeyOff();
Num*=10;
//转换成十进制
Num+=KeyValue;
(2)、与S—3530A有关的代码和延时函数代码
intrins.h>
//_crol_()循环左移头文件
//*****宏定义*****//
#defineWRITE0x00//SMBus写命令
#defineREAD0x01//SMB读命令
//******S—3530A命令类型******//
#defineCLOCK3530_ADDRESS_RESET0x60//时间值复位命令,1个ACK
#defineCLOCK3530_ADDRESS_STATUS0x62//状态寄存器读取,2个ACK
#defineCLOCK3530_ADDRESS_DATEHOUR0x64//时间读取年份开始,8个ACK
#defineCLOCK3530_ADDRESS_HOUR0x66//时间读取,从小时开始,4个ACK
#defineCLOCK3530_ADDRESS_INT10x68//中断1频率设置,3个ACK
#defineCLOCK3530_ADDRESS_INT20x6A//中断2频率设置,3个ACK
//******SMBus状态:
MT=主发送器、MR=主接收器******//
#defineSMB_BUS_ERROR0x00//(所有模式)总线错
#defineSMB_START0x08//(MT&MR)开始条件已发送
#defineSMB_RP_START0x10 //(MT&MR)重复开始条件已发送
#defineSMB_MTADDACK0x18 //(MT)从地址+W已发送,收到ACK
#defineSMB_MTADDNACK0x20//(MT)从地址+W已发送,收到NACK
#defineSMB_MTDBACK0x28//(MT)数据字节已发送,收到ACK
#defineSMB_MTDBNACK0x30//(MT)数据字节已发送,收到NACK
#defineSMB_MTARBLOST0x38//(MT)竞争失败
#defineSMB_MRADDACK0x40//(MR)从地址+R已发送,收到ACK
#defineSMB_MRADDNACK0x48//(MR)从地址+R已发送,收到NACK
#defineSMB_MRDBACK0x50//(MR)数据字节已收到,ACK已发出
#defineSMB_MRDBNACK0x58//(MR)数据字节已收到,NACK已发出
//******引用的全局变量声明******//
union
unsignedcharClockString[7];
structRealClock
unsignedcharYear,Month,Day,Week,Hour,Minute,Second;
}RT;
}RealTime;
//实时时间
unsignedcharxdataNowTime[7],Timer[2];
//当前时间,用于当前时间的设置
unsignedcharxdataYear,Month,Day,Week,Hour,Minute,Second;
charCOMMAND;
//发送的命令(从地址+R/W)
unsignedchar*I2CDataBuff;
//I2C总线数据缓冲区指针
charBYTE_NUMBER;
//需发送的字节数
bitSM_BUSY;
//SMBus总线忙标志
unsignedcharCount1ms;
//延时时间(单位为毫秒)
//*****对所调用其他文件中函数的声明*****//
voidSend7279Byte(unsignedcharch);
unsignedcharGetkeyValue(void);
voidFlashLED(unsignedcharNo);
unsignedlongInputNum(void);
voidDispValue(unsignedlongxx);
//*****时钟初始化*****//
voidSYSCLK_Init(void)
inti;
OSCXCN=0x67;
//外部晶振22.1184MHz
256;
i++);
while(!
(OSCXCN&
0x80));
//等待外部晶振稳定
OSCICN=0x88;
//选择外部晶振系统时钟源,允许时钟丢失检测
//*****端口初始化*****//
voidPORT_Init(void)
XBR0=0x07;
//允许SMBus、SPI0和UART0
XBR1=0x00;
XBR2=0x44;
//使能交叉开关和弱上拉
//*****定时器T0初始化*****//
voidTimer0_Init(void)
CKCON|=0x8;
//T0按系统时钟频率计数
TMOD|=0x1;
//T0方式1
Count1ms=10;
//停止T0
TR0=0;
TH0=(-SYSCLK/1000)>
>
//定时1ms的时间常数
TL0=-SYSCLK/1000;
TR0=1;
//启动T0
IE|=0x2;
//开T0中断
//*****定时器T0中断服务程序(每隔1ms中断1次)*****//
voidTimer0_ISR(void)interrupt1
//重新装入初值
if(Count1ms)Count1ms--;
//定时时间减1
//*****延时Tus(软件实现)*****//
voidDelay1us(unsignedcharT)
while(T)
_nop_();
_nop_();
--T;
}
//*****延时Tms(定时器T0实现)*****//
voidDelay1ms(unsignedcharT)
Count1ms=T;
while(Count1ms);
//在T0中断服务程序中减1
//*****延时Ts(定时器T0实现)*****//
voidDelay1s(unsignedcharT)
Delay1ms(200);
Delay1ms(200);
T--;
//*****定时器T3初始化)*****//
voidTimer3_Init(void)
{
TMR3RLL=0xff;
//定时25ms的时间常数
TMR3RLH=0x69;
TMR3L=0xff;
TMR3H=0x69;
TMR3CN=0x00;
//清零T3溢出标志、12分频计数、禁止T3
EIE2|=0x01;
//开T3中断
TMR3CN|=0x04;
//启动T3
//*****定时器T3中断服务程序*****//
voidTimer3_ISR(void)interrupt14
SM_BUSY=0;
ENSMB=0;
//ENSMB短暂清0后置1,复位SMBus
ENSMB=1;
//****复位S—3530A*****//
voidResetRealClock(void)
{
while(SM_BUSY)//等待SMBus空闲
SM_BUSY=1;
//置SMBus忙标志
SMB0CN=0x44;
//使能SMBus,应答类型为ACK
BYTE_NUMBER=0;
//命令字节数,1字节
COMMAND=(CLOCK3530_ADDRESS_RESET|READ);
STA=1;
//开始发送
Timer3_Init();
//允许T3工作以保证通信不超时
while(SM_BUSY);
//等待发送完成
TMR3CN&
=0x82;
//禁止T3
}
//*****写S—3530A内部实时数据寄存器(年、月、日、星期、时、分、秒)*****//
voidSetRealClock(void)
BYTE_NUMBER=7;
//命令字节数,8字节
COMMAND=(CLOCK3530_ADDRESS_DATEHOUR|WRITE);
RealTime.ClockString[0]=Year;
RealTime.ClockString[1]=Month;
RealTime.ClockString[2]=Day;
RealTime.ClockString[4]=Hour;
RealTime.ClockString[5]=Minute;
RealTime.ClockString[6]=Second;
I2CDataBuff=&
RealTime.ClockString[0];
//数据发送缓冲区
STA=1;
//开始传送
//*读S—3530A实时数据(接收数据放RealTime变量)*//
voidGetRealClock(void)
SM_BUSY=1;
SMB0CN=0x44;
BYTE_NUMBER=7;
COMMAND=(CLOCK3530_ADDRESS_DATEHOUR|READ);
I2CDataBuff=&
STA=1;
Timer3_Init();
while(SM_BUSY);
TMR3CN&
=0x82;
//*****读S—3530A状态寄存器程序*****//
unsignedcharGetRealClockStatus(void)
unsignedcharresult;
SM_BUSY=1