蓝桥杯第十届省赛试题

题目要求

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. 测量竞赛板上电位器 RB2 输出的模拟电压信号和 NE555 模块输出的频率信号, 以数码管、 LED 等外围设备进行数据呈现。
  2. 频率测量功能需将竞赛板 J3-SIGNAL 引脚与 P34 引脚短接。( P34 与 SIGNAL的短接可以使用竞赛板上超声/红外切换等与本试题功能要求无关的跳线帽完成)。
  3. 使用 PCF8591 测量电位器 RB2 的输出电压, 并根据试题要求通过其 DAC 功能输出该电压值。
  4. 电压、 频率数据刷新时间要求
    电压数据刷新时间≤0.5 秒。
    频率数据刷新时间≤1 秒。
  5. 电压、 频率数据测量范围要求
    电压数据测量范围: 电位器 RB2 输出的最小电压值到最大电压值。
    频率数据测量范围: NE555 模块输出的最低频率到最高频率值。
    4.2显示功能
  6. 频率显示界面
    频率显示界面如图 2 所示,显示内容包括提示符 F 和频率值,频率数据单位为 Hz。
    在这里插入图片描述
    备注: 如上图所示, 频率数据显示使用 6 位数码管,当显示的数据长度不足 6 位时,未使用到的数码管位应熄灭。
  7. 电压显示界面
    电压显示界面如图 3 所示,显示内容包括提示符 U 和电位器 RB2 输出的电压值, 电压测量结果保留小数点后两位有效数字。
    在这里插入图片描述在这里插入图片描述

4.3按键功能

  1. 按键功能说明
    S4: 定义为“ 显示界面切换”按键,按下 S4 按键,切换选择频率显
    示界面和电压显示界面,按键 S4 切换模式如下图所示:
    在这里插入图片描述
    S5: 定义为 PCF8591 DAC“输出模式切换” 按键, 按下 S5, DAC 输出电压跟随电位器 RB2 输出电压 VRB2变化而变化,保持与 VRB2电压值一致;再次按下 S5, DAC 输出固定电压 2.0V,不再跟随电位器 RB2 输出电压变化。 按键 S5 工作模式如下图所示:
    在这里插入图片描述
    S6: 定义为“ LED 指示灯功能控制” 按键, 按下 S6 按键, 关闭或打开LED 指示灯指示功能。 按键 S6 工作模式如下图所示:
    在这里插入图片描述
    S7: 定义为“数码管显示功能控制” 按键,按下 S7 按键, 关闭或打
    开数码管显示功能。 按键 S7 工作模式如下图所示:
    在这里插入图片描述
    备注: 关闭数码管状态下,所有数码管熄灭。

4.4LED 指示灯功能

  1. 电压测量功能指示: L1 点亮, L2 熄灭
  2. 频率测量功能指示: L1 熄灭, L2 点亮
  3. 指示灯 L3 功能:‘
    在这里插入图片描述
  4. 指示灯 L4 功能:
    在这里插入图片描述
  5. 指示灯 L5 功能: DAC 输出固定电压( 2.0V)时, L5 熄灭, DAC 输出电压跟随 RB2 电位器输出电压变化时, L5 点亮。
  6. 本试题未涉及的 LED 指示灯应处于熄灭状态。

4.5初始状态说明

  1. 初始状态上电默认处于电压测量状态,数码管显示和 LED 指示功能启用。
  2. 初始状态上电默认 PCF8591 DAC 芯片输出固定电压值 2.0V。

程序代码

主函数

#include "stc15f2k60s2.h"
#include "iic.h"

typedef unsigned char uchar;
typedef unsigned int uint;

uchar code SMG_TAB[]={
    
    0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
uchar SMG_WEI[]={
    
    0X01,0X02,0X04,0X08,0X10,0X20,0X40,0X80};

uchar DAC_display[8];
uchar Freq_display[8];

uint DAC_val;	   //注意取值范围(超过255)
long Freq_val;     //频率值

uchar mode_display;
uchar voltage_flag;		//选择电压
uchar led_enable;		//LED功能启用
uchar SMG_enable;		//数码管启用
bit flag500ms;			//频率刷新时间
bit flag200ms;			//电压刷新时间

uchar led=0xff,LEDDAT=0XFF;  
uchar key_init();
void Timer1Init();		//1毫秒@11.0592MHz
void Timer0Init();

void DAC_display_init();		//电压
void Freq_display_init();		//频率
void LED_init();				//LED

void All_init()				//板子初始化
{
    
    
  P2=(P2&0X1F)|0XA0;
  P0=0X00;
  P2=(P2&0X1F)|0X80;
  P0=0XFF;
  P2=P2&0X1F;
}

void ledlight()
{
    
    
  P0=0XFF;
  P2=(P2&0X1F)|0X80;
  P0=led;
  P2=P2&0X1F;
}

void main()
{
    
    
  uchar key_val;

  All_init();

  Timer0Init();
  Timer1Init();
  write_dac(0x03);

  while(1)
  {
    
    
  	P2=0X80;
	
	DAC_display_init();
	Freq_display_init();
	LED_init();

	key_val=key_init();
	switch(key_val)
	{
    
    
	  case 4:					 //模式选择
	  mode_display++;
	  if(mode_display==2)
	  mode_display=0;
	  break;

	  case 5:				   //电压测量选择
	  voltage_flag++;
	  if(voltage_flag==2)	
	  voltage_flag=0;	
	  break;

	  case 6:				 //LED使能
	  led_enable++;
	  if(led_enable==2)
	  led_enable=0;
	  break;

	  case 7:
	  SMG_enable++;
	  if(SMG_enable==2)
	  SMG_enable=0;
	  break;
	}
  }
}


void DAC_display_init()
{
    
    
  if(flag200ms)
  {
    
    
   flag200ms=0;
   if(voltage_flag==0)
   {
    
    
   	 DAC_out(102.4);
     DAC_val=200;	
   }
   else
   {
    
    
    DAC_val=read_dac(0x03)/0.51f;
   }
  }
   DAC_display[0]=0x3e;	DAC_display[1]=0x00;
   DAC_display[2]=0x00;	DAC_display[3]=0x00;
   DAC_display[4]=0x00;	DAC_display[5]=SMG_TAB[DAC_val/100]|0x80;
   DAC_display[6]=SMG_TAB[DAC_val/10%10];	DAC_display[7]=SMG_TAB[DAC_val%10];
}

void Freq_display_init()
{
    
    
   if(flag500ms)
   {
    
    
	 flag500ms=0;
	 TR0 = 0;								//关闭定时器0计数
	 Freq_val = TH0 * 256 + TL0;	//统计500ms内脉冲数
	 Freq_val *= 2;								//乘以2就是1s内脉冲数,就是频率
	 TH0 = TL0 = 0;					//清除定时器0计数数据
	 TR0 = 1; 								//定时器0重新开始计数
   }
   
   Freq_display[0]=0x71;	Freq_display[1]=0x00;
   if(Freq_val>99999)
   Freq_display[2]=SMG_TAB[Freq_val/100000];
   else
   Freq_display[2]=0x00;

   if(Freq_val>9999)	
   Freq_display[3]=SMG_TAB[Freq_val/10000%10];
   else
   Freq_display[3]=0x00;
   if(Freq_val>999)
   Freq_display[4]=SMG_TAB[Freq_val/1000%10];
   else
   Freq_display[4]=0x00;
   if(Freq_val>99)
   Freq_display[5]=SMG_TAB[Freq_val/100%10];
   else
   Freq_display[5]=0x00;
   if(Freq_val>9)
   Freq_display[6]=SMG_TAB[Freq_val/10%10];	
   else
   Freq_display[6]=0x00;
   Freq_display[7]=SMG_TAB[Freq_val%10];
}

void LED_init()
{
    
    
  if(led_enable==0)			    //LED功能允许
   {
    
    

     switch(mode_display)
	 {
    
    
	   case 0:
	   
	   LEDDAT=0xfe;	   //测压 L1亮
	   
	   break;

	   case 1:
	   LEDDAT=0xfd;	  //测频 L2亮
	   break;
	 }
	
     if(mode_display==0)	 //电压测量		
     {
    
    
	  if(voltage_flag==1)		 //不是固定输出2.0V
	  {
    
    
	   LEDDAT=0XEE;	//L5亮
	   				//关闭L4
	   if(DAC_val<150)
	   {
    
    
	    LEDDAT=0XEE;			   //关闭L3
	   }

	   else if((DAC_val>=150)&&(DAC_val<250))
	   {
    
    
	    LEDDAT=0XEA;			 //打开L3
	   }

	   else if((DAC_val>=250)&&(DAC_val<350))
	   {
    
    
	    LEDDAT=0XEE;				   //关闭L3
	   }

	   else
	   {
    
    
	    LEDDAT=0XEA;			 //打开L3
	   }
	  }
	  
	  else						 //是固定输出2.0V
	  {
    
    
	    LEDDAT=0XFE;				//关闭L5
	  } 	   	   
    }
	 
	if(mode_display==1)		   //频率测量
    {
    
    
       if(Freq_val<1000)
	   LEDDAT=0xfd;

	   else if((Freq_val>=1000)&&(Freq_val<5000))
	   LEDDAT=0xf5;

	   else if((Freq_val>=5000)&&(Freq_val<10000))
	   LEDDAT=0xfd;

	   else
	   LEDDAT=0xf5;
    }
  }

  else
  LEDDAT=0xff;					//led功能禁止

  led=LEDDAT;
  
}

void Timer1Init()		//1毫秒@11.0592MHz
{
    
    
	AUXR |= 0x40;		//定时器时钟1T模式
	TMOD &= 0x0F;		//设置定时器模式
	TL1 = 0xCD;		//设置定时初值
	TH1 = 0xD4;		//设置定时初值
	TF1 = 0;		//清除TF1标志
	TR1 = 1;		//定时器1开始计时
	EA=1;
	ET1=1;
}


void Timer0Init()
{
    
    
	AUXR &= 0x7F;					//定时器时钟1T模式
    TMOD = 0x04;          //设置定时器0为16位自动重装载外部记数模式
    TH0 = TL0 = 0;     		//设置定时器0初始值
	TR0 = 1;              //定时器0开始工作
	EA=1;
	ET0=1;
}

void timer1() interrupt 3
{
    
    
  uchar i;
  uchar SMG_count;
  uint fre_count,vol_count;
  SMG_count++;
  fre_count++;
  vol_count++;

  if(fre_count==500)		  //频率刷新时间0.5s
  {
    
    
    fre_count=0;
	flag500ms=1;
  }

  if(vol_count==200)		//电压刷新时间0.2s
  {
    
    
    vol_count=0;
	flag200ms=1;
  }

  if(SMG_count==3)
  {
    
    
    SMG_count=0;
	if(SMG_enable==0)
	{
    
    
		P2=(P2&0X1F)|0XC0; P0=0X00;
		P2=(P2&0X1F)|0XC0; P0=SMG_WEI[i];
		P2=P2&0X1F;

		if(mode_display==0)			//电压测量
		{
    
    
		 P2=(P2&0X1F)|0XE0; 
		 P0=~DAC_display[i];
		 P2=P2&0X1F;
		}
	
		if(mode_display==1)		  //频率测量
		{
    
    
		 P2=(P2&0X1F)|0XE0; 
		 P0=~Freq_display[i];
		 P2=P2&0X1F;
		}

	
	}
	else
    {
    
    
     P2=(P2&0X1F)|0XC0; P0=0X00;
	 P2=(P2&0X1F)|0XC0; P0=SMG_WEI[i];	 
	 P2=(P2&0X1F)|0XE0; P0=0XFF;
	 P2=P2&0X1F;
    }
    i++;
	if(i==8)
	i=0;
  }
  
  ledlight();  
}

按键模块

#define key_state0 0
#define key_state1 1
#define key_state2 2

uchar key_init()
{
    
    
  static uchar key_state=0;
  uchar key_press,key_return=0;
  key_press=P3&0X0F;

  switch(key_state)
  {
    
    
	case key_state0:
	if(key_press!=0x0f)
	key_state=key_state1;
	break;

	case key_state1:
	if(key_press!=0x0f)
	{
    
    
	  if(key_press==0x0e)  key_return=7;
	  if(key_press==0x0d)  key_return=6;
	  if(key_press==0x0b)  key_return=5;
	  if(key_press==0x07)  key_return=4;
	  key_state=key_state2;
	}
	else
	key_state=key_state0;
	break;

	case key_state2:
	if(key_press==0x0f)
	key_state=key_state0;
	break;
  }
  return key_return;
}

PCF8591模块

/*
  程序说明: IIC总线驱动程序
  软件环境: Keil uVision 4.10 
  硬件环境: CT107单片机综合实训平台(12MHz)
  日    期: 2011-8-9
*/

#include "iic.h"

void iic_delay(unsigned char ms)
{
    
    
  do
  {
    
    
	_nop_();
  }while(ms--);
}
//总线启动条件
void IIC_Start(void)
{
    
    
	SDA = 1;
	SCL = 1;
	iic_delay(5);
	SDA = 0;
	iic_delay(5);
	SCL = 0;	
}

//总线停止条件
void IIC_Stop(void)
{
    
    
	SDA = 0;
	SCL = 1;
	iic_delay(5);
	SDA = 1;
}
/*IIC总线协议规定,每传送一个字节数据后,都要有一个应答信号,以确定数据传送是否被对方收到,
应答信号由接收设备产生,在SCL为高电平期间,接收设备将SDA拉为低电平表示数据传输正确,即产生了应答。*/
//应答位控制

void IIC_Ack(unsigned char ackbit)	 //当ackbit为1时,表示单片机对从设备发送来数据的应答
                          //当ackbit为0时,表示主机接收了最后一个字节,因此不再应答,结束通信
{
    
    
	if(ackbit) 
	{
    
    	
		SDA = 0;
	}
	else 
	{
    
    
		SDA = 1;
	}
	iic_delay(5);
	SCL = 1;
	iic_delay(5);
	SCL = 0;
	SDA = 1; 
	iic_delay(5);
}

//等待应答
bit IIC_WaitAck(void)
{
    
    
	SDA = 1;
	iic_delay(5);
	SCL = 1;
	iic_delay(5);
	if(SDA)    //在SCL为高电平期间,因为接收设备未将SDA拉低,所以默认未接收到应答,结束IIC通信
	{
    
       
		SCL = 0;
		IIC_Stop();
		return 0;
	}
	else  		//接收到应答,返回1,继续下一个数据字节的传输
	{
    
     
		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;
		}
		iic_delay(5);
		SCL = 1;
		byt <<= 1;
		iic_delay(5);
		SCL = 0;
	}
}

//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
    
    
	unsigned char da;
	unsigned char i;
	
	for(i=0;i<8;i++)
	{
    
       
		SCL = 1;
		iic_delay(5);
		da <<= 1;
		if(SDA) 
		da |= 0x01;
		SCL = 0;
		iic_delay(5);
	}
	return da;
}

void write_dac(unsigned char dat)
{
    
    
  IIC_Start();
  IIC_SendByte(0x90);
  IIC_WaitAck();
  IIC_SendByte(dat);
  IIC_WaitAck();
  IIC_Stop();
}

unsigned char read_dac(unsigned char dat)
{
    
    
  unsigned char temp;
  IIC_Start();
  IIC_SendByte(0x90);
  IIC_WaitAck();
  IIC_SendByte(dat);
  IIC_WaitAck();

  IIC_Start();
  IIC_SendByte(0x91);
  IIC_WaitAck();
  temp=IIC_RecByte();
  IIC_Ack(0);
  IIC_Stop();
  return temp;
}

void DAC_out(unsigned char dat)		//  D/A转换
{
    
    
  IIC_Start();
  IIC_SendByte(0x90);
  IIC_WaitAck();
  IIC_SendByte(0x40);
  IIC_WaitAck(); 

  IIC_SendByte(dat);
  IIC_WaitAck();
  IIC_Stop();
}

以上就是代码全部内容,欢迎交流,共同学习~
(喜欢就留个赞和关注再走吧~)

猜你喜欢

转载自blog.csdn.net/qq_43280087/article/details/106032198