十三届省赛题
前言
上期我们学习了NE555方波发生器&频率测量,讲到我会更新之后省赛的题目,那么,他来了。
首先声明:我还没有参加蓝桥杯单片机比赛,也没有拿过奖,所以我写的代码注定不会那么完美,存在BUG是必然的,我写这个系列的目的纯粹是为了记录我的学习…………
任务要求
1.基本要求
2.竞赛板配置要求
3.硬件框图
4.功能描述
关于功能描述,我只想说是真的多,第一次写,花了我快一天的时间,但好在功能大部分已经实现完全了,不说了,看吧…………
看到这里,说明你是一个有耐心的人,那么作为一个有耐心的人,我觉得你一定能继续看下去的,下面,未来讲一下我的代码实现思路。
实现思路
首先我们拿到题目,必须要大概的看一遍,明确用到了那些模块,一些大概的要求什么的,重点要完成哪些部分。
【1】编写一些基本的函数内容,完成相关外设的初始化。
【2】完成数码管显示相关变量的各个页面,
【3】定义变量,实现数码管显示页面和显示内容的改变
【4】 按照任务要求在此基础上不断的修正代码结构框架
【5】检验代码的可行性,不断的DeBug…………
具体代码框架如下:
可能光看这个图会显得有些抽象,不知道在写什么,所以我们来尝试加上代码一起理解。
代码实现
1.main.C
#include <STC15F2K60S2.H>
#include "LS138.h"
#include "Key.h"
#include "ds1302.h"
#include "onewire.h"
unsigned int Mode = 1;
struct Environment
{
unsigned int Tempreature; //定义温度变量
unsigned int Tempreature_Set; //定义温度设置值
unsigned int Key_Vlaue; //定义按键值
unsigned int Time_Show_Mode; //定义时间显示模式
unsigned int Control_Mode; //定义温度/时间控制模式
unsigned char Relay_Flag; //定义继电器状态
unsigned int LED0_Flag ; //定义LED0/L1状态
unsigned int LED2_Flag ; //定义LED1/L2状态
unsigned long int Tick; //定义时间值/tick为一天过了多少秒
}E1;
void Timer_Init(void)
{
ET1 = 1;
TMOD = 0x00;
TH1 = 0xFC;
TL1 = 0x18;
EA = 1;
TR1 = 1;
}
void Environment_Init(void)
{
E1.Tempreature = 235;
E1.Tempreature_Set = 230;
E1.Key_Vlaue = 0;
E1.Relay_Flag = 0;
E1.Tick = 3595;
E1.Time_Show_Mode = 1;
E1.Control_Mode = 1;
E1.LED0_Flag = 0;
E1.LED2_Flag = 0;
}
void Init(void)
{
Environment_Init();
LS_Init();
DS1302_Write_Time(E1.Tick);
Timer_Init();
}
void SEG_Task(void)
{
switch(Mode)
{
case 1: SEG_Page1(E1.Tempreature);
break;
case 2: SEG_Page2(E1.Time_Show_Mode,E1.Tick);
break;
case 3: SEG_Page3(E1.Tempreature_Set);
break;
}
}
void Key_Task(void)
{
E1.Key_Vlaue = KeyScan();
if(E1.Key_Vlaue == 12)
{
Mode++;
if(Mode >3)
{
Mode = 1;
}
}
if(E1.Key_Vlaue == 13)
{
E1.Control_Mode ++;
if(E1.Control_Mode >=3)
{
E1.Control_Mode = 1;
}
}
if(E1.Control_Mode == 1)
{
if(E1.Tempreature > E1.Tempreature_Set)
{
Relay_Control(1);
E1.LED2_Flag = 1;
}
else
{
Relay_Control(0);
E1.LED2_Flag = 0;
}
}
if(E1.Control_Mode == 2)
{
if(E1.Tick % 3600 == 0 )
{
E1.Relay_Flag = 1;
E1.LED2_Flag = 1;
}
if(E1.LED0_Flag == 1)
{
LED_Write(0xFE);
}
else
{
LED_Write(0xFF);
}
}
if(E1.Tick % 3600 == 0 )
{
E1.LED0_Flag = 1;
}
if(E1.LED0_Flag == 1)
{
LED_Write(0xFE);
}
if(E1.LED0_Flag == 0)
{
LED_Write(0xFF);
}
if(Mode == 3)
{
if(E1.Key_Vlaue == 16)
{
E1.Tempreature_Set = E1.Tempreature_Set + 10;
if(E1.Tempreature_Set > 999)
{
E1.Tempreature_Set = 999;
}
}
if(E1.Key_Vlaue == 17)
{
E1.Tempreature_Set = E1.Tempreature_Set - 10;
if(E1.Tempreature_Set < 100)
{
E1.Tempreature_Set = 100;
}
}
}
if(Mode == 2)
{
if(E1.Key_Vlaue == 17)
{
E1.Time_Show_Mode++;
}
}
}
void main()
{
Init();
while(1)
{
E1.Tempreature = DS_Read_Tempreatur();
E1.Tick = DS1302_Read_Time();
SEG_Task();
Key_Task();
}
}
void Timer0_Handler() interrupt 3
{
static unsigned int Timer1_Count = 0;
static unsigned int Relay_Count = 0;
static unsigned int LED0_Count = 0;
static unsigned int LED2_Count = 0;
Timer1_Count++;
if(E1.Control_Mode == 1)
{
if(E1.LED0_Flag == 1)
{
LED_Write(0xFC);
}
else
{
LED_Write(0xFD);
}
}
if(Timer1_Count % 100 == 0)
{
if(E1.LED2_Flag == 1)
{
LED2_Count++;
if(LED2_Count%2)
{
LED_Write(0xFB);
}
else
{
LED_Write(0xFF);
}
}
}
if(Timer1_Count >= 1000)
{
Timer1_Count = 0;
if(E1.Relay_Flag == 1)
{
Relay_Count++;
if(Relay_Count < 5)
{
Relay_Control(1);
}
else
{
Relay_Count = 0;
E1.Relay_Flag = 0;
E1.LED2_Flag = 0;
Relay_Control(0);
}
}
if(E1.LED0_Flag == 1)
{
LED0_Count++;
if(LED0_Count >= 6)
{
LED0_Count = 0;
E1.LED0_Flag = 0;
}
}
}
}
LS138.h
#ifndef _LS138_H_
#define _LS138_H_
#include <STC15F2K60S2.H>
sbit LS_A = P2^5;
sbit LS_B = P2^6;
sbit LS_C = P2^7;
void LS_Init(void);
void LS138_Set(unsigned int dat);
void LS138_Clear(void);
void DelayXms(unsigned int x);
void LED_Control(unsigned int Flag);
void LED_Write(unsigned char dat);
void BEEP_Control(unsigned int Flag);
void Relay_Control(unsigned int Flag);
void SEG_Write(unsigned char pos, unsigned char dat);
void SEG_Page1(unsigned int tempreature);
void SEG_Page2(unsigned int Flag,unsigned long int Tick);
void SEG_Page3(unsigned int tempreature);
#endif
LS138.C
#include "LS138.h"
// 0 1 2 3 4 5 6 7 8 9
unsigned char code SEG_Index[25] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
/* 0. 1. 2. ………… 9.*/
0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,
/* U - */
0xc1,0xbf};
void LS_Init(void)
{
BEEP_Control(0);
Relay_Control(0);
LED_Control(0);
LED_Write(0xFF);
}
void LS138_Set(unsigned int dat)
{
switch(dat)
{
case 0: LS_A = 0; LS_B = 0; LS_C = 0;
break;
case 1:
break;
case 2:
break;
case 3:
break;
case 4: LS_A = 0; LS_B = 0; LS_C = 1;
break;
case 5: LS_A = 1; LS_B = 0; LS_C = 1;
break;
case 6: LS_A = 0; LS_B = 1; LS_C = 1;
break;
case 7: LS_A = 1; LS_B = 1; LS_C = 1;
break;
}
}
void LS138_Clear(void)
{
LS_A = 0; LS_B = 0; LS_C = 0;
}
void DelayXms(unsigned int x) //@12.000MHz
{
unsigned char i, j,k;
for(k=0;k<x;k++)
{
i = 12;
j = 169;
do
{
while (--j);
} while (--i);
}
}
void LED_Control(unsigned int Flag)
{
if(Flag == 1)
{
LS138_Clear();
LS138_Set(4);
P0 = 0x00;
LS138_Clear();
}
else
{
LS138_Clear();
LS138_Set(4);
P0 = 0xFF;
LS138_Clear();
}
}
void LED_Write(unsigned char dat)
{
LS138_Clear();
LS138_Set(4);
P0 = dat;
LS138_Clear();
}
void BEEP_Control(unsigned int Flag)
{
if(Flag == 1)
{
LS138_Clear();
LS138_Set(5);
P0 = 0x40;
LS138_Clear();
}
else
{
LS138_Clear();
LS138_Set(5);
P0 = 0x00;
LS138_Clear();
}
}
void Relay_Control(unsigned int Flag)
{
if(Flag == 1)
{
LS138_Clear();
LS138_Set(5);
P0 = 0x10;
LS138_Clear();
}
else
{
LS138_Clear();
LS138_Set(5);
P0 = 0x00;
LS138_Clear();
}
}
void SEG_Write(unsigned char pos, unsigned char dat)
{
LS138_Set(7);
P0 = SEG_Index[dat];
LS138_Clear();
LS138_Set(6);
P0 = 0x01 << pos;
LS138_Clear();
LED_Control(0);
DelayXms(1);
}
void SEG_Page1(unsigned int tempreature)
{
SEG_Write(0,20);
SEG_Write(1,1);
SEG_Write(5,tempreature/100%10);
SEG_Write(6,tempreature/10%10 + 10);
SEG_Write(7,tempreature %10);
}
void SEG_Page2(unsigned int Flag,unsigned long int Tick)
{
SEG_Write(0,20);
SEG_Write(1,2);
SEG_Write(5,21);
if(Flag % 2)
{
SEG_Write(3,Tick/3600/10%10);
SEG_Write(4,Tick/3600%10);
SEG_Write(6,Tick/3600/60/10%10);
SEG_Write(7,Tick/3600/60%10);
}
else
{
SEG_Write(3,Tick/3600/60/10%10);
SEG_Write(4,Tick/3600/60%10);
SEG_Write(6,Tick%60/10%10);
SEG_Write(7,Tick%60%10);
}
}
void SEG_Page3(unsigned int tempreature)
{
SEG_Write(0,20);
SEG_Write(1,3);
SEG_Write(6,tempreature/100%10);
SEG_Write(7,tempreature/10%10);
}
Key.C
#include "Key.h"
unsigned int KeyScan(void)
{
static unsigned char cnt = 0, //continue value
last_trg = 0; //last trigger value
unsigned char trg = 0, //trigger value
cur = 0, //current value
value = 3, //必须初始化为3
key_x = 0,
key_y = 0;
P3 = 0x0f;
P4 = 0x00;
if(!P30) key_x = 3; //获取X轴坐标
else if(!P31) key_x = 2;
else if(!P32) key_x = 1;
else if(!P33) key_x = 0;
P3 = 0xf0;
P4 = 0xff;
if(!P34) key_y = 4; //获取Y轴坐标
else if(!P35) key_y = 3;
else if(!P42) key_y = 2;
else if(!P44) key_y = 1;
cur = key_y^0;
trg = cur^cnt & cur;
cnt = cur;
if((last_trg ^ trg & last_trg) && cur)
{
//计算矩阵按键的键值
value = key_x + key_y * 4;
}
last_trg = trg;
return value; //返回独立按键的键值
}
Key.h这里就不写了,里面也没啥,就是一个KeyScan函数的声明
温度读取函数
unsigned int DS_Read_Tempreatur(void)
{
unsigned int dat =0;
unsigned char HSB,LSB;
init_ds18b20();
Write_DS18B20(0xCC);
Write_DS18B20(0x44);
init_ds18b20();
Write_DS18B20(0xCC);
Write_DS18B20(0xBE);
LSB = Read_DS18B20();
HSB = Read_DS18B20();
init_ds18b20();
dat = (HSB << 8) | LSB ;
if((dat & 0xF800) == 0x0000)
{
dat = (dat >> 4) * 10 ;
dat =dat + (LSB & 0x0F) * 0.625 ;
return dat ;
}
return dat ;
}
DS1302时间写入函数
void DS1302_Write_Time(unsigned long int Tick)
{
unsigned char sec,min,hour;
sec = Tick % 60;
sec = (sec/10 * 16) +( sec %10);
min = Tick / 60;
min = (min/10 * 16) +( min %10);
hour = Tick / 3600;
hour = (hour/10* 16) +( hour %10);
Write_Ds1302_Byte(0x8E,0x00);
Write_Ds1302_Byte(0x80,sec);
Write_Ds1302_Byte(0x82,min);
Write_Ds1302_Byte(0x84,hour);
Write_Ds1302_Byte(0x8E,0xFF);
}
DS1302时间读取函数
unsigned long int DS1302_Read_Time(void)
{
unsigned long int tick = 0;
unsigned char sec,min,hour;
sec = Read_Ds1302_Byte(0x81);
min = Read_Ds1302_Byte(0x83);
hour = Read_Ds1302_Byte(0x85);
sec =(sec /16 * 10) + sec %16;
min =(min /16 * 10) + min %16;
hour =(hour /16 * 10) + hour %16;
tick = hour * 3600 + min * 60 + sec;
return tick;
}
关于DS1302和DS18B20的底层驱动函数,我就不贴出来了,官方会提供的,我前面几期的博客里面也有,需要的可以自己去看看。
总结
- 这一次的省赛题总体来说还算是比较正常的,我也完成了七七八八,但没有完全完成,毕竟我只是个菜鸟,能不能拿奖还是未知呢…………
- 通过这次的实践,我也发现了许多的问题,我发现我写的代码存在可优化的地方,许多模块一起使用的话,会存在互相干扰的问题,针对这些问题,我也在想办法,希望在比赛前解决掉这些问题吧。
- 不出意外的话,下一期会更新12届省赛题目的代码。
存在的问题
- 调用数码管显示函数的时候,LED不受控制,时不时的乱跳,关于这个BUG,我想了好久,但是还是没法解决,所以我只能通过程序控制,把影响尽可能地减小,希望哪位大神来解答一下我的疑惑。
- 关于矩阵按键的扫描函数,我用的是我们老师提供的代码,因为我发现我之前写的代码存在使用过程中会影响其他外设正常工作,容易误触发等问题,而且我们老师提供的代码出奇的好用(我们老师就是厉害)。但是我还是没看懂原理,同样希望哪位大佬可以帮我解释一些。
你都看到这里了,说明你是一个很有耐心的人,那么这个有耐心的陌生人,能支持我一下吗?