デアゴ ミレニアムファルコン作成記 Episode 097 [ラズパイとPICのLED制御について]

デアゴ ファルコン
この記事は約12分で読めます。

ただひたすらファルコンに電飾を仕込みたいが為に、独学でRaspberry PiやPICについて学んでましたが、ちょっと間が空いていたので、課題になっていた事を片付けて、制御について再検討しました。

動画

リハビリ兼ねて、ビットシフトレジスタを2個つないで16個のLEDをラズパイとPICでコントロールしてみました。動画は最終的にPICを接続したときのもの。

(プログラムは本記事にあります)

久しぶりだったので、環境再設定したり、いろいろ思い出すの大変でした。

個人的な備忘録として、今回ハマったのをメモ。

  • シフトレジスタをクリアするSRCLR端子(負論理[端子に上線表記あり])を無効にするためHIGHに接続しておくのを忘れてた。

 

 

ビットシフトレジスタへ降順に格納する

以前に、Raspberry PiからたくさんのLEDを制御する方法について書いた下記の記事。

課題が残ってました。

レジスタの格納順序が逆になるため、配列を逆から見たパターンがセットされるため、ループ内の変数は、後ろ側からセットしています。これは直感的でないので、反転するプログラムがあると楽かも。後日の課題とします。

レジスタの値をFirst In First Outでシフトして設定する動きをします。

なので、配列を降順にセットしてあげる様に変更しました。

PIC 12F683 降順にセットするプログラム

ループ処理(for文)をデクリメントさせてるだけです。

/*
 * File:   main.c
 * プログラム概要
 *   ビットシフトレジスタ制御テストプログラム
 *   ビットシフトレジスタSN74HC595N2台接続の点滅制御を行う
 *     先頭のビットが最初に入るようにループを降順に制御
 */


//include
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>

// PIC12F683コンフィグレーションビット設定
#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = OFF      // MCLR Pin Function Select bit (MCLR pin function is digital input, MCLR internally tied to VDD)
#pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = ON       // Brown Out Detect (BOR enabled)
#pragma config IESO = OFF       // Internal External Switchover bit (Internal External Switchover mode is disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is disabled)

// クロック周波数指定
#define _XTAL_FREQ  1000000

//接続するLED数
#define LEDQTY 16

/*
 * main()関数
 */
int main(int argc, char** argv) {

    // PIC初期化
    OSCCON = 0x40;  //クロック周波数を1MHz
    ANSEL  = 0x00;  //全てデジタルモード
    TRISIO = 0x00;  //GP3以外を出力ピンに設定(GP3は入力固定)

    
    //カウンタ変数
    int j,k;

    //データ定義
    int LEDptn[LEDQTY]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};


    //リセット
    GP0=0; // SER
    GP1=0; // SRCLK
    GP2=0; // RCLK
   
while(1){  
    //j回目のループの時、LEDptn[j]だけHIGHに設定する
    for(j=0;j<LEDQTY;j++){
        LEDptn[j]=1;
        //配列の最後尾から降順にセットする
        for(k=LEDQTY-1;k>=0;k--){
            GP0=LEDptn[k];
            GP1=1;              //SRCLK HIGH
            GP1=0;              //SRCLK LOW
            }
    GP2=1;                      //RCLK HIGH
    GP2=0;                      //RCLK LOW
    __delay_ms(300);            //0.3sec待つ
    }
    // 全部点灯したらすべて全消灯(配列のリセット)
        for(j=0;j<LEDQTY;j++){
        LEDptn[j]=0;
        for(k=0;k<LEDQTY;k++){
            GP0=LEDptn[k];
            GP1=1;              //SRCLK HIGH
            GP1=0;              //SRCLK LOW
            }
        }
    GP2=1;                      //RCLK HIGH
    GP2=0;                      //RCLK LOW
    __delay_ms(300);

 }
}

 

Raspberry Pi Python 降順にセットするプログラム

調査にちょっと手間取りましたが、reversedを使うらしい。簡単に済みました。

   for i in reversed(range(n)):

 

上記リンク(Episode 054)の修正バージョンです。

import RPi.GPIO as GPIO
from time import sleep

def sendLEDdata(data, ser, rclk, srclk):
    n = len(data)

    GPIO.output(rclk, GPIO.LOW)
    GPIO.output(srclk, GPIO.LOW)

    for i in reversed(range(n)):
        if data[i] == 1:
            GPIO.output(ser, GPIO.HIGH)
        else:
            GPIO.output(ser, GPIO.LOW)

        GPIO.output(srclk, GPIO.HIGH)
        GPIO.output(srclk, GPIO.LOW)

    GPIO.output(rclk, GPIO.HIGH)
    GPIO.output(rclk, GPIO.LOW)

SER = 25
RCLK = 24
SRCLK = 23

GPIO.setmode(GPIO.BCM)
GPIO.setup(SER, GPIO.OUT)
GPIO.setup(RCLK, GPIO.OUT)
GPIO.setup(SRCLK, GPIO.OUT)

LEDdata0 = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
LEDdata1 = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
LEDdata2 = [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
LEDdata3 = [1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
LEDdata4 = [1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1]
LEDdata5 = [1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1]
LEDdata6 = [1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1]
LEDdata7 = [1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1]
LEDdata8 = [1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1]
LEDdata9 = [1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1]
LEDdata10= [1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1]
LEDdata11= [1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1]
LEDdata12= [1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1]
LEDdata13= [1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1]
LEDdata14= [1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1]
LEDdata15= [1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1]
LEDdata16= [1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1]
LEDdata17= [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0]

try:
    while True:
        sendLEDdata(LEDdata0, SER, RCLK, SRCLK)
        sleep(0.2)
        sendLEDdata(LEDdata1, SER, RCLK, SRCLK)
        sleep(0.2)
        sendLEDdata(LEDdata2, SER, RCLK, SRCLK)
        sleep(0.2)
        sendLEDdata(LEDdata3, SER, RCLK, SRCLK)
        sleep(0.2)
        sendLEDdata(LEDdata4, SER, RCLK, SRCLK)
        sleep(0.2)
        sendLEDdata(LEDdata5, SER, RCLK, SRCLK)
        sleep(0.2)
        sendLEDdata(LEDdata6, SER, RCLK, SRCLK)
        sleep(0.2)
        sendLEDdata(LEDdata7, SER, RCLK, SRCLK)
        sleep(0.2)
        sendLEDdata(LEDdata8, SER, RCLK, SRCLK)
        sleep(0.2)
        sendLEDdata(LEDdata9, SER, RCLK, SRCLK)
        sleep(0.2)
        sendLEDdata(LEDdata10, SER, RCLK, SRCLK)
        sleep(0.2)
        sendLEDdata(LEDdata11, SER, RCLK, SRCLK)
        sleep(0.2)
        sendLEDdata(LEDdata12, SER, RCLK, SRCLK)
        sleep(0.2)
        sendLEDdata(LEDdata13, SER, RCLK, SRCLK)
        sleep(0.2)
        sendLEDdata(LEDdata14, SER, RCLK, SRCLK)
        sleep(0.2)
        sendLEDdata(LEDdata15, SER, RCLK, SRCLK)
        sleep(0.2)
        sendLEDdata(LEDdata16, SER, RCLK, SRCLK)
        sleep(0.2)
        sendLEDdata(LEDdata17, SER, RCLK, SRCLK)
        sleep(0.2)

except KeyboardInterrupt:
    pass

GPIO.cleanup()

 

PICの配列定義の容量オーバーの問題

先日の投稿、

で、

defineで定義したデータの配列を永遠と書こうとおもったのですが、PICの変数用メモリが全然足りなくてエラーが発生しました。なので、今回は単純なロジックで1個ずつ点灯させるようにしました。

と書いてました。

今回も、

    //データ定義
    int LEDptn[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    int LEDptn2[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

と、2行に増やした段階でエラーとなってしまいます。

    //データ定義
    int LEDptn[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    int LEDptn2[100];

宣言だけだと、エラー無し。

。。。となると、プログラム本文中にオンコードでパターンを設定するのはできそうだけど、上記のプログラムで既に40%程度の容量を食ってるみたいなので、すぐにリミットが訪れそうな気がしててがっつり組むのはちょっと怖い。

 

ランダムなLED制御はPIC、規則的な制御はラズパイで

(ラズパイから接続された)PICのある端子がHIGHになった状態で、PICでコクピットなどのランダム点灯を制御して、着陸灯や頭上注意灯など、完全に制御したいものはラズパイやArduinoでコントロールした方が良さげですね。

 

 

コメント

  1. 6jiro より:

    こんばんは!

    マイコン関連は少し離れているとリハビリ大変ですよね〜w
    私もすぐにプログラムを忘れてしまいますw
    同じく自分のブログを見ながらリハビリしています。

    私の場合は各所でそれぞれの単純機能を制御するAVRを置いて、それらを統合するAVRを中央に置いて制御しようと思っています。
    その方がプログラム簡単ですもんね^^。

    • >6jiroさん

      そうなんですよ。
      今回は完全なるリハビリ。。
      一度再開したら勘所は回復するんですが。。

      PICよりAVRの方が制約なさそうですが、今回はそのまま突き進みます(笑)

タイトルとURLをコピーしました