DS18B20的带记忆功能温度报警系统源码

来源:本站
导读:目前正在解读《DS18B20的带记忆功能温度报警系统源码》的相关信息,《DS18B20的带记忆功能温度报警系统源码》是由用户自行发布的知识型内容!下面请观看由(电工技术网 - www.9ddd.net)用户发布《DS18B20的带记忆功能温度报警系统源码》的详细说明。
简介:单片机开源项目之基于DS18B20的带记忆功能温度报警系统源码
此程序是基于51hei单片机开发板上面做的,如需要移植到自己的电路上,修改相应的端口即可。

/**

***********************************************************************************************************

* @file : main.c

* @author : 徐冉

* @date : 2014年4月27日08:40:23 ~ 2014年5月1日23:03:58

* @version : V1.2.3

* @brief : 基于DS18B20的带记忆功能温度报警系统 单片机STC89C52RC MCU 晶振 : 11.0592MHZ

* @note : 温度报警值可由开发板键盘和红外遥控器按键进行调整,调整后下次上电将保存上一次的调整值

* ------------ 温度报警系统有三种状态:当温度达到设定的高温预警值范围时LED点阵将显示"火",同时蜂鸣器

* ------------ 以8000HZ的频率发声报警,且LED小灯全亮;当温度达到设定的低温预警值时LED点阵屏将显示“水”,

* ------------ 蜂鸣器将以4000HZ的频率报警,且LED小灯全亮;当温度处于正常温度值时,LED点阵屏显示“心形”,

* ------------ 蜂鸣器处于关闭状态,且LED小灯全部熄灭。

***********************************************************************************************************

*/

#include <reg52.h>

//74HC138

sbit ADDR3 = P1^3;

sbit ENLED = P1^4;

//蜂鸣器

sbit BUZZ = P1^6;

//数码管编码表

unsigned char code LedTable[] = {

0xC0, //"0"

0xF9, //"1"

0xA4, //"2"

0xB0, //"3"

0x99, //"4"

0x92, //"5"

0x82, //"6"

0xF8, //"7"

0x80, //"8"

0x90, //"9"

0x9C, // '小0'

0xC6, //'C'

0xBF //"-"

};

//数码管显示缓冲区+LED独立小灯

unsigned char idata LedBuff[] = {0xC6, 0x9C, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F};

//点阵取模

unsigned char pdata LedCode[3][8] = {

{0xFF,0x99,0x00,0x00,0x00,0x81,0xC3,0xE7}, //heart

{0xF7,0xD5,0xD5,0xE6,0xF7,0xEB,0xDD,0xBE}, //fire

{0xF7,0x77,0xA0,0xC3,0xE5,0xD6,0xB7,0x71} //water

};

/**************************local values definition***********************************/

//温度状态

unsigned char idata tempSta = 0;//0表示正常温度,1表示高温,2表示低温

bit flag2s = 0;

unsigned char setTempIndex = 0;//0-正常运行状态 1-8报警温度设定索引

unsigned char thr0, tlr0;//T0定时器重载值

unsigned int counter = 0;//计数器

unsigned char idata thr1, tlr1;//00H-70H内存不够,使用70H-FFH内存

signed int temp;//存储温度值

bit buzzflag = 0;//蜂鸣器启动标志

//定义报警温度的上限值和下限值范围(以下温度值是*10之后的温度值)温度值分正负且都是int型

signed int shangxianHigh = 300, shangxianLow = 280;//温度上限值高温度值和低温度值

signed int xiaxianHigh = 200, xiaxianLow = 180; //温度下限值的高温度值和低温度值

signed char num[8] = {0, 0, 0, 0, 0, 0, 0, 0};//保存报警温度值十位数和个位数

extern bit flagIrd; //红外解码完成标志

extern unsigned char IrdCode[4];//装载红外解码值

/**************************local function definition***********************************/

void ConfigTimer0(unsigned int xms);

void TempToLedBuf(signed int temp);

void TempertureWarning(signed int temp);

void ConfigBuzzFr(unsigned int fr);

void ReadE2PROMToNumArrary();

/**************************extern function definition***********************************/

extern void KeyDrive();

extern void KeyScan();

extern void LCD1602RefreshCoursor();

extern void InitLCD1602();

extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char * str);

extern bit StartConvertTemp();

extern bit ReadDS18B20Temperture(signed int * temperture);

extern void WriteEEPROMByte(unsigned char addr, unsigned char dat);

extern unsigned char ReadEEPROMByte(unsigned char addr);

extern void LEDRefreshPause();

extern void ContinueRefreshLED();

extern void ConfigInfrared();

extern void IrdKeyDrive();

/*主函数main()*/

void main(void)

{

ADDR3 = 1;

ENLED = 0;//选择LED

InitLCD1602();

ConfigTimer0(1);//T0定时1ms

ConfigInfrared();

//ConfigBuzzFr(1000);//默认设定蜂鸣器频率为1000

StartConvertTemp();//启动一次温度转换

LcdShowStr(0, 0, "high T: XX-XX 'C");

LcdShowStr(0, 1, "low T: XX-XX 'C");//LCD初始化显示

ReadE2PROMToNumArrary();

EA = 1; //打开总中断

while (1)

{

KeyDrive(); //检测按键动作

if (flagIrd)

{

flagIrd = 0;

IrdKeyDrive();//红外按键检测

}

if (flag2s)

{

flag2s = 0;

if (ReadDS18B20Temperture(&temp))

{

TempToLedBuf(temp); //将温度值转换成数码管数字并检测温度是否超限,超限启动声光报警!

StartConvertTemp();//再次启动温度转换

}

}

}

}

/*将eeprom的存储的报警温度值的各个位数字读取到num[8]数组中*/

void ReadE2PROMToNumArrary()

{

unsigned char str[4];

//数码管初始化显示0.00

LedBuff[2] = LedTable[0];

LedBuff[3] = LedTable[0];

LedBuff[4] = LedTable[0];

LedBuff[3] &= 0x7F;//add point

/*读取eeprom中的数据*/

num[0] = ReadEEPROMByte(0x00);

num[1] = ReadEEPROMByte(0x01);

num[2] = ReadEEPROMByte(0x02);

num[3] = ReadEEPROMByte(0x03);

num[4] = ReadEEPROMByte(0x04);

num[5] = ReadEEPROMByte(0x05);

num[6] = ReadEEPROMByte(0x06);

num[7] = ReadEEPROMByte(0x07);

LedBuff[6] = 0x7F;//读取成功指示

/*初始化更新设定的报警温度值*/

shangxianLow = (num[0] * 100 + num[1] * 10);

shangxianHigh = (num[2] * 100 + num[3] * 10);

xiaxianLow = (num[4] * 100 + num[5] * 10);

xiaxianHigh = (num[6] * 100 + num[7] * 10);

/*将报警温度值显示到LCD1602上*/

str[0] = num[0] + '0';

str[1] = num[1] + '0';

str[2] = '';

LcdShowStr(8, 0, str);

str[0] = num[2] + '0';

str[1] = num[3] + '0';

str[2] = '';

LcdShowStr(11, 0, str);

str[0] = num[4] + '0';

str[1] = num[5] + '0';

str[2] = '';

LcdShowStr(8, 1, str);

str[0] = num[6] + '0';

str[1] = num[7] + '0';

str[3] = '';

LcdShowStr(11, 1, str);

}

/*将温度值转换为有效数字存储到LedBuff中*/

void TempToLedBuf(signed int temp)

{

unsigned char buf[6];//缓冲区

signed char i = 0; //i必须是有符号型数据

if (temp < 0) //负温度值

{

buf[5] = LedTable[12];//添加负号

//保留一位小数

temp = (~temp + 1) * 0.0625 * 10;//负值,读取到的16位二进制数值取反+1再*分辨率0.0625

for (i = 0; i < 4; i++) //温度值最高3位数值+小数位

{

buf[i] = temp % 10;

temp /= 10;

}

//去掉无效位数字

for (i = 3; i > 1; i--)

{

if (buf[i] == 0)

{

buf[i] = 0xFF;//去掉高位0不显示

}

else

{

break;//遇到第一个有效数字就退出

}

}

//转换为实际的有效数字

for (; i >= 0; i--)

{

buf[i] = LedTable[buf[i]];

}

//将实际数字拷贝到数码管缓冲区中

for (i = 0; i < 4; i++)

{

LedBuff[i+2] = buf[i];

}

}

else

{

//温度值大于等于0,保留一位小数位

temp = (temp * 0.0625 * 10);//直接用读取到的16位二进制数值*分辨率即是实际的温度值

TempertureWarning(temp); //温度报警检测必须函数必须放在前面

for (i = 0; i < 4; i++)

{

buf[i] = temp % 10;

temp /= 10;

}

//去掉高位的0

for (i = 3; i > 1; i--)

{

if (buf[i] == 0)

{

buf[i] = 0xFF;

}

else

{

break;//遇到第一个有效数字就退出

}

}

//转换为实际的有效数字

for (; i >= 0; i--)

{

buf[i] = LedTable[buf[i]];

}

//拷贝到缓冲区

for (i = 0; i < 4; i++)

{

LedBuff[i+2] = buf[i]; //最低两位显示温度标示符

}

}

//在相应的位置点上小数点

LedBuff[3] &= 0x7F;//0 111 1111

}

/*刷新LCD设置位置上的数字显示*/

void RefreshLCDDisplay()

{

unsigned char str[3];//字符串缓冲区

switch (setTempIndex)

{

case 1: str[0] = num[0] + '0'; str[1] = ''; LcdShowStr(8, 0, str); break;

case 2: str[0] = num[1] + '0'; str[1] = ''; LcdShowStr(9, 0, str); break;//shangxianLow的十位和个位数字显示刷新

case 3: str[0] = num[2] + '0'; str[1] = ''; LcdShowStr(11, 0, str); break;

case 4: str[0] = num[3] + '0'; str[1] = ''; LcdShowStr(12, 0, str); break;

case 5: str[0] = num[4] + '0'; str[1] = ''; LcdShowStr(8, 1, str); break;

case 6: str[0] = num[5] + '0'; str[1] = ''; LcdShowStr(9, 1, str); break;

case 7: str[0] = num[6] + '0'; str[1] = ''; LcdShowStr(11, 1, str); break;

case 8: str[0] = num[7] + '0'; str[1] = ''; LcdShowStr(12, 1, str); break;

default: break;

}

LCD1602RefreshCoursor();

}

/*响应按键值来设置温度报警值*/

void SetTempByKeyNum(unsigned char keyNum)

{

switch (setTempIndex)

{

case 1: num[0] = keyNum; break;

case 2: num[1] = keyNum; break;

case 3: num[2] = keyNum; break;

case 4: num[3] = keyNum; break;

case 5: num[4] = keyNum; break;

case 6: num[5] = keyNum; break;

case 7: num[6] = keyNum; break;

case 8: num[7] = keyNum; break;

default: break;

}

RefreshLCDDisplay();

setTempIndex++;//光标右移

if (setTempIndex > 8)

setTempIndex = 1;//设置光标回返

LCD1602RefreshCoursor();

}

/*光标闪烁位置数字递增*/

void IncCoursorNum()

{

switch (setTempIndex)

{

case 1: {if (num[0] < 9) num[0]++; else num[0] = 0; break;} //十位数字++后重新设置温度值

case 2: {if (num[1] < 9) num[1]++; else num[1] = 0; break;}//shangxianLow是小数*10之后的值

case 3: {if (num[2] < 9) num[2]++; else num[2] = 0; break;}

case 4: {if (num[3] < 9) num[3]++; else num[3] = 0; break;}

case 5: {if (num[4] < 9) num[4]++; else num[4] = 0; break;}

case 6: {if (num[5] < 9) num[5]++; else num[5] = 0; break;}

case 7: {if (num[6] < 9) num[6]++; else num[6] = 0; break;}

case 8: {if (num[7] < 9) num[7]++; else num[7] = 0; break;}

default: break;

}

RefreshLCDDisplay();//刷新设置位置上的数字显示

LCD1602RefreshCoursor();//再次刷新光标显示

}

/*光标闪烁位置数字递减*/

void DecCoursorNum()

{

switch (setTempIndex) //根据光标闪烁的索引来递减相应位置的数字

{

case 1: {if (num[0] > 0) --num[0]; else num[0] = 9; break;} //十位数字++后重新设置温度值

case 2: {if (num[1] > 0) --num[1]; else num[1] = 9; break;}//shangxianLow是小数*10之后的值

case 3: {if (num[2] > 0) --num[2]; else num[2] = 9; break;}

case 4: {if (num[3] > 0) --num[3]; else num[3] = 9; break;}

case 5: {if (num[4] > 0) --num[4]; else num[4] = 9; break;}

case 6: {if (num[5] > 0) --num[5]; else num[5] = 9; break;}

case 7: {if (num[6] > 0) --num[6]; else num[6] = 9; break;}

case 8: {if (num[7] > 0) --num[7]; else num[7] = 9; break;}

default: break;

}

RefreshLCDDisplay();

LCD1602RefreshCoursor();//刷新光标闪烁

}

/*设置报警温度值*/

void SetWarningTemperture()

{

/*设置温度报警值*/

shangxianLow = (num[0] * 100 + num[1] * 10);

shangxianHigh = (num[2] * 100 + num[3] * 10);

xiaxianLow = (num[4] * 100 + num[5] * 10);

xiaxianHigh = (num[6] * 100 + num[7] * 10);

/*将数据保存到eeprom中*/

WriteEEPROMByte(0x00, num[0]);

WriteEEPROMByte(0x01, num[1]);

WriteEEPROMByte(0x02, num[2]);

WriteEEPROMByte(0x03, num[3]);

WriteEEPROMByte(0x04, num[4]);

WriteEEPROMByte(0x05, num[5]);

WriteEEPROMByte(0x06, num[6]);

WriteEEPROMByte(0x07, num[7]);

LedBuff[6] = 0xFE;//写入成功指示

}

/*温度报警检测*/

void TempertureWarning(signed int temp)

{

if ((temp > xiaxianLow) && (temp < xiaxianHigh)) //温度在18.0-20.0度进行低温报警

{

buzzflag = 1;//启动报警器

ConfigBuzzFr(4000); //蜂鸣器发声频率2000HZ

LedBuff[6] = 0x00;//低温亮8个LED小灯

tempSta = 2;//water

}

else if ((temp > shangxianLow) && (temp < shangxianHigh)) //温度在28.0-30.0度进行高温报警

{

buzzflag = 1;

ConfigBuzzFr(8000);//蜂鸣器发声频率5000HZ

LedBuff[6] = 0x00;//高温亮八个LED小灯

tempSta = 1;//fire

}

else

{

buzzflag = 0;//关闭报警器

LedBuff[6] = 0xFF;//关闭报警灯

tempSta = 0;//heart

}

}

/*配置T0定时器,由于刷新时间的要求,定时xms时间*/

void ConfigTimer0(unsigned int xms)

{

unsigned long tmp;

tmp = 11059200/12;//周期频率

tmp = (tmp * xms) / 1000;//定时xms需要的计数值

tmp = 65536 - tmp;//定时xms的定时器装入初值

thr0 = (unsigned char)(tmp >> 8);

tlr0 = (unsigned char)tmp;

TMOD &= 0xF0;//清零T0控制位

TMOD |= 0x01;//T0方式1,16位定时器可以设定

TH0 = thr0;

TL0 = tlr0;

TR0 = 1;//开启T0定时器

ET0 = 1;//开定时器T0中断

}

/*数码管刷新*/

void RefreshLEDChar()

{

static unsigned char index = 0;

P0 = 0xFF;//消隐

ADDR3 = 1;

if ((ENLED == 0) && (ADDR3 == 1))

{

P1 &= 0xF8;//清零P1口低三位

P1 |= index;//index控制三八译码器选择地址

P0 = LedBuff[index++];

if (index > 6) //刷新LEDS0-LEDS6,6个数码管+LED小灯

{

index = 0;

}

}

}

/*刷新点阵屏*/

void RefreshLed()

{

static unsigned char index = 0;

P0 = 0xFF;

ADDR3 = 0;

if ((ENLED == 0) && (ADDR3 == 0))

{

P1 &= 0xF8;//清零P1口低三位

P1 |= index;

P0 = LedCode[tempSta][index++];//tempSta == 0表示温度正常

if (index > 7)

index = 0;

//index &= 0x07;//到8归0

}

}

/*配置蜂鸣器发声频率fr*/

void ConfigBuzzFr(unsigned int fr)

{

unsigned long tmp = 0;

tmp = 11059200/12; //周期频率

tmp = tmp / fr; //设定fr频率需要的计数值

tmp = 65536 - tmp;//设定fr频率需要装入的计数初值

thr1 = (unsigned char)(tmp >> 8);

tlr1 = (unsigned char)tmp; //计数值高低字节

TMOD &= 0x0F; //清零T1控制位

TMOD |= 0x10; //配置T1工作方式1,16位定时器模式

TH1 = thr1;

TL1 = tlr1;

TR1 = 1;//开启T1

ET1 = 1;//开启定时器T1中断

}

/*定时器T0中断服务*/

void Timer0_ISP() interrupt 1

{

static bit biv = 0;

TH0 = thr0;

TL0 = tlr0;//重新装入初值

counter++;

KeyScan(); //扫描按键

RefreshLEDChar(); //1ms数码管显示刷新

if (!biv) //2ms

{

RefreshLed();//点阵刷新

}

biv = ~biv; //分频

if (counter >= 2000)

{

counter = 0;//2s

flag2s = 1;

}

}

/*定时器T1中断服务配置蜂鸣器的发声频率*/

void Timer1_ISP() interrupt 3

{

TH1 = thr1;

TL1 = tlr1;

if (buzzflag)

{

BUZZ = ~BUZZ;//以frHZ驱动蜂鸣器发声

}

}

/**

***********************************************************************************************

* @file : lcd1602.c

* @author : xr

* @date : 2014年4月27日08:40:23

* @version : V1.2.3

* @brief : LCD1602驱动

***********************************************************************************************

*/

#include <reg52.h>

//LCD1602

sbit LCD1602_RS = P1^0;

sbit LCD1602_RW = P1^1;

sbit LCD1602_EN = P1^5;

//74HC138

sbit ADDR0 = P1^0;

sbit ADDR1 = P1^1;

sbit ADDR2 = P1^2;

sbit ADDR3 = P1^3;

sbit ENLED = P1^4;

bit tmpADDR0 = 0;

bit tmpADDR1 = 0;//地址选择缓冲区

/**************************local function definition***********************************/

void ContinueRefreshLED();

void LEDRefreshPause();

/*LCD1602忙碌等待*/

void LCD1602Wait()

{

unsigned char sta;

P0 = 0xFF;//读状态前先拉高P0口

/*读状态*/

LCD1602_RS = 0;

LCD1602_RW = 1;

LCD1602_EN = 0;

do

{

LCD1602_EN = 1;

sta = P0;

LCD1602_EN = 0;//关闭液晶输出使能,避免液晶输出数据影响总线上的其他器件

} while (sta & 0x80); //状态字的最高位如果为1则表示液晶忙碌,禁止操作

}

/*暂停LED扫描*/

void LEDRefreshPause()

{

ENLED = 1;//关闭LED使能

tmpADDR0 = ADDR0;//因为LED和LCD同时使用了P1^0和P1^1引脚,所以要暂时保存ADDR0和ADDR1的数据即LED扫描地址值

tmpADDR1 = ADDR1;

P0 = 0xFF; //数码管+LED小灯去抖动

}

/*继续扫描LED*/

void ContinueRefreshLED()

{

ADDR0 = tmpADDR0;

ADDR1 = tmpADDR1;//恢复原来LED扫描的地址选择值

ENLED = 0;//选择LED

P0 = 0xFF; //数码管和LED去抖

}

/*LCD1602写命令*/

void LCD1602WriteCmd(unsigned char cmd)

{

LEDRefreshPause();//暂停LED扫描

//读写之前都要进行液晶的忙碌等待

LCD1602Wait();

LCD1602_RS = 0;

LCD1602_RW = 0;

LCD1602_EN = 0;

P0 = cmd;//送入命令

LCD1602_EN = 1;//高脉冲

LCD1602_EN = 0;//恢复原电平状态,关闭液晶输出

ContinueRefreshLED();//继续扫描LED(数码管+独立LED小灯)

}

/*LCD1602写数据*/

void LCD1602WriteData(unsigned char dat)

{

LEDRefreshPause();//暂停LED扫描

LCD1602Wait();

LCD1602_RS = 1;

LCD1602_RW = 0;

LCD1602_EN = 0;

P0 = dat;

LCD1602_EN = 1;//高脉冲

LCD1602_EN = 0;

ContinueRefreshLED();//继续扫描LED

}

/*液晶初始化*/

void InitLCD1602()

{

LCD1602WriteCmd(0x38);

LCD1602WriteCmd(0x0C);

LCD1602WriteCmd(0x06);

LCD1602WriteCmd(0x01);

}

/*设置光标位置*/

void LCD1602SetCoursor(unsigned char x, unsigned char y)

{

unsigned char addr;

if (y == 0) //第一行

{

addr = 0x00 + x;//x为地址偏移

}

else

{

addr = 0x40 + x;

}

LEDRefreshPause();

LCD1602WriteCmd(addr + 0x80);//写光标地址

ContinueRefreshLED();

}

/*打开光标闪烁*/

void OpenCoursor()

{

LCD1602WriteCmd(0x0F);//显示光标,且光标闪烁

}

/*关闭光标*/

void CloseCoursor()

{

LCD1602WriteCmd(0x0C);//关闭光标

}

/*写str字符串到液晶的坐标(x, y)上*/

void LcdShowStr(unsigned char x, unsigned char y, unsigned char * str)

{

unsigned char addr;

if (y == 0)

{

addr = 0x00 + x;

}

else

{

addr = 0x40 + x;

}

LEDRefreshPause();

LCD1602WriteCmd(addr + 0x80);

ContinueRefreshLED();

while (*str != '')

{

LEDRefreshPause();

LCD1602WriteData(*str++);

ContinueRefreshLED();

}

}

/**

***********************************************************************************************

* @file : ds18b20.c

* @author : xr

* @date : 2014年4月27日08:40:23

* @version : V1.2.3

* @brief : DS18B20驱动

***********************************************************************************************

*/

#include <reg52.h>

#include <intrins.h>

//DS18B20_IO

sbit DS18B20_IO = P3^2;//1ware总线引脚

/*DS18B20操作时间,延时x*10us*/

void DelayX10us(unsigned char x10us)

{

do

{

_nop_();

_nop_();

_nop_();

_nop_();

_nop_();

_nop_();

_nop_();

_nop_(); //大约延时10us

} while (x10us--);

}

/*复位DS18B20,读取DS18B20存在脉冲*/

bit ReadDS18B20Ack()

{

bit ack = 0;

EA = 0;//先关闭所有中断,以避免中断时间影响DS18B20操作

DS18B20_IO = 0;//拉低

DelayX10us(70); //延时700us

DS18B20_IO = 1;

DelayX10us(6); //延时60us一定可以读取到DS18B20的应答

ack = DS18B20_IO;//读取存在脉冲

while (!DS18B20_IO);//等待DS18B20复位结束

EA = 1;//打开中断

return (ack);

}

/*写一个字节数据到DS18B20总线上*/

void WriteDS18B20Byte(unsigned char byte)

{

unsigned char mask = 0x01;//最低位开始写

EA = 0;//关闭中断

for (mask = 0x01; mask != 0; mask <<= 1)

{

DS18B20_IO = 0;//拉低

_nop_();

_nop_();//延时2us

if ((byte & mask) != 0)

{

DS18B20_IO = 1;//发送1

}

else

{

DS18B20_IO = 0;//发送0

} //拉低延时到把数据送入总线上的时间不得超过15us,15us后DS18B20进行对总线进行采样

DelayX10us(6);//延时60us,等待DS18B20采样完成

DS18B20_IO = 1;//释放总线

}

EA = 1;//打开中断

}

/*从DS18B20读一个字节的数据*/

unsigned char ReadDS18B20Byte()

{

unsigned char mask = 0x01;//接收数据探测掩码

unsigned char byte = 0;

EA = 0;//关闭中断

for (mask = 0x01; mask != 0; mask <<= 1) //低位在先,逐位接收

{

DS18B20_IO = 0;

_nop_();

_nop_();//先拉低总线2us

DS18B20_IO = 1;

_nop_();

_nop_();//再拉高总线2us,然后主机进行对DS18B20_IO总线采样

if (DS18B20_IO != 0)

{

byte |= mask;//相应位置1

}

else

{

byte &= (~mask);//相应位清零

}//主机在将DS18B20拉低再拉高,然后主机进行采样,时间不超过15us

DelayX10us(6); //延时60us,这时总线将被上拉电阻拉高

}

EA = 1;//开中断

return (byte); //返回接收到的数据

}

/*启动温度转换Convert Temperature*/

bit StartConvertTemp()

{

bit ack;

ack = ReadDS18B20Ack();//复位总线,并读取DS18B20存在脉冲

if (ack == 0) //读取到复位脉冲

{

WriteDS18B20Byte(0xCC);//跳过ROM寻址

WriteDS18B20Byte(0x44);//启动温度转换

}

return (~ack);//ack==0表示温度启动转换成功

}

/*读取温度值,将温度值保存到*temperture中,并返回应答ack*/

bit ReadDS18B20Temperture(signed int * temperture)

{

unsigned char lsb, msb;

bit ack = 0;

ack = ReadDS18B20Ack();//复位总线,并读取DS18B20存在脉冲

if (ack == 0)

{

WriteDS18B20Byte(0xCC);//跳过ROM

WriteDS18B20Byte(0xBE);//读暂存数据寄存器

lsb = ReadDS18B20Byte();//读温度值低字节数据

msb = ReadDS18B20Byte();//读温度值高字节数据

/*将温度值的高低字节合并成int型数据并存入*temperture中*/

*temperture = ((unsigned int)(msb) << 8) + lsb;

}

return (~ack);//ack==0则表示温度值读取成功

}

/**

***********************************************************************************************

* @file : main.c

* @author : xr

* @date : 2014年4月27日20:26:26

* @version : V1.2.3

* @brief : 按键驱动程序

***********************************************************************************************

*/

#include <reg52.h>

//KEY

sbit KEY_IN_1 = P2^4;

sbit KEY_IN_2 = P2^5;

sbit KEY_IN_3 = P2^6;

sbit KEY_IN_4 = P2^7;

sbit KEY_OUT_1 = P2^3;

sbit KEY_OUT_2 = P2^2;

sbit KEY_OUT_3 = P2^1;

sbit KEY_OUT_4 = P2^0;

//按键当前状态

unsigned char keySta[4][4] = {1, 1, 1, 1, 1, 1, 1, 1,

1, 1, 1, 1, 1, 1, 1, 1};

//按键到PC标准键盘编码

unsigned char keyCodeMap[4][4] = {

'1', '2', '3', 0x26, //数字键123,向上键

'4', '5', '6', 0x25, //数字键456,向左键

'7', '8', '9', 0x28, //数字键789,向下键

'0', 0x1B, 0x0D, 0x27 //数字键0,向右键

};

/*红外遥控器键码对应标准PC键盘编码,21个键码*/

unsigned char code IrdKeyCode[21][2] = {

{0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00}, //前者为红外遥控器键码,后者为对应的标准PC键盘编码,0x00表示无对应值

{0x44, 0x00}, {0x40, 0x25}, {0x43, 0x27}, //后退->向左键,前进->向右键

{0x07, 0x1B}, {0x15, 0x28}, {0x09, 0x26}, //EQ->ESC,-->向下键,+->向上键

{0x16, '0'}, {0x19, 0x00}, {0x0D, 0x0D}, //0->0, U/SD->回车键

{0x0C, '1'}, {0x18, '2'}, {0x5E, '3'}, //1->1, 2->2, 3->3

{0x08, '4'}, {0x1C, '5'}, {0x5A, '6'}, //4->4, 5->5, 6->6

{0x42, '7'}, {0x52, '8'}, {0x4A, '9'} //7->7, 8->8, 9->9

};

/***************************local function definition************************************/

void KeyAction(unsigned char keycode);

/***************************extern function and values definition************************************/

extern unsigned char setTempIndex;

extern bit flagIrd; //红外解码完成标志

extern unsigned char IrdCode[4];//装载红外解码值

extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char * str);

extern void LCD1602SetCoursor(unsigned char x, unsigned char y);

extern void OpenCoursor();

extern void CloseCoursor();

extern void ContinueRefreshLED();

extern void LEDRefreshPause();

extern void IncCoursorNum();

extern void DecCoursorNum();

extern void SetWarningTemperture();

extern void SetTempByKeyNum(unsigned char keyNum);

/*按键驱动函数,检测按键动作*/

void KeyDrive()

{

static unsigned char keybackup[4][4] = {1, 1, 1, 1, 1, 1, 1, 1,

1, 1, 1, 1, 1, 1, 1, 1};//按键备份值

unsigned char i, j;

for (i = 0; i < 4; i++) //行

{

for (j = 0; j < 4; j++) //列

{

if (keySta[i][j] != keybackup[i][j]) //按键两次的值不相同,按键有动作

{

//由上一次的按键备份值确定这一次的按键状态值

if (keybackup[i][j] != 0)

{

//按键按下

KeyAction(keyCodeMap[i][j]);//传递相应的按键码值,驱动按键动作

}

keybackup[i][j] = keySta[i][j];//备份按键的值

}

}

}

}

/*红外遥控器按键驱动*/

void IrdKeyDrive()

{

unsigned char i = 0;

for (i = 0; i < 21; i++) //遍历红外键码表

{

if (IrdCode[2] == IrdKeyCode[i][0]) //IrdKeyCode[i][0]为红外键码,IrdKeyCode[i][1]为对应的PC键盘编码

{

//在表中找到对应的键码

KeyAction(IrdKeyCode[i][1]); //执行相应的动作

break;

}

}

}

/*刷新LCD1602光标显示*/

void LCD1602RefreshCoursor()

{

switch (setTempIndex)

{

case 1: LCD1602SetCoursor(8, 0); break;//shangxianLow的十位数字

case 2: LCD1602SetCoursor(9, 0); break; //shangxianLow的个位数字

case 3: LCD1602SetCoursor(11, 0); break; //shangxianHigh的十位数字

case 4: LCD1602SetCoursor(12, 0); break;

case 5: LCD1602SetCoursor(8, 1); break;

case 6: LCD1602SetCoursor(9, 1); break;

case 7: LCD1602SetCoursor(11, 1); break;

case 8: LCD1602SetCoursor(12, 1); break;

default: break;

}

OpenCoursor();//打开光标

}

/*光标闪烁左移*/

void LCDCoursorLeft()

{

if (setTempIndex > 1)

{

setTempIndex--;

}

else

{

setTempIndex = 8;

}

LCD1602RefreshCoursor();//刷新光标显示

}

/*光标右移*/

void LCDCoursorRight()

{

if (setTempIndex < 8)

{

setTempIndex++;

}

else

{

setTempIndex = 1;

}

LCD1602RefreshCoursor();//刷新光标显示

}

/*按键动作函数,根据keycode的值执行相应的动作*/

void KeyAction(unsigned char keycode)

{

if (keycode >= '0' && keycode <= '9')

{

if (setTempIndex != 0) //处于设置状态

{

SetTempByKeyNum(keycode - '0'); //0-9

}

}

else if (keycode == 0x25) //<-

{

if (setTempIndex != 0) //处于设置状态时响应

{

LCDCoursorLeft();

}

}

else if (keycode == 0x27) //->

{

if (setTempIndex != 0)

{

LCDCoursorRight();

}

}

else if (keycode == 0x26) //UP

{

if (setTempIndex != 0) //处于设置状态时响应

{

IncCoursorNum();

}

}

else if (keycode == 0x28)//Down

{

if (setTempIndex != 0)

{

DecCoursorNum();

}

}

else if (keycode == 0x1B) //ESC

{

setTempIndex = 0;

CloseCoursor();

}

else if (keycode == 0x0D) //Enter

{

if (setTempIndex == 0)

{

setTempIndex = 1;

LCD1602RefreshCoursor();

}

else

{

setTempIndex = 0;

SetWarningTemperture();//设定报警温度值,并将设定的报警值保存到eeprom中

CloseCoursor();

}

}

}

/*按键扫描函数,定时器消抖*/

void KeyScan()

{

static unsigned char keyout = 0;//按键行索引

static unsigned char keybuff[4][4] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,

0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

//16个按键的扫描缓冲区

unsigned char i = 0;

//扫描一行按键,将扫描值存入keybuff中

keybuff[keyout][0] = (keybuff[keyout][0] << 1) | KEY_IN_1;

keybuff[keyout][1] = (keybuff[keyout][1] << 1) | KEY_IN_2;

keybuff[keyout][2] = (keybuff[keyout][2] << 1) | KEY_IN_3;

keybuff[keyout][3] = (keybuff[keyout][3] << 1) | KEY_IN_4;

//更新消抖后的按键状态值

for (i = 0; i < 4; i++)

{

//每行有四个按键

if ((keybuff[keyout][i] & 0x1F) == 0x00) //五次检测都是0

{

keySta[keyout][i] = 0;//按键按下

}

else if ((keybuff[keyout][i] & 0x1F) == 0x1F)//五次都是1

{

keySta[keyout][i] = 1;//按键弹起

}

}

//检测下一行按键

keyout++;

keyout &= 0x03;//0x11按位与实现到4归零

//根据keyout的值来选择检测哪一行

switch (keyout)

{

case 0: KEY_OUT_1 = 0; KEY_OUT_4 = 1; break;

case 1: KEY_OUT_2 = 0; KEY_OUT_1 = 1; break;

case 2: KEY_OUT_3 = 0; KEY_OUT_2 = 1; break;

case 3: KEY_OUT_4 = 0; KEY_OUT_3 = 1; break;

default: break;

}

}

/**

***********************************************************************************************

* @file : I2C.c

* @author : xr

* @date : 2014年4月28日19:18:15

* @version : V1.2.3

* @brief : I2C通信底层驱动

***********************************************************************************************

*/

#include <reg52.h>

#include <intrins.h>

//I2C

sbit SDA = P3^6;

sbit SCL = P3^7;

/*I2C通信延时函数宏定义*/

#define nops() { _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); } //延时大约5us

/*I2C起始信号*/

void I2CStart()

{

SDA = 1;

SCL = 1; //先拉高SDA和SCL

nops();

SDA = 0;//拉低SDA,在SCL为高电平期间SDA1-0的跳变被当做I2C的起始信号

nops();

SCL = 0;//拉低SCL,准备好发送数据

}

/*I2C停止信号*/

void I2CStop()

{

SDA = 0;

SCL = 0; //首先确保SDA和SCL为低电平,即忙碌

nops();

SCL = 1; //拉高SCL

nops();

SDA = 1;//在SCL为高电平期间SDA0-1的变化被当做是停止信号

nops();

}

/*向I2C通信总线发送一个字节数据,并返回从机应答信号ack*/

bit I2CWriteByte(unsigned char byte)

{

bit ack = 0;

unsigned char mask = 0x80;//从高位开始发送

//I2CStart中已将SCL拉低,可以直接发送数据了

for (mask = 0x80; mask != 0; mask >>= 1)

{

if ((byte & mask) != 0) //送入数据

{

SDA = 1;//发送1

}

else

{

SDA = 0;//发送0

}

nops();//等待数据发送完成

SCL = 1;//拉高SCL使数据线SDA稳定不变

nops();

SCL = 0;//等待下一位的发送

}

/*主机释放SDA数据线,从机开始发送应答ack*/

SDA = 1;

nops();

SCL = 1; //拉高SCL以接收从机应答

ack = SDA;//接收从机应答ack

nops();

SCL = 0;//拉低SCL等待下一次的数据发送

return (~ack); //ack==0表示写成功

}

///*从I2C总线上接收一个字节数据,主机返回ack 0,返回值:读取到的数据byte*/

//unsigned char I2CReadByteAck()

//{

// unsigned char byte = 0;

// unsigned char mask = 0x80;//高位在先,逐位接收

//

// //主机释放SDA数据线

// SDA = 1;

// //I2CStart中已将SCL拉低,等待从机发送数据

// for (mask = 0x80; mask != 0; mask >>= 1)

// {

// nops();//延时>4.7us等待从机将数据发送到I2C总线上

// SCL = 1;//拉高SCL使SDA线上的数据稳定

// if (SDA != 0)

// {

// byte |= mask;//相应位置1

// }

// else

// {

// byte &= (~mask);//相应位清零

// }

// nops();//等待数据读取成功

// SCL = 0;//拉低SCL等待从机发送下一位数据

// }

// SDA = 0;//主机发送应答位0,继续接收数据

// nops();

// SCL = 1;//拉高SCL从机等待主机的应答

// nops();

// SCL = 0;//最后拉低SCL以进行下一次数据的发送和接收

//

// return (byte);

//}

/*从I2C总线上接收一个字节的数据,主机返回非应答1,返回值:接收到的数据byte*/

unsigned char I2CReadByteNAck()

{

unsigned char byte = 0;

unsigned char mask = 0x80;//高位在前,逐位接收

//主机先释放SDA等待从机发送数据

SDA = 1;

//I2CStart起始信号已将SCL拉低,从机开始发送数据

for (mask = 0x80; mask != 0; mask >>= 1)

{

nops();//等待从机将数据发送到I2C总线上

SCL = 1;//使SDA上的数据稳定

if (SDA != 0)

{

byte |= mask;

}<

提醒:《DS18B20的带记忆功能温度报警系统源码》最后刷新时间 2024-03-14 01:09:35,本站为公益型个人网站,仅供个人学习和记录信息,不进行任何商业性质的盈利。如果内容、图片资源失效或内容涉及侵权,请反馈至,我们会及时处理。本站只保证内容的可读性,无法保证真实性,《DS18B20的带记忆功能温度报警系统源码》该内容的真实性请自行鉴别。