由于DS18B20是單線操作,是以必須嚴格遵守它的時序要求才能正常與之建立聯系并實作讀寫操作。
網上見到的程式多是在主程式中以延時的方式實作,而且要求關中斷,以實作18B20對時序的要求。但是實際應用中,測溫操作一般是作為輔助功能,主要任務是通信及資料處理等其他操作,這樣一來,如果将DS18B20的程式代碼放在主程式中,勢必影響其他需要實時處理的中斷。
前些天用到DS18B20,就嘗試以51定時中斷的方法實作DS18B20時序,在面包闆上成功跑了起來。
用的單片機是STC11F16XE,使用外部晶振24MHz。下面的程式中不僅有DS18B20的操作,還包含了數位管顯示、按鍵檢測、EEPROM的操作。定時器T1專門用于DS18B20時序産生,定時器T0用于按鍵檢測、數位管顯示,主函數中做EEPROM及其他的操作。程式中有些注釋是調試過程中加的,并且有些代碼部分在調試中修改過,先前的注釋并沒有同時删去,是以看下面的代碼的時候,不要被注釋誤導了。
代碼如下:
#include "REG51.H"
#include "INTRINS.H"
typedef unsigned char BYTE;
typedef unsigned int WORD;
sfr P1M0 = 0x92; //
sfr P1M1 = 0x91; //
sfr P3M0 = 0xB2;
sfr P3M1 = 0xB1;
sfr P2M0 = 0x96;
sfr P2M1 = 0x95;
/*sfr associated with the IAP*/
sfr IAP_DATA = 0xc2;
sfr IAP_ADDRH = 0xc3;
sfr IAP_ADDRL = 0xc4;
sfr IAP_CMD = 0xc5;
sfr IAP_TRIG = 0xc6;
sfr IAP_CONTR = 0xc7;
/*ISP/IAP/EEPROM command*/
#define CMD_IDLE 0
#define CMD_READ 1
#define CMD_PROGRAM 2
#define CMD_ERASE 3
#define ENABLE_IAP 0x80 //if SYSCLK<30MHz
//#define ENABLE_IAP 0x81//if SYSCLK<24MHz
//start address for STC11/10xx series EEPROM
#define IAP_ADDRESS0x0000
void Delay(BYTE N);
void IapIdle();
BYTE IapReadByte(WORD addr);
void IapProgramByte(WORD addr, BYTE val);
void IapEraseSector(WORD addr);
#define MINUTE 8400 //60*140=8400 interrupts per minute
#define DAY3S 4320 //there are 72*60*8400=4320*8400 interrupts in 72 hours
//
sbit shi = P3^7;
sbit ge = P3^2;
//sbit led = P1^5;
sbit key1 = P3^3;
sbit key2 = P3^4;
sbit key3 = P3^5;
sbit heat = P2^7;
sbit water = P2^5;
sbit beep = P2^0;
unsigned char code digit[11] ={
0xbf,//0
0x83,//1
0xed,//2
0xeb,//3
0xd3,//4
0xfa,//5
0xfe,//6
0xa3,//7
0xff,//8
0xfb,//9
0xc0//nfinished
};
unsigned char code cmd[4] = {0xcc,0x44,0xcc,0xbe};
unsigned int cmd_n;
bit nodevice,cunz;
unsigned char saom;
unsigned int num,t1_num;
unsigned char temp,led;
unsigned int jiaoshui,jiaoshui_t,jiaoshui_tt;
unsigned char wendu,cishu;
unsigned int ds18b20;
unsigned char menu,inc,dec;
BYTE kflag; //
bit adjust;
bit updateEEP;
unsigned int heat_t;
sbit DQ = P3^1; //DS18B20?????P3.3
BYTE TPH; //?????????
BYTE TPL; //?????????
BYTE dat;
void main()
{
updateEEP = 0;
num = 0;
temp = 0;
saom = 0;
led = 0x00;
nodevice = 0;
menu = 0;
inc = 0;
dec = 0;
kflag = 0x00;
adjust = 0;
wendu = 50;
cishu = 72;
heat = 1;
water = 1;
jiaoshui = 0;
jiaoshui_t = 1;
jiaoshui_tt = 0;
P2M0 = 0x01;
P2M1 = 0x00;
beep = 0;
P1M0 = 0xff; //
P1M1 = 0x00; //
// P1 = digit[0];
P3M0 = 0x84; //
P3M1 = 0x84;
P3 = 0X0;
TMOD = 0x11; //TMOD = 0x1;
TH0 = 0x00;
TL0 = 0xff;
TR0 = 1;
ET0 = 1;
TH1 = 0xff;
TL1 = 0x88;//256-120=136=0x88
TR1 = 0;
ET1 = 1; // enable T1 interrupt
PT0 = 0;
PT1 = 1; // T1優先級高
EA = 1;
//read wendu and cishu value from EEPROM
Delay(10);
wendu = IapReadByte(0x0002);
cishu = IapReadByte(0x0003);
jiaoshui = 8400/cishu;
//
while (1)
{
if(updateEEP == 1)
{
updateEEP = 0;
IapEraseSector(0x0000);
IapProgramByte(0x0002,wendu);
IapProgramByte(0x0003,cishu);
jiaoshui = 8400/cishu;
}
beep= (ds18b20>30)? 1:0;
heat= (ds18b20>30)? 0:1;
water=(jiaoshui_t<420)? 0:1;
// beep= (jiaoshui_t<420)? 1:0;
}
}
/
void it_timer0(void) interrupt 1
{
TH0 = 0xc8; //定時時間是1/140s
TL0 = 0x32;
num++;
/*
if(jiaoshui_t
0) wendu--;
else wendu=0;
kflag = 0x00; break;}
else if(menu==2)
{if(cishu>0) cishu--;
else cishu=0;
kflag = 0x00; break;}
else break;
default ://??????????????
break;
}
// P1M0 = 0xff;
// P1M1 = 0x00;
//顯示
saom++;
saom = saom%3;
switch(menu)
{
case 0 : temp = ds18b20; led = 0x00; break;
case 1 : temp = wendu; led = 0x02; break;
case 2 : temp = cishu; led = 0x01; break;
default : temp = ds18b20; break;
}
if(nodevice)
{
shi = 0;
ge = 0;
P1 = digit[10];
}
else
switch(saom)
{
case 0 :
shi = 0;
ge = 1;
P1 = digit[temp/10];
break;
case 1 :
shi = 1;
ge = 0;
P1 = digit[temp%10];
break;
case 2 :
shi = 1;
ge = 1;
if(num < 80) P1 = led;
else P1 = 0x80;
break;
default : break;
}
/*
//加熱定時
if(ds18b20>30) {heat = 1; heat_t++;}
if((heat_t > 0) && (heat_t < 1400))
{heat_t++;}
else {heat_t = 0; heat = 0;}
*/
//采集18B20
if(num>=140)
{
num = 0;
t1_num = 0; cmd_n = 0; nodevice = 0;
TR1 = 1;
}
}
void it_timer1(void) interrupt 3
{
switch(t1_num)
{
case 0 :
case 33 :
cunz = 1; DQ = 0; break;
case 8 :
case 41 :
DQ = 1; break;
case 9 :
case 42 :
cunz = DQ; break;
case 16 : //寫位元組 第一位
case 49 :
if(cunz) {/*ET1 = 0;*/TR1 = 0; nodevice = 1; break;}
else
{
dat = cmd[cmd_n++]; DQ = 0; _nop_(); _nop_();
dat >>= 1; DQ = CY; break;
}
case 17 : //cmd[0]
case 18 :
case 19 :
case 20 :
case 21 :
case 22 :
case 23 :
case 25 : //cmd[1]
case 26 :
case 27 :
case 28 :
case 29 :
case 30 :
case 31 :
case 50 : //cmd[2]
case 51 :
case 52 :
case 53 :
case 54 :
case 55 :
case 56 :
case 58 : //cmd[3]
case 59 :
case 60 :
case 61 :
case 62 :
case 63 :
case 64 :
DQ = 1; _nop_(); _nop_(); //恢複資料線,恢複時間
DQ = 0; _nop_(); _nop_(); //開始下一位
dat >>= 1; DQ = CY; break;
case 24 :
case 57 :
DQ = 1; _nop_(); _nop_(); //寫第一個位元組結束
dat = cmd[cmd_n++]; //填充dat
DQ = 0; _nop_(); _nop_(); //寫第二個位元組
dat >>= 1; DQ = CY; break;
case 32 :
DQ = 1; _nop_(); _nop_(); //寫第二個位元組結束 0x44
_nop_(); _nop_();
case 65 :
DQ = 1; _nop_(); _nop_(); //0xbe 指令發完
dat = 0; //讀TPL
dat >>= 1;
DQ = 0; _nop_(); _nop_();
DQ = 1; _nop_(); _nop_();
if(DQ) dat |= 0x80;
break;
case 66 :
case 67 :
case 68 :
case 69 :
case 70 :
case 71 :
case 72 :
case 74 :
case 75 :
case 76 :
case 77 :
case 78 :
case 79 :
case 80 :
dat >>= 1;
DQ = 0; _nop_(); _nop_();
DQ = 1; _nop_(); _nop_();
if(DQ) dat |= 0x80;
break;
case 73 :
TPL = dat;
dat = 0; //讀TPH
dat >>= 1;
DQ = 0; _nop_(); _nop_();
DQ = 1; _nop_(); _nop_();
if(DQ) dat |= 0x80;
break;
case 81 :
TPH = dat;
TPL = (TPL>>4) & 0x0f;
TPH = (TPH<<4) & 0xf0;
ds18b20 = TPL | TPH;
if(ds18b20>99 | ds18b20 <=0)
nodevice = 1;
TR1 = 0;
break;
default : break;
}
t1_num++;
TH1 = 0xff;
TL1 = 0x88;//256-120=136=0x88
}
//
void Delay(BYTE n)
{
WORD x;
while(n--)
{
x = 0;
while(++x);
}
}
void IapIdle()
{
IAP_CONTR = 0;
IAP_CMD = 0;
IAP_TRIG = 0;
IAP_ADDRH = 0xff;
IAP_ADDRL = 0xff;
}
BYTE IapReadByte(WORD addr)
{
BYTE rdval;
IAP_CONTR = ENABLE_IAP;
IAP_CMD = CMD_READ;
IAP_ADDRL = addr;
IAP_ADDRH = addr >> 8;
IAP_TRIG = 0x5a;
IAP_TRIG = 0xa5;
_nop_();
rdval = IAP_DATA;
IapIdle();
return rdval;
}
void IapProgramByte(WORD addr, BYTE val)
{
IAP_CONTR = ENABLE_IAP;
IAP_CMD = CMD_PROGRAM;
IAP_ADDRL = addr;
IAP_ADDRH = addr >> 8;
IAP_DATA = val;
IAP_TRIG = 0x5a;
IAP_TRIG = 0xa5;
_nop_();
IapIdle();
}
void IapEraseSector(WORD addr)
{
IAP_CONTR = ENABLE_IAP;
IAP_CMD = CMD_ERASE;
IAP_ADDRL = addr;
IAP_ADDRH = addr >> 8;
IAP_TRIG = 0x5a;
IAP_TRIG = 0xa5;
_nop_();
IapIdle();
}