/*******************************************************************/
/* */
/*51hei單片機開發系統演示程序 - DS18B20-64位序列碼讀取程序 */
/* *
* LCD1602顯示 *
* *
* 工作芯片:STC89C516 晶振頻率:11.0592MHz *
* *
/*******************************************************************/
/*讀取DS18B20的64位序列碼并顯示在1602液晶上,如果讀取正確結果,則在
液晶第一行顯示DS18B20 OK,第二行顯示序列碼,如果讀取失敗,則在液晶上
顯示DS18B20 ERR0R PLEASE CHECK ,用戶可通過更改18B20接口自己外接。 */
#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit DQ = P2^2; //定義DS18B20端口DQ
sbit BEEP=P2^3 ; //蜂鳴器驅動線
bit presence ;
sbit LCD_RS = P3^5;
sbit LCD_RW = P3^6;
sbit LCD_EN = P3^4;
uchar code cdis1[ ] = {" DS18B20 OK "};
uchar code cdis2[ ] = {" "};
uchar code cdis3[ ] = {" DS18B20 ERR0R "};
uchar code cdis4[ ] = {" PLEASE CHECK "};
unsigned char data display[2] = {0x00,0x00};
unsigned char data RomCode[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
unsigned char Temp;
unsigned char crc;
void beep();
#define delayNOP(); {_nop_();_nop_();_nop_();_nop_();};
/*******************************************************************/
void delay1(int ms)
{
unsigned char y;
while(ms--)
{
for(y = 0; y<250; y++)
{
_nop_();
_nop_();
_nop_();
_nop_();
}
}
}
/******************************************************************/
/* */
/*檢查LCD忙狀態 */
/*lcd_busy為1時,忙,等待。lcd-busy為0時,閑,可寫指令與數據。 */
/* */
/******************************************************************/
bit lcd_busy()
{
bit result;
LCD_RS = 0;
LCD_RW =0;
LCD_EN = 1;
delayNOP();
result = (bit)(P0&0x80);
LCD_EN = 0;
return(result);
}
/*******************************************************************/
/* */
/*寫指令數據到LCD */
/*RS=L,RW=L,E=高脈沖,D0-D7=指令碼。 */
/* */
/*******************************************************************/
void lcd_wcmd(uchar cmd)
{
// while(lcd_busy());
LCD_RS = 0;
LCD_RW = 0;
LCD_EN = 0;
_nop_();
_nop_();
P0 = cmd;
delayNOP();
LCD_EN = 1;
delayNOP();
LCD_EN = 0;
delay1(5);
}
/*******************************************************************/
/* */
/*寫顯示數據到LCD */
/*RS=H,RW=L,E=高脈沖,D0-D7=數據。 */
/* */
/*******************************************************************/
void lcd_wdat(uchar dat)
{
// while(lcd_busy());
LCD_RS = 1;
LCD_RW = 0;
LCD_EN = 0;
P0 = dat;
delayNOP();
LCD_EN = 1;
delayNOP();
LCD_EN = 0;
delay1(5);
}
/*******************************************************************/
/* */
/* LCD初始化設定 */
/* */
/*******************************************************************/
void lcd_init()
{
delay1(15);
lcd_wcmd(0x01); //清除LCD的顯示內容
lcd_wcmd(0x38); //16*2顯示,5*7點陣,8位數據
delay1(5);
lcd_wcmd(0x38);
delay1(5);
lcd_wcmd(0x38);
delay1(5);
lcd_wcmd(0x0c); //顯示開,關光標
delay1(5);
lcd_wcmd(0x06); //移動光標
delay1(5);
lcd_wcmd(0x01); //清除LCD的顯示內容
delay1(5);
}
/*******************************************************************/
/* */
/* 設定顯示位置 */
/* */
/*******************************************************************/
void lcd_pos(uchar pos)
{
lcd_wcmd(pos | 0x80); //數據指針=80+地址變量
}
/*******************************************************************/
/* */
/*us級延時函數 */
/* */
/*******************************************************************/
void Delay(unsigned int num)
{
while( --num );
}
/*******************************************************************/
/* */
/*初始化ds1820 */
/* */
/*******************************************************************/
Init_DS18B20(void)
{
DQ = 1; //DQ復位
Delay(8); //稍做延時
DQ = 0; //將DQ拉低
Delay(90); //精確延時 大于 480us
DQ = 1; //拉高總線
Delay(8);
presence = DQ; //讀取存在信號
Delay(100);
DQ = 1;
return(presence); //返回信號,0=presence,1= no presence
}
/*******************************************************************/
/* */
/* 讀一位(bit) */
/* */
/*******************************************************************/
uchar read_bit(void)
{
unsigned char i;
DQ = 0; //將DQ 拉低開始讀時間隙
DQ = 1; // then return high
for (i=0; i<3; i++); // 延時15μs
return(DQ); // 返回 DQ 線上的電平值
}
/*******************************************************************/
/* */
/* 讀一個字節 */
/* */
/*******************************************************************/
ReadOneChar(void)
{
unsigned char i = 0;
unsigned char dat = 0;
//for (i = 8; i > 0; i--)
// {
// read_bit();
// DQ = 0; // 給脈沖信號
// dat >>= 1;
// DQ = 1; // 給脈沖信號
for (i=0;i<8;i++)
{ // 讀取字節,每次讀取一個字節
if(read_bit()) dat|=0x01<<i; // 然后將其左移
// if(DQ)
// dat |= 0x80;
Delay(4);
}
return (dat);
}
/*******************************************************************/
/* */
/* 寫一位 */
/* */
/*******************************************************************/
void write_bit(char bitval) {
DQ = 0; // 將DQ 拉低開始寫時間隙
if(bitval==1) DQ =1; // 如果寫1,DQ 返回高電平
Delay(5); // 在時間隙內保持電平值,
DQ = 1; // Delay函數每次循環延時16μs,因此delay(5) = 104μs
}
/*******************************************************************/
/* */
/* 寫一個字節 */
/* */
/*******************************************************************/
WriteOneChar(unsigned char dat)
{
unsigned char i = 0;
unsigned char temp;
// for (i = 8; i > 0; i--)
// {
for (i=0; i<8; i++) // 寫入字節, 每次寫入一位
{
// DQ = 0;
// DQ = dat&0x01;
// Delay(5);
// DQ = 1;
temp = dat>>i;
temp &= 0x01;
write_bit(temp);
// dat>>=1;
}
Delay(5);
}
/*******************************************************************/
/* */
/* 讀取64位序列碼 */
/* */
/*******************************************************************/
Read_RomCord(void)
{
unsigned char j;
Init_DS18B20();
WriteOneChar(0x33); // 讀序列碼的操作
for (j = 0; j < 8; j++)
{
RomCode[j] = ReadOneChar() ;
}
}
/*******************************************************************/
/* */
/*DS18B20的CRC8校驗程序 */
/* */
/*******************************************************************/
uchar CRC8()
{
uchar i,x; uchar crcbuff;
crc=0;
for(x = 0; x <8; x++)
{
crcbuff=RomCode[x];
for(i = 0; i < 8; i++)
{
if(((crc ^ crcbuff)&0x01)==0)
crc >>= 1;
else {
crc ^= 0x18; //CRC=X8+X5+X4+1
crc >>= 1;
crc |= 0x80;
}
crcbuff >>= 1;
}
}
return crc;
}
/*******************************************************************/
/* */
/* 數據轉換與顯示 */
/* */
/*******************************************************************/
Disp_RomCode()
{
uchar j;
uchar H_num=0x40; //LCD第二行初始位置
for(j=0;j<8;j++)
{
Temp = RomCode[j];
display[0]=((Temp&0xf0)>>4);
if(display[0]>9)
{ display[0]=display[0]+0x37;}
else{display[0]=display[0]+0x30;}
lcd_pos(H_num);
lcd_wdat(display[0]); //高位數顯示
H_num++;
display[1]=(Temp&0x0f);
if(display[1]>9)
{display[1]=display[1]+0x37;}
else {display[1]=display[1]+0x30;}
lcd_pos(H_num);
lcd_wdat(display[1]); //低位數顯示
H_num++;
}
}
/*******************************************************************/
/* */
/* 蜂鳴器響一聲 */
/* */
/*******************************************************************/
void beep()
{
unsigned char y;
for (y=0;y<100;y++)
{
Delay(60);
BEEP=!BEEP; //BEEP取反
}
BEEP=1; //關閉蜂鳴器
Delay(40000);
}
/*******************************************************************/
/* */
/* DS18B20 OK 顯示菜單 */
/* */
/*******************************************************************/
void Ok_Menu ()
{
uchar m;
lcd_init(); //初始化LCD
lcd_pos(0); //設置顯示位置為第一行的第1個字符
m = 0;
while(cdis1[m] != '\0')
{ //顯示字符
lcd_wdat(cdis1[m]);
m++;
}
lcd_pos(0x40); //設置顯示位置為第二行第1個字符
m = 0;
while(cdis2[m] != '\0')
{
lcd_wdat(cdis2[m]); //顯示字符
m++;
}
}
/*******************************************************************/
/* */
/* DS18B20 ERROR 顯示菜單 */
/* */
/*******************************************************************/
void Error_Menu ()
{
uchar m;
lcd_init(); //初始化LCD
lcd_pos(0); //設置顯示位置為第一行的第1個字符
m = 0;
while(cdis3[m] != '\0')
{ //顯示字符
lcd_wdat(cdis3[m]);
m++;
}
lcd_pos(0x40); //設置顯示位置為第二行第1個字符
m = 0;
while(cdis4[m] != '\0')
{
lcd_wdat(cdis4[m]); //顯示字符
m++;
}
}
/*******************************************************************/
/* */
/* 主函數 */
/* */
/*******************************************************************/
void main()
{
P0 = 0xff;
P2 = 0xff;
while(1)
{
Ok_Menu ();
Read_RomCord(); //讀取64位序列碼
CRC8(); //CRC效驗
if(crc==0) //CRC效驗正確
{
Disp_RomCode(); //顯示64位序列碼
beep();
}
while(!presence)
{
Init_DS18B20();
delay1(1000);
}
Error_Menu ();
do
{
Init_DS18B20();
beep();
}
while(presence);
}
}
/*******************************************************************/