十六届蓝桥杯单片机模拟试题I

题目

 

 

题目也是很长的一坨。 

但是外设只用到了ds18b20温度传感器,应该不会很难。

按键功能

S4简单的切换模式按键,s5切换触发模式,这两个都很常规,S8,S9不同界面不同参数的加减。

/*按键函数区域*/
void Key_Proc(){
	if(Key_Slow) return;
	Key_Slow = 1;
	
	Key_Val = Key_Read();
	Key_Down = Key_Val & (Key_Val ^ Key_Old);
	Key_Up = ~Key_Val & (Key_Val ^ Key_Old);
	Key_Old = Key_Val;
	
	switch(Key_Down){
		case 4://界面切换
			if(++Seg_Mode == 3) Seg_Mode = 0;
		break;
		case 5://触发模式切换
			Work_Mode ^= 1;
		break;
		case 8://减去
			if(Seg_Mode == 1){//校准值界面校准值减一
				adjust = adjust == -99?-99:adjust-1;
			}
			else if(Seg_Mode == 2){//参数界面参数减一
				tempature = tempature == -99?-99:tempature-1;
			}
		break;
		case 9:
			if(Seg_Mode == 1){//校准值界面校准值加一
				adjust = adjust == 99?99:adjust+1;
			}
			else if(Seg_Mode == 2){//参数界面参数加一
				tempature = tempature == 99?99:tempature+1;
			}
		break;
	}
	
}

显示界面

三种显示界面,标识符分别C,E,H。都是熄灭四位,这些共同的我们可以放在外面,

校准值的范围是-99~99,所以我们用int类型来作为校准值的变量,温度值依旧用float类型。

我们在对于校准值需要进行判断,这里按理来说,温度值是当前温度加上校准值,也有可能是负数,但是这里数码管的分配加上小数点后一位,并没有负号的空间,所以我们就根据题目的意思,正常显示温度即可。温度就不需要判断正负值了,判断一下高位熄灭就可以了。

而对于温度参数和温度校准值来说,就得判断正负和高位熄灭,两个显示模式代码一模一样就参数不一样罢了。

Seg_Buf[1] = 10;
	Seg_Buf[2] = 10;
	Seg_Buf[3] = 10;
	Seg_Buf[4] = 10;
	switch(Seg_Mode){
		case 0://温度显示模式
			Seg_Buf[0] = 11;//C
			Seg_Buf[5] = (unsigned char)temp>=10?(unsigned char)temp/10:10;
			Seg_Buf[6] = (unsigned char)(temp)%10;
			Seg_Buf[7] = (unsigned int)(temp*10)%10;
			Point[6] = 1;
		break;
		case 1://校准值界面
			Point[6] = 0;
			Seg_Buf[0] = 12;//E
			if(adjust<0){//负数值
				Seg_Buf[5] = adjust_negative>=10?14:10;//-
				Seg_Buf[6] = adjust_negative>=10?adjust_negative/10:14;
				Seg_Buf[7] = adjust_negative%10;
			}
			else{//正数
				Seg_Buf[5] = 10;
				Seg_Buf[6] = adjust>10?adjust/10:10;
				Seg_Buf[7] = adjust%10;
			}
		break;
		case 2:
			Point[6] = 0;
			Seg_Buf[0] = 13;//H
			if(temp<0){
				Seg_Buf[5] = temp_negative>=10?14:10;//-
				Seg_Buf[6] = temp_negative>=10?temp_negative/10:10;
				Seg_Buf[7] = temp_negative%10;
			}
			else{
				Seg_Buf[5] = 10;
				Seg_Buf[6] = tempature>=10?tempature/10:10;
				Seg_Buf[7] = tempature%10;
			}
		break;
	}

Led功能 

L1~L5都是简单的界面功能点亮对应的灯,不多赘述。

L8就是在触发模式不同不一样的判断条件,定义一个标志位去判断即可。

if(Work_Mode == 0){//上限触发
		if(temp>tempature) L8_flag = 1;
		else L8_flag = 0;
	}
	else{//下限触发
		if(temp<tempature) L8_flag = 1;
		else L8_flag = 0;
	}
/*Led函数区域*/
void Led_Proc(){
	Led_Buf[0] = (Seg_Mode == 0);//温度界面点亮L1
	Led_Buf[1] = (Seg_Mode == 1);
	Led_Buf[2] = (Seg_Mode == 2);
	Led_Buf[3] = (Work_Mode == 0);//上限触发点亮L4
	Led_Buf[4] = (Work_Mode == 1);
	Led_Buf[7] = L8_flag;
}

完整主函数 

/*头文件区域*/
#include <STC15F2K60S2.H>
#include <Init.h>
#include <Seg.h>
#include <Led.h>
#include <Key.h>
#include <onewire.h>
#include <intrins.h>
/*变量参数区域*/
unsigned char Key_Slow,Seg_Slow;
unsigned char Seg_Pos;
unsigned char Key_Down,Key_Old,Key_Up,Key_Val;
//数据
unsigned char Seg_Buf[8] = {10,10,10,10,10,10,10,10};
unsigned char Led_Buf[8] = {0,0,0,0,0,0,0,0};
unsigned char Point[8] = {0,0,0,0,0,0,0,0};
unsigned char Seg_Mode;//0温度界面,1校准值2参数
unsigned char Work_Mode;//0上触发1下触发
int adjust = 0;//校准值默认为0
unsigned char tempature = 26;//温度参数默认值26
float temp;//当前读取的温度
bit L8_flag;
/*按键函数区域*/
void Key_Proc(){
	if(Key_Slow) return;
	Key_Slow = 1;
	
	Key_Val = Key_Read();
	Key_Down = Key_Val & (Key_Val ^ Key_Old);
	Key_Up = ~Key_Val & (Key_Val ^ Key_Old);
	Key_Old = Key_Val;
	
	switch(Key_Down){
		case 4://界面切换
			if(++Seg_Mode == 3) Seg_Mode = 0;
		break;
		case 5://触发模式切换
			Work_Mode ^= 1;
		break;
		case 8://减去
			if(Seg_Mode == 1){//校准值界面校准值减一
				adjust = adjust == -99?-99:adjust-1;
			}
			else if(Seg_Mode == 2){//参数界面参数减一
				tempature = tempature == -99?-99:tempature-1;
			}
		break;
		case 9:
			if(Seg_Mode == 1){//校准值界面校准值加一
				adjust = adjust == 99?99:adjust+1;
			}
			else if(Seg_Mode == 2){//参数界面参数加一
				tempature = tempature == 99?99:tempature+1;
			}
		break;
	}
	
}
/*数码管函数区域*/
void Seg_Proc(){
	unsigned int adjust_negative,temp_negative;
	adjust_negative = -adjust;
	temp_negative = -temp;
	if(Seg_Slow) return;
	Seg_Slow = 1;
	
	temp = rd_tempature();
	temp = temp + adjust;
	
	if(Work_Mode == 0){//上限触发
		if(temp>tempature) L8_flag = 1;
		else L8_flag = 0;
	}
	else{//下限触发
		if(temp<tempature) L8_flag = 1;
		else L8_flag = 0;
	}
	
	Seg_Buf[1] = 10;
	Seg_Buf[2] = 10;
	Seg_Buf[3] = 10;
	Seg_Buf[4] = 10;
	switch(Seg_Mode){
		case 0://温度显示模式
			Seg_Buf[0] = 11;//C
			Seg_Buf[5] = (unsigned char)temp>=10?(unsigned char)temp/10:10;
			Seg_Buf[6] = (unsigned char)(temp)%10;
			Seg_Buf[7] = (unsigned int)(temp*10)%10;
			Point[6] = 1;
		break;
		case 1://校准值界面
			Point[6] = 0;
			Seg_Buf[0] = 12;//E
			if(adjust<0){//负数值
				Seg_Buf[5] = adjust_negative>=10?14:10;//-
				Seg_Buf[6] = adjust_negative>=10?adjust_negative/10:14;
				Seg_Buf[7] = adjust_negative%10;
			}
			else{//正数
				Seg_Buf[5] = 10;
				Seg_Buf[6] = adjust>10?adjust/10:10;
				Seg_Buf[7] = adjust%10;
			}
		break;
		case 2:
			Point[6] = 0;
			Seg_Buf[0] = 13;//H
			if(temp<0){
				Seg_Buf[5] = temp_negative>=10?14:10;//-
				Seg_Buf[6] = temp_negative>=10?temp_negative/10:10;
				Seg_Buf[7] = temp_negative%10;
			}
			else{
				Seg_Buf[5] = 10;
				Seg_Buf[6] = tempature>=10?tempature/10:10;
				Seg_Buf[7] = tempature%10;
			}
		break;
	}
	
}
/*Led函数区域*/
void Led_Proc(){
	Led_Buf[0] = (Seg_Mode == 0);//温度界面点亮L1
	Led_Buf[1] = (Seg_Mode == 1);
	Led_Buf[2] = (Seg_Mode == 2);
	Led_Buf[3] = (Work_Mode == 0);//上限触发点亮L4
	Led_Buf[4] = (Work_Mode == 1);
	Led_Buf[7] = L8_flag;
}
/*定时器0初始化区域*/
void Timer0_Init(void)		//1毫秒@12.000MHz
{
	AUXR &= 0x7F;			//定时器时钟12T模式
	TMOD &= 0xF0;			//设置定时器模式
	TL0 = 0x18;				//设置定时初始值
	TH0 = 0xFC;				//设置定时初始值
	TF0 = 0;				//清除TF0标志
	TR0 = 1;				//定时器0开始计时
	ET0 =1;
	EA = 1;
}


/*定时器0中断服务函数*/
void Timer0_Service() interrupt 1
{
	if(++Seg_Slow == 200) Seg_Slow = 0;
	if(++Key_Slow == 50) Key_Slow = 0;
	
	if(++Seg_Pos == 8) Seg_Pos = 0;
	Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos],Point[Seg_Pos]);
	Led_Disp(Seg_Pos,Led_Buf[Seg_Pos]);
	
}
void Delay750ms(void)	//@12.000MHz
{
	unsigned char data i, j, k;

	_nop_();
	_nop_();
	i = 35;
	j = 51;
	k = 182;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

/*主函数区域*/
void main(){
	Timer0_Init();
	Sys_Init();
	rd_tempature();
	Delay750ms();
	while(1){
		Key_Proc();
		Seg_Proc();
		Led_Proc();
	}
}

 

 

 

<think>好的,我需要帮助用户找到2016蓝桥杯单片机相关的模拟试题或资料。首先,用户提到了第七题目,涉及的外设有ADC、EEPROM、USART、LED、KEY等,还有温度数据获取的问题。用户提供的三个引用中,引用1和2提到了第七题的外设使用和头文件,引用3讨论了温度数据读取时的中断问题及解决方法。 用户的需求是查找该年的模拟题或试题解析。根据现有信息,第七的外设配置和问题点已经比较明确,但用户可能需要更具体的试题内容或解析步骤。我应该先整理现有的资料,然后看看能否扩展相关内容,比如提供试题解析的思路或常见考点。 首先,根据引用1,第七题目用到了多个外设,但没有PWM和蜂鸣器。这可能意味着考试重点在于这些外设的配置和综合应用。引用2中的头文件ledAndKey.h显示了LED和按键的函数,这可能涉及扫描按键和控制LED显示。引用3提到的温度数据读取问题,涉及中断处理,需在读取时关闭中断以避免数据错乱,但会影响PWM输出,这可能是一个考点,如何平衡中断和外围设备的稳定性。 接下来,用户可能需要试题的具体实现步骤或常见问题解析。例如,如何配置ADC和EEPROM,如何通过USART传输数据,以及如何处理中断冲突的问题。此外,代码示例可能有帮助,比如温度传感器的读取代码,或者按键扫描的实现。 另外,用户可能需要了解如何综合这些外设,例如,题目可能要求通过ADC读取电压,存储到EEPROM,再通过USART发送到上位机,同时用LED显示状态,按键控制流程。这类综合应用题的解析可能对用户有用。 由于现有引用中没有提供完整的试题内容,可能需要根据已有的信息构建可能的试题结构和解析方向。例如,结合外设的使用情况,分模块解析每个部分的实现方法,并指出常见错误,如中断处理不当导致的数据错乱,以及如何优化代码结构。 最后,生成相关问题,帮助用户进一步深入学习,比如涉及外设配置的步骤,中断处理的注意事项,或者如何调试综合应用中的问题。</think>### 2016蓝桥杯单片机第七相关解析 根据提供的引用资料,2016年第七蓝桥杯嵌入式/单片机题目主要涉及以下核心内容: --- #### **1. 外设模块与考点** - **主要外设**:ADC、EEPROM、USART、LED、按键(Key)[^1][^2]。 - **未涉及外设**:PWM、蜂鸣器。 - **综合应用**:需结合多个外设实现功能,例如数据采集(ADC)、存储(EEPROM)、通信(USART)、人机交互(LED和按键)[^1]。 --- #### **2. 关键问题与解决方法** - **温度数据读取问题**: - **现象**:温度显示跳动,因定时器中断打断了DS18B20的时序[^3]。 - **解决方案**:读取温度前关闭中断,读取完成后恢复中断。但需注意关闭中断可能导致PWM输出不稳定,需权衡时序优先级。 - **代码结构优化**: - **示例**:通过模块化编程分离功能(如`ledAndKey.h`中封装LED显示和按键扫描函数)。 - **中断管理**:避免外设操作冲突,如USART通信与定时器中断的协调。 --- #### **3. 试题解析方向** 1. **ADC与EEPROM综合应用**: - 题目可能要求通过ADC采集电压,将结果存储到EEPROM,并通过USART发送到上位机。 - **关键点**:ADC校准、EEPROM页写入、USART协议设计。 2. **LED与按键交互**: - 实现按键控制LED显示模式(如流水灯、呼吸灯)。 - **参考代码**: ```c // 按键扫描函数(引用自头文件) unsigned char Key_Scan(void) { // 扫描逻辑 } ``` 3. **温度传感器与中断冲突**: - 题目可能要求读取DS18B20温度并显示,同时处理定时器中断。 - **解决方法**:在温度读取临界区关闭中断,完成后恢复。 --- #### **4. 模拟试题示例** **题目**:设计一个系统,通过ADC采集0~3.3V电压,按键控制采样频率,采样结果存储到EEPROM,并通过USART发送到PC端显示。 **解析步骤**: 1. 配置ADC为连续扫描模式,DMA传输数据。 2. 按键设置采样间隔(如1s/5s)。 3. EEPROM分页存储数据,避免频繁擦写。 4. USART使用中断接收PC指令,触发数据回传。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值