蓝桥杯单片机第十五届模拟题二

本文详细描述了一项单片机竞赛中的编程任务,要求参赛者使用特定硬件配置,通过DS18B20传感器和PCF8591芯片实现温度和光照度测量,以及通过LED和数码管显示控制模式。代码示例展示了如何读取传感器数据、处理按键输入和数码管显示。
摘要由CSDN通过智能技术生成

1、题目

一、基本要求


使用大赛组委会提供的四梯/国信长天单片机竞赛实训平台,完成本试题的程序设计与调试。程序编写、调试完成后,选手需通过考试系统提交以准考证号命名的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 初始状态


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

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


2、代码

2.1 main.c

main.c
#include <STC15F2K60S2.H>
#include <onewire.h>
#include <intrins.h>
#include <iic.h>
#include <Init.h>
#include <Key.h>
#include <Seg.h>
#include <Led.h>

/*****************变量定义区********************/
/*按键专用*/
unsigned char Key_Slow_Down;//10ms
unsigned char Key_Down,Key_Up,Key_Val,Key_Old;
/*数码管专用*/
unsigned int Seg_Slow_Down;//500ms
unsigned char Seg_Pos;
unsigned char Seg_Buf[8]={10,10,10,10,10,10,10,10};
unsigned char Seg_Point[8]={0,0,0,0,0,0,0,0};
/*Led专用*/
unsigned char ucLed[8]={0,0,0,0,0,0,0,0};


unsigned char Seg_Disp_Mode;//界面切换 0-模式界面;1-输出界面
/*模式界面*/
unsigned char Seg_Mode;//模式切换 0-模式1;1-模式2
unsigned int temperature_10x;
unsigned char Value;//实时获取光照系数(0-255)
/*输出界面*/
unsigned char Voltage_10x;

/*****************函数处理区********************/
//按键处理函数
void Key_Proc()
{
	if(Key_Slow_Down) return;
	Key_Slow_Down=1;
	
	Key_Val=Key_Read();
	Key_Down=Key_Val&(Key_Old^Key_Val);
	Key_Up=~Key_Val&(Key_Old^Key_Val);
	Key_Old=Key_Val;
	
	switch(Key_Down)
	{
		case 4:
			if(Seg_Disp_Mode==0)
				Seg_Mode=!Seg_Mode;
		break;
			
		case 5:
			Seg_Disp_Mode=!Seg_Disp_Mode;
		break;
	}
}

//清除数码管数据
void Clear_Seg(void)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		Seg_Buf[i]=10;//熄灭
		Seg_Point[i]=0;//熄灭
	}
}

void Read_Voltage()
{
	if(Seg_Mode==0)
	{
		if(temperature_10x/10>=0&&temperature_10x/10<10)
			Voltage_10x=10;
		else if(temperature_10x/10>40)
			Voltage_10x=50;
		else if(temperature_10x/10>=10&&temperature_10x/10<=40)
			Voltage_10x=(2*temperature_10x/10 - 5)*10/15;
	}
	else
	{
		if(Value>=0&&Value<10)
			Voltage_10x=10;
		else if(Value>240)
			Voltage_10x=50;
		else
			Voltage_10x=(2*Value+95)*10/115;
	}
}

//数码管处理函数
void Seg_Proc()
{
	float temperature;//实时获取温度
	if(Seg_Slow_Down) return;
	Seg_Slow_Down=1;
	
	/*********实时读取数据*********/
	 temperature=Read_Temperature();
	 temperature_10x=temperature*10;
	 //如果是电压:Value/51.0;
	 Value=AD_Read(0x41);//光敏电阻
	 
	 //读取电压值
	 Read_Voltage();
	switch(Seg_Disp_Mode)
	{
		//模式界面
		case 0:
			switch(Seg_Mode)
			{

				//模式1:温度控制界面
				case 0:
					Clear_Seg();
					Seg_Buf[0]=Seg_Mode+1;
					Seg_Buf[5]=temperature_10x/100%10;
					Seg_Buf[6]=temperature_10x/10%10;
					Seg_Buf[7]=temperature_10x%10;	
					Seg_Point[6]=1;
				break;
				
				//模式2:光照控制界面
				case 1:
					Clear_Seg();
					Seg_Buf[0]=Seg_Mode+1;
				    Seg_Buf[5]=Value/100%10>0?Value/100%10:10;
					Seg_Buf[6]=((Value/10%10==0)&(Value/100%10==0))?10:Value/10%10;
					Seg_Buf[7]=Value%10;
				break;
			}
		break;
			
		//输出界面
		case 1:
			Clear_Seg();
			DA_Write(Voltage_10x*5.1);
			Seg_Buf[0]=11;//U
			Seg_Buf[6]=Voltage_10x/10;
			Seg_Buf[7]=Voltage_10x%10;
			Seg_Point[6]=1;
		break;
					
	}
}

//Led处理函数
void Led_Proc()
{
	ucLed[0]=!Seg_Mode;
	ucLed[1]=Seg_Mode;
	
}

//初始化定时器0
void Timer0Init(void)		//1毫秒@12.000MHz
{
	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x18;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	
	ET0=1;
	EA=1;
}

void Timer0Sever()interrupt 1
{
	if(++Key_Slow_Down==10) Key_Slow_Down=0;
	if(++Seg_Slow_Down==500) Seg_Slow_Down=0;
	if(++Seg_Pos==8) Seg_Pos=0;
	
	Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos],Seg_Point[Seg_Pos]);
	Led_Disp(Seg_Pos,ucLed[Seg_Pos]);
}

void Delay750ms()		//@12.000MHz
{
	unsigned char i, j, k;

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

//main()函数
void main()
{
	Read_Temperature();
	Delay750ms();
	Timer0Init();
	System_Init();
	while(1)
	{
		Key_Proc();
		Seg_Proc();
		Led_Proc();
	}
}

2.2 模块代码 

iic.c
/*	#   I2C代码片段说明
	1. 	本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
	2. 	参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
		中对单片机时钟频率的要求,进行代码调试和修改。
*/

#include <iic.h>
#include <intrins.h>
#define DELAY_TIME	5

sbit sda=P2^1;
sbit scl=P2^0;

//
static void I2C_Delay(unsigned char n)
{
    do
    {
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();		
    }
    while(n--);      	
}

//
void I2CStart(void)
{
    sda = 1;
    scl = 1;
	I2C_Delay(DELAY_TIME);
    sda = 0;
	I2C_Delay(DELAY_TIME);
    scl = 0;    
}

//
void I2CStop(void)
{
    sda = 0;
    scl = 1;
	I2C_Delay(DELAY_TIME);
    sda = 1;
	I2C_Delay(DELAY_TIME);
}

//
void I2CSendByte(unsigned char byt)
{
    unsigned char i;
	
    for(i=0; i<8; i++){
        scl = 0;
		I2C_Delay(DELAY_TIME);
        if(byt & 0x80){
            sda = 1;
        }
        else{
            sda = 0;
        }
		I2C_Delay(DELAY_TIME);
        scl = 1;
        byt <<= 1;
		I2C_Delay(DELAY_TIME);
    }
	
    scl = 0;  
}

//
unsigned char I2CReceiveByte(void)
{
	unsigned char da;
	unsigned char i;
	for(i=0;i<8;i++){   
		scl = 1;
		I2C_Delay(DELAY_TIME);
		da <<= 1;
		if(sda) 
			da |= 0x01;
		scl = 0;
		I2C_Delay(DELAY_TIME);
	}
	return da;    
}

//
unsigned char I2CWaitAck(void)
{
	unsigned char ackbit;
	
    scl = 1;
	I2C_Delay(DELAY_TIME);
    ackbit = sda; 
    scl = 0;
	I2C_Delay(DELAY_TIME);
	
	return ackbit;
}

//
void I2CSendAck(unsigned char ackbit)
{
    scl = 0;
    sda = ackbit; 
	I2C_Delay(DELAY_TIME);
    scl = 1;
	I2C_Delay(DELAY_TIME);
    scl = 0; 
	sda = 1;
	I2C_Delay(DELAY_TIME);
}

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

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

onewire.c
/*	# 	单总线代码片段说明
	1. 	本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
	2. 	参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
		中对单片机时钟频率的要求,进行代码调试和修改。
*/

#include <onewire.h>
sbit DQ=P1^4;

//
void Delay_OneWire(unsigned int t)  
{
	unsigned char i;
	while(t--){
		for(i=0;i<12;i++);
	}
}

//
void Write_DS18B20(unsigned char dat)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		DQ = 0;
		DQ = dat&0x01;
		Delay_OneWire(5);
		DQ = 1;
		dat >>= 1;
	}
	Delay_OneWire(5);
}

//
unsigned char Read_DS18B20(void)
{
	unsigned char i;
	unsigned char dat;
  
	for(i=0;i<8;i++)
	{
		DQ = 0;
		dat >>= 1;
		DQ = 1;
		if(DQ)
		{
			dat |= 0x80;
		}	    
		Delay_OneWire(5);
	}
	return dat;
}

//
bit init_ds18b20(void)
{
  	bit initflag = 0;
  	
  	DQ = 1;
  	Delay_OneWire(12);
  	DQ = 0;
  	Delay_OneWire(80);
  	DQ = 1;
  	Delay_OneWire(10); 
    initflag = DQ;     
  	Delay_OneWire(5);
  
  	return initflag;
}

float Read_Temperature()
{
	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)/16.0;
	
}

3、后话

代码可能有BUG,欢迎大家一起交流

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值