可设置初值的正倒计时秒表Word格式.docx
《可设置初值的正倒计时秒表Word格式.docx》由会员分享,可在线阅读,更多相关《可设置初值的正倒计时秒表Word格式.docx(34页珍藏版)》请在冰豆网上搜索。
(4)秒表具有清除当前显示值,显示初值的功能。
(5)秒表的显示全部在LED灯上实现。
(6)秒表的显示全部在LCD灯上实现。
第二章IIC通信协议
1、IIC总线的特点
I2C串行总线一般有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。
所有接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。
为了避免总线信号的混乱,要求各设备连接到总线的输出端时必须是漏极开路(OD)输出或集电极开路(OC)输出。
设备上的串行数据线SDA接口电路应该是双向的,输出电路用于向总线上发送数据,输入电路用于接收总线上的数据。
而串行时钟线也应是双向的,作为控制总线数据传送的主机,一方面要通过SCL输出电路发送时钟信号,另一方面还要检测总线上的SCL电平,以决定什么时候发送下一个时钟脉冲电平;
作为接受主机命令的从机,要按总线上的SCL信号发出或接收SDA上的信号,也可以向SCL线发出低电平信号以延长总线时钟信号周期。
总线空闲时,因各设备都是开漏输出,上拉电阻Rp使SDA和SCL线都保持高电平。
任一设备输出的低电平都将使相应的总线信号线变低,也就是说:
各设备的SDA是“与”关系,SCL也是“与”关系。
总线对设备接口电路的制造工艺和电平都没有特殊的要求(NMOS、CMOS都可以兼容)。
在I2C总线上的数据传送率可高达每秒十万位,高速方式时在每秒四十万位以上。
另外,总线上允许连接的设备数以其电容量不超过400pF为限。
总线的运行(数据传输)由主机控制。
所谓主机是指启动数据的传送(发出启动信号)、发出时钟信号以及传送结束时发出停止信号的设备,通常主机都是微处理器。
被主机寻访的设备称为从机。
为了进行通讯,每个接到I2C总线的设备都有一个唯一的地址,以便于主机寻访。
主机和从机的数据传送,可以由主机发送数据到从机,也可以由从机发到主机。
凡是发送数据到总线的设备称为发送器,从总线上接收数据的设备被称为接受器。
2、开始和停止条件
当IIC总线接口是不活动,其通常是在从设备模式。
换言之,接口在检测到SDA线上的开始条件之间一直处于从设备模式(开始条件可以被初始化,当SCL时钟信号是高电平是SDA线下跳变)。
当接口状态变为主设备模式,在SDA线上的数据传输被初始化且SCL信号生成。
开始条件可以通过SDA线传输一个字节串行数据,一个停止条件可以终止一个数据传输。
停止条件是当SCL是高电平时,SDA线从低电平到高电平的跳变。
开始和停止条件都是由主设备生成。
当开始条件生成,IIC总线忙。
停止条件将使IIC总线空闲。
当一个主设备初始化开始条件,它应该发送一个从地址来停止从设备。
一个字节的地址域包含7位地址和一位传输方向指示(说明读写)。
如果位8是0,说明是写操作。
如果位8是1说明是数据读请求。
主设备通过发送停止条件来完成一个传输操作。
如果主设备想继续到总线的数据传输,他应该生成另一个开始条件和从地址。
用这个方法,读写操作可以在不同形式下执行。
下图为起始和停止条件。
3、数据传输格式
每个放到SDA线上的字节应该是8位长度。
该字节应该被无限制的传输。
紧接着开始条件的第一个字节应该有一个地址区域。
当IIC在主设备模式下操作,地址区域应该由主设备发送。
每个字节后面应该紧跟一个应答位(ACK)。
串行数据的MSB位和地址总是先发。
4、ACK信号传输
为了完成一个字节的传输操作,接收器应该发送一个ACK位给发送器。
ACK脉冲应该出现在SCL线的第九个时钟。
一个字节数据传输需要8个时钟。
主设备生成传输ACK位所需的时钟脉冲。
发送器应该在接收到ACK时钟脉冲以后通过拉高SDA线释放SDA线。
接收器也应该在ACK时钟脉冲期间拉低SDA线,以至于在第九个SCL脉冲为高电平期间SDA保持低电平。
ACK位发送功能可以通过软件(IICSTAT)使能或使无效。
但是在SCL第九个时钟的ACK脉冲是用于完成一个字节数据传输。
5、读写操作
在发送模式下,如果数据传输后,IIC总线接口会等待直到IIC总线数据移位寄存器(IICDS)收到一个新数据。
在新数据写入寄存器之前,SCL线将保持低电平,然后在数据写入后释放。
S3C2410A应该保持中断来识别当前数据发送是否完成。
在CPU收到中断请求以后,它应该再写一个新数据到IICDS寄存器。
在接收模式下,当数据收到后,IIC总线几口应该等待直到IICDS寄存器被读取。
在一个新数据被读出之前,SCL线应该保持低电平,在数据被读出后再释放。
S3C2410A应该保持中断来识别当前数据接收是否完成。
在CPU收到中断请求以后,它应从IICDS寄存器读取数据。
第三章关键代码分析
3.1设置初值
运行程序中,初值可以由操作者自行设置,由于此处采用的是时——分——秒计时,所以在编写程序的时候注意,部分显示数字的最大值问题,比如说因为秒位最大值只有60,所以对于秒的十位来说,其最大值就应该是6,7、8、9不可取。
同理,对于分钟来说,也是一样的,但是对于时来说,个位和十位同样是需要注意的。
因为时的最大值就是24,所以在设置按键的时候,如果超过相应的最大位。
此时应该全部置0。
这块是容易出现错误的难点,此时应该注意。
其中,设置变量flag,用于多种程序之间的互相访问。
这是非常重要的一点。
关键代码如下:
//如果时的十位大于2,置0
if(s[0]==0xf2||s[0]==0x66||s[0]==0xb6||s[0]=
=0xbe||s[0]==0xe0||s[0]==0xfe||s[0]==0xf6)
{
s[0]=0xfc;
}
//如果分的十位大于6,置0
if(s[2]==0xe0||s[2]==0xfe||s[2]==0xf6)
s[2]=0xfc;
//如果秒的十位大于6,置0
if(s[4]==0xe0||s[4]==0xfe||s[4]==0xf6)
{
s[4]=0xfc;
}
//如果时的个位大于4,置0
if((s[0]==0xda&
&
s[1]==0x66)||(s[0]==0xda&
s[1]==0xb6)||
(s[0]==0xda&
s[1]==0xbe)||(s[0]==0xda&
s[1]==0xe0)||
s[1]==0xfe)||(s[0]==0xda&
s[1]==0xf6))
s[1]=0xfc;
3.2正计时启动
当按下按键‘+’的时候,秒表进行加运算。
//加计时
if(bkey==0xce)
flag=2;
}
if(flag==2)
second++;
if(second>
=60){second=0;
minut++;
if(minut>
=60){minut=0;
hour++;
if(hour>
=24){hour=0;
Show_Time();
LCD_printf("
%2d-%2d-%2d"
hour,minut,second);
3.3倒计时启动
当按下按键‘—’的时候,秒表进行减运算。
//减计时
if(bkey==0x3e)
flag=3;
if(flag==3)
second--;
if(second<
=0){second=59;
minut--;
if(minut<
=0){minut=59;
hour--;
if(hour<
=0){hour=0;
}
3.4暂停计时
本实验中,通过按Enter键控制暂停计时。
关键代码分析如下:
if(tempmcukey==31)
flag=1;
up=0;
count=0;
3.5清除数据,显示初值
本实验中,通过按*键控制清除数据。
for(i=0;
i<
6;
i++)
s1[i]=s[i];
if(bkey==0x6e)
hour=change(s1[0])*10+change(s1[1]);
minut=change(s1[2])*10+change(s1[3]);
second=change(s1[4])*10+change(s1[5]);
3.6LED显示
Show_Time();
voidShow_Time()
sechigh=Seg7Val_Map[second/10];
seclow=Seg7Val_Map[second%10];
minuhigh=Seg7Val_Map[minut/10];
minulow=Seg7Val_Map[minut%10];
hourhigh=Seg7Val_Map[hour/10];
hourlow=Seg7Val_Map[hour%10];
IIC_Write(0x70,0x10,seclow);
IIC_Write(0x70,0x11,sechigh);
IIC_Write(0x70,0x12,0x02);
IIC_Write(0x70,0x13,minulow);
IIC_Write(0x70,0x14,minuhigh);
IIC_Write(0x70,0x15,0x02);
IIC_Write(0x70,0x16,hourlow);
IIC_Write(0x70,0x17,hourhigh);
3.7LCD显示
3.8本章小结
程序在不断的调试过程中已经成功,并且可以成功的编译运行。
第四章系统测试分析
4.1系统整体布局
4.2实验步骤
1、在MetrowerksCodeWarriorforARMDeveloper开发平台上进行编程与调试,并生成可执行文件;
2、通过超级终端将可执行文件烧入实验箱;
3、在实验箱上进行操作,演示时钟的计时与修改时间。
4.3程序代码截图
主程序:
Timer1程序:
键盘程序:
4.4超级终端截图
4.5实验箱截图:
实验箱刚开始界面:
(LED空,LCD正在初始化)
设置初值,进行按键的响应,分别按键六次,其中如果超出相应的最大值,该位全部置0。
本次按键为11-11-11。
按“+”键,加计时启动,由于拍照的原因,LED和LCD显示不同步。
按“—”键,再按Enter键,减计时启动后暂停,此时,LED和LCD显示同步。
按“Enter”键,计时暂停,LED和LCD显示同步。
按“*”键,显示初值,LED和LCD显示同步。
4.6本章小结
经过耐心调试后,程序运行畅通。
第五章结论
通过本次实验,使我熟悉了IIC通信协议的原理以及熟悉了定时器的使用,掌握了一些编程的技巧。
通过对程序的不断修改和调试,我知道了要实现一个功能远不止仅仅搭出框架实现功能,通过对时钟的设计,需要保证多方面的判断条件,其中包含了很多的逻辑关系,所以要写出一个好的程序,必须把逻辑梳理清楚再进行编程。
在以后的编程路上,我会吸取本次实验的经验,更加注重逻辑关系以及编程语言中的一些细节问题,而且要耐心的不断调试程序。
在整个调试的过程中,我遇到了一些问题,在不断的尝试和同学们的帮助下,我都顺利的解决了,现在就我遇到的问题做下汇总:
问题1:
在开始设计按键的时候,对实验箱上的按键对应的十六进制数不清楚,导致不知道对应的参数分别是多少,在自己的耐心查看下,得出对应的值分别是多少。
解决方法:
unsignedcharGetKey()
unsignedcharscankey;
unsignedcharKeyBoard_Map[]={0,0,0x9e,0,0,0xe0,0x66,0x60,0,0,0x8e
14,0,0xfe,0xb6,0xda,0xfc,0x1c,0x6e,0,0
0xf6,0xbe,0xf2,0x3e,0,0,0,0,0xce,0
0x7c,0,1,0,0,17,2,0,0,0
4,0,6,0,5,0,0,0,7,0
9,15,8,0,0,0,0,0,0,0
0,0,0
};
//64,键值映射表while
(1){
if((up==1)&
(count==1)){
scankey=KeyBoard_Map[tempmcukey];
break;
elsecontinue;
returnscankey;
问题2:
本次实验没有两次使用Enter键,在之前的编程过程中,由于本次实验的设计,按键次数比较多,所以为避免冲突按键,设置不同的按键。
1、2、3、4、5、6、7、8、9、+、-、*、\、Enter键都使用。
问题3:
最开始没有想到时分秒,后来在编写的过程中,需要设置超过最大值归0。
//如果时的十位大于2,置0
另外,本次设计还有不足:
界面不是特别漂亮,优化界面还有待提高;
参考文献
ARM2410-SforUCOS实验指导书07.02.28
附录部分程序源代码
//*******************************main函数********************************//
voidsettime(void)//设置时间格式
for(a=0x15;
a>
=0x10;
a--)
key=GetKey();
s[b]=key;
if(s[0]==0xf2||s[0]==0x66||s[0]==0xb6||s[0]==0xbe||
s[0]==0xe0||s[0]==0xfe||s[0]==0xf6){s[0]=0xfc;
if(s[2]==0xe0||s[2]==0xfe||s[2]==0xf6){s[2]=0xfc;
if(s[4]==0xe0||s[4]==0xfe||s[4]==0xf6){s[4]=0xfc;
b=b+1;
if(a==0x15){IIC_Write(0x70,0x17,s[0]);
if(a==0x14)
{if((s[0]==0xda&
s[1]==0x66)||(s[0]==
0xda&
s[1]==0xb6)||(s[0]==0xda&
s[1]==0xbe)
||(s[0]==0xda&
s[1]==0xe0)||(s[0]==0xda&
s[1]
==0xfe)||(s[0]==0xda&
s[1]==0xf6)){s[1]=0xfc;
IIC_Write(0x70,0x16,s[1]);
}
if(a==0x13){IIC_Write(0x70,0x14,s[2]);
if(a==0x12){IIC_Write(0x70,0x13,key);
if(a==0x11){IIC_Write(0x70,0x11,s[4]);
if(a==0x10){IIC_Write(0x70,0x10,key);
IIC_Write(0x70,0x15,0x02);
hour=change(s[0])*10+change(s[1]);
minut=change(s[2])*10+change(s[3]);
second=change(s[4])*10+change(s[5]);
b=0;
i++){s1[i]=s[i];
intmain(void)
{
ARMTargetInit();
Timer1_init();
Key_init();
Led_IIC_init();
LCD_Init();
LCD_Cls();
settime();
while
(1)
if(flag==1)
bkey=GetKey();
if(bkey==0xce){flag=2;
}//加计时
if(bkey==0x3e){flag=3;
}//减计时
}
}
return0;
//*******************************Timer1函数********************************//
intchange(chartime)//找到seg7val-map中与输入时间相同的元素下标
intj;
for(j=0;
j<
=9;
j++)
if(Seg7Val_Map[j]==time)
returnj;
staticvoidTimer1_ISR(intvector,void*data)//时钟开始计时
if(flag==3)
voidTimer1_init(void)
rTCFG0=119;
//prescaler=119,也可取0-255,对应的rTCFG1=0x10;
rTCFG1=0x30;
//clockdivider=16
rTCNTB1=26406;
//pclk=50.7Mhz,rTCNTB1=50700000/(119+1)/16
rTCMPB1=0x0;
rTCON=(1<
<
11)|(1<
9)|(0<
8);
//手动设置相应定时器的手动更新位:
8:
start/stop9:
manualupdate11:
autoreloadon/off
11)|(0<
9)|(1<
INTS_OFF();
SetISR_Interrupt(IRQ_TIMER1,Timer1_ISR,NULL);
INTS_ON();
voidShow_Time()
IIC_Write(0x70,0x