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

QQ登錄

只需一步,快速開(kāi)始

搜索
查看: 5284|回復(fù): 6
打印 上一主題 下一主題
收起左側(cè)

簡(jiǎn)單51單片機(jī)多點(diǎn)18b20溫度測(cè)量系統(tǒng)源碼

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:280461 發(fā)表于 2018-1-28 18:21 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
分享我的期末作業(yè),基于51單片機(jī)的多點(diǎn)溫度測(cè)量
同時(shí)多點(diǎn)溫度測(cè)量是在單總線上掛載多個(gè)18b20溫度傳感器

單片機(jī)源程序如下:
  1. #include <reg51.h>      
  2. #include <intrins.h>  
  3. #define uchar unsigned char  
  4. #define uint unsigned int  
  5. #define MAXNUM 4        //宏定義單總線上最大可掃描DS18B20個(gè)數(shù)  
  6. //*****************************//
  7. //**初始定義管腳、變量與數(shù)組***//
  8. //*****************************//     
  9. sbit DS=P3^7;
  10. sbit lcden=P2^7;//液晶使能端
  11. sbit lcdrs=P2^6;//液晶數(shù)0據(jù)命令選擇端
  12. sbit lcdrw=P2^5;
  13. union{                 
  14.     uchar c[2];        
  15.     uint x;            
  16. }temp;                                          
  17. uchar time=0;   
  18. uint cc,xs;             //變量cc中保存計(jì)算出的溫度值的整數(shù)部分,xs保存計(jì)算出的溫度值的小數(shù)部分的第一位            
  19. uchar idata disbuffer[6];   //LCD顯示緩存數(shù)組  
  20. uchar idata ID[4][8]={0};//{{0x28,0xff,0x80,0x2e,0x70,0x16,0x03,0xad},{0x28,0xff,0x95,0xb5,0x81,0x16,0x03,0x50},{0x28,0xff,0x02,0x96,0xa1,0x16,0x04,0x59},{0x28,0xff,0xf0,0xf5,0x62,0x16,0x04,0xd3}};
  21.                        //{"82FF08E2076130DA","82FF595B18613005","82FF20691A614095","82FF0F5F2661403D"};   //用于記錄各DS18B20的ROM序列號(hào)  
  22. uchar idata RomID_temp[8];  //匹配DS18B20時(shí)臨時(shí)記錄要匹配DS18B20的序列號(hào)
  23. uchar east[5]=" EAST";
  24. uchar west[5]=" WEST";
  25. uchar south[5]="SOUTH";
  26. uchar north[5]="NORTH";
  27. uchar m=0;            
  28. uchar num=0;           
  29. //***************************//
  30. //*******18b20時(shí)序延時(shí)*******//
  31. //***************************//
  32. void delay(uint i)      //i*9.62us   
  33. {  
  34.     uint j;  
  35.     for(j=i;j>0;j--);  
  36. }  
  37.   
  38. void delay_ms(uchar i)  //(j*2+1+2)*i+5     
  39. { uchar j;              //12MHz   0.5*i ms  
  40.   do{j=248;            
  41.      do{j--;}while(j);   
  42.      i--;   
  43.     }while(i);   
  44. }  
  45.    
  46. void delay_2us(uchar i)   // 2*i+5 us  
  47. {  
  48.   while(--i);  
  49. }  
  50. //**************************//
  51. //******18b20子程***********//
  52. //**************************//  
  53. uchar DS_init(void)       //18B20復(fù)位,初始化函數(shù)  
  54. {  
  55.   uchar presence;  
  56.   DS=0;          delay_2us(250); //根據(jù)DS18B20的復(fù)位時(shí)序.先把總線拉低555us  
  57.   DS=1;          delay_2us(30);  //再釋放總線,65us后讀取DS18B20發(fā)出的信號(hào)  
  58.   presence=DS;   delay_2us(250); //如果復(fù)位成功,則presence的值為0;否則為1  
  59.   return (presence);             //返回0則初始化成功,否則失敗  
  60. }   
  61.   
  62. uchar read_byte(void)       //讀1字節(jié)  
  63. {  
  64.   uchar i,j,dat=0;  
  65.   for(i=1;i<=8;i++)          //作8個(gè)循環(huán),讀出的8位組成一個(gè)字節(jié)  
  66.     {DS=0;   _nop_();       //先將總線拉低1us,   
  67.      DS=1;   delay_2us(2);  //再釋放總線,產(chǎn)生讀起始信號(hào),延遲9us后讀取總線上的DS18B20發(fā)出的值  
  68.      j=DS;   delay_2us(30); //一位讀完后,延遲65us后讀下一位  
  69.      dat=(j<<7)|(dat>>1);   //讀出的數(shù)據(jù)最低位在一個(gè)字節(jié)的最低位,這樣剛好一個(gè)字節(jié)在DAT里  
  70.     }  
  71.   return(dat);  
  72. }   
  73.   
  74. uchar read_2bit(void)       //讀2位  
  75. {  
  76.   uchar i=0,j=0;  
  77.   DS=0;   _nop_();          //先將總線拉低1us,   
  78.   DS=1;   delay_2us(2);     //再釋放總線,產(chǎn)生讀起始信號(hào),延遲9us后讀取總線上的DS18B20發(fā)出的值  
  79.   j=DS;   delay_2us(30);    //一位讀完后,延遲65us后讀下一位  
  80.   DS=0;   _nop_();            
  81.   DS=1;   delay_2us(2);  
  82.   i=DS;   delay_2us(30);  
  83.   i=j*2+i;              //將讀出的兩位放到變量i中,其中第一個(gè)讀出的位處于i的第1位;而第二個(gè)讀出的位處于i的第0位  
  84.   return(i);  
  85. }   
  86.    
  87. void write_byte(uchar dat)  //寫(xiě)1字節(jié)  
  88. {   
  89.   uchar i;  
  90.   for(i=0;i<8;i++)           //作8個(gè)循環(huán),寫(xiě)入的8位組成一個(gè)字節(jié)  
  91.     {DS=0;                  //先將總線拉低  
  92.      DS = dat&0x01;         //向總線上放入要寫(xiě)的值  
  93.      delay_2us(50);         //延遲105us,以使DS18B20能采樣到要寫(xiě)入的值  
  94.      DS = 1;                //釋放總線,準(zhǔn)備寫(xiě)入下一位  
  95.      dat>>=1;             //將要寫(xiě)的下一位移到dat的最低位        
  96.     }  
  97. }   
  98.    
  99. void write_bit(bit dat) //寫(xiě)1位  
  100. {   
  101.   DS=0;             //先將總線拉低  
  102.   DS=dat;           //向總線上放入要寫(xiě)的值  
  103.   delay_2us(50);    //延遲105us,以使DS18B20能采樣到要寫(xiě)入的值  
  104.   DS = 1;           //釋放總線  
  105. }  
  106. //************************//
  107. //*******1602延時(shí)*********//
  108. //************************//
  109. void delay1(uint z)
  110. {
  111.         uint i,j;
  112.         for(i=z;i>0;i--)
  113.         for(j=110;j>0;j--);
  114. }
  115. //************************//
  116. //******1602子程**********//
  117. //************************//
  118. void write_com(uchar com) //寫(xiě)命令
  119. {
  120.         lcdrs=0;//選擇寫(xiě)命令模式
  121.         P0=com;//將要寫(xiě)的命令字送到數(shù)據(jù)總線上
  122.         delay1(5);//稍作延時(shí)以待數(shù)據(jù)穩(wěn)定
  123.         lcden=1;//使能端給一高電平脈沖,因?yàn)槌跏蓟瘮?shù)中已將lcden置零
  124.         delay1(5);//稍作延時(shí)
  125.         lcden=0;//將使能端置零完成高脈沖
  126. }

  127. void write_data(uchar date)  //寫(xiě)數(shù)據(jù)
  128. {
  129.         lcdrs=1;//選擇寫(xiě)數(shù)據(jù)操作
  130.         P0=date;//將要寫(xiě)的數(shù)據(jù)送到數(shù)據(jù)總線上
  131.         delay1(5);//稍作延時(shí)
  132.         lcden=1;//使能端給一高電平脈沖
  133.         delay1(5);
  134.         lcden=0;
  135. }

  136. void init()   //1602初始化
  137. {
  138.         lcdrw=0;
  139.         lcden=0;
  140.         write_com(0x38);//設(shè)置16*2顯示,5*7點(diǎn)陣,8位數(shù)據(jù)接口
  141.         write_com(0x0c);//設(shè)置開(kāi)顯示,不顯示光標(biāo)
  142.         write_com(0x06);//寫(xiě)一個(gè)字節(jié)后地址指針加1
  143.         write_com(0x01);//顯示清零,數(shù)據(jù)指針清零
  144.         write_com(0x80);//設(shè)置數(shù)據(jù)指針起點(diǎn)
  145. }
  146. //****************************//
  147. //***讀取18b20溫度數(shù)據(jù)子程 ***//
  148. //****************************//
  149. void Read_Temperature_rom(void) //讀取溫度函數(shù)  
  150. {   uchar i;  
  151.     DS_init();  
  152.     write_byte(0x55);       //匹配ROM  
  153.     for(i=0;i<8;i++)     //發(fā)出64位ROM編碼  
  154.             write_byte(RomID_temp[i]);  
  155.     write_byte(0x44);       //開(kāi)始轉(zhuǎn)換溫度
  156.     DS_init();  
  157.     write_byte(0x55);       //匹配ROM  
  158.     for(i=0;i<8;i++)     //發(fā)出64位ROM編碼  
  159.             write_byte(RomID_temp[i]);  
  160.     write_byte(0xBE);       //發(fā)讀溫度命令  
  161.     temp.c[1]=read_byte();  //讀低字節(jié),之所以c[1]中放低字節(jié),是因?yàn)镃51采用的是大端格式
  162.     temp.c[0]=read_byte();  //讀高字節(jié),之所以c[0]中放低字節(jié),是因?yàn)镃51采用的是大端格式
  163.                             //共用體定義
  164. }  
  165.   
  166. void Temperature_cov(void)      //溫度轉(zhuǎn)化
  167. {                              
  168.     cc=temp.x/16;           //計(jì)算出溫度值的整數(shù)部分,這個(gè)語(yǔ)句相當(dāng)于數(shù)值乘0.0625再取整數(shù)部分  
  169.     xs=temp.x&0x0f;         //取溫度值小數(shù)部分的第一位  
  170.     xs=xs*10;               //這兩條語(yǔ)句相當(dāng)于乘0.625,得小數(shù)位的第一位,注意不是乘0.0625  
  171.     xs=xs/16;
  172. }  
  173. //***********************//
  174. //******顯示子程*********//
  175. //***********************//
  176. void display_m(void)   //顯示18b20個(gè)數(shù)或方向
  177. {
  178.         uchar i;
  179.         write_com(0x8B);
  180.         //write_data('0'+m);
  181.         if(m==0)
  182.         for(i=0;i<5;i++)
  183.         {write_data(east[i]);}
  184.         if(m==1)
  185.         for(i=0;i<5;i++)
  186.         {write_data(west[i]);}
  187.         if(m==2)
  188.         for(i=0;i<5;i++)
  189.         {write_data(south[i]);}
  190.         if(m==3)
  191.         for(i=0;i<5;i++)
  192.         {write_data(north[i]);}
  193. }

  194. void display_ROMID(void)        //顯示序列號(hào)  
  195. {   
  196.     uchar tmp[]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,
  197.              0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46};       
  198.           uchar k,i;
  199.     uchar disbuffer_rom[16];                                                        
  200.              disbuffer_rom[0]=(ID[m][k]&0x0F);  
  201.              disbuffer_rom[1]=((ID[m][k]&0xF0)>>4);  
  202.              disbuffer_rom[2]=(ID[m][k+1]&0x0F);  
  203.              disbuffer_rom[3]=((ID[m][k+1]&0xF0)>>4);  
  204.              disbuffer_rom[4]=(ID[m][k+2]&0x0F);  
  205.              disbuffer_rom[5]=((ID[m][k+2]&0xF0)>>4);  
  206.              disbuffer_rom[6]=(ID[m][k+3]&0x0F);  
  207.              disbuffer_rom[7]=((ID[m][k+3]&0xF0)>>4);
  208.              disbuffer_rom[8]=(ID[m][k+4]&0x0F);  
  209.              disbuffer_rom[9]=((ID[m][k+4]&0xF0)>>4);
  210.              disbuffer_rom[10]=(ID[m][k+5]&0x0F);  
  211.              disbuffer_rom[11]=((ID[m][k+5]&0xF0)>>4);
  212.              disbuffer_rom[12]=(ID[m][k+6]&0x0F);  
  213.              disbuffer_rom[13]=((ID[m][k+6]&0xF0)>>4);
  214.              disbuffer_rom[14]=(ID[m][k+7]&0x0F);  
  215.              disbuffer_rom[15]=((ID[m][k+7]&0xF0)>>4);                                         
  216.                  write_com(0x80+0x40);
  217.     for(i=0;i<16;i++)               
  218.                         {
  219.                                
  220.                           write_data(tmp[disbuffer_rom[i]]);    //1602寫(xiě)入序列號(hào)
  221.                         }         
  222. }  
  223.    
  224. void display(void)         //溫度顯示
  225. {  
  226.         disbuffer[0]='+';
  227.         disbuffer[1]=cc/10;
  228.         disbuffer[2]=cc%10;
  229.         disbuffer[3]='.';
  230.         disbuffer[4]=xs;
  231.         disbuffer[5]='C';
  232.         write_com(0x80);
  233.   write_data(disbuffer[0]);
  234.         write_com(0x81);
  235.         write_data('0'+disbuffer[1]);
  236.         write_com(0x82);
  237.         write_data('0'+disbuffer[2]);
  238.         write_com(0x83);
  239.         write_data(disbuffer[3]);
  240.         write_com(0x84);
  241.         write_data('0'+disbuffer[4]);
  242.         write_com(0x85);
  243.         write_data(disbuffer[5]);
  244. }  
  245.   
  246. void diplay_final(void)     //顯示所用到的18b20的實(shí)時(shí)溫度
  247. {       uint q;   
  248.         for(q=0;q<8;q++)  
  249.             {  
  250.                 RomID_temp[q]=ID[m][q];     //給序列號(hào),等待匹配
  251.             }  
  252.                 Read_Temperature_rom();    //讀取溫度
  253.                 Temperature_cov();         //溫度轉(zhuǎn)換
  254.                 display();                 //顯示溫度
  255. }
  256. //****************************//
  257. //*****多點(diǎn)18b20搜索子程******//
  258. //****************************//
  259. void search_rom(void)   //遍歷搜索單線上所連的所有18b20的序列號(hào)  
  260. {   
  261.   uchar k,l=0,chongtuwei,m,n,a;   
  262.   uchar _00web[MAXNUM]={0};  
  263.   do  
  264.    {  
  265.      DS_init();         //復(fù)位單總線上的所有DS18B20  
  266.      write_byte(0xf0);  //單片機(jī)發(fā)布搜索命令  
  267.      for(m=0;m<8;m++)  
  268.        {  
  269.          uchar s=0; //s用來(lái)記錄本次循環(huán)得到的1個(gè)字節(jié)(8位)序列號(hào)  
  270.          for(n=0;n<8;n++)  
  271.             {  
  272.              k=read_2bit();  //讀第m*8+n位的原碼和反碼,保存在k中  
  273.              k=k&0x03;       //屏蔽掉k中其它位的干擾,為下一步判斷作準(zhǔn)備  
  274.              s>>=1;            //s右移一位,即把上一次循環(huán)得到的位值右移一位,  
  275.                              //這樣執(zhí)行完一次n為變量的循環(huán),便可得到一個(gè)字節(jié)的ROM號(hào)                                                
  276.              if(k==0x01)     //k為01,表明讀到的數(shù)據(jù)為0,即所有器件在這一位都為0,所以向總線上寫(xiě)0  
  277.                              //同時(shí)對(duì)s的值不進(jìn)行操作,即這位的序列號(hào)記為0  
  278.                 {      
  279.                  write_bit (0);  
  280.                 }  
  281.              else if(k==0x02)//k為02,表明讀到的數(shù)據(jù)為1,即所有器件在這一位都為1,所以向總線上寫(xiě)1  
  282.                 {  
  283.                  s=s|0x80;  //記錄下此位的值,即s的最高位置1  
  284.                  write_bit (1);  
  285.                 }  
  286.              else if(k==0x00)  
  287.                 {  
  288.                  chongtuwei=m*8+n+1;   //記錄下這個(gè)沖突位發(fā)生的位置;之所以加1是為了讓_00web數(shù)組中的第一位保持0不變,  
  289.                                        //便于判斷搜索循環(huán)是否結(jié)束;  
  290.                  if(chongtuwei>_00web[l])//如果沖突位比標(biāo)志00位的位高,即發(fā)現(xiàn)了新的沖突位,那么這位寫(xiě)0  
  291.                     {        
  292.                      write_bit (0);  
  293.                      _00web[++l]=chongtuwei;    //依次記錄位比沖突標(biāo)志位高的沖突位在_00web數(shù)組中   
  294.                     }  
  295.                  else if(chongtuwei<_00web[l]) //如果沖突位比標(biāo)志00位的位低,那么把ID中這位所在的字節(jié)右移n位,  
  296.                     {                        //從而得到這位先前已經(jīng)寫(xiě)過(guò)的值,如果為0,說(shuō)明這位先前寫(xiě)的是0,那么繼續(xù)寫(xiě)0,  
  297.                                             // 如果這位先前寫(xiě)的是1,那么繼續(xù)寫(xiě)1  
  298.                      a=(ID[num-1][m]>>n)&0x01;  
  299.                      s=s|(a<<7);          //記錄下此位的值  
  300.                      write_bit(a);  
  301.                     }  
  302.                  else if(chongtuwei==_00web[l])//如果沖突位就是標(biāo)志00位,那么s的最高位置1,即這位記為1,同時(shí)向總線上寫(xiě)1;  
  303.                                              //之所以不寫(xiě)0,是因?yàn)榍懊嬉呀?jīng)寫(xiě)過(guò)0,再寫(xiě)0,就得不到遍歷的效果.  
  304.                     {  
  305.                      s=s|0x80;  
  306.                      write_bit (1);  
  307.                      l=l-1;             //改變標(biāo)志00位的位置,即向前推一個(gè)00位,并且是往低位方向推  
  308.                     }  
  309.                 }  
  310.             }      
  311.          ID[num][m]=s;   
  312.        }  
  313.      num++;         //DS18B20的個(gè)數(shù)加1  
  314.    }while((_00web[l]!=0)&&(num<MAXNUM));//如果沖突位記錄數(shù)組已經(jīng)前推到0值或是DS18B20的數(shù)目已經(jīng)超過(guò)最大允許數(shù)目,  
  315.                                       //就退出循環(huán)  
  316. }   
  317. //************************//
  318. //*********主程序*********//
  319. //************************//
  320. void main()                 
  321. {     
  322.     delay(10);  
  323.     search_rom();                        
  324.     TMOD = 0x01; //選擇工作方式1
  325.     TH0 = 0x3C;         //設(shè)置初始值,定時(shí)50MS
  326.     TL0 = 0xB0;
  327.     EA = 1;                         //打開(kāi)總中斷
  328.     ET0 = 1;                 //打開(kāi)定時(shí)器0中斷
  329.     TR0 = 1;                 //啟動(dòng)定時(shí)器0  
  330.         init();  
  331.     while(1)  
  332.     {     
  333.            display_ROMID();   //顯示序列號(hào)
  334.                       display_m();      //顯示18b20個(gè)數(shù)
  335.            diplay_final();    //顯示溫度
  336.      
  337. …………限于本文篇幅 余下代碼請(qǐng)從51黑下載附件…………
復(fù)制代碼

完整代碼下載:
多點(diǎn)溫度測(cè)量.zip (53.69 KB, 下載次數(shù): 76)


評(píng)分

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

查看全部評(píng)分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:435757 發(fā)表于 2018-12-4 16:07 | 只看該作者
請(qǐng)問(wèn)有protues仿真圖么
回復(fù)

使用道具 舉報(bào)

板凳
ID:366216 發(fā)表于 2018-12-6 15:44 | 只看該作者
沒(méi)有頭文件代碼嗎,運(yùn)行不了啊
回復(fù)

使用道具 舉報(bào)

地板
ID:660749 發(fā)表于 2019-12-10 16:36 | 只看該作者
不錯(cuò)我覺(jué)得可以
回復(fù)

使用道具 舉報(bào)

5#
ID:660749 發(fā)表于 2019-12-10 16:37 | 只看該作者
zhangwb055 發(fā)表于 2018-12-4 16:07
請(qǐng)問(wèn)有protues仿真圖么

沒(méi)得,自己畫(huà)
回復(fù)

使用道具 舉報(bào)

6#
ID:482246 發(fā)表于 2020-2-14 15:10 | 只看該作者
溫度是錯(cuò)的,老是85
回復(fù)

使用道具 舉報(bào)

7#
ID:654509 發(fā)表于 2020-2-19 15:04 | 只看該作者
不錯(cuò),很有幫助
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

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

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

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