成绩评定表课程设计任务书目录一、题目分析2二、总体设计 (2)三、详细设计6四、实现代码8五、相关图片20六、结束语21七、参考文献 (22)1、实验题目分析1.1 问题描述结合实时时钟,IIC(控制小键盘和数码管等)来做具备定期功能的实时时钟。
1.2功能分析至少完成以下功能:(1)能显示每秒的时刻(2)按下功能键能切换显示日期(3)能设置定时闹钟,定时到产生某种输出(4)可以扩展考虑加入外部中断,如停止闹钟功能等。
1.3 开发平台及工具介绍实验器材有:CITK2410开发板,JTAG连接线,RS-232直通连接线RVDS集成开发环境,超级终端工具,2、总体设计2.1 实验基本原理IIC总线:IIC总线的器件分为主器件和从器件。
主器件的功能是启动在总线上传送数据,并产生时钟脉冲,以允许与被寻址的器件进行数据传送。
SCL线为高电平期间,SDA线由高电平向低电平的变化表示起始信号;SCL线为高电平期间,SDA线由低电平向高电平的变化表示终止信号。
I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。
超始和停止信号图数据传送时序图IIC总线(IICSDA、IICSCL)经过VDD33的上拉后,进入ZLG7290数码管:实验使用的数码管是广州周立公司单片机发展有限公司自行设计的一款数码管显示驱动及键盘扫描管理芯片。
下面是介绍该数码管的特点还有电路图:1 I2C 串行接口提供键盘中断信号方便与处理器接口2 可驱动8 位共阴数码管或64 只独立LED 和64 个按键3 可控扫描位数可控任一数码管闪烁4 提供数据译码和循环移位段寻址等控制5 8 个功能键可检测任一键的连击次数6 无需外接元件即直接驱LED 可扩展驱动电流和驱动电压7 提供工业级器件多种封装形式PDIP24 SO24采用24 引脚封装引脚图如图所示其引脚功能分述如下:实时时钟(Real Time Clock):2410提供了一个实时时钟,该时钟使用独立的一路1.8V 供电,保证主电源切断时能正常维持RTC工作。
2410的RTC支持两个中断:Time Tick(固定在一个频率内发出的时钟中断)和Alarm中断(在某个时刻产生闹铃中断)。
利用这两个中断可以设置每一秒中断一次显示变化时间,用Alarm中断实现闹钟功能。
以下为S3C2410内部RTC模块结构图:2.2 实验电路图ZLG7290功能电路图:IIC总线接口电路图:2.3 实验主要步骤1.初始化配置(各种寄存器)。
2.编写各种相关的中断程序。
3.主函数调用这几个中断程序。
4.编译程序,在zoc串口工具进行测试。
5.使用zoc下载和调试。
3、详细设计3.1 具体实验过程和内容(1)实现实时时钟功能设置rRTCCON、rTICNT、rRTCALM寄存器TICNT[6:0]=127;可以设置rTICNT=(1<<7)|(127)实现每秒中断一次。
可以设置闹铃寄存器,例如每秒的第几秒中断一次,实现定时闹钟的功能。
要设置初始化当前时间。
这里还包括编写Time Tick中断和Alarm中断的中断服务程序。
(2)初始化IIC总线编写一个IIC的操作库。
包括发送和接受功能。
编写可以向ZLG7290发出指令的函数。
(3)编写键盘中断处理程序通过键盘中断,实现数码管显示日期和时间的切换,还有停止。
(4)使用RVDS集成开发环境编译调试程序(5)使用ZOV软件测试3.2 程序流程图3.3 实验和程序问题分析这次试验实际上是融合了三个实验的要求,要实验实时时钟的功能,包括显示当前时间,还有设置闹钟,主要使用到2410的RTC的两个中断:Time Tick和Alarm中断。
而要实现在数码管上显示当前时间,并且按键盘时实现时间与日期的切换,需要用到数码管和IIC总线的知识。
而实现的难处在于如何把几个内容融合在一起并且实现所需的功能,这也是实验要求做的。
4、实现程序#include "2410addr.h"#include "target.h"#include "2410lib.h"#include "iic.h"void iic_init(void){rGPEUP |= 0xc000; // 禁止上拉rGPECON |= 0xa00000; // 设置GPIO 为IIC 总线// Enable ACK, Prescaler IICCLK=PCLK/16, Enable interrupt, Transmit clock value Tx clock=IICCLK/16//rIICCON = (1<<7) | (0<<6) | (1<<5) | (0xf);//rIICADD = 0x10; // 2410 从设备地址//rIICSTAT = 0x10; // IIC 总线输出有效}void iic_send_master(unsigned char *buf, int size){// IIC 总线Master 模式数据发送函数int fc1;// ZLG7290要求IIC传输速率不大于32Kbit/s,即Tx clock不大于32KHz// 设置IICCLK=PCLK/512 Tx clock=IICCLK/4,则// 如果FLCK=200MHz,则最大Tx clock = 24kHz,处于可接受范围// 初始化IICrIICCON = (1<<7) | (1<<6) | (1<<5) | (0<<4) | (3<<0);rIICSTAT = 0xD0;// 发送从设备地址rIICDS = *(buf++) & 0xFE;size--;rIICSTAT = 0xF0;while(!(rIICCON & IIC_PENDING_BIT));while(size>0){// 发送buf 数据rIICDS=*(buf++);size--;// 等待IICSCL 到达触发沿for(fc1=0;fc1<10;fc1++){;}if(size!=0){rIICCON = rIICCON & IIC_PENDING_MASK;}else{// 最后发送不需要应答rIICCON = rIICCON & IIC_PENDING_MASK & IIC_ACK_MASK;}// 等待发送完成while(!(rIICCON & IIC_PENDING_BIT));}// 停止IICrIICSTAT = 0xD0;rIICCON = rIICCON & IIC_PENDING_MASK;Delay(10);}void iic_receive_master(unsigned char *cmdbuf, int cmdsize, unsigned char *buf, int size){// IIC 总线Master 模式数据接收函数int fc1;// ZLG7290要求IIC传输速率不大于32Kbit/s,即Tx clock不大于32KHz // 设置IICCLK=PCLK/512 Tx clock=IICCLK/4,则// 如果FLCK=200MHz,则最大Tx clock = 24kHz,处于可接受范围int slave_addr;rIICCON = (1<<7) | (1<<6) | (1<<5) | (0<<4) | (3<<0);rIICSTAT = 0xD0;// 发送从设备地址slave_addr = *(cmdbuf++);cmdsize--;rIICDS = slave_addr & 0xFE;rIICSTAT = 0xF0;while(!(rIICCON & IIC_PENDING_BIT));while(cmdsize>0){// 发送buf 数据rIICDS=*(cmdbuf++);cmdsize--;// 等待IICSCL 到达触发沿for(fc1=0;fc1<10;fc1++){;}rIICCON = rIICCON & IIC_PENDING_MASK;// 等待发送完成while(!(rIICCON & IIC_PENDING_BIT)){;}}rIICDS = slave_addr | 0x01;rIICSTAT = 0xB0;while(size>0){if(size>1){rIICCON = rIICCON & IIC_PENDING_MASK;}else{// 最后接收不需要应答rIICCON = rIICCON & IIC_PENDING_MASK & IIC_ACK_MASK;}// 等待接收完成while(!(rIICCON & IIC_PENDING_BIT)){;}// 取出数据*(buf++) = rIICDS;size--;}// 停止IICrIICSTAT = 0x90;rIICCON = rIICCON & IIC_PENDING_MASK;Delay(10);}void __irq isr_keyboard(void){unsigned char cmdbuf[4];unsigned char key[5];// 关闭1号外中断rINTMSK = rINTMSK | BIT_EINT1;// 清除中断位rINTPND = BIT_EINT1;rSRCPND = BIT_EINT1;// 等待IIC 总线空闲while(rIICCON & IIC_PENDING_BIT){;}// 读取键值cmdbuf[0]=IIC_ADDR_ZLG7290;cmdbuf[1]=IIC_ADDR_ZLG7290_KEY;iic_receive_master(cmdbuf,2,key,4);// 判断是否有效按键if(key[1] == 0x01){// 数字左移2位for(fc1=0;fc1<4;fc1++){cmdbuf[1]=IIC_ADDR_ZLG7290_DPM0+date[fc1];cmdbuf[2]=0xff;iic_send_master(cmdbuf,3);}}else if(key[1] == 0x02){// 数字左移2位for(fc1=0;fc1<4;fc1++){cmdbuf[1]=IIC_ADDR_ZLG7290_DPM0+time[fc1];cmdbuf[2]=0xff;iic_send_master(cmdbuf,3);}}// 打开1号外中断rINTMSK = rINTMSK & ~BIT_EINT1;}void __irq isr_alarm(void){rINTMSK = rINTMSK | BIT_RTC;Uart_Printf("This is a alarm interrupt occur at the 30th second every minute.\n");// 清除中断位rINTPND = BIT_RTC;rSRCPND = BIT_RTC;rINTMSK = rINTMSK & ~BIT_RTC;}void __irq isr_tick(void){public int tmpintmsk;public int year;public int month;public int day;public int date;public int hour;public int minute;public int second;public int readtime=0;public int date[3];public int time[3];// 在实际应用中,由于“嘀嗒”中断实时性要求较高,中断时间固定,而且处理时间不长// 所以需要屏蔽所有中断,并且清除中断位操作必须尽快执行// 屏蔽所有中断tmpintmsk = rINTMSK;rINTMSK = BIT_ALLMSK;// 清除中断位rINTPND = BIT_TICK;rSRCPND = BIT_TICK;// “嘀嗒”中断服务处理// 读时间// 由于读时间时可能跨越了年、月、日、时、分界限// 例如:本来时间是2000年12月31日23时59分59秒,但刚好读取到hour的时候,到达了2001年的0秒// 从而造成了读出的时间前后不一致性// 所以,如果遇到了秒读取是0的话,则需要再读一次。