十五届蓝桥杯单片机模拟赛二程序题

本文详细描述了一个单片机竞赛项目,涉及DS18B20温度传感器、PCF8591AD/DA转换、数码管显示、按键控制、光照度测量和DAC输出等功能。参赛者需按照特定硬件配置和编程要求来完成比赛作品。
摘要由CSDN通过智能技术生成

 题目

一、基本要求


使用大赛组委会提供的四梯/国信长天单片机竞赛实训平台,完成本试题的程序设计与调试。程序编写、调试完成后,选手需通过考试系统提交以准考证号命名的hex文件。不符合以上文件提交要求的作品将被评为零分或者被酌情扣分。

硬件设置:

将IAP15F2K61S2单片机内部振荡器频率设定为12MHz

键盘工作模式跳线J5配置为KBD矩阵按键模式。

扩展方式跳线J13配置为IO模式。

请注意:选手需严格按照以上要求配置竞赛板,编写和调试程序,不符合以上配置要求的作品将被评为零分或者被酌情扣分。

二、硬件框图


图1 系统硬件框图

三、功能描述


3.1 基本功能描述

1)通过获取DS18B20温度传感器的温度数据,完成温度测量功能;

2)通过PCF8591 AD/DA芯片完成环境光测量和DAC输出功能;

3)通过LED指示灯完成试题要求的状态指示功能;

4)通过数码管、按键完成试题要求的数据显示和界面切换功能。

3.2 显示功能

1、模式界面

模式界面如图2所示,显示内容包括模式编号,测量的参数数据。

模式1为温度控制模式,显示内容包括编号‘1’和测量的温度参数。

温度参数单位为℃,保留小数点后1位,固定使用3位数码管显示。

图2.1 温度控制模式

模式2为光照度控制模式,显示内容包括编号‘2’和测量的光照度参数。

光照度参数单位为Lux,保留整数,固定使用3位数码管显示,不足3位时,高位(左侧)数码管熄灭。

图2.3 光照度控制模式

2、输出界面

输出界面如图3所示,由标识符(U)和输出的DAC数据组成。

输出的DAC数据单位为V,保留小数点后1位,固定使用2位数码管显示。

图3 输出界面

3、显示要求

按照题目要求的界面格式和切换方式进行设计。

数码管显示无重影、闪烁、过暗、亮度不均匀等严重影响显示效果的缺陷。

3.3 按键功能

1、功能说明

1)S4:定义为“模式切换”,在模式界面下,按下S4按键,切换2种控制模式,切换顺序如下图所示。

图4 模式切换顺序

2)S5:定义为“界面切换”,按下S5按键,切换模式界面和输出界面,切换顺序如图所示。

图5 模式切换顺序

2、按键要求

按键应做好消抖处理,避免出现一次按键动作导致功能多次触发。

按键动作不影响数码管显示等其他功能。

按键S4仅在“模式界面”有效。

3.4 输出功能

模式1,DAC输出与测量的温度参数有关,温度参数与DAC输出关系如图6.1所示。

图6.1 温度参数与DAC输出关系

模式2,DAC输出与测量的光照度参数有关,光照度参数与DAC输出关系如图6.2所示。

图6.2 光照度参数与DAC输出关系

3.5 LED指示灯功能


1)温度控制模式下,指示灯L1点亮,否则指示灯L1熄灭。

2)光照度控制模式下,指示灯L2点亮,否则指示灯L2熄灭。

其余指示灯均处于熄灭状态。

3.6 初始状态


请严格按照以下要求设计作品的上电初始状态。

处于模式界面,温度控制模式。

代码

这里就不写底层部分了,可以参考上一篇博客,有一个地方是上一篇博客可能按键值那里,因为根据题目的要求,对应按键输入对应的键值,所以对部分按键的键值进行了修改,这里放一下默认的以及上一篇没有涉及到的底层代码

main.c

#include <iic.h>
#include <tim.h>
#include <seg.h>
#include <key.h>
#include <stdio.h>
#include <onewire.h>

unsigned char Seg_Buf[10],Seg_Code[8],Seg_Dly,Seg_Pos;
unsigned char Key_Val,Key_Up,Key_Down,Key_Old,Key_Dly;
unsigned char Sys_Mod,Output_Mod;
unsigned int  temper;
unsigned char Light_Stat;
unsigned int  volt_stat;
unsigned char ucLED,LED_Dly;
unsigned char Output_Dly;

void Key_Proc(void);
void Seg_Proc(void);
void LED_Proc(void);
void Output_Proc(void);

void main(void)
{
	Close_Ws();
	Timer1_Init();
	
	while(1)
	{
		Key_Proc();
		Seg_Proc();
		LED_Proc();
		Output_Proc();
	}
}

void Key_Proc(void)
{
	if(Key_Dly) return;
	Key_Dly=1;
	
	Key_Val=Read_Key();
	Key_Down=Key_Val&(Key_Old^Key_Val);
	Key_Up=~Key_Val&(Key_Old^Key_Val);
	Key_Old=Key_Val;
	
	if(Key_Down==4)
		if(Sys_Mod==0)
			if(++Output_Mod==2) Output_Mod=0;
	
	if(Key_Down==5)
		if(++Sys_Mod==2) Sys_Mod=0;
}

void Seg_Proc(void)
{
	if(Seg_Dly) return;
	Seg_Dly=1;
	
	switch(Sys_Mod)
	{
		case 0:
			switch(Output_Mod)
			{
				case 0:
					temper=Read_Temperture();
					if((temper/16)==85) sprintf(Seg_Buf,"1       ");
					else sprintf(Seg_Buf,"1    %03.1f",temper/16.0);
					Seg_Tran(Seg_Buf,Seg_Code);
				break;
				
				case 1:
					Light_Stat=Read_ADC();	
					sprintf(Seg_Buf,"2    %3d",(unsigned int)Light_Stat);
					Seg_Tran(Seg_Buf,Seg_Code);
				break;
			}
		break;
		
		case 1:
			switch(Output_Mod)
			{
				case 0:temper=Read_Temperture();break;
				case 1:Light_Stat=Read_ADC();break;
			}
			sprintf(Seg_Buf,"U     %2.1f",volt_stat/10.0);
			Seg_Tran(Seg_Buf,Seg_Code);
		break;
	}
	
	Write_DAC((unsigned char)volt_stat*5.1);
}

void Output_Proc(void)
{
	switch(Output_Mod)
	{
		case 0:
			if(temper/16<10) volt_stat=10;
			else if(temper/16>40) volt_stat=50;
			else volt_stat=(temper-40)/12;
		break;
		
		case 1:
			if(Light_Stat<10) volt_stat=10;
			else if(Light_Stat>240) volt_stat=50;
			else volt_stat=(4*Light_Stat+190)/23;			
		break;
	}
}

void LED_Proc(void)
{
	if(LED_Dly) return;
	LED_Dly=1;
	
	switch(Output_Mod)
	{
		case 0:ucLED=0x01;break;
		case 1:ucLED=0x02;break;
	}
	
	LED_Disp(ucLED);
}

void Timer1_Isr(void) interrupt 3
{
	Seg_Disp(Seg_Code,Seg_Pos);
	if(++Seg_Pos==8) Seg_Pos=0;
	
	if(++Seg_Dly==100) Seg_Dly=0;
	
	if(++Key_Dly==10) Key_Dly=0;
	
	if(++LED_Dly==10) LED_Dly=0;
	
}

key.c

#include <key.h>

unsigned char Read_Key(void)
{
	unsigned char Key_Val;
	unsigned int  Key_New;
	
	P44=0;P42=1;P35=1;P34=1;
	Key_New=P3;
	
	P44=1;P42=0;
	Key_New=(Key_New<<4)+(P3&0x0f);
	
	P42=1;P35=0;
	Key_New=(Key_New<<4)+(P3&0x0f);
	
	P35=1;P34=0;
	Key_New=(Key_New<<4)+(P3&0x0f);
	
	switch(~Key_New)
	{
		case 0x8000:Key_Val=4; break;
		case 0x4000:Key_Val=5; break;
		case 0x2000:Key_Val=6; break;
		case 0x1000:Key_Val=7; break;
		case 0x0800:Key_Val=8; break;
		case 0x0400:Key_Val=9; break;
		case 0x0200:Key_Val=10;break;
		case 0x0100:Key_Val=11;break;
		case 0x0080:Key_Val=12;break;
		case 0x0040:Key_Val=13;break;
		case 0x0020:Key_Val=14;break;
		case 0x0010:Key_Val=15;break;
		case 0x0008:Key_Val=16;break;
		case 0x0004:Key_Val=17;break;
		case 0x0002:Key_Val=18;break;
		case 0x0001:Key_Val=19;break;
		
		default:Key_Val=0;
	}
	
	return Key_Val;
}

onewire.c

unsigned int Read_Temperture(void)
{
	unsigned char high,low;
	
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0x44);
	
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0xbe);
	
	low=Read_DS18B20();
	high=Read_DS18B20();
	
	return (high<<8)+low;
}

iic.c

unsigned char Read_ADC()
{
	unsigned char temp;
	
	I2CStart();
	I2CSendByte(0x90);
	I2CWaitAck();
	I2CSendByte(0x41);
	I2CWaitAck();
	
	I2CStart();
	I2CSendByte(0x91);
	I2CWaitAck();
	
	temp=I2CReceiveByte();
	I2CSendAck(1);
	I2CStop();
	
	return temp;
}

void Write_DAC(unsigned char dat)
{
	I2CStart();
	I2CSendByte(0x90);
	I2CWaitAck();
	I2CSendByte(0x43);
	I2CWaitAck();
	I2CSendByte(dat);
	I2CWaitAck();
	I2CStop();
	
	I2C_Delay(DELAY_TIME);
}

遇到的一些问题

在写模拟题2时不知道为什么遇到了很多问题hhhh,还是应该多练习才是

1.一个很简单的问题!一定要认真看题目

注意题目中当温度参数小于10或者大于40时DAC输出都有固定的值1或者5,不要忘记加上对参数的判断;光照参数同理

而且这部分要放在while(1)里实时刷新,不然就会出现模式切换了但是DAC输出的值还是上一个值的问题

void Output_Proc(void)
{
	switch(Output_Mod)
	{
		case 0:
			if(temper/16<10) volt_stat=10;
			else if(temper/16>40) volt_stat=50;
			else volt_stat=(temper-40)/12;
		break;
		
		case 1:
			if(Light_Stat<10) volt_stat=10;
			else if(Light_Stat>240) volt_stat=50;
			else volt_stat=(4*Light_Stat+190)/23;			
		break;
	}
}

2.关于参数的读取 

还是和上一篇博客出现的问题很像,切换控制界面为输出界面时,因为只在控制界面进行了对温度和光照的读取,所以改变界面后,外界的变化无法影响此时的DAC数据

解决这个问题还是需要在切换界面后也要对温度或者光照进行读取,但这里读取参数的语句放的位置出现了一点点小问题

一开始我把读取参数放在了Output_Proc()这个函数里,但特别容易出现问题就是切换界面时会卡顿!可能是因为读取数据需要一些时间,在切换界面时可能正在读取数据所以就很容易很容易卡顿

然后我再试着把读取参数放在了输出界面,这样就不会出现问题了

case 1:
    switch(Output_Mod)
	{
		case 0:temper=Read_Temperture();break;
		case 1:Light_Stat=Read_ADC();break;
	}
	sprintf(Seg_Buf,"U     %2.1f",volt_stat/10.0);
	Seg_Tran(Seg_Buf,Seg_Code);
break;

3.DAC数据的输出

为了方便起见,设置DAC数据的时候设置成了需要输出值的十倍,就是假如说我需要输出2.3V,volt_stat的值就是23,在Write_DAC()中写入数据的时候需要注意:如果采用除法去设置,即(((volt_stat/10.0)*255.0)/5.0)时候就会出现错误,输出DAC本来是2.3V,但这样操作一下就被取整了,导致输出的结果是2.0V。我试着把它乘开之后,就不会出现这样的问题了

Write_DAC((unsigned char)volt_stat*5.1);

还遇到了一个我不知道怎么解释的问题,就是我一开始把volt_stat定义成char型的,然后在sprintf中对它进行计算让它变成小数,但这样显示的数据总是0.0,改成int型之后就能正常显示了,如果大家知道为什么的话可以交流一下👉👈

  • 25
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值