網頁最後修改時間:2019/01/19
Arduino 使用 Serial Monitor 和整合型 LCD 輸出結果,ESP8266 則燒錄 NodeMCU 韌體使用 UART 輸出 ( NodeMCU 韌體燒錄可參閱這篇網頁說明 )。不同的是 ESP8266 可以整合 WiFi 網路做成 IoT ( 物聯網 ) 應用,而且只需要 ESP8266 本身就可做到,不再需要其他微處理器;若使用 AT 韌體就需要其他微處理器做控制中心。
*********************************************************************************
整合型 LCD可至露天賣場訂購:
DS18B20 溫度感測器可至露天賣場訂購:
*********************************************************************************電路圖
DS18B20 使用單線式通訊與外部裝置做溝通,有兩種接線方式可供選擇 ( 不清楚的請看資料手冊或是露天賣場商品網頁中的介紹 ),電路圖使用正常供電模式 ( 與 DHT11 接線類似 ),可使用在高於 100 °C 的環境上。
DS18B20 每一顆都擁有唯一的 64-bit 序列號 ( ID ) 可供來識別,而且可以多個裝置同時使用單一線路來做通訊,佈線相當的簡單;所需要的外部元件只需要一個提升 ( pull-up ) 電阻 ( 無論使用多少個 DS18B20,只需要一個提升電阻 ),接線的參考電路圖如下所示。
Arduino + DS18B20s 參考電路圖 |
實際接線參考圖 - 1 |
實際接線參考圖 - 2 |
若手邊沒有整合型 LCD 的話,可以省略掉其電路接線的部分,只要使用 Arduino IDE 中 Serial Monitor 也可以得到每一顆 DS18B20 的序號與偵測到的溫度值。
Arduino 函式庫
Arduino 程式碼中使用下面兩個函式庫 ( 雲端硬碟裡面有,也可以使用下面所提供的連結下載 ):
- OneWire v2.2
解壓縮之後的檔名為:OneWire - DallasTemperature372Beta
解壓縮之後的檔名為:Dallas-Temperature-Control
執行結果
DallasTemperature 函式庫需要 OneWire 函式庫才能正常動作。程式碼修改自 DallasTemperature 函式庫 Examples/Multiple 目錄中的 Multiple.pde ( {Arduino Libraries}/Dallas-Temperature-Control/Multiple ),裡面加入了整合型 LCD 的支援與經由序號取得溫度值 ... 等功能,程式執行之後的結果會輸出到 Arduino IDE 的 Serial Monitor 與整合型 LCD 中。
如下圖所示,Serial Monitor 會輸出詳細的資料與說明
Serial Monitor 輸出結果 |
整合型 LCD 輸出結果 |
Note:下面將提供完整的程式碼片段,請使用者自行組合;其中一些註解的部分為節省網頁長度已被拿除,但不影響程式最終執行結果。* 程式碼開頭:
此部分是屬於執行時的一些設定與定義,使用者在不增加任何功能的情況下,由這邊可調整程式執行的方式
10 #include <Wire.h>
11 #include <string.h>
12 #include <OneWire.h>
13 #include <DallasTemperature.h>
14
15 // Data wire is plugged into port 2 on the Arduino
16 #define ONE_WIRE_BUS 2
17 #define TEMPERATURE_PRECISION 9
18 #define MAX_DS18B20_DEVICES 10
19 //*-----
20 // 若不使用整合型 LCD,只要在下面這一行前面加雙斜線取消掉就可以
21 #define I2CLCD 0x3C // I2C address of I2CLCD
22 #ifdef I2CLCD
23 void initLCD();
24 void clearLCD();
25 void displayCharOnLCD( int line, int column, const char *dp, unsigned char len );
26 #endif
27 //*-----
28 void printAddress(DeviceAddress deviceAddress);
29 void discoverOneWireDevices(void);
30
31 // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
32 OneWire oneWire(ONE_WIRE_BUS);
33
34 // Pass our oneWire reference to Dallas Temperature.
35 DallasTemperature sensors(&oneWire);
36
37 // arrays to hold device addresses
38 DeviceAddress Thermometer[MAX_DS18B20_DEVICES];
39 uint8_t noDS = 0;
40
line 10 - 13:使用到的函式庫以及標頭檔案。
line 16 - 18:這三個定義很重要!首先 line 16 定義了 Arduino 與 DS18B20 通訊的接腳 ( D2 );line 17 定義 DS18B20 的溫度解析度為 9-bit ( 9, 10, 11, 12 bits 可以選擇 );line 18 定義搜尋的 DS18B20 的數量 ( 理論上可以無限大!請視實際需要設定即可 )。
line 21 - 26:如果使用整合型 LCD,line 21 就必須是有效的一行程式碼;反之,若不使用整合型 LCD,就必須在 line 21 前方加雙斜線取消掉。只要 line 21 是有效的程式碼,那麼就運行 line 22 - 25,而整個程式中只要有 #ifdef I2CLCD ... #endif 裡面的程式碼就會被執行。
line28 - 29:函式宣告;程式碼在下方說明。
line 32:OneWire 函式庫初始化並定義通訊接腳。
line 35:DallasTemperature 函示庫初始化,參數是 line 32 宣告的實體 oneWire。
line 38:宣告一個可存放 MAX_DS18B20_DEVICES 數目大小的陣列,且陣列中的每一個元素都可存放 8-bytes ( 64-bit ) 的資料 ( 用來存放每一個 DS18B20 的序號 );DeviceAddress 定義如下:
line 40:紀錄取得的 DS18B20 數目,最多為 255 個。DallasTemperature.h, line 5857 58 typedef uint8_t DeviceAddress[8]; 59
* 初始化設定 ( setup() ):
基本的函式庫初始化與設定都在這個地方,並將設定值與取得的 DS18B20 數量輸出到 Serial Monitor。
10
41 void setup(void)
42 {
43 // start serial port
44 Serial.begin(9600);
45 Serial.println("Dallas Temperature IC Control Library Demo");
46
47 // Start up the library
48 sensors.begin();
49
50 // LCD
51 #ifdef I2CLCD
52 Wire.begin();
53 initLCD();
54 delay(100);
55 clearLCD();
56 delay(100);
57 #endif
58
59 // locate devices on the bus
60 Serial.print("Locating devices...");
61 Serial.print("Found ");
62 noDS = sensors.getDeviceCount();
63 Serial.print(noDS, DEC);
64 Serial.println(" devices.");
65
66 // report parasite power requirements
67 Serial.print("Parasite power is: ");
68 if (sensors.isParasitePowerMode()) Serial.println("ON");
69 else Serial.println("OFF");
70
107 discoverOneWireDevices();
108 // show the addresses we found on the bus
109 for(uint8_t i = 0; i < noDS; i++)
110 {
111 Serial.print("Device ");
112 Serial.print(i);
113 Serial.print(" Address: ");
114 printAddress( Thermometer[i] );
115 Serial.println();
116 // set the resolution to 9 bit
117 sensors.setResolution( Thermometer[i], TEMPERATURE_PRECISION);
118 Serial.print("Device ");
119 Serial.print( i );
120 Serial.print(" Resolution: ");
121 Serial.print(sensors.getResolution(Thermometer[i]), DEC);
122 Serial.println();
123 }
124 }
line 44:設定 Arduino 硬體 UART 的通訊速率。使用 USB 連接 Arduino 板子時,可以將訊息由此輸出到 Serial Monitor 中。
line 48:開始使用 DallasTemperature 函式庫。
line 51 - 57:如果 line 21 是有效的,就執行整合型 LCD 的初始化。
line 59 - 64:開始尋找連接到 line 16 接腳上面所有的 DS18B20,並輸出相關訊息。
line 67 - 69:詢問並輸出 DS18B20 使用的電源模式是否為 "寄生供電模式" ?
line 107:開始尋找通訊線上所有的 DS18B20 並且取得它們的 ID,並儲存在 Thermometer 陣列中 ( discoverOneWireDevices 函式下面再解釋 )。
line 109 - 124:設定在 line 107 函式所取得的所有的 DS18B20 解析度,設定後再取出輸出到 Serial Monitor 中 ( line 104 printAddress 函式下面再解釋 )
* 重複執行的部分 ( loop() ):
loop() 函式中,會一直重複的讀取所有 DS18B20 的溫度,然後每隔三秒輸出一個 DS18B20 的再序號與溫度。如果不需要顯示在 LCD 上,那麼 line 207 的延遲時間是可以拿掉,這樣可以很快地得到所有的 DS18B20 的序號和溫度值。
195 void loop(void)
196 {
197 // call sensors.requestTemperatures() to issue a global temperature
198 // request to all devices on the bus
199 Serial.print("Requesting temperatures...");
200 sensors.requestTemperatures();
201 Serial.println("DONE");
202
203 // print the device information
204 for( uint8_t i = 0; i < noDS; i++)
205 {
206 printData( Thermometer[i] );
207 delay(3000);
208 }
209 }
line 200:取得所有在通訊接腳上所有 DS18B20 的溫度值。
line 206:以序號取得溫度值,並輸出即顯示出來。( printData 函式下面再解釋 )。
* 副程式部分
各個副程式的名稱就說明該程式碼的用途:
126 // function to print a device address
127 void printAddress(DeviceAddress deviceAddress)
128 {
129 for (uint8_t i = 0; i < 8; i++)
130 {
131 // zero pad the address if necessary
132 if (deviceAddress[i] < 16) Serial.print("0");
133 Serial.print(deviceAddress[i], HEX);
134 }
135
136 // LCD
137 #ifdef I2CLCD
138 char chrbuf[17];
139 for( uint8_t i = 0; i < 16; i+=2)
140 {
141 chrbuf[i] = 0x30 + deviceAddress[i/2] / 16;
142 if( chrbuf[i] > 0x39 ) chrbuf[i] += 7;
143 chrbuf[i+1] = 0x30 + deviceAddress[i/2] % 16;
144 if( chrbuf[i+1] > 0x39 ) chrbuf[i+1] += 7;
145 }
146 displayCharOnLCD( 1, 1, chrbuf, 16 );
147 #endif
148 }
149
150 // function to print the temperature for a device
151 void printTemperature(DeviceAddress deviceAddress)
152 {
153 char chrbuf[17];
154 char prx[3];
155 int val_int, val_fra;
156 float tempC = sensors.getTempC(deviceAddress);
157 Serial.print("Temp C: ");
158 Serial.print(tempC);
159 Serial.print(" Temp F: ");
160 Serial.print(DallasTemperature::toFahrenheit(tempC));
168 #ifdef I2CLCD
169 displayCharOnLCD( 2, 1, "Temp: ", 6);
170 dtostrf( tempC, 8, 4, chrbuf );
171 displayCharOnLCD( 2, 7, chrbuf, 8 );
172 sprintf( prx, "%cC", 0xdf );
173 displayCharOnLCD( 2, 15, prx, 2 );
174 #endif
175 }
176
177 // function to print a device's resolution
178 void printResolution(DeviceAddress deviceAddress)
179 {
180 Serial.print("Resolution: ");
181 Serial.print(sensors.getResolution(deviceAddress));
182 Serial.println();
183 }
184
185 // main function to print information about a device
186 void printData(DeviceAddress deviceAddress)
187 {
188 Serial.print("Device Address: ");
189 printAddress(deviceAddress);
190 Serial.print(" ");
191 printTemperature(deviceAddress);
192 Serial.println();
193 }
194
printAddress ( line 127 - 148 ):經由給定的 DeviceAddress,然後將裡面 8-bytes 的資料使用文字的方式輸出以及顯示在 LCD 上。
printTemperature ( line 151 - 175 ):經由給定的 DeviceAddress,取出通訊接腳中該 DS18B20 的溫度值並轉換為 °C 和 °F 輸出與顯示在 LCD 上。
printResolution ( line 178 - 183 ):取得現在給定的 DeviceAddress 所指定的 DS18B20 的溫度解析度並輸出。
printData ( line 186 - 193 ):呼叫 printAddress 和 printTemperature 兩個函式輸出資料。
213 void discoverOneWireDevices() {
214 uint8_t i;
215 uint8_t devs = 0;
216
217 Serial.print("Looking for 1-Wire devices...\n\r");
218 while(oneWire.search( Thermometer[devs] )) {
219 Serial.print("\n\rFound \'1-Wire\' device [");
220 Serial.print( devs );
221 Serial.print("]with address:\n\r");
222 for( i = 0; i < 8; i++) {
223 Serial.print("0x");
224 if (Thermometer[devs][i] < 16) {
225 Serial.print('0');
226 }
227 Serial.print(Thermometer[devs][i], HEX);
228 if (i < 7) {
229 Serial.print(", ");
230 }
231 }
232 if ( OneWire::crc8( Thermometer[devs], 7) != Thermometer[devs][7]) {
233 Serial.print("CRC is not valid!\n");
234 return;
235 }
236 else
237 devs++;
238 }
239 Serial.print("\n\r\n\rThat's it.\r\n");
240 oneWire.reset_search();
241 return;
242 }
discoverOnwWoreDevice ( line 213 - 244 ):這函式用來搜尋接在通訊接腳 ( Arduino D2 ) 上所有的 DS18B20,紀錄並輸出,而這函式只在程式運行時執行一次。每次要搜尋之前,必須執行 line 217:reset_search 一次,然後再搜尋 ( line 220),直到搜尋結束;每次只要搜尋到,就會輸出搜尋到的裝置順序號碼與其唯一的序號 ( line221 - 232 ),最後確認取得的資料 ( CRC check ) 是否正確,正確就繼續輸出下一筆的資料。
* 整合型 LCD 使用的程式
下面是整合型 LCD ( 使用 I2C 模式 ) 使用到的函式,主要是用來初始化 ( initLCD, line 248 - 257 )、清除螢幕 ( clearLCD, line 25 9 -268 ) 和從指定的位置上顯示字元 ( displayCharOnLCD, line 270 - 286 )。使用的方式請直接參考程式碼就可以。
244 /************************************************************************************
245 * LCD
246 ************************************************************************************/
247 #ifdef I2CLCD
248 void initLCD()
249 {
250 Wire.beginTransmission(I2CLCD);
251 Wire.write( 0x00 ); // N x commands
252 Wire.write( 0x38 ); // Function set
253 Wire.write( 0x0C ); // Display ON/OFF
254 Wire.write( 0x01 ); // Clear display
255 Wire.write( 0x06 ); // Entry mode set
256 Wire.endTransmission();
257 }
258
259 void clearLCD()
260 {
261
262 Wire.beginTransmission(I2CLCD);
263
264 Wire.write( 0x80 ); // One command
265 Wire.write( 0x01 ); // Clear display
266
267 Wire.endTransmission();
268 }
269
270 void displayCharOnLCD( int line, int column, const char *dp, unsigned char len )
271 {
272 unsigned char i;
273
274 Wire.beginTransmission(I2CLCD);
275
276 Wire.write( 0x80 );
277 Wire.write( 0x80 + ( line - 1 ) * 0x40 + ( column - 1 ) );
278 Wire.write( 0x40 );
279
280 for( i = 0; i < len; i++)
281 {
282 Wire.write( *dp++ );
283 }
284
285 Wire.endTransmission();
286 }
287 #endif
以上就是所有程式碼的說明。
* 程式測試說明:
線路都弄好之後,就直接使用 Arduino IDE 上傳 sketch。
多顆 DS18B20 使用時,可以先個別插在線路上以取得唯一的 64-bit 序號,只要按下板子上面的 RESET 按鈕,就可以重複這個動作。如果使用者的應用需要在不同距離上面,那麼剛剛說的部份就很重要,因為可以用序號取得溫度而且也可以做為該位置溫度的識別。
取得序號之後,就可以將全部使用到的 DS18B20 插上去,開始取得所有 DS18B20 的溫度值,一直循環下去。
結論:
這是個簡單使用 DS18B20 的例子,使用 Arduino 做為控制板取得所有單線上面所有的 DS18B20 序號與溫度值,使用者可以使用這個程式的框架,加入對於一片區域的溫度監控再產生相對應的動作,或是做為其他的應用。
若是使用者對於 IoT ( Internet of Thing, 物聯網 ) 有著濃厚興趣,可以參考另一篇使用 ESP8266 讀取 DS18B20 的部落格網頁 ( 使用 ESP8266 ( 燒錄 NodeMCU 韌體,使用 Lua 撰寫程式 ),多加入了,可使用瀏覽器查看連接的 DS18B20 溫度,敬請拭目以待!!!
沒有留言:
張貼留言
留言屬名為"Unknown"或"不明"的用戶,大多這樣的留言都會直接被刪除掉,不會得到任何回覆!
發問問題,請描述清楚你(妳)的問題,別人回答前不會想去 "猜" 問題是什麼?
不知道怎麼發問,請看 [公告] 部落格提問須知 - 如何問問題 !