2012年6月13日 星期三

水族箱控制器 : Arduino 三部曲

因為發現要顯示的資料越來越多,原本用來顯示的LCD 1602已不夠使用,於是上網又找到了這一片 SPI LCD12864 Module
原圖:http://www.dfrobot.com/wiki/images/4/43/DFR0091_CD.jpg
原圖:http://www.dfrobot.com.cn/image/cache/data/DFR0091/DFR0091-500x500.jpg
但是這一片是使用 SPI 介面,為了方便使用這一塊,所以我又加購了 一片 interface shield:

原圖:http://www.dfrobot.com.cn/image/cache/data/DFR0074/2-340x340.jpg
在這一片 Interface Shield 上,IIC 及 SPI 接口都直接拉出來,而且還作上了 SD 儲存卡的接口,這塊板子佔用了一些 Arduino 上的埠:

  1. IIC:Analog 4,5
  2. Shiftout:Digital 3,8,9
  3. TLC:Digital 3,9,10,11,13
  4. SD:Digital 10,11,12,13
先用原廠的測試程式LCD12864RSPI 測一下顯示器如何,Compile時就發生了 Error :

D:\arduino-1.0.1\libraries\LCD12864RSPI\LCD12864RSPI.cpp:75: error: 'digitalWrite' was not declared in this scope


我想這應該是我已經用 Arduino 1.0.1,廠家給的測試程式是舊的,打開原廠的 LCD12864RSPI_h ,原始的宣告前幾行:

//Demo LCD12864 spi
//www.dfrobot.com

#ifndef LCD12864RSPI_h
#define LCD12864RSPI_h
#include <avr/pgmspace.h>
#include <inttypes.h>

在#clude 的最後一行加上:

 #include <Arduino.h>

再重新編譯程式 ,錯誤訊息就消失了。






接著先把 RTC-PCF8563 時間跟 I2C 連接,試著用 LCD12864 來顯示時間,先用一段小程式測試:





#include <Wire.h>
#include <Rtc_Pcf8563.h>
/* add the lcd support */ 
#include "LCD12864RSPI.h"
//init the real time clock


Rtc_Pcf8563 rtc;


void setup()
{
  // set up the LCD's number of rows and columns: 

  LCDA.Initialise(); // INIT SCREEN
  delay(1000);
  LCDA.CLEAR();
  //clear out all the registers
  rtc.initClock();
  //set a time to start with.
  //day, weekday, month, century, year
  rtc.setDate(13, 3, 6, 0, 12);
  //hr, min, sec
  rtc.setTime(13, 42, 40);
}


void loop()
{
  char datetime[16] = " ";
  strncat(datetime,rtc.formatDate(),5);
  strcat(datetime," ");
  strcat(datetime,rtc.formatTime());
  LCDA.DisplayString(0,0,(unsigned char*) datetime,strlen(datetime));
  delay(1000);


}



再來把 Arduino 的 Sensor Shield 架上,修改程是讓 DS18B20 的溫度也顯示出來,應該是很簡單的工作,卻花了我快2個小時,最後發現是 Arduino 的 sprintf 在印 float 時只會印出 "?",上網 google 一下,發現只要把 sprinf 改成:



dtostrf(floatVar, minStringWidthIncDecimalPoint, numVarsAfterDecimal, charBuf);

重新編譯溫度就顯示出來了。


目前的程式:

#include <Wire.h>
#include <OneWire.h>
#include <Rtc_Pcf8563.h>
/* add the lcd support */ 
#include "LCD12864RSPI.h"
//init the real time clock

Rtc_Pcf8563 rtc;
OneWire  ds(10);

/* initialize the library objects */

void setup()
{
  Serial.begin(9600);
  LCDA.Initialise(); // INIT SCREEN
  delay(1000);
  LCDA.CLEAR();
//
  rtc.initClock();
  rtc.setDate(13, 3, 6, 0, 12);
  rtc.setTime(13, 42, 40);
}

void loop()
{
  char datetime[16] = " ";
  char tempature[8];
  byte addr[8];
  float celsius;
  byte present = 0;
  byte i;
  byte data[12];
  byte type_s;
  
 if ( !ds.search(addr)) {
    // LCDA.DisplayString(1,0,(unsigned char *) "error",5);
    ds.reset_search();
    delay(250);
    return;
  } 
  
  ds.reset();
  ds.select(addr);
  ds.write(0x44,1);         // start conversion, with parasite power on at the end
  
  delay(1000);     
  
  present = ds.reset();
  ds.select(addr);    
  ds.write(0xBE);         
   
  for ( i = 0; i < 9; i++) {           // we need 9 bytes
    data[i] = ds.read();
    // Serial.print(data[i], HEX);
    // Serial.print(" ");
  }
  
    unsigned int raw = (data[1] << 8) | data[0];
  if (type_s) {
    raw = raw << 3; // 9 bit resolution default
    if (data[7] == 0x10) {
      // count remain gives full 12 bit resolution
      raw = (raw & 0xFFF0) + 12 - data[6];
    }
  } else {
    byte cfg = (data[4] & 0x60);
    if (cfg == 0x00) raw = raw << 3;  // 9 bit resolution, 93.75 ms
    else if (cfg == 0x20) raw = raw << 2; // 10 bit res, 187.5 ms
    else if (cfg == 0x40) raw = raw << 1; // 11 bit res, 375 ms
    // default is 12 bit resolution, 750 ms conversion time
  }
  celsius = (float)raw / 16.0;
  // Serial.print(celsius);
  dtostrf(celsius,5,2,tempature);
  strncat(datetime,rtc.formatDate(),5);
  strcat(datetime," ");
  strcat(datetime,rtc.formatTime());
  LCDA.DisplayString(0,0,(unsigned char*) datetime,strlen(datetime));
  LCDA.DisplayString(1,0,(unsigned char *) tempature,strlen(tempature));
  
  delay(1000);
  }