目录
1.前言
1.1实验现象
1.2 项目资源
2.主要程序及解释
2.1中断中进行按键扫描
2.2 中断中进行数码管扫描
2.3中断中进行秒表的驱动
2.4主函数
1.前言
1.1实验现象
实验现象:按下K1并松开按键秒表开始计时,按下K2并松开按键秒表停止计时,按下K3并松开数据存储到AT24C02中,按下K4并松开读取AT24C02中存储的数据显示在数码管上;
1.2 项目资源
https://download.csdn.net/download/YLG_lin/86544425
2.主要程序及解释
本次实验用到数码管扫描;按键扫描;AT24C02;还有就是定时器;秒表在运行中按键与数码管都要用到定时器进行不断的定时扫描,但1个定时器只能有1个中断;为了解决这个问题,我们只需要在中断里不断调用按键扫描与数码管扫描这两个模块就ok了;
2.1中断中进行按键扫描
void Timer0_Routine() interrupt 1
{static unsigned int T0Count1,T0Count2,T0Count3;TL0 = 0x18; //设置定时初值TH0 = 0xFC; //设置定时初值(1ms)T0Count1++;if(T0Count1>=20){T0Count1=0;Key_Loop(); //20ms调用一次按键驱动函数}T0Count2++;if(T0Count2>=2){T0Count2=0;xianshi_Loop();//2ms调用一次数码管驱动函数}T0Count3++;if(T0Count3>=10){T0Count3=0;Sec_Loop(); //10ms调用一次数秒表驱动函数}
}
unsigned char Key_KeyNumber;/*** @brief 获取按键键码* @param 无* @retval 按下按键的键码,范围:0,1~4,0表示无按键按下*/
unsigned char Key(void)
{unsigned char Temp=0;Temp=Key_KeyNumber;Key_KeyNumber=0;return Temp;
}/*** @brief 获取当前按键的状态,无消抖及松手检测* @param 无* @retval 按下按键的键码,范围:0,1~4,0表示无按键按下*/
unsigned char Key_GetState()
{unsigned char KeyNumber=0;if(P3_1==0){KeyNumber=1;}if(P3_0==0){KeyNumber=2;}if(P3_2==0){KeyNumber=3;}if(P3_3==0){KeyNumber=4;}return KeyNumber;
}/*** @brief 按键驱动函数,在中断中调用* @param 无* @retval 无*/
void Key_Loop(void)
{static unsigned char NowState,LastState;LastState=NowState; //按键状态更新NowState=Key_GetState(); //获取当前按键状态//如果上个时间点按键按下,这个时间点未按下,则是松手瞬间,以此避免消抖和松手检测if(LastState==1 && NowState==0){Key_KeyNumber=1;}if(LastState==2 && NowState==0){Key_KeyNumber=2;}if(LastState==3 && NowState==0){Key_KeyNumber=3;}if(LastState==4 && NowState==0){Key_KeyNumber=4;}
}
2.2 中断中进行数码管扫描
void Timer0_Routine() interrupt 1
{static unsigned int T0Count1,T0Count2,T0Count3;TL0 = 0x18; //设置定时初值(1ms)TH0 = 0xFC; //设置定时初值T0Count1++;if(T0Count1>=20){T0Count1=0;Key_Loop(); //20ms调用一次按键驱动函数}T0Count2++;if(T0Count2>=2){T0Count2=0;xianshi_Loop();//2ms调用一次数码管驱动函数}T0Count3++;if(T0Count3>=10){T0Count3=0;Sec_Loop(); //10ms调用一次数秒表驱动函数}
}
//数码管显示缓存区
unsigned char xianshi_Buf[9]={0,10,10,10,10,10,10,10,10};//数码管段码表
unsigned char xianshi_Table[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00,0x40};/*** @brief 设置显示缓存区* @param Location 要设置的位置,范围:1~8* @param Number 要设置的数字,范围:段码表索引范围* @retval 无*/
void xianshi_SetBuf(unsigned char Location,Number)
{xianshi_Buf[Location]=Number;
}/*** @brief 数码管扫描显示* @param Location 要显示的位置,范围:1~8* @param Number 要显示的数字,范围:段码表索引范围* @retval 无*/
void xianshi_Scan(unsigned char Location,Number)
{P0=0x00; //段码清0,消影switch(Location) //位码输出{case 1:P2_4=1;P2_3=1;P2_2=1;break;case 2:P2_4=1;P2_3=1;P2_2=0;break;case 3:P2_4=1;P2_3=0;P2_2=1;break;case 4:P2_4=1;P2_3=0;P2_2=0;break;case 5:P2_4=0;P2_3=1;P2_2=1;break;case 6:P2_4=0;P2_3=1;P2_2=0;break;case 7:P2_4=0;P2_3=0;P2_2=1;break;case 8:P2_4=0;P2_3=0;P2_2=0;break;}P0=xianshi_Table[Number]; //段码输出
}/*** @brief 数码管驱动函数,在中断中调用* @param 无* @retval 无*/
void xianshi_Loop(void)
{static unsigned char i=1;xianshi_Scan(i,xianshi_Buf[i]);i++;if(i>=9){i=1;}
}
2.3中断中进行秒表的驱动
static 修饰的是静态变量;把值放到静态区,直到程序全部运行完毕才会销毁;
void Timer0_Routine() interrupt 1
{static unsigned int T0Count1,T0Count2,T0Count3;TL0 = 0x18; //设置定时初值TH0 = 0xFC; //设置定时初值(1ms)T0Count1++;if(T0Count1>=20){T0Count1=0;Key_Loop(); //20ms调用一次按键驱动函数}T0Count2++;if(T0Count2>=2){T0Count2=0;xianshi_Loop();//2ms调用一次数码管驱动函数}T0Count3++;if(T0Count3>=10){T0Count3=0;Sec_Loop(); //10ms调用一次数秒表驱动函数}
}
/*** @brief 秒表驱动函数,在中断中调用* @param 无* @retval 无*/
void Sec_Loop(void)
{if(RunFlag){MiniSec++;if(MiniSec>=100){MiniSec=0;Sec++;if(Sec>=60){Sec=0;Min++;if(Min>=60){Min=0;}}}}
}
2.4主函数
首先定时器进行初始化(设置初值,定时器工作模式等),在while循环中不断进行着按键扫描与数码管扫描;其中RunFlag 为启动标志位;AT24C02写周期需要延迟5ms,具体可以查看芯片手册;把分写进0地址,把秒写进1地址;Min/10取十位,Min%10取个位. . .
unsigned char KeyNum;
unsigned char Min,Sec,MiniSec;
unsigned char RunFlag;void main()
{Timer0_Init();while(1){KeyNum=Key();if(KeyNum==1) //K1按键按下{RunFlag=!RunFlag; }if(KeyNum==2) //K2按键按下{Min=0; //分秒清0Sec=0;MiniSec=0;}if(KeyNum==3) //K3按键按下{AT24C02_WriteByte(0,Min); //将分秒写入AT24C02Delay(5);AT24C02_WriteByte(1,Sec);Delay(5);AT24C02_WriteByte(2,MiniSec);Delay(5);}if(KeyNum==4) //K4按键按下{Min=AT24C02_ReadByte(0); //读出AT24C02数据Sec=AT24C02_ReadByte(1);MiniSec=AT24C02_ReadByte(2);}xianshi_SetBuf(1,Min/10); //设置显示缓存,显示数据xianshi_SetBuf(2,Min%10);xianshi_SetBuf(3,11); //显示——xianshi_SetBuf(4,Sec/10);xianshi_SetBuf(5,Sec%10);xianshi_SetBuf(6,11); //显示——xianshi_SetBuf(7,MiniSec/10);xianshi_SetBuf(8,MiniSec%10);}
}