写在前面
经过一段时间的学习,我们已经学会了基本C51语言的逻辑及框架,现在让我们来实现第一个有实际意义的程序吧
一、要求
定义矩阵键盘S5为闹钟设置界面,按下后进入闹钟设置界面
定义矩阵键盘S6为时钟设置界面,按下后进入时钟设置界面
定义矩阵键盘S7为时钟显示按键,按下后进入时钟显示界面
定义矩阵键盘S8为数加按键,处于设置模式时对当前设置位减一
定义矩阵键盘S9为数加按键,处于设置模式时对当前设置位增一
定义矩阵键盘S10为位减按键,处于设置模式时切换上一个设置位
定义矩阵键盘S11为位加按键,处于设置模式时切换下一个设置位
定义矩阵键盘S16为数加按键,处于设置模式时保存当前设置
二、实现思路
1.组成部分
定时器、按键处理、数码管处理、蜂鸣器处理、中断服务、主函数
2.思路
按键处理把按键输入转成Key_void,检测下降沿给Key_down,通过switch语句把按键输入功能对印上,用Seg_mod区分数码管显示状态,通过按键输入改变Seg_mod,设置三种状态,分别是:0-时钟显示、1-时钟设置、2-闹钟设置,用临时变量Seg_set存储设置数据,在按下设置按键(S6、S5)时把时钟数据或闹钟数据赋值给Seg_set,设置完成后按下保存(S16),将Seg_set赋值给时钟数据或者闹钟数据,当Clock==Seg_time时,使能蜂鸣器
三、代码
1.头文件
Seg.h(位选、段选)
#include "Seg.h"
unsigned char code Seg_duan[] = {
0xc0,0xf9,0xa4,0xb0,0x99,//0~5
0x92,0x82,0xf8,0x80,0x90,//6~10
0x88,0x83,0xc6,0xa1,0x86,//A~E
0x8e,0xbf,0x7f,0x00,0xff,//F,-,.
0x40,0x79,0x24,0x30,0x19,//0~5
0x12,0x02,0x78,0x00,0x10,//6~10
0x08,0x03,0x46,0x21,0x06,//A~E
0x0e//F
};
unsigned char code Seg_dian[]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0x08,0x03,0x46,0x21,0x06,0x0e};
unsigned char code Seg_wei[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
void Seg_disp(unsigned char wei,duan)
{
//消影
P2=(P2&0x1f)|0xc0;
P0=0x00;
P2&=0x1f;
//段选
P2=(P2&0x1f)|0xe0;
P0=Seg_duan[duan];
P2&=0x1f;
//位选
P2=(P2&0x1f)|0xc0;
P0=Seg_wei[wei];
P2&=0x1f;
}
Key.h(矩阵键盘)
#include "Key.h"
void Delay_ms(int xms) //15单片机延时函数
{
int i;
long a;
for (i = xms; i > 0; i --)
for(a = 810; a > 0; a --);
}
unsigned char Key_read()
{
unsigned char KeyNumber = 0;
unsigned char temp;
//第一列
P3 = 0x7F; //P37 = 0,其他是1,检测第一列
P4 = 0xEF; //P44 = 0; P42 = 1; //15单片机第一列占用的引脚
temp = P3; //按键检测,输入
temp &= 0x0F;
if(temp != 0x0F)
{
Delay_ms(20); //延时20ms来确认是否真正按下按键
temp = P3;
temp &= 0x0F;//检测是第一列哪个按键
if(temp != 0x0F)
{
temp = P3;
switch (temp)
{
case 0x7E : KeyNumber = 7; break;
case 0x7D : KeyNumber = 6; break;
case 0x7B : KeyNumber = 5; break;
case 0x77 : KeyNumber = 4; break;
}
while(temp != 0x0f)
{
temp = P3;
temp &= 0x0F; //因为这条,所以松手检测才写成 temp != 0x0f
}
}
}
//第二列
P3 = 0xBF;
P4 = 0xFB; //P42 = 0; P44 = 1; //15单片机第二列占用的引脚
temp = P3;
temp &= 0x0F;
if(temp != 0x0F)
{
Delay_ms(20);
temp = P3;
temp &= 0x0F;
if(temp != 0x0F)
{
temp = P3;
switch (temp)
{
case 0xBE : KeyNumber = 11; break;
case 0xBD : KeyNumber = 10; break;
case 0xBB : KeyNumber = 9; break;
case 0xB7 : KeyNumber = 8; break;
}
while(temp != 0x0f)
{
temp = P3;
temp &= 0x0F; //因为这条,所以松手检测才写成 temp != 0x0f
}
}
}
//第三列
P3 = 0xDF;
P4 = 0xFF;
temp = P3;
temp &= 0x0F;
if(temp != 0x0F)
{
Delay_ms(20);
temp = P3;
temp &= 0x0F;
if(temp != 0x0F)
{
temp = P3;
switch (temp)
{
case 0xDE : KeyNumber = 15; break;
case 0xDD : KeyNumber = 14; break;
case 0xDB : KeyNumber = 13; break;
case 0xD7 : KeyNumber = 12; break;
}
while(temp != 0x0f)
{
temp = P3;
temp &= 0x0F; //因为这条,所以松手检测才写成 temp != 0x0f
}
}
}
//第四列
P3 = 0xEF;
temp = P3;
temp &= 0x0F;
if(temp != 0x0F)
{
Delay_ms(20);
temp = P3;
temp &= 0x0F;
if(temp != 0x0F)
{
temp = P3;
switch (temp)
{
case 0xEE : KeyNumber = 19; break;
case 0xED : KeyNumber = 18; break;
case 0xEB : KeyNumber = 17; break;
case 0xE7 : KeyNumber = 16; break;
}
while(temp != 0x0f)
{
temp = P3;
temp &= 0x0F; //因为这条,所以松手检测才写成 temp != 0x0f
}
}
}
return KeyNumber;
}
Seg.c
#include <stc15f2k60s2.h>
void Seg_disp(unsigned char wei,duan);
Key.c
#include <stc15f2k60s2.h>
unsigned char Key_read();
2.主函数
/* 头文件声明 */
#include <stc15f2k60s2.h>
#include "Key.h"
#include "Seg.h"
/* 定义 */
#define uint unsigned int
#define uchar unsigned char
/* 变量声明 */
uchar Key_slow;//10ms
uchar Key_val,Key_down,Key_old=0;//按键扫描
uchar Seg_pos;
uchar Seg_buf[8];//位选,段选
uchar Seg_mod=0;//数码管模式 0-显示,1-设置2-,闹钟
uchar Seg_time[3]={23,59,55};
uchar Seg_set[3];
uchar Clock[3]={00,00,00};
char Blink_index=0;//0-时,1-分,2-秒
uint Timer_1000ms=0;
uint Timer_500ms=0;
uint Seg_slow;//500ms
bit Blink_flag;
/* 函数声明 */
void Key_proc();//按键处理
void Seg_proc();
void Other_proc();
void Timer0_init();
void Timer0_ISR();
void Buzz();
/* 代码 */
int main()//主函数
{
Timer0_init();
while(1)
{
Key_proc();
Seg_proc();
Other_proc();
}
}
void Key_proc()//按键处理
{
if (Key_slow) return;
Key_slow=1;
Key_val=Key_read();
Key_down=Key_val&(Key_val^Key_old);//捕捉下降沿
Key_old=Key_val;//辅助扫描
switch(Key_down)
{
case 7://数码管显示界面
Seg_mod=0;
break;
case 6://时间设置界面
Seg_set[0]=Seg_time[0];
Seg_set[1]=Seg_time[1];
Seg_set[2]=Seg_time[2];
Seg_mod=1;
break;
case 11://位增
if(Seg_mod==1||Seg_mod==2)
{
Blink_index++;
if(Blink_index==3)
{
Blink_index=0;
}
}
break;
case 10://位减
if(Seg_mod==1||Seg_mod==2)
{
Blink_index--;
if(Blink_index==-1)
{
Blink_index=2;
}
}
break;
case 9://数增
Seg_set[Blink_index]++;
if(Seg_set[Blink_index]==(Blink_index==0?24:60))
{
Seg_set[Blink_index]=0;
}
break;
case 8://数减
Seg_set[Blink_index]--;
if(Seg_set[Blink_index]==0)
{
Seg_set[Blink_index]=(Blink_index==0?23:59);
}
break;
case 16://保存
if(Seg_mod==1)
{
Seg_time[0]=Seg_set[0];
Seg_time[1]=Seg_set[1];
Seg_time[2]=Seg_set[2];
Seg_mod=0;
}
if(Seg_mod==2)
{
Clock[0]=Seg_set[0];
Clock[1]=Seg_set[1];
Clock[2]=Seg_set[2];
Seg_mod=0;
}
break;
case 5:
Seg_set[0]=Clock[0];
Seg_set[1]=Clock[1];
Seg_set[2]=Clock[2];
Seg_mod=2;
}
}
void Seg_proc()//数码管处理
{
if (Seg_slow) return;
Seg_slow=1;
switch(Seg_mod)
{
case 0://时钟
Seg_buf[0]=Seg_time[0]/10%10;
Seg_buf[1]=Seg_time[0]%10;
Seg_buf[2]=16;
Seg_buf[3]=Seg_time[1]/10%10;
Seg_buf[4]=Seg_time[1]%10;
Seg_buf[5]=16;
Seg_buf[6]=Seg_time[2]/10%10;
Seg_buf[7]=Seg_time[2]%10;
break;
case 1://设置
Seg_buf[0]=Seg_set[0]/10%10;
Seg_buf[1]=Seg_set[0]%10;
Seg_buf[2]=16;
Seg_buf[3]=Seg_set[1]/10%10;
Seg_buf[4]=Seg_set[1]%10;
Seg_buf[5]=16;
Seg_buf[6]=Seg_set[2]/10%10;
Seg_buf[7]=Seg_set[2]%10;
switch(Blink_index)
{
case 0:
Seg_buf[0]=Blink_flag?Seg_set[0]/10%10:19;
Seg_buf[1]=Blink_flag?Seg_set[0]%10:19;
break;
case 1:
Seg_buf[3]=Blink_flag?Seg_set[1]/10%10:19;
Seg_buf[4]=Blink_flag?Seg_set[1]%10:19;
break;
case 2:
Seg_buf[6]=Blink_flag?Seg_set[2]/10%10:19;
Seg_buf[7]=Blink_flag?Seg_set[2]%10:19;
break;
}
break;
case 2://设置
Seg_buf[0]=Seg_set[0]/10%10;
Seg_buf[1]=Seg_set[0]%10;
Seg_buf[2]=16;
Seg_buf[3]=Seg_set[1]/10%10;
Seg_buf[4]=Seg_set[1]%10;
Seg_buf[5]=16;
Seg_buf[6]=Seg_set[2]/10%10;
Seg_buf[7]=Seg_set[2]%10;
switch(Blink_index)
{
case 0:
Seg_buf[0]=Blink_flag?Seg_set[0]/10%10:19;
Seg_buf[1]=Blink_flag?Seg_set[0]%10:19;
break;
case 1:
Seg_buf[3]=Blink_flag?Seg_set[1]/10%10:19;
Seg_buf[4]=Blink_flag?Seg_set[1]%10:19;
break;
case 2:
Seg_buf[6]=Blink_flag?Seg_set[2]/10%10:19;
Seg_buf[7]=Blink_flag?Seg_set[2]%10:19;
break;
}
break;
}
}
void Other_proc()//其他处理
{
if(Clock[0]==Seg_time[0]&&Clock[1]==Seg_time[1]&&Clock[2]==Seg_time[2])
{
Buzz();
}
}
void Timer0_init()//定时器0初始化函数
{
// 设置定时器0工作方式,使用模式1
TMOD &= 0xF0; // 清零低四位
TMOD |= 0x01; // 设置定时器0为模式1
// 设置定时器0的初值,使定时器定时时间为1ms
TH0 = 252; // 高八位
TL0 = 223; // 低八位
// 启动定时器0
TR0 = 1;
// 允许定时器0中断
ET0 = 1;
EA = 1; // 允许总中断
}
void Timer0_ISR() interrupt 1 //中断服务函数
{
TH0 = 252;
TL0 = 223;
if(++Key_slow==10)Key_slow=0;
if(++Seg_slow==500)Seg_slow=0;
if(++Seg_pos==8)Seg_pos=0;
Seg_disp(Seg_pos,Seg_buf[Seg_pos]);
Timer_1000ms++;
if(Timer_1000ms==1000)//1s标志位
{
Timer_1000ms=0;
Seg_time[2]++;
if(Seg_time[2]==60)
{
Seg_time[2]=0;
Seg_time[1]++;
if(Seg_time[1]==60)
{
Seg_time[1]=0;
Seg_time[0]++;
if(Seg_time[0]==24)
{
Seg_time[0]=0;
}
}
}
}
Timer_500ms++;
if(Timer_500ms==500)
{
Timer_500ms=0;
Blink_flag^=1;
}
}
void Buzz()
{
P2 = (P2&0x1f)|0xa0;//101 Buzz
}
四、上电效果图
無限進步