前回リモコン信号の解析を行ったため、そのとおりに作るだけ。
まず、「何のマイコンを使うか?」だが、結論から言うとRL78のR5F10Y47ASPを使うことにした。
理由としては、手持ちのマイコンの中で最も動作電圧が低く(2.0V)、電池駆動に適していたため。本当はPICが一番使い慣れているので、それが良かったんだけどね。最低でも2.3Vのやつしか持っていなかった。
プログラム
全て説明すると大変なので、主要な部分だけ書くことにする。
リモコン信号は38kHzパルス信号のON/OFFなので、内蔵ペリフェラルのタイマ・アレイ・ユニットを使用して、
・パルス信号の生成(チャネル0&1でPWM)
・パルス信号のON時間計測(チャネル2)
・パルス信号のOFF時間計測(チャネル3)
を行うことにした。これだけでは何のことか分からないので、図で表すとこんな感じ。
つまり、、
- チャネル0&1と、チャネル2をスタート。
- チャネル2のカウント完了割り込みで、チャネル0&1と、チャネル2をストップ。チャネル3をスタート。
- チャネル3のカウント完了割り込みで、チャネル3をストップ。
の一連の流れで1bitのデータを送信することになる。
基本的にレジスタ設定はCS+のコード生成機能を使用して行った。
クロック設定画面。
割り込み設定画面。割り込みは、全灯ボタン・消灯ボタンを押したときにスタンバイ状態から通常動作に復帰するために使用している。
タイマ・アレイ・ユニットの設定画面はこんな感じ。チャネル2とチャネル3のインターバル時間についてはプログラム上で可変するので適当な値。
で、コード生成されたタイマ・アレイ・ユニットの割り込みサービスルーチンには、以下のようにタイマのスタート/ストップやフラグを立てる処理を追加。
r_cg_tau_user.c
- /***********************************************************************************************************************
- Includes
- ***********************************************************************************************************************/
- #include "r_cg_macrodriver.h"
- #include "r_cg_tau.h"
- /* Start user code for include. Do not edit comment generated here */
- /* End user code. Do not edit comment generated here */
- #include "r_cg_userdefine.h"
- /***********************************************************************************************************************
- Pragma directive
- ***********************************************************************************************************************/
- #pragma interrupt r_tau0_channel2_interrupt(vect=INTTM02)
- #pragma interrupt r_tau0_channel3_interrupt(vect=INTTM03)
- /* Start user code for pragma. Do not edit comment generated here */
- /* End user code. Do not edit comment generated here */
- /***********************************************************************************************************************
- Global variables and functions
- ***********************************************************************************************************************/
- /* Start user code for global. Do not edit comment generated here */
- /* End user code. Do not edit comment generated here */
- /***********************************************************************************************************************
- * Function Name: r_tau0_channel2_interrupt
- * Description : This function INTTM02 interrupt service routine.
- * Arguments : None
- * Return Value : None
- ***********************************************************************************************************************/
- static void __near r_tau0_channel2_interrupt(void)
- {
- /* Start user code. Do not edit comment generated here */
- R_TAU0_Channel0_Stop();//38kHz発振停止
- TO0=0;//TO01の出力をLにする
- R_TAU0_Channel2_Stop();
- R_TAU0_Channel3_Start();//OFF時間の計測開始
- /* End user code. Do not edit comment generated here */
- }
- /***********************************************************************************************************************
- * Function Name: r_tau0_channel3_interrupt
- * Description : This function INTTM03 interrupt service routine.
- * Arguments : None
- * Return Value : None
- ***********************************************************************************************************************/
- static void __near r_tau0_channel3_interrupt(void)
- {
- /* Start user code. Do not edit comment generated here */
- PPMTime_flg=1;//フラグを立てる
- R_TAU0_Channel3_Stop();
- /* End user code. Do not edit comment generated here */
- }
- /* Start user code for adding. Do not edit comment generated here */
- /* End user code. Do not edit comment generated here */
リモコンの処理関数はこんな感じ。
nec_remocon.c
- /***********************************************************************************************************************
- Includes
- ***********************************************************************************************************************/
- #include "nec_remocon.h"
- static void sendWave(uint16_t onTime_us, uint16_t offTime_us);
- const uint16_t _1T_CLK=2810;
- const uint16_t _1T_OFF_CLK=2810-240;
- const uint16_t _3T_CLK=8430-240;
- const uint16_t _8T_CLK=22480-240;
- const uint16_t _16T_CLK=44960-240;
- void sendDataByte(uint8_t val){
- uint8_t data_bit=0;
- uint8_t cnt=0;
- for(cnt=0;cnt<8;cnt++){
- data_bit=val & 0x01;
- if (data_bit){
- sendWave(_1T_CLK,_3T_CLK);
- }else{
- sendWave(_1T_CLK,_1T_OFF_CLK);
- }
- val=val>>1;
- }
- }
- void sendLeader(void){
- sendWave(_16T_CLK,_8T_CLK);
- }
- void sendStopbit(void){
- sendWave(_1T_CLK,_1T_OFF_CLK);
- }
- static void sendWave(uint16_t onTime_clkcount, uint16_t offTime_clkcount){
- //38kHzの発振のON時間をセット
- TDR02H=(onTime_clkcount & 0xff00)>>8;
- TDR02L=(onTime_clkcount & 0xff);
- //OFF時間をセット
- TDR03H=(offTime_clkcount & 0xff00)>>8;
- TDR03L=offTime_clkcount & 0xff;
- PPMTime_flg=0;
- R_TAU0_Channel0_Start();//38kHz発振開始
- R_TAU0_Channel2_Start();//発振のON時間の計測開始
- while(PPMTime_flg==0);//フラグが1になるまで待つ
- }
クロック周波数が5MHzなので、インターバルタイマーで1T(=562us)をカウントする場合、設定値は562*10^(-6)*5*10^6=2810となる。ちなみに、定数で-240しているものがあるが、これはクロック周波数が5MHzと遅く、オーバーヘッドを無視できないため、調整のために入れている。20MHz駆動とかなら多分不要。
メインの処理はこんな感じ。
r_cg_main.c
- /***********************************************************************************************************************
- Includes
- ***********************************************************************************************************************/
- #include "r_cg_macrodriver.h"
- #include "r_cg_cgc.h"
- #include "r_cg_port.h"
- #include "r_cg_tau.h"
- #include "r_cg_it.h"
- #include "r_cg_intp.h"
- /* Start user code for include. Do not edit comment generated here */
- #include "nec_remocon.h"
- /* End user code. Do not edit comment generated here */
- #include "r_cg_userdefine.h"
- /***********************************************************************************************************************
- Pragma directive
- ***********************************************************************************************************************/
- /* Start user code for pragma. Do not edit comment generated here */
- /* End user code. Do not edit comment generated here */
- /***********************************************************************************************************************
- Global variables and functions
- ***********************************************************************************************************************/
- /* Start user code for global. Do not edit comment generated here */
- volatile uint8_t PPMTime_flg=0;
- volatile uint8_t timer_200msec_flg=0;
- /* End user code. Do not edit comment generated here */
- static void R_MAIN_UserInit(void);
- /***********************************************************************************************************************
- * Function Name: main
- * Description : This function implements main function.
- * Arguments : None
- * Return Value : None
- ***********************************************************************************************************************/
- void main(void)
- {
- R_MAIN_UserInit();
- /* Start user code. Do not edit comment generated here */
- R_IT_Start();//200msインターバルタイマをスタート
- R_INTC1_Start();//INT割り込み有効
- R_INTC3_Start();//INT割り込み有効
- while (1U){
- LED1=~LED1;//デバッグ用
- R_IT_Stop();
- if (TURN_ON_BTN==0){//全灯ボタンを押したとき
- sendLeader();
- sendDataByte(0x51);
- sendDataByte(0x76);
- sendDataByte(0x10);
- sendDataByte(0x00);
- sendDataByte(0x01);
- sendDataByte(0x00);
- sendDataByte(0x6C);
- sendStopbit();
- timer_200msec_flg=0;
- }else if (TURN_OFF_BTN==0){//消灯ボタンを押したとき
- sendLeader();
- sendDataByte(0x51);
- sendDataByte(0x76);
- sendDataByte(0x10);
- sendDataByte(0x00);
- sendDataByte(0x02);
- sendDataByte(0x00);
- sendDataByte(0x6F);
- sendStopbit();
- timer_200msec_flg=0;
- }else{//ボタンが押されていないとき
- timer_200msec_flg=0;
- LED1=0;
- STOP();//STOPモードに入る
- }
- R_IT_Start();
- while(timer_200msec_flg==0);
- }
- /* End user code. Do not edit comment generated here */
- }
- /***********************************************************************************************************************
- * Function Name: R_MAIN_UserInit
- * Description : This function adds user code before implementing main function.
- * Arguments : None
- * Return Value : None
- ***********************************************************************************************************************/
- static void R_MAIN_UserInit(void)
- {
- /* Start user code. Do not edit comment generated here */
- EI();
- /* End user code. Do not edit comment generated here */
- }
- /* Start user code for adding. Do not edit comment generated here */
- /* End user code. Do not edit comment generated here */
200ms毎に消灯ボタン・全灯ボタンの状態を取得し、何も押されていない場合はスタンバイ状態(STOPモード)に入って電池の消耗を抑えるようにしている。
今回はソースコードを一部しか載せていないが、全ソースコードをGitHubで公開したいね。GitHubは使ったことが無いので、まずは使い方を覚えるところからだけど・・。
動作確認
ブレッドボードで回路を組んで問題なく、全灯/消灯できることを確認した。ぶっちゃけこんな画像を載せても何のこっちゃって感じだが・・。清書した回路図を次回は作りたいね。