2015年7月19日 星期日

偷懶用溫度紀錄器

最近弄了機車,
為了確定大太陽底下車廂溫度最高會到多少而弄的小玩意....

設計理念來說,
溫度精準度不用太過計較,MCU有內建最好,
能保存一定數量的溫度紀錄(好畫線XD)
然後使用的東西要儘量簡單&少....

看了看自己手上的MCU:
名稱 溫度計 EEPROM 操作溫度°C
LPC1114 no 用flash代替 -40~85
LPC812 no 用flash代替 -40~105
STM32F103C8T6 yes 用flash代替 -40~105
Atmega328P(pro mini) yes yes -40~85

嚴格說起來STM32F103C8T6是最符合需求的,
只是...手上只有一片&基礎功能都還沒玩過= =
所以就先pass....拿Arduino來繼續偷懶了XD

假設溫度不會到85度....那麼這個裝置就不會有問題....
可是超過85度的話....我想應該會GG吧= =
(至少確定他超過datasheet的工作範圍了...
希望不會超過85度吧....

操作方式:
接上電源自動開始紀錄,最多紀錄169筆,
每5分鐘紀錄一次(第92行可以改)
要讀取的話,
先接好UART轉USB,
然後按一下reset,
會自動跳到顯示模式,
輸入"C"會讓記錄從0開始記;
輸入"F"會把EEPROM設成0xFF;
輸入"D"會把EEPROM裡面所有的資料列出來.

輸出格式為: 時間\t溫度\t電壓
時間為開機後第幾次紀錄,
溫度是攝氏溫度*10(256等於25.6度)
電壓為mV



code:
(使用這個函式庫:http://www.rocketscream.com/blog/2011/07/04/lightweight-low-power-arduino-library/)


  1. #include <EEPROM.h>
  2. #include "LowPower.h"
  3. int led = 13;
  4. struct Temp{
  5. unsigned int t;
  6. int temp;
  7. unsigned int Vcc;
  8. };
  9. struct Temptab{
  10. unsigned int num;
  11. Temp max;
  12. };
  13. char print = 0;
  14. char cmd = 0x00;
  15. Temptab status;
  16. int total = 0;
  17. int offset = sizeof(Temptab);
  18. unsigned int cont = 0;
  19. Temp work;
  20. Temp max = {
  21. 0,
  22. -64,
  23. 0
  24. };
  25. void setup()
  26. {
  27. pinMode(led, OUTPUT);
  28. EEPROM.get( 0, status );
  29. total = status.num;
  30. offset = sizeof(Temptab) + status.num * sizeof(Temp);
  31. if(MCUSR & _BV(EXTRF)){
  32. Serial.begin(115200);
  33. print = 1;
  34. Serial.println( "Read status from EEPROM: " );
  35. Serial.print( "total\t" );Serial.println( status.num );
  36. Serial.print( "max_t\t" );Serial.println( status.max.t );
  37. Serial.print( "max_temp\t" );Serial.println( status.max.temp );
  38. Serial.print( "max_Vcc\t" );Serial.println( status.max.Vcc );
  39. if(status.num){
  40. dump();
  41. }
  42. }else{
  43. LowPower.powerDown(SLEEP_2S, ADC_OFF, BOD_OFF);
  44. total++;
  45. rec();
  46. }
  47. }
  48. // https://code.google.com/p/tinkerit/wiki/SecretVoltmeter
  49. // The voltage is returned in millivolts. So 5000 is 5V, 3300 is 3.3V.
  50. unsigned int vccVoltage() {
  51. unsigned int result;
  52. // Read 1.1V reference against AVcc
  53. ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  54. delay(2); // Wait for Vref to settle
  55. ADCSRA |= _BV(ADSC); // Convert
  56. while (bit_is_set(ADCSRA,ADSC));
  57. result = ADCL;
  58. result |= ADCH << 8;
  59. result = 1126400L / result; // Back-calculate AVcc in mV
  60. return result;
  61. }
  62. // https://code.google.com/p/tinkerit/wiki/SecretThermometer
  63. // Temperature is returned in 10x°C. So 250 is 25°C.
  64. int readTemp() {
  65. long result;
  66. // Read temperature sensor against 1.1V reference
  67. ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX3);
  68. delay(50); // Wait for Vref to settle
  69. ADCSRA |= _BV(ADSC); // Convert
  70. while (bit_is_set(ADCSRA,ADSC));
  71. result = ADCL;
  72. result |= ADCH << 8;
  73. //result = (result*1000 - 324310L) / 122;
  74. result = ((result*2000 - 648620L) / 144 + 1) >> 1;
  75. return result;
  76. }
  77. void sleepMinutes()
  78. {
  79. for (unsigned int i = 0; i < 150; i++) {
  80. LowPower.powerDown(SLEEP_2S, ADC_OFF, BOD_OFF);
  81. }
  82. cont++;
  83. }
  84. void blinkLed(){
  85. digitalWrite(led, HIGH);
  86. delay(100);
  87. digitalWrite(led, LOW);
  88. }
  89. void rec(){
  90. work.t = cont;
  91. work.temp = readTemp();
  92. work.Vcc = vccVoltage();
  93. if(work.temp > status.max.temp){
  94. status.max.t = work.t;
  95. status.max.temp = work.temp;
  96. status.max.Vcc = work.Vcc;
  97. }
  98. status.num = total;
  99. EEPROM.put( offset, work );
  100. EEPROM.put( 0, status );
  101. total++;
  102. offset += sizeof(Temp);
  103. if(offset >= EEPROM.length()){
  104. total = 0;
  105. offset = sizeof(Temptab);
  106. }
  107. }
  108. void dump(){
  109. unsigned int i = 0;
  110. EEPROM.get( 0, status );
  111. Serial.print( "max_time\t" );Serial.println( status.max.t );
  112. Serial.print( "max_temp\t" );Serial.println( status.max.temp );
  113. Serial.print( "max_Vcc\t" );Serial.println( status.max.Vcc );
  114. for(offset=sizeof(Temptab); offset+sizeof(Temp)<=EEPROM.length(); offset+=sizeof(Temp)){
  115. EEPROM.get( offset, work);
  116. Serial.print( i++ );Serial.print( "\t" );
  117. Serial.print( work.t );Serial.print( "\t" );
  118. Serial.print( work.temp );Serial.print( "\t" );
  119. Serial.print( work.Vcc );Serial.println();
  120. }
  121. }
  122. void loop()
  123. {
  124. if(print == 0){
  125. blinkLed();
  126. sleepMinutes();
  127. rec();
  128. }else{
  129. if(Serial.available()){
  130. cmd = Serial.read();
  131. if(cmd == 'C'){
  132. Serial.print( "clear EEPROM..." );
  133. status.num = 0;
  134. status.max.t = 65535;
  135. status.max.temp = -63;
  136. status.max.Vcc = 65535;
  137. EEPROM.put( 0, status );
  138. Serial.println( "done" );
  139. }
  140. if(cmd == 'F'){
  141. Serial.print( "set EEPROM to 0xFF..." );
  142. for(offset=sizeof(Temptab); offset<EEPROM.length(); offset++){
  143. EEPROM.write(offset, 0xFF);
  144. }
  145. Serial.println( "done" );
  146. }
  147. if(cmd == 'D'){
  148. Serial.println( "Read status from EEPROM: " );
  149. Serial.print( "total\t" );Serial.println( status.num );
  150. Serial.println( "dump EEPROM..." );
  151. dump();
  152. }
  153. if(cmd == 'N'){
  154. Serial.print( "now_temp\t" );Serial.println( readTemp() );
  155. Serial.print( "now_Vcc\t" );Serial.println( vccVoltage() );
  156. }
  157. }
  158. }
  159. }

沒有留言:

張貼留言