蓝桥杯单片机第五届初赛程序设计——“简易温度采集与控制装置”设计任务书

综述

第五届初赛赛题除了基础的数码管显示、继电器和蜂鸣器的控制、LED灯的控制以外,难度增加的部分体现在需要使用矩阵键盘,以及DS18B20的调用。

本解析不代表标准答案或官方答案,仅做分享。若有不足或是更好的写法,望在评论区进行指正!

模板搭建

基础的功能:
1、独立按键
2、数码管显示

可以独立于赛题,提前写好,适用于各类赛题,仅做修改即可。

模板部分代码与解释在第三届赛题分享中 模板代码

根据此题要求对模板做出的改变

1、该题需要用到矩阵按键,也就是按键部分需要进行修改。同时也意味着无法使用MM模式。

void keyScan(){
	uchar i, j, k;
	for(i = 0; i < 4; i ++)
		for(j = 0; j < 4; j ++) keyPress[i][j] = 0;
	
	for(i = 0; i < 4; i ++){
		k = ~(0x01 << i);
		P44 = (k & 0x01);P42 = ((k & 0x02) >> 1);P35 = ((k & 0x04) >> 2);P34 = ((k & 0x08) >> 3);
		if((P3 & 0x0f) != 0x0f){
			Delay5ms();
			if((P3 & 0x0f) != 0x0f){
				switch(P3 & 0x0f){
					case 0x0e:keyPressFlag[i][0] = 1;break;
					case 0x0d:keyPressFlag[i][1] = 1;break;
					case 0x0b:keyPressFlag[i][2] = 1;break;
					case 0x07:keyPressFlag[i][3] = 1;break;
				}
			}
		}
	}
	for(i = 0; i < 4; i ++){
		k = ~(0x01 << i);
		P44 = (k & 0x01);P42 = ((k & 0x02) >> 1);P35 = ((k & 0x04) >> 2);P34 = ((k & 0x08) >> 3);
		for(j = 0; j < 4; j ++){
			if(keyPressFlag[i][j] == 1){
				if((P3 & 0x0f) == 0x0f){
					keyPress[i][j] = 1;
					keyPressFlag[i][j] = 0;
				}
			}
		}
	}	
}

这里的keyPresskeyPressFlag两个数组被扩充为[4][4]的二维数组。
例如:[0][2]代表矩阵键盘的第1列,第3排,即S5

程序设计

DS18B20

官方为我们提供了DS18B20的一个c文件一个h头文件。需要在项目中导入DS18B20.c,同时声明DS18B20.h。
需要我们写的函数需要参照芯片手册中的下图:
在这里插入图片描述
也就是说我们写的函数,必须遵循以下流程:初始化->写ROM命令->写DS18B20函数命令->循环

而我们需要跳过寻址(与DS18B20原理有关),再进行温度转换。
之后进行温度的读取:
在这里插入图片描述
读出的数据格式如图,先返回低字节,后返回高字节。
由于我们通常不需要用到小数点后面的数据,所以需要将高字节左移,低字节右移来进行拼接。

代码:

uchar getTemp(){
	uchar low, high;
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0x44);
	Delay_OneWire(20);  
	
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0xbe);
	
	low = Read_DS18B20();
	high = Read_DS18B20();
	
	return ((low >> 4) | (high << 4));
}

系统设计

在系统设计的时候,尽量避免对P2的重复操作第三届系统设计示例

这一道赛题对于P2的问题较为明显,即L1灯闪烁部分必须要进行优化,否则L1会出现闪烁不规则的情况。
只有当L1发生变化时(L1由亮到灭或者由灭到亮),才对P2和P0进行操作。

对于L1的闪烁,可以用定时器来实现。

主函数代码:

#include <stc15f2k60s2.h>
#include <intrins.h>
#include <ds18b20.h>

#define uchar unsigned char
	
uchar keyPress[4][4];
uchar keyPressFlag[4][4];

uchar code shapeOfNum[11] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0xbf};
uchar numGrp[8] = {11, 0, 5, 0, 0, 0, 0, 0};

uchar tempSet[4] = {11, 11, 11, 11};

uchar count = 0, t = 0;


void Delay1ms(){
	unsigned char i, j;

	_nop_();
	_nop_();
	_nop_();
	i = 11;
	j = 190;
	do
	{
		while (--j);
	} while (--i);
}

void Delay5ms(){
	unsigned char i, j;

	i = 54;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
}

void openP2(uchar num){
	P2 &= 0x1f;
	P2 |= (num << 5);
}


void showNum(){
	uchar i;
	for(i = 0; i < 8; i ++){
		if(numGrp[i] != 11){
			openP2(6);P0 = (0x01 << i);
			openP2(7);P0 = shapeOfNum[numGrp[i]];
			Delay1ms();
		}
	}
	openP2(6);P0 = 0x00;
}

void keyScan(){
	uchar i, j, k;
	for(i = 0; i < 4; i ++)
		for(j = 0; j < 4; j ++) keyPress[i][j] = 0;
	
	for(i = 0; i < 4; i ++){
		k = ~(0x01 << i);
		P44 = (k & 0x01);P42 = ((k & 0x02) >> 1);P35 = ((k & 0x04) >> 2);P34 = ((k & 0x08) >> 3);
		if((P3 & 0x0f) != 0x0f){
			Delay5ms();
			if((P3 & 0x0f) != 0x0f){
				switch(P3 & 0x0f){
					case 0x0e:keyPressFlag[i][0] = 1;break;
					case 0x0d:keyPressFlag[i][1] = 1;break;
					case 0x0b:keyPressFlag[i][2] = 1;break;
					case 0x07:keyPressFlag[i][3] = 1;break;
				}
			}
		}
	}
	for(i = 0; i < 4; i ++){
		k = ~(0x01 << i);
		P44 = (k & 0x01);P42 = ((k & 0x02) >> 1);P35 = ((k & 0x04) >> 2);P34 = ((k & 0x08) >> 3);
		for(j = 0; j < 4; j ++){
			if(keyPressFlag[i][j] == 1){
				if((P3 & 0x0f) == 0x0f){
					keyPress[i][j] = 1;
					keyPressFlag[i][j] = 0;
				}
			}
		}
	}	
}

uchar getTemp(){
	uchar low, high;
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0x44);
	Delay_OneWire(20);  
	
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0xbe);
	
	low = Read_DS18B20();
	high = Read_DS18B20();
	
	return ((low >> 4) | (high << 4));
}

void Timer0Init(void){
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0xCD;		//设置定时初值
	TH0 = 0xD4;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
}

void timer0() interrupt 1{
	if(count == 200){
		t ++;
		if(t == 9) t = 1;
		count = 0;
	}
	count ++;
}

void main(){
	uchar i, j, p;
	uchar temp, part = 0;
	uchar mod = 0, preMod = 1;
	uchar tmin = 20, tmax = 30;
	uchar L2 = 0, L10 = 0, L1 = 0;
	P2 = 0xa0;P0 = 0x00;
	P2 = 0x80;P0 = 0xff;
	EA = 1;ET0 = 1;
	Timer0Init();
	
	while(1){
		keyScan();
		if(mod == 0){ //mod为0时表示显示模式,为1时表示设置模式
			if(preMod == 1){
				preMod = 0;
			}
			temp = getTemp();
			if(temp < tmin) part = 0;
			else if(temp <= tmax) part = 1;
			else if(temp > tmax) part = 2;
			
			
			//如果设置错误,L2长亮
			if(tmax <tmin){
				if(L2 == 0){
					L2 = 1;
					openP2(4);P0 = ~(0x02);openP2(0);
				}
			}
			else{
				if(L2 == 1){
					L2 = 0;
					openP2(4);P0 = ~(0x00);openP2(0);
				}
			}
			
			//开关继电器
			if(part == 2){
				if(L10 == 0){
					openP2(5);P0 = 0x10;openP2(0);
					L10 = 1;
				}
			}
			else{
				if(L10 == 1){
					openP2(5);P0 = 0x00;openP2(0);
					L10 = 0;
				}
			}
			
			//L1闪烁
			switch(part){
				case 0:{
					if(t == 4){
						if(L1 == 0){
							openP2(4);P0 = ~(0x01);openP2(0);
							L1 = 1;
						}
					}
					if(t == 8){
						if(L1 == 1){
							openP2(4);P0 = ~(0x00);openP2(0);
							L1 = 0;
						}
					}
					break;
				}
				case 1:{
					if((t == 2) || (t == 6)){
						if(L1 == 0){
							openP2(4);P0 = ~(0x01);openP2(0);
							L1 = 1;
						}
					}
					if((t == 4) || (t == 8)){
						if(L1 == 1){
							openP2(4);P0 = ~(0x00);openP2(0);
							L1 = 0;
						}
					}
					break;
				}
				case 2:{
					if((t % 2) == 1){
						if(L1 == 0){
							openP2(4);P0 = ~(0x01);openP2(0);
							L1 = 1;
						}
					}
					if((t % 2) == 0){
						if(L1 == 1){
							openP2(4);P0 = ~(0x00);openP2(0);
							L1 = 0;
						}
					}
					break;
				}
			}
			
			//数码管显示
			numGrp[0] = 10;
			numGrp[1] = part;
			numGrp[2] = 10;
			numGrp[3] = 11;
			numGrp[4] = 11;
			numGrp[5] = 11;
			numGrp[6] = (temp / 10) % 10;
			numGrp[7] = temp % 10;
			
			if(keyPress[1][3] == 1){
				mod = 1;
			}
		}
		
		else if(mod == 1){
			if(preMod == 0){
				p = 0;
				preMod = 1;
			}
			
			//数码管显示
			numGrp[0] = 10;
			numGrp[1] = tempSet[0];
			numGrp[2] = tempSet[1];
			numGrp[3] = 11;
			numGrp[4] = 11;
			numGrp[5] = 10;
			numGrp[6] = tempSet[2];
			numGrp[7] = tempSet[3];
			
			for(i = 0; i < 4; i ++){
				for(j = 0; j < 4; j ++){
					if((keyPress[i][j] == 1) && (p <= 3)){
						if((j * 3 + i) <= 9){
							tempSet[p++] = (j * 3 + i);
						}
					}
				}
			}
			
			if(keyPress[2][3] == 1){
				for(i = 0; i < 4; i ++) tempSet[i] = 11;
				p = 0;
			}
			
			if((keyPress[1][3] == 1) && (p == 4)){
				tmax = tempSet[0] * 10 + tempSet[1];
				tmin = tempSet[2] * 10 + tempSet[3];
				for(i = 0; i < 4; i ++) tempSet[i] = 11;
				mod = 0;
			}
		}
		
		
		
		showNum();
	}
	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值