第七届蓝桥杯单片机省赛题目解析

这篇博客介绍了第七届省赛的一道题目,涉及LED显示、数码管显示、按键控制、PWM占空比调整以及DS18B20温度传感器的使用。作者解析了各模块的工作原理,如通过独立键盘控制LED亮灭、数码管显示模式切换,以及利用PWM模拟不同亮度,并给出了DS18B20的底层驱动代码。此外,还展示了如何结合定时器实现功能,并提供了完整的代码示例。
摘要由CSDN通过智能技术生成

今天给大家带来第七届(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;
}

最后,这是本人第一次写博客,写的不好的地方,还希望大家指正。我也会往后写,打算写完一题,就和大家讨论一下。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值