Archive
こんばんは!
夜が冷えるようになったせいか、今朝、猛烈な腹痛に襲われたゆってぃです(涙)

さて、今日は前回に引き続きXBeeネタです。
前回は、マイコン側からPC側への通信を行いました。
今回は、PCからマイコン側にデータを送ってみましょう。

PC側は、我らがTeraTerm様があれば準備完了なので、いつものようにマイコン側のソースコードを書いていきます。
なお、今回も前回同様FIFOやフロー制御は使用しませんが、受信部は割り込みで制御します。
これは、受信に関してはいつPC側からデータが来るのかわからないためです。

それでは、前回のコードと大半は重複しますが、おさらいの意味もかねてuart_ctrl.hとuart_ctrl.cを記載します。

と、そのまえに・・・

このソフトのデバッグ中、つまらないミスにハマってしまいました。。。
よくあるミスなので、自戒の念をこめてここに書かせていただきます。

僕は開発環境にIARのEWARMを、ICEはj-link使用しています。
このIDEは他の一般的な製品同様、ペリフェラルレジスタの中身をIDE上で簡単に確認・編集することが出来ます。
つまり、受信レジスタであるRDRの中身も覗けてしまいます。
するとね、マイコンはデータが取り出されたと判断して、RDRFをクリアしてしまいますたぶん!!(汗)

これはその時のIDEのスクリーンショットですが、受信割り込みが発生してハンドラが呼ばれているのでも関わらず、レジスタエディタ内のRDRFは0クリアされていることがわかります。

ブレーク

この様に、例えば受信割り込みハンドラ内でブレークを貼って、開発環境側でRDRの中を確認してしまうと、その後の処理がうまくいかなかったりします。
(このスクリーンショットの例では、if文内の処理が実行されません)
これは、レジスタエディタを開いていなければ起こらない現象ですので、皆さんもデバッグの際は注意しましょう。
(ROMに焼くと動くけど、デバッグ中にブレーク張るとうまく動かない…という現象の典型的な例です。たぶん)

では、話をソースへ戻します。
なお、赤字で書かれた箇所が、前回からの追加部分です。



//-----
uart_ctrl.h
//------------



#ifndef __UART_CTRL_H
#define __UART_CTRL_H

#ifdef __cplusplus
extern "C" {
#endif

#include "typedefine.h"

#define XB24_UART_REG (FM3_MFS0_UART)

//------------------
//UART制御クラス
//-----------------------------
typedef struct UART_CTRL{

BOOL isMethodInitialized; //関数の初期化判別フラグ

BOOL (*initUartReg)(struct UART_CTRL *pUC); //UART関連のレジスタ初期化
BOOL (*writeUartData)(struct UART_CTRL *pUC, UINT8 *data, UINT32 size);
BOOL (*readUartData)(struct UART_CTRL *pUC, UINT8 *data);

}UART_CTRL;

extern UART_CTRL* initUartCtrl(void);

#ifdef __cplusplus
}
#endif


#endif



//-----
uart_ctrl.c
//------------



#include "mcu.h"

#include "typedefine.h"
#include "uart_ctrl.h"
#include "timer.h"

static BOOL INIT_UART_REG(UART_CTRL *pUC);
static BOOL WRITE_UART_DATA(UART_CTRL *pUC, UINT8 *data, UINT32 size);
static BOOL READ_UART_DATA(UART_CTRL *pUC, UINT8 *data);

static UART_CTRL instance_uart_ctrl;

extern UART_CTRL* initUartCtrl(){

if(!instance_uart_ctrl.isMethodInitialized){
instance_uart_ctrl.isMethodInitialized = TRUE;
instance_uart_ctrl.initUartReg = INIT_UART_REG;
instance_uart_ctrl.writeUartData = WRITE_UART_DATA;
instance_uart_ctrl.readUartData = READ_UART_DATA;
}

return &instance_uart_ctrl;

}

/*
* レジスタ設定
*/
static BOOL INIT_UART_REG(UART_CTRL *pUC){

BOOL ret = FALSE;

//端子設定
FM3_GPIO->ADE_f.AN31 = 0; //SOT0_0
FM3_GPIO->PFR2_f.P1 = 1; //SIN0_0
FM3_GPIO->PFR2_f.P2 = 1; //SOT0_0
FM3_GPIO->EPFR07 |= 0x00000050; //リロケート設定

//割り込み禁止
XB24_UART_REG->SCR_f.RIE = 0;
XB24_UART_REG->SCR_f.TIE = 0;
XB24_UART_REG->SCR_f.TBIE = 0;

//送受信禁止
XB24_UART_REG->SCR_f.RXE = 0;
XB24_UART_REG->SCR_f.TXE = 0;

//内部状態初期化(プログラマブルクリア)
XB24_UART_REG->SCR_f.UPCL = 1;

//------ SMR Setting ------//
// 動作モード設定(UART NORMAL)
// WAKE UP OFF
// STOP bit : 1 bit (ESBL = 0)
// LSBファースト
// 出力禁止
//--------------------------------//

XB24_UART_REG->SMR &= 0x00;

//------ SSR Setting ------//
// 受信エラーフラグ クリア
//--------------------------------//

XB24_UART_REG->SSR |= 0x80;

//------ ESCR Setting ------//
// ハードウェアフロー制御禁止(とりあえず)
// STOP bit : 1 bit (SBL = 0)
// NRZフォーマット
// パリティ禁止(とりあえず)
// データ長 = 8 bit
//--------------------------------//

XB24_UART_REG->ESCR &= 0x00;

//------ BGR1 BGR0 Setting ------//
// 内部クロック使用
// ボーレートは9600Hzに設定(とりあえず)@ Main = 144MHz, バスクロック = 36MHz
// リロード値:3750(0x0ea5)
//--------------------------------//

XB24_UART_REG->BGR1 = 0x0e;
XB24_UART_REG->BGR0 = 0xa5;

//受信許可(割り込み許可)
XB24_UART_REG->SCR |= 0x12;

//割り込み許可
NVIC_EnableIRQ(MFS0RX_IRQn);


ret = TRUE;

return ret;

}

/*
* 送信
*/
static BOOL WRITE_UART_DATA(UART_CTRL *pUC, UINT8 *data, UINT32 size){

BOOL ret = FALSE;
UINT8 buf;
int i;


XB24_UART_REG->SMR_f.SOE = 1;
XB24_UART_REG->SCR_f.TXE = 1;

TimerWait(10); //相手側の準備待ち

for(i=0;i < size;i++){

buf = *data;

while(XB24_UART_REG->SSR_f.TDRE == 0);

XB24_UART_REG->TDR = buf;

while(XB24_UART_REG->SSR_f.TBI == 0);

data++;

}

XB24_UART_REG->SCR_f.TXE = 0;
XB24_UART_REG->SMR_f.SOE = 0;

ret = TRUE;

return ret;

}

/*
* 受信
*/
static BOOL READ_UART_DATA(UART_CTRL *pUC, UINT8 *data){

BOOL ret = FALSE;


if( XB24_UART_REG->SSR_f.PE || XB24_UART_REG->SSR_f.FRE || XB24_UART_REG->SSR_f.ORE ){
//[TODO]エラー処理
XB24_UART_REG->SSR |= 0x80;
}else{

*data = XB24_UART_REG->RDR;

ret = TRUE;
}


return ret;

}




データを受信するだけではつまらなかったので、今回、受信データによってLEDの輝度を変えるような実装を行いました。
ASCIIコードで'a'を受信するとLEDを明るく、's'を受信すると暗くし、現在のPWMのDUTYをPC側に返してみました。
(ついでにLCDにも表示しています)



#include "mcu.h"

#include "pwm_ctrl.h"
#include "lcd.h"
#include "timer.h"
#include "uart_ctrl.h"

static UART_CTRL *pUC;
static PWM_CTRL *pPC;

int main()
{

pUC = initUartCtrl();
pUC->initUartReg(pUC);

pPC = initPwmCtrl(0x0fff, 0x00ff);
pPC->initPwmReg(pPC);
pPC->startPwmOutput();

initDisp();
printUpLine("XBee Test");

while(1);


return 0;
}

void MFS0RX_IRQHandler(){

UINT8 str[16] = {0};
UINT8 TxMsg[14] = "BRIGHTNESS = ";
UINT8 brightness[7] = {0};
UINT8 data;

pUC = initUartCtrl();

if(XB24_UART_REG->SSR_f.RDRF){
pUC->readUartData(pUC,&data);

printLowLine(&data);

if(data == 'a'){
if(pPC->mDuty < 0x0fff){
UINT16 duty = pPC->mDuty + 0x000f;
pPC->changeDuty(pPC, duty);
}
}else if(data == 's'){
if(pPC->mDuty > 0x0001){
UINT16 duty = pPC->mDuty - 0x000f;
pPC->changeDuty(pPC, duty);
}
}
sprintf(brightness,"%x\r\n",pPC->mDuty);
pUC->writeUartData(pUC,TxMsg,sizeof(TxMsg));
pUC->writeUartData(pUC,brightness,sizeof(brightness));
sprintf(str,"BRIGHTNESS:%x ",pPC->mDuty);
printLowLine(str);
}

}




無事に、TeraTerm上から明るさを変更し、そのときの明るさをターミナル上に表示することが出来ました。
ターミナル上の表示はこんな感じです。

BRIGHTNESS


マイコン側はこんな感じ。

XBee2


全然大したことはやっていないのですが、やはり無線でモノが動かせるとテンションあがりますね!(笑)

せっかく5000円出して買ったXBeeなので、これからも遊んでみたいと思います^ ^

最後までお読みいただいて、ありがとうございました!(感謝)
関連記事
スポンサーサイト
こんばんは!
最近、車を買ってしまったゆってぃです!
(色々悩んだ末、結局フィットですけど…)

納車が楽しみです^ ^


話は変わりますが…


本ブログも、ついに累計10000アクセスを突破しました!

皆様、本当にありがとうございます!
皆様が懲りずにご覧になって下さるお陰で、僕自身も今まで書き続けてくることが出来ました。

有益な情報はほとんど書かれておりませんが、これからもご支援のほどをよろしくお願いいたしますm(_ _)m


さて、タイトルにもあるとおり、本ブログもいよいよ無線通信に手を出してしまいます!
満を持してといったところでしょうか?(本当か??)
(ごめんなさい。。。PWMは別の何かと組み合わせて記事を書きます)

XBeeとは、超お手軽に使える無線モジュールです。
モジュールのインターフェースはUARTなので、GNDとTX及びRXさえ接続すれば、PCからもマイコンからも、簡単に制御することが出来ます。
モジュールで技適も取得済みなので、電波法を気にする必要もありません。

という訳で、早速自作のFM3拡張ボードに接続してみました。
と言っても、もうボード上にスペースが無かったので、ちょっとカッコ悪いですが無理やりくっつけてみました。

FM3側XBeeモジュール

PC側に至っては、もはやブレッドボードです。。。
PC側XBeeモジュール


無線通信と言えば聞こえは良いですが、実際はXBeeモジュールとUARTで通信しているに過ぎません。
XBee本体に必要になる面倒くさい設定は、X-CTUというツールで、GUIベースで行うことが出来ます。
X-CTUはここからダウンロード可能です。
(Diagnostics, Utilities and MIBsって書かれてるとこにあります)
64bitOSはサポート外らしいですが、僕のWin7(64bit)上では問題なく動いているようです。

ただ、このツール、ダウンロード中に最新バージョンのダウンロードを促す画面が出てきます。
これが、ものっすごい時間がかかります。
ですが、これを乗り切らないと(少なくとも僕の買った)XBeeZBモジュールは、設定が出来ませんでした。

あと、これはZBタイプだけなのかもしれませんが、X-CTUの設定画面でMY-16-bit NetworkAddressが編集できませんでした。
そのため、Destination Addressは、モジュールの裏に書いてあるシリアルで指定するようです。
なんか他にも色々設定できる項目があるようですが、とりあえず触らぬ神に祟り無しということで、全然触っていません(笑)

とりあえず手元のボードで「マイコン → PC」という一方通行のデータ転送には成功しました。
ですので、今日はそこまでのコードを公開します。

まずは、UART通信を行うためのUART_CTRLクラスを定義します。
なお、ここでは最小限の通信しか行いませんので、皆さんで必要に応じて改良してくださいね^ ^
(そもそも一方通行という時点で不完全…。UARTもwriteしか作って無いです。FIFOも使って無いです(汗))

以下に、uart_ctrl.huart_ctrl.cの2つのコードを掲載します。
まずはuart_ctrl.hから!

因みに、開発環境はIARのEWARM ver6.30の評価版(コードサイズ制限版)です。




//----uart_ctrl.h-------//

#ifndef __UART_CTRL_H
#define __UART_CTRL_H

#ifdef __cplusplus
extern "C" {
#endif

#include "typedefine.h"

#define XB24_UART_REG (FM3_MFS0_UART)

//------------------
//UART制御クラス
//-----------------------------
typedef struct UART_CTRL{

BOOL isMethodInitialized; //関数の初期化判別フラグ

BOOL (*initUartReg)(struct UART_CTRL *pUC); //UART関連のレジスタ初期化
BOOL (*writeUartData)(struct UART_CTRL *pUC, UINT8 *data, UINT32 size);

}UART_CTRL;

extern UART_CTRL* initUartCtrl(void);

#ifdef __cplusplus
}
#endif


#endif



typedefine.hは、単に変数名を再定義しただけのヘッダですので、気にしないで下さい(笑)
つぎに、メソッドを定義したuart_ctrl.cです。



//----uart_ctrl.c-------//

#include "mcu.h"

#include "typedefine.h"
#include "uart_ctrl.h"
#include "timer.h"

static BOOL INIT_UART_REG();
static BOOL WRITE_UART_DATA(UART_CTRL *pUC, UINT8 *data, UINT32 size);

static UART_CTRL instance_uart_ctrl;

extern UART_CTRL* initUartCtrl(){

if(!instance_uart_ctrl.isMethodInitialized){
instance_uart_ctrl.isMethodInitialized = TRUE;
instance_uart_ctrl.initUartReg = INIT_UART_REG;
instance_uart_ctrl.writeUartData = WRITE_UART_DATA;
}

return &instance_uart_ctrl;

}

/*
* レジスタ設定
*/
static BOOL INIT_UART_REG(UART_CTRL *pUC){

BOOL isOk = FALSE;

//端子設定
FM3_GPIO->ADE_f.AN31 = 0; //SOT0_0
FM3_GPIO->PFR2_f.P1 = 1; //SIN0_0
FM3_GPIO->PFR2_f.P2 = 1; //SOT0_0
FM3_GPIO->EPFR07 |= 0x00000050; //リロケート設定

//割り込み禁止
XB24_UART_REG->SCR_f.RIE = 0;
XB24_UART_REG->SCR_f.TIE = 0;
XB24_UART_REG->SCR_f.TBIE = 0;

//送受信禁止
XB24_UART_REG->SCR_f.RXE = 0;
XB24_UART_REG->SCR_f.TXE = 0;

//内部状態初期化(プログラマブルクリア)
XB24_UART_REG->SCR_f.UPCL = 1;

//------ SMR Setting ------//
// 動作モード設定(UART NORMAL)
// WAKE UP OFF
// STOP bit : 1 bit (ESBL = 0)
// LSBファースト
// 出力禁止
//--------------------------------//

XB24_UART_REG->SMR &= 0x00;

//------ SSR Setting ------//
// 受信エラーフラグ クリア
//--------------------------------//

XB24_UART_REG->SSR |= 0x80;

//------ ESCR Setting ------//
// ハードウェアフロー制御禁止(とりあえず)
// STOP bit : 1 bit (SBL = 0)
// NRZフォーマット
// パリティ禁止(とりあえず)
// データ長 = 8 bit
//--------------------------------//

XB24_UART_REG->ESCR &= 0x00;

//------ BGR1 BGR0 Setting ------//
// 内部クロック使用
// ボーレートは9600Hzに設定(とりあえず)@ Main = 144MHz, バスクロック = 36MHz
// リロード値:3750(0x0ea5)
//--------------------------------//

XB24_UART_REG->BGR1 = 0x0e;
XB24_UART_REG->BGR0 = 0xa5;

isOk = TRUE;

return isOk;

}

static BOOL WRITE_UART_DATA(UART_CTRL *pUC, UINT8 *data, UINT32 size){

BOOL isOk = FALSE;
UINT8 buf;
int i;


XB24_UART_REG->SMR_f.SOE = 1;
XB24_UART_REG->SCR_f.TXE = 1;

TimerWait(10); //相手側の準備待ち

for(i=0;i < size;i++){

buf = *data;

while(XB24_UART_REG->SSR_f.TDRE == 0);

XB24_UART_REG->TDR = buf;

while(XB24_UART_REG->SSR_f.TBI == 0);

data++;

}

XB24_UART_REG->SCR_f.TXE = 0;
XB24_UART_REG->SMR_f.SOE = 0;

isOk = TRUE;

return isOk;

}



ここでは特に言及しませんが、TimerWait()関数は、自作した単なるウエイト関数です。
引数×1msecだけウエイトします。

最後に、蛇足ですがmain関数を含んだmain.cを掲載します。



//------main.c-------//

#include "lcd.h"
#include "uart_ctrl.h"


int main()
{
UART_CTRL *pUC;

UINT8 message[14] = {0};
strcpy(message,"Hello World\r\n");

pUC = initUartCtrl();

pUC->initUartReg(pUC);

pUC->writeUartData(pUC,message,sizeof(message));

initDisp();
printUpLine("XBee Test");

while(1);

return 0;
}



なお、lcd.hは、FM3からLCD(SC1602)を動かすための関数を定義したヘッダです。
これも解説はしませんが、ご要望があればソースコードを掲載します。

PC側はTeraTermでXBeeモジュールからの信号を受け取るようにしておきます。
その上で、マイコン側の電源を入れれば、リセットボタンを押すたびにTeraTerm上にHello Worldが表示されます。

XBee通信結果


なんて簡単なんだろう!

こんな簡単に無線通信が出来てしまったら、僕のような組み込み系の人間は必要なくなっちゃうんじゃないかと、リアルに心配になってしまいます(汗)

とりあえず、かなり不完全ではありますが、FM3とPCの通信が確認できました。
次は、PCからFM3側に信号を送りたいと思います。

最後までお読みいただいて、ありがとうございました!(感謝)
関連記事
ご訪問者様
プロフィール

ゆってぃ

Author:ゆってぃ
経歴7年の組み込み系・制御系エンジニアです。
("ど素人"という文言は取りました…笑)
ソフトウェア開発経験ゼロの状態から、なんとか実務がこなせるようになってきた現在に至るまでの経験を、備忘録代わりに綴っていきたいと思います。
入門者の方、大歓迎!
(上級者の方、ごめんなさい…)

あと、ブログには全然関係ないですが、Bumpy Headというバンドのギターをやっています。
ライブ情報なんかも書いたりすることがあるので、その時に「行ってもいいよ~」といった感じのコメントを戴けると、泣いて喜びます(泣)
ブログ読んでくださってる方なら、チケット代サービスしちゃいます!

最後に…滅多に流用することは無いでしょうが、このブログに書かれているソースは、特に指定の無い限りMITライセンスとします。ただし、一部それ以外のものもございますのでご注意下さい。
※ブログのリンク先にあるコードに関しては、リンク先のポリシーに従ってください。

最新記事
最新コメント
カテゴリ
RSSリンクの表示
メールフォーム

名前:
メール:
件名:
本文:

twitter
リンク
ブロとも申請フォーム
スポンサードリンク