找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

帖子
查看: 2743|回復(fù): 2
收起左側(cè)

系統(tǒng)分析51單片機(jī)時(shí)鐘12C887+溫度18b20C程序

[復(fù)制鏈接]
ID:444712 發(fā)表于 2018-12-18 16:26 | 顯示全部樓層 |閱讀模式
本帖最后由 lzj23642008 于 2018-12-18 16:38 編輯

目前單片機(jī)數(shù)據(jù)傳輸?shù)拇锌偩€主要由Inter IC Bus, SPI和SCI。其中IIC總線以同步串行二線方式進(jìn)行通信(一條數(shù)據(jù)線、一條時(shí)鐘線),SPI總線則是以同步串行三線方式進(jìn)行通信(一條時(shí)鐘線,一條數(shù)據(jù)輸入線,一條數(shù)據(jù)輸出線),而SCI總線是以異步方式進(jìn)行通信(一條輸入線,一條輸出線)。DS18B20采用單條信號(hào)線,既可以傳輸時(shí)鐘又可以傳輸數(shù)據(jù),而且數(shù)據(jù)是雙向傳輸,因而這種總線技術(shù)具有線路簡單,硬件開銷少、陳本低廉,便于總線擴(kuò)展等優(yōu)點(diǎn)。單總線適用于單主機(jī)系統(tǒng),能夠控制一個(gè)或者多個(gè)從機(jī)設(shè)備。

設(shè)備(主機(jī)或者從機(jī))通過一個(gè)漏極開路或三態(tài)端口連接至數(shù)據(jù)線,以允許設(shè)備在不發(fā)送數(shù)據(jù)時(shí)能夠釋放總線,而讓求他設(shè)備使用總線。單總線通常要求外接一個(gè)約為5Kohm的上拉電阻。

1336038306_4401.jpg

工作原理

64位光刻ROM各位定義
8位CRC碼        48位序列號(hào)        8位產(chǎn)品類型標(biāo)號(hào)

首先是DS18B20的控制命令

1. 33H - 讀ROM。讀取DS18B20溫度傳感器ROM中的編碼(64位地址)

2. 55H- 匹配ROM。發(fā)出此命令后,接著發(fā)出64位ROM碼,訪問單總線上相對(duì)應(yīng)的DS18B20并使之作出響應(yīng),為下一步對(duì)該模塊讀寫做準(zhǔn)備;

3. F0H- 搜索ROM。用于確定掛載在同一總線上DS18B20的個(gè)數(shù),識(shí)別64位ROM地址,位操作和期間做準(zhǔn)備。

4. CCH - 跳過ROM。忽略64位ROM地址,直接向18B20發(fā)溫度變換指令,適用于一個(gè)從幾工作形式

5. ECH - 告警搜索命令。執(zhí)行后只有溫度超多設(shè)定值上限或者下線的時(shí)候芯片才做出響應(yīng)。



64位光刻ROM中的序號(hào)是粗長前就被可好的,他可以看作該模塊的地址序列號(hào)。光刻ROM的作用就是使每個(gè)DS18B20都具有不一樣的序列號(hào),這樣就可以實(shí)現(xiàn)在一條總線上掛載多個(gè)DS18B20的目的。

常見模式:當(dāng)主機(jī)需要與眾多在線DS18B20中某一個(gè)連接時(shí),首先將主機(jī)逐個(gè)與DS18B20掛載,讀出器序列號(hào),然后再將所有的DS18B20掛載到總線上,單片機(jī)發(fā)出匹配ROM命令(55H),緊接著主機(jī)提供64位序列號(hào)之后的操作就只針對(duì)此DS18B20。

如果主機(jī)只與一個(gè)DS18B20進(jìn)行操作,就不需要讀取ROM編碼,以及匹配編碼,只要用跳過ROM指令,就可以進(jìn)行如下的溫度轉(zhuǎn)化和讀取操作。

1. 44H -- 溫度轉(zhuǎn)換。啟動(dòng)DS18B20進(jìn)行溫度轉(zhuǎn)換,12轉(zhuǎn)換時(shí)間長度為750ms(9位時(shí)長93.75ms)。結(jié)果存入內(nèi)部RAM中。

2. BEH -- 讀暫存器。讀內(nèi)部RAM中的9字節(jié)的溫度數(shù)據(jù)

3. 4EH -- 寫暫存器;發(fā)出向內(nèi)部RAM的第2,3字節(jié)寫上、下限數(shù)溫度數(shù)據(jù)命令,緊跟該命令之后,是傳輸兩字節(jié)數(shù)據(jù)。

4. 48H-- 復(fù)制暫存器;將RAM中的第2、3字節(jié)內(nèi)容復(fù)制到EEPROM中。

5.B8H -- 重調(diào)EEPROM。將EEPROM的內(nèi)容復(fù)制到RAM中的第3、4字節(jié)。

6. B4H -- 讀取供電方式。讀DS18B20的供電模式,寄生供電時(shí),DS18B20發(fā)送0;外接電源供電時(shí),DS18B20發(fā)送1;

高速暫存RAM

高速暫存RAM
寄存器內(nèi)容        字節(jié)地址
溫度值低位(LSB)        0
溫度值高位(MSB)        1
高溫限制(TH)        2
低溫限制(LH)        3
配置寄存器        4
保留        5
保留        6
CRC校驗(yàn)值        8
少了一個(gè)保留至在第七位
溫度數(shù)據(jù)在高速暫存寄存器的第0、1字節(jié)中存儲(chǔ)格式

溫度數(shù)據(jù)存儲(chǔ)格式
D7        D6        D5        D4        D3        D2        D1        D0
                                                               
D15        D14        D13        D12        D11        D10        D9        D8
                                                               
DS18B20在出廠默認(rèn)設(shè)置是12位精度,其中最高位為符號(hào)位,即溫度值共11位,單片機(jī)在讀取數(shù)據(jù)時(shí),一次會(huì)讀取兩字節(jié)共16位,讀完后將低11位的二進(jìn)制數(shù)轉(zhuǎn)化為十進(jìn)制數(shù)后,再乘以0..625便為所測(cè)量的實(shí)際溫度。另外需要判斷溫度的正負(fù)值、前五位數(shù)字為符號(hào)位,著5位同時(shí)變化。同時(shí)為1時(shí)候,讀取的溫度為負(fù)值,且測(cè)量到的溫度需要取反加一再乘以0.0625才可以得到正確溫度值,前五位為0時(shí),讀取溫度為正值,直接乘以0.0625即可。
---------------------

這個(gè)設(shè)計(jì)軟件的源程序如下:

#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;//數(shù)值加1
sbit s3=P3^2;//數(shù)值減1
sbit s4=P3^6;//鬧鐘查看設(shè)置鍵
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;  //溫度數(shù)據(jù)通信線
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;//開定時(shí)器0中斷
IT1=1;//
flag1=0;//鬧鐘設(shè)置,0為不響
s1num=0;
dula=0;//關(guān)閉數(shù)碼管
wela=0;//關(guān)閉數(shù)碼管
lcden=0;
rd=0;
// set_time();
read_alarm();
write_ds(0x0a,0x20);//時(shí)鐘芯片寄存器A
write_ds(0x0b,0x26);//時(shí)鐘芯片寄存器B
// read_ds(0x0c);      //時(shí)鐘芯片寄存器C
write_com(0x38);    //液晶顯示模式
write_com(0x0c);    //液晶顯示、開關(guān)、光標(biāo)打開
write_com(0x06);    //液晶地址指針及光標(biāo)移動(dòng)情況
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復(fù)位
Delay_DS18B20(8);//稍做延時(shí)
DQ = 0;         //單片機(jī)將DQ拉低
Delay_DS18B20(80);//精確延時(shí),大于480us
DQ = 1;         //拉高總線
Delay_DS18B20(14);
x = DQ;        //稍做延時(shí)后,如果x=0則初始化成功,x=1則初始化失敗
Delay_DS18B20(20);
}

uchar ReadOneChar()
{
uchar i=0;
uchar dat = 0;
for (i=8;i>0;i--)
{
  DQ = 0;     // 給脈沖信號(hào)
  dat>>=1;
  DQ = 1;     // 給脈沖信號(hào)
  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);  //跳過讀序號(hào)列號(hào)的操作
WriteOneChar(0x44);  //啟動(dòng)溫度轉(zhuǎn)換
Init_DS18B20();
WriteOneChar(0xCC);  //跳過讀序號(hào)列號(hào)的操作
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);//個(gè)位
write_date(0x2e);//小數(shù)點(diǎn)
write_date(0x30+A3);//小數(shù)點(diǎn)后一位
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鍵消除報(bào)警
{
  if((s1==0)||(s4==0))
  {
   delay(5);
   if((s1==0)||(s4==0))
   while(!(s1&&s4));
   didi();
   flag1=0;//消除報(bào)警標(biāo)志
  }
}

if(s1==0) //調(diào)時(shí)功能鍵
{
  delay(5);
  if(s1==0)
  {
   s1num++;
   flag=1;//flag功能鍵標(biāo)志位  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)//鬧鐘設(shè)置鍵
{
  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;  //再寫數(shù)據(jù)
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; //再讀數(shù)據(jù)
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;        //時(shí)鐘芯片的顯示標(biāo)志
  init();      //時(shí)鐘芯片的初始化   
while(1)
{
  keyscan();
  if(flag1==1)//鬧鐘設(shè)置
  {
   didi();
   delay(100);
   didi();
   delay(500);
  }
  if(flag==0)//flag顯示標(biāo)志位 0為顯示
  {
   keyscan();
   miao=read_ds(0);//讀12C887數(shù)據(jù)
   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);
}



評(píng)分

參與人數(shù) 1黑幣 +100 收起 理由
admin + 100 共享資料的黑幣獎(jiǎng)勵(lì)!

查看全部評(píng)分

回復(fù)

使用道具 舉報(bào)

ID:981080 發(fā)表于 2021-11-16 15:17 | 顯示全部樓層
大佬有沒有hex文件
回復(fù)

使用道具 舉報(bào)

ID:981080 發(fā)表于 2021-11-16 16:23 | 顯示全部樓層
液晶顯示亮屏但沒有數(shù)字顯示是怎么回事
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表