2010年5月22日土曜日

プログラム初学者の視点

何人かの学生が

int  ledPin = 13;

pinMode(ledPin, OUTPUT);


のような変数?の使い方を理解できず,なやんでいた.名前をつけているだけなのだが,「変数=変わるもの,結果を入れるもの」という初々しい理解が邪魔をするのかもしれない.


#define ledPin 13

のほうが素直に理解できるらしい.たしかに他の用途がないという意味では明確だが...
Arduino は C++ が基本になっているので,スケッチを書く人間は,本来


const int ledPin = 13;

と書くべきだが表面的に予約語を増やすのはやめておこう,と考えているのかもしれない.
変数にするとメモリを消費する気がするが,レジスタも多いしコンパイラも最適化で定数として処理してしまうのかもしれない.

ブートローダが PORTD0, PORTD1 をシリアルでふさいだままだったり,プログラムのアップロードでリセットボタンをいちいち押す必要があったりと,いろいろなことがあるので,いっそプログラマを使って書き込みをするほうがすっきりするのだが..
HC595を二つ使って,使いづらい 8x8 マトリクスLED 1588BH (Paralight 4880X とピン互換)を3本(データ,シリアルクロック,ラッチ)と+5V,GNDの5本の接続で使うことができる.
LEDの行列とピンの対応は,ソフトウェアで入れ替える.ここでは最近 Arduino 言語に加えられた shiftOut 関数を使っている.

#include "matrix8x8.h"

const int latchPin = 8;   //Pin connected to ST_CP of 74HC595
const int clockPin = 12;   //Pin connected to SH_CP of 74HC595
const int dataPin  = 11;   //Pin connected to DS of 74HC595


void shiftOut16(byte dout, byte clk, byte latch, word val) {
  digitalWrite(latch, LOW);
  shiftOut(dout, clk, LSBFIRST, lowByte(val));
  shiftOut(dout, clk, LSBFIRST, highByte(val));
  digitalWrite(latch, HIGH);
}

inline void changeTimer2Prescaler(byte psc) {
  TCCR2B = TCCR2B & 0b11111000 | psc;
}

void setup() {
  //set pins to output because they are addressed in the main loop
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);

  changeTimer2Prescaler(2);
  analogWrite(3,96);
}

int n = 0;
char message[] = "If thou beest he; But O how fall'n! how chang'd From him, who in the happy Realms of Light Cloth'd with transcendent brightness didst out-shine ";
long elapsed = millis();
int intens = 0;
void loop() {
  word wval, pval;
  int i, s;
  //count up routine
  for (int r = 0; r < 8; r++) {
    wval = allColumnOff;
    for (int c = 0; c < 8; c++) {
      wval |= rowBV[r];
      if ( (n+c)%6 < 5 )
        if ( (font[message[(n+c)/6]-0x20][(n+c)%6]>>r) & 1 )
          wval &= ~colBV[c];
    }
    shiftOut16(dataPin, clockPin, latchPin, wval);
    delayMicroseconds(500);
  }
  //
  if ( millis() - elapsed > 222 ) {
    n++;
    if ( n > (sizeof(message)-2)*6 )
      n = 0;
    elapsed = millis();
  }
}

d3 を PWM に使って明るさを制御する配線を加えている.PWMのスピードをあげている.いらなければ Output Enable (OE) をGNDに接続する.
LEDのピンとの対応はソフトウェアでつける.定数は別のヘッダファイルにしている.


/*
 *  matrix8x8.h
 *
 *
 *  Created by Sin on 10/05/22.
 *  Copyright 2010 . All rights reserved.
 *
 */

#include


int row[] = {
  8, 13, 7, 11, 0, 6, 1, 4
};

word rowBV[] ={
  0x0001<<8,
  0x0001<<13,
  0x0001<<7,
  0x0001<<11,
  0x0001<<0,
  0x0001<<6,
  0x0001<<1,
  0x0001<<4
};

int col[] = {
  12, 2, 3, 9, 5, 10, 14, 15
};

word colBV[] = {
  (0x00001<<12),
  (0x00001<<2),
  (0x00001<<3),
  (0x00001<<9),
  (0x00001<<5),
  (0x00001<<10),
  (0x00001<<14),
  (0x00001<<15)
};

const word allColumnOff
  = colBV[0] | colBV[1] | colBV[2] | colBV[3] | colBV[4]
    | colBV[5] | colBV[6] | colBV[7];

const byte font[][5] = {
{0x00,0x00,0x00,0x00,0x00},   //   0x20 32
{0x00,0x00,0x6f,0x00,0x00},   // ! 0x21 33
{0x00,0x07,0x00,0x07,0x00},   // " 0x22 34
{0x14,0x7f,0x14,0x7f,0x14},   // # 0x23 35
{0x00,0x07,0x04,0x1e,0x00},   // $ 0x24 36
{0x23,0x13,0x08,0x64,0x62},   // % 0x25 37
{0x36,0x49,0x56,0x20,0x50},   // & 0x26 38
{0x00,0x00,0x07,0x00,0x00},   // ' 0x27 39
{0x00,0x1c,0x22,0x41,0x00},   // ( 0x28 40
{0x00,0x41,0x22,0x1c,0x00},   // ) 0x29 41
{0x14,0x08,0x3e,0x08,0x14},   // * 0x2a 42
{0x08,0x08,0x3e,0x08,0x08},   // + 0x2b 43
{0x00,0x50,0x30,0x00,0x00},   // , 0x2c 44
{0x08,0x08,0x08,0x08,0x08},   // - 0x2d 45
{0x00,0x60,0x60,0x00,0x00},   // . 0x2e 46
{0x20,0x10,0x08,0x04,0x02},   // / 0x2f 47
{0x3e,0x51,0x49,0x45,0x3e},   // 0 0x30 48
{0x00,0x42,0x7f,0x40,0x00},   // 1 0x31 49
{0x42,0x61,0x51,0x49,0x46},   // 2 0x32 50
{0x21,0x41,0x45,0x4b,0x31},   // 3 0x33 51
{0x18,0x14,0x12,0x7f,0x10},   // 4 0x34 52
{0x27,0x45,0x45,0x45,0x39},   // 5 0x35 53
{0x3c,0x4a,0x49,0x49,0x30},   // 6 0x36 54
{0x01,0x71,0x09,0x05,0x03},   // 7 0x37 55
{0x36,0x49,0x49,0x49,0x36},   // 8 0x38 56
{0x06,0x49,0x49,0x29,0x1e},   // 9 0x39 57
{0x00,0x36,0x36,0x00,0x00},   // : 0x3a 58
{0x00,0x56,0x36,0x00,0x00},   // ; 0x3b 59
{0x08,0x14,0x22,0x41,0x00},   // < 0x3c 60
{0x14,0x14,0x14,0x14,0x14},   // = 0x3d 61
{0x00,0x41,0x22,0x14,0x08},   // > 0x3e 62
{0x02,0x01,0x51,0x09,0x06},   // ? 0x3f 63
{0x3e,0x41,0x5d,0x49,0x4e},   // @ 0x40 64
{0x7e,0x09,0x09,0x09,0x7e},   // A 0x41 65
{0x7f,0x49,0x49,0x49,0x36},   // B 0x42 66
{0x3e,0x41,0x41,0x41,0x22},   // C 0x43 67
{0x7f,0x41,0x41,0x41,0x3e},   // D 0x44 68
{0x7f,0x49,0x49,0x49,0x41},   // E 0x45 69
{0x7f,0x09,0x09,0x09,0x01},   // F 0x46 70
{0x3e,0x41,0x49,0x49,0x7a},   // G 0x47 71
{0x7f,0x08,0x08,0x08,0x7f},   // H 0x48 72
{0x00,0x41,0x7f,0x41,0x00},   // I 0x49 73
{0x20,0x40,0x41,0x3f,0x01},   // J 0x4a 74
{0x7f,0x08,0x14,0x22,0x41},   // K 0x4b 75
{0x7f,0x40,0x40,0x40,0x40},   // L 0x4c 76
{0x7f,0x02,0x0c,0x02,0x7f},   // M 0x4d 77
{0x7f,0x04,0x08,0x10,0x7f},   // N 0x4e 78
{0x3e,0x41,0x41,0x41,0x3e},   // O 0x4f 79
{0x7f,0x09,0x09,0x09,0x06},   // P 0x50 80
{0x3e,0x41,0x51,0x21,0x5e},   // Q 0x51 81
{0x7f,0x09,0x19,0x29,0x46},   // R 0x52 82
{0x46,0x49,0x49,0x49,0x31},   // S 0x53 83
{0x01,0x01,0x7f,0x01,0x01},   // T 0x54 84
{0x3f,0x40,0x40,0x40,0x3f},   // U 0x55 85
{0x0f,0x30,0x40,0x30,0x0f},   // V 0x56 86
{0x3f,0x40,0x30,0x40,0x3f},   // W 0x57 87
{0x63,0x14,0x08,0x14,0x63},   // X 0x58 88
{0x07,0x08,0x70,0x08,0x07},   // Y 0x59 89
{0x61,0x51,0x49,0x45,0x43},   // Z 0x5a 90
{0x3c,0x4a,0x49,0x29,0x1e},   // [ 0x5b 91
{0x02,0x04,0x08,0x10,0x20},   // \ 0x5c 92
{0x00,0x41,0x7f,0x00,0x00},   // ] 0x5d 93
{0x04,0x02,0x01,0x02,0x04},   // ^ 0x5e 94
{0x40,0x40,0x40,0x40,0x40},   // _ 0x5f 95
{0x00,0x00,0x03,0x04,0x00},   // ` 0x60 96
{0x20,0x54,0x54,0x54,0x78},   // a 0x61 97
{0x7f,0x48,0x44,0x44,0x38},   // b 0x62 98
{0x38,0x44,0x44,0x44,0x20},   // c 0x63 99
{0x38,0x44,0x44,0x48,0x7f},   // d 0x64 100
{0x38,0x54,0x54,0x54,0x18},   // e 0x65 101
{0x08,0x7e,0x09,0x01,0x02},   // f 0x66 102
{0x0c,0x52,0x52,0x52,0x3e},   // g 0x67 103
{0x7f,0x08,0x04,0x04,0x78},   // h 0x68 104
{0x00,0x44,0x7d,0x40,0x00},   // i 0x69 105
{0x20,0x40,0x44,0x3d,0x00},   // j 0x6a 106
{0x00,0x7f,0x10,0x28,0x44},   // k 0x6b 107
{0x00,0x41,0x7f,0x40,0x00},   // l 0x6c 108
{0x7c,0x04,0x18,0x04,0x78},   // m 0x6d 109
{0x7c,0x08,0x04,0x04,0x78},   // n 0x6e 110
{0x38,0x44,0x44,0x44,0x38},   // o 0x6f 111
{0x7c,0x14,0x14,0x14,0x08},   // p 0x70 112
{0x08,0x14,0x14,0x18,0x7c},   // q 0x71 113
{0x7c,0x08,0x04,0x04,0x08},   // r 0x72 114
{0x48,0x54,0x54,0x54,0x20},   // s 0x73 115
{0x04,0x3f,0x44,0x40,0x20},   // t 0x74 116
{0x3c,0x40,0x40,0x20,0x7c},   // u 0x75 117
{0x1c,0x20,0x40,0x20,0x1c},   // v 0x76 118
{0x3c,0x40,0x30,0x40,0x3c},   // w 0x77 119
{0x44,0x28,0x10,0x28,0x44},   // x 0x78 120
{0x0c,0x50,0x50,0x50,0x3c},   // y 0x79 121
{0x44,0x64,0x54,0x4c,0x44},   // z 0x7a 122
{0x00,0x08,0x36,0x41,0x41},   // { 0x7b 123
{0x00,0x00,0x7f,0x00,0x00},   // | 0x7c 124
{0x41,0x41,0x36,0x08,0x00},   // } 0x7d 125
{0x04,0x02,0x04,0x08,0x04},   // ~ 0x7e 126
};



文字を出すだけならともかく,これでもCPUパワーをかなりとられて,使いづらい.割り込みにしてもあまりかわらないだろう.
ATTiny2313 かなにかでドライバを作ってディスプレイとして接続するほうが実用的だろう.

LM60 アナログ温度センサ

アナログピンで出力を読み,係数をかければ温度が得られる.ただし1.0Vが約100℃に相当するスケールなので,8ビットほどしか解像度がとれず、そのままではおよそ0.8度刻みになる.

//#define AREF_V 1096   // the value for INTERNAL AREF Voltage
#define AREF_V 5125

long a0avr;

void setup() {
  Serial.begin(9600);
}

void loop() {
  //analogReference(INTERNAL);
  a0avr = (analogRead(0) + a0avr)/2;
  Serial.println( a0avr * AREF_V /1024 / 6.25 - 67.84 );
  delay(750);
}

マイコンの内部参照電圧約 1.1V を使えば,0.16度の刻みが得られる.内部参照電圧で analogRead を使う場合は,analogReference(INTERNAL) をコールし,係数を変更する.