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を使っているようだけど、移植の手間も無いしさらに便利。
使わせて頂いたプログラムはUSBHostMSDとMSCUsbHost。
どっちでも問題無く動作確認できた。
東芝の暗号化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関数とかでやっても良いんだけど、この方式ならソースの見通しが良いかなと思って。
コメント