蓝桥杯单片机大模板及头文件

 一、大模板

本模板基于以下两篇文章和西风老师讲解归纳而成,仅为比赛学习而用。如有侵权立删。

http://t.csdnimg.cn/ty2gP

http://t.csdnimg.cn/NqrAO

#include "reg52.h"
#include "ds1302.h"
#include "onewire.h"
#include "iic.h"

sfr P4    = 0xC0;

sbit A0 = P3^4;
sbit A1 = P3^5;
sbit A2 = P4^2;
sbit A3 = P4^4;

/*===================初始化函数======================*/
void System_Init()
{
	P0 = 0xff;//关闭数码管
	P2 = P2 & 0x1f | 0x80;
	P2 &= 0x1f;
	
	P0 = 0x00;//关闭蜂鸣器,继电器
	P2 = P2 & 0x1f | 0xa0;
	P2 &= 0x1f;
}

/*===================数码管======================*/

unsigned char Seg_Dula[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff};//段选 0~9+熄灭
unsigned char Seg_Wela[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};//位选

void Seg_Disp(unsigned char wela,dula,point)//数码管显示函数
{
  P0=0xff;//消隐
  P2=P2&0x1f|0xe0;
  P2&=0x1f;
	
  P0=Seg_Wela[wela];//位选
  P2=P2&0x1f|0xc0;
  P2&=0x1f;
	
  P0=Seg_Dula[dula];//段选
  if(point)
  {
    P0=Seg_Dula[dula] & 0x7f;
  }
  else
  {
	P0=Seg_Dula[dula];
  }
  P2=P2&0x1f|0xe0;
  P2&=0x1f;
}

/*===================按键======================*/

unsigned char Key4_Read(void) //独立按键读取函数
{
  unsigned char Key_temp;
	unsigned char Key_Value;
	
	P3 |= 0x0f;        //将P3低四位即独立按键接口拉高置为1
	Key_temp = P3&0x0f;//读取P3低四位I/O口的电平
	
	switch(Key_temp)//
	{
	    case 0x0e : Key_Value = 7; break;  //S7
		case 0x0d : Key_Value = 6; break;  //S6
		case 0x0b : Key_Value = 5; break;  //S5
		case 0x07 : Key_Value = 4; break;  //S4
		default: Key_Value = 0;
	}
	return Key_Value;
}

unsigned char Key16_Read(void)    
{
    unsigned int  Key_temp;
	unsigned char Key_Value;
	
	A3=0; 
	A2=1; 
	A1=1; 
	A0=1; 
	P3|=0X0F; 
	Key_temp = P3;                        
	
	A3=1; 
	A2=0; 
	A1=1; 
	A0=1; 
	P3|=0X0F;  
	Key_temp = (Key_temp<<4) | (P3&0X0F);  
	
	A3=1; 
	A2=1; 
	A1=0; 
	A0=1; 
	P3|=0X0F; 
	Key_temp = (Key_temp<<4) | (P3&0X0F); 
	
	A3=1; 
	A2=1; 
	A1=1; 
	A0=0; 
	P3|=0X0F; 
	Key_temp = (Key_temp<<4) | (P3&0X0F);  
	
	switch(~Key_temp)   
	{
        //第一列
		case 0X8000: Key_Value = 4; break;   //S4
		case 0X4000: Key_Value = 5; break;   //S5
		case 0X2000: Key_Value = 6; break;   //S6
		case 0X1000: Key_Value = 7; break;   //S7
		//第二列
		case 0X0800: Key_Value = 8; break;   //S8
		case 0X0400: Key_Value = 9; break;   //S9
		case 0X0200: Key_Value = 10; break;   //S10
		case 0X0100: Key_Value = 11; break;   //S11
		//第三列
		case 0X0080: Key_Value = 12; break;   //S12
		case 0X0040: Key_Value = 13; break;   //S13
		case 0X0020: Key_Value = 14; break;   //S14
		case 0X0010: Key_Value = 15; break;   //S15
		//第四列
		case 0X0008: Key_Value = 16; break;   //S16
		case 0X0004: Key_Value = 17; break;   //S17
		case 0X0002: Key_Value = 18; break;   //S18
		case 0X0001: Key_Value = 19; break;   //S19
		
		default: Key_Value = 0;  
	}
	return Key_Value;
}

/*===================LED亮灭======================*/

unsigned char ucLed[8]={0,0,0,0,0,0,0,0};

void Led_Disp(unsigned char addr,enable)
{
	static unsigned char temp;
	static unsigned char temp_old;
	if(enable)
		temp |= 0x01 << addr;
	else
		temp &= ~(0x01 << addr);
	if(temp != temp_old)
	{
		P0 = ~temp;
		P2 = P2 & 0x1f | 0x80;
		P2 &= 0x1f;
		temp_old = temp;
	}
}
 
void Beep(unsigned char enable)//蜂鸣器
{
	static unsigned char temp;
	static unsigned char temp_old;
	
	if(enable)
	{
		temp |= 0x40;
	}
	else
	{
		temp &= ~0x40;
	}
	if(temp != temp_old)
	{
		P0 = temp;
		P2 = (P2 & 0x1f) | 0xa0;
		P2 = P2 & 0x1f;
		temp_old = temp;
	}
}

void Relay(unsigned char enable)//继电器
{
	static unsigned char temp;
	static unsigned char temp_old;
	
	if(enable)
	{
		temp |= 0x10;
	}
	else
	{
		temp &= ~0x10;
	}
	if(temp != temp_old)
	{
		P0 = temp;
		P2 = (P2 & 0x1f) | 0xa0;
		P2 = P2 & 0x1f;
		temp_old = temp;
	}
}
/*===================DS18B20温度======================*/
 
float Temp_Read()//读取温度
{
	unsigned char low,high;
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0x44);
 
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0xbe);
	low=Read_DS18B20();
	high=Read_DS18B20();
	
	return (high<<8|low)/16.0;
}

/*===================DS1302时钟======================*/

//控制时分秒

unsigned char ucRtc[3] = {0x23,0x59,0x55};//时钟显示数组,时分秒
unsigned char unDat[3] = {0x22,0x12,0x31};//年月日

void Set_Rtc(unsigned char* ucRtc)//设置闹钟数据,将时钟显示数组中的数据写入
{
	unsigned char i;
	Write_Ds1302_Byte(0x8e,0x00);
	for(i=0;i<3;i++)
	 Write_Ds1302_Byte(0x84-2*i,ucRtc[i]);		
	Write_Ds1302_Byte(0x8e,0x80);	
}

void Get_Rtc(unsigned char* ucRtc)//读取闹钟数据,存放在时钟显示数组中
{                                 
	unsigned char i;
	for(i=0;i<3;i++)
	 ucRtc[i]=Read_Ds1302_Byte(0x85-2*i);		
}

void Set_Dat(unsigned char* ucDat)//设置日期,年月日
{
	Write_Ds1302_Byte(0x8e,0);
	Write_Ds1302_Byte(0x8c,ucDat[0]);
	Write_Ds1302_Byte(0x88,ucDat[1]);
	Write_Ds1302_Byte(0x86,ucDat[2]);
	Write_Ds1302_Byte(0x8e,1);	
}

void Read_Date(unsigned char* ucDat)//读取日期,年月日
{
	ucDate[0] = Read_Ds1302_Byte(0x8d);
	ucDate[1] = Read_Ds1302_Byte(0x89);
	ucDate[2] = Read_Ds1302_Byte(0x87);
}

/*===================PCF8591======================*/
void Da_Wirte(unsigned char dat)
{
	I2CStart();
	I2CSendByte(0x90);
	I2CWaitAck();
	I2CSendByte(0x41);
	I2CWaitAck();
	I2CSendByte(dat);
	I2CWaitAck();	
	I2CStop();
}

unsigned char Ad_Read(unsigned char addr)
{
	unsigned char temp;
	I2CStart();
	I2CSendByte(0x90);
	I2CWaitAck();
	I2CSendByte(addr);
	I2CWaitAck();
	
	I2CStart();
	I2CSendByte(0x91);
	I2CWaitAck();
	temp=I2CReceiveByte();
	I2CSendAck(1);
	I2CStop();	
	return temp;
}

/*===================EEPROM======================*/

void EEPROM_Write(unsigned char* EEPROM_String,unsigned char addr,num)//页写入
{
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(addr);
	I2CWaitAck();
	while(num--)
	{
		I2CSendByte(*EEPROM_String++);
		I2CWaitAck();
		I2C_Delay(200);
	}
	I2CStop();
}
 
void EEPROM_Read(unsigned char* EEPROM_String,unsigned char addr,num)//读取
{
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(addr);
	I2CWaitAck();
	
	I2CStart();
	I2CSendByte(0xa1);
	I2CWaitAck();	
	while(num--)
	{
		*EEPROM_String++=I2CReceiveByte();
		if(num) I2CSendAck(0);
		I2CSendAck(1);
	}
	I2CStop();
}

/*===================预备变量======================*/

unsigned char Key_Val,Key_Down,Key_Old,Key_Up;//按键专用变量
unsigned char Key_Slow_Down;//按键减速专用变量
unsigned char Seg_Buf[8] = {10,10,10,10,10,10,10,10};//数码管显示数组
unsigned char PointShow[8] = {0,0,0,0,0,0,0,0};//小数点显示数组
unsigned char Seg_Pos;//数码管扫描专用变量
unsigned int Seg_Slow_Down;//数码管减速专用变量

/*===================功能函数======================*/

void Key_Proc()//按键处理函数
{
	if(Key_Slow_Down) return;
	Key_Slow_Down = 1;

	Key_Val = Key16_Read();
	Key_Down = Key_Val & (Key_Old ^ Key_Val);
    Key_Up = ~Key_Val & (Key_Old ^ Key_Val);
	Key_Old = Key_Val;//按键消抖
    switch(Key_Down)
    {
       case 4:
       //当写入数据为数组时,中间变量务必是8的倍数,最后变量为写入数据长度
       EEPROM_Write(dat,0,2);
       //当写入数据为变量时
       EEPROM_Write(&a,8,1);
       break;
    }
}

void Seg_Proc()//数码管显示函数
{
	if(Seg_Slow_Down) return;
	Seg_Slow_Down = 1;//数码管显示减速
    
    /*
    Da_Write(51*0.4);//0.4V写入
    */
    /*
    //读取温度显示
    temp=Temp_Read();
	Seg_Buf[4]=(unsigned char)temp/10%10;//十位
	Seg_Buf[5]=(unsigned char)temp%10;//个位
	Seg_Buf[6]=(unsigned int)(temp*100)/10%10;//小数位第一位
	Seg_Buf[7]=(unsigned int)(temp*100)%10;//小数位第二位
	Seg_Point[5]=1;//个位小数点
    */

    /*
    //读取电压
    //d_val为float类型
	d_val=Ad_Read(0x43)/51.0;	//0x43为光敏,0x41为电阻,/51.0为数据转换
	Seg_Point[5]=1;
	Seg_Buf[5]=(unsigned char)d_val%10;//个位
	Seg_Buf[6]=(unsigned int)(d_val*100)/10%10;//小数位第一位
	Seg_Buf[7]=(unsigned int)(d_val*100)%10;//小数位第二位
    */

}

void Led_Proc()//LED处理函数
{

}

/*===================定时器0计数器======================*/
void Timer0_Init(void)		
{			
	TMOD &= 0xF0;			
	TMOD |= 0x05;
	TL0 = 0;				
	TH0 = 0;				
	TF0 = 0;				
	TR0 = 1;				
}

/*===================定时器1中断======================*/
void Timer1_Init(void)		
{	
    TMOD &= 0x0F; 
    TL1 = (65535 - 1000)%256;	
	TH1 = (65535 - 1000)/256;  
    TF1 = 0;      
    TR1 = 1;      
    ET1 = 1;      
    EA = 1;     
}
unsigned int freq;
unsigned int time_1s;
          
void Timer1Server() interrupt 3//定时器0终端服务函数
{	
	if(++Key_Slow_Down == 10) Key_Slow_Down = 0;//10ms按键减速
	if(++Seg_Slow_Down == 500) Seg_Slow_Down = 0;//500ms数码管减速
	if(++Seg_Pos == 8) Seg_Pos = 0;//数码管扫描
	Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos],PointShow[Seg_Pos]);//数码管扫描
    Led_Disp(Seg_Pos,ucLed[Seg_Pos]);//LED扫描
    
    if (++time_1s == 1000)//频率读取
    {
        TR0 = 0;
        time_1s = 0;
        freq = TH0 << 8 | TL0;
        TH0 = 0;
        TL0 = 0;
        TR0 = 1;
    }

}

 
void Delay750ms(void)	//@12.000MHz
{
	unsigned char data i, j, k;

	i = 35;
	j = 51;
	k = 182;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

/*===================主函数======================*/
void main()
{
    Temp_Read();
    Delay750ms();//消除温度默认85显示
    System_Init();
    Timer0Init();
    Set_Rtc(ucRtc);
	while (1)
	{
		Key_Proc();
		Seg_Proc();
		Led_Proc();
	}
}

二、头文件 

DS1302

#ifndef __DS1302_H
#define __DS1302_H

#include <reg52.h>
#include <intrins.h>

sbit SCK = P1^7;		
sbit SDA = P2^3;		
sbit RST = P1^3; 

void Write_Ds1302(unsigned char temp);
void Write_Ds1302_Byte( unsigned char address,unsigned char dat );
unsigned char Read_Ds1302_Byte( unsigned char address );

#endif

IIC 

#ifndef __IIC_H
#define __IIC_H

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

sbit sda = P2^1;
sbit scl = P2^0;

static void I2C_Delay(unsigned char n);
void I2CStart(void);
void I2CStop(void);
void I2CSendByte(unsigned char byt);
unsigned char I2CReceiveByte(void);
unsigned char I2CWaitAck(void);
void I2CSendAck(unsigned char ackbit);

#endif

ONEWIRE 

#ifndef __ONEWIRE_H
#define __ONEWIRE_H

#include "reg52.h"

sbit DQ = P1^4;  

void Delay_OneWire(unsigned int t);
void Write_DS18B20(unsigned char dat);
unsigned char Read_DS18B20(void);
bit init_ds18b20(void);

#endif

三、重点操作

1、温度读取

	//temp为float类型
	temp=Temp_Read();
	Seg_Buf[4]=(unsigned char)temp/10%10;//十位
	Seg_Buf[5]=(unsigned char)temp%10;//个位
	Seg_Buf[6]=(unsigned int)(temp*100)/10%10;//十分位
	Seg_Buf[7]=(unsigned int)(temp*100)%10;//百分位
	Seg_Point[5]=1;//小数点

    //整数读取
    temp=(unsigned char)Temp_Read();

2、电压读取

	//d_val为float类型
	d_val=Ad_Read(0x43)/51.0;	//0x43为光敏,0x41为电阻,/51.0为数据转换
	Seg_Point[5]=1;
	Seg_Buf[5]=(unsigned char)d_val%10;	
	Seg_Buf[6]=(unsigned int)(d_val*100)/10%10;
	Seg_Buf[7]=(unsigned int)(d_val*100)%10;

 3、写入电压

//写入0.4V,需要*51进行数据转换
Da_Write(51*0.4);

4、写入EEPROM

 
//当写入数据为数组时,中间变量务必是8的倍数,最后变量为写入数据长度
EEPROM_Write(dat,0,2);
//当写入数据为变量时
EEPROM_Write(&a,8,1);

5、读取EEPROM 

 
//当写入数据为数组时,中间变量务必是8的倍数,最后变量为写入数据长度
EEPROM_Write(dat,0,2);
//当写入数据为变量时
EEPROM_Write(&a,8,1);

6、参数设置

unsigned char Seg_Disp[] = {20,30,50};
unsigned char Seg_Ctrol[] = {20,30,50};
unsigned char Seg_Mode;//0-显示 1-参数设置 2-其他界面

void Key_Proc()
{
  if(Key_Slow_Down)return;
  Key_Slow_Down = 1;

  switch(Key_Down)
  {
     case 4://界面切换按键
     if(++Seg_Mode == 3)Seg_Mode  = 0;
     if(Seg_Mode == 1)//处于参数设置界面
     {
        Seg_Disp[0] = Seg_Ctrol[0];
        Seg_Disp[1] = Seg_Ctrol[1];
        Seg_Disp[2] = Seg_Ctrol[2];
     }
     if(Seg_Mode == 2)//参数设置界面切出后
     {
        Seg_Ctrol[0] = Seg_Disp[0];
        Seg_Ctrol[1] = Seg_Disp[1];
        Seg_Ctrol[2] = Seg_Disp[2];
     }
    break;
  }
}

7、加减按键

unsigned char temp[] = {0,0,0}
unsigned char temp_index;

void Key_Proc()
{
  if(Key_Slow_Down)return;
  Key_Slow_Down = 1;

  switch(Key_Down)
  {
     case 6://加
     if(++temp[temp_index] == 100)
     temp[index] = 99;
     break;
     case 7://减
     if(--temp[temp_index] == 255)
     temp[index] = 0;
     break;
  }
}

8、LED互斥点亮

unsigned char ucLed[] = {0,0,0,0,0,0,0,0};
unsigned char Seg_Disp_Mode;//0,1,2

for(i=0;i<3;i++)
{
   ucLed[i] = (i == Seg_Disp_Mode);
}

9、数码管高位熄灭

unsigned char i = 3;//从第四位开始检测
while(Seg_Buf[i] == 0)
{
  Seg_Buf[i] = 10;
  if(++i == 7)break;//保留最后一位零显示
}

10、数码管定时闪烁

bit Seg_Flag;
unsigned int time_1s;

void Seg_Proc()
{
   if(Seg_Slow_Down)return;
   Seg_Slow_Down = 1;
   
   switch(Seg_Disp_Mode)
   {
     case 0:
     Seg_Buf[0] = temp/100%10;
     Seg_Buf[1] = temp/10%10;
     Seg_Buf[2] = temp%10;
     if(Seg_Index == 0)
       Seg_Buf[0] = Seg_Flag?temp/100%10:10;
       Seg_Buf[1] = Seg_Flag?temp/10%10:10;
       Seg_Buf[2] = Seg_Flag?temp%10:10;
     }
     break;
   }
}

void Timer1_Init(void)		//100微秒@12.000MHz
{		
	TMOD &= 0x0F;			//设置定时器模式
	TL1 = 0x20;				//设置定时初始值
	TH1 = 0xD1;
	TF1 = 0;				//清除TF1标志
	TR1 = 1;				//定时器1开始计时
    ET1 = 1;
    EA = 1;
}

void Timer1Server()interrupt 3
{
   if(++Seg_Slow_Down == 500)Seg_Slow_Down  = 0;
   if(++time_1s == 1000)
   {
     time_1s  = 0;
     Seg_Flag = ~Seg_Flag;
   }
   
}

11、彩灯闪烁(第九届省赛)

void Led_Proc()
{
	unsigned char i;
	if(System_Flag == 1)
	{
		if(Ms_Tick == Led_Time_Ctrol[Led_Mode])
		{
			Ms_Tick = 0;
			switch(Led_Mode)
			{
				case 0:
					if(++Led_Pos == 8)
					{
						Led_Pos = 7;
						Led_Mode = 1;
					}
				break;
				case 1:
					if(--Led_Pos == 255)
					{
						Led_Pos = 7;
						Led_Mode = 2;
					}
				break;
				case 2:
					Led_Pos += 9;
					if(Led_Pos > 34)
					{
						Led_Pos = 34;
						Led_Mode = 3;
					}
				break;
				case 3:
					Led_Pos -= 9;
					if(Led_Pos > 200)
					{
						Led_Pos = 0;
						Led_Mode = 0;
					}
				break;
			}
		}
	}
	
	if(Led_Mode < 2)
	{
		for(i=0;i<8;i++)
			ucLed[i] = (i == Led_Pos);
	}
	else
	{
		for(i=0;i<8;i++)
			ucLed[i] = (i == (Led_Pos / 10) || i == (Led_Pos % 10));
	}
}

12、按键长短按

void Key_Proc()
{
  if(Key_Slow_Down)return;
  Key_Slow_Down = 1;

  Key_Val = Key16_Read();
  Key_Down = Key_Val & (Key_Val ^ Key_Old);
  Key_Old = Key_Val;

	if(Key_Down == 12 || Key_Down == 13)	//假设按键12、13
		Key_Flag = 1;
	
	if(Timer_1000Ms < 1000 && Key_Flag == 1) //短按
	{
		switch(Key_Up)
		{
			case 12:	//短按12
            Timer_1000Ms = Key_Flag = 0; 
			break;
			case 13:	//短按13
            Timer_1000Ms = Key_Flag = 0;    
			break;
		}
	}
	else //长按
	{
		switch(Key_Old)
		{
			case 12:
            Timer_1000Ms = Key_Flag = 0;
			break;
			case 13:
            Timer_1000Ms = Key_Flag = 0;    
			break;
		}
	}
}

   //中断函数写
   if(Key_Flag)Timer_1000Ms++;

13、AD电压分等级

unsigned char Level;

Level = Ad_Read(0x43)/64;//64 = 256/4 电压读取分为四个等级

14、PWM控制LED亮度

void Timer1Server()interrupt 3
{
  if(++Led_Count == 12)Led_Count = 0;
  if(Led_Count <= (Led_Level+1)*3 )
    Led_Disp(Seg_Pos,ucLed[Seg_Pos]);
  else
    Led_Disp(Seg_Pos,0);
}

  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值