mbedでI/O

当サイトにはアフィリエイト広告が表示されます。

mbedの基本的なI/O方法と実例。
やや古い情報ですが、基本的な構造は変わらないのでアップしておきます。
部品も未だ市販してるようです。
興味があるところを読む

基本のI/O

 DigitalIn、DigitalOut、PwmOut、Serial、タイマー割込み、ディレーを使う。
 mbedなら至って簡単・・・初期化もクロック設定も割込みの設定も不要。

DigitalIn

  • DigitalIn swIN(p30);      // p30をパラレル入力として使う。変数名は swIN。
  • ピンのハード的なモード設定
    swIN.mode(PullUp);        // PullUpに設定
    swIN.mode(PullNone);     // オープンに設定。
    swIN.mode(PullDown);    // PulDownに設定。これがデフォルト。
  • 入力
    char x = swIN; とする。
    あ~簡単だ~神経が休まるで~

DigitalOut

  • DigitalOut swOUT(p30);     // p30をパラレル出力に設定。変数名は swOUT だ。
  • 出力
    swOUT = 1; とか swOUT = 0; とかする。
  • ところでC++だから、こんな使い方が出来る。
    void ledCtrl(DigitalOut o, BYTE onoff)
    {
        o = onoff;
    }

    int main()
    {
        DigitalOut *x = new DigitalOut(LED1);
        ledCtrl(*x, 1);  // LED1点灯;
        ledCtrl(*x, 0);  // LED1消灯
        delete x;
    }
スポンサーリンク

秋月のLCDモジュールを使う 2013/11/21

 あまりにあっさり動いてしまった(mbed以外のCPUで使うならELMさんのEZ-LCDが便利です)。
 使ったモジュールはこれ。
 3.3V動作の20×4の白色バックライト付きLCDでドライバICはSC2004。

 こんな感じで接続して・・・
 ここでサンプルをImport。
 サンプルとは接続PINが異なるのでちょっと書き直したソースがこれ(サンプルではコメントが"d0,d1,d2,d3"となってるけど間違いと思われる)。
TextLCD_20X4  DO_Lcd(p15, p16, p17, p18, p19, p20); // rs, e, d4, d5, d6, d7

int main()
{
    wait_ms(1);   // すこし待たないと表示が乱れた

    DO_Lcd.locate(0,0);
    DO_Lcd.printf("80");

    DO_Lcd.locate(18,0);
    DO_Lcd.printf("93");
    ;
    ;
 素晴らしい。
  ・mbedを使うという選択をする。
  ・サンプルがあることを確認してから、メジャーなコントローラの載ったLCDを買う。
 この辺を上手く立ち回れば徹底的に楽をすることが出来る。
 大事なのは調査力・・・この頃しみじみ感じてます。良い時代になりました。

音声合成LSI ATP3011F4-PU をSPIで使う 2013/11/30

 これもあまりに簡単。
 使ったモジュールはこれ。

 回路図はこんな感じ。
 プログラムはこんな。
 SHでのSPIの時は本気で取り組んだけど、mbedはもうやんなっちゃうぐらい簡単。
 SHっていったいなんだったんだ(^^;
//----------------------------------------------------------------------------------------
// mbedのSPIで音声合成LSI ATP3011F4-PU を使う  2013/12/15 oj3
//  SPIのMODE=3, 周波数は1MHz, SSを使用
//----------------------------------------------------------------------------------------
static bool VoiceRdy(void);
// 出力開始
static void VoiceOut(const char *s, bool stopv=FALSE)
{
    DGO_VoiceSs = 0;    // CS=ON
    // 前の発声を中断して発声するなら・・・
    if (stopv == TRUE) {
        const char *w = "$\r";
        while (*w) {
            SPI_a.write(*w++);
            wait_ms(1);
        }
        while (VoiceRdy() == FALSE);
    }
    // 発声の終了を待つなら・・・
    else while (VoiceRdy() == FALSE);
    // 発声開始
    while (*s) {
        SPI_a.write(*s++);
        wait_ms(1);
    }
    wait_us(5);
    DGO_VoiceSs = 1;    // CS=OFF
}
// 出力が終了したか調べる(終了時TRUE)
static bool VoiceRdy(void)
{
    if (SPI_a.write(0xff) != '>') {
        wait_ms(10);
        return (SPI_a.write(0xff) == '>')? TRUE:FALSE;
    }
    return TRUE;
}
スポンサーリンク

SDメモリーカードを使う 2014/1/25

 ライブラリが有るんで使うのは簡単(mbed以外のCPUで使うならELMさんのFatFsが便利です)。
 OSを入れるまでもなくFATファイルシステムをチョー簡単に使用可能・・・素晴らしい。
 でもUART受信を落とす。
 でっかいデータをUARTで115200bpsで受信しながらSDカードに(ファイルとして)書き込むと受信データを落とす。
 まだライブラリを良く見てないけど、カードへのアクセス時に割込みを禁止してる?UART側の受信バッファオーバーとか?不明。
 で、対症療法としてCTSを上げ下げして、相手(パソコン)の送信を時々停めてやるハードウエアフロー制御を追加。
 試しに2Mbyteのデータを受信&File書き込みしてみたけどOK・・・実用的にはこれで十分だ。
// パソコン側のC#のプログラム 
 	
const int sz = 0x200000;
byte[] buf = new byte[2];
byte csum = 0;
for (int i = 0; i < sz; ++i) {
    buf[0] = (byte)i;
    csum += buf[0];
    serialPort1.Write(buf, 0, 1);
    while (false == serialPort1.CtsHolding) Thread.Sleep(1);    // targetでLにするとTrueになる
}
buf[0] = (byte)(0xff - csum);
serialPort1.Write(buf, 0, 1);
 	 
// mbed側のプログラム 
 	DigitalOut CTS(p26);  // 秋月のL023_FT232RLのCTS(CN2-10)とp26を接続
define _BFSZ 64       // このサイズを変えても通信時間に大差はない
bool func(char*fname)
{
    byte buf[_BFSZ+1];
    FILE *fp;
    if (NULL == (fp=fopen(fname, "wb" ))) return FALSE;
    while (1) {
        CTS=0; // CTS enable(PCは送信して寄こせ)
        // ここで受信データをバッファへ溜め込み・・・
        CTS=1; // CTS disable(PCは送信待て)
        if (fwrite(buf, 1, _BFSZ, fp) < _BFSZ) break; // write error
        ;

追記 2016/8/8

忘れっぽいんで、基本的な使い方を追記。mbedページ
秋月のSDカードコネクタを使用。コネクタ取説

DigitalOut    dbL1(LED1);
SDFileSystem  sd(p5, p6, p7, p22, "sd");     // mosi, miso, sclk, ss(p22)

void main(void)
{
    //---------------------------------
    // SDカードR/Wテスト
    //---------------------------------
    dbL1 = 0; // デバッグ用LEDをOFF
    char *fname = "/sd/test.txt";    // ここに/sd/が必須
    byte s1[50], s2[50];
    strcpy((char*)s1, "1234567890");
    if (TRUE == WrFile_Pkt(fname, s1, 10)) {
        if (TRUE == RdFile_Pkt(fname, s2, 50)) dbL1 = 1;    // 成功ならデバッグ用LEDをON
    }
}
//========================================================================================
// GLOBAL 指定fileから読む
//========================================================================================
bool RdFile_Pkt(char *fname, byte *ptr, int size)
{
    FILE *fp;
    if (NULL == (fp=fopen(fname, "rb" ))) return FALSE;
    fread(ptr, 1, size, fp);
    fclose(fp);
    return TRUE;
}
//========================================================================================
// GLOBAL 指定fileに書く
//========================================================================================
bool WrFile_Pkt(char *fname, byte *ptr, int size)
{
    FILE *fp;
    if (NULL == (fp=fopen(fname, "wb" ))) return FALSE;
    fwrite(ptr, 1, size, fp);
    fclose(fp);
    return TRUE;
}
スポンサーリンク

エンコーダを使う 2014/1/28

 元々はSHで使ってたのをチョイ改造してmbed用にした。
 ハードウエアでチャタリングを取る回路を入れるのが面倒なので、インターバルタイマーで読み出すタイプ。
 手動のエンコーダ程度ならこれで十分動く。
 使ったエンコーダは秋月の3色LEDと押しボタンSW内蔵のタイプ(LEDとSWは使ってない)。

 プログラムは例によって「結果オーライ」タイプ。
 動いてるから良しとしよう(^^;
 正統派の理屈や美しいプログラムはELMさんのところにあります。ELMさんの作る物は美しい、素晴らしい。

DigitalIn       DGI_EncA(p30);   // A相
DigitalIn       DGI_EncB(p29);   // B相
Ticker          TimerIntr;       // タイマー割込み(1mSで使用)

// 1mSごとに実行される関数
static void TimerLoop(void)
{
    EncRead();    // エンコーダ読み出し      
}
// エンコーダの状態を読んで変数にセットする
#define _ENCRESET   1000000UL // マイナスにしないため適当にでかい値をセット
static volatile ulong _encCnt = _ENCRESET;
static void EncClr(void)
{
    _encCnt = _ENCRESET;
}
static ulong EncGet(void)
{
    return _encCnt / 4UL;
}
// インターバルタイマーで1mSごとに実行する
static void EncRead(void)
{
    static BYTE old;
    BYTE pd = (BYTE)(DGI_EncA | (DGI_EncB << 1));
    // 時計回り
    if (old==0x0 && pd==0x2) --_encCnt;
    else if (old==0x2 && pd==0x3) --_encCnt;
    else if (old==0x3 && pd==0x1) --_encCnt;
    else if (old==0x1 && pd==0x0) --_encCnt;
    // 反時計回り
    if (old==0x0 && pd==0x1) ++_encCnt;
    else if (old==0x1 && pd==0x3) ++_encCnt;
    else if (old==0x3 && pd==0x2) ++_encCnt;
    else if (old==0x2 && pd==0x0) ++_encCnt;
    old = pd;
}
// 動作テスト用
void main(void)
{
    TimerIntr.attach_us(&TimerLoop, 1000.0f);
    EncClr();
    ulong encCnt = EncGet();
    while (1) {
        long p = EncGet() - encCnt;
        if (p < 0) {        // Encが左回転したら・・・
            ;
        } else if (p > 0) {   // Encが右回転したら・・・
            ;
        }
        encCnt = EncGet();
    }
}

USBメモリのR/W 2014/4/26

 LPC1768でUSBホストの実験。
 そこらに転がってたUSBメモリにアクセスしてみた。
 あまりに簡単でビックリ。
 USBホストのMSDプログラムをこつこつ組むなんてオラには無理。
 でもChanさんのFatFs以降便利になりました。
 mbedでもFatFsを使っているようだけど、移植の手間も無いしさらに便利。

 使わせて頂いたプログラムはUSBHostMSDMSCUsbHost
 どっちでも問題無く動作確認できた。
 東芝の暗号化USBメモリはさすがに動かなかったけど他のはOK。
 USB-Aソケットの接続図はこちらを参考にした。
 皆様、有り難うございます。ホントに楽になりました。

スポンサーリンク

エンコーダを使う 2014/7/09

 今回はハードウエア割り込みでエンコーダを使ってみた(抵抗とコンデンサでチャタリングを取ってる)。
 と言っても自分じゃ何もしてない。
 ここからQEIプログラムをImportして動かしただけ。
 あまりにも簡単で書くこともナシ。

 LPC1114で動かしたけど、初期化を一行書いて・・・
  QEI wheel (dp10, dp11, NC, 128, QEI::X4_ENCODING); // A相,B相,INDEX_pulse(NC),一回転のパルス数,X4(X2は動かない)
 パルス数を取得するなら・・・
  int pcnt = wheel.getPulses();
 回転した回数を取得するなら・・・
  int rcnt = wheel.getRevolutions();
 リセットしたいなら・・・
  int rcnt = wheel.reset();

 自分の環境では X2_ENCODING では動かなかったけど、なにかやり方があるんでしょう。
 X4で困らないんでOKっす。
 ところでImportしたLibraryのリファレンスはここにある。
 知らないと結構気が付かないのだ。

スポンサーリンク

mbedのAPIよりも先にやりたい処理が有る場合 2014/9/20

 mbedでコードを書くときって、main関数の前に外部変数としてAPIを宣言することが多い。
 この方式だとどこからでもアクセス出来て便利なんだけど、ちょい困る場合もある。
 例えばDigitalOutなんかは、main関数に行く前に初期化されるんで一瞬Hが出たりする。
 で、こうしてみた。

InitIo    _Init1st;            // DO_Upの初期化処理の前にやりたいことをやっちまう
DigitalOut  DO_Up(dp4);        // GPIO

InitIo::InitIo()
{
    LPC_IOCON->R_PIO0_11 = 0xc9;    // DO_UpからHが出ないように事前にPullDown
}

 InitIoをDigitalOutIよりも先に宣言して、やりたいことをやっておく。
 まぁmain関数の中でDigitalOutを宣言するとか、SystemInit関数とかでやっても良いんだけど、この方式ならソースの見通しが良いかなと思って。

スポンサーリンク
  • URLをコピーしました!

コメント

コメントする

CAPTCHA


興味があるところを読む