Pl,lATAtyMCLK
PIO/TAG
实际物理连接如下图(图3),黄色的线为上,绛红色的线接到DVSS上,为地。
P1.1,
给蜂鸣器提供信号,红色的线接到开发板上露出的
VCC
-
J»**
-.■.心p•-■■
蜂鸣器部分如下图,就是用了某个板上的蜂鸣器部分。
图3
"jGt'L£U
电fl电帀弋L-_
■-,尸I』
■"—一
心;
图5
八位数码管部分如下图(图6)
aoaari
2.软件部分:
定义LED3作为时间指示器,每一秒钟改变一次状态(亮
定义LED4作为settime或者setalarm的指示器,若亮则表示在settime状态,若灭则表示在设置alarm状态。
开机默认状态是setalarm状态。
定义K1作为改变成settime状态的键,按下K1后,进入settime状态。
定义K2作为改变成setalarm状态的键,按下K2后,进入setalarm状态。
定义K3作为改变设置第几个数
定义K4作为改变设置数的value
-->火/火-->亮)O
使用WDT勺普通定时器功能,为时钟和蜂鸣器来提供时钟信号。
因为时钟需要的频率为低频率下无法出声。
则在WDT勺中断函数中有如下处理:
设置WDTCTL=WDT_MDLY_0_即2KHZ然后设置staticsecond_cnt=0,当它到达2000,局变量time_1s_ok,当主程序读到time_1s_ok这个标志,就对时间进行更新(在数码管上增加
1HZ,蜂鸣器在
即1s,再修改全
1s)O
当alarm_ok==1(即闹钟设定的时间和当前时间相等时)就按照2KHZ勺频率来让蜂鸣器发声,并通过
alarmcnt==4000来控制蜂鸣器只响2s。
#pragmavector=WDT_VECTOR__interrupt
{
static
static
if
{
voidWDT_lnterrupt(void)
intsecond_cnt=0;intalarm_cnt=0;
(alarm_ok)
P1OUTA=0x02;alarm_cnt++;
if(alarm_cnt==4000)alarm_ok=0;
//P1.1outputToggle
second_cnt++;
time_1s_ok=1;second_cnt=0;P1OUTA=0x01;
读取键值部分就参照例程KB12,通过延时来消除抖动。
进行实验,了解有中断和轮询两种方式来读取键值。
I************************************************************
*key_Event(),检测键盘是否有键按下,如果有获取键值
*************************************************************Ivoidkey_Event(void){
unsignedchartmp;
P1OUT&=0x01;
tmp=P1IN;
II设置P1OU输出值
II获取p1IN
if((key_Pressed==0x00)&&((tmp&0xf0)<0xf0))
II
key_Pressed=1;II
delay();II
check_Key();II
是否有键按下
如果有按键按下,设置key_Pressed标识消除抖动
调用check_Key(),获取键值
elseif((key_Pressed==1)&&((tmp&0xf0)==0xf0))
II
II
II
key_Pressed=0;key_Flag=1;
是否按键已经释放
清除key_Pressed标识设置key_Flag标识
在数码管显示部分也参照例程,
一个led_Display(),因为while循环的速度很快,所以通过
在自己的main函数中只需要修改led_Buf的内容,再在while循环中的末尾加
led_Display()可以实现动态刷新。
I****************************************************
*LED显示,该函数可以放到定时器中断中
****************************************************I
voidled_Display(){unsignedtmp;
tmp=0x01;
P3OUT=NUM_LED[led_Buf[led_Ctrl]];
P4OUT|=0x02;
P4OUT&=0XFD;
P3OUT=~(tmpvvled_Ctrl);
P4OUT|=0x01;
P4OUT&=0XFE;
led_Ctrl=(led_Ctrl+1)%LED_IN_USE;
II
II
II
II
II
II
II
设置显示值
打开数据锁存器
关闭数据锁存
设置那只LED显示
打开控制锁存
关闭控制锁存
设置下一个要显示的LED
四、
实验内容
在MSP430的资源和外接蜂鸣器的基础上,编写一个带校时和闹钟的时钟系统软件。
主要的流程的伪代码是
while
(1)
{
修改time[]中数据,并修改Ied8中的数据判断如果time[]中的值和alarm[]中的值数据一样,setalarm_ok标志位
}
key_Event();//读取键值
switch(key_value)//处理键值的子模块{
在程序中增加一个return_time的变量,设置目的是在设置time或者alarm过程中,如果20s没有按键事件发生,则返回显示时间状态。
状态转换图如下图:
配置好硬件环境,外接上蜂鸣器。
设计软件,上机调试运行。
1.
因为这个实验实际是综合以前的LED数码管,Keyboard,WDT勺部分,遇到的问题不是特别多,
在开始在调试的时候发现无论怎样修改程序,在实验板上跑出的结果都是一样的(不是我修改的程序的正确结果)。
因为以前碰到过类似情况,是通过Projectclean清除以前生成的
Object代码,再重新生成就可以了。
但是这次没有效果。
经过很长时间的查错才发现是在项目的设置里面,选择的是Simulator,而不是FlashOnlineDebug。
所以程序一直没有下载到目标
板上,目标板上跑的是以前固化在上面的程序。
2.
在最初Key_board读取键值时没有参考例程采用消除抖动,就自己直接写的一个读取键值。
尽管以前原理课上也讲过需要消除抖动,但是自己没有一个直观印象。
通过实验发现得到的结果一直不对,问题就是出在按下一次键会读出几次键值。
这种硬件部分的问题只有通过真正的实践才会了解,否则光看看原理脱离硬件,自己推测的结果往往是不正确的。
然后结合硬件和原理,了解读键值可以通过中断和轮询两种方法来进行。
在这次写的程序里面直接采用例程的void
key_Event(void),通过轮询来读取键值。
实际操作时可以对其中通过delay来消抖进行优化,使
用一个Timer来控制Press.Release之类的状态转换。
=/
#define
MSP430F449_H0
#include
#ifndef
LED_IN_USE
#include
"..//..//led//led.c"
#endif
#ifndef
KEY_BOARD
#include
"keyboard12.c"
#endif
#define
key_set_time1
#define
key_set_alarm2
#define
key_change_state3
#define
key_change_value10
unsigned
chartime_1_alarm_2;
unsigned
chartime[3],time_set[3],alarm_set[3];
unsigned
chardis_buff[6];
unsigned
chartime_1s_ok,alarm_ok;
unsigned
charclock_state=6,return_time=0;
voidsetWDT(intmode)
unsignedinttmp;
if(mode==1)
{//定时器模式
WDTCTL=WDT_MDLY_0_5;//1000ms中断间隔IE1|=WDTIE;
P1DIR|=0x01;
P1DIR|=0x02;
P5DIR|=0x02;_EINT();
}elseif(mode==0)
{
//使能WDT中断
//P1.0outputmode//P1.1outputmode//P5.1outputmode
//开中断
//看门狗模式
WDTCTL=WDT_ARST_250;//设置看门狗时间间隔为ms
//在系统加电后,默认子系统时钟频率是M
II延迟
//P5.1outputmode
//lightLED4
//延迟,执行一次tmp--至少要用个指令
for(tmp=0x7fff;tmp>0;tmp--);P1DIR|=0x01;
P1OUT|=0x01;
for(tmp=0x7fff;tmp>0;tmp--);
void
{
time_to_disbuffer(unsignedchar*time)//时钟显示送显示缓冲区函数
unsignedchari,j=0;for
{
(i=0;iv3;i++)
led_Buf[(5-(j++))]=time[i]%10;led_Buf[(5-(j++))]=time[i]/10;
/**********************************************************
*函数说明:
*WDT中断函数
************************************************************/
#pragmavector=WDT_VECTOR__interrupt
{
voidWDT_Interrupt(void)
static
staticif(alarm_ok)
{
intsecond_cnt=0;intalarm_cnt=0;
P1OUTA=0x02;alarm_cnt++;
if(alarm_cnt==4000)alarm_ok=0;}--
//P1.1outputToggle
second_cnt++;
if{
(second_cnt==2000)
time_1s_ok=1;second_cnt=0;P1OUTA=0x01;
/*********************************************
*main()函数
*********************************************/
alarm_ok=0;
time[1]=0;
if(++time[2]>=24)time[2]=0;
if
if
((++return_time>=20)&&(clock_state!
=6))clock_state=6;(clock_state==6)time_to_disbuffer(time);
//match
if((alarm_set[0]==time[0])&&(alarm_set[1]==time[1])&&(alarm_set[2]==time[2])){
alarm_ok=1;
}
//if(key_stime_ok)
{--
//检测按键事件
//检测key_val里是否有键值可以读取
key_Event();
if(key_Flag==1)
{-
key_Flag=0;
switch(key_val)
//恢复键盘按键标识
{case
case
key_set_time:
//settimeclock_state=6;time_1_alarm_2=1;
//亮led4
P50UT|=0x02;
break;
key_set_alarm:
//setalarmclock_state=6;time_1_alarm_2=2;
//灭led4
P5OUT&=〜(0x02);
break;
for(i=0;i<3;i++)
time_set[i]=0;
time_to_disbuffer(time_set);
for(i=0;i<3;i++)time[i]=time_set[i];time_to_disbuffer(time);
}else
{
for(i=0;i<3;i++)
alarm_set[i]=0;
time_to_disbuffer(alarm_set);
if{
(clock_state==6)
//for(i=0;iv3;i++)//time[i]=alarm_set[i];
time_to_disbuffer(time);
}
}
break;
casekey_change_value:
if(time_1_alarm_2==1){
if(clock_state!
=6){
if(clock_state%2)time_set[clock_state/2]+=10;else
{
if((time_set[clock_state/2]%10)==9)time_set[clock_state/2]-=9;
else
time_set[clock_state/2]+=1;
}//endif
if(time_set[0]>=60)time_set[0]-=60;
if(time_set[1]>=60)time_set[1]-=60;
if(time_set[2]>=24)time_set[2]-=10;
time_to_disbuffer(time_set);
}//endif
}//endcase
//响应
else//time_1_alarm_2==2{
return_time=0;
if(clock_state!
=6){
if(clock_state%2)alarm_set[clock_state/2]+=10;else
{
if((alarm_set[clock_state/2]%10)==9)alarm_set[clock_state/2]-=9;
elsealarm_set[clock_state/2]+=1;
}//endif
if(alarm_set[0]>=60)alarm_set[0]-=60;
if(alarm_set[1]>=60)alarm_set[1]-=60;
if(alarm_set[2]>=24)alarm_set[2]-=10;
time_to_disbuffer(alarm_set);
}//endif
}default:
break;
}//endswitch
}//endif
//使用LED数据
}//endif
led_Display();
}//endwhile