RX220でパソコンとシリアル通信
秋月のRX220のマイコンボードがあったのでパソコンとシリアル通信をしてみた.
シリアル通信とは1本の信号線の信号を時間で変化するようにして信号を送受信する通信方式のこと.
多くのマイコンにはUARTが中に入っていてシリアル通信はハードウェアで可能で,プログラムをマイコンに書き込む際に使用することも多い. ルネサスの場合はSCI通信と書かれている, 秋月のRX220のマイコンボードのRX220にはR5F52206BDFMが使用されているのでシリアルが5チャネルもあり様々な物と通信が可能だ.
特にPCとかと通信できると,マイコン内部の変数の状態を読み出すことも出来るようになるのでデバッグの際に非常に便利だ.
ルネサスからサンプルプログラムが出てた気がするが,なんとなく使用したくなかったのでユーザーズマニュアルを読んで自分で書くこととした.
この本お勧め
SCIは調歩同期式通信とクロック同期式通信が可能です.ほかにも簡易I2Cと簡易SPIも使えるらしいが使ったことは無い.
調歩同期式通信は通信速度,データの始まりと終わり方をあらかじめ合わせてから通信する方式.
クロック同期式は通信の主導権を握っているマスターから供給されるクロックに両者が合わせて通信する方式.
どのように,プログラムを書けば良いかはユーザーズマニュアルに記載されている.
この様なソースコードを書いてみた.PCと通信は出来るが,最適でない,バグがある可能性が高いので使用は自己責任でお願いしたい,この様にしたほうが良い等があればぜひ指摘してほしい.
これはクロックが32MHzで動作していることを前提としている.
sci1.h
#include"iodefine.h" #include<machine.h> #define SCI SCI1 #define RDR SCI.RDR #define TEND SCI.SSR.BIT.TEND #define BPS(a) BPS_##a #define BPS_19200 SCI.SEMR.BIT.ABCS=1;SCI.BRR =104 #define BPS_38400 SCI.SEMR.BIT.ABCS=1;SCI.BRR =51 #define BPS_115200 SCI.SEMR.BIT.ABCS=1;SCI.BRR =17 #define BPS_230400 SCI.SEMR.BIT.ABCS=0;SCI.BRR =5 #define BPS_460800 SCI.SEMR.BIT.ABCS=0;SCI.BRR =2 #define BPS_921600 SCI.SEMR.BIT.ABCS=0;SCI.BRR =1 #define ESC_KEY 0x1b #define ENTER_KEY 0x0a unsigned char get_buff; static unsigned char get_buff_m[40]; unsigned char trans_buff ; unsigned char trans_buff_m[]; unsigned char trans_b[100]; short sci1_error=0; static int receve_data_num , string_num; static char get_buff_2[40]; void INIT_SCI1(void); void int_scr1_txi1(void); void int_scr1_tei1(void); void int_scr1_rxi1(void); void int_scr1_eri1(void); void sci1_putc(unsigned char c); void sci1_puts(unsigned char* c); void sci1_put(unsigned char* c,int n); int sci1_get( volatile unsigned char* p); char sci1_getc_2(void);
sci1.c
#include "sci1.h" void INIT_SCI1(void){ SYSTEM.PRCR.WORD = 0xA502; // 消費電力低減機能設定レジスタ書き込み許可 MSTP(SCI1)=0; SYSTEM.PRCR.WORD = 0xA500; // 消費電力低減機能設定レジスタ書き込み禁止 SCI1.SCR.BIT.TE =0; //送信停止 SCI1.SCR.BIT.RE =0; SCI1.SMR.BIT.CKS=0; // PCLK/1 SCI1.SMR.BIT.STOP =0; // 1stop bit SCI1.SCR.BIT.TEIE =0; //トランスミットエンドインタラプトイネーブル SCI1.SCR.BIT.TIE =1; SCI1.SCR.BIT.RIE =1; ICU.IER[27].BIT.IEN3 = 1; // ICU.IER[27].BIT.IEN4 = 1; // ICU.IER[27].BIT.IEN5 = 1; // ICU.IPR[218].BIT.IPR = 15; //004 SCI1.SEMR.BIT.ABCS = 1;//1syc8bit SCI1.SEMR.BIT.NFEN = 1;//ノイズフィルタ BPS(115200); MPC.PWPR.BIT.B0WI = 0; //PFSWEへの書き込み許可 MPC.PWPR.BIT.PFSWE = 1; //PFCレジスタへ書き込み許可 PORT2.PMR.BIT.B6 = 1; PORT3.PMR.BIT.B0 = 1; MPC.P30PFS.BIT.PSEL = 10; // RXD1 MPC.P26PFS.BIT.PSEL = 10; // TXD1 MPC.PWPR.BIT.PFSWE = 0; //PFCレジスタへ書き込み禁止 MPC.PWPR.BIT.B0WI = 1; //PFSWEへの書き込み禁止 SCI1.SCR.BIT.TE =0; //送信開始 SCI1.SCR.BIT.RE =1; //受信開始 SCI1.TDR = 0xff; } void int_scr1_txi1(void){ static int i=0; setpsw_i(); if(trans_b[i]=='\0'){ SCI1.SCR.BIT.TIE =0; SCI1.SCR.BIT.TEIE=1; SCI1.TDR='\0'; i=0; }else{ SCI1.TDR=trans_b[i++]; } trans_b[(i-1)]=0x00; }//intprg.cで呼び出す void int_scr1_tei1(void){ setpsw_i(); SCI1.SCR.BIT.TIE =0; SCI1.SCR.BIT.TE =0; // SCI1.SCR.BIT.TEIE=0; PORT2.PMR.BIT.B6 = 0; //PORT3.PMR.BIT.B0 = 0; //PORT3.PDR.BIT.B0 = 1; PORT2.PDR.BIT.B6 = 1; //PORT3.PODR.BIT.B0=1; PORT2.PODR.BIT.B6=1; }//intprg.cで呼び出す void int_scr1_rxi1(void){ int n; setpsw_i(); get_buff_m[receve_data_num++]=RDR; if(receve_data_num >= sizeof(get_buff_m)-1 )receve_data_num=0; switch(RDR){ case ESC_KEY: receve_data_num=0; for( n=0; n<=sizeof(get_buff_m); n++ ){ get_buff_m[n]='\0'; }for( n=0; n<=sizeof(get_buff_2); n++ ){ get_buff_2[n]='\0'; } PORT4.PODR.BIT.B0^=1; break; case ENTER_KEY: string_num = receve_data_num; receve_data_num=0; for( n=0; n<=sizeof(get_buff_2); n++ ){ get_buff_2[n]='\0'; } for( n=0; n<string_num-1 ; n++ ){ get_buff_2[n]=get_buff_m[n]; } get_buff_2[string_num]='\0'; for(n=0 ;n<sizeof(get_buff_m) ;n++){ get_buff_m[n]='\0'; } PORT4.PODR.BIT.B4^=1; break; } }//intprg.cで呼び出す void int_scr1_eri1(void){ int er=1; if(SCI.SSR.BIT.PER == 1){ SCI.SSR.BIT.PER=0;///パリティエラーフラグ er= 2; } if(SCI.SSR.BIT.FER == 1){ SCI.SSR.BIT.FER=0;///フレームエラーフラグ er= 3; } if(SCI.SSR.BIT.ORER == 1){ SCI.SSR.BIT.ORER=0;//オーバランエラーフラグ er = 4; } sci1_error =er; } void sci1_putc(unsigned char c){ SCI1.SCR.BIT.TIE =1; SCI1.SCR.BIT.TE =1; //送信開始 trans_buff =c; } void sci1_puts(unsigned char* c){ int i; if(TEND != 1)return; PORT2.PMR.BIT.B6 = 1; for(i=0; (*(c+i)!='\0')&&(sizeof(trans_b)>=i);i++) trans_b[i]=(*(c+i)); sci1_putc(*c); } void sci1_put(unsigned char* c,int n){ int i; if(TEND != 1)return; PORT2.PMR.BIT.B6 = 1; for(i=0; i<=n-1;i++) trans_b[i]=(*(c+i)); sci1_putc(*c); } int sci1_get( volatile unsigned char* p){ int n ; for( n=0 ; (get_buff_2[n]!='\0')&&(n<=sizeof(get_buff_2)); n++){ *(p+n) = get_buff_2[n]; } return 0; }
以下のように使えばPCと通信ができる. ただし,送信の間隔が狭すぎて前回の送信動作中にもう一度送信しようとすると後者は無視するようにしてあるので,一定周期割り込みの中で送信する等をすると安定して送信できる.
unsigned char send_data[100]; sprintf((char*)send_data,"DUTY=:%4d ANGLE:%4d PTM:%d\r",duty,SERVO_TGR,PTM_DATA); // send_dataに””内の文字列を代入,PTM_DATAを sci1_puts(send_data); // send_dataをSCI1から出力