/***************************************************************** CAT_CI-V monitor By JA3OOK 中村 利和 v1.0 2017/8     ・CATコマンドやCI-Vコマンドをモニターする。       CAT  ;まで、または先頭から26バイトまでをモニター       CI-V 0xFEから0xFDまで、または13バイトまでをモニタ     ・コマンドには時刻マーキングを付けてLCDに表示し、同時に一時メモリーに記憶する。       記憶されたコマンドは電源を切ると消える。       時刻マーキングとは:本モニターの起動開始からの秒数(0.1秒きざみ)であって            最長 999.9秒まで表示し、超えると 0000.0秒に戻りカウントされる。            sleepingt中は時刻マーキングはアップしない。     ・記憶できるコマンド件数は Data SRAM 容量に依存する。       記憶できる件数を超えると古いコマンドに上書きされ、常に最新のn件が記憶される。           ・プログラムは二つのモードで動作し、両モードは赤ボタンの長押しで切り替える。        Monitorモード(モニターし一時メモリーに記憶するモード)        Replayモード(記憶されたコマンドをLCDに繰り返し表示できるモード)     ・記憶されたコマンドはReplayモードにおいて、赤ボタンと白ボタンで時刻順、      および逆時刻順に表示できる ------------------------------------------------------------------ 開発環境 MPLAB X IDE MPLAB XC8 C Compiler Free mode ******************************************************************/ // refer \c:Program Files(x86)\Microchip\xc8\v1.40\docs\chips\16f1619.html #pragma config BOREN = OFF //Brown-out Reset enable #pragma config WRT =OFF //Write protection off #pragma config FOSC = INTOSC //INTOSC oscillator: I/O function on CLKIN pin #pragma config PLLEN =OFF //4x PLL is enabled when software sets the SPLLEN bit #pragma config MCLRE =OFF //MCLR disabled #pragma config WDTE =OFF //WDT disabled #pragma config CP =ON //Code protection on #pragma config LVP =OFF //High-voltage on MCLR/VPP must be used for programming #pragma config PWRTE =OFF //Power-up Timer Enable #pragma config IESO =OFF //Internal External Switchover mode disabled #pragma config FCMEN =OFF //Fail-Safe Clock Monitor disabled #include "pic16f1619.h" //#include //#include #include #include "lcd.h" #define MHz 000000 #define _XTAL_FREQ 8MHz //PIC_OSC_FREQ // Version and author #define ver " v1.0 " #define author "JA3OOK " //入力ポートは Rxx を記述 出力ポートは LATxx を記述 #define PUSHSW_WHITE RA5 #define PUSHSW_RED RA4 #define slideSW RA3 // スライドスイッチ #define LCD_VDD LATC0 // VDD of LCD #define redButton_pull_up WPUA4=1 // 赤ボタン pull-up #define redButton_NOpull_up WPUA4=0 // 赤ボタン no_pull-up #define whtButton_pull_up WPUA5=1 // 白ボタン pull-up #define whtButton_NOpull_up WPUA5=0 // 白ボタン no_pull-up #define RX_pull_up WPUC4=1 // RX-PORT pull-up #define RX_NOpull_up WPUC4=0 // RX-PORT no_pull-up #define sec_to_sleep 120 //Sleepまでの秒数 //#define sec_to_sleep 15 //Sleepまでの秒数 debug #define in2ChStr_tbl_max 26 //最大記録データ数 //#define in2ChStr_tbl_max 3 //最大記録データ数 debug unsigned char seq_no[] //コマンド表示番号への変換table = " 123456789abcdefghijklmnopq"; #define in2ChStr_max 26 //POST記号の ; や xFD を含めた最長モニターバイト数 unsigned char in2ChStr[in2ChStr_max]; //受け取ったコマンド文字列 unsigned int sec_tbl[in2ChStr_tbl_max]; unsigned char ddd_tbl[in2ChStr_tbl_max]; unsigned char in2ChStr_tbl[in2ChStr_tbl_max][in2ChStr_max]; signed char in2ChStr_tbl_bgn; //record/read table begin item pos. signed char in2ChStr_tbl_cur; //record/read table current item pos. signed char in2ChStr_tbl_sav; //record/read table current item pos. unsigned int t1count ; // タイマー設定値 unsigned int tm1_count ; // タイマーの割込み発生回数をカウントする変数 unsigned int sec_to_sleep_count ;// 1秒ごとにカウント unsigned int sendCIV_flag ; // sendCIV unsigned int count_sec ; // 経過秒数 unsigned char count_ddd ; // 経過秒数 0.2秒単位 unsigned char in2ChStr_max_civ ;// in2ChStr_max の半分の値 unsigned int timer; //タイマー用(符号無し16ビット長) bit civ_or_cat; // 1:CI-V 0:CAT bit mode; // 0:Monitor mode 1:Replay mode bit tbl_cycle_use; // nChStr2_tbl_max を超えてモニター中 bit in2end; //1:コマンド終了記号を受信した 0:コマンド終了記号を未だ受信していない bit through_to_semicolon;//1:バイト受信しても無視 0:バイト処理必要 bit sw1_state; bit sw2_state; bit sec_flag; unsigned char in2Ch; //受け取った文字 unsigned char in2cmd_buffloc; //コマンド中の文字の位置(0から始まる) unsigned char in2cmd_tbl_byteloc; //コマンド中の文字の位置(0から始まる) //ICOM TRCVER機種コード既定値 // IC-PW1 : 0x54 T // IC-7410 : 0x80 // IC-756PRO : 0x5C \ // PC : 0xE0 // (IC-780 : 0x26 使用しないほうがよさそう) //CI-V形式 周波数データ転送コマンド // {0xFE,0xFE,0x22,0x33,0x00,0x56,0x34,0x12,0x14,0x00,0xFD}; // pre pre To frm CMD 拾壱 千百 拾万万 拾壱M 千百M post // 0 1 2 3 4 5 6 7 8 9 10 // CMD // 00:周波数データの設定(トランシーブ) // 03:表示周波数の読み込み // 05:周波数データの設定 unsigned int tim1; //for Push SW unsigned int tim2; //for Push SW unsigned char i; unsigned char j; unsigned char str[21]; //temporary work unsigned char hexch_tbl[] ="0123456789ABCDEF"; void //intやchar正数をASCII文字に変換し*bufferに格納されるので文字として送信したり液晶に表示できる Bin2str(unsigned int data, char *buffer, unsigned int digit) { // 引数:intやchar正数データ, 文字データ, 期待する文字データの文字数 char i; buffer += digit; // 最後の数字位置 += : Buffer=Buffer+digit *buffer = 0; // 文字列終端(文字数+1の位置)へ0X00 for(i=digit; i>0; i--) { // 変換は下位から上位へ buffer--; // ポインター1 *buffer = (data % 10) + 0x30;// ASCIIへ  % : 割り算の余り data = data / 10; // 次の桁へ } } void //int正数を16進のASCII文字に変換しstrに格納されるので文字として送信したり液晶に表示できる DispHex(unsigned int j){ char i; i = j >> 12; str[0] = hexch_tbl[i]; //上位4bit表示 max:03FF i = (j >> 8) & 0x000F; str[1] = hexch_tbl[i]; //下位4bit表示 max:03FF i = (j >> 4) & 0x000F; str[2] = hexch_tbl[i]; //上位4bit表示 max:03FF i = j & 0x000F; str[3] = hexch_tbl[i]; //下位4bit表示 max:03FF str[4] = 0; //set NULL } void // unsigned charを16進表示に変換しstrに格納されるので液晶に表示できる Char2hex(unsigned char cha){ unsigned char temp_ch; //local 汎用char temp_ch = (cha >> 4) & 0x000F; str[0] = hexch_tbl[temp_ch]; //上位4bit表示 max:03FF temp_ch = cha & 0x000F; str[1] = hexch_tbl[temp_ch]; //下位4bit表示 max:03FF str[2] = 0; //set NULL 0x00 } void interrupt InterTimer( void ){ // タイマー割込み if(TMR1IF == 1) { // タイマー1の割込み発生か? TMR1H = (t1count >> 8); // タイマーの初期化 TMR1L = (t1count & 0x00FF) ; // タイマーの初期化 TMR1IF = 0 ; // タイマー割込フラグをリセット tm1_count++ ; // 割込み発生回数をカウント if(tm1_count >= 10){ //割り込み10回で1秒 count_sec++; // タイムスタンプ(秒)生成 sec_flag = 1; tm1_count = 0; if(!mode){ // Monitor mode Lcd_goto(0x4D); Bin2str(count_sec, str, 3); Lcd_puts(str); } } count_ddd = count_ddd + 1 ; // タイムスタンプ(0.1秒ごと)生成 if(count_ddd == ':'){ // ':' は 0x3A count_ddd = '0' ; } } if(RCIF) { // 受信割込み発生か? // if(WUE){ // in2Ch = RCREG; // } if(FERR){ //Framingエラーがあった場合 // Lcd_goto(0x00); Lcd_puts("RCV2 FERR "); //bebug in2Ch = RCREG; CREN = 0; //OFF in2Ch = '?'; //ダミーデータ CREN = 1; //1命令以上実行後にON } else if(OERR){ //Overrunエラーがあった場合の処理 // Lcd_goto(0x00); Lcd_puts("RCV2 OERR "); //debug in2Ch = RCREG; CREN = 0; //OFF in2Ch = '?'; //ダミーデータ CREN = 1; //1命令以上実行後にON } else { in2Ch = RCREG; } RCREG = 0; //受信バッファをクリア // RCIF = 0; //RCxIFビットはプログラムでクリアしてはいけない(read only)Data Sheet:324ページ //RCREGxが読まれた時にクリアされる if(in2cmd_buffloc < in2ChStr_max){ //入るだけ貯める in2ChStr[in2cmd_buffloc] = in2Ch; in2cmd_buffloc ++; } if(civ_or_cat){ // CI-V if(in2Ch == 0xFD){ //コマンドの終了文字 xFD in2end = 1; } }else{ // CAT if(in2Ch == ';'){ //コマンドの終了文字;semicolon in2end = 1; } } } /* if(IOCAF5 || IOCAF4 || IOCAF3) {// 変化割込み発生か? IOCAF5 = 0; IOCAF4 = 0; IOCAF3 = 0; IOCIE = 0; } */ // if(IOCAF) {// どれかのピンの変化割込み発生か? // if(IOCAF || IOCCF) {// どれかのピンの変化割込み発生か? if(IOCIF) {// どれかのピンの変化割込み発生か? IOCAF = 0; IOCBF = 0; IOCCF = 0; // IOCIE = 0; } } void InitEUSART2(){ //初期設定 //TX1STA:Transmit Status and Control PIC16F1619 Data Sheet:329Page TX9 = 0; //Selects 8-bit transmission SYNC = 0; //非同期モードを選択 TXEN = 0; //送信を有効にする //RC1STA: RECEIVE STATUS AND CONTROL REGISTER PIC16F1619 Data Sheet:330Page SPEN = 1; //シリアルポートを有効にする RX9 = 0; //Selects 8-bit reception CREN = 1; //連続受信を可能にする //通信速度の指定 9600bps PIC16F1619 Data Sheet:334Page BRGH = 0; BRG16 = 0; SPBRG = 12; } void Eusart2_OutCh(char outChar){ //一文字送信 while(!TRMT); //送信可能になるまで待つ TXREG = outChar; //送信するためにデータを格納 } void Put_civcmd_freq(const char * s){ // 11文字送信 int i; for(i=0; i<=10; i++){ Eusart2_OutCh(*s++); } } void Init_data_of_recv(){ // EUSART2 一コマンド受信に関するデータ初期化 in2cmd_buffloc = 0; // コマンドの先頭文字(1文字目) in2end = 0; mode = 0; // 0:Monitor mode through_to_semicolon = 0; } void Disp_1data(){ // LCDへ表示 Lcd_clear(); __delay_ms(50); //0.05s Lcd_goto(0x00); Bin2str(sec_tbl[in2ChStr_tbl_cur], str, 3); Lcd_puts(str); Lcd_putch('.'); Lcd_putch(ddd_tbl[in2ChStr_tbl_cur]); if(mode){ //Replay mode Lcd_putch(seq_no[i]); }else{ Lcd_putch(' '); } if(civ_or_cat){//CI-V for(in2cmd_tbl_byteloc=0; in2cmd_tbl_byteloc < in2ChStr_max_civ; in2cmd_tbl_byteloc++){ if(in2cmd_tbl_byteloc == 5){ Lcd_goto(0x40); } Char2hex(in2ChStr_tbl[in2ChStr_tbl_cur][in2cmd_tbl_byteloc]); Lcd_puts(str); if(in2ChStr_tbl[in2ChStr_tbl_cur][in2cmd_tbl_byteloc] == 0xFD){ break; } } }else{//CAT for(in2cmd_tbl_byteloc=0; in2cmd_tbl_byteloc < in2ChStr_max; in2cmd_tbl_byteloc++){ if(in2cmd_tbl_byteloc == 10){ Lcd_goto(0x40); } Lcd_putch(in2ChStr_tbl[in2ChStr_tbl_cur][in2cmd_tbl_byteloc]); if(in2ChStr_tbl[in2ChStr_tbl_cur][in2cmd_tbl_byteloc] == ';'){ break; } } } if(mode){ //Replay mode Lcd_goto(0x05); Lcd_write(0b00001101); //Display On, blink of character } } void Analize_msg(void){ Init_data_of_recv(); in2ChStr_max_civ = in2ChStr_max / 2; in2ChStr_tbl_bgn = -1; // in2ChStr_tbl_cur = -1; // in2ChStr_tbl_sav = -1; // tbl_cycle_use = 0; count_sec = 0; // 経過秒数 count_ddd ='0'; // 経過秒数 0.1秒単位 sw1_state = 0; sw2_state = 0; tim1 = 0; tim2 = 0; sec_flag = 0; sec_to_sleep_count = 0; while(1){ //無限loop //コマンドの記録と表示 if(mode == 0 && in2end){// Monitor mode かつ 文字列受信終了 sec_to_sleep_count = 0; in2ChStr_tbl_cur++; if(in2ChStr_tbl_cur >= in2ChStr_tbl_max){ tbl_cycle_use = 1; in2ChStr_tbl_cur = 0; } if(tbl_cycle_use){ in2ChStr_tbl_bgn++; if(in2ChStr_tbl_bgn >= in2ChStr_tbl_max){ in2ChStr_tbl_bgn = 0; } } else{ in2ChStr_tbl_bgn = 0; } sec_tbl[in2ChStr_tbl_cur] = count_sec; ddd_tbl[in2ChStr_tbl_cur] = count_ddd; for(in2cmd_tbl_byteloc=0; in2cmd_tbl_byteloc < in2ChStr_max; in2cmd_tbl_byteloc ++){ in2ChStr_tbl[in2ChStr_tbl_cur][in2cmd_tbl_byteloc] = in2ChStr[in2cmd_tbl_byteloc]; } Disp_1data(); in2cmd_buffloc = 0; in2end = 0; sec_to_sleep_count = 0; } whtButton_pull_up; if(PUSHSW_WHITE == 0) { //push 白 sw1 whtButton_NOpull_up; sw1_state = 1; __delay_ms(200); sec_to_sleep_count = 0; tim1++; whtButton_pull_up; } whtButton_NOpull_up; if(tim1 > 5) { // 白 長押し SW1 sw1_state = 0; tim1 = 0; //ここから白長押しAP処理 sec_to_sleep_count = 0; //ここまで白長押しAP処理 } whtButton_pull_up; if(PUSHSW_WHITE && sw1_state && mode == 1) { // 白 短押し SW1 かつ  Replay mode sw1_state = 0; tim1 = 0; //ここから白短押しAP処理 if(in2ChStr_tbl_bgn < 0){ Lcd_goto(0x00); Lcd_puts("No data"); } else{ if(in2ChStr_tbl_bgn <= in2ChStr_tbl_sav){ // No tbl_cycle_use in2ChStr_tbl_cur --; if(in2ChStr_tbl_cur < in2ChStr_tbl_bgn){ in2ChStr_tbl_cur = in2ChStr_tbl_sav; } i --; if(i < 1){ i = j; } Disp_1data(); } else{ // tbl_cycle_use in2ChStr_tbl_cur --; if(in2ChStr_tbl_cur < 0){ in2ChStr_tbl_cur = in2ChStr_tbl_max - 1; } i --; if(i < 1){ i = j; } Disp_1data(); } } sec_to_sleep_count = 0; //ここまで白短押しAP処理 } whtButton_NOpull_up; redButton_pull_up; //PUSHSW_RED pull-up if(PUSHSW_RED == 0) { //push 赤 SW2 redButton_NOpull_up; //PUSHSW_RED no pull-up sw2_state = 1; __delay_ms(200); tim2++; sec_to_sleep_count = 0; redButton_pull_up; //PUSHSW_RED pull-up } redButton_NOpull_up; //PUSHSW_RED no pull-up if(tim2 > 5) { //  赤 長押し 1秒 SW2 sw2_state = 0; tim2 = 0; //ここから赤長押しAP処理 if(mode == 1){ //現在Replay mode なので Monitor mode へ遷る Lcd_write(0b00001100); //Display on, no cursor, no blinking Lcd_clear(); Lcd_goto(0x00); //LCDの表示位置を一行目左端 if (civ_or_cat) { Lcd_puts("CI-V Monitor "); }else { Lcd_puts("CAT Monitor "); } mode = 0; //Monitor mode Init_data_of_recv(); in2ChStr_tbl_cur = in2ChStr_tbl_sav; __delay_ms(1000); //Wait if(in2ChStr_tbl_cur >= 0){ Disp_1data(); } } else{ //現在Monitor mode なので Replay mode へ遷る in2ChStr_tbl_sav = in2ChStr_tbl_cur; in2ChStr_tbl_cur = in2ChStr_tbl_bgn; i = 1; //Data's No Lcd_clear(); Lcd_goto(0x00); //LCDの表示位置を一行目左端 Lcd_puts("Replay"); //LCDにメッセージを表示 Lcd_goto(0x40); //LCDの表示位置を一行目左端 Lcd_puts("Data count="); //LCDにメッセージを表示 if(in2ChStr_tbl_bgn < 0){ j = 0; } else{ if(tbl_cycle_use){ // tbl_cycle_use j = in2ChStr_tbl_max; }else{ // No tbl_cycle j = in2ChStr_tbl_sav - in2ChStr_tbl_bgn +1; } } Bin2str(j, str, 2) ; Lcd_puts(str); // 記録されているコマンド件数を表示 mode = 1; //Replay mode timer = 1; while(timer--){__delay_ms(1000);}; //Wait } sec_to_sleep_count = 0; //ここまで赤長押しAP処理 } redButton_pull_up; //PUSHSW_RED pull-up if(PUSHSW_RED && sw2_state && mode == 1) { // 赤 短押し かつ  Replay mode sw2_state =0; tim2 = 0; //ここから赤短押しAP処理 if(in2ChStr_tbl_bgn < 0){ Lcd_goto(0x00); Lcd_puts("No data"); } else{ if(in2ChStr_tbl_bgn <= in2ChStr_tbl_sav){ // No tbl_cycle_use Disp_1data(); in2ChStr_tbl_cur ++; if(in2ChStr_tbl_cur > in2ChStr_tbl_sav){ in2ChStr_tbl_cur = in2ChStr_tbl_bgn; } } else{ // tbl_cycle_use Disp_1data(); in2ChStr_tbl_cur ++; if(in2ChStr_tbl_cur >= in2ChStr_tbl_max){ in2ChStr_tbl_cur = 0; } } i ++; if(i > j){ i = 1; } } sec_to_sleep_count = 0; //ここまで赤短押しAP処理 } redButton_NOpull_up; //PUSHSW_RED no pull-up if(sec_flag){ sec_flag = 0; sec_to_sleep_count ++ ; if(sec_to_sleep_count > sec_to_sleep){ sec_to_sleep_count = 0 ; RX_NOpull_up; // RX-PORT=TR2-コレクター no pull-up Lcd_off() ; // LCD control all PORTs 0 before VDD off LCD_VDD= 0; // LCD control VDD off LCD_off()の直後にVDDをOFFにしないと電気の消費が莫大 whtButton_pull_up; //白ボタン pull-up redButton_pull_up; //赤ボタン pull-up TMR1ON = 0; // WUE = 1; //ON にすると着信なくても wake-upしてしまう! SLEEP(); NOP(); RX_pull_up; // RX-PORT=TR2コレクター pull-up LCD_VDD = 1; __delay_ms(40); //低電圧でも動作させたいので長めを設定 Lcd_init(); Lcd_clear(); Lcd_write(0b00001100); //Display on, no cursor, no blinking whtButton_NOpull_up; //白ボタン no pull-up redButton_NOpull_up; //赤ボタン no pull-up if (civ_or_cat) { Lcd_puts("CI-V Monitor "); }else { Lcd_puts("CAT Monitor "); } __delay_ms(1000); //Wait if(in2ChStr_tbl_cur >= 0){ Disp_1data(); } TMR1ON = 1; } } } } void main(void){ OSCCON = 0b01110010 ;//internal OSC 8Mz OPTION_REG = 0b00000000; //PORT pull-up enabled // LCDのVDDをONする前は、LCDへのすべてのポートはlowであること。 ANSELA= 0b00000000; //All デジタル(既定値:アナログ) TRISA = 0b00111000; // RA5白ボタン、RA4赤ボタン、RA3スライドSW PORTA = 0b00001000; // RA3スライドSW ON WPUA = 0b00001000; // RA3スライドSW pull-up ANSELB= 0b00000000; //All デジタル(既定値:アナログ) TRISB = 0b00000000; // PORTB = 0b00000000; //初期化 ANSELC= 0b00000000; //All デジタル(既定値:アナログ) TRISC = 0b00010000; //USART-RX:RC4 PORTC = 0b00010000; // WPUC = 0b00010000; //RC4=RX EUSARTをInitializeする前にpull-upしておくこと RXPPS = 0b00010100; //USART-RX:RC4 (see Data sheet P182,P180) RC3PPS= 0b00010010; //RC3:USART-TX (see Data sheet P180,P183) T1CON = 0b00110001; // instruction clock (FOSC/4)でTIMER1を使用、プリスケーラカウント値 1:8 t1count = -25000; // タイマー1用カウントの初期値 //t1count:25000の場合 割込間隔0.100sec = (1/8000000μs*4*8*25000) // (Fosc=8MHz Prescale=8 において) TMR1H = (t1count >> 8); // タイマーの初期化 TMR1L = (t1count & 0x00FF) ; // タイマーの初期化 TMR1IF = 0 ; // タイマー0割込フラグを0 tm1_count = 0 ; // 割込み発生の回数カウンターを0 InitEUSART2(); //EUSART2 初期設定 これより前に RX-PORTをPULL-UPしておくこと //LCD initialize and cleare // LCDのVDDをONする前は、LCDへのすべてのポートはlowであること。 LCD_VDD = 1; __delay_ms(40); //低電圧でも動作させたいので長めを設定 Lcd_init(); Lcd_clear(); Lcd_write(0b00001100); //Display on, no cursor, no blinking Lcd_goto(0x00); //LCDの表示位置を一行目左端 if (slideSW) { Lcd_puts("CI-V Monitor "); civ_or_cat = 1; }else { Lcd_puts("CAT Monitor "); civ_or_cat = 0; WPUA3 = 0; //CATの場合:slideSW no pull-up CI-Vの場合:pull-upのまま(この方がsleep時も省電力) } Lcd_goto(0x40); //LCDの表示位置を二行目左端 Lcd_puts(ver); //LCDにメッセージを表示 Lcd_puts(author); //LCDにメッセージを表示 IOCAP4 = 1; // SW_port Positive Edge Enable. IOCAN4 = 1; // SW_port Negative Edge Enable. IOCAF4 = 0; // SW_port pin interuupt flag IOCAP5 = 1; // SW_port Positive Edge Enable. IOCAN5 = 1; // SW_port Negative Edge Enable. IOCAF5 = 0; // SW_port pin interuupt flag TMR1IE = 1 ; // タイマー1割込をマスクしない IOCIE = 1 ; // All PORT-pin change interrupt RCIE = 1 ; // 受信割り込みをマスクしない PEIE = 1 ; // 周辺割込みをマスクしない GIE = 1 ; // 全割込み処理をマスクしない Analize_msg(); }