声明:代码确实写的不好,用的都是最笨的方法实现功能,不喜勿喷
第五届的题跟我之前写过的有一点小区别,之前写过的那几届都是使用的
独立按键,但是
第五届要求的是使用矩阵按键
矩阵按键相对于独立按键还是有一些稍加复杂的,独立按键我们只需要检测一个IO的电平就可以判断按键的状态,矩阵按键也是这样判断的但是是要先对高四位中的一位赋值或者低四位中的一位赋值来检测IO的电平,如果不是很理解可以看看我的另一篇文章:
https://blog.csdn.net/weixin_42994525/article/details/88101523。
下面看一下第五届的题:
就这个题目的要求而言我是觉得不太难。唯一的难点就是矩阵键盘的操作吧,其实在这个题目里矩阵键盘的操作也不是很难,因为都是单一的操作,没有说一个按键实现很多功能。这个题目我是写了五个半小时,比着上一个题目时间缩短了半个小时,虽然我知道自己和别人还是有很大差距的,但是我知道自己在进步。
还是老样子的说一下我自己的写题思路:
第一步:实现温度初值的设定以及初步的比较,LED灯的闪烁。数码管的显示
第二步:实现温度上下线的设置
第三步:实现按键的清零功能以及L2灯的常亮和熄灭
在整个题目的实现过程中唯一遇到的问题就是,在设置温度上下线的时候对按键的判断,举个例子来说一下这个问题:
如果我们第一次按下S4那么第二 个数码管会显示9,随后就到了第三个数码管的值设定,这个时候如果第一次按下S5我们让第三个数码管显示6,意思就是我们对数码管的赋值不是说第二个数码管就是显示的是按键第一次按下的值,而第三个数码管显示的只是按键第二次按下的值。我可能说的不太明白,如果读者自己写这个程序就会发现这个问题,或者也可以直接看我的代码,相信大家也会看明白的。
问题的解决方法有两种一种是从按键按下的次数入手,也就是我写的这种方法。另一种是从四个需要赋值的数码管入手,在第一个数码管赋值完之后,设置标志位,然后赋值第二个数码管,依次往下。第二种解决方法比较简单,建议使用。
下面看一下程序:
第一:按键程序(我比较笨按键写了将近一千行,这肯定是不太好的,希望读者能看懂我想表达的问题,自己找到更好的解决方式)
在这里我只粘贴部分的按键程序。
#include "key.h"
extern uchar Set_temp_max;
extern uchar Set_temp_min;
extern uchar Num_high_max;
extern uchar Num_low_max;
extern uchar Num_high_min;
extern uchar Num_low_min;
extern uchar T_min;
extern uchar T_max;
extern uchar Init_flag;
extern uchar Set_flag;
extern uchar yi,er,san,si,wu,liu,qi,ba;
uchar Kef7_0_flag[7]=0;
uchar Kef11_1_flag[7]=0;
uchar Kef15_2_flag[7]=0;
uchar Kef6_3_flag[7]=0;
uchar Kef10_4_flag[7]=0;
uchar Kef14_5_flag[7]=0;
uchar Kef5_6_flag[7]=0;
uchar Kef9_7_flag[7]=0;
uchar Kef13_8_flag[7]=0;
uchar Kef4_9_flag[7]=0;
uchar Kef8_set_flag;
uchar Kef12_clear_flag;
void Delay6ms() //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
_nop_();
i = 65;
j = 136;
do
{
while (--j);
} while (--i);
}
void keysca16()
{
uchar temp;
//第一列按键
P3 = 0X7F;P42 = 1;P44=0;
temp = P3;
temp = temp&0X0F;
if(temp!=0X0F)
{
Delay6ms();
if(temp!=0X0F)
{
temp = P3;
switch(temp)
{
case 0X7E: Kef7_0_flag[0]+=1;Kef7_0_flag[1]=1;Kef7_0_flag[2]=1;Kef7_0_flag[3]=1;Kef7_0_flag[4]=1;Kef7_0_flag[5]=1;Kef7_0_flag[6]=1;break;//按键S7按下
case 0X7D: Kef6_3_flag[0]+=1;Kef6_3_flag[1]=1;Kef6_3_flag[2]=1;Kef6_3_flag[3]=1;Kef6_3_flag[4]=1;Kef6_3_flag[5]=1;Kef6_3_flag[6]=1;break;//按键S6按下
case 0X7B: Kef5_6_flag[0]+=1;Kef5_6_flag[1]=1;Kef5_6_flag[2]=1;Kef5_6_flag[3]=1;Kef5_6_flag[4]=1;Kef5_6_flag[5]=1;Kef5_6_flag[6]=1;break;//按键S5按下
case 0X77: Kef4_9_flag[0]+=1;Kef4_9_flag[1]=1;Kef4_9_flag[2]=1;Kef4_9_flag[3]=1;Kef4_9_flag[4]=1;Kef4_9_flag[5]=1;Kef4_9_flag[6]=1;break;//按键S4按下
}
if(Kef7_0_flag[0] == 5) //控制设置循环
Kef7_0_flag[0] = 1;
if(Kef6_3_flag[0] == 5)
Kef6_3_flag[0] = 1;
if(Kef5_6_flag[0] == 5)
Kef5_6_flag[0] = 1;
if(Kef4_9_flag[0] == 5)
Kef4_9_flag[0] = 1;
while(temp!=0X0F)
{
temp = P3;
temp = temp&0X0F;
}
}
}
//第二列按键
P3 = 0XBF;P42 = 0;P44 = 1;
temp = P3;
temp = temp&0X0F;
if(temp!=0X0F)
{
Delay6ms();
if(temp!=0X0F)
{
temp = P3;
switch(temp)
{
case 0XBE: Kef11_1_flag[0]+=1;Kef11_1_flag[1]=1;Kef11_1_flag[2]=1;Kef11_1_flag[3]=1;Kef11_1_flag[4]=1;Kef11_1_flag[5]=1;Kef11_1_flag[6]=1;break;//按键S11按下
case 0XBD: Kef10_4_flag[0]+=1;Kef10_4_flag[1]=1;Kef10_4_flag[2]=1;Kef10_4_flag[3]=1;Kef10_4_flag[4]=1;Kef10_4_flag[5]=1;Kef10_4_flag[6]=1;break;//按键S10按下
case 0XBB: Kef9_7_flag[0]+=1;Kef9_7_flag[1]=1;Kef9_7_flag[2]=1;Kef9_7_flag[3]=1;Kef9_7_flag[4]=1;Kef9_7_flag[5]=1;Kef9_7_flag[6]=1;break;//按键S9按下
case 0XB7: Kef8_set_flag+=1;break;//按键S8按下进入设置界面
}
if(Kef8_set_flag == 2) //退出温度设置界面,回到温度显示界面
{
Kef8_set_flag = 0;
Set_flag = 0;
Init_flag = 0;
T_max = Set_temp_max; //将设置的温度上线存入
T_min = Set_temp_min; //将设置的温度下线存入
}
if(Kef11_1_flag[0] == 5) //控制设置循环
Kef11_1_flag[0] = 1;
if(Kef10_4_flag[0] == 5)
Kef10_4_flag[0] = 1;
if(Kef9_7_flag[0] == 5)
Kef9_7_flag[0] = 1;
while(temp!=0X0F)
{
temp = P3;
temp = temp&0X0F;
}
}
}
//第三列按键
P3 = 0XDF;P42 = 1;
temp = P3;
temp = temp&0X0F;
if(temp!=0X0F)
{
Delay6ms();
if(temp!=0X0F)
{
temp = P3;
switch(temp)
{
case 0XDE: Kef15_2_flag[0]+=1;Kef15_2_flag[1]=1;Kef15_2_flag[2]=1;Kef15_2_flag[3]=1;Kef15_2_flag[4]=1;Kef15_2_flag[5]=1;Kef15_2_flag[6]=1;break;//按键S15按下
case 0XDD: Kef14_5_flag[0]+=1;Kef14_5_flag[1]=1;Kef14_5_flag[2]=1;Kef14_5_flag[3]=1;Kef14_5_flag[4]=1;Kef14_5_flag[5]=1;Kef14_5_flag[6]=1;break;//按键S14按下
case 0XDB: Kef13_8_flag[0]+=1;Kef13_8_flag[1]=1;Kef13_8_flag[2]=1;Kef13_8_flag[3]=1;Kef13_8_flag[4]=1;Kef13_8_flag[5]=1;Kef13_8_flag[6]=1;break;//按键S13按下
case 0XD7: Kef12_clear_flag=1;break;//按键S12按下清零
}
if(Kef15_2_flag[0] == 5) //控制设置循环
Kef15_2_flag[0] = 1;
if(Kef14_5_flag[0] == 5)
Kef14_5_flag[0] = 1;
if(Kef13_8_flag[0] == 5)
Kef13_8_flag[0] = 1;
while(temp!=0X0F)
{
temp = P3;
temp = temp&0X0F;
}
}
}
//第四列按键
P3 = 0XEF;
temp = P3;
temp = temp&0X0F;
if(temp!=0X0F)
{
Delay6ms();
if(temp!=0X0F)
{
temp = P3;
switch(temp)
{
case 0XEE: break;//按键S19按下
case 0XED: break;//按键S18按下
case 0XEB: break;//按键S17按下
case 0XE7: break;//按键S16按下
}
while(temp!=0X0F)
{
temp = P3;
temp = temp&0X0F;
}
}
}
}
//还有第二个数码管,第七个数码管,第八个数码管的程序没有粘出来
//第三个数码管的显示控制函数(温度上线值的个位)
void Dis_shuma_san(void)
{
if((Kef7_0_flag[0] == 1) && (Kef7_0_flag[1] == 1))
{
if(er == 0)
{
san = 12;
Kef7_0_flag[1] = 0;
}
else
san = 0;
}
else if((Kef11_1_flag[0] == 1) && (Kef11_1_flag[1] == 1))
{
if(er == 1)
{
san = 12;
Kef11_1_flag[1] = 0;
}
else
san = 1;
}
else if((Kef15_2_flag[0] == 1) && (Kef15_2_flag[1] == 1))
{
if(er == 2)
{
san = 12;
Kef15_2_flag[1] = 0;
}
else
san = 2;
}
else if((Kef6_3_flag[0] == 1) && (Kef6_3_flag[1] == 1))
{
if(er == 3)
{
san = 12;
Kef6_3_flag[1] = 0;
}
else
san = 3;
}
else if((Kef10_4_flag[0] == 1) && (Kef10_4_flag[1] == 1))
{
if(er == 4)
{
san = 12;
Kef10_4_flag[1] = 0;
}
else
san = 4;
}
else if((Kef14_5_flag[0] == 1) && (Kef14_5_flag[1] == 1))
{
if(er == 5)
{
san = 12;
Kef14_5_flag[1] = 0;
}
else
san = 5;
}
else if((Kef5_6_flag[0] == 1) && (Kef5_6_flag[1] == 1))
{
if(er == 6)
{
san = 12;
Kef5_6_flag[1] = 0;
}
else
san = 6;
}
else if((Kef9_7_flag[0] == 1) && (Kef9_7_flag[1] == 1))
{
if(er == 7)
{
san = 12;
Kef9_7_flag[1] = 0;
}
else
san = 7;
}
else if((Kef13_8_flag[0] == 1) && (Kef13_8_flag[1] == 1))
{
if(er == 8)
{
san = 12;
Kef13_8_flag[1] = 0;
}
else
san = 8;
}
else if((Kef4_9_flag[0] == 1) && (Kef4_9_flag[1] == 1))
{
if(er == 9)
{
san = 12;
Kef4_9_flag[1] = 0;
}
else
san = 9;
}
else if(Kef7_0_flag[0] == 2)
{
san = 0;
}
else if(Kef11_1_flag[0] == 2)
{
san = 1;
}
else if(Kef15_2_flag[0] == 2)
{
san = 2;
}
else if(Kef6_3_flag[0] == 2)
{
san = 3;
}
else if(Kef10_4_flag[0] == 2)
{
san = 4;
}
else if(Kef14_5_flag[0] == 2)
{
san = 5;
}
else if(Kef5_6_flag[0] == 2)
{
san = 6;
}
else if(Kef9_7_flag[0] == 2)
{
san = 7;
}
else if(Kef13_8_flag[0] == 2)
{
san = 8;
}
else if(Kef4_9_flag[0] == 2)
{
san = 9;
}
}
第二:数码管程序
#include "shuma.h"
u8 shu_tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XC6,0XFF};//0XC6是英文C
uchar yi,er,san,si,wu,liu,qi,ba;
//第一和第二个数码管
void Display1_2(uchar yi,uchar er)
{
P2=0XC0;//打开位选573 U8
P0=0X01;//选择第一个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[yi];
Delay1ms();Delay1ms();
P2=0XC0;//打开位选573 U8
P0=0X02;//选择第二个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[er];
Delay1ms();Delay1ms();
}
//第四和第五个数码管
void Display4_5(uchar si,uchar wu)
{
P2=0XC0;//打开位选573 U8
P0=0X08;//选择第一个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[si];
Delay1ms();Delay1ms();
P2=0XC0;//打开位选573 U8
P0=0X10;//选择第一个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[wu];
Delay1ms();Delay1ms();
}
//第三和第六个数码管
void Display3_6(uchar san,uchar liu)
{
P2=0XC0;//打开位选573 U8
P0=0X04;//选择第三个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[san];
Delay1ms();Delay1ms();
P2=0XC0;//打开位选573 U8
P0=0X20;//选择第四个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[liu];
Delay1ms();Delay1ms();
}
//第七和第八个数码管
void Display7_8(uchar qi,uchar ba)
{
P2=0XC0;//打开位选573 U8
P0=0X40;//选择第一个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[qi];
Delay1ms();Delay1ms();
P2=0XC0;//打开位选573 U8
P0=0X80;//选择第一个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[ba];
Delay1ms();Delay1ms();
}
void Delay1ms() //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
第三:DS18B20程序(我用的是我自己改的官方的驱动,也可以用自己写的)
#include "ds18b20.h"
//DS18B20初始化
void DSInit()
{
DQ=0;
Delay_OneWire(40);
DQ=1;
Delay_OneWire(40);
}
void Delay_OneWire(unsigned int t)
{
unsigned char i;
while(t--){
for(i=0; i<8; i++);
}
}
//温度处理函数
uchar Date_Handing()
{
uchar high,low;
uchar temp;
DSInit();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
Delay_OneWire(40);
DSInit();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);
low=Read_DS18B20();
high=Read_DS18B20();
temp=high<<4;
temp|=(low>>4);
return temp;
}
//向DS写控制字
//通过单总线向DS18B20写一个字节
void Write_DS18B20(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
DQ = 0;
DQ = dat&0x01;
Delay_OneWire(5);
DQ = 1;
dat >>= 1;
}
Delay_OneWire(5);
}
//读取温度存储器的数据
//从DS18B20读取一个字节
unsigned char Read_DS18B20(void)
{
unsigned char i;
unsigned char dat;
for(i=0;i<8;i++)
{
DQ = 0;
dat >>= 1;
DQ = 1;
if(DQ)
{
dat |= 0x80;
}
Delay_OneWire(5);
}
return dat;
}
第四:初始化程序(.c)
#include "system.h"
void Init(void)
{
P2 = 0XA0;P0 = 0X00;//打开继电器,蜂鸣器的控制端,关闭蜂鸣器,继电器
P2 = 0X80;P0 = 0XFF;//打开LED灯的控制端,关闭所有LED灯
P2 = 0XC0;P0 = 0XFF;//打开数码管片选控制端,选中所有数码管
P2 = 0XFF;P0 = 0XFF;//打开数码管段选控制端,关闭所有段
}
初始化程序(.h)
#ifndef __SYSTEM_H
#define __SYSTEM_H
#include "STC15F2K60S2.H"
#include "intrins.h"
#define uchar unsigned char
#define uint unsigned int
typedef unsigned int u16;
typedef unsigned char u8;
void Init(void);
#endif
第五:主函数程序
#include "system.h"
#include "key.h"
#include "ds18b20.h"
#include "shuma.h"
void Timer0Init(void);
extern uchar yi,er,san,si,wu,liu,qi,ba;
extern uchar Kef7_0_flag[7];
extern uchar Kef11_1_flag[7];
extern uchar Kef15_2_flag[7];
extern uchar Kef6_3_flag[7];
extern uchar Kef10_4_flag[7];
extern uchar Kef14_5_flag[7];
extern uchar Kef5_6_flag[7];
extern uchar Kef9_7_flag[7];
extern uchar Kef13_8_flag[7];
extern uchar Kef4_9_flag[7];
extern uchar Kef8_set_flag;
extern uchar Kef12_clear_flag;
uchar temp; //存储温度的变量
uchar Init_flag; //进入设置界面之后控制数目管的显示初值,只初始化一次
uchar Set_flag; //显示温度和设置温度上下线的标志位
uchar Set_temp_max;//判断温度上下线的大小
uchar Set_temp_min;
uchar Num_high_max;
uchar Num_low_max;
uchar Num_high_min;
uchar Num_low_min;
uchar Led1_flag;//LED灯(L1)闪烁时间控制位
uchar Led2_flag;
uchar Led3_flag;
uchar T_min = 20;//设定温度比较的下线
uchar T_max = 30;//设定温度比较的上线
void main(void)
{
Init();
Timer0Init();
while(1)
{
keysca16();
temp = Date_Handing();
if(Set_flag == 0)
{
if(temp < T_min) //当前温度小于温度下线
{
yi = 10;er = 0;san = 10;
si = 12;wu = 12;liu = 12;
qi = temp/10;ba = temp%10;
Display1_2(yi,er);
Display4_5(si,wu);
Display3_6(san,liu);
Display7_8(qi,ba);
P2 = 0XA0;P0 = 0X00; //关闭继电器和蜂鸣器
if(Led1_flag == 1) //LED800ms闪烁
{
P2 = 0X80;P0 = 0XFE;
Led1_flag = 0;
}
else
{
P2 = 0X80;P0 = 0XFF;
}
}
else if((temp >= T_min) && (temp <= T_max))//当前温度小于等于温度上线,大于等于温度线下
{
yi = 10;er = 1;san = 10;
si = 12;wu = 12;liu = 12;
qi = temp/10;ba = temp%10;
Display1_2(yi,er);
Display4_5(si,wu);
Display3_6(san,liu);
Display7_8(qi,ba);
P2 = 0XA0;P0 = 0X00; //关闭继电器和蜂鸣器
if(Led2_flag == 1) //LED400ms闪烁
{
P2 = 0X80;P0 = 0XFE;
Led2_flag = 0;
}
else
{
P2 = 0X80;P0 = 0XFF;
}
}
else if(temp > T_max) //当前温度大于温度上线
{
yi = 10;er = 2;san = 10;
si = 12;wu = 12;liu = 12;
qi = temp/10;ba = temp%10;
Display1_2(yi,er);
Display4_5(si,wu);
Display3_6(san,liu);
Display7_8(qi,ba);
P2 = 0XA0;P0 = 0X10; //打开继电器
if(Led3_flag == 1) //LED200ms闪烁
{
P2 = 0X80;P0 = 0XFE;
Led3_flag = 0;
}
else
{
P2 = 0X80;P0 = 0XFF;
}
}
}
if(Kef8_set_flag == 1)//上下线设置标志位
{
Set_flag = 1;
P2 = 0X80;P0 = 0XFF;
if(Init_flag == 0)
{
yi = 10;er = 12;san = 12;si = 12;
wu = 12;liu = 10;qi = 12;ba = 12;
Kef7_0_flag[0]=0;
Kef11_1_flag[0]=0;
Kef15_2_flag[0]=0;
Kef6_3_flag[0]=0;
Kef10_4_flag[0]=0;
Kef14_5_flag[0]=0;
Kef5_6_flag[0]=0;
Kef9_7_flag[0]=0;
Kef13_8_flag[0]=0;
Kef4_9_flag[0]=0;
Init_flag = 1;
}
if(er == 12)
Dis_shuma_er();
if(san == 12)
Dis_shuma_san();
if(qi == 12)
Dis_shuma_qi();
if(ba == 12)
Dis_shuma_ba();
if((er != 12) && (san != 12) && (qi != 12) && (ba != 12))
{
if(Kef12_clear_flag == 1)//清零标志位
{
er = 12;san = 12;
qi = 12;ba = 12;
Kef7_0_flag[0]=0;
Kef11_1_flag[0]=0;
Kef15_2_flag[0]=0;
Kef6_3_flag[0]=0;
Kef10_4_flag[0]=0;
Kef14_5_flag[0]=0;
Kef5_6_flag[0]=0;
Kef9_7_flag[0]=0;
Kef13_8_flag[0]=0;
Kef4_9_flag[0]=0;
Kef12_clear_flag = 0;
}
else
{
Set_temp_max = er*10 + san;
Set_temp_min = qi*10 + ba;
}
}
if(Set_temp_max < Set_temp_min) //如果温度下线大于温度上线,L2灯常亮
{
P2 = 0X80;P0 = 0XFD;
}
Display1_2(yi,er);
Display4_5(si,wu);
Display3_6(san,liu);
Display7_8(qi,ba);
}
}
}
void Timer0Init(void) //2毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x9A; //设置定时初值
TH0 = 0xA9; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1;
EA = 1;
}
void Timer0() interrupt 1
{
uint num1,num2,num3;
TL0 = 0x9A; //设置定时初值
TH0 = 0xA9; //设置定时初值
num1++;
num2++;
num3++;
if(num1 == 400)//LED灯800ms闪烁
{
num1 = 0;
Led1_flag = 1;
}
if(num2 == 200)//LED灯400ms闪烁
{
num2 = 0;
Led2_flag = 1;
}
if(num3 == 100)//LED灯200ms闪烁
{
num3 = 0;
Led3_flag = 1;
}
}
程序中的很多位置我都加了注释,有助于大家看懂我的程序思路,在最后我还是把我的整个工程上传
https://download.csdn.net/my