第十届蓝桥杯省赛单片机程序

一、比赛总结
趁着清明放假,对前一阶段比赛做做总结。这次蓝桥杯比赛还是相当可以的,没有取得好成绩也是在意料之中。虽说不是很难,但如果之前没有充分的准备是不可能完完整整做出来的。尤其考了555定时器,虽说是很简单的应用,让P3.4输出正弦波,测它的频率,蓝桥杯单片机CT107D 555方波发生器可以产生实验所需的 200Hz 到 20Khz 的方波信号。通过改变Rb3大小即可调整555方波发生器输出方波频率,定时器0设为计数模式,但当时比赛就是做不出来,赛前我还看了那个官方的模拟题,就是简单的瞥了一眼,个人感觉不可能考吧。看到题的一瞬间,崩了,竟让出了。前一天晚上,我疯狂准备的DS1302实时时钟、DS18B20、EEPROM 都没用到,就用到了一个AD。总的来说,比赛重在参与,积累经验,不断提升自己的实力,当自己实力达到一定水平,奖这东西还不是信手拈来。不得补充一句这个比赛客观题也很重要,基本那个二十多分,再加上程序稍微做出来一点,省三不成问题。
二、程序设计分析
从整体来看不算很难,用到模块也不是很多
1.读取Rb2上的电压,利用竞赛提供的IIC底层驱动代码,设计程序,实现对电压的采集。
[注意]:PCF8591是具有IIC接口的8位A/D和D/A转换芯片,具有4路模拟输入、一路DAC输出和一个IIC总线接口。所以我们读取AIN3通道,得到数据应该是(0~255),为使显示到数码管上的数据为电压数据,要对读取的数据做一下处理,请看具体程序
“IIC,H”

#ifndef _IIC_H
#define _IIC_H

void IIC_Start(void); 
void IIC_Stop(void);  
bit IIC_WaitAck(void);  
void IIC_SendAck(bit ackbit); 
void IIC_SendByte(unsigned char byt); 
unsigned char IIC_RecByte(void); 
unsigned char IIC_Read(unsigned char add);
#endif

“IIC.C”

/*
 程序说明: IIC总线驱动程序
 软件环境: Keil uVision 4.10 
 硬件环境: CT107单片机综合实训平台 8051,12MHz
 日    期: 2011-8-9
*/
#include "stc15f2k60s2.h"
#include "intrins.h"
#define DELAY_TIME 5
#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1

//总线引脚定义
sbit SDA = P2^1;  /* 数据线 */
sbit SCL = P2^0;  /* 时钟线 */

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

//总线停止条件
void IIC_Stop(void)
{
   SDA = 0;
   SCL = 1;
   IIC_Delay(DELAY_TIME);
   SDA = 1;
   IIC_Delay(DELAY_TIME);
}

//发送应答
void IIC_SendAck(bit ackbit)
{
   SCL = 0;
   SDA = ackbit;  					// 0:应答,1:非应答
   IIC_Delay(DELAY_TIME);
   SCL = 1;
   IIC_Delay(DELAY_TIME);
   SCL = 0; 
   SDA = 1;
   IIC_Delay(DELAY_TIME);
}

//等待应答
bit IIC_WaitAck(void)
{
   bit ackbit;
   
   SCL  = 1;
   IIC_Delay(DELAY_TIME);
   ackbit = SDA;
   SCL = 0;
   IIC_Delay(DELAY_TIME);
   return ackbit;
}
//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
   unsigned char i;

   for(i=0; i<8; i++)
   {
       SCL  = 0;
       IIC_Delay(DELAY_TIME);
       if(byt & 0x80) SDA  = 1;
       else SDA  = 0;
       IIC_Delay(DELAY_TIME);
       SCL = 1;
       byt <<= 1;
       IIC_Delay(DELAY_TIME);
   }
   SCL  = 0;  
}

//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
   unsigned char i, da;
   for(i=0; i<8; i++)
   {   
   	SCL = 1;
   IIC_Delay(DELAY_TIME);
   da <<= 1;
   if(SDA) da |= 1;
   SCL = 0;
   IIC_Delay(DELAY_TIME);
   }
   return da;    
}
unsigned char IIC_Read(unsigned char add)
{
  unsigned char date;
   IIC_Start();
   IIC_SendByte(0x90);
   IIC_WaitAck();
   IIC_SendByte(add);
   IIC_WaitAck();

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

2.555定时器相关函数
计数器T0和定时器T1中断来实现
这里我们设置C/T(计数定时器)0为计数器模式,C/T 1为定时器模式,因为C/T 0计数器模式的触发IO口(P3.4)就与SIGNAL相邻,因此用一个跳线帽连接即可。

/****************************定时器函数*****************/
void Timer0Init(void)		//@11.0592MHz
{
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD = 0x05;		
	TL0 = 0x00;		//设置定时初值
	TH0 = 0x00;		//设置定时初值
	TF0 = 0;		//清除TF0标志 
	TR0 = 1;		//定时器0开始计时  
}
void Timer1Init(void)		//5毫秒@11.0592MHz
{
	AUXR |= 0x40;		//定时器时钟1T模式
	TMOD &= 0x0F;		//设置定时器模式
	TL1 = 0x00;		//设置定时初值
	TH1 = 0x28;		//设置定时初值
	TF1 = 0;		//清除TF1标志
	TR1 = 1;		//定时器1开始计时
	EA=1;
	ET1=1;
}
void  Service_time1() interrupt 3
{
    static  unsigned int counter=0;
	  counter++;
	if(counter==200)
	{	 counter =0;
		Fout=(TH0<<8)+TL0;
	   TL0=0x00;
	   TH0=0x00;
	   TF0=0;
	   TR0=1;
	}
}

3.数码管显示界面
在这里插入图片描述

/****************************周期显示****************/
void Display_F()
{
	DisplaySmg(0,smgDuan[11]);
	Delay1ms();	
	DisplaySmg(1,smgDuan[12]);
	Delay1ms();	
    DisplaySmg(2,smgDuan[12]);
	Delay1ms();
	if(Fout<=9999)							//  对第四位数码管进行判断,是否显示
	{
	 DisplaySmg(3,smgDuan[12]);
	  Delay1ms();
	}
	else
	{	
    DisplaySmg(3,smgDuan[Fout/10000]);
	Delay1ms();
	}
	DisplaySmg(4,smgDuan[(Fout%10000)/1000]);
	Delay1ms();	
    DisplaySmg(5,smgDuan[(Fout%1000)/100]);
	Delay1ms();	
    DisplaySmg(6,smgDuan[(Fout%100)/10]);
	Delay1ms();
	DisplaySmg(7,smgDuan[Fout%10]);
	Delay1ms();		
}

/****************************电压显示**********************/
void Display_U()
{	
	DisplaySmg(0,smgDuan[10]);
	Delay1ms();	
	DisplaySmg(1,smgDuan[12]);
	Delay1ms();	
    DisplaySmg(2,smgDuan[12]);
	Delay1ms();	
    DisplaySmg(3,smgDuan[12]);
	Delay1ms();	
    DisplaySmg(4,smgDuan[12]);
	Delay1ms();
	DisplaySmg(5,smgDuan1[Vrb2*2/100]);
	Delay1ms();	
    DisplaySmg(6,smgDuan[Vrb2*2%100/10]);
	Delay1ms();	
    DisplaySmg(7,smgDuan[Vrb2*2%10]);
	Delay1ms();	
}
void Display_U_zero()				 //电压固定2.00V显示
{	
	DisplaySmg(0,smgDuan[10]);
	Delay1ms();	
	DisplaySmg(1,smgDuan[12]);
	Delay1ms();	
    DisplaySmg(2,smgDuan[12]);
	Delay1ms();	
    DisplaySmg(3,smgDuan[12]);
	Delay1ms();	
    DisplaySmg(4,smgDuan[12]);
	Delay1ms();
	DisplaySmg(5,smgDuan1[2]);
	Delay1ms();	
    DisplaySmg(6,smgDuan[0]);
	Delay1ms();	
    DisplaySmg(7,smgDuan[0]);
	Delay1ms();
	DisplaySmg(7,smgDuan1[12]);	
}
void Display_zero()					  //关闭所有数码管
{	
	DisplaySmg(0,smgDuan[12]);
	Delay1ms();	
	DisplaySmg(1,smgDuan[12]);
	Delay1ms();	
    DisplaySmg(2,smgDuan[12]);
	Delay1ms();	
    DisplaySmg(3,smgDuan[12]);
	Delay1ms();	
    DisplaySmg(4,smgDuan[12]);
	Delay1ms();
	DisplaySmg(5,smgDuan[12]);
	Delay1ms();	
    DisplaySmg(6,smgDuan[12]);
	Delay1ms();	
    DisplaySmg(7,smgDuan[12]);
	Delay1ms();
	
}   

4.独立按键扫描函数

/*******************************独立按键扫描*************/

void  Scan_keys()
{
    if(P33==0)						   //S4
	{
	  	Delay1ms();
	   if(P33==0)
	   {
	   	   if(flag4==0)
		   {
		   	 flag4=1;
		   }
	   	   else if(flag4==1) 
		   {
		   	flag4=0;
		   }
		   
		}
	}
	   if(P32==0)						   //S5
	{
	  	Delay1ms();
	   if(P32==0)
	   {
	   	   if(flag5==1)
		   {
		   	 flag5=0;
		   }
	   	   else if(flag5==0)
		   {
		   	flag5=1;
		   }
		   
		}
	}
	  if(P31==0)						   //S6
	{
	  	Delay1ms();
	   if(P31==0)
	   {
	   	   if(flag6==1)
		   {
		   	 flag6=0;
		   }
	   	   else if(flag6==0)
		   {
		   	flag6=1;
		   }
		   }
	}
 if(P30==0)						   //S7
	{
	  	Delay1ms();
	   if(P30==0)
	   {
	   	   if(flag7==1)
		   {
		   	 flag7=0;
			 
		   }
	   	   else if(flag7==0)
		   {
		   	flag7=1;
		
		   }
		   
		}
	}
}

5.指示灯 L3 L4 判断函数
在这里插入图片描述

/****************************判断函数**********************/
void panduan_U()					   //L3指示灯亮灭
{
   if(Vrb2<75)
   {
   	XBYTE[0X8000]=0XFf;
   }
    else if((Vrb2>=75) &&(Vrb2<125))
   {
   	 XBYTE[0X8000]=0XFB;
   }
     else if((Vrb2>=125) &&(Vrb2<175))
	{
	
	  XBYTE[0X8000]=0XFf;
	}
    else if(Vrb2>=175)
	{
	   XBYTE[0X8000]=0XFb;
	}
}
void panduan_F()					  //L4 指示灯亮灭
{
   if(Fout<1000)
   {
   	  XBYTE[0X8000]=0XF7;
   }
   else if((Fout>=1000)&&(Fout<5000))
   {
   	   XBYTE[0X8000]=0XF7;
   }
   else if((Fout>=5000)&&(Fout<10000))
	{
   	    XBYTE[0X8000]=0XFf;
	}
	else if(Fout>=10000)
	{
    	XBYTE[0X8000]=0XF7;
	}
}

6.系统初始化函数
在这里插入图片描述

/****************************系统初始化*****************/
void Init_System()
{
    XBYTE[0Xa000]= 0X00;
	XBYTE[0X8000]= 0XFF;
 	Timer1Init();
	Timer0Init();
}

7.主函数
在这里插入图片描述

/*****************************主函数********************/
void main()
{
	 Init_System();
  	 while(1)
	{	
    	Scan_keys();
	   if(T_flag==1)    //频率采集
	 { 
	   T_flag=0;
	   Fout=(TH0<<8)+TL0;
	   TL0=0x00;
	   TH0=0x00;
	   TF0=0;
	   TR0=1;
	  }
		if(flag7==0)
	   	 {    if(flag4==0)
	         {	 XBYTE[0X8000]=0XFE;
		         if(flag5==1)
		        {
			    
			       Vrb2=IIC_Read(0x03); 
	               XBYTE[0X8000]=0XEF;
		           Display_U();
			     }
                 if(flag5==0)
		        {	  
		   	      Vrb2=103; XBYTE[0X8000]=0XFF;
	              Display_U_zero();
				}
				if(flag6==0)
				{  if(flag5==0)
				   {panduan_U();}
				   else if(flag5==1)
				   {
				   	 panduan_U();}
				}
				else if(flag6==1)
				{
				   XBYTE[0X8000]=0XFF;
				}
		     }
		 else  if(flag4==1)							//S4界面切换
	        { XBYTE[0X8000]=0XFd;
		       Display_F();
			   if(flag6==0)
			   {
		        panduan_F();
			   }
			  else if(flag6==1)
			  {
			   XBYTE[0X8000]=0XFF;
			  }
			}
		}
		 if(flag7==1)
		{
		  
		  Display_zero();
		}	
	  
   }
}

三、比赛经验分享
蓝桥杯作为一个全国性赛事,比赛比较人性化,五个小时的开发时间,作为比赛,一定会有选拔的作用,所以一定要要好好准备。不要抱着投机取巧的心态,今年就是对违纪的处理相当严格,不管是电子类还是软件类,甚至一个赛点的成绩全部取消,可见对比赛的违纪的处罚力度相当的狠。一定要准备客观题,即便程序写的不是很完整,也能有个不错的分数。其次,要多看看官网的模拟题,今年就是因为没看官网那个模拟题,成绩不是很理想,要注重综合性训练,即便你每个模块都很熟练,比如(DS1302 DS18B20 24C02 PCF8591 IIC )单个模块可能你用的得心应手,但当遇到综合性题目时,没有一个整体任务的理解是不行的,只有不断的训练,将历届真题含金量比较高的,跳出重点训练,当你融汇贯通的时候,不管它题目千变万化,依然可以有条不紊的完成对任务的程序的设计。

**========================================================**
到此,第十届省赛试题已经解析完毕,以上代码,仅供参考之用。

2019.4.6 星期六 我们都是追梦人,我们都在努力奔跑。考研加油!

  • 26
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 15
    评论
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值