蓝桥杯第3届省赛(单片机)_温度监控器
题目
这是2011年蓝桥杯单片机组的省赛题,我感觉整体的难度不大,可能有点挑战性的就是EEPROM储存了,本次题型主要考查了数码管,独立按键,IIC-(EEPROM储存),继电器和电机拖动了。考察的都是那几种固定的模块。
题目分析
1 数码管显示单元
首先在数码管那一面上,DS1部分显示上限温度与下限温度,而在DS2部分我们要关闭前两位数码管而在最后两位显示自测温度,这题主要考的是数码管显示,对于DS1部分,我们只需写变量来控制温度上下限的高低,而自测温度那一部分,我们可以通过ds18b20部分将所得温度表达出来,最后再将温度通过乘除部分来通过数码管显示。
2 温度测量单元
这题比较简单,只需要改写底层驱动代码(onewhile)就可以测量了。
3 按键控制单元
这里主要考察的是独立按键,独立按键比较简单,只需要写好相应的按键代码格式就行,然后通过不同按键来控制不同的变量来控制温度值的变量。
(这里的按键代码格式我会在下面的代码显示部分表达出来)
4 EEPROM的记录
这里也是一样,只需要改写底层驱动代码(iic)就可以测量了.不过温度要保留在0x01,0x00部分。
5 电机拖动,6温控单元
由于我没有电机拖动,我在这里就用led1来代替了,其实主要的程序都一样,等我到时候有电机时我再来改动吧!再电机拖动哪里我主要是用了定时器,继电器也是一样,把定时器函数写在定时器函数里面,这里我先不多说,等到代码部分我在详见。
代码部分
time.c
# include "time.h"
void Timer0Init(void) //100微秒@12.000MHz
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x9C; //设置定时初值
TH0 = 0xFF; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
EA=ET0=1;
}
time.h
# ifndef _TIME_H
# define _TIME_H
# include <STC15F2K60S2.H>
void Timer0Init(void);
# endif
smg.c
# include "smg.h"
unsigned char code tab[11]={ 0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xFF};
unsigned char dspbuf[8]={ 10,10,10,10,10,10,10,10};
void smg_display(void)
{
static unsigned char i;
P0=0xFF;
P2&=0x1F;
P2|=0xE0;//Y7C
P2&=0x1F;
P0=(1<<i);
P2&=0x1F;
P2|=0xC0;//Y6C
P2&=0x1F;
P0=tab[dspbuf[i]];
P2&=0x1F;
P2|=0xE0;//Y7C
P2&=0x1F;
if(++i==8)
i=0;
}
smg.h
# ifndef _SMG_H
# define _SMG_H
# include <STC15F2K60S2.H>
void smg_display(void);
extern unsigned char dspbuf[8];
# endif
key.c
(这里的是矩阵按键的基本模型,通过按键控制变量最后控制数码管)
# include "key.h"
unsigned char key_value;
void key_read(void)
{
static unsigned char i; //静态变量
if(P30!=1||P31!=1||P32!=1||P33!=1)
{
i++;
if(i==1)
{
if(P30!=1) key_value=1;
else if(P31!=1) key_value=2;
else if(P32!=1) key_value=3;
else if(P33!=1) key_value=4;
}
else if(i>=30) //长按变短按
{
i=1;
key_value=0;
}
}
else //没有按键按下则为零
i=0;
}
key.h
# ifndef _KEY_H
# define _KEY_H
# include <STC15F2K60S2.H>
void key_read(void);
extern unsigned char key_value;
# endif
other.c
# include "other.h"
void relay_on(void)
{
P2=(P2&0x1F)|0xA0;
P0|=0x10;
P2&=0x1F;
P04=1; //在这里我认为这部分代码比上述代码好,出现的bug少
P2&=0x1F;
P2|=0xA0;
P2&=0x1F;
}
void relay_off(void)
{
P04=0;
P2&=0x1F;
P2|=0xA0;
P2&=0x1F;
// P2=(P2&0x1F)|0xA0;
// P0&=0xEF;
// P2&=0x1F;
}
void bee_off(void)
{
P06=0;
P2&=0x1F;
P2|=0xA0;
P2&=0x1F;
// P2=(P2&=0x1F)|0xA0;
// P0&=0x00;
// P2&=0x1F;
}
other.h
# ifndef _OTHER_H
# define _OTHER_H
# include <STC15F2K60S2.H>
void relay_on(void);
void relay_off(void);
void bee_off(void);
# endif
main.c
# include <STC15F2K60S2.H>
# include "time.h"
# include "smg.h"
# include "key.h"
# include "ds18b20.h"
# include "iic.h"
# include "other.h"
unsigned char tempature_max;
unsigned char tempature_min;
unsigned char key_allow;
unsigned int temp;
unsigned char flag_key;
unsigned char flag_relay;
void Delay5ms() //@12.000MHz
{
unsigned char i, j;
i = 59;
j = 90;
do
{
while (--j);
} while (--i);
}
void allinit(void)
{
P0=0x00;
P2&=0x1F;
P2|=0xA0; //Y5C
P2&=0x1F;
//灯全灭
P0=0xFF;
P2&=0x1F;
P2|=0x80;//Y4C
P2&=0x1F;
}
void eeprom_init(void)
{
if(eeprom_read(0x99)==0x99)//这里可以随便定,只要不是数据库里的变量就行
{ //这里主要是把板里的数据清除掉
tempature_max=30;
tempature_min=23;
tempature_max=eeprom_read(0x00);
tempature_min=eeprom_read(0x01);
}
else
{
eeprom_write(0x99,0x99);
}
}
void main(void)
{
allinit();
eeprom_init();
Timer0Init();
bee_off();
relay_off();
while(1)
{
if(key_allow==1)
{
key_allow=0;
key_read();
}
switch(key_value)
{
case 1:
key_value=0;
flag_key=1;
break;
case 2:
key_value=0;
flag_key=2;
break;
case 3:
key_value=0;
flag_key=3;
break;
case 4:
key_value=0;
flag_key=4;
break;
}
temp=temp_read();
if(temp<tempature_min)
{
flag_relay=1;
}
if(temp>tempature_min)
{
flag_relay=2;
}
if(temp>tempature_max)
{
flag_relay=3;
}
if(temp<tempature_max)
{
flag_relay=4;
}
if(tempature_min>tempature_max||tempature_max==99||tempature_min==99)
{
tempature_min--;
}
switch(flag_key)
{
case 4:
flag_key=0;
if(tempature_max!=99)
{
tempature_max++;
eeprom_write(0x00,tempature_max);
Delay5ms();//延迟5毫秒来储存数据
}
break;
case 3:
flag_key=0;
if(tempature_min!=99)
{
tempature_min++;
eeprom_write(0x01,tempature_min);
Delay5ms();
}
break;
case 2:
flag_key=0;
if(tempature_max!=99)
{
tempature_max--;
eeprom_write(0x00,tempature_max);
Delay5ms();
}
break;
case 1:
flag_key=0;
if(tempature_min!=99)
{
tempature_min--;
eeprom_write(0x01,tempature_min);
Delay5ms();
}
break;
}
dspbuf[0]=tempature_max/10;
dspbuf[1]=tempature_max%10;
dspbuf[2]=tempature_min/10;
dspbuf[3]=tempature_min%10;
dspbuf[4]=10;
dspbuf[5]=10;
dspbuf[6]=temp/10;
dspbuf[7]=temp%10;
}
}
void time0(void) interrupt 1
{
static unsigned char key_30_times;
if(++key_30_times==30)
{
key_30_times=0;
key_allow=1;
}
if(flag_relay==1)
{
relay_on();
flag_relay=0;
bee_off();
}
if(flag_relay==2)
{
flag_relay=0;
relay_off();
bee_off();
}
if(flag_relay==3)
{
P0=0xFE;
P2&=0x1F;
P2=0x80;
P2&=0x1F;
}
if(flag_relay==4)
{
P0=0xFF;
P2&=0x1F;
P2=0x80;
P2&=0x1F;
}
smg_display();
}
//(这里的温控单元要在这里因为因为就是你那个如果放在中断的话,你可能在调用那个继电器打开函数的时候,刚执行到p14等于1他那个中断时间到了,
//它就进入到那个数码段,显示那里要批零就等于0xff,然后继续往下执行,P0就会被刷新掉。)
//然后等你处理完数码管之后,出来再继续进行那个继电器那个,打开那个函数,然后这时候p04应该不是1了,或者是其他的数,如果把温控单元这一部分放在主函数部分那继电器会不灵敏,会跳来跳去,显示bug。
结语
在这里我还是要感谢一下我都朱师兄,感谢他帮我找到了bug(就是温控单元那部分),不然我现在可能还卡在这道题吧!,我也看了一些大佬的文章,感觉自己的代码还是有许多问题,比如代码过长,不简便,所以,我认为我自己还是要好好学习,也感谢大家的观看,如果你认为可以的话可以收藏一下哦(⊙o⊙)!实在不行也给个赞( ̄▽ ̄)"吧!谢谢大家。