第十一屆 藍橋杯 微控制器設計與開發專案 省賽 程式設計試題及原始碼

2020-10-20 14:00:32

一、試題

1、 基本要求

1.1 使用大賽組委會提供的國信長天微控制器競賽實訓平臺,完成本試題的程式設計
與偵錯。
1.2 選手在程式設計與偵錯過程中,可參考組委會提供的「資源封包」。
1.3 請注意: 程式編寫、偵錯完成後選手應通過考試系統提交完整、可編譯的 Keil
工程檔案。選手提交的工程檔案應是最終版本, 要求 Keil 工程檔案以准考證
號(8 位數位)命名, 工程資料夾內應包含以准考證號命名的 hex 檔案,該 hex
檔案是成績評審的依據。 不符合以上檔案提交要求的作品將被評為零分或者被
酌情扣分。
1.4 請勿上傳與作品工程檔案無關的其它檔案。

2、 競賽板設定要求

2.1將 IAP15F2K61S2 微控制器內部振盪器頻率設定為 12MHz。
2.2鍵盤工作模式跳線 J5 設定為 BTN 按鍵模式。
2.3擴充套件方式跳線 J13 設定為 IO 模式。
2.4請注意: 選手需嚴格按照以上要求設定競賽板,編寫和偵錯程式, 不符合以上
設定要求的作品將被評為零分或者被酌情扣分。

3、 硬體框圖

在這裡插入圖片描述

圖 1 系統硬體框圖

4、 功能描述

4.1基本功能

  1. 通過 DS18B20 完成溫度資料測量。
  2. 通過數碼管實現資料和引數介面的顯示。
  3. 通過按鍵實現介面切換、引數設定等功能。
  4. 通過 LED 指示燈實現狀態指示與報警輸出功能。
  5. 通過 PCF8591 完成 DAC 模擬電壓輸出功能。
    4.2設計要求
  6. 溫度資料重新整理時間:≤0.5 秒
  7. 顯示介面切換時間:≤0.3 秒
  8. DAC 模擬電壓輸出響應時間:≤0.3 秒
  9. 溫度引數可調整範圍:
     溫度上限引數 0 ≤ TMAX < 100
     溫度下限引數 0 ≤ TMIN < 100
    4.3顯示功能
  10. 資料介面
    資料介面如圖 2 所示,顯示內容包括提示符 C 和通過 DS18B20 溫度感測器
    採集到的溫度資料,溫度資料取整數。
    在這裡插入圖片描述

圖 2 資料顯示介面
2) 引數介面如圖 3 所示,顯示內容包括提示符 P、溫度上限引數 TMAX和溫度下
限引數 TMIN。
在這裡插入圖片描述

圖 3 引數設定介面
4.4按鍵功能

  1. 按鍵功能說明
     S4: 定義為「介面切換」按鍵,按下 S4 按鍵,切換選擇資料顯示界
    面和引數設定介面。3 / 3
     S5:定義為「引數切換」 按鍵,按下 S5 按鍵,切換選擇溫度上限參
    數 TMAX和溫度下限引數 TMIN。
     S6:定義為「加」 按鍵, 按下 S6 按鍵,當前選擇的溫度引數增加 1℃。
     S7:定義為「減」按鍵,按下 S7 按鍵,當前選擇的溫度引數減少 1℃。
  2. 按鍵功能設計要求
     按鍵 S6 和按鍵 S7 的加、 減功能僅在引數設定介面有效。
     合理設定引數邊界範圍, 防止出現引數越界和邏輯錯誤。
     每次從資料介面切換到引數介面,預設當前選擇的引數是溫度下限參
    數 TMIN。
     通過 S4 按鍵,從引數設定介面退出,進入資料顯示介面時,需要進行
    必要的引數合理性檢查( TMAX≥TMIN);若設定的引數合理,引數生效,
    進入資料介面;反之, 自動恢復進入引數設定介面前的有效引數, 進
    入資料介面。
    4.5DAC 輸出功能
  3. 當前溫度 T > TMAX時,控制 DAC 輸出 4.0V。
  4. 當前溫度 TMIN ≤ T ≤ TMAX時,控制 DAC 輸出 3.0V。
  5. 當前溫度 T < TMIN時,控制 DAC 輸出 2.0V。
    4.6LED 指示燈功能
  6. 當前溫度滿足 T > TMAX,指示燈 L1 點亮,否則熄滅。
  7. 當前溫度滿足 TMIN ≤ T ≤ TMAX,指示燈 L2 點亮,否則熄滅。
  8. 當前溫度滿足 T < TMIN,指示燈 L3 點亮,否則熄滅。
  9. 如出現錯誤的引數設定操作,指示燈 L4 點亮,直至下一次正確的引數設
    置後,指示燈熄滅。
    4.7初始狀態說明
  10. 初始狀態上電預設處於資料顯示介面。
  11. 預設引數
     溫度上限引數 TMAX = 30℃
     溫度下限引數 TMIN = 20℃

二、原始碼(有瑕疵)

1、main.c

#include<STC15F2K60S2.H>
#include"onewire.h"
#include"iic.h"

#define uchar unsigned char
#define uint unsigned int
	
void delayms(uint ms);
void Select573(char channel);	
void allinit();
void display1();
void display2();
void display3();
void display4();
void keyscan();
void work_key();
void work_led();
void work_dac();

uchar code tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xFF,0xc6,0x8c};
uchar code dot[]={0x40,0x79,0x24,0x30,0x19,0x12,0x20,0x78,0x00,0x10};//&0x7f
uchar yi,er,san,si,wu,liu,qi,ba;

int temper;
bit mode=0;
bit choose=1;
char tmax;
char tmin;
char tomax;
char tomin;

void main()
{
	allinit();
	temper=temperature_rd_F();
	tmax=30;
	tmin=20;
	while(1)
	{
		work_key();
		work_led();
		work_dac();
		display1();
		display2();
		display3();
		display4();
		keyscan();
	}
}

void work_key()
{
	if(mode==0)
	{
		yi=12;
		er=11;san=11;si=11;wu=11;liu=11;
		qi=temper/10;ba=temper%10;
	}
	else
	{
		yi=13;
		er=11;san=11;
		si=tmax/10;wu=tmax%10;
		liu=11;
		qi=tmin/10;ba=tmin%10;
	}
}

void work_led()
{
	Select573(4);
	if(tmax<tmin)
	{
		P03=0;
		P00=1;P01=1;P02=1;
	}
	else P03=1;
	if(tmax>=tmin)
	{
		if(temper>tmax)P00=0;
		else P00=1;
		if(temper<tmin)P02=0;
		else P02=1;
		if(temper<tmax&&temper>tmin)P01=0;
		else P01=1;
	}
	Select573(0);
}

void work_dac()
{
	if(temper>tmax)
		AD_write(0x40,204);
	if(temper<tmin)
		AD_write(0x40,102);
	if(temper<tmax&&temper>tmin)
		AD_write(0x40,153);
	if(tmax<tmin)
		AD_write(0x40,0);
}

void delayms(uint ms)
{
	uint i,j;
	for(i=ms;i>0;i--)
		for(j=845;j>0;j--);
}

void Select573(char channel)
{
	switch(channel)
	{
		case 4:
			P2=(P2&0x1f)|0x80;
		break;
		case 5:
			P2=(P2&0x1f)|0xa0;
		break;
		case 6:
			P2=(P2&0x1f)|0xc0;
		break;
		case 7:
			P2=(P2&0x1f)|0xe0;
		break;
		case 0:
			P2=(P2&0x1f)|0x00;
		break;
	}
}

void allinit()
{
	Select573(4);
	P0=0xff;
	Select573(5);
	P0=0x00;
	Select573(6);
	P0=0xff;
	Select573(7);
	P0=0xff;
	Select573(0);
}

void display1()
{
	Select573(6);
	P0=0x01;
	Select573(7);
	P0=tab[yi];
	delayms(1);
	
	Select573(6);
	P0=0x02;
	Select573(7);
	P0=tab[er];
	delayms(1);
}

void display2()
{
	Select573(6);
	P0=0x04;
	Select573(7);
	P0=tab[san];
	delayms(1);
	
	Select573(6);
	P0=0x08;
	Select573(7);
	P0=tab[si];
	delayms(1);
}

void display3()
{
	Select573(6);
	P0=0x10;
	Select573(7);
	P0=tab[wu];
	delayms(1);
	
	Select573(6);
	P0=0x20;
	Select573(7);
	P0=tab[liu];
	delayms(1);
}

void display4()
{
	Select573(6);
	P0=0x40;
	Select573(7);
	P0=tab[qi];
	delayms(1);
	
	Select573(6);
	P0=0x80;
	Select573(7);
	P0=tab[ba];
	delayms(1);
	
	Select573(6);
	P0=0xff;
	Select573(7);
	P0=0xff;
}

void keyscan()
{
	if(P33==0)
	{//S4
		delayms(5);
		if(P33==0)
		{
			if(mode==0)
			{
				mode=1;
				tomax=tmax;
				tomin=tmin;
			}
			else if(mode==1)
			{
				mode=0;
				if(tmax<tmin)
				{
					tmax=tomax;
					tmin=tomin;
				}
			}
		}
		while(!P33);
	}
		
	if(P32==0)
	{//S5
		delayms(5);
		if(P32==0)
		{
			if(mode==1)
			{
				if(choose==0)choose=1;
				else if(choose==1)choose=0;	
			}
		}
		while(!P32);
	}
		
	if(P31==0)
	{//S6
		delayms(5);
		if(P31==0)
		{
			if(mode==1)
			{
				if(choose==0)
				{
					if(tmax<99)tmax++;
				}
				else if(choose==1)
				{
					if(tmin<99)tmin++;
				}
			}

		}
		while(!P31);
	}
	
	if(P30==0)
	{//S7
		delayms(5);
		if(P30==0)
		{
			if(mode==1)
			{
				if(choose==0)
				{
					if(tmax>0)tmax--;
					
				}
				else if(choose==1)
				{
					if(tmin>0)tmin--;
				}
		}
		while(!P30);
	  }
	}
}

2、icc.c

/*
  程式說明: IIC匯流排驅動程式
  軟體環境: Keil uVision 4.10 
  硬體環境: CT107微控制器綜合實訓平臺 8051,12MHz
  日    期: 2011-8-9
*/

#include "reg52.h"
#include "intrins.h"

#define somenop {_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();}    


#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1

//匯流排引腳定義
sbit SDA = P2^1;  /* 傳輸線 */
sbit SCL = P2^0;  /* 時鐘線 */


//匯流排啟動條件
void IIC_Start(void)
{
	SDA = 1;
	SCL = 1;
	somenop;
	SDA = 0;
	somenop;
	SCL = 0;	
}

//匯流排停止條件
void IIC_Stop(void)
{
	SDA = 0;
	SCL = 1;
	somenop;
	SDA = 1;
}

//應答位控制
void IIC_Ack(bit ackbit)
{
	if(ackbit) 
	{	
		SDA = 0;
	}
	else 
	{
		SDA = 1;
	}
	somenop;
	SCL = 1;
	somenop;
	SCL = 0;
	SDA = 1; 
	somenop;
}

//等待應答
bit IIC_WaitAck(void)
{
	SDA = 1;
	somenop;
	SCL = 1;
	somenop;
	if(SDA)    
	{   
		SCL = 0;
		IIC_Stop();
		return 0;
	}
	else  
	{ 
		SCL = 0;
		return 1;
	}
}

//通過I2C匯流排傳送資料
void IIC_SendByte(unsigned char byt)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{   
		if(byt&0x80) 
		{	
			SDA = 1;
		}
		else 
		{
			SDA = 0;
		}
		somenop;
		SCL = 1;
		byt <<= 1;
		somenop;
		SCL = 0;
	}
}

//從I2C匯流排上接收資料
unsigned char IIC_RecByte(void)
{
	unsigned char da;
	unsigned char i;
	
	for(i=0;i<8;i++)
	{   
		SCL = 1;
		somenop;
		da <<= 1;
		if(SDA) 
		da |= 0x01;
		SCL = 0;
		somenop;
	}
	return da;
}

unsigned char AD_get(unsigned char add)
{
	unsigned char temp;
	IIC_Start();
	IIC_SendByte(0x90);
	IIC_WaitAck();
	IIC_SendByte(add);
	IIC_WaitAck();	
	IIC_Stop();
	
	IIC_Start();
	IIC_SendByte(0x91);
	IIC_WaitAck();
	temp=IIC_RecByte();
	IIC_Stop();
	return temp;
}

void AD_write(unsigned char add,unsigned char dat)
{
	IIC_Start();
	IIC_SendByte(0x90);
	IIC_WaitAck();
	IIC_SendByte(add);
	IIC_WaitAck();
	IIC_SendByte(dat);
	IIC_WaitAck();
	IIC_Stop();
}


unsigned char EEPROM_get(unsigned char add)
{
	unsigned char temp;
	IIC_Start();
	IIC_SendByte(0xa0);
	IIC_WaitAck();
	IIC_SendByte(add);
	IIC_WaitAck();	
	IIC_Stop();
	
	IIC_Start();
	IIC_SendByte(0xa1);
	IIC_WaitAck();
	temp=IIC_RecByte();
	IIC_Stop();
	return temp;
}

void EEPROM_write(unsigned char add,unsigned char dat)
{
	IIC_Start();
	IIC_SendByte(0xa0);
	IIC_WaitAck();
	IIC_SendByte(add);
	IIC_WaitAck();
	IIC_WaitAck();
	IIC_SendByte(dat);
	IIC_Stop();
}

3、onewire.c

/*
  程式說明: 單匯流排驅動程式
  軟體環境: Keil uVision 4.10 
  硬體環境: CT107微控制器綜合實訓平臺(外部晶振12MHz) STC89C52RC微控制器
  日    期: 2011-8-9
*/
#include "reg52.h"

sbit DQ = P1^4;  //單匯流排介面

//單匯流排延時函數
void Delay_OneWire(unsigned int t)  //STC89C52RC
{
	char i;
	while(t--)
	{
		for(i=12;i>0;i--);
	}
}

//通過單匯流排向DS18B20寫一個位元組
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);
}

//從DS18B20讀取一個位元組
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;
}

//DS18B20裝置初始化
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;
}

unsigned char temperature_rd(void)
{
	unsigned char low,high;
	unsigned char temp;
	init_ds18b20();
	Write_DS18B20(0XCC);
	Write_DS18B20(0X44);
	Delay_OneWire(200);
	
	init_ds18b20();
	Write_DS18B20(0XCC);
	Write_DS18B20(0XBE);
	low=Read_DS18B20();
	high=Read_DS18B20();
	temp=high<<4;
	temp|=low>>4;
	return temp;
}

float temperature_rd_F(void)
{
	unsigned char low,high;
	unsigned int temp;
	float temperature;
	init_ds18b20();
	Write_DS18B20(0XCC);
	Write_DS18B20(0X44);
	Delay_OneWire(200);
	
	init_ds18b20();
	Write_DS18B20(0XCC);
	Write_DS18B20(0XBE);
	low=Read_DS18B20();
	high=Read_DS18B20();
	temp=high&0x0f;
	temp<<=8;
	temp|=low;
	temperature=temp*0.0625;
	return temperature;
}