51单片机-DS18B20(温度传感器)&AT24C02(存储芯片) & IIC通信-实验2-温度实时监测(可设置阈值)

作者:王开心

座右铭:刻苦专研,百折不挠,千磨万击还坚韧,任尔东西南北风!干就完了!(可交流技术)

主要利用DS18B20芯片去采集温度,通过采集的温度能够自动保存上一次温度值,在设置几个按键对温度阈值进行设置,最后可以检测温度变化,可通过蜂鸣器产生报警提示,温度显示可以在LCD1602中显示。

实验现象:

51单片,自动报警器

代码整合可参考(主页代码标题章节)(.h文件自己加)(工程文件最后免费共享)

main.c

#include <REGX52.H>
#include "LCD1602.h"
#include "DS18B20.h"
#include "Delay.h"
#include "AT24C02.h"
#include "IIC.h"
#include "Key.h"
#include "Buzzer.h"
#include "Timer0.h"

/*
本程序需要注意,当定时器不断的去扫描按键的时候,会打断我们的延时函数,这就是为什么程序在定时器内尽量少使用延时函数
*/


float T, TShow;
char TL,TH; //阈值高和低
unsigned KeyNum;
unsigned char KeyNm,TimeSetFlashFlag;




void main(void)
{
	DS18B20_ConvertTemperature();
	Delay_Any(1000);	
	
	TH = AT24C02_ReadByte(0); 
	TL = AT24C02_ReadByte(1);
	if(TH>125 || TL<-55 ||TH<=TL)
	{
		TH = 20;
		TL = 15;
	}
	
	
	LCD_Init();  //LCD1602初始化
	Timer0_Init(); //定时器扫描按键
	LCD_ShowString(1,1,"T:");
	LCD_ShowString(2,1,"TH:");
	LCD_ShowString(2,9,"TL:");
	while(1)
	{
		//温度读取及显示
		DS18B20_ConvertTemperature();
		T = DS18B20_ReadTemperature();
		if(T<0)
		{
			LCD_ShowChar(1,3,'-');//温度正负号
			TShow = -T;
		}
		else
			LCD_ShowChar(1,3,'+');
			TShow = T;
		
		LCD_ShowNum(1,4,T,3); //显示温度整数部分
		LCD_ShowChar(1,7,'.'); //显示小数点
		LCD_ShowNum(1,8,(unsigned long)(T*100)%100,2); //显示小数部分,保留两位小数,最后,一定要类型转化
		
	
		
		//阈值判断及显示
		KeyNum = Key();  //按键设置阈值
		if(KeyNum)
		{
			if(KeyNum == 1)
			{
				TH++;
				Buzzer_Key();
				if(TH>125)
				{
					TH = 125;
				}
			}

			if(KeyNum == 2)
			{
				TH--;
				if(TH <= TL)
				{
					TH++;
				}
				Buzzer_Key();
			}

			if(KeyNum == 3)
			{
				TL++;
				if(TL >= TH)
				{
					TL--;
				}
				Buzzer_Key();
			}

			if(KeyNum == 4)
			{
				TL--;
				if(TL<-55)
				{
					TL = -55;
				}
				Buzzer_Key();
			}
		}
		
		if(T > TH)
		{
			LCD_ShowString(1,12,"T:H!!");
		
			if(TimeSetFlashFlag == 1)
				LCD_ShowString(1,12,"T:   ");
		
			Buzzer_Siren();
		}
		else if(T < TL)
		{
			LCD_ShowString(1,12,"T:L!!");
			
			if(TimeSetFlashFlag == 1)
				LCD_ShowString(1,12,"T:   ");
			
			Buzzer_Siren();
		}
		
		else
		{
			LCD_ShowString(1,12,"T: NC ");
		}
		
		LCD_ShowSignedNum(2,4,TH,3);
		LCD_ShowSignedNum(2,12,TL,3);
		
		//将数据存储在存储芯片中AT24C02  ,0-255个地址
		AT24C02_WriteByte(0,TH);  //
		Delay_Any(5); //写入数据必须延时5毫秒
		AT24C02_WriteByte(1,TL);
		Delay_Any(5); //写入数据必须延时5毫秒
		
		
			
		
	}
}





//定时器中断函数

void Timer0_Rountine(void)  interrupt 1
{
	static unsigned int T0Count ,T0Count1;  //Timer0_Rountine(void) 函数结束之后T0Count保留其原来的值
	
	TL0 = 0x66;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	
	T0Count++;
	
	if(T0Count >= 5)
	{
		
		TimeSetFlashFlag = !TimeSetFlashFlag;
		T0Count = 0;
		Key_Loop(); //每隔20毫秒,定时器扫描一下
		
	}	
	
	T0Count1++;
	
	if(T0Count1 >= 1000)
	{	
		T0Count1 = 0;
		TimeSetFlashFlag = !TimeSetFlashFlag;		
	}	
	
}

DS18B20.c

#include <REGX52.H>
#include "OneWire.h"

//DS18B20 程序使用的寄存器进行红宏定义
#define SKIP_ROM			0XCC	//ROM指令 跳过ROM ,相当于直接访问DS18B20
#define CONVERT_T			0X44   //功能指令 温度转换
#define READ_SCRATCHPAD		0XBE  //功能指令  暂存器


//温度转换函数 :初始化→跳过ROM →开始温度变换

void DS18B20_ConvertTemperature(void)
{
	OneWire_Init();
	OneWire_SendByte(SKIP_ROM); //跳过ROM,写入一个字节数据,说我要读取温度
	OneWire_SendByte(CONVERT_T); //发送一个字节,让DS18B20开始温度转化
	
}


//温度读取:初始化→跳过ROM →读暂存器→连续的读操作
float DS18B20_ReadTemperature(void)
{
	unsigned char TLSB, TMSB;
	int Temp;
	float T;
	OneWire_Init();//初始化
	OneWire_SendByte(SKIP_ROM);
	OneWire_SendByte(READ_SCRATCHPAD); //跳过ROM,写入一个字节数据,说我要读取温度
	TLSB = OneWire_ReceiveByte();
	TMSB = OneWire_ReceiveByte();
	
	Temp = (TMSB<<8) | TLSB;
	
	T = Temp/16.0;
	return T;


}

Delay.c

#include <REGX52.H>
#include "intrins.h"



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

	_nop_();
	i = 2;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
}





void Delay70us()		//@11.0592MHz
{
	unsigned char i;

	_nop_();
	i = 29;
	while (--i);
}


void Delay_Any(unsigned int xms)		//@11.0592MHz
{
	unsigned char i, j;
	
	while(xms--)
	{
		_nop_();
		i = 2;
		j = 199;
		do
		{
			while (--j);
		} while (--i);
	}
}


void Delay10us()		//@11.0592MHz
{
	unsigned char i;

	i = 2;
	while (--i);
}


void Delay50us()		//@11.0592MHz
{
	unsigned char i;

	_nop_();
	i = 20;
	while (--i);
}


void Delay5us()		//@11.0592MHz
{
}

LCD1602.c

#include <REGX52.H>

//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0

//函数定义:
/**
  * @brief  LCD1602延时函数,12MHz调用可延时1ms
  * @param  无
  * @retval 无
  */
void LCD_Delay()
{
	unsigned char i, j;

	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
}

/**
  * @brief  LCD1602写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void LCD_WriteCommand(unsigned char Command)
{
	LCD_RS=0;
	LCD_RW=0;
	LCD_DataPort=Command;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void LCD_WriteData(unsigned char Data)
{
	LCD_RS=1;
	LCD_RW=0;
	LCD_DataPort=Data;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602设置光标位置
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @retval 无
  */
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
	if(Line==1)
	{
		LCD_WriteCommand(0x80|(Column-1));
	}
	else if(Line==2)
	{
		LCD_WriteCommand(0x80|(Column-1+0x40));
	}
}

/**
  * @brief  LCD1602初始化函数
  * @param  无
  * @retval 无
  */
void LCD_Init()
{
	LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
	LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
	LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
	LCD_WriteCommand(0x01);//光标复位,清屏
}

/**
  * @brief  在LCD1602指定位置上显示一个字符
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的字符
  * @retval 无
  */
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
	LCD_SetCursor(Line,Column);
	LCD_WriteData(Char);
}

/**
  * @brief  在LCD1602指定位置开始显示所给字符串
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串
  * @retval 无
  */
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=0;String[i]!='\0';i++)
	{
		LCD_WriteData(String[i]);
	}
}

/**
  * @brief  返回值=X的Y次方
  */
int LCD_Pow(int X,int Y)
{
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++)
	{
		Result*=X;
	}
	return Result;
}

/**
  * @brief  在LCD1602指定位置开始显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~65535
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以有符号十进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-32768~32767
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
	unsigned char i;
	unsigned int Number1;
	LCD_SetCursor(Line,Column);
	if(Number>=0)
	{
		LCD_WriteData('+');
		Number1=Number;
	}
	else
	{
		LCD_WriteData('-');
		Number1=-Number;
	}
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以十六进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xFFFF
  * @param  Length 要显示数字的长度,范围:1~4
  * @retval 无
  */
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i,SingleNumber;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		SingleNumber=Number/LCD_Pow(16,i-1)%16;
		if(SingleNumber<10)
		{
			LCD_WriteData(SingleNumber+'0');
		}
		else
		{
			LCD_WriteData(SingleNumber-10+'A');
		}
	}
}

/**
  * @brief  在LCD1602指定位置开始以二进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
	}
}

OneWire.c

#include <REGX52.H>
#include "Delay.h"
#include "Timer0.h"


sbit OneWire_DQ = P3^7; //单总线的管脚定义

//编写5个函数 初始化、写一位、读一位、写一个字节、读一个字节



//初始化:主机将总线拉低至少480us,然后释放总线,等待15~60us后,存在的从机会拉低总线60~240us以响应主机,之后从机将释放总线

unsigned char OneWire_Init(void)
{
	
	unsigned char AckBit,i;
	
	EA = 0 ; //定时器关闭(因为这个函数里面有延时函数,会和定时器扫描按键时产生冲突) 延时过程中防止被中断打断
	
	OneWire_DQ = 1; //保证拉低之前是高电平
	OneWire_DQ = 0; //拉低
	Delay1ms();//延时1ms ,至少480us
	OneWire_DQ = 1;  //释放
	Delay70us();
	AckBit = OneWire_DQ; //应答位:存在的从机会拉低总线60~240us以响应主机
	Delay1ms();//延时1ms ,至少480us
	
	EA = 1 ;  //定时器打开
	
	return AckBit;
	
}


//写一位数据,即主机51发送一位:主机将总线拉低60~120us,然后释放总线,表示发送0;主机将总线拉低1~15us,
//然后释放总线,表示发送1。从机将在总线拉低30us后(典型值)读取电平,整个时间片应大于60us

void OneWire_SendBit(unsigned char Bit)
{
	//EA = 0 ; //定时器关闭(因为这个函数里面有延时函数,会和定时器扫描按键时产生冲突) 延时过程中防止被中断打断
	OneWire_DQ = 0; //拉低
	Delay10us();
	OneWire_DQ = Bit; //10us 将数据放到总线上,主机写,
	Delay50us();
	OneWire_DQ = 1;  //释放
	//EA = 1 ;  //定时器打开
}


//接收一位:即主机51读取一位:主机将总线拉低1~15us,然后释放总线,并在拉低后15us内读取总线电平(尽量贴近15us的末尾),
//读取为低电平则为接收0,读取为高电平则为接收1 ,整个时间片应大于60us
unsigned char OneWire_ReadBit(void)
{
	unsigned char Bit;
	EA = 0 ; //定时器关闭(因为这个函数里面有延时函数,会和定时器扫描按键时产生冲突) 延时过程中防止被中断打断
	OneWire_DQ = 0; //拉低
	Delay5us();
	OneWire_DQ = 1;  //释放
	Delay5us();
	Bit = OneWire_DQ;  //数据放到总线上,主机读
	Delay50us();
	
	return Bit;
	
	EA = 1 ;  //定时器打开
		
}

//发送一个字节:连续调用8次发送一位的时序,依次发送一个字节的8位(低位在前)
void OneWire_SendByte(unsigned char Byte)
{
	
	
	unsigned char i;
	EA = 0 ; //定时器关闭(因为这个函数里面有延时函数,会和定时器扫描按键时产生冲突) 延时过程中防止被中断打断
	
	for(i=0; i<8; i++)
	{
		OneWire_SendBit(Byte & (0X01 << i));
	}
	
	EA = 1 ;  //定时器打开
}

//接收一个字节:连续调用8次接收一位的时序,依次接收一个字节的8位(低位在前)

unsigned char OneWire_ReceiveByte(void)
{
	
	//中断先执行变量赋初值操作,再关闭定时器中断
	unsigned char i, Byte = 0X00;
	EA = 0 ; //定时器关闭(因为这个函数里面有延时函数,会和定时器扫描按键时产生冲突) 延时过程中防止被中断打断
	
	for(i=0; i<8; i++)
	{
		if(OneWire_ReadBit())
		{
			Byte |= (0x01<<i);
		}
	}
		
	return Byte;
	EA = 1 ;  //定时器打开
}






//#include <REGX52.H>

引脚定义
//sbit OneWire_DQ=P3^7;

///**
//  * @brief  单总线初始化
//  * @param  无
//  * @retval 从机响应位,0为响应,1为未响应
//  */
//unsigned char OneWire_Init(void)
//{
//	unsigned char i;
//	unsigned char AckBit;
//	OneWire_DQ=1;
//	OneWire_DQ=0;
//	i = 247;while (--i);		//Delay 500us
//	OneWire_DQ=1;
//	i = 32;while (--i);			//Delay 70us
//	AckBit=OneWire_DQ;
//	i = 247;while (--i);		//Delay 500us
//	return AckBit;
//}

///**
//  * @brief  单总线发送一位
//  * @param  Bit 要发送的位
//  * @retval 无
//  */
//void OneWire_SendBit(unsigned char Bit)
//{
//	unsigned char i;
//	OneWire_DQ=0;
//	i = 4;while (--i);			//Delay 10us
//	OneWire_DQ=Bit;
//	i = 24;while (--i);			//Delay 50us
//	OneWire_DQ=1;
//}

///**
//  * @brief  单总线接收一位
//  * @param  无
//  * @retval 读取的位
//  */
//unsigned char OneWire_ReceiveBit(void)
//{
//	unsigned char i;
//	unsigned char Bit;
//	OneWire_DQ=0;
//	i = 2;while (--i);			//Delay 5us
//	OneWire_DQ=1;
//	i = 2;while (--i);			//Delay 5us
//	Bit=OneWire_DQ;
//	i = 24;while (--i);			//Delay 50us
//	return Bit;
//}

///**
//  * @brief  单总线发送一个字节
//  * @param  Byte 要发送的字节
//  * @retval 无
//  */
//void OneWire_SendByte(unsigned char Byte)
//{
//	unsigned char i;
//	for(i=0;i<8;i++)
//	{
//		OneWire_SendBit(Byte&(0x01<<i));
//	}
//}

///**
//  * @brief  单总线接收一个字节
//  * @param  无
//  * @retval 接收的一个字节
//  */
//unsigned char OneWire_ReceiveByte(void)
//{
//	unsigned char i;
//	unsigned char Byte=0x00;
//	for(i=0;i<8;i++)
//	{
//		if(OneWire_ReceiveBit()){Byte|=(0x01<<i);}
//	}
//	return Byte;
//}

AT24C02.c

#include <REGX52.H>
#include "IIC.h"

#define AT24C02_ADDRESS 0XA0 //1010 0000 前四位AT24C02地址不变,最后一位决定是写还是读 1:读,即接收 0:写,即发送


//仿照帧格式去写(可参考上一节IIC时序介绍)
//字节写:在WORD ADDRESS处写入数据DATA
void AT24C02_WriteByte(unsigned char WordAddress,Data)
{

	IIC_Start();  //起始信号
	IIC_SendByte(AT24C02_ADDRESS); //发送从机地址和写操作
	IIC_ReceiveAck();  //接收应答位
	IIC_SendByte(WordAddress); //字地址:指定在WORD ADDRESS处写入数据DATA
	IIC_ReceiveAck();  //接收应答位
	IIC_SendByte(Data); //写入数据到WordAddress中
	IIC_ReceiveAck(); //接收应答位
	IIC_Stop();//结束信号
	
}



//Ack : 0:表示应答 1:表示非应答
//随机读:读出在WORD ADDRESS处的数据DATA
unsigned char AT24C02_ReadByte(unsigned char WordAddress)
{
	unsigned char Data;
	
	//写操作,就是先找到要通信的从机
	IIC_Start();  //起始信号
	IIC_SendByte(AT24C02_ADDRESS); //发送从机地址和写操作
	IIC_ReceiveAck();  //接收应答位
	IIC_SendByte(WordAddress); //字地址:指定在WORD ADDRESS处写入数据DATA
	IIC_ReceiveAck();  //接收应答位
	
	//找到对应的从机之后,开始接收从机发过来的数据
	IIC_Start();  //起始信号
	IIC_SendByte(AT24C02_ADDRESS | 0X01); //发送从机地址和读操作
	IIC_ReceiveAck();  //接收应答位
	Data = IIC_ReceiveByte();  //接收一个字节的数据
	IIC_SendAck(1); 
	IIC_Stop();//结束信号
	
	
	return Data;
}

IIC.c

#include <REGX52.H>


//位声明 ,两根线定义在单片机的管脚,也就是说SCL接在P2^1管脚,SDA接在P2^0管脚,
sbit IIC_SCL = P2^1;
sbit IIC_SDA = P2^0;


//IIC的6个基本函数(符合IIC时序的基本操作,软件模拟IIC,让AT24C02继承于IIC,后期直接调用即可,无需关注底层细节,其实这个就是IIC的驱动)

//起始函数
void IIC_Start(void)
{
	
	//起始条件:SCL高电平期间,SDA从高电平切换到低电平
	IIC_SDA = 1;  //先保证SDA处于高电平状态	
	IIC_SCL = 1; 
	IIC_SDA = 0;
	IIC_SCL = 0; 	
	
}

//终止函数
void IIC_Stop(void)
{
	
	
	//终止条件:SCL高电平期间,SDA从低电平切换到高电平
	IIC_SDA = 0; //先保证SDA处于低电平状态
	IIC_SCL = 1; 	
	IIC_SDA = 1;
	IIC_SCL = 0; 	
}

//发送一个字节,发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位在前),
//然后拉高SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节(可参考上一节内容)

void IIC_SendByte(unsigned char Byte)
{
	unsigned char i;
	for(i=0; i<8; i++)
	{
		IIC_SDA = Byte & (0X80>>i) ;//将数据位依次放到SDA线上(高位在前)&按位与
		IIC_SCL = 1;
		IIC_SCL = 0;
	}
	
}




//接收一个字节:SCL低电平期间,从机将数据位依次放到SDA线上(高位在前),
//然后拉高SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,
//即可接收一个字节(主机在接收之前,需要释放SDA)

//接收一个字节数据
unsigned char IIC_ReceiveByte(void)
{
	unsigned char i, Byte = 0X00; //用于保存接收的字节
	
	IIC_SDA = 1; //主机在接收之前,需要释放SDA,终止对SDA的控制
	
	for(i=0; i<8; i++)
	{
		IIC_SCL = 1; //拉高SCL,主机将在SCL高电平期间读取数据位
		if(IIC_SDA)
		{
			Byte |= (0X80>>i);
		}
		IIC_SCL = 0;  //SCL低电平期间,从机将数据位依次放到SDA线上(高位在前)
	}
	
	
	return Byte;	
}



//发送应答:在接收完一个字节之后,主机在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答 (IIC时序手册)
void IIC_SendAck(unsigned char AckBit)
{
	IIC_SDA = AckBit; //应答位,SCL低电平期间,从机将数据位依次放到SDA线上(高位在前)
	IIC_SCL = 1;  //SCL从高到底,把数据放到SDA上
	IIC_SCL = 0;
	
}


//接收应答:在发送完一个字节之后,主机在下一个时钟接收一位数据,判断从机是否应答,
//数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)

unsigned char IIC_ReceiveAck(void)
{
	unsigned char AckBit;
	IIC_SDA = 1; //主机在接收之前,需要释放SDA
	
	IIC_SCL = 1; //高电平期间,主机可以读取IIC上的数据位
	
	AckBit = IIC_SDA;
	
	IIC_SCL = 0;
	
	return AckBit;
}

Buzzer.c

#include "Buzzer.h"
#include "intrins.h"
#include <REGX52.H>




sbit Buzzer = P2^5; //蜂鸣器位声明

/**
  * @brief  蜂鸣器私有延时函数 延时500us
  * @param  无
  * @retval 无
  */

void Buzzer_Delay500us()		//@11.0592MHz
{
	unsigned char i;

	_nop_();
	i = 227;
	while (--i);
}






void Buzzer_Key()
{
		
		Buzzer = !Buzzer;
		Buzzer_Delay500us();

}

void Buzzer_Siren()//报警
{
	
	unsigned char i;
	while(i--)
	{
		Buzzer = !Buzzer;
		Buzzer_Delay500us();
	}
		
		

	
}

Key.c

#include <REGX52.H>
#include "Delay.h"



//定时器扫描按键
unsigned char Key_KeyNumber;

unsigned char Key(void)
{
	unsigned Temp = 0;
	Temp = Key_KeyNumber;
	Key_KeyNumber = 0;
	
	return Temp;
	
}

unsigned char Key_GetState()
{
	unsigned char KeyNumber=0;
	
	if(P3_1==0){KeyNumber=1;}
	if(P3_0==0){KeyNumber=2;}
	if(P3_2==0){KeyNumber=3;}
	if(P3_3==0){KeyNumber=4;}
	
	return KeyNumber;
}


//循环调用
void Key_Loop(void)  
{
	static unsigned char NowState,lastState; 
	lastState = NowState;
	NowState = Key_GetState();
	
	if(lastState==1 && NowState==0)
	{
		Key_KeyNumber = 1;
	}
	
	if(lastState==2 && NowState==0)
	{
		Key_KeyNumber = 2;
	}
	
	if(lastState==3 && NowState==0)
	{
		Key_KeyNumber = 3;
	}
	
	if(lastState==4 && NowState==0)
	{
		Key_KeyNumber = 4;
	}
	
}

Timer0.c

#include <REGX52.H>


//由软件配置的定时器STC-ISP

/**
* @brief 定时器初始化(51单片机软件内置配置的定时器)
  * @param 无
  * @retval 无
  */

void Timer0_Init()		//1毫秒@11.0592MHz
{
	
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x66;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	
	//打开定时器中断
	ET0  = 1; 
	EA = 1;
	PT0 = 0;
}



//void Timer0_Init()
//{
//	/*
//	采用与或式赋值法,可以把不可寻址的位进行寻址,改变其中几位而不影响其他位
//	TMOD = TMOD & 0XF0; //低四位清零,高四位置一
//	TMOD = TMOD | 0X01;//把TMOD的最低位置1,高四位保持不变
//	如上,改变低四位而不改变高四位
//	
//	*/
//	//TMOD = 0x01;  //工作模式寄存器
//	TMOD = TMOD & 0XF0; //低四位清零,高四位置一
//	TMOD = TMOD | 0X01;//把TMOD的最低位置1,高四位保持不变
//	//控制寄存器
//	TF0  = 0;
//	TR0 = 1;
//	
//	/*定时器赋初值  定时1ms,12Mhz的晶振,1us产生一个计数脉冲,
//	而16位的计数器是0~65535个可能,也就是65536us,65536个脉冲
//	如何差生一微秒(1ms=1000us)那么从64535开始记到65535产生一个中断
//	通过配置TL0和TH0控制处置也就是把64535变成16进制TL0是低八位两个十六进制,TH0是高八位的两十六进制*/
//	
//	TL0  = 64535%56;
//	TH0  = 64535/256;
//	
//	ET0  = 1; 
//	EA = 1;
//	PT0 = 0;
//	
//}


/*定时器中断函数模板
void Timer0_Rountine(void)  interrupt 1
{
	static unsigned int T0Count ;  //Timer0_Rountine(void) 函数结束之后T0Count保留其原来的值
	
	TL0 = 0x66;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	
	T0Count++;
	if(T0Count >= 1000)
	{
		T0Count = 0;
		P2_0 = ~P2_0;
	}	
}
*/
相关推荐
LN花开富贵32 分钟前
stm32g431rbt6芯片中VREF+是什么?在电路中怎么设计?
笔记·stm32·单片机·嵌入式硬件·学习
qq210846295341 分钟前
【stm32笔记】使用rtt-studio与stm32CubeMx联合创建项目
笔记·stm32·嵌入式硬件
CV金科1 小时前
蓝桥杯—STM32G431RBT6按键的多方式使用(包含软件消抖方法精讲)从原理层面到实际应用(一)
stm32·单片机·嵌入式硬件·蓝桥杯
2021.091 小时前
五、CAN总线
嵌入式硬件
luckyluckypolar1 小时前
STM32——输入捕获
stm32·单片机·嵌入式硬件·物联网
hong1616881 小时前
嵌入式硬件基础知识
嵌入式硬件
hai405871 小时前
单片机(Microcontroller)原理及应用
单片机·嵌入式硬件
jun7788952 小时前
嵌入式硬件基础知识
嵌入式硬件
Projectsauron3 小时前
STM32 芯片启动过程
stm32·单片机·芯片启动过程
CDialog3 小时前
arduino ide开发esp32-wroom-32E
单片机·嵌入式硬件