頂戴した LCD シールドで暫定的に遊んでみた

結果的に随分放置することになってしまったが、ある意味、正解だったのかもしれない。

話は少し長くなるが、まとめておいて(公益的な意味でも)損はないと思うので少々お付き合い下さい。「付き合いきれん!」という方はこれの次のエントリへ。(Coming Soon …たぶん)



っていうのを(長編覚悟で)書こうと思っていたのだけれども、こうして書いているあいだにも Twitter 経由で基板がガンガン改良されており、私の考えたこと・試したことが瞬時に陳腐化してゆく。私の浅慮など秒殺状態。なんか虚しくなってきたので、とりあえず昔書いたスケッチだけ上げておしまいにする。



因みにここで使用している「LCD シールド」はプロトタイプ。ユーザーテストという形で試作基板を分けていただいたものに(概ね)自前でパーツ実装している。できるだけ変態「シェフの気紛れパーツ」を使用することに腐心した(なんでだ)


こういうかんじ。


あ、あと勿論、CLCD モジュール(これ とか このへん )が必要。秋月の以外を使用する場合は電源ピンのレイアウトが異なる可能性があるので、要注意。
液晶モジュールを固定するためにスペーサなりなんなりも要る。勿論なくても平気ではある。このへんもいろいろと(ノウハウ的なものを含めて)あるのだが、書くのが面倒になったので割愛。



時期は不明だが、今後ネット通販等を通じて市販もされるようななるであろう量産版の LCD シールドには PWM 用の配線が標準搭載されるなど、まだまだ改良が加えられてゆくことになりそうな雰囲気なので、まあ、参考程度に。
…と思っていたのだが、どうやら量産型は(すみません量産型って言いたいだけです)シリパラ変換の CMOS IC を使って占有ポートを節約するタイプになる模様…。つまり、ここで紹介しているものはスケッチも流用できないし、あんまり参考にならないです。すみません m(_ _)m



/*
OKAERINASA"I"

2010/06/14
2010/08/15
By OkibiWorksLabo.
 */

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11,  5, 4, 3, 2);

const int ledPin = 13;
const int lcdContPin = 6;
const int sensPin = 5;
const int pseudoVCC = 17;
const int pseudoGND = 18;

int pos = 3;

  byte lcdChar[3][8] = {
    {16,  8,  4,  6,  5,  4,  4,  0},  // Reverse HIRAKAGANA "i"
    {31, 21, 31, 21, 31, 21, 31,  0},  // HAYABUSA SOLAR PANEL
    {14,  4, 31, 14, 14,  4,  0,  0},  // HAYABUSA BODY
    };

int sensRead() {
  int lcdOn;
  int sens;
  int thresh = 900;  //  900 の場合 4.4V ぐらい
  
  sens = analogRead(sensPin);
    lcd.setCursor(12,0);
    lcd.print(sens);
    lcd.print("   ");
    
    if (sens > thresh) 
        { lcdOn = 1; }
    else
        { lcdOn = 0; }

//  lcdOn = sens / thresh;  //  正の相関の場合これでもいい

  return lcdOn;
}

void lcd_bright(int dly) {
  int dStep = 50;
  float vUpper = 3.5;  //  電圧の上限
  float vLower = 0.2;  //  電圧の下限
  float volt;
  
      
  for(int i = 0; i <= dStep / 2; i++) {
    volt = vLower + (i * (vUpper - vLower) / dStep);
    analogWrite(lcdContPin, volt / 5 * 256 * sensRead()); 
    delay(dly / dStep);
  }
     digitalWrite(ledPin, HIGH); 
 
  for(int i = dStep / 2; i >= 0; i--) {
    volt = vLower + (i * (vUpper - vLower) / dStep);
    analogWrite(lcdContPin, volt / 5 * 256 * sensRead()); 
    delay(dly / dStep);
  }
     digitalWrite(ledPin, LOW); 

}



void setup()   {                
//  Serial.begin(9600);
  pinMode(ledPin, OUTPUT); 
  pinMode(lcdContPin, OUTPUT); 
  
  pinMode(pseudoVCC, OUTPUT);
  pinMode(pseudoGND, OUTPUT);

  digitalWrite(pseudoVCC, HIGH);
  digitalWrite(pseudoGND, LOW);

    for(int i = 0; i<=2; i++) {
        lcd.createChar(i, lcdChar[i]);
    }
    
  lcd.begin(16, 2); 
  //  lcd.begin( 8, 2); 
  lcd.clear();
  lcd.write(0xB5);
  lcd.write(0xB6);
  lcd.write(0xB4);
  lcd.write(0xD8);
  lcd.write(0xC5);
  lcd.write(0xBB);
  lcd.write(0);
  

//     for(int i = 0; i<=23; i++){
//       lcd.scrollDisplayRight();
//       delay(50);
//     }


  randomSeed(analogRead(0));

}

void loop() {
    lcd.setCursor(pos, 1);
    lcd.write(32);
    lcd.write(1);
    lcd.write(2);
    lcd.write(1);
    lcd.write(32);
  
//      delay(1000);
      lcd_bright(3000);

    pos = pos + random(3) - 1;
    if(pos <  1) { pos =  2;}
    if(pos > 11) { pos = 10;}
    
}

それと、温度計。今回は LM60 を使用してみた。

「…なんで SMD …?」とかそのへんは気にしてはいけないポイントであります*1

これが右下隅にくっついてる。LCD シールドは、こういう単体のセンサのテストなどにも非常に便利。

/*
temperture003

for LM35D, 60, 61
for LCD panel

2009/11/21 
2009/11/22
2009/11/23
2010/08/13 *bugfix
By OkibiLabo.
 */

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11,     5, 4, 3, 2);   // Enable -> GND
 
const int ledPin = 13;
const int thmPin =  5;

//  const int pseudoGND = 6;
//  const int pseudoVCC = 7;
const int pseudoGND = 18;
const int pseudoVCC = 17;

// const byte deg = B11011111;

  byte lcdChar[8][8] = {
    {12, 18, 18, 12,  0,  0,  0,  0},  // Degree Mark
    { 9,  5,  1, 12,  1,  5, 11,  0},  // following means
    {31,  1, 31,  0, 31, 21, 31,  0},  //     thermometer ("Ondokei")
    { 0,  3,  2,  3,  2,  4, 21,  0},  //      by Japanese KANJI.
    {14, 31, 17, 31, 17, 14, 29,  0},
    { 1, 23,  3, 17,  7,  4, 23,  0},
    { 1, 25,  7, 17, 25,  9, 25,  0},
    { 0,  0, 24,  0,  0,  0,  0,  0},
    };

//        const float thmPitch = 0.01;  // for LM35D , LM61
        const float thmPitch = 0.00625;  // for LM60 *bugfix
//        const float thmOffset = 0;    // for LM35D
        const float thmOffset = 0.424;  // for LM60
//        const float thmOffset = 0.6;  // for LM61
        
int aValue = 0;
float temp = 0;
float aRef ;
float gain ;

void ondokei_LCD()
{
    for(int i = 1; i<=7; i++) {
        lcd.createChar(i, lcdChar[i]);
    }
    
  lcd.begin(16, 2); 
  //  lcd.begin( 8, 2); 
  lcd.clear();
  lcd.print("Hello!");
    lcd.setCursor(0, 1);
    for(int i = 1; i<=7; i++) {
      lcd.write(i);
    }
  
      delay(2000);

     for(int i = 0; i<=23; i++){
       lcd.scrollDisplayRight();
       delay(50);
     }
}

int pickDecimal(float a, int digit)
{
  float d = pow(10, -1 - digit);
  return int((abs(a * d) - abs(int(a * d))) * 10);
}

void setup()   {                
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT); 
  pinMode(pseudoGND, OUTPUT);
  pinMode(pseudoVCC, OUTPUT); 
  
    analogReference(INTERNAL);
    aRef = 1.1;
//    analogReference(EXTERNAL);   // 基準電圧外部化には問題ありとの噂
//    aRef = 2.5;
//    analogReference(DEFAULT);
//    aRef = 5;
    
    gain = 1.0;    
  
    digitalWrite(pseudoVCC, HIGH);
    digitalWrite(pseudoGND,  LOW);
  
    lcd.createChar(0, lcdChar[0]);

  ondokei_LCD();

}

void loop()                     
{
  
      digitalWrite(ledPin, HIGH);
      delay(200);
    
  aValue = analogRead(thmPin);
  temp = ((float)aValue / gain / 1024 * aRef - thmOffset) / thmPitch;
  
      digitalWrite(ledPin, LOW);
      delay(800);  
    
/* */    Serial.print  (aValue);   
/* */    Serial.print  ("   ");   
/* */    Serial.println(temp); 

  lcd.clear();

  lcd.print("Temp:");  
  lcd.setCursor(1, 1);
  lcd.print((long)temp);
    lcd.print(".");
    lcd.print(pickDecimal(temp + 0.05 * temp / abs(temp), -1));
//    lcd.print(deg, BYTE);
    lcd.write(0);
  lcd.print("C");

    lcd.setCursor(8, 0);
  lcd.print("Gain");
  lcd.print(gain);
    lcd.setCursor(8, 1);
  lcd.print("Ref");
  lcd.print(aRef);
  lcd.print("V");
  
}


スケッチの説明その他は、気力が戻ってきたら、ぼちぼちやるかもしれません。
基本的にそんな面倒くさいことはしていないので(下手過ぎて(というか行き当たりばったりにもほどがある)読むに耐えないコードではありますが)解説も何も不要だとは思いますけども。


因みに、LM35 にしても LM60 , 61 にしても、どうも若干温度が高めに計測されるという傾向が私のところでは、あります。データシートに示されている仕様の誤差範囲内には充分収まって入るようですが、気になるところではあります。(そもそもこの手の温度センサは相対値で読み取ることでより正確な運用ができるものだという認識ですが。)実用上は 2℃程度リニアにマイナス補正をかけてやると、なんとなくそのあたりの空気温度と比較してちょうどいい感じになりそうな気がします。
Arduino 側の analogRead() 関数による読み値はさほど悪くない気がしました。基準電圧を INTERNAL に設定した際の誤差も気になるところではありますが、系統誤差があるというよりはブレが大きいということなのではないかという気がします。(ブレは相当ひどい様子*2。)

*1:無論、TO-92 パッケージもございます。
http://akizukidenshi.com/catalog/g/gI-02490/

*2:カップリングキャパシタを入れればブレは解消するだろうけどズレに関しては、なんとも。