• 第八届(17年)整套做下来给我的第一印象就是数码管的操作要求真的高(骚),其与14年的“简易温度采集与控制装置”的数码管操作类似,不过17年的多了一个“选中数码管实现一秒闪烁”的要求。思考了将近一两天的时间...

          第八届(17年)整套做下来给我的第一印象就是数码管的操作要求真的高(骚),其与14年的“简易温度采集与控制装置”的数码管操作类似,不过17年的多了一个“选中数码管实现一秒闪烁”的要求。思考了将近一两天的时间(原谅我脑子僵,估计真正比赛的时候就死翘翘了)独创了一个算法,我称之为“数码管同异步扫描”(该名借鉴了异步UART通信与同步IIC通信)

    废话不多说,直接上图,红圈部分对我来说是个难点。


    unsigned char pcom; //选中的数码管标识符  
    unsigned char num[8]; //LedScan1()与jia间的桥梁
    unsigned char jia;    //控制数字增减

    接下来是“同异步数码管扫描”的核心代码
    void LedScan()              /*异步数码管扫描函数*/  
    {  
        static unsigned char i;
      if((pcom==2)|(pcom==5)) pcom++;
      if((i!=pcom))             //扫描未选中的数码管
      {
    	P2&=0X1F; 
    
    	P2|=0XC0;
    	P0=0x01<<i;
    
    	P2&=0X1F;
    
        P2|=0XE0;
    	P0=LedBuff[i];
              
    	P2&=0X1F;
      }
        i++;
    	if(i==8) i=0;
      
    } 
    
    
    void LedScan1()               /*同步数码管扫描函数*/
    {
       static unsigned char j=0;
       static unsigned char k=0;
     
       if(j==pcom)           { if((pcom==2)|(pcom==5)) k=1; else k=0;P2&=0X1F; P2|=0XC0;P0=0x01<<pcom+k;P2&=0X1F; P2|=0XE0;P0=num[pcom]; P2&=0X1F; } j++; if(j==8) j=0;}   
    //扫描选中的数码管
    “同异步数码管扫描”的核心思想是:建立两个数码管扫描函数,一个扫描选中的数码管,另一个扫描未选中的数码管
    void InterruptTimer0() interrupt 1
    {
    
       TH0=(65536 - ((11059200/12)/1000))/256;
       TL0=(65536 - ((11059200/12)/1000))%256;
       
      
       KeyScan();  
    
    LedScan();			   //与pcom异步扫描
       LedScan1();			   //与pcom同步扫描
       cnt++;
       if(cnt>=1000)
       {
    	  cnt=0;
    	  if(flag==0)
    	  {
    	     num[pcom]=LedChar[jia];		//与pcom同步数码管显示		
    	     flag=1;
    	  }
          else
    	  {
    	    
    	    num[pcom]=0xff;
    	    flag=0;
    	  }
       }
        LedBuff[pcom]=LedChar[jia];	//保存设置好的数据,1ms快刷,否则切换数码管的时候后一个数码管会保留前一个数码管的数字的
       if(pcom==0){if(jia<3){if(jia==2){hourflag=1;g_time[5]=jia;}else{g_time[5]=jia;}}else if(jia==3){jia=0;g_time[5]=jia;}}		//解决一下界面且换,进入二级菜单跳到左二数码管的问题,否则hourflag一直为0,判断不了小时的十位为2时,个位超2
    
       if(pcom==1){if(hourflag==1){if(jia==4){jia=0;g_time[4]=jia;}else{g_time[4]=jia;}}  else{g_time[4]=jia;}}
    
    	  if(pcom==3)
    	  {
    	        
    	         if(jia<6) g_time[3]=jia;			  	
    	         if(jia==6)
    			  {
    			      jia=0;
    			      g_time[3]=jia;
    			  }
    	  }
    
       if(pcom==4){ g_time[2]=jia;}
       if(pcom==6){ if(jia<6){g_time[1]=jia;}else {jia=0;g_time[1]=jia;}}
       if(pcom==7){ g_time[0]=jia;}	 
    
    
    }
    
    
    

    以下是完整代码

    头文件

    display.h

    unsigned char code LedChar[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xbf}; //数码管真值表
    unsigned char LedBuff[8]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
    
    unsigned char pcom=0;
    
    unsigned char num[8]={0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0};                  //数码管切换
    void LedScan()              /*数码管动态刷新*/  
    {  
        static unsigned char i;
      if((pcom==2)|(pcom==5)) pcom++;
      if((i!=pcom))
      {
    	P2&=0X1F; 
    
    	P2|=0XC0;
    	P0=0x01<<i;
    
    	P2&=0X1F;
    
        P2|=0XE0;
    	P0=LedBuff[i];
              
    	P2&=0X1F;
      }
        i++;
    	if(i==8) i=0;
      
    } 
    
    
    void LedScan1()
    {
       static unsigned char j=0;
       static unsigned char k=0;
     
       if(j==pcom)
       {
        if((pcom==2)|(pcom==5)) k=1;
        else k=0;
    	P2&=0X1F; 
    
    	P2|=0XC0;
    	P0=0x01<<pcom+k;
    
    	P2&=0X1F;
    
        P2|=0XE0;
    	P0=num[pcom];
              
    	P2&=0X1F;
       }
       j++;
       if(j==8) j=0;
    
    }
    
    void ds1302scan()              /*数码管动态刷新*/  
    {  
        static unsigned char c;
    
    	P2&=0X1F; 
    
    	P2|=0XC0;
    	P0=0x01<<c;
    
    	P2&=0X1F;
    
        P2|=0XE0;
    	P0=LedBuff[c];
              
    	P2&=0X1F;
        c++;
    	if(c==8) c=0;
      
    } 
    
    void ConfigTimer0()
    {  
      EA=1;
      TMOD=0X01;
       TH0=(65536 - ((11059200/12)/1000))/256;
       TL0=(65536 - ((11059200/12)/1000))%256;
      ET0=1;
      TR0=1;
    }
    
    ds1302.h

    /*
      程序说明: DS1302驱动程序
      软件环境: Keil uVision 4.10 
      硬件环境: CT107单片机综合实训平台 8051,12MHz
      日    期: 2011-8-9
    */
    
    
    #include <intrins.h>
    
    sbit SCK=P1^7;		
    sbit SDA=P2^3;		
    sbit RST = P1^3;   // DS1302复位												
    
    
    void Write_Ds1302_Byte(unsigned  char temp) 
    {
    	unsigned char i;
    	for (i=0;i<8;i++)     	
    	{ 
    		SCK=0;
    		SDA=temp&0x01;
    		temp>>=1; 
    		SCK=1;
    	}
    }   
    
    void Write_Ds1302( unsigned char address,unsigned char dat )     
    {
     	RST=0;
    	_nop_();
     	SCK=0;
    	_nop_();
     	RST=1;	
       	_nop_();  
     	Write_Ds1302_Byte(address);	
     	Write_Ds1302_Byte(dat);		
     	RST=0; 
    }
    
    unsigned char Read_Ds1302 ( unsigned char address )
    {
     	unsigned char i,temp=0x00;
     	RST=0;
    	_nop_();
     	SCK=0;
    	_nop_();
     	RST=1;
    	_nop_();
     	Write_Ds1302_Byte(address);
     	for (i=0;i<8;i++) 	
     	{		
    		SCK=0;
    		temp>>=1;	
     		if(SDA)
     		temp|=0x80;	
     		SCK=1;
    	} 
     	RST=0;
    	_nop_();
     	RST=0;
    	SCK=0;
    	_nop_();
    	SCK=1;
    	_nop_();
    	SDA=0;
    	_nop_();
    	SDA=1;
    	_nop_();
    	return (temp);			
    }
    
    void delay(int n)/*延时函数*/  		  
    {  
        char z=110;  
        while(n--)  
        for(z=0;z<110;z++);  
    }  
    
    

    主程序

    #include<reg52.h>
    #include<display.h>
    #include<ds1302.h>
    
    sfr P4=0XC0;
    
    sbit KO1=P3^0;
    sbit KO2=P3^1;
    sbit KO3=P3^2;
    sbit KO4=P3^3;
    
    sbit KI1=P3^4;
    sbit KI2=P3^5;
    sbit KI3=P4^2;
    sbit KI4=P4^4;
    
    
    
    unsigned char ModelSwitch=0;
    unsigned char FStair=0;  //一级菜单标志位
    unsigned char SStair=0;  //二级菜单标志位
    
    unsigned char KeyCodeMap[4][1]={0x07,0x06,0x05,0x04};	//按键真值表
    unsigned char KeySta[4][1]={1,1,1,1};				//按键状态区
    unsigned char jia=0;
    
    int flag200ms;
    unsigned char tbackup=0xaa;
    unsigned char y_time[3];
    
    bit s7flag=0;
    bit s4start=0;
    bit flag=1;
    int cnt=0;
    bit hourflag=0;
    
    unsigned char g_time[6]={0,5,9,5,3,2};
    
    void KeyAction(unsigned char keycode);
    void KeyDriver();
    void set_time();
    void show_ds1302();
    
    void close_digital()
    {
       P2=(P2&0X1F);
       P2|=0XC0;
       P0=0X00;
       P2&=0X1F;
    
    }
    
    void main()
    {
      ConfigTimer0();
      set_time();
      while(1)
      {
    	 KeyDriver();
      }
    }
    
    void show_ds1302()
    {
      LedBuff[0]=LedChar[y_time[2]/16];
      LedBuff[1]=LedChar[y_time[2]%16];
    
      LedBuff[2]=0xbf;
    
      LedBuff[3]=LedChar[y_time[1]/16];
      LedBuff[4]=LedChar[y_time[1]%16];
    
      LedBuff[5]=0xbf;
    
      LedBuff[6]=LedChar[y_time[0]/16];
      LedBuff[7]=LedChar[y_time[0]%16];
    }
    
    void set_time()	/**/
    {
        unsigned char i=0;
    	Write_Ds1302(0x8e,0x00); 
    	Write_Ds1302(0x80,g_time[1]*16+g_time[0]);
    	Write_Ds1302(0x82,g_time[3]*16+g_time[2]);
    	Write_Ds1302(0x84,g_time[5]*16+g_time[4]);
    	Write_Ds1302(0x8e,0x00); 
    }
    
    void get_time()                /**/          
    {  
        char i=0;  
        for(i=0;i<3;i++)  
        {  
        y_time[i]=Read_Ds1302(0x81+i*2);  
        delay(30);  
        }  
    }
    
    void KeyScan()	 /*按键扫描,先从第二行开始扫描*/
    {
     static unsigned char keyout=0;
     static unsigned char keybuf[4][1]={                  //检测缓冲区	低四位为0即确定为按下
     {0xff},{0xff},{0xff},{0xff}
     };
    
       /*按下一个按键,需要16ms时间检测一个按键的状态*/
       keybuf[keyout][0]=(keybuf[keyout][0]<<1)|KI4;
    
       if((keybuf[keyout][0] & 0x0f) ==0)	KeySta[keyout][0]=0;
       else if((keybuf[keyout][0] & 0x0f)==0x0f) KeySta[keyout][0]=1;
    
    
     keyout++;
     if(keyout>=4) keyout=0;
     switch(keyout)			    /*行刷新,4ms一周期*/
     {
       case 0 : KO4=1;KO1=0; break;
       case 1 : KO1=1;KO2=0; break;
       case 2 : KO2=1;KO3=0; break;
       case 3 : KO3=1;KO4=0; break;
       default:break;
     }
    
    }
    
    void KeyDriver()   /*按键驱动*/
    {
    	unsigned char i;
    	static unsigned char backup[4][1]={1,1,1,1};
    
       	   for(i=0;i<4;i++)
    	   {
    	     
    		 if(backup[i][0]!=KeySta[i][0])								//按下 backup=1 弹起 backup=0 亮 backup=1        按下 backup=1 不亮
    		 {
    		      backup[i][0]=KeySta[i][0];						        //放前面才能一按下,就检测到0,变换也是先变换
                  if(backup[i][0]==0)
    			  {
    			    KeyAction(KeyCodeMap[i][0]);
    			  }	 	  
    		 }		
    	   }
    
    }
    
    
    void KeyAction(unsigned char keycode)
    {
    	if(keycode==0x07)
    	{
    	  FStair=1;
    	  if(s7flag==1)
    	  pcom++;
    	  else s7flag=1;
    
    	  if(pcom<8)
    	  {
    		 jia=0;
    	  }
    
    	  if(pcom==8)
          {
            pcom=0;	 FStair=0;close_digital(); set_time();s7flag=0;
          } 
    	}
    
    	if(keycode==0x05)
    	{
    	 
    	  if(jia<10)  jia++;
    	  if(jia==10) jia=0;
    	}
    
    	if(keycode==0x04)
    	{
    	  if(jia>0) jia--;
    
    	}
    }
    
    
     void InterruptTimer0() interrupt 1
    {
    
       TH0=(65536 - ((11059200/12)/1000))/256;
       TL0=(65536 - ((11059200/12)/1000))%256;
       
      
       KeyScan();  
    
    if(FStair==1)			   //一级菜单
    {
       LedScan();			   //与pcom异步扫描
       LedScan1();			   //与pcom同步扫描
       cnt++;
       if(cnt>=1000)
       {
    	  cnt=0;
    	  if(flag==0)
    	  {
    	     num[pcom]=LedChar[jia];		//与pcom同步数码管显示
    		
    	     flag=1;
    	  }
          else
    	  {
    	    
    	    num[pcom]=0xff;
    	    flag=0;
    	  }
       }
        LedBuff[pcom]=LedChar[jia];	//保存设置好的数据,1ms快刷,否则切换数码管的时候后一个数码管会保留前一个数码管的数字的
       if(pcom==0){if(jia<3){if(jia==2){hourflag=1;g_time[5]=jia;}else{g_time[5]=jia;}}else if(jia==3){jia=0;g_time[5]=jia;}}		//解决一下界面且换,进入二级菜单跳到左二数码管的问题,否则hourflag一直为0,判断不了小时的十位为2时,个位超2
    
       if(pcom==1){if(hourflag==1){if(jia==4){jia=0;g_time[4]=jia;}else{g_time[4]=jia;}}  else{g_time[4]=jia;}}
    
    	  if(pcom==3)
    	  {
    	        
    	         if(jia<6) g_time[3]=jia;			  	
    	         if(jia==6)
    			  {
    			      jia=0;
    			      g_time[3]=jia;
    			  }
    	  }
    
       if(pcom==4){ g_time[2]=jia;}
    
       if(pcom==6){ if(jia<6){g_time[1]=jia;}else {jia=0;g_time[1]=jia;}}
       if(pcom==7){ g_time[0]=jia;}	 
    }
    
    else if(FStair==0)		  //一级菜单
    {
        ds1302scan();
    	flag200ms++;
    	if(flag200ms>=400)
    	{
    	  flag200ms=0;
    	  get_time();
    	  if(tbackup!=y_time[0]%16)
    	  {
    	      tbackup=y_time[0]%16;
    		  show_ds1302();
    	  }
    
    
    	}
    
    
    }
    
    }
    
    
    
    
    
    
    

    最后来张马斯克的“重型猎鹰”来激励自己,“梦想总是值得我们不畏艰险地去追寻“。



    展开全文
  • 蓝桥杯单片机学习过程记录(二十七)届国赛串口通信相关代码补充 /* //UART串口通信 届国赛uart串口内容相关补充 设置数组存储输入输入字符,并与设定的密码相判断。 */ #include<STC15F2K60S2.H> ...

    蓝桥杯单片机学习过程记录(二十八)第五届国赛串口通信相关代码补充

    在这里插入图片描述

    /*
    //UART串口通信
    第五届国赛uart串口内容相关补充
    设置数组存储输入输入字符,并与设定的密码相判断。
    */
    #include<STC15F2K60S2.H>
    unsigned char count_uart,uart_num;
    unsigned char seg[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xff};
    unsigned char yi,er,san,si,wu,liu,qi,ba;
    unsigned char urdat[6],urdat_set[6]={"AAASSS"};
    void delayms(int ms);
    void sendbyte(unsigned char dat);
    void UartInit(void);
    //void sendstring(unsigned char *str);
    void display_12(yi,er);
    void display_34(san,si);
    void display_56(wu,liu);
    void display_78(qi,ba);
    void allinit();
    void uart_pd();
    void main(){
    	allinit();
    	UartInit();EA=1;ES=1;
    //	sendstring("Hello,everyone\r\n");
    	yi=10;er=10;san=10;si=10;wu=10;liu=10;qi=10;ba=10;
    	while(1){
    		uart_pd();
    		display_12(yi,er);
    		display_34(san,si);
    		display_56(wu,liu);
    		display_78(qi,ba);
    	}
    }
    //串口初始化
    void UartInit(void)	
    {
    	SCON = 0x50;	
    	AUXR |= 0x40;		
    	AUXR &= 0xFE;		
    	TMOD &= 0x0F;		
    	TL1 = 0xE0;		
    	TH1 = 0xFE;		
    	ET1 = 0;		
    	TR1 = 1;		
    }
    //中断接收
    void uart_service() interrupt 4{
    	//接收完人工进行清零
    	if(RI==1){
    		RI=0;
    		//存入数组
    		urdat[count_uart]=SBUF;
    	}
    	//发送
    	sendbyte(urdat[count_uart]);
    	count_uart++;
    	if(count_uart==6)
    		count_uart=0;
    }
    //判断与设定密码是否一致,一致的话小灯亮
    void uart_pd(){
    	unsigned char i;
    	for(i=0;i<6;i++){
    		if(urdat[i]==urdat_set[i]){
    			uart_num++;
    		}
    	}
    	if(uart_num==6){
    		P2=0X80;P0=0X00;
    	}
    	uart_num=0;
    }
    //发送字节
    void sendbyte(unsigned char dat){
    	SBUF=dat;
    	while(TI==0);
    	TI=0;
    }
    //初始化
    void allinit(){
    	P2=0XA0;P0=0X00;
    	P2=0XC0;P0=0XFF;P2=0XE0;P0=0XFF;
    	P2=0X80;P0=0XFF;
    }
    //延时
    void delayms(int ms){
    	int q,w;
    	for(q=0;q<ms;q++)
    		for(w=0;w<845;w++);
    }
    //数码管
    void display_12(yi,er){
    	P2=0XC0;P0=0X01;P2=0XE0;P0=seg[yi];delayms(1);
    	P2=0XC0;P0=0X02;P2=0XE0;P0=seg[er];delayms(1);
    }
    void display_34(san,si){
    	P2=0XC0;P0=0X04;P2=0XE0;P0=seg[san];delayms(1);
    	P2=0XC0;P0=0X08;P2=0XE0;P0=seg[si];delayms(1);
    }
    void display_56(wu,liu){
    	P2=0XC0;P0=0X10;P2=0XE0;P0=seg[wu];delayms(1);
    	P2=0XC0;P0=0X20;P2=0XE0;P0=seg[liu];delayms(1);
    }
    void display_78(qi,ba){
    	P2=0XC0;P0=0X40;P2=0XE0;P0=seg[qi];delayms(1);
    	P2=0XC0;P0=0X80;P2=0XE0;P0=seg[ba];delayms(1);
    	P2=0XC0;P0=0XFF;P2=0XE0;P0=0XFF;delayms(1);
    }
    
    //void sendstring(unsigned char *str){
    //	while(*str !='\0'){
    //	sendbyte(*str++);
    //	}
    //}
    
    展开全文
  • 2018蓝桥杯国赛试题(单片机类) 有需要的可以下下看哦,谢谢支持
  • 这一届国赛感觉不是特别难,但是还是有几点需要注意: 1.不要把超声波程序写在中断里面。如果把超声波程序写在中断里面的话,可能就不会及时的检测到溢出标志,在我开始验证代码的时候出现的现象是最后一个数码管...

    本次使用到的模块大概有:超声波测距、EEPROM读和写、时钟DS1302、矩阵键盘、数码管显示

    这一届国赛感觉不是特别难,但是还是有几点需要注意:

            1.不要把超声波程序写在中断里面。如果把超声波程序写在中断里面的话,可能就不会及时的检测到溢出标志,在我开始验证代码的时候出现的现象是最后一个数码管闪烁,然后把超声波写在主函数里面就解决了问题。

            2.程序里面经常调用的代码,写在函数里面,会大大减少代码量和重复代码,并且利于检查以及代码美观。如写EEPROM和读EEPROM可以专门写在函数里面,在我们要修改的时候直接调用函数传递一个参数进去就行了,也比如我们在输入密码的时候,计算密码这一重复的工作,可以直接写在函数里面,这样我们在检测到按键的时候,就可以直接调用函数,不需要每一次都在里面计算。


    本次用到的模块:

        超声波测距:

      超声波测距发射8个脉冲函数以及延时13us函数

    void Delay13us()		//@11.0592MHz
    {
    	unsigned char i;
    
    	_nop_();
    	_nop_();
    	i = 33;
    	while (--i);
    }
    void sonic_send(void)
    {
    	u8 i = 8;
    	while( i-- )
    	{
    		TX = 1;
    		Delay13us();
    		TX = 0;
    		Delay13us();
    	}
    }

    超声波函数:

    TR0 = 0;
    sonic_send();
    TR0 = 1;
    while(RX == 1 && TF0 == 0 );
    TR0 = 0;
    if(TF0 == 1)
    {
    	TF0 = 0;
    	distance = 999;
    }
    else
    {
    	distance = TH0;
    	distance = (distance<<8)|TL0;
    	distance = (u16)(distance*0.00153718);
    }
    TH0 = 0;
    TL0 = 0;

    DS1302初始化时间以及读取时间函数:

    void DS1302_INIT(void)
    {
    	unsigned char i,add = 0x80;
    	Write_Ds1302_Byte(0x8e,0x00);
    	for(i = 0;i < 7 ; i++)
    	{
    		Write_Ds1302_Byte(add,Time[i]);
    		add += 2;
    	}
    	Write_Ds1302_Byte(0x8e,0x80);
    }
    void DS1302_GET(void)
    {
    	unsigned char i,add = 0x81;
    	Write_Ds1302_Byte(0x8e,0x00);
    	for(i = 0;i < 7 ; i++)
    	{
    		Time[i] = Read_Ds1302_Byte(add);
    		add += 2;
    	}
    	Write_Ds1302_Byte(0x8e,0x80);
    }

    写EEPROM函数和读EEPROM函数

    void Write_AT24C02(unsigned char add,unsigned char dat)
    {
    	IIC_Start();
    	IIC_SendByte(0XA0);
    	IIC_WaitAck();
    	IIC_SendByte(add);
    	IIC_WaitAck();
    	IIC_SendByte(dat);
    	IIC_WaitAck();
    	IIC_Stop();
    }
    unsigned char Read_AT24C02(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_WaitAck();
    	
    	return temp;
    }

    完整代码:

    #include <STC15F2K60S2.h>
    #include <intrins.h>
    #include "iic.h"
    #include "ds1302.h"
    
    #define u8 unsigned char
    #define u16 unsigned int
    	
    u8 code LED[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xff};
    u8 KEY_TEMP,KEY = 0XFF;
    u8 Digcom = 0, Digbuf[] = {1,2,3,4,10,10,10,10};
    sbit RX = P1^1;
    sbit TX = P1^0;
    u16 distance = 999,T = 0,T_GATE = 0,password = 0;
    u8 Tmeasure = 0,intr = 0,shezhi = 0,error = 0;
    bit flag = 0,KEY_FLAG = 0,GATE_FLAG = 0;
    bit flag1 = 0,flag2 = 0,flag3 = 0,flag4 = 0,zidong = 1;
    u8 yi = 10,er = 10,san = 11,si = 11,wu = 11,liu = 11,qi = 11,ba = 11;
    u16 DELAY_TIME;
    extern u8 Time[];
    
    void Delay13us()		//@11.0592MHz
    {
    	unsigned char i;
    
    	_nop_();
    	_nop_();
    	i = 33;
    	while (--i);
    }
    
    void delay_ms(u16 ms)
    {
    	u16 i,j;
    	for(i = ms; i>0 ; i--)
    		for(j = 845; j > 0 ; j--);
    }
    void INIT(void)
    {
    	P2 |= 0X80;
    	P2 &= 0X9F;
    	P0 = 0XFF;
    	
    	P2 |= 0XA0;
    	P2 &= 0XBF;
    	P0 = 0X00;
    	
    	P2 |= 0XC0;
    	P2 &= 0XDF;
    	P0 = 0XFF;
    	P2 |= 0XE0;
    	P2 &= 0XFF;
    	P0 = 0XFF;
    }
    void Relay_ON(void)
    {
    	P2 |= 0XA0;
    	P2 &= 0XBF;
    	P0 = 0X10;
    }
    void OFF(void)	//关掉蜂鸣器和继电器
    {
    	P2 |= 0XA0;
    	P2 &= 0XBF;
    	P0 = 0X00;
    }
    void Buzz_ON(void)
    {
    	P2 |= 0XA0;
    	P2 &= 0XBF;
    	P0 = 0X40;
    }
    void Get_Password(u8 temp)
    {
    	if(intr <= 6)password = password*10 + temp;
    	
    	if(intr == 1) san = temp;
    	else if(intr == 2)	si = temp;
    	else if(intr == 3)	wu = temp;
    	else if(intr == 4)	liu = temp;
    	else if(intr == 5)	qi = temp;
    	else if(intr == 6)	ba = temp;
    }
    u16 Read_Password()
    {
    	u16 temp;
    	temp = Read_AT24C02(0XA0);
    	temp = temp*100;
    	temp += Read_AT24C02(0XA1);
    	temp = temp*100;
    	temp += Read_AT24C02(0XA2);
    	return temp;
    }
    void Write_Password(u16 temp)
    {
    	Write_AT24C02(0XA0,temp/10000);delay_ms(5);
    	Write_AT24C02(0XA1,temp/100%100);delay_ms(5);
    	Write_AT24C02(0XA2,temp%100);delay_ms(5);
    }
    void KEY_KBD(void)
    {
    	u16 temp;	//暂时存储当前的密码
    	bit zhengque  = 0;
    	P3 = 0X7F;P44 = 0;P42 = 1;
    	KEY_TEMP = P3 & 0X0F;
    	if(KEY_TEMP != 0x0f && flag1 == 0 && zidong == 0) 
    	{
    		delay_ms(5);
    		KEY_TEMP = P3&0X0F;
    		if(KEY_TEMP != 0x0f)
    		{
    			flag1 = 1;
    			KEY_TEMP = P3;
    			switch(KEY_TEMP)
    			{
    				case 0x7E:intr++;Get_Password(0);break;
    				case 0x7D:intr++;Get_Password(4);break;
    				case 0x7B:intr++;Get_Password(8);break;
    //				case 0x77:intr++;	qi = 0;ba = 4;break;
    			}
    		}
    	}
    	else if(KEY_TEMP == 0x0f && flag1)
    	{
    		delay_ms(5);
    		KEY_TEMP = P3 & 0X0F;
    		if(KEY_TEMP == 0x0f)
    		{
    			flag1 = 0;
    		}
    	}
    	
    	P3 = 0XbF;P44 = 1;P42 = 0;
    	KEY_TEMP = P3 & 0X0F;
    	if(KEY_TEMP != 0x0f && flag2 == 0 && zidong == 0) 
    	{
    		delay_ms(5);
    		KEY_TEMP = P3&0X0F;
    		if(KEY_TEMP != 0x0f)
    		{
    			flag2 = 1;
    			KEY_TEMP = P3;
    			switch(KEY_TEMP)
    			{
    				case 0xbE:intr++;Get_Password(1);break;
    				case 0xbD:intr++;Get_Password(5);break;
    				case 0xbB:intr++;Get_Password(9);break;
    //				case 0xb7:qi = 0;ba = 8;break;
    			}
    		}
    	}
    	else if(KEY_TEMP == 0x0f && flag2)
    	{
    		delay_ms(5);
    		KEY_TEMP = P3 & 0X0F;
    		if(KEY_TEMP == 0x0f)
    		{
    			flag2 = 0;
    		}
    	}
    	
    	P3 = 0XdF;P42 = 1;P44 = 1;
    	KEY_TEMP = P3 & 0X0F;
    	if(KEY_TEMP != 0x0f && flag3 == 0 && zidong == 0) 
    	{
    		delay_ms(5);
    		KEY_TEMP = P3&0X0F;
    		if(KEY_TEMP != 0x0f)
    		{
    			flag3 = 1;
    			KEY_TEMP = P3;
    			switch(KEY_TEMP)
    			{
    				case 0xDE:intr++;Get_Password(2);break;
    				case 0xDD:intr++;Get_Password(6);break;
    				case 0xDB:	//设置按键
    					if(shezhi == 0)shezhi = 1;
    					yi = 11;er = 10;san = 11;si = 11;
    					wu = 11;liu = 11;qi = 11;ba = 11;
    					break;	
    				case 0xD7:				//确认按键
    					if(shezhi == 0 || shezhi == 1)
    					{
    						temp = Read_Password();
    						if(password == temp) 	//密码正确并且不是设置状态打开继电器
    						{
    							error = 0;
    							zhengque = 1;
    							DELAY_TIME = 5000;
    							GATE_FLAG = 1;
    							Relay_ON();	//打开继电器
    							T_GATE = 0;	//从头开始计时5s
    						}
    						else if(password != temp)		//密码不正确,蜂鸣器报警三秒
    						{
    							if(++error == 3)
    							{
    								error = 0;
    								DELAY_TIME = 3000;
    								GATE_FLAG = 1;
    								Buzz_ON();	//打开继电器
    								T_GATE = 0;	//从头开始计时3s
    							}
    						}
    					}
    					else if(shezhi == 2)
    					{
    						Write_Password(password);
    						
    					}
    					
    					if(shezhi == 0 || shezhi == 2)//密码输入完成,显示密码初始界面
    					{
    						yi = 10;er = 10;san = 11;si = 11;
    						wu = 11;liu = 11;qi = 11;ba = 11;
    						if(shezhi == 2)shezhi = 0 ;
    					}
    					else if(shezhi == 1 && zhengque)
    					{
    						yi = 10;er = 11;san = 11;si = 11;
    						wu = 11;liu = 11;qi = 11;ba = 11;
    						shezhi = 2;
    					}
    					else if(shezhi == 1 && zhengque == 0)
    					{
    						yi = 11;er = 10;san = 11;si = 11;
    						wu = 11;liu = 11;qi = 11;ba = 11;
    					}
    					password = 0;
    					intr = 0;
    					break;	//确认按键,表示当前输入完成
    			}
    		}
    	}
    	else if(KEY_TEMP == 0x0f && flag3)
    	{
    		delay_ms(5);
    		KEY_TEMP = P3 & 0X0F;
    		if(KEY_TEMP == 0x0f)
    		{
    			flag3 = 0;
    		}
    	}
    	
    	P3 = 0XeF;P42 = 1;P44 = 1;
    	KEY_TEMP = P3 & 0X0F;
    	if(KEY_TEMP != 0x0f && flag4 == 0 && zidong == 0) 
    	{
    		delay_ms(5);
    		KEY_TEMP = P3 & 0X0F;
    		if(KEY_TEMP != 0x0f)
    		{
    			flag4 = 1;
    			KEY_TEMP = P3;
    			switch(KEY_TEMP)
    			{
    				case 0xEE:intr++;Get_Password(3);break;
    				case 0xED:intr++;Get_Password(7);break;
    				case 0xEB:		//复位按键,恢复初始密码654321
    					Write_Password(654321);
    					intr = 0;
    					password = 0;
    					break;
    				case 0xE7:		//退出按键,显示输入密码状态
    					yi = 10;er = 10;san = 11;si = 11;
    					wu = 11;liu = 11;qi = 11;ba = 11;
    					intr = 0;
    					shezhi = 0;
    					password = 0;
    					break;
    			}
    		}
    	}
    	else if(KEY_TEMP == 0x0f && flag4)
    	{
    		delay_ms(5);
    		KEY_TEMP = P3 & 0X0F;
    		if(KEY_TEMP == 0x0f)
    		{
    			flag4 = 0;
    		}
    	}
    }
    
    void sonic_send(void)
    {
    	u8 i = 8;
    	while( i-- )
    	{
    		TX = 1;
    		Delay13us();
    		TX = 0;
    		Delay13us();
    	}
    }
    void Timer2Init(void)		//1毫秒@11.0592MHz
    {
    	AUXR |= 0x04;		//定时器时钟1T模式
    	T2L = 0xCD;		//设置定时初值
    	T2H = 0xD4;		//设置定时初值
    	AUXR |= 0x10;		//定时器2开始计时
    	IE2 |= 0X04;
    	EA = 1;
    }
    void timer2(void)interrupt 12
    {
    //数码管动态显示
    	P2 |= 0XC0;
    	P2 &= 0XDF;
    	P0 = (0X01<<Digcom);
    	P2 |= 0xE0;
    	P2 &= 0XFF;
    	P0 = LED[Digbuf[Digcom]];
    	if(++Digcom == 8)	Digcom = 0;
    //超声波测距(200毫秒一次)
    	if(++Tmeasure == 200 && zidong)	//只有在自动的工作状态下才检测距离
    	{
    		Tmeasure = 0;
    		flag = 1;
    	}
    //继电器打开5s
    	if(++T_GATE == DELAY_TIME && GATE_FLAG)
    	{
    		GATE_FLAG = 0;
    		T_GATE = 0;
    		OFF();	//关掉蜂鸣器和继电器
    	}
    }
    void Timer0Init(void)
    {
    	AUXR |= 0x80;		//定时器时钟1T模式
    	TMOD &= 0xF0;		//设置定时器模式
    	TL0 = 0x00;		//设置定时初值
    	TH0 = 0x00;		//设置定时初值
    	TF0 = 0;		//清除TF0标志
    //	TR0 = 1;		//定时器0开始计时
    }
    
    void main()
    {
    	u8 temp;
    //初始化外设、定时器、时钟
    	INIT();
    	Timer2Init();
    	Timer0Init();
    	DS1302_INIT();
    //把初始密码写进EEPROM里面
    	Write_Password(654321);
    	while(1)
    	{
    //读取时间		
    		DS1302_GET();
    		temp = Time[2]/16;
    		temp = temp*10 + (Time[2]%16);
    		if( temp>=7 && temp < 22 )	zidong = 1;
    			else zidong = 0;
    //判断工作状态		
    		if(zidong)
    		{
    			Digbuf[0] = Time[2]/16;	Digbuf[1] = Time[2]%16;
    			Digbuf[2] = 10;					Digbuf[3] = Time[1]/16;
    			Digbuf[4] = Time[1]%16;	Digbuf[5] = 10;
    			Digbuf[6] = Time[0]/16;	Digbuf[7] = Time[0]%16;
    			if(distance < 30 && GATE_FLAG == 0)		//自动工作状态下,如果距离小于30厘米
    			{
    				DELAY_TIME = 5000;
    				GATE_FLAG = 1;
    				Relay_ON();	//打开继电器
    				T_GATE = 0;	//从头开始计时5s
    			}
    			if(flag)
    			{	
    				flag = 0;
    				TR0 = 0;
    				sonic_send();
    				TR0 = 1;
    				while(RX == 1 && TF0 == 0 );
    				TR0 = 0;
    				if(TF0 == 1)
    				{
    					TF0 = 0;
    					distance = 999;
    				}
    				else
    				{
    					distance = TH0;
    					distance = (distance<<8)|TL0;
    					distance = (u16)(distance*0.00153718);
    				}
    				TH0 = 0;
    				TL0 = 0;
    			}
    		}
    		else
    		{
    			Digbuf[0] = yi;	Digbuf[1] = er;
    			Digbuf[2] = san;	Digbuf[3] = si;
    			Digbuf[4] = wu;	Digbuf[5] = liu;
    			Digbuf[6] = qi;	Digbuf[7] = ba;
    		}
    		KEY_KBD();
    	}
    }

     

    展开全文
  • 这 些 代 码 是 我 当 初 参 加 比 赛 时 练 习 写 的,有 需 要 的 朋 友 可 以 下 载 来 看 看。
  • 本人参加了第十届蓝桥杯单片机国赛,现在把做过的练习发给大家参考一下。 设计一超声波测距报警实时时钟电路 电路具体功能要求: 电路通电后进入初始化状态:灯 L1 亮,数码管全亮,蜂鸣器接通,1s 后全部 关闭,...

    本人参加了第十届蓝桥杯单片机国赛,现在把做过的练习发给大家参考一下。

    设计一超声波测距报警实时时钟电路

    电路具体功能要求:

    1. 电路通电后进入初始化状态:灯 L1 亮,数码管全亮,蜂鸣器接通,1s 后全部

    关闭,显示时间设定 11-50-59。

    1. 按下 S7 按键切换显示实时时钟 XX-XX-XX、显示超声波测量距离 XXX。

    2. 显示实时时钟状态下,按 S6 按键进行时间调整,第一次按下 S6 进入时调整,

    “时”闪烁;第二次按下 S6 进入分调整,“分”闪烁。再一次按下退出调整。

    S4、S5 为调节数值 S5+,S4-(时间距离)的加减按键。

    1. 显示超声波测距状态下,按 S6 按键进行报警距离调整,S6 按第一次进入调

    整状态,第二次按下退出,将调节后的数值保存到 24C02 中。S4、S5 为调节数

    值 S5+,S4-(时间距离)的加按键。显示超声波报警距离–XXX。

    1. 超声波测距报警初值设定为 30cm,超声波检测超过设定值 X 不报警,小于 X

    立即报警,小于 1.2 倍的 X, L1 灯闪烁。

    1. 设计一个欠压电路,12V 供电,电压小于 10V 切断电路电源。

    #include<stc15f2k60s2.h>
    #include<intrins.h>
    #include<ds1302.h>
    #include<iic.h>

    #define somenop {nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();}
    #define u8 unsigned char
    u8 code smg_duan[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00,0x40};
    u8 code smg_wei[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};

    sbit buzzer=P0^6;
    sbit relay= P0^4;

    sbit RX=P1^1;
    sbit TX=P1^0;

    #define KEY P3
    #define NO_KEY 0xff
    #define KEY_STATE0 0
    #define KEY_STATE1 1
    #define KEY_STATE2 2

    u8 xian_shi[8];
    u8 mo_si=1,shi_zhong;

    void send_wave()
    {

    	TX=1;
    	somenop;somenop;somenop;somenop;somenop;
    	somenop;somenop;somenop;somenop;somenop;
    	TX=0;
    

    }

    void Delay2ms() //@11.0592MHz
    {

      unsigned char i, j;
    _nop_();
    _nop_();
    i = 22;
    j = 128;
    do
    {
    	while (--j);
    } while (--i);
    

    }

    u8 key_scan()
    {
    static unsigned char key_state=KEY_STATE0;
    u8 key_value=0,key_temp;
    u8 key1,key2;
    P30=0;P31=0;P32=0;P33=0;P34=1;P35=1;P42=1;P44=1;
    if(P440) key1=0x70;
    if(P42
    0) key1=0xb0;
    if(P350) key1=0xd0;
    if(P34
    0) key1=0xe0;
    if((P341)&&(P351)&&(P421)&&(P441)) key1=0xf0;
    P30=1;P31=1;P32=1;P33=1;P34=0;P35=0;P42=0;P44=0;
    if(P300) key2=0x0e;
    if(P31
    0) key2=0x0d;
    if(P320) key2=0x0b;
    if(P33
    0) key2=0x07;
    if((P301)&&(P311)&&(P321)&&(P331)) key2=0x0f;
    key_temp=key1|key2;
    switch(key_state)
    {

    	case KEY_STATE0:
    	if(key_temp!=NO_KEY)
    	{
    		key_state=KEY_STATE1;
    	}
    	break;
    	case KEY_STATE1:
    	if(key_temp==NO_KEY)
    	{
    		key_state=KEY_STATE0;
    	}
    	else
    	{
    		switch(key_temp)
    		{
    			case 0x77:key_value=4 ;break;
    			case 0x7b:key_value=5 ;break;
    			case 0x7d:key_value=6 ;break;
    			case 0x7e:key_value=7 ;break;
    			case 0xb7:key_value=8 ;break;
    			case 0xbb:key_value=9 ;break;
    			case 0xbd:key_value=10;break;
    			case 0xbe:key_value=11;break;
    			case 0xd7:key_value=12;break;
    			case 0xdb:key_value=13;break;
    			case 0xdd:key_value=14;break;
    			case 0xde:key_value=15;break;
    			case 0xe7:key_value=16;break;
    			case 0xeb:key_value=17;break;
    			case 0xed:key_value=18;break;
    			case 0xee:key_value=19;break; 
    		}
    		key_state=KEY_STATE2;
    	}
    	break;
    	case KEY_STATE2:
    	if(key_temp==NO_KEY)
    	{
    		key_state=KEY_STATE0;
    	}
    	break;
    }
    return key_value;
    

    }

    void Delay1000ms() //@11.0592MHz
    {
    unsigned char i, j, k;

    _nop_();
    _nop_();
    i = 43;
    j = 6;
    k = 203;
    do
    {
    	do
    	{
    		while (--k);
    	} while (--j);
    } while (--i);
    

    }

    void Timer0Init(void) //1毫秒@11.0592MHz
    {

    AUXR |= 0x80;		//定时器时钟1T模式
    TMOD &= 0xF0;		//设置定时器模式
    TL0 = 0xCD;		//设置定时初值
    TH0 = 0xD4;		//设置定时初值
    TF0 = 0;		//清除TF0标志
    TR0 = 1;		//定时器0开始计时
    ET0 = 1;
    EA = 1;
    

    }

    void Time1Init()//1ms
    {

    AUXR&=0xbf;
    TMOD&=0xbf;
    TL1=0x00;
    TH1=0x00;
    TF1=0;
    TR1=0;
    

    }

    bit key_flag,sonic_flag=0,shan_shuo=0;
    void main()
    {

    unsigned int t,distance;
    u8 shi,fen,miao,shi_1,fen_1,miao_1,shi_zhong=0;  
    u8 csb_set=30,csb_mo_si=0;     //超声波正常工作 0    超声波设置距离  1
    u8 key_val = NO_KEY;
    csb_set=Read_24C02(0x01);
    
    P2 = 0X80;    //初始化要求
    P0 = 0X00; 
    P2=0XA0;
    buzzer =1;
    Delay1000ms();
    P2 = 0X80;
    P0=0XFF;
    P2=0XA0;
    buzzer =0;
    P2 = 0X00;
    
    
    Timer0Init();
    Time1Init();
    set_sfm(11,50,59);
    while(1)
    {	
    if(key_flag == 1)
    {
    	 key_flag = 0;
       key_val = key_scan();
    	
    
    	
    	 switch(key_val)
    	 {
    		 case 4: 
    			 if(mo_si==1)   //时钟调整模式
    			 {
    				if(shi_zhong==3)
    				{
    					if(shi_1==0)
    					shi_1=24;
    					shi_1--;
    				}
    				if(shi_zhong==2)
    				{
    					
    					if(fen_1==0)
    					fen=60;
    					fen_1--;
    				}
    				if(shi_zhong==1)
    				{
    						
    							if(miao_1==0)
    							miao_1=60;
    							miao_1--;
    						}
    			}
    			 
    			 if(mo_si==0)   //超声波调整模式
    			{
    			   csb_set--;
    				Write_24C02(0x01,csb_set); 			
    			}
    		 break;
    		 case 5:  
    			 if(mo_si==1)   //时钟调整模式
    	   {
    			if(shi_zhong==3)
    				{
    					shi_1++;
    					if(shi_1>23)
    					shi_1=0;
    				}
    				if(shi_zhong==2)
    				{
    					fen_1++;
    					if(fen_1>59)
    					fen_1=0;
    				}
    				if(shi_zhong==1)
    				{
    					miao_1++;
    					if(miao_1>59 )
    					miao_1=0;
    				}
    			}
    		 
    	    if(mo_si==0)   //超声波调整模式
    			{
    			   csb_set++;
    				Write_24C02(0x01,csb_set); 
    								
    			}
    		 break;
    		 case 6:   
    			if(mo_si==1)   //位切换
    		 {
    		   shi_zhong++;
    			 if(shi_zhong>=4)
    				 shi_zhong=0;
    		 }
    		 if(mo_si==0)   //超声波模式切换
    		 {
    		    csb_mo_si++;
    			 if(csb_mo_si>=2)
    			 {
    			    csb_mo_si=0;
    			 }
    			 
    		 }
    		 
    		 break;
    		 case 7:     //时钟  超声波  切换
    	    mo_si++;
    			if(mo_si>=2)
    				mo_si=0;
    		
    		
    		 break;
    		
    	 }
    	 
    	 
     }
      if(shi_zhong!=0&&mo_si==1)   //时钟显示
    	{
    		if(shi_zhong==1&&shan_shuo==1)
    		{
    			xian_shi[0]=10;
    			xian_shi[1]=10;	
    		}
    		else
    		{
    			xian_shi[0]=shi_1/10;
    			xian_shi[1]=shi_1%10;
    		}			
    		xian_shi[2]=11;
    		if(shi_zhong==2&&shan_shuo==1)
    		{
    		   xian_shi[3]=10;
    		   xian_shi[4]=10;	
    		}
    		else
    		{
    			xian_shi[3]=fen_1/10;
    			xian_shi[4]=fen_1%10;	
    		}
    		xian_shi[5]=11;
    		if(shi_zhong==3&&shan_shuo==1)
    		{
    			xian_shi[6]=10;
    			xian_shi[7]=10;	
    		}
    		else
    		{
    			xian_shi[6]=miao_1/10;
    			xian_shi[7]=miao_1%10;		
    		}
    		 
    		if(shi_zhong==3)
    		set_sfm(shi_1,fen_1,miao_1);		//写入自己的时分秒
    	}
     if(mo_si==1&&shi_zhong==0)
     {
    		ET0=0;
    		shi=Ds1302_Single_Byte_Read(ds1302_hr_addr);   //现实时分秒
    		fen=Ds1302_Single_Byte_Read(ds1302_min_addr);
    		miao=Ds1302_Single_Byte_Read(ds1302_sec_addr);
    		ET0=1;		
      shi_1=shi/16*10+shi%16;    //存储现在的时分秒用来调节
    		fen_1=fen/16*10+fen%16;
    		miao_1=miao/16*10+miao%16;	
    		xian_shi[0]=shi/16;
    		xian_shi[1]=shi%16;
    		xian_shi[2]=11;
    		xian_shi[3]=fen/16;
    		xian_shi[4]=fen%16;
    		xian_shi[5]=11;
    		xian_shi[6]=miao/16;
    		xian_shi[7]=miao%16;
    	 
     }
     if(mo_si==0&&csb_mo_si==0)  //超声波测距
     {  
    		sonic_flag=0;
    		send_wave();
    		TR1=1;
    		while((RX==1)&&(TF1==0));
    		TR1=0;
    		if(TF1==1)
    		{
    			TF1=0;
    			distance=999;
    		}
    		else
    		{
    			t=TH1;
    			t<<=8;
    			t|=TL1;
    			distance=(unsigned int)(t*0.017);	
    		}
    		TH1=0;
    		TL1=0;
    	
        xian_shi[0]=10;
    		xian_shi[1]=10;
    		xian_shi[2]=10;
    		xian_shi[3]=10;
    		xian_shi[4]=10;
    	  xian_shi[5]=distance/100;
    		xian_shi[6]=distance%100/10;
    		xian_shi[7]=distance%10;
    		Delay2ms()	;
    		Delay2ms()	;
    		Delay2ms()	;
    		Delay2ms()	;
    		if(distance<csb_set*1.2)    //距离小于警告值
    		{
    			if(shan_shuo==1)
    		  P2=0X80;P0=0X7F;P2=0X00;	  //led
    		
    			if(shan_shuo==0)
    		  P2=0X80;P0=0XfF;P2=0X00;	
    		}
    		if(distance>csb_set*1.2)    //距离大于警告值
    		{		
    		  P2=0X80;P0=0XfF;P2=0X00;			   
    		}
    		
    		if(distance<=csb_set)     //距离小于警告值
    		{		
    		  P2=0XA0;buzzer=1;relay=0;P2=0X00;//蜂鸣器 继电器
    		}
    		if(distance>csb_set)  //距离大于警告值
    		{		
    		  P2=0XA0;buzzer=0;relay=0;P2=0X00;		 //蜂鸣器 继电器
    		}
    		
    		
     }
    
      if(mo_si==0&&csb_mo_si==1)
    	{
    	  
    	  xian_shi[0]=10;
    		xian_shi[1]=10;
    		xian_shi[2]=10;
    		xian_shi[3]=10;
    		xian_shi[4]=10;
    	  xian_shi[5]=csb_set/100;
    		xian_shi[6]=csb_set%100/10;
    		xian_shi[7]=csb_set%10;
    	
    	
    	}
    

    }
    }

    void Timer0() interrupt 1 using 1
    {
    static unsigned int key_count = 0,sing_count = 0,i = 0,shan_count=0;
    key_count++;
    sing_count++;

    if(key_count == 10)    //键盘扫描
    {
    	key_count = 0;
    	key_flag = 1;
    }
    
     
    if(sing_count == 3)   //数码管显示
    {
    	sing_count = 0;
    	P2 = 0xc0; P0 = 0X00; P2=0X00;
    	
      P2 = 0xE0; P0 =~smg_duan[xian_shi[i]]; P2=0X00;
    	
    	P2 = 0xc0; P0 = smg_wei[i]; P2=0X00;
    
    	i++;
    	if(i == 8)
    		i = 0;
    }
    
    	shan_count++;    //数码管闪烁
    	if(shan_count>1000)
    	{
    		  shan_count=0;
    	  	shan_shuo=~shan_shuo;
    	}
    

    }

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

    #include “iic.h”

    //总线启动条件
    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(unsigned char 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 Read_24C02(unsigned char addr) //24c02的读
    {
    unsigned char tmp;

    IIC_Start();					
    IIC_SendByte(0xa0); 		
    IIC_WaitAck();					
    IIC_SendByte(addr); 		
    IIC_WaitAck(); 					
    
    IIC_Start();						
    IIC_SendByte(0xa1); 		
    IIC_WaitAck();				
    tmp = IIC_RecByte();		
    IIC_Ack(0); 						
    IIC_Stop();							
    return tmp;
    

    }

    void Write_24C02(unsigned char addr, unsigned char dat) //24c02的写
    {
    IIC_Start();
    IIC_SendByte(0xa0);
    IIC_WaitAck();
    IIC_SendByte(addr);
    IIC_WaitAck();
    IIC_SendByte(dat);
    IIC_WaitAck();
    IIC_Stop();
    }

    unsigned char read_adc(unsigned char add) //电位器或者光敏电阻
    {
    unsigned char temp;
    IIC_Start();
    IIC_SendByte(0x90);
    IIC_WaitAck();
    IIC_SendByte(add);
    IIC_WaitAck();
    IIC_Start();
    IIC_SendByte(0x91);
    IIC_WaitAck();
    temp=IIC_RecByte();
    IIC_WaitAck();
    IIC_Stop();
    return temp;
    }

    这是iic的h文件

    #ifndef _IIC_H
    #define _IIC_H

    #include<stc15f2k60s2.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);
    void IIC_Stop(void);
    void IIC_Ack(unsigned char ackbit);
    void IIC_SendByte(unsigned char byt);
    unsigned char Read_24C02(unsigned char addr);
    void Write_24C02(unsigned char addr, unsigned char dat);
    unsigned char read_adc(unsigned char add);
    void write_adc(unsigned char add);

    bit IIC_WaitAck(void);
    unsigned char IIC_RecByte(void);

    #endif

    这是ds1302的c文件
    #include “ds1302.h”
    //
    /单字节写入一字节数据/
    void Write_Ds1302_Byte(unsigned char dat)
    {
    unsigned char i;
    SCK = 0;
    for (i=0;i<8;i++)
    {
    if (dat & 0x01) // 等价于if((addr & 0x01) ==1)
    {
    SDA_SET; //#define SDA_SET SDA=1 /电平置高/
    }
    else
    {
    SDA_CLR; //#define SDA_CLR SDA=0 /电平置低/
    }
    SCK_SET;
    SCK_CLR;
    dat = dat >> 1;
    }
    }
    /
    /
    /单字节读出一字节数据/
    unsigned char Read_Ds1302_Byte(void)
    {
    unsigned char i, dat=0;
    for (i=0;i<8;i++)
    {
    dat = dat >> 1;
    if (SDA_R) //等价于if(SDA_R==1) #define SDA_R SDA /电平读取/
    {
    dat |= 0x80;
    }
    else
    {
    dat &= 0x7F;
    }
    SCK_SET;
    SCK_CLR;
    }
    return dat;
    }

    /********************************************************************/
    /向DS1302 单字节写入一字节数据/
    void Ds1302_Single_Byte_Write(unsigned char addr, unsigned char dat)
    {

    RST_CLR;			/*RST脚置低,实现DS1302的初始化*/
    SCK_CLR;			/*SCK脚置低,实现DS1302的初始化*/
    
    RST_SET;			/*启动DS1302总线,RST=1电平置高 */
    addr = addr & 0xFE;	 
    Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是写操作,写之前将最低位置零*/	
    Write_Ds1302_Byte(dat);	 /*写入数据:dat*/
    RST_CLR;				 /*停止DS1302总线*/
    

    }

    /********************************************************************/
    /从DS1302单字节读出一字节数据/
    unsigned char Ds1302_Single_Byte_Read(unsigned char addr)
    {
    unsigned char temp;
    RST_CLR; /RST脚置低,实现DS1302的初始化/
    SCK_CLR; /SCK脚置低,实现DS1302的初始化/

    RST_SET;	/*启动DS1302总线,RST=1电平置高 */	
    addr = addr | 0x01;	 
    Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是读操作,写之前将最低位置高*/
    temp=Read_Ds1302_Byte(); /*从DS1302中读出一个字节的数据*/		
    RST_CLR;		   /*停止DS1302总线*/
    SDA_CLR; 		//xiu gai   fei chang zhong yao
    
    return temp;
    

    }

    void set_sfm(char shi,char fen,char miao)
    {
    Ds1302_Single_Byte_Write(0x8e,0); //关闭写保护
    Ds1302_Single_Byte_Write(0x80,(miao/10)*16+miao%10); //以BCD码写入秒数据
    Ds1302_Single_Byte_Write(0x82,(fen/10)*16+fen%10); //以BCD码写入分数据
    Ds1302_Single_Byte_Write(0x84,(shi/10)*16+shi%10); //以BCD码写入时数据
    Ds1302_Single_Byte_Write(0x8e,0x80); //打开写保护
    }

    这是ds1302的h文件
    #ifndef DS1302_H
    #define DS1302_H

    #include<stc15f2k60s2.h>
    #include<intrins.h>
    //
    sbit SCK=P1^7;
    sbit SD=P2^3;
    sbit RST=P1^3;
    /
    /
    /复位脚/
    #define RST_CLR RST=0 /电平置低/
    #define RST_SET RST=1 /电平置高/
    /双向数据/
    #define SDA_CLR SD=0 /电平置低/
    #define SDA_SET SD=1 /电平置高/
    #define SDA_R SD /电平读取/
    /时钟信号/
    #define SCK_CLR SCK=0 /时钟信号/
    #define SCK_SET SCK=1 /电平置高/
    /********************************************************************/
    #define ds1302_sec_addr 0x80 //秒数据地址
    #define ds1302_min_addr 0x82 //分数据地址
    #define ds1302_hr_addr 0x84 //时数据地址
    #define ds1302_date_addr 0x86 //日数据地址
    #define ds1302_month_addr 0x88 //月数据地址
    #define ds1302_day_addr 0x8A //星期数据地址
    #define ds1302_year_addr 0x8C //年数据地址

    #define ds1302_control_addr 0x8Ee //写保护命令字单元地址
    #define ds1302_charger_addr 0x90 //涓电流充电命令字地址
    #define ds1302_clkburst_addr 0xBE //日历、时钟突发模式命令字地址
    /********************************************************************/

    /********************************************************************/

    单字节写入一字节数据*/
    extern void Write_Ds1302_Byte(unsigned char dat);
    /********************************************************************/
    /单字节读出一字节数据/
    extern unsigned char Read_Ds1302_Byte(void);

    //
    /
    /
    /向DS1302单字节写入一字节数据/
    extern void Ds1302_Single_Byte_Write(unsigned char addr, unsigned char dat);
    /********************************************************************/
    /从DS1302单字节读出一字节数据/
    extern unsigned char Ds1302_Single_Byte_Read(unsigned char addr);
    extern void set_sfm(char shi,char fen,char miao);

    #endif
    //
    //       END FILE
    /
    /

    展开全文
  • 最近在做蓝桥杯练习的时候,发现网上关于届国赛试题的代码少之又少,于是自己便尝试着编写,经过一个星期的努力,终于把所以代码搞定,功能也全部实现。个人觉得届国赛试题是近几年最难的一,试题几乎涉及...

    写在前面的话

    最近在做蓝桥杯练习的时候,发现网上关于第五届国赛试题的代码少之又少,于是自己便尝试着编写,经过一个星期的努力,终于把所以代码搞定,功能也全部实现。个人觉得第五届国赛试题是近几年最难的一届,试题几乎涉及了开发板的所有基础模块,对个人编程能力是一个不小的挑战,这也是花费了一个星期的原因(可能我个人比较菜~~)。
    在编程的过程中遇到的最大问题就是RB2电阻和光敏电阻共用一个PCF8591,导致在读取它们数值的时候,总是会互相干扰,最后采用了多次读取然后取平均值的办法,解决了这一问题。如果大家有什么好的建议,欢迎交流。废话不多说,开始上程序~

    题目要求

    (找遍了网上,也没发现这届比赛的PDF版资料)
    在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

    程序代码

    主函数

    #include "stc15f2k60s2.h"
    #include "key.h"
    #include "onewire.h"
    #include "iic.h"
    #include "display.h"
    #include "ds1302.h"
    #include "uart.h"
    
    uint temperture;		 //温度
    uchar AD_value;			 //RB2电压值
    uchar iic_count;
    uchar key_value;		//按键值
    uchar shi,fen,miao;		//时、分、秒
    uint tingliu_time;		//物体停留时间
    
    extern uchar work_mode;		//工作模式
    extern uchar mode_display;		// 显示模式
    extern uchar guangmin;	   //光敏值
    
    bit move_flag;		   //物体靠近标志
    bit rec_flag;		   //串口输入指令正确标志
    bit flag1s;			   //1秒发送一次串口信息
    
    void Delayms(unsigned int ms);		//@11.0592MHz
    void iic_write();				//写EEPROM
    
    void All_init()
    {
      P2=(P2&0X1F)|0XA0;	//关闭蜂鸣器,继电器
      P0=0X00;
      P2=P2&0X1F;
    
      P2=(P2&0X1F)|0X80;   //关闭led
      P0=0XFF;
      P2=P2&0X1F;
    }
    
    uchar jishu=0;
    
    void main()
    {
      Timer0Init();
      All_init();
      
      Ds1302_Single_Byte_Write(ds1302_control_addr,0);
      Ds1302_Single_Byte_Write(ds1302_sec_addr,TIME[0]);
      Ds1302_Single_Byte_Write(ds1302_min_addr,TIME[1]);
      Ds1302_Single_Byte_Write(ds1302_hr_addr,TIME[2]);
      
      UartInit();
      
      while(1)
      {
        Display1();		//温度、湿度显示界面
    	Display2();		//时间显示界面
    	Display3();	    //物体停留时间显示界面
    	led();
    
    	shi = TIME[2]/16*10 + TIME[2]%16;
    	fen = TIME[1]/16*10 + TIME[1]%16;
    	miao = TIME[0]/16*10 + TIME[0]%16;
    	
    
        if(work_mode==0)	  //自动传输模式
    	{	
    	  if(rec_flag)
    	  {
    	   if(flag1s)
    	   {
    	    flag1s=0;
    	    UART_SendString("{");
    	    UART_SendNumber(temperture);
    	    UART_SendString("-");
    	    UART_SendNumber(AD_value);
    	    UART_SendString("%}");
    
    	    UART_SendString("{");
    	    UART_SendNumber(shi);
    	    UART_SendString("-");
    	    UART_SendNumber(fen);
    	    UART_SendString("-");
    	    UART_SendNumber(miao);
    	    UART_SendString("}");
    
    	    UART_SendString("{");
    	    UART_SendNumber(move_flag);
    	    UART_SendString("}");
    	    UART_SendString("\r\n");
    	   }
    	  }
    	}
    	
    	if(work_mode==1)	
    	{	  
    	  if(move_flag)
    	  {
    	    
    		iic_count++;
    		if(iic_count==5)
    		iic_count=0;
    		
    	  }
    	  iic_write();
    	  if(rec_flag)	  //串口指令正确
    	  {
    	   if(flag1s)
    	   {
    	    flag1s=0;
    	    UART_SendString("{");
    	    UART_SendNumber(Read_eeprom(0x00+jishu));
    	    UART_SendString("-");
    	    UART_SendNumber(Read_eeprom(0x01+jishu));
    	    UART_SendString("%}");
    
    	    UART_SendString("{");
    	    UART_SendNumber(Read_eeprom(0x02+jishu));
    	    UART_SendString("-");
    	    UART_SendNumber(Read_eeprom(0x03+jishu));
    	    UART_SendString("-");
    	    UART_SendNumber(Read_eeprom(0x04+jishu));
    	    UART_SendString("}");
    
    	    UART_SendString("{");
    	    UART_SendNumber(Read_eeprom(0x05+jishu));
    	    UART_SendString("}");
    	    UART_SendString("\r\n");
    
    		jishu=jishu+0x06;
    		if(jishu==30)
    		jishu=0;
    	   }
    	  }
    	}
    
    	key_value=key_init();
    	switch(key_value)
    	{
    	  case 4:
    	  work_mode++;
    	  if(work_mode==2)
    	  work_mode=0;
    	  break;
    
    	  case 5:
    	  mode_display++;
    	  if(mode_display==3)
    	  mode_display=0;
    	  break;
    	}
      }
    }
    
    void iic_write()
    {
      switch(iic_count)
      {
        case 0:
    	Write_eeprom(0x00,temperture);
    	Delayms(5);
    	Write_eeprom(0x01,AD_value);
    	Delayms(5);
    	Write_eeprom(0x02,shi);
    	Delayms(5);
    	Write_eeprom(0x03,fen);
    	Delayms(5);
    	Write_eeprom(0x04,miao);
    	Delayms(5);
    	Write_eeprom(0x05,tingliu_time);
    	Delayms(5);
    	break;
    
    	case 1:
    	Write_eeprom(0x06,temperture);
    	Delayms(5);
    	Write_eeprom(0x07,AD_value);
    	Delayms(5);
    	Write_eeprom(0x08,shi);
    	Delayms(5);
    	Write_eeprom(0x09,fen);
    	Delayms(5);
    	Write_eeprom(0x0A,miao);
    	Delayms(5);
    	Write_eeprom(0x0B,tingliu_time);
    	Delayms(5);
    	break;
    
    	case 2:
    	Write_eeprom(0x0C,temperture);
    	Delayms(5);
    	Write_eeprom(0x0D,AD_value);
    	Delayms(5);
    	Write_eeprom(0x0E,shi);
    	Delayms(5);
    	Write_eeprom(0x0F,fen);
    	Delayms(5);
    	Write_eeprom(0x10,miao);
    	Delayms(5);
    	Write_eeprom(0x11,tingliu_time);
    	Delayms(5);
    	break;
    
    	case 3:
    	Write_eeprom(0x12,temperture);
    	Delayms(5);
    	Write_eeprom(0x13,AD_value);
    	Delayms(5);
    	Write_eeprom(0x14,shi);
    	Delayms(5);
    	Write_eeprom(0x15,fen);
    	Delayms(5);
    	Write_eeprom(0x16,miao);
    	Delayms(5);
    	Write_eeprom(0x17,tingliu_time);
    	Delayms(5);
    	break;
    
    	case 4:
    	Write_eeprom(0x18,temperture);
    	Delayms(5);
    	Write_eeprom(0x19,AD_value);
    	Delayms(5);
    	Write_eeprom(0x1A,shi);
    	Delayms(5);
    	Write_eeprom(0x1B,fen);
    	Delayms(5);
    	Write_eeprom(0x1C,miao);
    	Delayms(5);
    	Write_eeprom(0x1D,tingliu_time);
    	Delayms(5);
    	break;
      }
    }
    
    void Delayms(unsigned int ms)		//@11.0592MHz
    {
       unsigned int i, j;
       for(i=0;i<ms;i++)
       for(j=845;j>0;j--);
     
    }
    

    数码管显示
    界面一:温度、湿度

    void Display1()	   //温度、湿度显示界面
    {
       uchar i,j;
       for(i=0;i<5;i++)
       {
        ad_tab[i]=Read_PCF8591(0x03)/2.54f;
       	Delay_ms(1);
       }
       AD_value=(ad_tab[0]+ad_tab[1]+ad_tab[2]+ad_tab[3]+ad_tab[4])/5;
    
       for(j=0;j<5;j++)
       {
        guangmin_tab[j]=Read_PCF8591(0x01); 
        Delay_ms(1);
       }
       guangmin=(guangmin_tab[0]+guangmin_tab[1]+guangmin_tab[2]+guangmin_tab[3]+guangmin_tab[4])/5;
    
       temperture=Get_Temperture();
    
       if(guangmin<100)		  //有人靠近
       move_flag=1;
       else
       move_flag=0;
    
      display[0]=SMG_TAB[temperture%100/10];  
      display[1]=SMG_TAB[temperture%10];
      display[2]=0x39;  
      display[3]=0x00;
      display[4]=0x00;  
      display[5]=SMG_TAB[AD_value/10];
      display[6]=SMG_TAB[AD_value%10];  display[7]=0x76;
    }
    

    界面二:时间

    void Display2()	   //时间显示界面
    {
      
      TIME[0]=Ds1302_Single_Byte_Read(ds1302_sec_addr);
      TIME[1]=Ds1302_Single_Byte_Read(ds1302_min_addr);
      TIME[2]=Ds1302_Single_Byte_Read(ds1302_hr_addr);
    
      time_display[0]=SMG_TAB[TIME[2]/16];  
      time_display[1]=SMG_TAB[TIME[2]%16];   
      time_display[3]=SMG_TAB[TIME[1]/16];
      time_display[4]=SMG_TAB[TIME[1]%16];   
      time_display[6]=SMG_TAB[TIME[0]/16];  
      time_display[7]=SMG_TAB[TIME[0]%16];
    
      if(blink_flag)
      {
    	time_display[2]=0x40;
    	time_display[5]=0X40;
      }
      else
      {
    	time_display[2]=0x00;
    	time_display[5]=0X00;
      }
    }
    

    界面三:物体停留时间

    void Display3()	   //物体停留时间显示界面
    {
      tingliu_display[0]=0x00;  
      tingliu_display[1]=0x00;
      tingliu_display[2]=0x00;  
      tingliu_display[3]=0x40;
      tingliu_display[4]=SMG_TAB[tingliu_time/1000];  
      tingliu_display[5]=SMG_TAB[tingliu_time/100%10];
      tingliu_display[6]=SMG_TAB[tingliu_time/10%10];  
      tingliu_display[7]=SMG_TAB[tingliu_time%10];
    }
    

    定时器显示

    void Timer0Init()		//1毫秒@11.0592MHz
    {
    	AUXR |= 0x80;		//定时器时钟1T模式
    	TMOD &= 0xF0;		//设置定时器模式
    	TL0 = 0xCD;		//设置定时初值
    	TH0 = 0xD4;		//设置定时初值
    	TF0 = 0;		//清除TF0标志
    	TR0 = 1;		//定时器0开始计时
    	EA=1;
    	ET0=1;
    }
    
    void timer0() interrupt 1
    {
      uchar i;
      uchar smg_count;
      uint UART_count,blink_count;
      
      smg_count++;
      UART_count++;
      blink_count++;
    
      if(smg_count==3)
      {
        smg_count=0;
    	P2=(P2&0X1F)|0XC0;	//位选
    	P0=SMG_WEI[i];
    	P2=P2&0X1F;
    
    	if(mode_display==0)
    	{
    	  P2=(P2&0X1F)|0Xe0;
    	  P0=~display[i];
    	  P2=P2&0X1F;
    	}
    
    	if(mode_display==1)
    	{
    	  P2=(P2&0X1F)|0Xe0;
    	  P0=~time_display[i];
    	  P2=P2&0X1F;
    	}
    
    	if(mode_display==2)
    	{
    	  P2=(P2&0X1F)|0Xe0;
    	  P0=~tingliu_display[i];
    	  P2=P2&0X1F;
    	}
    
    	i++;
    	if(i==8)
    	i=0;
      }
     if(work_mode==1)
     {
      if(move_flag)
      {
    	tingliu_count++;
      }  
      else
      {		
    	if(tingliu_count!=0)
    	{
    	 temp=tingliu_count;
    	 tingliu_time=temp/1000;
    	 tingliu_count=0;
    	}
      }
     }	
    
      if(UART_count==1000)
      {
        UART_count=0;
    	flag1s=1;
      }
    
      if(blink_count==500)
      {
        blink_count=0;
    	blink_flag=~blink_flag;
      }
    }
    

    EERROM模块

    /*
      程序说明: IIC总线驱动程序
      软件环境: Keil uVision 4.10 
      硬件环境: CT107单片机综合实训平台(12MHz)
      日    期: 2011-8-9
    */
    
    #include "iic.h"
    
    void delay(unsigned char i)
    {
      do{
    
       _nop_();
      }while(i--);
    }
    //总线启动条件
    void IIC_Start(void)
    {
    	SDA = 1;
    	SCL = 1;
    	delay(5);
    	SDA = 0;
    	delay(5);
    	SCL = 0;	
    }
    
    //总线停止条件
    void IIC_Stop(void)
    {
    	SDA = 0;
    	SCL = 1;
    	delay(5);
    	SDA = 1;
    }
    /*IIC总线协议规定,每传送一个字节数据后,都要有一个应答信号,以确定数据传送是否被对方收到,
    应答信号由接收设备产生,在SCL为高电平期间,接收设备将SDA拉为低电平表示数据传输正确,即产生了应答。*/
    //应答位控制
    void IIC_Ack(unsigned char ackbit)	 //当ackbit为1时,表示单片机对从设备发送来数据的应答
                              //当ackbit为0时,表示主机接收了最后一个字节,因此不再应答,结束通信
    {
    	if(ackbit) 
    	{	
    		SDA = 0;
    	}
    	else 
    	{
    		SDA = 1;
    	}
    	delay(5);
    	SCL = 1;
    	delay(5);
    	SCL = 0;
    	SDA = 1; 
    	delay(5);
    }
    
    //等待应答
    bit IIC_WaitAck(void)
    {
    	SDA = 1;
    	delay(5);
    	SCL = 1;
    	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;
    		}
    		delay(5);
    		SCL = 1;
    		byt <<= 1;
    		delay(5);
    		SCL = 0;
    	}
    }
    
    //从I2C总线上接收数据
    unsigned char IIC_RecByte(void)
    {
    	unsigned char da;
    	unsigned char i;
    	
    	for(i=0;i<8;i++)
    	{   
    		SCL = 1;
    		delay(5);
    		da <<= 1;
    		if(SDA) 
    		da |= 0x01;
    		SCL = 0;
    		delay(5);
    	}
    	return da;
    }
    
    unsigned char Read_PCF8591(unsigned char addr)
    {
      unsigned char temp;
      IIC_Start();
      IIC_SendByte(0x90);
      IIC_WaitAck();
      IIC_SendByte(addr);
      IIC_WaitAck();
    
      IIC_Start();
      IIC_SendByte(0x91);
      IIC_WaitAck();
      temp=IIC_RecByte();
      IIC_Ack(0);
      IIC_Stop();
    
      return temp;
    }
    
    void Write_eeprom(unsigned char addr,unsigned char dat)
    {
      IIC_Start();
      IIC_SendByte(0xa0);
      IIC_WaitAck();
      IIC_SendByte(addr);
      IIC_WaitAck();
      IIC_SendByte(dat);
      IIC_WaitAck();
      IIC_Stop();
    }
    
    unsigned char Read_eeprom(unsigned char addr)
    {
      unsigned char temp;
      IIC_Start();
      IIC_SendByte(0xa0);
      IIC_WaitAck();
      IIC_SendByte(addr);
      IIC_WaitAck();
    
      IIC_Start();
      IIC_SendByte(0xa1);
      IIC_WaitAck();
      temp=IIC_RecByte();
      IIC_Ack(0);
      IIC_Stop();
    
      return temp;
    }
    

    DS1302时钟模块

    #include "ds1302.h"
    /********************************************************************/ 
    /*单字节写入一字节数据*/
    unsigned char TIME[]={0x55,0x59,0x23};
    
    void Write_Ds1302_Byte(unsigned char dat) 
    {
    	unsigned char i;
    	SCK = 0;
    	for (i=0;i<8;i++) 
    	{ 
    		if (dat & 0x01) 	// 等价于if((addr & 0x01) ==1) 
    		{
    			SDA_SET;		//#define SDA_SET SDA=1 /*电平置高*/
    		}
    		else 
    		{
    			SDA_CLR;		//#define SDA_CLR SDA=0 /*电平置低*/
    		}		 
    		SCK_SET;
    		SCK_CLR;		
    		dat = dat >> 1; 
    	} 
    }
    /********************************************************************/ 
    /*单字节读出一字节数据*/
    unsigned char Read_Ds1302_Byte(void) 
    {
    	unsigned char i, dat=0;	
    	for (i=0;i<8;i++)
    	{	
    		dat = dat >> 1;
    		if (SDA_R) 	  //等价于if(SDA_R==1)    #define SDA_R SDA /*电平读取*/	
    		{
    			dat |= 0x80;
    		}
    		else 
    		{
    			dat &= 0x7F;
    		}
    		SCK_SET;
    		SCK_CLR;
    	}
    	return dat;
    }
    
    /********************************************************************/ 
    /*向DS1302 单字节写入一字节数据*/
    void Ds1302_Single_Byte_Write(unsigned char addr, unsigned char dat)
    { 
    
    	RST_CLR;			/*RST脚置低,实现DS1302的初始化*/
    	SCK_CLR;			/*SCK脚置低,实现DS1302的初始化*/
    
    	RST_SET;			/*启动DS1302总线,RST=1电平置高 */
    	addr = addr & 0xFE;	 
    	Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是写操作,写之前将最低位置零*/	
    	Write_Ds1302_Byte(dat);	 /*写入数据:dat*/
    	RST_CLR;				 /*停止DS1302总线*/
    }
    
    /********************************************************************/ 
    /*从DS1302单字节读出一字节数据*/
    unsigned char Ds1302_Single_Byte_Read(unsigned char addr) 
    { 
    	unsigned char temp;
    	RST_CLR;			/*RST脚置低,实现DS1302的初始化*/
    	SCK_CLR;			/*SCK脚置低,实现DS1302的初始化*/
    
    	RST_SET;	/*启动DS1302总线,RST=1电平置高 */	
    	addr = addr | 0x01;	 
    	Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是读操作,写之前将最低位置高*/
    	temp=Read_Ds1302_Byte(); /*从DS1302中读出一个字节的数据*/		
    	RST_CLR;	/*停止DS1302总线*/
    	SDA_CLR;	//数据线拉低
    
    	return temp;
    }
    

    DS18B20温度传感器模块

    /*
      程序说明: 单总线驱动程序
      软件环境: Keil uVision 4.10 
      硬件环境: CT107单片机综合实训平台
      日    期: 2011-8-9
    */
    
    #include "onewire.h"
    #include "intrins.h"
    //单总线延时函数
    void Delay_OneWire(unsigned int t)
    {
      unsigned char i;
      while(t--)
      {
        for(i=0;i<12;i++);
      }
    }
    
    
    void Delay1ms()		//@11.0592MHz
    {
    	unsigned char i, j;
    
    	_nop_();
    	_nop_();
    	_nop_();
    	i = 11;
    	j = 190;
    	do
    	{
    		while (--j);
    	} while (--i);
    }
    
    //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;
    }
    
    //通过单总线向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;
    }
    
    void DS18B20_init()
    {
      Init_DS18B20();
      Delay1ms();
      Write_DS18B20(0xcc);
      Write_DS18B20(0x44);
    
      Init_DS18B20();
      Delay1ms();
      Write_DS18B20(0xcc);
      Write_DS18B20(0xbe);
    }
    
    int Get_Temperture()
    {
      int high,low;
      int temp;
    
      DS18B20_init();
      low=Read_DS18B20();	 //先读取低位
      high=Read_DS18B20();
      
    
      temp=high<<4;
      temp|=low>>4;
    
      return temp;
    }
    

    按键模块

    #include "key.h"
    
    unsigned char key_init()
    {
      static unsigned char key_state;
      unsigned char key_press, key_val=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_val=7;
    	  if(key_press==0x0d)  key_val=6;
    	  if(key_press==0x0b)  key_val=5;
    	  if(key_press==0x07)  key_val=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_val;
    }
    

    串口通信模块

    #include "uart.h"
    
    unsigned char UART_RxBuf[10];
    unsigned char UART_RxFlag;
    
    
    extern bit rec_flag;
    void UartInit(void)		//1200bps@11.0592MHz
    {
    	SCON = 0x50;		//8位数据,可变波特率
    	AUXR |= 0x40;		//定时器1时钟为Fosc,即1T
    	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
    	TMOD &= 0x0F;		//设定定时器1为16位自动重装方式
    	TL1 = 0x00;		//设定定时初值
    	TH1 = 0xF7;		//设定定时初值
    	ET1 = 0;		//禁止定时器1中断
    	TR1 = 1;		//启动定时器1
    	ES=1;		   //允许串行口中断
    }
    
    /**
      * 简介:	使用串口发送一个字节数据
      *	参数:	Byte 要发送的数据
      * 返回值:无
      */
    void UART_SendByte(unsigned char Byte)
    {
    	SBUF=Byte;
    	while(!TI);
    	TI=0;
    }
    
    /**
      * 简介:	使用串口发送一个字符串
      *	参数:	String 要发送的字符串
      * 返回值:无
      */
    void UART_SendString(unsigned char *String)
    {
    	unsigned char i;
    	for(i=0;String[i]!='\0';i++)
    	{
    		UART_SendByte(String[i]);
    	}
    }
    
    /**
      * 简介:	内部调用的次方函数
      * 说明:	返回值=X的Y次方
      */
    int UART_Pow(int X,int Y)
    {
    	unsigned char i;
    	int Result=1;
    	for(i=0;i<Y;i++)
    	{
    		Result*=X;
    	}
    	return Result;
    }
    
    /**
      * 简介:	使用串口发送一个数字
      *	参数:	Number 要发送的数字,范围-32768~32767
      * 返回值:无
      */
    void UART_SendNumber(int Number)
    {
    	unsigned char i,Length;
    	if(Number<0)
    	{
    		UART_SendByte('-');
    		Number=-Number;
    	}
    	for(Length=1;Number/UART_Pow(10,Length);Length++);	 //获取数字的长度
    	for(i=Length;i>0;i--)
    	{
    		UART_SendByte(Number/UART_Pow(10,i-1)%10+'0');		
    	}
    }
    
    /**
      * 简介:	使用串口接收一个字节数据
      *	参数:	无
      * 返回值:接收到的数据,若无数据也返回0
      */
    //unsigned char UART_ReceiveByte(void)
    //{
    //	if(UART_RxFlag)
    //	{
    //		UART_RxFlag=0;
    //		return UART_RxBuf;
    //	}
    //	return 0;
    //}
    
    
    
    /**
      * 简介:	串口中断函数,用于内部运转
      *	参数:	无
      * 返回值:无
      */
     
    void UART_Int(void) interrupt 4
    {
        static unsigned char count;	  //接收次数 
    	if(RI)	  //接收中断
    	{
    	    
    		UART_RxBuf[count]=SBUF;
    		switch(count)
    		{
    		  case 0:
    		  if(UART_RxBuf[count]=='A')
    		  count=1;
    		  else
    		  {
    		    count=0;
    			rec_flag=0;
    		  }
    		  break;
    
    		  case 1:
    		  if(UART_RxBuf[count]=='A')
    		  count=2;
    		  else
    		  {
    		    count=0;
    			rec_flag=0;
    		  }
    		  break;
    
    		  case 2:
    		  if(UART_RxBuf[count]=='A')
    		  count=3;
    		  else
    		  {
    		    count=0;
    			rec_flag=0;
    		  }
    		  break;
    
    		  case 3:
    		  if(UART_RxBuf[count]=='S')
    		  count=4;
    		  else
    		  {
    		    count=0;
    			rec_flag=0;
    		  }
    		  break;
    
    		  case 4:
    		  if(UART_RxBuf[count]=='S')
    		  count=5;
    		  else
    		  {
    		    count=0;
    			rec_flag=0;
    		  }
    		  break;
    
    		  case 5:
    		  if(UART_RxBuf[count]=='S')
    		  {		   
    		   rec_flag=1;
    		   count=0;
    		  }
    		  else
    		  {
    		    count=0;
    			rec_flag=0;
    		  }	  
    		  break;
    		  default:
    		  count=0;
    		  rec_flag=0;
    		  break;
    		}	
    		UART_RxFlag=1;
    		RI=0;
    	}
    }
    

    以上就是代码全部内容,欢迎交流,共同学习~
    附上工程包链接:第五届国赛试题

    展开全文
  • 使用竞赛板 NE555 方波信号发生器产生用于频率测量功能测试的方波信号,信号频率范围为 500Hz ~ 20KHz,电位器 RB3 调节信号频率, 可使用“跳线帽” 将单片机P34 引脚与方波信号发生器输出引脚 NET_SIG 短接。...
  • 系统硬件部分主要由按键电路、显示电路、数据存储电路、传感器检测电路及单片机系统组成,系统框图如图1所示: I2C总线驱动程序、CT107D单片机考试平台电路原理图以及本题所涉及到的芯片数据手册,可参考计算机上的...
  • 第十 蓝桥杯 单片机设计与开发项目 省赛 二部分 程序设计试题(70 分) 1、 基本要求 1.1 使用大赛组委会提供的国信长天单片机竞赛实训平台,完成本试题的程序设计 与调试。 1.2 选手在程序设计与调试过程中,...
  • 第八届蓝桥杯嵌入式决赛项目,功能全部实现,获全国一等奖。欢迎大家下载
  • 题目要求 功能简述 “门禁系统” 主要有两种工作模式: 模式 1: 7: 00—22: 00 为自动门状态, 该状态下门的开和关是通过超声波测距来的测距来控制, 当测到的距离小于 30mc 时门就开, 门开 5 秒后自动闭。...
  • 如果用a b c d这4个字母组成一个串,有4!=24种,如果把它们排个序,每个串都对应一个序号: ...bcad 8 bcda 9 bdac 10 bdca 11 cabd 12 cadb 13 cbad 14 cbda 15 cdab 16 cdba 17 … 现在有不多于10个两两不同的...
  • 第一题 第二题 第三题 第四题 第五题 第六题 第七题 第八题 第九题
  • 蓝桥杯单片机学习过程记录(二十九)第八届国赛超声波测距机 题目如下: 已完成 应用的内容: EEPROM、 定时器、数码管 led灯,独立按键 DA电压输出 超声波测距 /* ----------------------------- 第八届国赛...
  • ** 题目要求 ** 程序代码 主函数 #include "stc15f2k60s2.h" #include "driver.h" #include "ds1302.h" #include "sonic.h" #include "display.h" #include "iic.h" ...uchar code SMG_TAB[]={0x3F,0x06,0x5B,0x4F,0...
  • 蓝桥杯单片机学习过程记录(三十一)届国赛多功能测量仪表 届国赛,比较基础。有几点需要注意:一是温度获取需要小数,定义变量时long。二是存储时拆分开成两部分进行存储,要不然eeprom保存不了那么大的...
  • 工程可见Github&amp;amp;amp;lt;传送门&amp;amp;amp;gt;...代码过多,这里不再一一粘贴,只挑重要的讲。...这个互补输出算的上是该题的一大亮点,PA9(TIM1_CH2)和PB14(TIM1_CH2N)是一对互补通道。...
  • 蓝桥杯单片机学习过程记录(二十六)届国赛电压、频率采集设备 N555方波这部分没写,准备重新理解一下,其余部分都已经完成,遇到了两个问题,一是时钟芯片,调整时,记得调整完后重新初始化一下,二是采集电压...
  • 2019年蓝桥杯国赛总结

    2019-05-27 19:23:17
    2019年蓝桥杯国赛北京站,我们是C/C++B组,赛点在中国农业大学东校区,比赛时间为5月25日下午14点--下午18点,赛完26日上午出成绩,且26日下午13点--16点有个峰会可以凭蓝桥杯准考证领取门票,时间可以自行安排,...
1 2 3 4 5
收藏数 88
精华内容 35