找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 6753|回復(fù): 0
收起左側(cè)

利用AVR單片機(jī)設(shè)計(jì)的DS18B20測溫程序

[復(fù)制鏈接]
ID:75926 發(fā)表于 2015-4-3 00:57 | 顯示全部樓層 |閱讀模式
  1. /********************************
  2.   DS18B20測溫程序
  3.   文件名:main.c
  4.   編譯:WinAVR-20070122

  5.   硬件環(huán)境:CA-M8X   打開的開關(guān)如下
  6.             S6(1,2,5,6,7)   - 外部4MHz晶振和595接口
  7.             J8(EN-SEG)      - 數(shù)碼管顯示允許
  8.             S7(4)          - 連接PC1 與DS18B20數(shù)據(jù)口
  9.             (在CA-M8X 上DS18B20為非總線供電)
  10.   
  11.   芯藝設(shè)計(jì)室 2004-2007  版權(quán)所有
  12.   轉(zhuǎn)載請保留本注釋在內(nèi)的全部內(nèi)容
  13.   Email: changfutong@sina.com
  14. *******************************/
  15. #include <avr/io.h>
  16. #include <util/delay.h>
  17. #include <stdint.h>

  18. #include "seg.h"  //聲明數(shù)碼管顯示接口函數(shù)

  19. #define CLR_1WIRE_BUS DDRC|=_BV(PC1) //設(shè)置為輸出,此時(shí)由于PORTC1是低所以輸出低
  20. #define SET_1WIRE_BUS DDRC&=~_BV(PC1)//設(shè)置為輸入,此時(shí)由于PORTC1是低所以程高阻,又因?yàn)橥獠坑猩侠娮杷韵喈?dāng)于設(shè)置總線為高
  21. #define GET_1WIRE_BUS PINC&_BV(PC1)

  22. #define DS18B20_READ_ROM 0x33
  23. #define DS18B20_MATCH_ROM 0X55
  24. #define DS18B20_SKIP_ROM 0XCC
  25. #define DS18B20_SEARCH_ROM 0XF0
  26. #define DS18B20_ALARM_SEARCH_ROM 0XEC
  27. #define DS18B20_WRITE_RAM 0X40
  28. #define DS18B20_READ_RAM 0XBE
  29. #define DS18B20_COPY_RAM 0X48
  30. #define DS18B20_CONVERT_TEM 0X44
  31. #define DS18B20_EECALL_EEPROM 0XB8
  32. #define DS18B20_READ_POWER_SUPPLY 0XB4

  33. //總線端口初始化
  34. void BusInit(void)
  35. {
  36.   PORTC&=~_BV(PC1);//此口總保持低
  37.   DDRC&=~_BV(PC1); //初始化為輸入,用外部上拉電阻保持總線的高電平
  38. }

  39. //由于系統(tǒng)時(shí)鐘為4MHz,一個(gè)_delay_loop_2正好延時(shí)一us
  40. #define DelayUs(x) _delay_loop_2(x)

  41. void DelayMs(uint16_t t)
  42. {
  43.   uint16_t i;
  44.   for(i=0;i<t;i++)
  45.     _delay_loop_2(250 * 4);
  46. }

  47. //單總線復(fù)位
  48. uint8_t ds18b20_reset(void)
  49. {
  50.   uint8_t ret=0;
  51.   CLR_1WIRE_BUS;
  52.   DelayUs(500);  //拉低總線至少480us
  53.   SET_1WIRE_BUS;
  54.   DelayUs(100);//釋放總線后等待15-60us
  55.   if((GET_1WIRE_BUS)==0)//檢測到DS18B20把總線拉低
  56.     ret=1;        //復(fù)位成功
  57.   DelayUs(1000);//等待器件釋放總線
  58.   return ret;
  59. }

  60. //單總線讀一字節(jié)
  61. uint8_t ds18b20_read(void)
  62. {
  63.   uint8_t data=0;
  64.   uint8_t i=0;
  65.   for(i=0;i<8;i++)
  66.   {
  67.     data>>=1;
  68.     CLR_1WIRE_BUS;
  69.     DelayUs(2);//此時(shí)>1us
  70.     SET_1WIRE_BUS;
  71.     DelayUs(4);//此時(shí)<15us
  72.     if(GET_1WIRE_BUS)
  73.       data|=0x80;
  74.     DelayUs(60);//此時(shí)>60us
  75.   }
  76.   return(data);
  77. }
  78. //單總線寫一字節(jié)
  79. void ds18b20_write(uint8_t data)
  80. {
  81.   uint8_t i=0;
  82.   for(i=0;i<8;i++)
  83.   {
  84.     if(data&0x01)
  85.     {
  86.       CLR_1WIRE_BUS;
  87.       DelayUs(8);//8us
  88.       SET_1WIRE_BUS;
  89.       DelayUs(55);//55us
  90.     }
  91.     else
  92.     {
  93.       CLR_1WIRE_BUS;
  94.       DelayUs(55);//55us
  95.       SET_1WIRE_BUS;
  96.       DelayUs(20);//8us
  97.     }
  98.     data>>=1;
  99.   }
  100. }

  101. //執(zhí)行轉(zhuǎn)換
  102. uint8_t Ds18b20Convert(uint8_t *t)
  103. {
  104.   //發(fā)送轉(zhuǎn)換命令
  105.   if(ds18b20_reset()==0)
  106.     return 0;
  107.   ds18b20_write(DS18B20_SKIP_ROM); //忽略地址匹配,總線上只有一個(gè)器件時(shí),或?qū)偩所有器件操作
  108.   ds18b20_write(DS18B20_CONVERT_TEM);//開始轉(zhuǎn)換命令
  109.   
  110.   //等待轉(zhuǎn)換完成,ds18b20默認(rèn)轉(zhuǎn)換精度為12位,此時(shí)最大轉(zhuǎn)換時(shí)間為750ms
  111.   DelayMs(1000);
  112.   
  113.   //讀溫度字節(jié)
  114.   if(ds18b20_reset()==0)
  115.     return 0;
  116.   ds18b20_write(DS18B20_SKIP_ROM); //忽略地址匹配
  117.   ds18b20_write(DS18B20_READ_RAM); //讀RAM命令
  118.   t[0]=ds18b20_read();
  119.   t[1]=ds18b20_read();
  120.   
  121.   return 1;
  122. }

  123. //根據(jù)DS18B20中讀的溫度字節(jié),計(jì)算實(shí)際溫度值
  124. int8_t GetTemperature(uint8_t *t)
  125. {
  126.   int8_t ret;
  127.   uint32_t  val;
  128.   uint16_t tmp=(t[1]*256)+t[0];
  129.   uint8_t sflag=0;

  130.   if((t[1]&0xf8)==0xf8) //若負(fù)溫度,從補(bǔ)碼轉(zhuǎn)換(取反加一)
  131.   {
  132.     sflag=1;
  133.     tmp=~tmp;
  134.     tmp++;
  135.   }
  136.   tmp&=0x07ff;    //確保前5位為0
  137.   
  138.   //乘0.0625操作,為此本函數(shù)只適用于DS18B20 12位轉(zhuǎn)換(默認(rèn))時(shí)
  139.   val=((uint32_t)tmp)*625;
  140.   val/=10000;
  141.   
  142.   ret=(int8_t)val;
  143.   
  144.   if(sflag)
  145.     ret|=0x80;//變負(fù)數(shù)
  146.    
  147.   return ret;
  148. }

  149. //測試主函數(shù)
  150. int main(void)
  151. {
  152.   uint8_t tmp[2];//保存溫度字節(jié)
  153.   int8_t tval;    //保存溫度值
  154.   
  155.   SegInit();//數(shù)碼管初始化
  156.   SegNumberOut(0,0);//顯示 0
  157.   BusInit();  //單總線I/O口初始化

  158.   while(1)
  159.   {
  160.     if(Ds18b20Convert(tmp))//如果轉(zhuǎn)換成功
  161.     {
  162.       tval=GetTemperature(tmp);//計(jì)算實(shí)際溫度值
  163.       if(tval>=0)
  164.         SegNumberOut(tval,0);//十進(jìn)制顯示溫度值
  165.       else
  166.         SegNumberOut(0,0);//數(shù)碼管無法顯示負(fù)數(shù),只能顯示0
  167.     }
  168.   }
  169.   return 0;
  170. }


  171. seg.c文件:


  172. /********************************
  173.   74HC95驅(qū)動的數(shù)碼管顯示模塊
  174.   文件名:seg.c
  175.   編譯:WinAVR-20070122

  176.   硬件環(huán)境:CA-M8X   打開的開關(guān)如下
  177.             S6(1,2,5,6,7)   - 外部4MHz晶振和595接口
  178.             J8(EN-SEG)      - 數(shù)碼管顯示允許
  179.   
  180.   芯藝設(shè)計(jì)室 2004-2007  版權(quán)所有
  181.   轉(zhuǎn)載請保留本注釋在內(nèi)的全部內(nèi)容
  182.   WEB: http://www.chipart.cn
  183.   Email: changfutong@sina.com
  184. *******************************/

  185. #include <avr/io.h>
  186. #include <util/delay.h>
  187. #include <stdint.h>

  188. #include "seg.h"

  189. #define SER_PORT  PORTD
  190. #define SER_DAT  PD4
  191. #define SER_RCK  PD5
  192. #define SER_SCK  PD6

  193. //顯示碼(可從chipart.cn下載生成工具)
  194. static uint8_t g_aDisplayBuf[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

  195. //向595 寫一字節(jié)
  196. static void ser_out(uint8_t dat)
  197. {
  198.   uint8_t i;

  199.   for(i=0;i<8;i++)
  200.   {
  201.     if(dat&0x80)
  202.       SER_PORT|=_BV(SER_DAT);
  203.     else
  204.       SER_PORT&=~_BV(SER_DAT);
  205.       
  206.     //產(chǎn)生移位脈沖   
  207.     SER_PORT|=_BV(SER_SCK);
  208.     SER_PORT&=~_BV(SER_SCK);
  209.     dat<<=1;
  210.   }
  211. }
  212. //數(shù)碼管顯示數(shù)(0~255)
  213. //num :顯示的數(shù)   hex:是否用十六進(jìn)制顯示
  214. void SegNumberOut(uint8_t num,uint8_t hex)
  215. {
  216.   uint8_t buf[2];//發(fā)送顯示碼緩沖區(qū)
  217.   uint8_t temp;
  218.   
  219.   if(hex) //十六進(jìn)制
  220.   {
  221.     buf[0]=g_aDisplayBuf[num>>4];//高位
  222.     buf[1]=g_aDisplayBuf[num&0x0f];//低位
  223.   }
  224.   else//十進(jìn)制
  225.   {
  226.     buf[1]=g_aDisplayBuf[num%10];
  227.     temp=num%100;
  228.     buf[0]=g_aDisplayBuf[temp/10];
  229.     temp=num/100;
  230.    
  231.     if(temp>0)
  232.       buf[1]|=0x80; //第一個(gè)數(shù)碼管小數(shù)點(diǎn)表示百位1
  233.     if(temp>1)
  234.       buf[0]|=0x80;//兩個(gè)數(shù)碼管小數(shù)點(diǎn)表示百位2
  235.   }
  236.   
  237.   //串行發(fā)送數(shù)據(jù)
  238.   ser_out(buf[0]);
  239.   ser_out(buf[1]);

  240.   //產(chǎn)生鎖存脈沖
  241.   SER_PORT|=_BV(SER_RCK);
  242.   SER_PORT&=~_BV(SER_RCK);
  243. }

  244. void SegInit(void)
  245. {
  246.   //595控制I/O初始化
  247.   DDRD=_BV(SER_DAT)|_BV(SER_SCK)|_BV(SER_RCK);  
  248.   SER_PORT&=~_BV(SER_SCK);
  249.   SER_PORT&=~_BV(SER_RCK);
  250. }
復(fù)制代碼


相關(guān)帖子

回復(fù)

使用道具 舉報(bào)

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

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

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

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