今天给大家带来第七届(2016)省赛题目的解析,题目总体不算难,我们一起来看看吧。
题目
这次省赛题整体还是不难的,做起来除了PWM不是很好理解以外,其他的还是很好理解的,最重要的是编程的逻辑。题目考察了LED显示、按键、数码管显示(这三个模块是每套题目都会考的,我们应该要很熟悉了)、PWM、DS18B20。
1 数码管显示
数码管有两种模式,一种是工作模式,一种是室温模式。我们可以写两个界面函数,一个用来显示工作模式,另一个显示室温模式,通过按键来选择显示哪种模式。
2 LED显示
定义一个变量mode,通过按键来控制mode的值让它在1-3之间循环。mode为1时L1亮,mode为2时L2亮,mode为3时L3亮。
3 按键模块
题目是用了s4,s5,s6,s7四个按键,是独立键盘。s4用来控制mode的值。s5用来控制倒计时,也定义一个countdown_mode变量在1-3之间循环,countdown_mode为1时倒计时为0,countdown_mode为2时倒计时为60,countdown_mode为3时倒计时为120。s6就是把countdown_mode设置为1。s7有两个状态,定义一个temp_m变量来控制,为1时显示室温模式,为0时显示工作模式。
4 pwm
由于pwm的信号频率为1KHz,就是1ms。P34引脚有连接定时器0,我们用1ms的定时器0来控制pwm的占空比,比如当pwm的占空比为20%时,就可以用定时器0控制让L1亮0.2ms,灭0.8ms来显示pwm的占空比。具体看代码。
5 DS18B20
就是改写底层驱动代码部分(onewire),然后放在定时器里,每隔一段时间去测量一次。
onewire.c
#include"onewire.h"
#define u8 unsigned char
#define u16 unsigned int
bit initflag;
sbit DQ=P1^4;
void Delay1us()
{
_nop_();
_nop_();
_nop_();
}
void delay_us(unsigned int us)
{
while(us--)
{
Delay1us();
}
}
bit init_ds18b20()
{
DQ=0;
delay_us(500);
DQ=1;
delay_us(20);
initflag=DQ;
delay_us(50);
return initflag;
}
unsigned int get_temp()
{
unsigned char low,high;
unsigned int result;
float i;
init_ds18b20();//³õʼ»¯
ds18b20_wirteByte(0xcc);
ds18b20_wirteByte(0x44);
init_ds18b20();
ds18b20_wirteByte(0xcc);
ds18b20_wirteByte(0xbe);
low=ds18b20_readByte();
high=ds18b20_readByte();
result=high&0x0f;
result<<=8;
result=result|low;
i=result*0.0625;
result=i*100;
return result;
}
void ds18b20_wirteByte(unsigned char dat)
{
unsigned char i=0;
for(i;i<8;i++)
{
DQ=0;
DQ=dat&0x01;
delay_us(65);
DQ=1;
dat=dat>>1;
}
}
u8 ds18b20_readByte()
{
unsigned char i=0;
unsigned char dat;
for (i;i<8;i++)
{
DQ=0;
dat=dat>>1;
DQ=1;
if(DQ)
{
dat|=0x80;
}
delay_us(15);
}
return dat;
}
onewire.h
#ifndef _ONEWIRE_H_
#define _ONEWIRE_H_
#define u8 unsigned char
#define u16 unsigned int
#include<STC15F2K60S2.h>
#include"intrins.h"
void Delay1us();
void delay_us(u16 us);
bit init_ds18b20();
u16 get_temp();
void ds18b20_wirteByte(u8 dat);
u8 ds18b20_readByte();
#endif
INIT.c
个人喜欢把初始化、定时器、数码管显示、键盘放在一个模块里。
#include"INIT.h"
#define u8 unsigned char
#define u16 unsigned int
#define state P3
#define state_0 0
#define state_1 1
#define state_2 2
u8 tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xff,0xc6};
u8 seg[]={11,11,11,11,11,11,11,11};
static u8 key_state=0;
static u8 segadder=0;
u8 row=0,key_press=0,key_num=0;
void all_init() //关闭无关的外设
{
P2=(P2&0x1f)|0x80;
P0=0xff;
P2&=0x1f;
P2=(P2&0x1f)|0xa0;
P04=0;
P06=0;
P2&=0x1f;
P2=(P2&0x1f)|0xc0;
P0=0x00;
P2&=0x1f;
P2=(P2&0x1f)|0xe0;
P0=0xff;
P2&=0x1f;
}
void display() //数码管显示函数
{
P2=(P2&0x1f)|0xe0; //消隐
P0=0xff;
P2&=0x1f;
P2=(P2&0x1f)|0xc0; //位选
P0=1<<segadder;
P2&=0x1f;
P2=(P2&0x1f)|0xe0; //段选
P0=tab[seg[segadder]];
P2&=0x1f;
if(++segadder==8)
segadder=0;
}
u8 read_key() //独立键盘
{
switch(key_state)
{
case state_0:
state=0x0f;
key_press=state;
if(key_press!=0x0f)
key_state=state_1;
break;
case state_1:
key_press=state;
if(key_press!=0x0f)
{
if((key_press & 0x08)==0) row=4;
if((key_press & 0x04)==0) row=5;
if((key_press & 0x02)==0) row=6;
if((key_press & 0x01)==0) row=7;
key_state=state_2;
}
else
key_state=state_0;
break;
case state_2:
state=0x0f;
key_press=state;
if(key_press==0x0f)
key_state=state_0;
break;
}
key_num=row;
row=0;
return key_num;
}
void Timer0Init(void) //100us
{
AUXR |= 0x80;
TMOD &= 0xF0;
TL0 = 0xAE;
TH0 = 0xFB;
TF0 = 0;
TR0 = 1;
EA = 1;
}
void Timer1Init(void) //1ms
{
AUXR |= 0x40;
TMOD &= 0x0F;
TL1 = 0xCD;
TH1 = 0xD4;
TF1 = 0;
TR1 = 1;
ET1 = 1;
EA = 1;
}
INIT.h
#ifndef _INIT_H_
#define _INIT_H_
#define u8 unsigned char
#define u16 unsigned int
#include<STC15F2K60S2.h>
#include"intrins.h"
void all_init();
void display();
u8 read_key();
void Timer0Init(void);
void Timer1Init(void);
#endif
jm.c
这个模块是每个按键所控制的功能。
#include"jm.h"
#include"onewire.h"
#define u8 unsigned char
#define u16 unsigned int
extern u8 seg[],countdown,moude,temp_flag; // extern表示此变量是在别处定义的,要在此处引用
u16 temp;
void jm4() //s4所控制的功能
{
seg[0]=10;
seg[1]=moude;
seg[2]=10;
seg[3]=11;
}
void jm5() //s5所控制的功能
{
seg[4]=countdown/1000;
seg[5]=countdown/100%10;
seg[6]=countdown/10%10;
seg[7]=countdown%10;
}
void jm6() //s6所控制的功能
{
seg[4]=countdown/1000;
seg[5]=countdown/100%10;
seg[6]=countdown/10%10;
seg[7]=countdown%10;
}
void jm7() //s7所控制的功能
{
if(temp_flag==1)
{
temp_flag=0;
temp=get_temp();
}
seg[0]=10;
seg[1]=4;
seg[2]=10;
seg[3]=11;
seg[4]=11;
seg[5]=temp/1000;
seg[6]=temp/100%10;
seg[7]=12;
}
jm.h
#ifndef _JM_H_
#define _JM_H_
#define u8 unsigned char
#define u16 unsigned int
#include<STC15F2K60S2.h>
#include"intrins.h"
void jm4();
void jm5();
void jm6();
void jm7();
#endif
main.c
#include"INIT.h"
#include"jm.h"
#include"onewire.h"
#define u8 unsigned char
#define u16 unsigned int
static u16 moude_count=0,pwm;
u8 num=0,moude=1,countdown=0,temp_m=0,countdown_moude=1;
u8 temp_flag=0;
u8 jma,jmb;
u16 countdown_count=0,temp_count=0;
extern seg[];
void main()
{
all_init();
Timer0Init();
Timer1Init();
while(1)
{
if(countdown>0) ET0 = 1; //倒计时大于0打开定时器0
else ET0 = 0;
num=read_key();
switch(num)
{
case 4:
if(++moude==4) moude=1; //三种工作模式
if(moude==1) pwm=2;
if(moude==2) pwm=3;
if(moude==3) pwm=7;
jma=0,jmb=0;
break;
case 5:
if(++countdown_moude==4) countdown_moude=1; //设定倒计时
if(countdown_moude==1) countdown=0;
if(countdown_moude==2) countdown=60;
if(countdown_moude==3) countdown=120;
jma=0,jmb=1;
break;
case 6: //停止,清零
countdown=0;
jma=1,jmb=0;
break;
case 7: //工作或室温界面
temp_m^=1;
if(temp_m==1)
{
jma=1,jmb=1;
}
else
{
jma=0,jmb=0;
}
break;
}
num=0;
if(jma==0&&jmb==0)
{
jm4();
jm5();
}
if(jma==0&&jmb==1) jm5();
if(jma==1&&jmb==0) jm6();
if(jma==1&&jmb==1) jm7();
}
}
void Timer1() interrupt 3
{
display();
countdown_count++;
temp_count++;
if(countdown_count==1000) //每一秒倒计时减一
{
if(countdown>0) countdown--;
countdown_count=0;
}
if(temp_count==200) //每200ms获取一次室温
{
temp_flag=1;
temp_count=0;
}
}
void Timer0() interrupt 1
{
if(moude_count<pwm) pwm的占空比越大,led灯越亮。
{
if(moude==1&&countdown!=0)
{
P2=(P2&0x1f)|0x80;P0=0xfe;P2&=0x1f;
}
if(moude==2&&countdown!=0)
{
P2=(P2&0x1f)|0x80;P0=0xfd;P2&=0x1f;
}
if(moude==3&&countdown!=0)
{
P2=(P2&0x1f)|0x80;P0=0xfb;P2&=0x1f;
}
}
else
{
P2=(P2&0x1f)|0x80;P0=0xff;P2&=0x1f;
}
if(++moude_count>=10) moude_count=0;
}
最后,这是本人第一次写博客,写的不好的地方,还希望大家指正。我也会往后写,打算写完一题,就和大家讨论一下。