ポン菓子屋店頭用電光掲示板
電光掲示板(LED 64×16)
SODIALのLEDモジュール(8×8×4連)を4個連結して、64×16にしてArduinoDUEでコントロールさせています
「たま吉さん」のスケッチ等を参考にさせていただき(感謝!)、SODIALのモジュールはLEDユニットの並びが左右逆のようなので、少し変更して動かしています
64×16での表示は出来たので、時計と温度・湿度表示をできるようにしたら(夏の屋外営業では必須?)ケースに入れようかと思っています
ちなみに、この表示で5V入力での消費電流は約200mAなので、6000mAh程度のモバイルバッテリーで、1日はもちそうです
変更箇所1 SDカード接続ピンアサイン
//#define MOSI_SD 11 // SDカードのMOISへ接続
//#define MISO_SD 12 // SDカードのMISOへ接続
//#define CLK_SD 13 // SDカードのCLKへ接続
#define MOSI_SD 75 // SDカードのMOSIへ接続@DUE
#define MISO_SD 74 // SDカードのMISOへ接続@DUE
#define CLK_SD 76 // SDカードのCLKへ接続@DUE
変更箇所2 MAX7219接続数、表示エリアの横ドット数指定
// #define SCREENS 8 // MAX7219カスケード接続数
#define SCREENS 16 // MAX7219カスケード接続数
// #define SC_WIDTH 32 // マトリック表示横ドット数
#define SC_WIDTH 64 // マトリック表示横ドット数
変更箇所3 フレームバッファからMAX7219バッファへの変換部
// for (uint8_t i=0; i < 8; i++) {
// memcpy(&ptr[i*8],&fbuf[i*4+32], 4);
// memcpy(&ptr[i*8+4],&fbuf[i*4], 4);
// }
for (uint8_t i=0; i < 8; i++) { // each MAX7219 has 8 rows
memcpy(&ptr[i*SCREENS],&fbuf[i*SC_WIDTH/8+SC_WIDTH+7], 1);
memcpy(&ptr[i*SCREENS+1],&fbuf[i*SC_WIDTH/8+SC_WIDTH+6], 1);
memcpy(&ptr[i*SCREENS+2],&fbuf[i*SC_WIDTH/8+SC_WIDTH+5], 1);
memcpy(&ptr[i*SCREENS+3],&fbuf[i*SC_WIDTH/8+SC_WIDTH+4], 1);
memcpy(&ptr[i*SCREENS+4],&fbuf[i*SC_WIDTH/8+SC_WIDTH+3], 1);
memcpy(&ptr[i*SCREENS+5],&fbuf[i*SC_WIDTH/8+SC_WIDTH+2], 1);
memcpy(&ptr[i*SCREENS+6],&fbuf[i*SC_WIDTH/8+SC_WIDTH+1], 1);
memcpy(&ptr[i*SCREENS+7],&fbuf[i*SC_WIDTH/8+SC_WIDTH], 1);
memcpy(&ptr[i*SCREENS+8],&fbuf[i*SC_WIDTH/8+7], 1);
memcpy(&ptr[i*SCREENS+9],&fbuf[i*SC_WIDTH/8+6], 1);
memcpy(&ptr[i*SCREENS+10],&fbuf[i*SC_WIDTH/8+5], 1);
memcpy(&ptr[i*SCREENS+11],&fbuf[i*SC_WIDTH/8+4], 1);
memcpy(&ptr[i*SCREENS+12],&fbuf[i*SC_WIDTH/8+3], 1);
memcpy(&ptr[i*SCREENS+13],&fbuf[i*SC_WIDTH/8+2], 1);
memcpy(&ptr[i*SCREENS+14],&fbuf[i*SC_WIDTH/8+1], 1);
memcpy(&ptr[i*SCREENS+15],&fbuf[i*SC_WIDTH/8], 1);
}
変更箇所4 max7219_matrix.hの中の
//#define MAXSCREENS 8 // 最大接続数
#define MAXSCREENS 16 // 最大接続数
カットしたアクリル材(2セット分)到着(1/9)・・・穴あけ加工前
完成(1/17) ArduinoDUE + SODIAL LED ディスプレイモジュール×4
Arduinoシールド基板部品表(DUEの背中に乗せた基板)
①I2C接続のRTC:秋月電子 RTC-8564NB をLi電池でバックアップ(275nA)
②I2C接続のOLED:秋月電子 0.96インチ 128×64ドット OLED
③I2C接続の温湿度センサ:秋月電子 AM2322
④プッシュスイッチ×4:秋月電子
⑤Arduinoシールド基板:秋月電子 Arduino用ユニバーサルプロトシールド
⑥3.3V出力 → 5.0V入力 レベル変換IC実装(SN74LS07)
メッセージ部分は完成したので、ポン菓子屋に引き渡した
2/24(日)が「今年の初ポン=デビュー日」らしい
行ってらっしゃ~い
C++ (Arduino)
継承
class U8G2_MAX7219_64X8_1_4W_HW_SPI : public U8G2 {
public: U8G2_MAX7219_64X8_1_4W_HW_SPI(const u8g2_cb_t *rotation, uint8_t cs, uint8_t dc, uint8_t reset = U8X8_PIN_NONE) : U8G2() {
u8g2_Setup_max7219_64x8_1(&u8g2, rotation, u8x8_byte_arduino_hw_spi, u8x8_gpio_and_delay_arduino);
u8x8_SetPin_4Wire_HW_SPI(getU8x8(), cs, dc, reset);
}
};
解釈:
U8G2_MAX7219_64X8_1_4W_HW_SPI が派生クラス
U8G2 が基底クラス (: public がキーワード)
その後ろの {・・・} の部分が派生クラスの定義
関数 U8G2_MAX7219_64X8_1_4W_HW_SPI(・・・)はコンストラクタ(関数が生成(実体化)されたときに自動的に実行される初期化関数)
「U8G2_MAX7219_64X8_1_4W_HW_SPI」のコンストラクタとして
U8G2()(基底クラスのコンストラクタ)を実行した後に
u8g2_Setup_max7219_64x8_1(・・・)と u8x8_SetPin_4Wire_HW_SPI(・・・)の関数が実行されることになる
Arduino(忘備録)
- 共通
- ArduinoM0(Atmel SAMD:ARM Cortex-M0+)
- ArduinoDUE(Atmel SAM:ARM Cortex-M3)
- ESP32(Tensilica Xtensa LX6)
- STM32の自作ボード用のコンフィグファイルの作成方法
- マイクロSD
共通
- 「Arduino」はワンチップマイコンに、ドライバ(ブートローダ)を書き込み
統合化開発環境「Arduino IDE」経由で、コンパイラ・リンカ「gcc toolchain」を使用している
(AVR、SAM、ESP32、STM32、ルネサス(旧日立系)など) - 「Arduino IDE」の代わりに、「Visual Micro (Arduino IDE for Visual Studio)」を使用すると、関数定義の参照、ブレークポイントの使用、などの機能が使えて便利
(最初に、「Arduino IDE」でビルド後に使用しないと、ライブラリの参照とかがうまくいかない、二つの環境を適宜使い分けてデバッグしている) - 「setup()」,「loop()」:実は「main.cpp」の中から、以下のように呼ばれている
int main(void) {
init(); //CPUの初期化
initVariant(); //システムの初期化(差分?)
setup(); //ユーザープログラム(.ino)の初期化プロセス
for(;;) {
loop(); //ユーザープログラム(.ino)のプログラム
if(serialEventRun)
serialEventRun(); //シリアル通信は別プロセスとして動作
}
retun(0);
} - 環境設定file C:\Users\<アカウント名>\AppData\Local\Arduino15\ の中の 「preferences.txt」 に設定情報が格納される
- 追加ライブラリー C:\Users\<アカウント名>\Documents\Arduino\libraries
- ピンと信号名の対応
C:\Users\*yourName\AppData\Local\Arduino15\packages\arduino\hardware\sam\1.6.11\variants\arduino_due_x\variant.h とか variant.cpp の中で定義されている(*yourNameは各PCごと)
ArduinoM0(Atmel SAMD:ARM Cortex-M0+)
- "serial"は無くって、"serialUSB"を使用
- "serial5"が使えるようになった 0,1ピン(RX、TXと書いてあるピン)を使用
- SPIはICSP (SCK,MISO,MOSI,SS)=(24,22,23,SS)(DMA付)
- SERCOM4で SPI.begin(13,12,11,10); を追加可能(UNOと同じ)
- SD:HardSSを使用しないときでもHardSSピンを出力に設定
- ArduinoZERO が M0 に名前を変えたらしい…が同じではなさそう
ArduinoDUE(Atmel SAM:ARM Cortex-M3)
- SPIはICSP (SCK,MISO,MOSI,SS)=(76,74,75,SS)(DMA付)
SPI_CONTINUE(SSをアクティブのままにしておく)が使えるのはDUEのみ - setup()内でSS信号ピンを設定 : SPI.begin(*SS); *SS=4(CS1),10(CS0),52(CS2) のみ設定可
- I2C wire :SDA,SCL=20,21(MEGAタイプのArduinoにしか存在しないピン)
wire1:SDA,SCL=70,71 (他のArduino のI2Cのピン) - A/D 10bit(default)/12bit(analogReadResolution(12);で指定)
SPANはdefaultでは3.3Vになっているが「AREF」というジャンパ(ICSPコネクタのCPU寄り)で「EXT」側にジャンパすると「AREFピン」に変更できる
「AREFピン」入力は10bit動作時は2.0V~VDD、12bit動作時は2.4V~VDD
入力電流は250μAmax(14kΩtyp)…フィルタなしだとノイズで9bit程度
ESP32(Tensilica Xtensa LX6)
- IO12を”H"にして、serialへ”Enter"を入力すると「BASIC」が起動する
これがHSPIのMOSI信号になっているので「プルアップ」すると
このモードになってしまい、プログラムの書き込みができなくなる - GPIO6,7,8,9,10,11はGPIOとしては使えない(らしいがSPIとしては使えるみたい、内蔵FLASHとSSを分ける)
- SPIは"SPI.begin(SCK,MISO,MOSI,SS);"で宣言(DMA付)
VSPI(標準SPI): SPI.begin(18,19,23,5);
HSPI(SPI2になる): SPI.begin(14,12,13,15);
*HSPIにmicroSDを割り付けるとなぜだかうまくいかない→VSPIに割り付けた
SPI(内蔵FLASH用): SPI.begin(6,7,8,SS); (SS≠11) - freeRTOS with LwIPの下で走っている
- ピンマップ
#define EXTERNAL_NUM_INTERRUPTS 16 //外部割込み
#define NUM_DIGITAL_PINS 40 //デジタル入出力ピン
#define NUM_ANALOG_INPUTS 16 //アナログ入力ピン#define analogInputToDigitalPin(p) (((p)<20)?(esp32_adc2gpio[(p)]):-1)
#define digitalPinToInterrupt(p) (((p)<40)?(p):-1)
#define digitalPinHasPWM(p) (p < 34)static const uint8_t TX = 1; // Serialピンアサイン
static const uint8_t RX = 3;static const uint8_t SDA = 21; // Wire(I2C)ピンアサイン
static const uint8_t SCL = 22;static const uint8_t SS = 5; // SPIピンアサイン(VSPI)
static const uint8_t MOSI = 23;
static const uint8_t MISO = 19;
static const uint8_t SCK = 18;static const uint8_t A0 = 36; // A1,A2が無い!!
static const uint8_t A3 = 39;
static const uint8_t A4 = 32;
static const uint8_t A5 = 33;
static const uint8_t A6 = 34;
static const uint8_t A7 = 35; // A8,A9も無い…
static const uint8_t A10 = 4;
static const uint8_t A11 = 0;
static const uint8_t A12 = 2;
static const uint8_t A13 = 15;
static const uint8_t A14 = 13;
static const uint8_t A15 = 12;
static const uint8_t A16 = 14;
static const uint8_t A17 = 27;
static const uint8_t A18 = 25;
static const uint8_t A19 = 26;static const uint8_t T0 = 4; // Timer出力(PWM)
static const uint8_t T1 = 0;
static const uint8_t T2 = 2;
static const uint8_t T3 = 15;
static const uint8_t T4 = 13;
static const uint8_t T5 = 12;
static const uint8_t T6 = 14;
static const uint8_t T7 = 27;
static const uint8_t T8 = 33;
static const uint8_t T9 = 32;static const uint8_t DAC1 = 25; // DAC出力
static const uint8_t DAC2 = 26;
STM32の自作ボード用のコンフィグファイルの作成方法
- C:\Users\<user_name>\AppData\Local\Arduino15\packages\STM32\hardware
\stm32\1.7.0\variants\ の下のboard_templateフォルダから、元になりそうなものをコピーしてくる - それにピンマップを追加
C:\Users\<user_name>\AppData\Local\Arduino15\packages\STM32
\tools\STM32Tools\1.3.1\tools\src\genpinmap\Arduino\ の下の
PeripheralPins.c と PinNamesVar.h を元に変更 - システムクロックの設定方法
CubeMXを使って初期化ファイルを出力させて、それを
C:\Users\<user_name>\AppData\Local\Arduino15\packages\STM32
\hardware\stm32\1.7.0\variants\NUCLEO_F303K8 の下の
variant.cppに反映させる