本帖最后由 lzj23642008 于 2018-12-18 16:38 編輯
目前單片機數據傳輸的串行總線主要由Inter IC Bus, SPI和SCI。其中IIC總線以同步串行二線方式進行通信(一條數據線、一條時鐘線),SPI總線則是以同步串行三線方式進行通信(一條時鐘線,一條數據輸入線,一條數據輸出線),而SCI總線是以異步方式進行通信(一條輸入線,一條輸出線)。DS18B20采用單條信號線,既可以傳輸時鐘又可以傳輸數據,而且數據是雙向傳輸,因而這種總線技術具有線路簡單,硬件開銷少、陳本低廉,便于總線擴展等優點。單總線適用于單主機系統,能夠控制一個或者多個從機設備。
設備(主機或者從機)通過一個漏極開路或三態端口連接至數據線,以允許設備在不發送數據時能夠釋放總線,而讓求他設備使用總線。單總線通常要求外接一個約為5Kohm的上拉電阻。
1336038306_4401.jpg (132.7 KB, 下載次數: 49)
下載附件
2018-12-18 16:21 上傳
工作原理
64位光刻ROM各位定義
8位CRC碼 48位序列號 8位產品類型標號
首先是DS18B20的控制命令
1. 33H - 讀ROM。讀取DS18B20溫度傳感器ROM中的編碼(64位地址)
2. 55H- 匹配ROM。發出此命令后,接著發出64位ROM碼,訪問單總線上相對應的DS18B20并使之作出響應,為下一步對該模塊讀寫做準備;
3. F0H- 搜索ROM。用于確定掛載在同一總線上DS18B20的個數,識別64位ROM地址,位操作和期間做準備。
4. CCH - 跳過ROM。忽略64位ROM地址,直接向18B20發溫度變換指令,適用于一個從幾工作形式
5. ECH - 告警搜索命令。執行后只有溫度超多設定值上限或者下線的時候芯片才做出響應。
64位光刻ROM中的序號是粗長前就被可好的,他可以看作該模塊的地址序列號。光刻ROM的作用就是使每個DS18B20都具有不一樣的序列號,這樣就可以實現在一條總線上掛載多個DS18B20的目的。
常見模式:當主機需要與眾多在線DS18B20中某一個連接時,首先將主機逐個與DS18B20掛載,讀出器序列號,然后再將所有的DS18B20掛載到總線上,單片機發出匹配ROM命令(55H),緊接著主機提供64位序列號之后的操作就只針對此DS18B20。
如果主機只與一個DS18B20進行操作,就不需要讀取ROM編碼,以及匹配編碼,只要用跳過ROM指令,就可以進行如下的溫度轉化和讀取操作。
1. 44H -- 溫度轉換。啟動DS18B20進行溫度轉換,12轉換時間長度為750ms(9位時長93.75ms)。結果存入內部RAM中。
2. BEH -- 讀暫存器。讀內部RAM中的9字節的溫度數據
3. 4EH -- 寫暫存器;發出向內部RAM的第2,3字節寫上、下限數溫度數據命令,緊跟該命令之后,是傳輸兩字節數據。
4. 48H-- 復制暫存器;將RAM中的第2、3字節內容復制到EEPROM中。
5.B8H -- 重調EEPROM。將EEPROM的內容復制到RAM中的第3、4字節。
6. B4H -- 讀取供電方式。讀DS18B20的供電模式,寄生供電時,DS18B20發送0;外接電源供電時,DS18B20發送1;
高速暫存RAM
高速暫存RAM
寄存器內容 字節地址
溫度值低位(LSB) 0
溫度值高位(MSB) 1
高溫限制(TH) 2
低溫限制(LH) 3
配置寄存器 4
保留 5
保留 6
CRC校驗值 8
少了一個保留至在第七位
溫度數據在高速暫存寄存器的第0、1字節中存儲格式
溫度數據存儲格式
D7 D6 D5 D4 D3 D2 D1 D0
D15 D14 D13 D12 D11 D10 D9 D8
DS18B20在出廠默認設置是12位精度,其中最高位為符號位,即溫度值共11位,單片機在讀取數據時,一次會讀取兩字節共16位,讀完后將低11位的二進制數轉化為十進制數后,再乘以0..625便為所測量的實際溫度。另外需要判斷溫度的正負值、前五位數字為符號位,著5位同時變化。同時為1時候,讀取的溫度為負值,且測量到的溫度需要取反加一再乘以0.0625才可以得到正確溫度值,前五位為0時,讀取溫度為正值,直接乘以0.0625即可。
---------------------
這個設計軟件的源程序如下:
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit dula=P2^6;
sbit wela=P2^7;
sbit rs=P3^5;
sbit lcden=P3^4;
sbit s1=P3^0;//功能鍵選擇
sbit s2=P3^1;//數值加1
sbit s3=P3^2;//數值減1
sbit s4=P3^6;//鬧鐘查看設置鍵
sbit rd=P3^7;//
sbit beep=P2^3;//蜂鳴器
sbit dscs=P1^4;
sbit dsas=P1^5;
sbit dsrw=P1^6;
sbit dsds=P1^7;
sbit dsirq=P3^3;
sbit DQ=P2^2; //溫度數據通信線
uint temp,tplsb,tpmsb; //溫度
uchar s1num,s4num,flag,flag1;
uchar miao,shi,fen,week,ri,yue,nian,amiao,afen,ashi;
uchar code table1[]=" - - ";
uchar code table2[]=" : : ";
// 周一周二 周三 周四 周五 周六 周日
uchar code table3[]={0xff,0x4d,0x54,0x57,0x54,0x46,0x53,0x53};
// M T W T F S S
uchar code table4[]={0xff,0x4f,0x55,0x45,0x48,0x52,0x41,0x55};
// O U E H R A U
uchar code table5[]={0xff,0x4e,0x45,0x44,0x55,0x49,0x54,0x4e};
// N E D U I T N
void write_ds(uchar,uchar);
void set_alarm(uchar,uchar,uchar);
uchar read_ds(uchar);
//void set_time();
void read_alarm();
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void Delay_DS18B20(uint num)
{
while(num--) ;
}
void write_com(uchar com)
{
rs=0;
lcden=0;
P0=com;
delay(3);
lcden=1;
delay(3);
lcden=0;
}
void write_date(uchar date)
{
rs=1;
lcden=0;
P0=date;
delay(3);
lcden=1;
delay(3);
lcden=0;
}
void init()
{
uchar num;
EA=1; //打開總中斷
EX1=1;//開定時器0中斷
IT1=1;//
flag1=0;//鬧鐘設置,0為不響
s1num=0;
dula=0;//關閉數碼管
wela=0;//關閉數碼管
lcden=0;
rd=0;
// set_time();
read_alarm();
write_ds(0x0a,0x20);//時鐘芯片寄存器A
write_ds(0x0b,0x26);//時鐘芯片寄存器B
// read_ds(0x0c); //時鐘芯片寄存器C
write_com(0x38); //液晶顯示模式
write_com(0x0c); //液晶顯示、開關、光標打開
write_com(0x06); //液晶地址指針及光標移動情況
write_com(0x01); //清屏
write_com(0x80); //屏幕第一行
for(num=0;num<12;num++)
{
write_date(table1[num]);
delay(1);
}
write_com(0x80+0x40);//屏幕第二行
for(num=0;num<16;num++)
{
write_date(table2[num]);
delay(1);
}
}
void Init_DS18B20()
{
uchar x=0;
DQ = 1; //DQ復位
Delay_DS18B20(8);//稍做延時
DQ = 0; //單片機將DQ拉低
Delay_DS18B20(80);//精確延時,大于480us
DQ = 1; //拉高總線
Delay_DS18B20(14);
x = DQ; //稍做延時后,如果x=0則初始化成功,x=1則初始化失敗
Delay_DS18B20(20);
}
uchar ReadOneChar()
{
uchar i=0;
uchar dat = 0;
for (i=8;i>0;i--)
{
DQ = 0; // 給脈沖信號
dat>>=1;
DQ = 1; // 給脈沖信號
if(DQ)
dat|=0x80;
Delay_DS18B20(4);
}
return(dat);
}
void WriteOneChar(uchar dat)
{
uchar i=0;
for (i=8; i>0; i--)
{
DQ = 0;
DQ = dat&0x01;
Delay_DS18B20(5);
DQ = 1;
dat>>=1;
}
}
uint Readtemp()
{
uchar a=0;
uchar b=0;
uint t=0;
float tt=0;
Init_DS18B20();
WriteOneChar(0xCC); //跳過讀序號列號的操作
WriteOneChar(0x44); //啟動溫度轉換
Init_DS18B20();
WriteOneChar(0xCC); //跳過讀序號列號的操作
WriteOneChar(0xBE); //讀取溫度寄存器
a=ReadOneChar(); //讀低8位
b=ReadOneChar(); //讀高8位
t=b;
t<<=8;
t=t|a;
tt=t*0.0625;
t= tt*10+0.5; //放大10倍輸出并四舍五入
return(t);
}
void display(uint temp)
{
uchar A1,A2,A3;
A1=temp/100;
A2=temp%100/10;
A3=temp%10;
write_com(0x80+0x40+10);
write_date(0x30+A1);//十位
write_date(0x30+A2);//個位
write_date(0x2e);//小數點
write_date(0x30+A3);//小數點后一位
write_date(0xdf);//
write_date(0x43);//C
}
void didi()
{
beep=0;
delay(100);
beep=1;
}
void write_nyrx(uchar add,uchar date)
{
uchar shi,ge;
shi=date/10;
ge=date%10;
write_com(0x80+add);
write_date(0x30+shi);
write_date(0x30+ge);
}
void write_sfm(uchar add,uchar date)//
{
uchar shi,ge;
shi=date/10;
ge=date%10;
write_com(0x80+0x40+add);
write_date(0x30+shi);
write_date(0x30+ge);
}
void keyscan()
{
// rd=0;
if(flag1==1)//按s1 s4鍵消除報警
{
if((s1==0)||(s4==0))
{
delay(5);
if((s1==0)||(s4==0))
while(!(s1&&s4));
didi();
flag1=0;//消除報警標志
}
}
if(s1==0) //調時功能鍵
{
delay(5);
if(s1==0)
{
s1num++;
flag=1;//flag功能鍵標志位 0為顯示,1為不顯示
while(!s1);
didi();
if(s1num==1)
{
TR1=0;
write_com(0x80+0x40+8);
write_com(0x0f);
}
if(s1num==2)
{
write_com(0x80+0x40+5);
}
if(s1num==3)
{
write_com(0x80+0x40+2);
}
if(s1num==4)
{
write_com(0x80+9);
}
if(s1num==5)
{
write_com(0x80+6);
}
if(s1num==6)
{
write_com(0x80+3);
}
if(s1num==7)
{
write_com(0x80+0);
}
if(s1num==8)
{
s1num=0;
write_com(0x0c);
flag=0;
write_ds(0,miao);
write_ds(2,fen);
write_ds(4,shi);
write_ds(6,week);
write_ds(7,ri);
write_ds(8,yue);
write_ds(9,nian);
}
}
}
if(s1num!=0)
{
if(s2==0)//功能鍵加1
{
delay(5);
if(s2==0)
{
delay(5);
while(!s2);
didi();
if(s1num==1)
{
miao++;
if(miao==60)
miao=0;
write_sfm(7,miao);
write_com(0x80+0x40+8);
}
if(s1num==2)
{
fen++;
if(fen==60)
fen=0;
write_sfm(4,fen);
write_com(0x80+0x40+5);
}
if(s1num==3)
{
shi++;
if(shi==24)
shi=0;
write_sfm(1,shi);
write_com(0x80+0x40+2);
}
if(s1num==4)
{
week++;
if(week==8)
week=0;
write_com(0x80+9);
write_date(table3[week]);
write_date(table4[week]);
write_date(table5[week]);
}
if(s1num==5)
{
ri++;
if(ri==32)
ri=1;
write_nyrx(6,ri);
write_com(0x80+6);
}
if(s1num==6)
{
yue++;
if(yue==13)
yue=1;
write_nyrx(3,yue);
write_com(0x80+3);
}
if(s1num==7)
{
nian++;
if(nian==99)
nian=0;
write_nyrx(0,nian);
write_com(0x80+0);
}
}
}
if(s3==0)//功能鍵減1
{
delay(5);
if(s3==0)
{
delay(5);
while(!s3);
didi();
if(s1num==1)
{
miao--;
if(miao==-1)
miao=59;
write_sfm(7,miao);
write_com(0x80+0x40+8);
}
if(s1num==2)
{
fen--;
if(fen==-1)
fen=59;
write_sfm(4,fen);
write_com(0x80+0x40+5);
}
if(s1num==3)
{
shi--;
if(shi==-1)
shi=23;
write_sfm(1,shi);
write_com(0x80+0x40+2);
}
if(s1num==4)
{
week--;
if(week==0)
week=7;
write_com(0x80+9);
write_date(table3[week]);
write_date(table4[week]);
write_date(table5[week]);
}
if(s1num==5)
{
ri--;
if(ri==0)
ri=31;
write_nyrx(6,ri);
write_com(0x80+6);
}
if(s1num==6)
{
yue--;
if(yue==0)
yue=12;
write_nyrx(3,yue);
write_com(0x80+3);
}
if(s1num==7)
{
nian--;
if(nian==-1)
nian=99;
write_nyrx(0,nian);
write_com(0x80+0);
}
}
}
}
if(s4==0)//鬧鐘設置鍵
{
delay(5);
if(s4==0)
{
s4num++;
flag=1; //
while(!s4);
didi();
if(s4num==1)
{
write_com(0x80);
write_date(' ');
write_date(' ');
write_date('S');
write_date('E');
write_date('T');
write_date(' ');
write_date(' ');
write_date('A');
write_date('L');
write_date('A');
write_date('R');
write_date('M');
write_com(0x80+0x40);
write_date(' ');
write_date('0');
write_date('0');
write_date(':');
write_date('0');
write_date('0');
write_date(':');
write_date('0');
write_date('0');
write_com(0x80+0x40+8);
write_com(0x0f);
}
if(s4num==2)
write_com(0x80+0x40+5);
if(s4num==3)
write_com(0x80+0x40+2);
if(s4num==4)
{
s4num=0;
write_com(0x0c);
flag=0;
write_com(0x80+2);
write_date('-');
write_com(0x80+5);
write_date('-');
write_com(0x80+8);
write_date(' ');
write_ds(0,miao);
write_ds(1,amiao);
write_ds(2,fen);
write_ds(3,afen);
write_ds(4,shi);
write_ds(5,ashi);
write_ds(6,week);
write_ds(7,ri);
write_ds(8,yue);
write_ds(9,nian);
}
}
}
if(s4num!=0)
{
if(s2==0)//加1
{
delay(5);
if(s2==0)
{
delay(5);
while(!s2);
didi();
if(s4num==1)
{
amiao++;
if(amiao==60)
amiao=0;
write_sfm(7,amiao);
write_com(0x80+0x40+8);
}
if(s4num==2)
{
afen++;
if(afen==60)
afen=0;
write_sfm(4,afen);
write_com(0x80+0x40+5);
}
if(s4num==3)
{
ashi++;
if(ashi==24)
ashi=0;
write_sfm(1,ashi);
write_com(0x80+0x40+2);
}
}
}
if(s3==0)//減1
{
delay(5);
if(s3==0)
{
delay(5);
while(!s3);
didi();
if(s4num==1)
{
amiao--;
if(amiao==-1)
amiao=59;
write_sfm(7,amiao);
write_com(0x80+0x40+8);
}
if(s4num==2)
{
afen--;
if(afen==-1)
afen=59;
write_sfm(4,afen);
write_com(0x80+0x40+5);
}
if(s4num==3)
{
ashi--;
if(ashi==-1)
ashi=23;
write_sfm(1,ashi);
write_com(0x80+0x40+2);
}
}
}
}
}
void write_ds(uchar add,uchar date)
{
dscs=0;
dsas=1;
dsds=1;
dsrw=1;
P0=add; //先寫地址
dsas=0;
dsrw=0;
P0=date; //再寫數據
dsrw=1;
dsas=1;
dscs=1;
}
uchar read_ds(uchar add)
{
uchar ds_date;
dsas=1;
dsds=1;
dsrw=1;
dscs=0;
P0=add; //先寫地址
dsas=0;
dsds=0;
P0=0xff;
ds_date=P0; //再讀數據
dsds=1;
dsas=1;
dscs=1;
return ds_date;
}
void read_alarm()
{
amiao=read_ds(1);
afen=read_ds(3);
ashi=read_ds(5);
}
void main()
{
Readtemp(); // 讀溫度
flag=0; //時鐘芯片的顯示標志
init(); //時鐘芯片的初始化
while(1)
{
keyscan();
if(flag1==1)//鬧鐘設置
{
didi();
delay(100);
didi();
delay(500);
}
if(flag==0)//flag顯示標志位 0為顯示
{
keyscan();
miao=read_ds(0);//讀12C887數據
fen=read_ds(2);
shi=read_ds(4);
week=read_ds(6);
ri =read_ds(7);
yue=read_ds(8);
nian=read_ds(9);
write_sfm(7,miao);//送液晶顯示
write_sfm(4,fen);
write_sfm(1,shi);
write_nyrx(6,ri);
write_nyrx(3,yue);
write_nyrx(0,nian);
write_com(0x80+9);
write_date(table3[week]);
write_date(table4[week]);
write_date(table5[week]);
display(Readtemp());//顯示溫度
}
}
}
void exter() interrupt 2 //鬧鐘中斷
{
uchar c;
flag1=1;
c=read_ds(0x0c);
}
|