当前位置:文档之家› 基于状态机的多功能时钟的设计

基于状态机的多功能时钟的设计

基于状态机的多功能时钟的设计周文敏121035011 电子与通信工程一、实验目的:1.学习常见LCD 驱动程序设计,按键处理等人机对话。

2.学习状态机在监控程序中的应用。

二、实验器材(平台)1、南京师范大学物科院机电控制实验板及其附件(包括一块STC89C52RC单片机和一块1602LCD液晶显示器等);2、装有Keil uVision4单片机开发软平台和STC烧录软件STC_ISP_V483的计算机一台。

三、实验内容1、根据有限状态机的原理和1602液晶显示器以及4X4矩阵键盘的使用方法,在Keil uVision4单片机开发软平台上用C语言编写和调试程序,使该程序能分别实现时钟和闹钟的时、分的调整以及跑表等功能。

2、连接好硬件,利用STC烧录软件STC_ISP_V483下载生成的HEX文件到实验板,在硬件上实现和调试预设的时钟功能。

四、实验电路五、实验原理1、状态机状态机流程图如下所示:图1-1 流程图本时钟一共用到两个按键,R和F。

各个状态的意义:状态0:时钟正常运行;状态1:设置时钟的时;状态2:设置时钟的分;状态3:设置时钟的秒;状态4:进入闹钟设置状态;状态5:设置闹钟的时;状态6:设置闹钟的分;状态7:设置闹钟的秒;各个状态之间的转换关系如图1-1所示。

2、矩阵键盘的构成本设计所用的矩阵键盘如图2-1所示:图2-1 4*4矩阵键盘使用P3口作为数据输入输出口,采用行列反转法来扫描键盘。

采用行列反转法来读取按键,先对行线全部输出为0,然后读入列线值,如果有按键按下,则读入列线值,并输出该列线值,读取行线值,将列线和行线值组合起来返回给主程序判断按下的是什么键。

3、1602液晶显示模块液晶显示器LCD有着显示直观、耗电小、体积小及重量轻等优点,在仪器仪表、家用电器和各类电子装置中得到广泛的应用。

1602可以显示16*2个字符,其基本指令如下:六、实验结果根据图1-1的状态转换关系进行变成,并在硬件上进行实现,具体实现情况由下面的一系列图片来显示:图4-1上电启动,时钟正常开始计时。

图4-2对时间进行设置,图4-2显示的是正在对时针进行设置。

图4-3对闹钟进行设置,图4-3设置的时间为1:06:00。

图4-4当时间运行到1:06:00之后,代表闹铃的P1.1口的LED灯亮起,如图4-5所示。

图4-5图4-6所使用的开发板。

七、总结通过本次设计,我比较深入地了解了通过状态机来进行程序设计的一般方法,并且强化了51单片机编程的语法语句,通过此次的学习,在单片机的开发上我又有了进一步的提高,对单片机的理解也更加深刻。

附录一实验程序://-------------------------------------变量定义------------------------------------------#include "string.h"#include "stdio.h"#include "reg52.h"unsigned char i;//-----LCD16液晶显示控制引脚定义---------sbit E=0xb6; //老板为E=0xb4;sbit RS=0xb7;sfr lcd_dat_port=0x80; //lcd数据口unsigned char lcd_buf[32];//------按键端口定义---------------------sfr key_port=0xa0; //P2口接键盘unsigned char code key_index[16]={0xdb,0xee,0xde,0xbe, //0,1,2,30x7e,0xed,0xdd,0xbd, //4,5,6,70x7d,0xeb,0xbb,0x7b, //8,9,上,下0xe7,0xd7,0xb7,0x77};//左,右,功能,确认unsigned long time_count=0; //时间计数器unsigned long atime_count=0; //闹钟计数器bit ten_ms_flag=0;bit one_s_flag=0;bit half_s_flag=0;unsigned char mode=0; //工作模式变量//mode=0;实时时钟//mode=1;闹钟//mode=2;码表unsigned int sec=0;unsigned int min=0;unsigned int hour=0;unsigned int asec=0;unsigned int amin=12;unsigned int ahour=12;unsigned char state=0; //状态机变量//state=0: 显示实时时钟//state=1:设置小时,秒数置0//state=2: 设置分钟,秒数置0//-----------------------------变量定义结束------------------------------------------------/*----------------- 约延时100us --------------------*/delay(unsigned int dy){unsigned int ii;while(--dy)for(ii=0;ii<22;ii++) ;}//--------------写一个字节到液晶------------------------void lcd_write(bit slr,unsigned char write_dat){RS=slr;lcd_dat_port=write_dat;E=1;delay(2);E=0;}//--------------液晶初始化-----------------------------void ini_lcd(){delay(50);lcd_write(0,0x38);lcd_write(0,0x0F);lcd_write(0,0x06);lcd_write(0,0x01);delay(50);}//-------------------------液晶显示--------------------------void display(unsigned char *P_LCD) //将指针P_LCD所指内容显示{unsigned char ii;lcd_write(0,0x80); //光标复位for(ii=0;ii<16;ii++){lcd_write(1,*P_LCD);P_LCD++;}lcd_write(0,0xc0);for(ii=0;ii<16;ii++){lcd_write(1,*P_LCD);P_LCD++;}}//------定时器T0计10ms,作为最小计时单位--------void Timer0() interrupt 1{TH0=(65536-18400)/256; //22.1184MHz晶振,18432个机器周期约为10毫秒 TL0=(65536-18400)%256;time_count++;if(time_count % 100==0) one_s_flag=1; //100*10ms=1sif(time_count % 50==0) half_s_flag=1; //50*10ms=0.5s}//----------- T0初始化设置,--------------------------//功能: 设置T0定时10msvoid ini_T0(){TMOD=0x01; //T0:定时方式1,16位定时器TH0=(65536-18400)/256; //22.1184MHz晶振,18400个机器周期约为10毫秒 TL0=(65536-18400)%256;EA=1;ET0=1; //开定时器T0中断TR0=1; //计时开始}//-----------显示时间时,闪烁时分、分秒之间的分割点------void second_point_flash(){if (half_s_flag==1 && one_s_flag==1){half_s_flag=0;one_s_flag=0;lcd_buf[21]=':';}else if (half_s_flag==1 && one_s_flag==0){half_s_flag=0;lcd_buf[21]=' ';}}//-----------整形数转换为两位ASCII码-------------------void Int2Char (unsigned char IntNumber,unsigned char *P){if (IntNumber < 100){*P =IntNumber/10+'0';P++;*P= IntNumber%10 +'0';}}//-----------显示即时时间 -----------------------------void display_real_time(){//lcd_write(0,0x0c); //关光标sec=(time_count/100)%60;min=(time_count/100/60)%60;hour=(time_count/100/3600)%24;Int2Char(hour,lcd_buf+16);//时分秒转换成ASCII码,并存入lcd_buf相关单元内 Int2Char(min,lcd_buf+19);Int2Char(sec,lcd_buf+22);display(lcd_buf);if(sec==0&&min==amin&&hour==ahour){ini_lcd();strcpy(lcd_buf,"time is up ");display(lcd_buf);delay(10000); //10msini_lcd();strcpy(lcd_buf,"Real-time Clock 00-00:00 0");display(lcd_buf);delay(10000); //10ms}}void display_alarm_time(){//lcd_write(0,0x0c); //关光标Int2Char(ahour,lcd_buf+16);//时分秒转换成ASCII码,并存入lcd_buf相关单元内 Int2Char(amin,lcd_buf+19);Int2Char(asec,lcd_buf+22);display(lcd_buf);}//-------------- 线路反转法按键子程序 ----------------------unsigned char get_key(){unsigned char key1,key2,ii;key_port=0xf0;if (key_port!=0xf0){key1=key_port;delay(100); //10ms消抖动if(key1==key_port) //延时10ms后键不变{key_port=0x0f; //高低4位0,1反转key2=key_port;key1=key1|key2;for(ii=0;ii<16;ii++){if(key1==key_index[ii]){key_port=0xf0; //等待释放按键while(key_port!=0xf0);delay(100);while(key_port!=0xf0);return(ii);}}return(0xff);}else return(0xff);}else return(0xff);}//------------------移动当前光标 ----------------------void move_cursor(unsigned char position){if(position<16) lcd_write(0,0x80+position); //第一行光标闪烁else if (position<32) lcd_write(0,0x80+0x40+position-16); //第二行光标闪烁}//------------------状态转换---------------------------void state_convert(unsigned key){if(mode==0){if(state==0){if(key==13){state=1; //右箭头键move_cursor(17);}else if(key==11){mode=1;}}else if(state==1){if(key==13){state=2; //右箭头键move_cursor(20);}else if(key==11){min=(time_count/100/60)%60;hour=(time_count/100/3600)%24;if(hour<23) hour++;else hour=0;time_count=hour*3600L*100L+min*60L*100L;display_real_time();move_cursor(17);}}else if(state==2){if(key==13) state=0; //右箭头键else if(key==11)min=(time_count/100/60)%60;hour=(time_count/100/3600)%24;if(min<59) min++;else min=0;time_count=hour*3600L*100L+min*60L*100L;display_real_time();move_cursor(20);}}}else if(mode==1){if(state==0){if(key==13){state=1; //右箭头键move_cursor(17);}if(key==11){mode=0;}}else if(state==1){if(key==13){state=2; //右箭头键move_cursor(20);}else if(key==11){asec=(atime_count/100)%60;amin=(atime_count/100/60)%60;ahour=(atime_count/100/3600)%24;if(ahour<23) ahour++;else ahour=0;atime_count=ahour*3600L*100L+amin*60L*100L; display_alarm_time();move_cursor(17);}else if(state==2){if(key==13) state=0; //右箭头键else if(key==11){asec=(atime_count/100)%60;amin=(atime_count/100/60)%60;ahour=(atime_count/100/3600)%24;if(amin<59) amin++;else amin=0;atime_count=ahour*3600L*100L+amin*60L*100L;display_alarm_time();move_cursor(20);}}}}//----------------------主程序------------------------------ main(){unsigned char key;unsigned char sec,min,hour;ini_lcd();ini_T0();while(1){strcpy(lcd_buf,"Real-time Clock 00-00:00 0");display(lcd_buf);while(mode==0){key=get_key();if(key!=0xFF){state_convert(key);}if(state==0) //状态0需要不断更新显示{second_point_flash();display_real_time();}ini_lcd();strcpy(lcd_buf,"Alarm Clock 00-00:00 0"); display(lcd_buf);while(mode==1){key=get_key();if(key!=0xFF) state_convert(key);if(state==0){second_point_flash();display_alarm_time();}}ini_lcd();}}。

相关主题