嵌入式系统编程实践数字钟.docx
《嵌入式系统编程实践数字钟.docx》由会员分享,可在线阅读,更多相关《嵌入式系统编程实践数字钟.docx(21页珍藏版)》请在冰豆网上搜索。
嵌入式系统编程实践数字钟
实验报告
课程名称嵌入式系统编程实践
实验仪器清华同方辰源嵌入式系统实验箱
实验名称实验五:
数字钟实验
系别__计算机学院_
专业______
班级/学号__
学生姓名
实验日期
成绩___________________
指导教师_____
实验五:
数字钟实验
一、实验问题回答
(1)画出数字时钟的有限状态自动机,列出全部状态、状态转换规则,以及对应状态下的动作。
按A键
按A键
按B键设置结束按C键
按C键按B键
(2)倒计时和正计时怎么设置?
答:
先添加一个功能键,令其完成的功能是实现倒计时和正计时。
正计时实现利用
if(ms>=99){
ms=0;
if(s>=59){
s=0;
if(m>=59){
m=0;
}
else{
m++;
}
}
else{
s++;
}
}
else{
ms++;
}
在毫秒计数满100令其置零,并向秒进1,秒计数满60令其置零,并向分钟进1。
在其后面加上代码段
else{
if(ms<=0){
ms=99;
if(s<=0){
s=59;
if(m<=0){
m=59;
}
else{
m--;
}
}
else{
s--;
}
}
else{
ms--;
}
}
若毫秒小于等于0责令其变为0,秒计数-1,若秒小于等于0责令其变为0,分钟计数-1,即可实现倒计时功能。
二、实验目的和效果
(1)学习、理解、掌握利用状态机模型实现数字钟系统
实验结果及检查
(1)6个数码管上显示样式改为“分钟+秒+百分之一秒”,其中各占两个数码管。
(2)OLED屏幕上显示和数码管一样效果,“分钟:
秒:
百分之一秒”各占两个字符。
(3)屏幕上显示功能选单,通过键盘A-F键选择不同功能,选择后屏幕显示相关功能提示,并在数码管和OLED屏幕上显示相应功能。
如:
开始显示:
“pleasechoosethefunction:
”“A:
…”“B:
…”“C:
…”“D:
…”
按下“A”键后,显示”nowyouchoosefunctionA”
(4)按下“A”键,暂停,再按“A”键,继续。
(5)按下“B”键,表示设置时钟时间,从前往后或从后往前逐次设置时钟值。
(6)按下“C”键,OLED和数码管回归“00:
00:
00”。
(7)扩展:
按下“D”键,倒计时,再按“D”键,正计时。
三、实验内容和步骤(重点阐述自己的思路及遇到的问题)
(一)Keil开发环境中对项目Project配置
(1)建立项目
1、新建一个project;
2、选择CPU中的LuminaryLM3S8962;
3、加载库文件;
4、项目相关配置项修改。
(二)新建主函数程序,并加载到项目中
(1)加载必要程序
本次实验提供了几个源程序rit128x96x4.h,rit128x96x4.c,startup.s,utility.c,utility.h,definition.h都压在work2.zip中,与实验一
(二)
(1)步骤类似。
其中,definition.h文件中定义了一些宏定义,用于将整个工程中的宏定义放在一起,目的是为了程序的可读性更好。
本例中定义了五个不同的功能模式,可以根据自己习惯进行修改。
Utility.c和utility.h中包含了数码管显示处理函数。
其函数声明如下:
voiddisp(charx,intlocation);使用方法:
第一个参数表示要显示的字符,在本例中,就是键盘中断服务程序执行完后保存在oledkey[0]里的字符,第二个参数表示显示的位置,其中1表示数码管的最右端,6表示数码管的最左端,2-4依次表示中间4个数码管。
新建一个文件,保存为main.c,把main.c也加载到项目中,与实验一
(二)
(2)步骤类似。
本次实验需要增加以下头文件
#include
#include
#include
#include
#include
#include
#include
#include
#include"rit128x96x4.h"
#include"utility.h"
#include"definition.h"
(2)系统初始化
SysCtlClockSet(SYSCTL_SYSDIV_1|SYSCTL_USE_OSC|SYSCTL_OSC_MAIN|SYSCTL_XTAL_8MHZ);
/*使能外设GPIO*/
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
/*配置GPIO端口为输出*/
//7segd1(PB6);7segd2(PB4);7segd3(PB5)
GPIOPinTypeGPIOOutput(GPIO_PORTB_BASE,GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6);
//bitcode0(PC5);bitcode1(PC6);bitcode2(PC7)
GPIOPinTypeGPIOOutput(GPIO_PORTC_BASE,GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7);
//7segd0(PD4);7segdot(PD5);rst(PD6)
GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE,GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6);
/*设置GPIO为输入*/
GPIOPinTypeGPIOInput(GPIO_PORTD_BASE,GPIO_PIN_7);
GPIOPinTypeGPIOInput(GPIO_PORTC_BASE,GPIO_PIN_4);
/*使能中断*/
IntEnable(INT_GPIOD);
IntMasterEnable();
GPIOPinIntEnable(GPIO_PORTD_BASE,GPIO_PIN_7);
GPIOIntTypeSet(GPIO_PORTD_BASE,GPIO_PIN_7,GPIO_RISING_EDGE);
(3)利用键盘GPIOPortD中断,接收键盘输入
本步骤与实验
(二)对应部分一样,不再重复。
(4)利用系统Time0中断,来控制控制时钟速度
/*使能中断*/
IntEnable(INT_GPIOD);
IntMasterEnable();
GPIOPinIntEnable(GPIO_PORTD_BASE,GPIO_PIN_7);
GPIOIntTypeSet(GPIO_PORTD_BASE,GPIO_PIN_7,GPIO_RISING_EDGE);
/*计时器初始化*/
timerset();
初始化的具体函数实现
voidtimerset()
{
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
TimerConfigure(TIMER0_BASE,TIMER_CFG_32_BIT_PER);
TimerLoadSet(TIMER0_BASE,TIMER_A,SysCtlClockGet()/100);//不除以100则1秒中断一次
IntEnable(INT_TIMER0A);
TimerIntEnable(TIMER0_BASE,TIMER_TIMA_TIMEOUT);
}
通过对Timer0中断进行使能和屏蔽来实现秒表的暂停和恢复
TimerEnable(TIMER0_BASE,TIMER_A);
TimerDisable(TIMER0_BASE,TIMER_A);
中断处理函数实例
voidTimer0IntHandler(void)
{
unsignedlongulStatus;
ulStatus=TimerIntStatus(TIMER0_BASE,true);//获取当前中断状态
TimerIntClear(TIMER0_BASE,TIMER_TIMA_TIMEOUT);//清除全部中断状态
if(ulStatus&TIMER_TIMA_TIMEOUT)//如果是超时中断
{
//补充该部分代码
//每次计时中断,相应计数值进行变化
}
}
(5)修改主函数,实现本次实验要求的功能
选好A、B、F功能后,按键后在数码管上按照不同的功能显示秒表显示效果。
自己设计程序逻辑并实现。
注意:
数码管上所有位置的数字同时显示,可以使用for循环赋值并进行显示:
for(j=1;j<7;j++)
{
disp(digits[j],j);
for(k=0;k}
计数值如m,s,ms分别表示分钟,秒,百分之一秒的具体数值,是个整数,方便计数,但在OLED上显示需要转换成字符格式。
charbuf[2];
sprintf(buf,“%d”,m);
再显示buf[0]和buf[1]的字符
暂停的功能实现:
关掉中断即可、
(6)编译、连接,生成可执行程序文件
(编译)
(链接)
(7)反复(3)--(7)步骤,直到完成
如果中间出现错误,修改代码,一直到无错,生成最后程序。
(三)硬件连接
(1)接上电源线,先关闭开关
(2)用蓝色USB线接上仿真器,仿真器另一JTAG端接LM3S8962CPU板(左下较大子板),USB线接电脑
(3)确认连接无误后,打开电源开关
(四)联调
(1)在KeiluVision4中执行下载,(Flash菜单---Download),即可通过仿真器将
(一)步编译链接好的执行程序下载到LM3S8962芯片内的Flash中。
(2)按下实验箱上LM3S8962子板屏幕上方的白色按钮Reset键,即可查看程序执行效果。
若有问题,返回第一步继续修改程序,编译、链接、下载,一直到显示出满意的效果。
实验代码:
main.c
#include
#include
#include
#include
#include
#include
#include
#include
#include"rit128x96x4.h"
#include"utility.h"
#include"definition.h"
intEvent_key=0;
intb_press_count=0;
intc_press_count=0;
intcountdown_flag=0;//倒计时标记,1表示倒计时;0表示正常计时
intkey_i=0;//i定义为全局变量,因为只有1根线GPIO_PIN_4与CPU相联,所以一个按键(16种,4bit表示)需要四次中断才能传给CPU。
unsignedcharucValue=0x00;//ucValue定义为全局变量,该值存储输入的按键值的中间结果。
charoledkey[2];//设置全局变量oledkey用于保存键盘输入的按键
charkeychar[1];
intkey_press_flag=0;//有没有按键,0表示没有,1表示有
intA_flag,B_flag,C_flag,D_flag,E_flag,F_flag;//按键ABCDEF状态,0表示未选中,1表示选中
intled_postion;//led位置
chardigits[7];//6个位置的数字字符
intinputnext=0;//检测有无下一个输入数字,0表示没有,1表示有。
charcm[3];//cm[2]=cs[0]
charcs[3];
charcms[3];
intm=0,s=0,ms=0;
intE_clr=0;
//时钟中断处理函数实例
voidTimer0IntHandler(void)
{
unsignedlongulStatus;
ulStatus=TimerIntStatus(TIMER0_BASE,true);//获取当前中断状态
TimerIntClear(TIMER0_BASE,TIMER_TIMA_TIMEOUT);//清除全部中断状态
if(ulStatus&TIMER_TIMA_TIMEOUT)//如果是超时中断
{if(countdown_flag==0){
if(ms>=99){
ms=0;
if(s>=59){
s=0;
if(m>=59){
m=0;
}
else{
m++;
}}
else{
s++;
}}
else{
ms++;
}}
else{
if(ms<=0){
ms=99;
if(s<=0){
s=59;
if(m<=0){
m=59;
}
else{
m--;
}}
else{
s--;
}}
else{
ms--;
}}
//补充该部分代码
//每次计时中断,相应计数值进行变化
}}
//键盘中断服务函数
voidGPIO_PORT_D_ISR(void)
{
unsignedcharucKey;
unsignedlongulStatus;
ulStatus=GPIOPinIntStatus(GPIO_PORTD_BASE,true);
GPIOPinIntClear(GPIO_PORTD_BASE,ulStatus);
if(ulStatus&GPIO_PIN_7)
{
ucKey=GPIOPinRead(GPIO_PORTC_BASE,GPIO_PIN_4);
ucKey=ucKey>>1;
ucValue=ucValue+ucKey;
ucValue=ucValue<<1;
key_i++;
if(key_i==4)
{
key_i=0;
Event_key=1;
oledkey[1]='\0';
if((ucValue>>4)<10)
oledkey[0]=(ucValue>>4)+48;
else
oledkey[0]=(ucValue>>4)-10+'A';
}}}
//计时器初始化函数
voidtimerset()
{
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
TimerConfigure(TIMER0_BASE,TIMER_CFG_32_BIT_PER);
TimerLoadSet(TIMER0_BASE,TIMER_A,SysCtlClockGet()/100);//不除以100则1秒中断一次
IntEnable(INT_TIMER0A);
TimerIntEnable(TIMER0_BASE,TIMER_TIMA_TIMEOUT);
}
//更新led
//暂停或者继续
voidgoOn_pause(inti)
{
//如果是奇数次(第一次)按B就是暂停,偶数次(第二次)就是恢复
if((i%2)==1)
TimerEnable(TIMER0_BASE,TIMER_A);//恢复
else
TimerDisable(TIMER0_BASE,TIMER_A);//暂停
}
//倒计时
voidcountdown(inti)
{
if((i%2)==1)
countdown_flag=1;
else
countdown_flag=0;
}
voiddispled(){
inti,k;
for(i=1;i<=6;i++){
disp(digits[i],i);
for(k=0;k<200;k++);
}}
voidclear(){
inti;
for(i=1;i<=6;i++)
digits[i]='0';
}
//主函数
intmain()
{charbuf[5];
SysCtlClockSet(SYSCTL_SYSDIV_1|SYSCTL_USE_OSC|SYSCTL_OSC_MAIN|SYSCTL_XTAL_8MHZ);
RIT128x96x4Init(1000000);
RIT128x96x4Clear();
/*使能外设GPIO*/
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
/*配置GPIO端口为输出*/
//7segd1(PB6);7segd2(PB4);7segd3(PB5)
GPIOPinTypeGPIOOutput(GPIO_PORTB_BASE,GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6);
//bitcode0(PC5);bitcode1(PC6);bitcode2(PC7)
GPIOPinTypeGPIOOutput(GPIO_PORTC_BASE,GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7);
//7segd0(PD4);7segdot(PD5);rst(PD6)
GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE,GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6);
/*设置GPIO为输入*/
GPIOPinTypeGPIOInput(GPIO_PORTD_BASE,GPIO_PIN_7);
GPIOPinTypeGPIOInput(GPIO_PORTC_BASE,GPIO_PIN_4);
/*使能中断*/
IntEnable(INT_GPIOD);
IntMasterEnable();
GPIOPinIntEnable(GPIO_PORTD_BASE,GPIO_PIN_7);
GPIOIntTypeSet(GPIO_PORTD_BASE,GPIO_PIN_7,GPIO_RISING_EDGE);
/*计时器初始化*/
timerset();
//默认
RIT128x96x4StringDraw("2011011374",0,0,15);
RIT128x96x4StringDraw("pengxin",0,10,15);
RIT128x96x4StringDraw("Work5",0,20,15);
RIT128x96x4StringDraw("pleasechoose",0,30,15);
RIT128x96x4StringDraw("A:
start",5,40,15);
RIT128x96x4StringDraw("B:
inputchar",5,50,15);
//RIT128x96x4StringDraw("B:
pause",5,50,15);
RIT128x96x4StringDraw("C:
clear",5,60,15);
RIT128x96x4StringDraw("D:
countdown",5,70,15);
//RIT128x96x4StringDraw("B:
inputchar",5,70,15);
while
(1)
{
if(Event_key)
{
Event_key=0;
if('A'<=oledkey[0]&&oledkey[0]<='F')
{
//显示按下的字母
keychar[0]=oledkey[0];
RIT128x96x4StringDraw(keychar,90,30,15);
//只要按ABCDEF中任意一个都必须先把A_flag,B_flag,D_flag,F_flag置0,避免混乱。
A_flag=B_flag=D_flag=E_flag=F_flag=0;
switch(oledkey[0]){
case'A':
A_flag=1;//开始
TimerEnable(TIMER0_BASE,TIMER_A);
b_press_count=b_press_count+1;
TimerDisable(TIMER0_BASE,TIMER_A);
goOn_pause(b_press_count);
break;
case'B':
E_flag=1;//input
E_clr=1;
m=s=ms=0;
TimerDisable(TIMER0_BASE,TIMER_A);
clear();
led_postion=6;
break;
case'C':
D_flag=1;//qing0
TimerDisable(TIMER0_BASE,TIMER_A);
m=s=m