未分类 · 2022年2月23日

蓝桥杯单片机组代码示例程序模板

1、 头文件

因为习惯原因和节约时间,虽然15单片机有专门的头文件,但是内部框架和51单片机是同样的,所以可以直接使用51的头文件,因为15的单片有多几个IO口,所以需要多定义几个IO口,另外引入头文件还有一些其他的,通过#include方式引入 ,代码模板如下。

  1. #include "reg52.h"    //包含51单片机寄存器定义的头文件  
  2. #include "intrins.h"  //包含_nop_()定义的头文件  
  3. #include "iic.h"      //通信驱动  
  4. #include "AT24C02.h"  //数据写入  
  5. #include "display.h"  //数码管  
  6. #include "cls.h"      //关闭外设
  7. #include "delay.h"    //延迟
  8. #include "key.h"              //按键
  9. #include "interrupt.h"//中断  
  10. sfr P4   = 0xC0;      //定义P4 io口
  11. sbit P42 = P4^2;  
  12. sbit P44 = P4^4; 

2、   按键函数

(1)  普通按键

  1. sbit S7 = P3^0;     //给io口命名  
  2. unsigned char count=0;  
  3. unsigned char key_value = 0;  
  4. void key_scanf()  
  5. {  
  6.     if(S7==0)        //判断按键按下  
  7.     {  
  8.         Delay(5);      //消抖 需要引入延时函数  
  9.         if(S7==0)       //再次判断按键按下  
  10.         {  
  11.             key_value=1;  //判断按下的数值  
  12.             count++;      //判断按键按下次数  
  13.             while(!S7);  
  14.         }  
  15.     }  
  16. }  

(2)  矩阵按键

需要提前定义 n变量和key_value,count变量

  1. void key_scan()  
  2. {  
  3.     P3=0xf0;P44=1;P42=1;  
  4.     if(P3!=0xf0||P44!=1||P42!=1)  
  5.     {  
  6.         Delay50ms();  
  7.         if(P3!=0xf0||P44!=1||P42!=1)  
  8.         {  
  9.             P3=0xf0;P44=1;P42=1;  
  10.             if(P44==0) n=0;                 //判断哪一列被拉低  
  11.             else if(P42==0) n=1;  
  12.             else if((P3&0X10)==0) n=3;  
  13.             else if((P3&0x20)==0) n=2;  
  14.       
  15.             P3=0x0F;P44=0;P42=0;            //行信号置零,列信号置一  
  16.             if((P3&0x01)==0) key_value =n;           //判断哪一行被拉低  
  17.             else if((P3&0x02)==0) key_value =n+4;  
  18.             else if((P3&0x04)==0) key_value =n+8;  
  19.             else if((P3&0x08)==0) key_value =n+12;  
  20.             count++;      //判断按键按下操作  
  21.             while(P3!=0x0F);       
  22.         }  
  23.     }  
  24. }  

3、 延时函数

延时函数可以通过软件直接生成精准延时,然后对其进行修改,这里的是一毫秒。通过形式参数可以实现调用不同时间的延时,因为延时会卡住单片机无法继续线下运行,因此中断中尽量少用。_nop_()需要引入同文件#include“intrins.h”。

  1. void Delay(unsigned int t)      //@11.0592MHz  
  2. {  
  3.     unsigned char i, j;  
  4.     for(;t>0;t--)  
  5.     {  
  6.         _nop_();  
  7.         _nop_();  
  8.         _nop_();  
  9.         i = 11;  
  10.         j = 190;  
  11.         do  
  12.         {  
  13.             while (--j);  
  14.         } while (--i);  
  15.     }  

4、 关闭外设

因为单片机初始化会默认所有引脚高电平,容易对外设产生影响,因此需要上电过乘进行外设的关闭。

  1. void cls_buzz(void) //关闭蜂鸣器,继电器等。  
  2. {  
  3.         P2=(P2&0X1F)|0XA0;   
  4.         P0=0x00;      
  5.         P2&=0X1F;    
  6. }  
  7.   
  8. void cls_led(void) //关闭led灯  
  9. {  
  10.     P2=(P2&0X1F)|0X80;     
  11.     P0=0XFF;     
  12.     P2 &= 0X1F;  
  13. }  
  14.   
  15. void cls_display(void)  //关闭数码管  
  16. {   
  17.     P2 = (P2&0x1F|0xC0);          
  18.     P0 = 0xff;   //关闭位选起消影作用  
  19.     P2 &= 0x1f;    

5、 流水灯

流水灯千变万化,为了适用各种流水灯的操作,这里编写了能过适用各种方式的流水灯。可以静态点灯调用也可以动态点灯调用。

  1. unsigned char led_flash[8]={0x80,0x40,0x20,0x10,0x08,0x40,0x02,0x01}//通过数组方法点灯  
  2. unsigned char led_num = 0;  
  3. void led_location(unsigned char Led_Mode,unsigned char Led_Num)  
  4. {  
  5.     P0=0xff;    //消隐  
  6.     P2=(P2&0x1f)|0x80;  
  7.     switch(Led_Mode)  
  8.     {  
  9.         case 0:P0=0xff;break;  
  10.         case 1:P0=~(0x01<<Led_Num);break;  
  11.         case 2:P0=~(0x80>>Led_Num);break;  
  12.         case 3:P0=led_flash[Led_Num];break;  
  13.         case 4:P0=0x00;break;  
  14.         case 5:P0=~0x80;break;  
  15.     }  
  16.     P2&=0x1f;  
  17. }  
  18. void led_flash_mode1() //模式1的方法闪烁流水灯将函数放入循环中  
  19. {  
  20.     if(led_flash_mode1_switch == 0xff)//led流水灯运行标志位  
  21.     {  
  22.         delay(500);//如果在中断中可以删除延迟,调节中断间隔。  
  23.         if(++led_num<8)  
  24.         {  
  25.             void led_location(1,led_num);  
  26.         }else  
  27.         {  
  28.             led_num=0;  
  29.         }  
  30.     }  
  31.       

6、按键功能处理

需要放在循环中

  1. void key_pro()  
  2. {  
  3.     if(count!=0)  
  4.     {  
  5.         count=0;  
  6.         switch(key_value)  
  7.         {  
  8.             case 1:led_flash_mode1_switch =~led_flash_mode1_switch;break;  
  9.             case 2:break;  
  10.             case 3:break;  
  11.         }  
  12.     }  

7、 数码管动态显示

动态显示就可以当作静态的功能,因此这里只用动态的方法。调用只需要对数组

  1. code unsigned char tab[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0X7f,0XFF}; //数码管显示数字表  
  2.  // 0    1    2     3    4    5    6    7    8    9    .   无     
  3.  // 0    1    2     3    4    5    6    7    8    9    10   11   
  4. unsigned char dspbuf[8] = {11,11,11,11,11,11,11,11};    
  5. unsigned char dspcom = 0;     
  6.   
  7. void display(void)  //数码管需要放入中断中扫描  
  8. {   
  9.     P0 = 0xff;  
  10.     P2 = (P2&0x1F|0xE0);      
  11.     P2 &= 0x1f;   
  12.       
  13.     P2 = (P2&0x1F|0xC0);              
  14.     P0 = (1<<dspcom);   
  15.     P2 = 0x1f;        
  16.       
  17.     P2 = (P2&0x1F|0xE0);          
  18.     P0 = tab[dspbuf[dspcom]];         
  19.     P2 = 0x1f;            
  20.       
  21.     if(++dspcom == 8)     
  22.     dspcom = 0;                                                                                                                                                                 //如
  23. }  

8、 中断函数

可以通过软件直接生成。

  1. void Timer0Init(void)       //1毫秒@11.0592MHz  
  2. {  
  3.     AUXR |= 0x80;       //定时器时钟1T模式  
  4.     TMOD &= 0xF0;       //设置定时器模式  
  5.     TL0 = 0xCD;     //设置定时初值  
  6.     TH0 = 0xD4;     //设置定时初值  
  7.     TF0 = 0;        //清除TF0标志  
  8.     TR0 = 1;        //定时器0开始计时  
  9.     ET0 = 1;  
  10.     EA = 1;  
  11. }  
  12. void T0time() interrupt 1  
  13. {  
  14.     display();  

9、 温度函数

温度函数为调用官方提供的onewire.h因为15芯片的时间要快12倍因此需要将延迟函数进行变慢12倍。然后加入读取温度函数。

  1. void Delay_OneWire(unsigned int t)  
  2. {  
  3.     unsigned char i;  
  4.   while(t--)  
  5.         for(i=0;i<12;i++);  
  6. }  
  7. unsigned char read_temper(void)  
  8. {  
  9.     unsigned char low,high,temp;  
  10.     Init_DS18B20();                 //初始化DS18B20  
  11.     Write_DS18B20(0xcc);            //跳过芯片ROM区  
  12.     Write_DS18B20(0x44);            //启动温度转换  
  13.     Delay_OneWire(200);             //延时  
  14.     Init_DS18B20();                 //重复初始化DS18B20  
  15.     Write_DS18B20(0xcc);            //跳过芯片ROM区  
  16.     Write_DS18B20(0xbe);            //开始读取温度暂存器中的值  
  17.     low=Read_DS18B20();             //读取温度低字节  
  18.     high=Read_DS18B20();            //读取温度高字节  
  19.     temp=low>>4|high<<4;            //去除符号位与小数位  
  20.     return temp;                     //返回温度  
  21. }  

10、 时间函数

调用官方提供的时间函数ds1302.h 然后添加两个函数,一个为涉资函数一个为读取函数。

  1. void Set_Ds1302(unsigned char* put_time)  
  2. {  
  3.     unsigned char temp;  
  4.     Write_Ds1302_Byte( 0x8e,0 );    //关闭写保护;  
  5.       
  6.     temp =((put_time[0]/10)<<4)|put_time[0]%10;  
  7.     Write_Ds1302_Byte( 0x84,temp);  //写入时 ;  
  8.     temp =((put_time[1]/10)<<4)|put_time[1]%10;  
  9.     Write_Ds1302_Byte( 0x82,temp);  //写入分 ;  
  10.     temp =((put_time[2]/10)<<4)|put_time[2]%10;  
  11.     Write_Ds1302_Byte( 0x80,temp);  //写入秒 ;  
  12.       
  13.     Write_Ds1302_Byte( 0x8e, 0x80 );    //开启写保护;  
  14.   
  15. }  
  16.   
  17. void red_Ds1302(unsigned char* put_time)  
  18. {  
  19.     unsigned char temp;  
  20.       
  21.     temp = Read_Ds1302_Byte ( 0x85 );   //读小时  
  22.     put_time[0]=((temp>>4)*10)+(temp&0x0f);  
  23.     temp = Read_Ds1302_Byte ( 0x83 );   //读分钟  
  24.     put_time[1]=((temp>>4)*10)+(temp&0x0f);  
  25.     temp = Read_Ds1302_Byte ( 0x81 );   //读秒钟  
  26.     put_time[2]=((temp>>4)*10)+(temp&0x0f);  
  27.       

11、存储函数

一般国赛才用到,具体方法也就是iic的方式。需要查看芯片手册编写程序

  1. #include "reg52.h"  //包含51单片机功能寄存器的头文件  
  2. #include "iic.h"        //包含IIC操作函数的头文件  
  3.   
  4. #define AT24C02_AddrW 0xA0  //宏定义AT24C02的写地址  
  5. #define AT24C02_AddrR 0xA1  //宏定义AT24C02的读地址  
  6.   
  7. void wirte_eeprom(unsigned char addr,unsigned char date)  
  8. {  
  9.     EA=0;                                                   //总中断关闭,防止打断IIC总线  
  10.     IIC_Start();                                    //启动总线  
  11.     IIC_SendByte(AT24C02_AddrW);    //进行寻址,写数据  
  12.     IIC_WaitAck();                              //等待应答  
  13.     IIC_SendByte(addr);                     //写入指定的存储单元  
  14.     IIC_WaitAck();                              //等待应答  
  15.     IIC_SendByte(date);                     //写入一字节数据  
  16.     IIC_WaitAck();                              //等待应答  
  17.     IIC_Stop();                                     //停止总线  
  18.     EA=1;                                                   //重新使能总中断  
  19. }  
  20.   
  21. unsigned char read_eeprom(unsigned char addr)  
  22. {  
  23.     unsigned char date;  
  24.     EA=0;                                                   //总中断关闭,防止打断IIC总线  
  25.     IIC_Start();                                    //启动总线  
  26.     IIC_SendByte(AT24C02_AddrW);    //进行寻址,写数据  
  27.     IIC_WaitAck();                              //等待应答  
  28.     IIC_SendByte(addr);                     //写入指定的存储单元  
  29.     IIC_WaitAck();                              //等待应答  
  30.     IIC_Start();                                    //重新启动总线  
  31.     IIC_SendByte(AT24C02_AddrR);    //进行寻址,读数据  
  32.     IIC_WaitAck();                              //等待应答  
  33.     date=IIC_RecByte();                     //读取一字节数据  
  34.     IIC_Ack(0);                                     //发送非应答  
  35.     IIC_Stop();                                     //停止总线  
  36.     EA=1;                                                   //重新使能总中断  
  37.     return date;                                    //返回date  

12、        数模函数

这里调用pcf8591也就是也是iic驱动带动。

  1. #include "iic.h"                            //包含IIC操作函数的头文件  
  2. #include "reg52.h"  
  3.   
  4. #define PCF8591_AddrW 0x90      //宏定义PCF8591的写地址  
  5. #define PCF8591_AddrR 0x91      //宏定义PCF8591的读地址  
  6. #define control_word 0x40           //宏定义PCF8591控制字  
  7. //允许模拟输出、四通道都为单端输入、不允许自动增量  
  8. unsigned char read_pcf8591(unsigned char AIN)  
  9. {  
  10.     unsigned char dat;  
  11.     EA=0;  
  12.     IIC_Start();                                        //启动总线  
  13.     IIC_SendByte(PCF8591_AddrW);        //进行寻址,写数据  
  14.     IIC_WaitAck();                                  //等待应答  
  15.     IIC_SendByte(control_word|AIN); //选中传入的通道  
  16.     IIC_WaitAck();                                  //等待应答  
  17.     IIC_Start();                                        //重复启动总线  
  18.     IIC_SendByte(PCF8591_AddrR);        //进行寻址,读数据  
  19.     IIC_WaitAck();                                  //等待应答,并启动A/D转换,开始传送第一字节  
  20.     IIC_RecByte();  //接收第一字节,为上一次的转换值,不是我们想要的,剔除此次数据  
  21.     IIC_Ack(1);                                         //发送应答信号  
  22.     dat=IIC_RecByte();                          //接送第二字节数据  
  23.     IIC_Ack(0);                                         //发送非应答信号,停止数据传送  
  24.     IIC_Stop();                                         //停止总线  
  25.     EA=1;  
  26.     return dat;                                         //返回AD值  
  27. }  
  28.   
  29.   
  30.   
  31. void write_pcf8591(unsigned char dat)  
  32. {  
  33.   EA=0;  
  34.   IIC_Start();                                            //启动总线  
  35.   IIC_SendByte(PCF8591_AddrW);            //进行寻址,写数据  
  36.   IIC_WaitAck();                                      //等待应答  
  37.   IIC_SendByte(control_word);             //控制为模拟输出  
  38.   IIC_WaitAck();                                      //等待应答  
  39.   IIC_SendByte(dat);                              //发送模拟数据  
  40.   IIC_WaitAck();                                      //等待应答  
  41.   IIC_Stop();                                             //停止总线  
  42.   EA=1;