#include <reg52.h> #include <intrins.h>
#define LCDClear() LCDWriteCmd(0x01) #define CRC8Check(dat, size) (CRC8(dat, size) == dat[size]) //#define TEMPTEST
sbit RS = P2^0; sbit RW = P2^1; sbit E = P2^2; sbit BF = P0^7;
sbit DQ = P3^3;
sbit K1 = P1^4;
unsigned char serial[8]; // 64位序列号
void delay(unsigned int n) { unsigned char i; while (n--) for (i = 0; i < 115; i++); }
void LCDBusyTest(void) { E = 0; RS = 0; RW = 1; E = 1; BF = 1; while (BF); E = 0; }
void LCDWriteCmd(unsigned char cmd) { LCDBusyTest(); RS = 0; RW = 0; E = 1; P0 = cmd; E = 0; }
void LCDWriteData(unsigned char dat) { LCDBusyTest(); RS = 1; RW = 0; E = 1; P0 = dat; E = 0; }
void LCDWriteString(char *s) { while (*s) LCDWriteData(*s++); }
void LCDWriteHex(unsigned char num) { char *list = "0123456789ABCDEF"; LCDWriteData(list[num >> 4]); LCDWriteData(list[num & 0x0f]); }
void LCDWriteNumber(char num) { if (num < 0) { LCDWriteData('-'); num = -num; } else if (num == 0) LCDWriteData(' '); else LCDWriteData('+'); LCDWriteData(num / 100 + '0'); LCDWriteData(num % 100 / 10 + '0'); LCDWriteData(num % 10 + '0'); }
void LCDInit(void) { delay(40); LCDWriteCmd(0x30); delay(10); LCDWriteCmd(0x30); delay(10); LCDWriteCmd(0x0c); delay(1); LCDWriteCmd(0x01); }
void wait(unsigned int p) { TMOD = 0x01; TL0 = p & 0xff; TH0 = p >> 8; TF0 = 0; TR0 = 1; while (!TF0); TR0 = 0; }
bit DQInit(void) { bit flag; // DS18B20是否存在的标志 DQ = 1; // 先将数据线拉高 _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); DQ = 0; wait(0xfd68); // 720us DQ = 1; wait(0xffc8); // 60us flag = !DQ; wait(0xfe33); // 500us return flag; }
bit DQReadBit(void) { bit result; DQ = 1; _nop_(); DQ = 0; // 将总线拉低, 启动读时序 _nop_(); DQ = 1; // 释放总线, 准备读, 必须在15us(包括拉低总线的时间)的时间内读完端口 _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); result = DQ; // 15us过后, 数据线已经被拉高, 此时已无法读数据 wait(0xffd3); // 48us return result; }
unsigned char DQRead(void) { unsigned char dat = 0; unsigned char i; for (i = 0; i < 8; i++) { dat >>= 1; if (DQReadBit()) dat |= 0x80; } return dat; }
void DQWriteBit(bit dat) { DQ = 1; // 先将数据线拉高 _nop_(); DQ = 0; // 将数据线从高拉低时即启动写时序 _nop_(); _nop_(); DQ = dat; wait(0xffc8); // 60us DQ = 1; _nop_(); _nop_(); }
void DQWrite(unsigned char dat) { unsigned char i; for (i = 0; i < 8; i++) { DQWriteBit(dat & 1); dat >>= 1; } }
unsigned char CRC8(unsigned char dat[], unsigned char size) { unsigned char buf; unsigned char crc = 0; unsigned char i, j; for (i = 0; i < size; i++) { buf = dat[i]; for (j = 0; j < 8; j++) { if (((crc ^ buf) & 1) == 0) crc >>= 1; else { crc ^= 0x18; crc >>= 1; crc |= 0x80; } buf >>= 1; } } return crc; }
bit DQReadSerial(void) { unsigned char i; DQInit(); DQWrite(0x33); for (i = 0; i < 8; i++) serial[i] = DQRead(); return CRC8Check(serial, 7); }
void DQWriteSerial(bit skip) { unsigned char i; if (!skip) { DQWrite(0x55); for (i = 0; i < 8; i++) DQWrite(serial[i]); } else DQWrite(0xcc); }
// 读64位序列号(总线上只有1个DS18B20时才能使用这个命令) void ShowSerial(void) { bit flag = DQReadSerial(); unsigned char i; LCDClear(); LCDWriteString("序列号:"); LCDWriteCmd(0x90); for (i = 0; i < 8; i++) LCDWriteHex(serial[i]); LCDWriteCmd(0x88); if (flag) LCDWriteString("已通\xb9\xfd校验"); // 因为编码原因, '过'字不能直接在源文件中使用 else LCDWriteString("未通\xb9\xfd校验"); LCDWriteCmd(0x98); LCDWriteString("电源模式: "); DQInit(); DQWrite(0xb4); if (DQReadBit()) LCDWriteString("外部"); else LCDWriteString("寄生"); }
// 按下K1键后继续 void pause(void) { while (1) { if (!K1) { delay(15); if (!K1) { while (!K1); break; } } } }
void ShowTemp(bit skip_rom) { unsigned char dat[9]; unsigned int i; #ifdef TEMPTEST unsigned char list[] = {0xff, 0xff, 0xfd, 0xfe, 0xfd, 0xff, 0xfe, 0x00, 0xfe, 0x01, 0xfe, 0x02, 0x07, 0xd0, 0x01, 0x91, 0x00, 0xa2, 0x00, 0x08, 0x00, 0x00, 0xff, 0xf8, 0xff, 0x5e, 0xfe, 0x6f, 0xfc, 0x90}; static char p = 0; // 温度列表测试 #endif DQInit(); DQWriteSerial(skip_rom); DQWrite(0x44); // 开始转换 delay(1000); DQInit(); DQWriteSerial(skip_rom); DQWrite(0xbe); for (i = 0; i < 9; i++) dat[i] = DQRead(); #ifdef TEMPTEST dat[0] = list[p + 1]; dat[1] = list[p]; p += 2; if (p == sizeof(list)) p = 0; #endif LCDWriteCmd(0x80); #ifndef TEMPTEST if (CRC8Check(dat, 8)) #endif { //LCDWriteString("\xca\xfd据\xd5\xfd确"); LCDWriteString("温度:"); if (dat[1] & 0xf8) { // 只要高5位有1位是1, 就是负温度 dat[0] = ~dat[0]; dat[1] = ~dat[1]; dat[1] &= 0x7ff; // 去掉高5位 dat[0]++; // 低位加1 if (dat[0] == 0) dat[1]++; // 进位 LCDWriteData('-'); } else { if (dat[0] == 0 && dat[1] == 0) LCDWriteData(' '); else LCDWriteData('+'); } i = (dat[1] & 0x07) << 4; i |= (dat[0] & 0xf0) >> 4; LCDWriteData('0' + i / 100); LCDWriteData('0' + i % 100 / 10); LCDWriteData('0' + i % 10); LCDWriteData('.'); i = (dat[0] & 0x0f) * 625; LCDWriteData('0' + i / 1000); LCDWriteData('0' + i % 1000 / 100); LCDWriteData('0' + i % 100 / 10); LCDWriteData('0' + i % 10); LCDWriteString("℃"); } #ifndef TEMPTEST else LCDWriteString("\xca\xfd据错误"); #endif
LCDWriteCmd(0x90); LCDWriteString("范围:"); LCDWriteNumber(dat[3]); LCDWriteData('~'); LCDWriteNumber(dat[2]); LCDWriteString("℃"); LCDWriteCmd(0x88); LCDWriteString("分辨率:"); i = (dat[4] >> 5 & 0x03) + 9; if (i >= 10) { LCDWriteData(' '); LCDWriteData('0' + i / 10); } LCDWriteData('0' + i % 10); LCDWriteString("位"); if (i < 10) LCDWriteString(" "); #ifdef TEMPTEST pause(); #endif }
void config(void) { DQInit(); DQWriteSerial(0); DQWrite(0x4e); DQWrite(30); // 温度上限 DQWrite(-13); // 温度下限 DQWrite(0x7f); // 12位分辨率 DQInit(); DQWriteSerial(0); DQWrite(0x48); // 把温度报警值存入EEPROM中(关闭电源再打开会自动读取) delay(10); // 重设RAM中的报警值, 但不保存到EEPROM /* DQInit(); DQWriteSerial(0); DQWrite(0x4e); DQWrite(50); // 温度上限 DQWrite(10); // 温度下限 DQWrite(0x7f); // 12位分辨率 DQInit(); DQWriteSerial(0); // 从EEPROM中读取温度报警值 DQWrite(0xb8); delay(10); */ }
int main(void) { LCDInit(); if (!DQInit()) { LCDWriteString("无温度传感器"); while (1); } ShowSerial(); pause(); config(); LCDClear(); while (1) { ShowTemp(0); } }
|