//usartmonitor18F46K22X.c by PIC18F46K22 窓防犯システムのテストボード用。
//
//UART1/2 外部OSC 9.8304MHZ 4逓倍で39.3216MHZ
//
//FRAM(MB85R256F/FM28V020)への書込み、読み出し及びRTC(RTC-7301DG)からの読み出し、書込み
//液晶用モジュール<lcd_lib_18F46K22.c>
//key 入力
//
//  create 2015.3.23
//  update 2017.7.13
//  update 2017.7.27
//  update 2017.8.2時刻設定
//
//#include <stdlib.h>
#include <18f46K22.h>    //*
#fuses HSH,PLLEN,PRIMARY_ON,NOFCMEN,NOIESO,PUT,NOBROWNOUT,WDT512,NOPBADEN,MCLR,NOLVP,NODEBUG,NOPROTECT// クロックの4逓倍のためPLLEN
//NOWDTはプログラム中でWDTを使用する場合ここではNO指定が必要。NOIESOも同様か？
#use delay(CLOCK =  39321600)                            //クロック周波数指定。setup_oscillatorと一致させること。
#use rs232(BAUD = 9600, XMIT = PIN_C6, RCV = PIN_C7, STREAM=usart1)
#use rs232(BAUD = 9600, XMIT = PIN_D6, RCV = PIN_D7, STREAM=usart2) //PCからは2byteを送信。最初の1byteはリード、r(0x72)又はライト、w(0x77)
                                                                    //次の1byte中、上位4ビットはaddress、下位4ビットはデータ
#use fast_io(A)
#use fast_io(B)
#use fast_io(C)
#use fast_io(D)
#use fast_io(E)
//ポートのio指定は以下で行うこと。
#define mode       0b10000000//
//RA0   :out LCD data DB4
//RA1   :out LCD data DB5
//RA2   :out LCD data DB6
//RA3   :out LCD data DB7
//RA4   :out LCD E
//RA5   :out LCD RS
//RA6   :out osc1
//RA7   :in  osc1
#define input_x         input_A         //ポートA使用
#define output_x        output_A
#define set_tris_x      set_tris_A//
#define stb             PIN_A4//　
#define rs              PIN_A5//
#include  <lcd_lib_18F46K22.c>//この位置に記述しないとコンパイルエラーとなる。
//
#define port_b_o        0b00000000//出力モード
#define port_b_i        0b11111111//入力モード
//RB0   :i/o データ
//RB1   :i/o データ
//RB2   :i/o データ
//RB3   :i/o データ
//RB4   :i/o データ
//RB5   :i/o データ
//RB6   :i/o データ
//RB7   :i/o データ
//
#define port_c_io       0b10000000//
//RC0   :out アドレス by  RTC
//RC1   :out アドレス by  RTC
//RC2   :out アドレス by  RTC
//RC3   :out アドレス by  RTC
//RC4   :out _OE by FRAM
//RC5   :out _WE by FRAM
//RC6   :out TX1.usart1
//RC7   :in  RX1.usart1
#define   out_oe      PIN_C4
#define   out_we      PIN_C5
//
#define port_d_io       0b10000000//
//RD0   :out
//RD1   :out
//RD2   :out _CE RTC
//RD3   :out _CE FRAM
//RD4   :out _CCLR by 74HC590A内部カウンタ.low active.
//RD5   :out FRAM アドレス　カウントアップ　クロック(立上がり)
//RD6   :out TX1.usart2
//RD7   :in  RX1.usart2
#define   out_led2     PIN_D0
#define   out_led      PIN_D1
#define   out_ce_rtc   PIN_D2
#define   out_ce_fram  PIN_D3
#define   out_cclr     PIN_D4
#define   out_cclk     PIN_D5
//
#define port_e_io       0b1111//
//RE0   :in key data 2^0
//RE1   :in key data 2^1
//RE2   :in stb 立上がり
//RE3   :in  MCKR
#define   in_stb       PIN_E2
//////
#define timer0_interval 0xB500  //0.5秒=( (1/clock= 39.3216MHZ)×4×256×19200 )。2^16-19200=46336(B500)からスタートしてオーバーフローさせて割込0を使用。
#define timer1_interval 0xF8CC  //1.5ms=( (1/clock= 39.3216MHZ)×4×8×1844 )。2^16-1844=63692(F8CC)からスタートしてオーバーフローさせて割込1を使用。
////// その他
static int1     timer0_500ms = 0;       //0.5秒毎に1となるフラグ。
static int1     timer1_1R5ms = 0;       //1.5ms毎に1となるフラグ。
static int      result;//
static int1     time_stamp;             //
static int1     int_0 = 0;              //外部割込0フラグ
static int1     int_usart1;             //USART1外部割込フラグ
static int1     int_usart2;             //USART2外部割込フラグ
static int      r1;
static int      idx;
static int      cnt;
static int      time[6];//yy,mm,dd,hh,mm,ss。yyは4bit十の位のy+4bit一の位のy。yyが[0]。FRAMに書き込まれる日時データでHEX表示で見た値が10進の値と一致するため。
static long     address_L;//74HC590Aで作り出す15bitアドレスデータ
static int1     wr;//RTC7301へのwriteが0、readが1。
static int      ad;
static int      d1;
static int      rtc_data1[9] ={0xf6,0xe0,0xbc,0xdb,0xc0,0xfa,0x10,0x80,0xf2};//全電源が消失後の初期設定値。アドレス4bit+データ4bit
static int      rtc_data2[15]={0xe2,0xd0,0xc1,0xb5,0xa0,0x93,0x80,0x78,0x51,0x47,0x30,0x24,0x13,0x09,0xf1};//2015年03月08日17時04分39秒
static int1     busy;
static int1     skip_sw;
static int      cursor1;//0x80-0xa7　1行目と3行目が連続した40桁
static int      cursor2;//0xc0-0xe7　2行目と4行目が連続した40桁
static int1     bef_stb;//キーエンコーダからの立上がりストローブ（割込み）信号
static int      key;//キーデータ0から3。
static int      dsp_num;//画面番号。0は2chシリアルデータ表示画面、1はFRAMのアドレスカウント数及び時刻の表示/更新、2はFRAM読み出し、3は時刻変更
static int      cur_point;//0x97,0x9a,0x9d,0xa0,0xa3,0xa6　時刻設定する際の3行目のカーソルの位置
static int      time_point;//0,1,2,3,4,5　time[]とset_time[]の指標でyyから順にssまで。
static int      set_time[6];//yy,mm,dd,hh,mm,ss。yyは1byte。時刻セット時に使用する日時データで、10進数。
static int      receive_cnt;//時刻設定シリアルデータの受信用、rtc_data2[]の指標。
static int      send_cnt;//時刻設定シリアルデータの送信用、rtc_data2[]の指標。
static int      div_syo;//割り算の商
static int      div_amari;//割り算の余り
static int1     send_sw;//時刻設定データをシリアルで送出するときは1。
static int      hi_adrs[2];//FRAMリード時の範囲設定で使用する上位7ビットデータの4ビット＋4ビットデータ。上位が[0]、下位が[1]
static long     dsp_address_L;//74HC590Aで作り出す15bitアドレスデータ
static int      adrs_point;// hi_adrs[]の指標。0又は1で上位が[0]、下位が[1]
static long     cnt_L;
//
void dsp_opening(void);//LCD初期化
void rtc_read(void);//RTC時刻データリード
void dsp_ctrl(void);//LCD
void dsp_num0(void);//LCD 2chシリアルデータ表示画面。全てブランク
void dsp_num1(void);//LCD FRAMのアドレスカウント数及び時刻の表示/更新
void dsp_num2(void);//LCD FRAM読み出し
void dsp_num3(void);//LCD 時刻設定
void rtc_set(void);//
void send_serial(void);//
void fram_erase(void);//FRAM消去
//
////////////////////////////////////////////////////////////////////
////// タイマー0割り込み0.5秒毎
////////////////////////////////////////////////////////////////////
#INT_TIMER0
void intval1()
    {
        set_timer0(timer0_interval);
        output_toggle(out_led);
        timer0_500ms = 1;
    }
////////////////////////////////////////////////////////////////////
////// タイマー1割り込み1.5ms毎
////////////////////////////////////////////////////////////////////
#INT_TIMER1
void intval2()
    {
        set_timer1(timer1_interval);
        timer1_1R5ms = 1;
    }
////////////////////////////////////////////////////////////////////
/////// 外部割り込み0
////////////////////////////////////////////////////////////////////
#INT_EXT
void intval3()
    {
        int_0 = 1;
    }
////////////////////////////////////////////////////////////////////
/////// USART1外部割込み　usart1が1byte受信したら、フラグを立てる
////////////////////////////////////////////////////////////////////
#INT_RDA
void intval4()
    {
        int_usart1 = 1;
        result = fgetc(usart1);//0d(\r)
        clear_interrupt(INT_RDA);
    }
////////////////////////////////////////////////////////////////////
/////// USART2外部割込み　usart2が1byte受信したら、フラグを立てる
////////////////////////////////////////////////////////////////////
#INT_RDA2
void intval5()
    {
        int_usart2 = 1;
        result = fgetc(usart2);//0d(\r)
        clear_interrupt(INT_RDA2);
    }
//
////////////////////////
void  main() {
    setup_oscillator(OSC_NORMAL);   //外部発振子
    set_tris_E(port_e_io);
    set_tris_D(port_d_io);
    output_high(out_ce_rtc);//RTC初期値
    output_high(out_ce_fram);//FRAM初期値
    set_tris_C(port_c_io);
    output_high(out_we);//FRAM初期値
    output_high(out_oe);//FRAM初期値
    set_tris_B(port_b_i);
    dsp_opening();//Aポートの設定も行う。
    setup_adc_ports(NO_ANALOGS);
//
    output_low(out_cclk);//カウンタ初期値
    int_usart1 = 0;
    int_usart2 = 0;
//
    output_low(out_led2);
    output_high(out_led);
    delay_ms(200);
    output_low(out_led);
    delay_ms(200);
    restart_wdt();
    output_high(out_led);
    delay_ms(200);
    output_low(out_led);
//
    //ext_int_edge( L_TO_H );             //RB0/INT立ち上がり
//
    setup_timer_0(T0_INTERNAL | T0_DIV_256 );//内部クロック(Fosc/4、プリスケラー1/256、16bitレジスタ(記述無し)タイマー0の0.5s間隔用。
    //setup_timer_0(RTCC_INTERNAL | RTCC_DIV_256 );//内部クロック(Fosc/4、プリスケラー1/256、16bitレジスタ(記述無し)タイマー0の0.5s間隔用。旧記述法
    setup_timer_1( T1_INTERNAL | T1_DIV_BY_8 );//内部クロック(Fosc/4、プリスケラー1/8、16bitレジスタ(記述無し)タイマー0の1.5ms間隔用。
//  未使用モジュールの停止
    setup_timer_2(T2_DISABLED,0,1); //未使用タイマーを止める
    setup_timer_3(T3_DISABLED);     //未使用タイマーを止める
    SETUP_CCP1(CCP_OFF);            //未使用モジュールを止める
    SETUP_CCP2(CCP_OFF);            //未使用モジュールを止める
    setup_adc(ADC_OFF);
//
//WDTテスト。foscクロック可変のテスト
    //SETUP_WDT(WDT_ON);              //WDTの開始(FUSEにて512倍=約2秒の指定有り)
//
    disable_interrupts(INT_EXT);//外部割り込み0許可
    disable_interrupts(INT_RDA);//UASRT1割り込み許可
    disable_interrupts(INT_RDA2);//UASRT2割り込み許可
    enable_interrupts(INT_TIMER0);//タイマー0許可
    enable_interrupts(INT_TIMER1);//タイマー0許可
    enable_interrupts(GLOBAL);//全割り込み許可
//
    clear_interrupt(INT_EXT);
    clear_interrupt(INT_RDA);
    clear_interrupt(INT_RDA2);
    clear_interrupt(INT_TIMER0);
    clear_interrupt(INT_TIMER1);
    int_0 = 0;
    idx = 0;
    cnt = 0;
    time_stamp = 1;
    skip_sw = 0;
    bef_stb = 0;
//
    set_timer0(timer0_interval);
    set_timer1(timer1_interval);
    timer0_500ms = 0;
    timer1_1R5ms = 0;
    lcd_clear();               //LCD全消
    output_low(out_cclr);//カウンタクリアの開始
    delay_ms(10);
    output_high(out_cclr);//カウンタクリアの完了
    delay_ms(10);
    //
//FRAMのリード↓
//  set_tris_B(port_b_i);
//  output_high(out_we);//FRAMリード
//  output_low(out_ce_fram);//チップセレクト開始
//  for (address_L=1;address_L < 0x1000; address_L = address_L + 1 )
//      {
//          output_high(out_cclk);//カウンタ↑
//          output_low(out_cclk); //カウンタ↓
//          delay_cycles(1);
//          output_low(out_oe);//FRAMリード
//          delay_cycles(1);
//          r1 = input_b();
//          output_high(out_oe);//FRAMリード
//          //fputc(r1,usart1);
//          //fprintf(usart1,"%c",r1);
//      }
//  output_high(out_ce_fram);//チップセレクト終了
//FRAMのリード↑
    //fprintf(usart1,"start");
    lcd_clear();               //LCD全消
    //1行目best
    lcd_cursor(0x80);
    printf(lcd_data,"Is FRAM erased?     ");
    //2行目
    lcd_cursor(0xc0);
    printf(lcd_data,"Yes=1or2or3         ");
    while ( input(in_stb) == 0 )//キー入力待ち
        {
            restart_wdt();
        }
    key = input_E() & 0b00000011;//下2bitのみが有効なデータをkeyへセット
    if  ( key > 0 )
        {
            fram_erase();
            delay_ms(200);
            restart_wdt();
            delay_ms(200);
            restart_wdt();
            delay_ms(200);
            restart_wdt();
        }
    lcd_clear();               //LCD全消
//
//RTC時刻初期設定と時刻設定
        output_low(out_ce_rtc);//
                                                //FOSビットの読み込み↓
                                //BANK指定のためのライト
        set_tris_B(port_b_o);//
        output_high(out_oe);//RTCライト
        output_c( 0x0F | (input_c() & 0xF0));//F番地アドレスセット
        output_b(0);//BANK=0、STOP=0、ADJ=0データのライト
        delay_cycles(1);
        output_low(out_we);//RTCライト
        delay_cycles(1);
        output_high(out_we);//RTCライト
                                 //FOSビットの読み込み
        set_tris_B(port_b_i);
        output_high(out_we);//RTCリード
        output_c( 0x01 | (input_c() & 0xF0));//1番地アドレスセット
        delay_cycles(1);
        output_low(out_oe);//RTCリード
        delay_cycles(1);
        d1 = input_b();
        output_high(out_oe);//RTCリード            //FOSビットの読み込み↑
        if ( bit_test(d1,3) == 1 )//FOSビット判定→バックアップ中の電圧低下ありで時刻データが不定の可能性
            {
                rtc_set();
            }
        output_high(out_ce_rtc);//
    //このタイミングでBANK0選択を維持
//
    cursor1 = 0x80;
    cursor2 = 0xc0;
    dsp_num = 0;
    address_L = 0;
    cur_point = 0;
    receive_cnt = 0;
    send_cnt = 0;
    send_sw = 0;
//
    while(True)//2017.7.13
        {
            //時刻データ送信
            if ( send_sw == 1 )
                {
                    //send_serial();           //2017.8.2交換
                    output_low(out_ce_rtc);     //2017.8.2交換
                    rtc_set();                 //2017.8.2交換
                    output_high(out_ce_rtc);    //2017.8.2交換
                }
            rtc_read();//
            //キー入力↓
            if ( input(in_stb) == 1 )
                {
                    if ( bef_stb == 0 )//立ち上がり
                        {
                            key = input_E() & 0b00000011;//下2bitのみが有効なデータをkeyへセット
                            dsp_ctrl();//
                            bef_stb = 1;
                        }
                 }
            else
                {
                    if ( bef_stb == 1 )//立ち下がり
                        {
                            bef_stb = 0;
                        }
                }
            //キー入力↑
            if ( timer1_1R5ms == 1 )//最後の受信から1.5ms経過したら時刻書込み。1.5msとは9600bpiで1byte分の1.5倍。
                {
                    timer1_1R5ms = 0;
                    if ( time_stamp == 0 )
                        {
                            //時刻書き出し
                            set_tris_B(port_b_o);
                            output_high(out_oe);//FRAMライト
                            output_low(out_ce_fram);//チップセレクト開始
                            for ( idx=0;idx < 6;idx = idx + 1 )
                                {
                                    output_b(time[idx]);//FRAMライト
                                    address_L = address_L + 1;//表示のためだけ
                                    output_high(out_cclk);//カウンタ↑
                                    output_low(out_cclk); //カウンタ↓
                                    delay_cycles(1);
                                    output_low(out_we);//FRAMライト
                                    delay_cycles(1);
                                    output_high(out_we);//FRAMライト
                                }
                            output_high(out_ce_fram);//チップセレクト終了
                            set_tris_B(port_b_i);
                            time_stamp = 1;
                        }
                }
            //
            if ( kbhit(usart1) == 1 )//usart1が受信したら
                {
                    //output_high(out_led);//+++++++++++++++
                    result= fgetc(usart1);
                    set_tris_B(port_b_o);
                    output_high(out_oe);//FRAMライト
                    output_low(out_ce_fram);//チップセレクト開始
                    //
                    set_timer1(timer1_interval);
                    time_stamp = 0;
                    output_b(0x20);//FRAM usart1指標のライト
                    address_L = address_L + 1;//表示のためだけ
                    output_high(out_cclk);//カウンタ↑
                    output_low(out_cclk); //カウンタ↓
                    delay_cycles(1);
                    output_low(out_we);//FRAMライト
                    delay_cycles(1);
                    output_high(out_we);//FRAMライト
                    //
                    output_b(result);//FRAMライト
                    address_L = address_L + 1;//表示のためだけ
                    output_high(out_cclk);//カウンタ↑
                    output_low(out_cclk); //カウンタ↓
                    delay_cycles(1);
                    output_low(out_we);//FRAMライト
                    delay_cycles(1);
                    output_high(out_we);//FRAMライト
                    //
                    output_high(out_ce_fram);//チップセレクト終了
                    set_tris_B(port_b_i);
                    //output_low(out_led);//+++++++++++++++
//
                    //output_high(out_led2);//+++++++++++++++
                    if  ( ( result >= 0x20 ) && ( result <= 0x7d ) )//キャラクタ文字
                        {
                            if ( cursor1 == 0xa7)//カーソルが40文字目だったら
                                {
                                    lcd_cursor(0xa7);
                                    printf(lcd_data,"%C",result);
                                    lcd_cursor(0x80);
                                    printf(lcd_data," ");//下の行へ戻って1文字空白
                                    cursor1 = 0x80;
                                }
                            else
                                {
                                    lcd_cursor(cursor1);
                                    printf(lcd_data,"%C ",result);//データの次の文字は空白
                                    cursor1 = cursor1 + 1;
                                }
                        }
                    else//キャラクタ文字以外は16進表記x○○
                        {
                            switch (cursor1)
                            {
                                case 0xa5://2行目に表示して下の行へ戻って空白表示
                                    lcd_cursor(0xa5);
                                    printf(lcd_data,"x%X",result);//x+データ2桁
                                    lcd_cursor(0x80);
                                    printf(lcd_data," ");
                                    cursor1 = 0x80;
                                    break;
                                case 0xa6://2行目に表示はせず空白で潰し、データは下の行へ戻って表示
                                    lcd_cursor(0xa6);
                                    printf(lcd_data,"  ");//2文字空白
                                    lcd_cursor(0x80);
                                    printf(lcd_data,"x%X ",result);//x+データ2桁+空白
                                    cursor1 = 0x83;
                                    break;
                                case 0xa7://2行目にはxだけ表示してデータは下の行へ戻って表示
                                    lcd_cursor(0xa7);
                                    printf(lcd_data,"x");
                                    lcd_cursor(0x80);
                                    printf(lcd_data,"%X ",result);//データ2桁+空白
                                    cursor1 = 0x82;
                                    break;
                                default:
                                    lcd_cursor(cursor1);
                                    printf(lcd_data,"x%X ",result);//x+データ2桁
                                    cursor1 = cursor1 + 3;
                                    break;
                            }
                        }
                    //output_low(out_led2);//+++++++++++++++
//
                }
//
            if ( ( kbhit(usart2) == 1 ) && ( dsp_num == 0 ) )//usart2が受信したら
                {
                    result= fgetc(usart2);
                    set_tris_B(port_b_o);
                    output_high(out_oe);//FRAMライト
                    output_low(out_ce_fram);//チップセレクト開始
                    //
                    set_timer1(timer1_interval);
                    time_stamp = 0;
                    output_b(0x21);//FRAM usart2指標のライト
                    address_L = address_L + 1;//表示のためだけ
                    output_high(out_cclk);//カウンタ↑
                    output_low(out_cclk); //カウンタ↓
                    delay_cycles(1);
                    output_low(out_we);//FRAMライト
                    delay_cycles(1);
                    output_high(out_we);//FRAMライト
                    //
                    output_b(result);//FRAMライト
                    address_L = address_L + 1;//表示のためだけ
                    output_high(out_cclk);//カウンタ↑
                    output_low(out_cclk); //カウンタ↓
                    delay_cycles(1);
                    output_low(out_we);//FRAMライト
                    delay_cycles(1);
                    output_high(out_we);//FRAMライト
                    //
                    output_high(out_ce_fram);//チップセレクト終了
                    set_tris_B(port_b_i);
//
                    if  ( ( result >= 0x20 ) && ( result <= 0x7d ) )//キャラクタ文字
                        {
                            if ( cursor2 == 0xe7)//カーソルが40文字目だったら
                                {
                                    lcd_cursor(0xe7);
                                    printf(lcd_data,"%C",result);
                                    lcd_cursor(0xc0);
                                    printf(lcd_data," ");//下の行へ戻って1文字空白
                                    cursor2 = 0xc0;
                                }
                            else
                                {
                                    lcd_cursor(cursor2);
                                    printf(lcd_data,"%C ",result);//データの次の文字は空白
                                    cursor2 = cursor2 + 1;
                                }
                        }
                    else//キャラクタ文字以外は16進表記x○○
                        {
                            switch (cursor2)
                            {
                                case 0xe5://2行目に表示して下の行へ戻って空白表示
                                    lcd_cursor(0xe5);
                                    printf(lcd_data,"x%X",result);//x+データ2桁
                                    lcd_cursor(0xc0);
                                    printf(lcd_data," ");
                                    cursor2 = 0xc0;
                                    break;
                                case 0xe6://2行目に表示はせず空白で潰し、データは下の行へ戻って表示
                                    lcd_cursor(0xe6);
                                    printf(lcd_data,"  ");//2文字空白
                                    lcd_cursor(0xc0);
                                    printf(lcd_data,"x%X ",result);//x+データ2桁+空白
                                    cursor2 = 0xc3;
                                    break;
                                case 0xe7://2行目にはxだけ表示してデータは下の行へ戻って表示
                                    lcd_cursor(0xe7);
                                    printf(lcd_data,"x");
                                    lcd_cursor(0xc0);
                                    printf(lcd_data,"%X ",result);//データ2桁+空白
                                    cursor2 = 0xc2;
                                    break;
                                default:
                                    lcd_cursor(cursor2);
                                    printf(lcd_data,"x%X ",result);//x+データ2桁
                                    cursor2 = cursor2 + 3;
                                    break;
                            }
                        }
//
                }
            //usart接続による、時刻設定↓
            if ( ( kbhit(usart2) == 1 ) && ( dsp_num == 3 ) )//時刻設定。usart2が受信したら
                {
                    rtc_data2[receive_cnt] = fgetc(usart2);//他又は自身からの時刻データをusartにより受信する。
                    if ( receive_cnt == 14 )
                        {
                            lcd_cursor(0x80);
                            printf(lcd_data,"received %3u %3u",receive_cnt,dsp_num);
                            output_low(out_ce_rtc);//
                            rtc_set();
                            output_high(out_ce_rtc);//
                            //rtc_read();//
                            //key = 0;
                            //dsp_num = 1;
                            //dsp_ctrl();//
                            receive_cnt = 0;
                        }
                    else
                        {
                            receive_cnt = receive_cnt + 1;
                        }
                }
           //テスト中のためskip_swにて停止中。シリアルコマンドでRTC7301を動かすテスト
            if ( ( kbhit(usart2) == 1 ) && ( skip_sw == 1) )//usart2が受信したら
                {
                    if ( cnt == 0 )//1byte目の受信
                        {
                            //ライトかリードの判断
                            cnt = 1;
                            if ( fgetc(usart2) == 0x72 )// データが「r」だったら
                                {
                                    wr = 1;
                                }
                            else                          // データが「w」だったら
                                {
                                    wr = 0;
                                }
                        }
                    else
                        {
                            result = fgetc(usart2);//2byte目の受信。上位4bitはRTCレジスタアドレス、下記4bitはデータ
                            d1 = result & 0x0f;//下位4bitを抽出しデータへ
                            ad = result>>4;//上位4bitを抽出アドレスへ                            
                            if ( wr == 0 )//RTCライト
                                {
                                    output_c((ad & 0x0F) | (input_c() & 0xF0));//アドレスセット
                                    set_tris_B(port_b_o);
                                    output_high(out_oe);//RTCライト
                                    output_b(d1);//データのライト
                                    output_low(out_ce_rtc);//
                                    delay_cycles(1);
                                    output_low(out_we);//RTCライト
                                    delay_cycles(1);
                                    output_high(out_we);//RTCライト
                                    output_high(out_ce_rtc);//
                                }
                            else//RTCリード
                                {
                                    set_tris_B(port_b_i);
                                    output_high(out_we);//RTCリード
                                    output_low(out_ce_rtc);//
                                    output_c( 0x0F | (input_c() & 0xF0));//アドレスセット
                                    
                                    busy = 1;
                                    while (busy == 1)
                                        {
                                            output_low(out_oe);//RTCリード
                                            delay_cycles(1);
                                            d1 = input_b();
                                            output_high(out_oe);//RTCリード
                                            busy = bit_test(d1,0);
                                        }
                                    
                                    output_c((ad & 0x0F) | (input_c() & 0xF0));//アドレスセット
                                    delay_cycles(1);
                                    output_low(out_oe);//RTCリード
                                    delay_cycles(1);
                                    d1 = input_b() & 0x0F;
                                    output_high(out_oe);//RTCリード
                                    fprintf(usart2,"%c",d1);
                                    output_high(out_ce_rtc);//
                                }
                            cnt = 0;
                        }
                }
            restart_wdt();
//          if ( ( idx > 9 ) || ( cnt2 > 9 ) )
//              {
//                  idx = 0;
//                  cnt2 = 0;
//                  lcd_cursor(0x80);
//                  printf(lcd_data,"%S",string1);
//                  lcd_cursor(0xc0);
//                  printf(lcd_data,"%S",string2);
//              }
            //
        }
}
//オープニング画面
void dsp_opening()
    {
        lcd_init();                //LCD初期化
        lcd_clear();               //LCD全消
        //1行目best
        lcd_cursor(0x80);
        printf(lcd_data,"usartmonitor18F46K22");
        //2行目
        lcd_cursor(0xc0);
        printf(lcd_data,"X.c  2015.3.23      ");
        return;
    }
//RTC時刻データリード
void rtc_read()
    {
        //output_high(out_led);//+++++++++++++++
        set_tris_B(port_b_i);
        output_high(out_we);//RTCリード
        output_low(out_ce_rtc);//
        output_c( 0x0F | (input_c() & 0xF0));//アドレスセット
        output_low(out_oe);//RTCリード
        delay_cycles(1);
        d1 = input_b();
        output_high(out_oe);//RTCリード
        if ( bit_test(d1,0) == 0 )
            {
                idx = 6;//time[11]から
                for ( ad=0;ad < 6;ad = ad + 2 )//adはBANK0のレジスタアドレスで0から5迄
                    {//十の位と一の位を読み込んで1byteに合成する。
                        output_c((ad & 0x0F) | (input_c() & 0xF0));//アドレスセット
                        delay_cycles(1);
                        output_low(out_oe);//RTCリード
                        delay_cycles(1);
                        result = input_b() & 0x0F;//一の位
                        output_high(out_oe);//RTCリード
                        //
                        output_c((ad+1 & 0x0F) | (input_c() & 0xF0));//アドレスセット
                        delay_cycles(1);
                        output_low(out_oe);//RTCリード
                        delay_cycles(1);
                        idx = idx - 1;
                        time[idx] = ( (input_b() & 0x0F)<<4 ) | result;//十の位を左シフトしてから、一の位とorをとる
                        output_high(out_oe);//RTCリード
                    }//アドレス6(曜日)は不要なため、2つのループにした。
                for ( ad=7;ad < 0xd;ad = ad + 2 )//adはBANK0のレジスタアドレスで7からc迄
                    {//十の位と一の位を読み込んで1byteに合成する。
                        output_c((ad & 0x0F) | (input_c() & 0xF0));//アドレスセット
                        delay_cycles(1);
                        output_low(out_oe);//RTCリード
                        delay_cycles(1);
                        result = input_b() & 0x0F;//一の位
                        output_high(out_oe);//RTCリード
                        //
                        output_c((ad+1 & 0x0F) | (input_c() & 0xF0));//アドレスセット
                        delay_cycles(1);
                        output_low(out_oe);//RTCリード
                        delay_cycles(1);
                        idx = idx - 1;
                        time[idx] = ( (input_b() & 0x0F)<<4 ) | result;//十の位を左シフトしてから、一の位とorをとる
                        output_high(out_oe);//RTCリード
                    }
            }
        output_high(out_ce_rtc);//
        //output_low(out_led);//+++++++++++++++
        return;
    }
//画面
void dsp_ctrl()
    {
        switch (dsp_num)
        {
            case 0://画面0の時 2chシリアルデータ表示画面
                if ( key == 0 )//次画面キーを押すと、次画面1へ
                    {
                        dsp_num = 1;//画面1
                        lcd_clear();               //LCD全消
                        dsp_num1();//画面1
                    }
                else//次画面キー以外を押すと
                    {
                        reset_cpu();//ソフトウエア　リセット
                    }
                break;
            case 1://画面1の時 FRAMのアドレスカウント数及び時刻の表示/更新
                if ( key == 0 )//次画面キーを押すと、次画面2へ
                    {
                        dsp_num = 2;//画面2
                        lcd_clear();               //LCD全消
                        dsp_address_L = address_L+ 2;
                        result = dsp_address_L>>8;
                        hi_adrs[0] = result>>4;
                        hi_adrs[1] = result & 0x0f;
                        dsp_num2();//画面2
                        lcd_cursor(0xa3);
                        cur_point = 0xa3;
                    }
                else//次画面キー以外を押すと
                    {
                        dsp_num1();//画面1の更新
                    }
                break;
            case 2://画面2の時 FRAM読み出し
                switch ( key )
                {
                    case 0://次画面キーを押すと、始めの画面3へ
                        dsp_num = 3;//画面3
                        lcd_clear();               //LCD全消
                        set_time[0] = ( time[0]>>4 ) * 10 + ( 0x0f & time[0] );
                        set_time[1] = ( time[1]>>4 ) * 10 + ( 0x0f & time[1] );
                        set_time[2] = ( time[2]>>4 ) * 10 + ( 0x0f & time[2] );
                        set_time[3] = ( time[3]>>4 ) * 10 + ( 0x0f & time[3] );
                        set_time[4] = ( time[4]>>4 ) * 10 + ( 0x0f & time[4] );
                        set_time[5] = ( time[5]>>4 ) * 10 + ( 0x0f & time[5] );
                        lcd_clear();               //LCD全消
                        dsp_num3();//画面3
                        lcd_cursor(0x97);
                        cur_point = 0x97;
                        break;
                    case 1://→（カーソル移動キー）を押すと、それぞれの桁へ移動
                        if ( cur_point == 0xa4 )
                            {
                                cur_point = 0xa3;
                            }
                        else
                            {
                                cur_point = 0xa4;
                            }
                        lcd_cursor(cur_point);
                        break;
                    case 2://↑（値アップキー）を押すと、カーソルの位置の値がアップする。
                        adrs_point = cur_point - 0xa3;//カーソルの位置から、2バイトアドレスの上位1バイトの更に上位4ビットと下位4ビットのどちらなのかを計算する
                        switch ( adrs_point )
                        {
                            case 0://上位1バイトアドレス中の上位4ビット
                                if ( hi_adrs[0] == 7 )
                                    {
                                        hi_adrs[0] = 0;
                                    }
                                else
                                    {
                                        hi_adrs[0] = hi_adrs[0] + 1;
                                    }
                                break;
                            case 1://上位1バイトアドレス中の下位4ビット
                                if ( hi_adrs[1] == 15 )
                                    {
                                        hi_adrs[1] = 0;
                                    }
                                else
                                    {
                                        hi_adrs[1] = hi_adrs[1] + 1;
                                    }
                                break;
                        }
                        result = (hi_adrs[0]<<4) | hi_adrs[1];
                        dsp_address_L = make16(result,0xff);
                        dsp_num2();
                        lcd_cursor(cur_point);
                        break;
                    case 3://FRAM 出力
                        output_low(out_cclr);//カウンタクリアの開始
                        delay_ms(10);
                        output_high(out_cclr);//カウンタクリアの完了
                        delay_ms(10);
                        lcd_cursor(0xd4);
                        printf(lcd_data,"Start!!             ");
                        set_tris_B(port_b_i);
                        output_high(out_we);//FRAMリード
                        output_low(out_ce_fram);//チップセレクト開始
                        for (cnt_L=1;cnt_L <= dsp_address_L; cnt_L = cnt_L + 1 )
                            {
                                output_high(out_cclk);//カウンタ↑
                                output_low(out_cclk); //カウンタ↓
                                delay_cycles(1);
                                output_low(out_oe);//FRAMリード
                                delay_cycles(1);
                                r1 = input_b();
                                output_high(out_oe);//FRAMリード
                                fputc(r1,usart1);//2017.7.13オリジナルはusart2
                                //fprintf(usart1,"%c",r1);
                            }
                        output_high(out_ce_fram);//チップセレクト終了
                        lcd_cursor(0xd4);
                        printf(lcd_data,"Finish!! %4Lx       ",dsp_address_L);
                        output_low(out_cclr);//カウンタクリアの開始
                        delay_ms(10);
                        output_high(out_cclr);//カウンタクリアの完了
                        delay_ms(10);
                        break;
                }
                break;
            case 3://画面3の時 時刻変更
                switch ( key )
                {
                    case 0://次画面キーを押すと、始めの画面0へ
                        lcd_clear();               //LCD全消
                        dsp_num = 0;//画面0
                        dsp_num0();//画面0
                        break;
                    case 1://→（カーソル移動キー）を押すと、それぞれの桁へ移動
                        if ( cur_point == 0xa6 )
                            {
                                cur_point = 0x97;
                            }
                        else
                            {
                                cur_point = cur_point + 3;
                            }
                        lcd_cursor(cur_point);
                        break;
                    case 2://↑（値アップキー）を押すと、カーソルの位置の値がアップする。
                        time_point = ( cur_point - 0x97 )/3;//カーソルの位置から年/月/日/時/分/秒(0から5)のどれからを計算する
                        switch ( time_point )
                        {
                            case 0://yy年
                                if ( set_time[0] == 45 )
                                    {
                                        set_time[0] = 15;
                                    }
                                else
                                    {
                                        set_time[0] = set_time[0] + 1;
                                    }
                                break;
                            case 1://mm月
                                if ( set_time[1] == 12 )
                                    {
                                        set_time[1] = 1;
                                    }
                                else
                                    {
                                        set_time[1] = set_time[1] + 1;
                                    }
                                break;
                            case 2://dd日
                                if ( set_time[2] == 31 )
                                    {
                                        set_time[2] = 1;
                                    }
                                else
                                    {
                                        set_time[2] = set_time[2] + 1;
                                    }
                                break;
                            case 3://hh時
                                if ( set_time[3] == 23 )
                                    {
                                        set_time[3] = 0;
                                    }
                                else
                                    {
                                        set_time[3] = set_time[3] + 1;
                                    }
                                break;
                            case 4://mm分
                                if ( set_time[4] == 59 )
                                    {
                                        set_time[4] = 0;
                                    }
                                else
                                    {
                                        set_time[4] = set_time[4] + 1;
                                    }
                                break;
                            case 5://ss秒
                                if ( set_time[5] == 59 )
                                    {
                                        set_time[5] = 0;
                                    }
                                else
                                    {
                                        set_time[5] = set_time[5] + 1;
                                    }
                                break;
                        }
                        dsp_num3();
                        lcd_cursor(cur_point);
                        break;
                    case 3://時刻設定確定キー
                        send_sw = 1;//設定した時刻データ送出可。この後、メインループ内でsend_serial()を実行。
                        for ( idx=2;idx < 13;idx = idx + 2 )//rtc_data2の下位4bitをset_time[]の数値へ書き換え。rtc_data2[2]から[13]まで
                            {
                                result = idx/2 - 1;
                                div_syo = set_time[result]/10;//十の位
                                div_amari = set_time[result] - (div_syo * 10);//一の位
                                rtc_data2[idx]   = rtc_data2[idx]   & 0xf0;
                                rtc_data2[idx]   = rtc_data2[idx]   | div_syo;
                                rtc_data2[idx+1] = rtc_data2[idx+1] & 0xf0;
                                rtc_data2[idx+1] = rtc_data2[idx+1] | div_amari;
                            }
                        break;
                }
                break;
        }
        return;
    }
//画面0     2chシリアルデータ表示画面
void dsp_num0()//
    {
        return;
    }
//画面1     FRAMのアドレスカウント数及び時刻の表示/更新
void dsp_num1()//
    {
        set_time[0] = ( time[0]>>4 ) * 10 + ( 0x0f & time[0] );
        set_time[1] = ( time[1]>>4 ) * 10 + ( 0x0f & time[1] );
        set_time[2] = ( time[2]>>4 ) * 10 + ( 0x0f & time[2] );
        set_time[3] = ( time[3]>>4 ) * 10 + ( 0x0f & time[3] );
        set_time[4] = ( time[4]>>4 ) * 10 + ( 0x0f & time[4] );
        set_time[5] = ( time[5]>>4 ) * 10 + ( 0x0f & time[5] );
        lcd_cursor(0x80);
        printf(lcd_data,"FRAM address = %5Lu",address_L);//x+データ2桁
        lcd_cursor(0x94);
        printf(lcd_data,"20%2u/%2u/%2u %2u:%2u:%2u ",set_time[0],set_time[1],set_time[2],set_time[3],set_time[4],set_time[5]);
        return;
    }
//画面2     FRAM読み出し
void dsp_num2()//
    {
        lcd_cursor(0x80);
        printf(lcd_data,"FRAM range of output");
        //3行目
        lcd_cursor(0x94);
        printf(lcd_data,"FRAM address=0x%4Lx ",dsp_address_L);
        return;
    }
//
//画面3     時刻変更
void dsp_num3()//
    {
        lcd_cursor(0x80);
        printf(lcd_data,"Time set.Received=%2u",receive_cnt);
        //3行目
        lcd_cursor(0x94);
        printf(lcd_data,"20%2u/%2u/%2u %2u:%2u:%2u ",set_time[0],set_time[1],set_time[2],set_time[3],set_time[4],set_time[5]);
        return;
    }
//
void rtc_set()//RTC時刻初期設定と時刻設定
    {
        output_high(out_led2);
        set_tris_B(port_b_o);
        output_high(out_oe);//RTCライト
        for ( idx=0;idx < 9;idx = idx + 1 )
            {
                d1 = rtc_data1[idx] & 0x0f;//下位4bitを抽出しデータへ
                ad = rtc_data1[idx]>>4;//上位4bitを抽出アドレスへ
                output_c((ad & 0x0F) | (input_c() & 0xF0));//アドレスライト
                output_b(d1);//データのライト
                delay_cycles(1);
                output_low(out_we);//RTCライト
                delay_cycles(1);
                output_high(out_we);//RTCライト
                //
            }
        delay_us(122);
        for ( idx=0;idx < 15;idx = idx + 1 )
            {
                d1 = rtc_data2[idx] & 0x0f;//下位4bitを抽出しデータへ
                ad = rtc_data2[idx]>>4;//上位4bitを抽出アドレスへ
                output_c((ad & 0x0F) | (input_c() & 0xF0));//アドレスライト
                output_b(d1);//データのライト
                delay_cycles(1);
                output_low(out_we);//RTCライト
                delay_cycles(1);
                output_high(out_we);//RTCライト
                //
            }
        set_tris_B(port_b_i);
        output_low(out_led2);
        return;
    }
//
void send_serial()//メインループ内で1バイトずつ時刻データを送出する。send_sw=1でこのサブルーチンにくる。
    {
        fputc(rtc_data2[send_cnt],usart1);//時刻データの送信
        send_cnt = send_cnt + 1;
        if ( send_cnt == 15 )
            {
                send_sw = 0;
                send_cnt = 0;
            }
        return;
    }
//FRAM消去
void  fram_erase()
    {
        output_low(out_cclr);//カウンタクリアの開始
        delay_ms(10);
        output_high(out_cclr);//カウンタクリアの完了
        delay_ms(10);
        //
    //FRAM初期化　FFの書込み
        set_tris_B(port_b_o);
        output_high(out_oe);//FRAMライト
        output_low(out_ce_fram);//チップセレクト開始
        //result = 1;//テスト
        for (address_L=1;address_L< 0x8000; address_L = address_L + 1 )
            {
                //output_b(result);//テスト
                //result =  result + 1;//テスト
                output_b(0xff);//FRAMライト
                output_high(out_cclk);//カウンタ↑
                output_low(out_cclk); //カウンタ↓
                delay_cycles(1);
                output_low(out_we);//FRAMライト
                delay_cycles(1);
                output_high(out_we);//FRAMライト
            }
        output_high(out_ce_fram);//チップセレクト終了
        set_tris_B(port_b_i);
        //
        output_low(out_cclr);//カウンタクリアの開始
        delay_ms(10);
        output_high(out_cclr);//カウンタクリアの完了
        delay_ms(10);
        lcd_clear();               //LCD全消
        //1行目best
        lcd_cursor(0x80);
        printf(lcd_data,"FRAM erased!!       ");
        //2行目
        lcd_cursor(0xc0);
        printf(lcd_data,"                    ");
        return;
    }

/////////////////////////////////////////////////////////
























