UMEHOSHI ITA TOP PAGE    COMPUTER SHIEN LAB

UMEHOSHI IT (my_uart.cと.h)

UART (Universal Asynchronous Receiver/Transmitter, ユーアート) は、調歩同期方式によるシリアル信号で p32mx270f256bのUART1と通信する際に使う関数群です。

初期化概要 

my_sys.cのinit_handle_area関数で、handlers[_IDX_INIT_UART1]にinit_uart関数を設定するなどの各マクロが登録されます。
 _recv_uart1や _send_uart1 などのマクロに、通常モードで使うrecv_uart1の1byte受信関数や send_uart1の1byte送信関数などを登録しています。
send_uart1(uint8_t)関数は、uart1へ出力するデータをuartSndBufのリングバッファに登録します。
この出力は、_def_polls_uart()マクロで実行するrecive_and_send_uart_with_polling関数のポーリングで行われています。

続いて、init_interrupt()内で、handlers[_IDX_INIT_UART1]マクロのinit_uart関数でUART1の方向モード(フロー制御しない)など
各設定の初期化をしていますが、割り込みは不可にしています。(デフォルトでUart1Handlerの割り込みは使用していません。)
ポーリング処理で、UART送受信の割り込みが使われていません。
ですが、将来に割り込みを使う変更を考慮して割り込み関数の定義(Uart1Handler関数)が存在しています。
(受信用リングバッファは割り込み関数で使っていますが、recv_uart1関数で使用して使っていません。参考コードとして存在します。)

起動時に、通常モード、スルーモード、UART1コマンドモードに選択可能で、USRTの使い方が後述のように違っています。
(各モードの切り替えはコアタイマ割り込みで起動されるcore_timer_sub_1関数で、スルーモードやUART1コマンドモードに切り替わります。)

各モードのUART受信処理では、UMEHOSHI IT のに改行("\r\n")を1回だけUART1に送出して、起動時の2秒間の受信データを無視にするreply_boot_message関数を実行しています。

通常モード (スルーモードやUART1コマンドモードに遷移するまでは、通常モードです。)

UMEHOSHIのUSB処理であるMy_APP_Tasks()内で、_def_polls_uart()マクロ(handlers[_IDX_DEF_POLLS_UART] )に登録されるrecive_and_send_uart_with_polling関数を 実行します。
recive_and_send_uart_with_polling内では、エラーチェック後に、uartSndBufに送信すべきデータがあればUARTに出力しますが、 受信のポーリングが優先されて、UART受信が判断されれば、 _recv_uart1(data); マクロを呼び出します。
_recv_uart1(data)マクロは、handlers[_IDX_RECV_UART1] に登録された関数実行です。
よって、「ウメ・エディットプログラム(ユーザー用のプログラム)」で処理の置き換えが可能です。
(デフォルトでは _recv_uart1マクロに、recv_uart1関数が登録されています。)

recv_uart1関数では、残りのUSB送信バッファをチェックして、可能なら受信dataをUSBへ出力しています。(USBに送信できないならエラー)
これにより UARTからの出力を、UMEHOSHI ITA介して、接続しているPC側(umehoshiEditツールなど)で確認できます。



スルーモード 

UMEHOSHIのUSB処理であるMy_APP_Tasks_Through()を実行内で、ringbuf_is_read関数で、USRT受信から受信した情報をUSBに出力します。 (通常モードやUART1コマンドモードで使っている _recv_uart1(data)マクロを使わない、低レベル関数のringbuf_is_readを直接呼び出している。)

UART1コマンドモード 

UARTで「UME専用Hexコマンド」を受け付けるモードです。
UMEHOSHIのUSB処理であるMy_APP_Tasks()内で、_def_polls_uart()マクロに登録されるuart_cmd_mode_polling関数を実行します。
_def_polls_uart()マクロは、handlers[_IDX_DEF_POLLS_UART]に記憶される登録関数ですが、 初期登録関数はこれを handlers[_IDX_CMD_POLLS_UART]にへ切り替えることで実現しています。
(このhandlers[_IDX_CMD_POLLS_UART]には、uart_cmd_mode_polling()関数が登録されています。)

uart_cmd_mode_polling関数では、UART受信データでselect_command、set_commad_charを実行して「UME専用Hexコマンド」の処理を行っています。
(通常モードやUART1コマンドモードで使っている _recv_uart1(data)マクロを使わない、低レベル関数のringbuf_is_readを直接呼び出している。)


my_uart.hのソース

#ifndef _MY_UART_H
#define _MY_UART_H

#define RINGBUFFSIZE 256

// 送受信リングバッファ構造体と操作関数-------------------------------------------
typedef struct RingBuffer_t {
    uint8_t buff[RINGBUFFSIZE]; 
    int in_Idx;
    int outIdx;
    int numSndBytes; // 上記のバッファに記憶されるバイト数
} RingBuffer;
extern RingBuffer uartSndBuf; // USRT送信用リングバッファ
extern RingBuffer uartRecBuf; // USRT受信用リングバッファ

//void ringbuf_reset(RingBuffer *p);
bool ringbuf_is_read(RingBuffer *p);
//bool ringbuf_is_full(RingBuffer *p);
//void ringbuf_set_data(RingBuffer *p, uint8_t c );
//uint8_t ringbuf_get_data(RingBuffer *p);
int ringbuf_copy_to(RingBuffer *p,uint8_t *pBuff);
// 以上が送受信リングバッファ構造体と操作関数-------------------------------ここまで


// デフォルトのuartのポーリング関数と、関連メソッド------------------------------
void recive_and_send_uart_with_polling();
void init_uart();
int recv_uart1(uint8_t);
int send_uart1(uint8_t);
// デフォルトのuartのポーリング関数と、関連メソッド-------------------------ここまで


// UARTコマンドモードや割り込み用ポーリング関数と、関連メソッド---------------------
bool request_acc_uartbuff(uint16_t id);
uint16_t release_acc_uartbuff(uint16_t id);
void uart_cmd_mode_polling();//UARTコマンドモード時のポーリング関数
void uart_isr_buff_polling();//uartの割り込みリ利用時のポーリング処理
int get_size_rec_uart();//uartRecBufに記憶されたUART送信データ数を返す
int get_data_rec_uart();//uartRecBufからの受信データ取り出し
int get_size_snd_uart();// uartSndBufに記憶されたUART送信データ数を返す
void set_data_snd_uart(uint8_t c);// uartSndBufへの送信データをセット
int get_uart1_capacity();//uartSndBufにセット可能なバイト数を返す。
void send_string_to_uart1(char *s);// 文字列をuart1に送信します.
// UARTコマンドモードや割り込み用ポーリング関数と、関連メソッド--------------ここまで


#define MY_UART_ERR_PARITY  0x0001 // UARTパリティエラー判定
#define MY_UART_ERR_FRAMING 0x0002 // UARTフレーミングエラー(STOPbit異常)
#define MY_UART_ERR_OVERRUN 0x0004 // USRT受信バッファオーバーラン エラー
#define MY_UART_ERR_SND_ISR 0x0008 // 送信必要なしで、送信割り込みが起きた矛盾
#define MY_UART_ERR_REC_SET 0x0010 // UART受信処理でUSB出力バッファフルの設定失敗
#define MY_UART_ERR_SND_SET 0x0020 // UART送信処理でUART送信バッファフルの設定失敗

#endif /* _UART_H */

my_uart.cのソース

// my_uart.c
// (p32mx270f256bのUART1と調歩同期方式によるシリアル通信する際に使う定義群です。)

#include <stdbool.h>                    // Defines true
#include <stdlib.h>                     // Defines EXIT_FAILURE
#include <xc.h>
#include <sys/attribs.h>//割込み関係の定義
#include <proc/p32mx270f256b.h>
#include "my_sys.h"
#include "my_app.h"
#include "my_usb_cmd.h"
#include "my_uart.h"
#include "my_beep.h"
#include "common.h"

// RingBuffer構造体の操作関数群--------------------------------------------------
void ringbuf_reset(RingBuffer *p) {
    p->in_Idx = p->outIdx = -1;
    p->numSndBytes = 0;
}

bool ringbuf_is_read(RingBuffer *p) {
    return p->numSndBytes > 0;
}

bool ringbuf_is_full(RingBuffer *p) {
    return p->numSndBytes == RINGBUFFSIZE;
}

void ringbuf_set_data(RingBuffer *p, uint8_t c) {
    p->numSndBytes++;
    if (p->in_Idx + 1 >= RINGBUFFSIZE) p->in_Idx = -1;
    p->buff[++p->in_Idx] = c;
}

uint8_t ringbuf_get_data(RingBuffer *p) {
    p->numSndBytes--;
    if (p->outIdx + 1 >= RINGBUFFSIZE) p->outIdx = -1;
    return p->buff[++p->outIdx];
}

int ringbuf_copy_to(RingBuffer *p, uint8_t *pBuff) {
    int recSize = 0;
    while (ringbuf_is_read(p))
        pBuff[recSize++] = ringbuf_get_data(p);
    return recSize;
}

// USRT送信用リングバッファ--と関連操作関数定義====================================
RingBuffer uartSndBuf = {
    {0}, -1, -1, 0
};
RingBuffer uartRecBuf = {
    {0}, -1, -1, 0
}; // USRT受信用リングバッファ


//割り込み時に上記ringbuffを操作の排他制御用
volatile uint16_t accessing_uartbuffer __attribute__((section("sfrs")));

uint16_t my_uart_err = 0; // my_uart.c でのエラー情報
// 上記エラー情報への設定関数
int my_uart_set_err(uint16_t d) {
    my_uart_err |= d;
}

// UART関連通信エラーチェック.
void check_uart_error() {
    // パリティエラー判定
    if (core_once_count3_val == 0 && U1STAbits.PERR == 1) {
        my_uart_set_err(MY_UART_ERR_PARITY);
    }
    // フレーミングエラー判定(あるべき位置にストップビットがなかった)
    if (core_once_count3_val == 0 && U1STAbits.FERR == 1) {
        my_uart_set_err(MY_UART_ERR_FRAMING);
    }
    // 受信バッファオーバーラン エラー 判定(チップから取り出す前に次のデータが来た)
    if (core_once_count3_val == 0 && U1STAbits.OERR == 1) {
        my_uart_set_err(MY_UART_ERR_OVERRUN);
    }
}

// 割り込み時に上記ringbuffを操作する使う排他制御用の権限要求関数
bool request_acc_uartbuff(uint16_t id) {
    if (accessing_uartbuffer == id) {
        if (id == _ID_ACCESS_UARTASK) IEC1bits.U1RXIE = 1; // UART1受信割込みを許可    
        else IEC1bits.U1RXIE = 0; // UART1受信割込みを不許可
        return true;
    }
    if (accessing_uartbuffer != 0) {
        if (id != _ID_ACCESS_UARTASK) IEC1bits.U1RXIE = 1; // UART1受信割込みを許可    
        else IEC1bits.U1RXIE = 0; // UART1受信割込みを不許可
        return false;
    }
    accessing_uartbuffer |= id;
    if (accessing_uartbuffer == id) {
        if (id == _ID_ACCESS_UARTASK) IEC1bits.U1RXIE = 1; // UART1受信割込みを許可    
        else IEC1bits.U1RXIE = 0; // UART1受信割込みを不許可
        return true; // outBuffersへのアクセス権を得た
    }
    accessing_uartbuffer &= ~id;
    if (id != _ID_ACCESS_UARTASK) IEC1bits.U1RXIE = 1; // UART1受信割込みを許可    
    else IEC1bits.U1RXIE = 0; // UART1受信割込みを不許可
    return false;
}

// 上記割込み取得した権限を返す関数(ウメ・エディット・側だけで使う)
uint16_t release_acc_uartbuff(uint16_t id) {
    uint16_t rtnval = accessing_uartbuffer &= ~id; //出力バッフ利用終了
    IEC1bits.U1RXIE = 1; // UART1受信割込みを許可    
    return rtnval;
}

//UARTコマンドモード時のポーリング関数
// 受信データがあれば、
void uart_cmd_mode_polling() {
    uint8_t data;
    if (U1STAbits.URXDA == 1) {//UART受信バッファ内にデータが存在する。
        data = U1RXREG; // 受信データ取得
        if (_reply_boot_message() == 0) return;// 202503:追加
        char rtn = select_command(data); // 逐次に受け取る引数がコマンド判定実行
        if (rtn == 0) {
            set_commad_char(data); // 文字をコマンド解析バッファにセット   
        }
    }
    if (ringbuf_is_read(& uartSndBuf) // UARTへの送信データがある?  
            && U1STAbits.UTXBF == 0 // 送信バッファはフルではない
            && U1STAbits.TRMT == 1 //送信バッファが空?
            ) {
        data = ringbuf_get_data(& uartSndBuf); // UART送信バッファから取り出し
        U1TXREG = data; // チップ内UARTの送信バッファに入れる。 
    }
}

//uartRecBufに記憶されたUART送信データ数を返す
int get_size_rec_uart() {
    return uartRecBuf.numSndBytes;
}

//uartRecBufからの受信データ取り出し
int get_data_rec_uart() {
    return ringbuf_get_data(& uartRecBuf);
}

// uartSndBufに記憶されたUART送信データ数を返す
int get_size_snd_uart() {
    return uartSndBuf.numSndBytes;
}

// uartSndBufへの送信データをセット
void set_data_snd_uart(uint8_t c) {
    ringbuf_set_data(& uartSndBuf, c);
}

// UART1の初期設定
void init_uart() {
    // UART用の入出力ビットを指定
    TRISASET = 0x00000010; // RX  (RA4)入力指定 
    TRISBSET = 0x00000100; // CTS (RB8)入力指定 
    TRISBCLR = 0x00000210; // RTS (RB9) , TX(RB4) 出力
    U1CTSR = 0x4; //RPB8(TABLE 11-6: PERIPHERAL PIN SELECT INPUT REGISTER MAP )
    U1RXR = 0x2; //RPA4を、UART1のRX入力に使う指定
    RPB4R = 0x1; //U1TX(出力)
    RPB9R = 0x1; //U1RTS(出力)

    U1MODE = 0x0; // UARTx モードレジスタ設定--------------------------------------
    U1MODEbits.ON = 1; //UART1を有効 (USRT 関連端子がUSRT仕様指定で働く).
    //(無効時はPORTx、TRISx、LATxレジスタでビット制御).
    U1MODEbits.SIDL = 0; //アイドル中も動作を継続する.
    U1MODEbits.IREN = 0; //IrDAを無効にする .
    U1MODEbits.RTSMD = 1; // UxRTS ピンモード選択を片方向モード(フロー制御しない). 
    //U1MODEbits.UEN = 2;//UxTX、UxRX、UxCTS、UxRTS ピンを有効にして使う
    U1MODEbits.UEN = 0; //UxTX、UxRXをピンを有効, UxCTS、UxRTSはPORTxレジスタで指定
                        // (RTSはRB9で制御).
    U1MODEbits.WAKE = 0; //スリープ中スタートビット検出時復帰を無効.
    U1MODEbits.LPBACK = 0; //ループバックモードを有無効にする.
    // UART ボーレート(baudrate)設定関連指定.
    U1MODEbits.ABAUD = 0; //baud レート自動検出イネーブルビット無効.
    U1MODEbits.RXINV = 0; // 受信極性反転ビット UxRXのアイドル状態は「1」.
    U1MODEbits.BRGH = 1; //高baudレート指定(高速モード:4x baudクロックを有効にする).
    U1BRG = 87; // 115200 bps Set Baud rate( BRGH が1の時).
    //上記の意味: 87=(40000000/4/88-115200)/115200
    U1MODEbits.PDSEL = 0; // 8 ビットデータ、パリティなし.
    U1MODEbits.STSEL = 0; // 1 個のストップビット.
    U1STA = 0; // UARTのステータスレジスタ設定 ( 割り込みを含む ).
    U1STAbits.ADM_EN = 0; //自動アドレス検出モードを無効にする.
    U1STAbits.ADDR = 0; //自動アドレス検出に使うアドレスキャラクタ(上が0で意味なし).
    U1STAbits.UTXISEL = 0; //送信バッファに空きが1つでもあればで割込みする指定.
    U1STAbits.UTXINV = 0; //UxTXの送信極性反転ビット:アイドル状態は「1」.
    U1STAbits.URXEN = 1; // レシーバイネーブルビット:有効.
    U1STAbits.UTXBRK = 0; // 送信ブレークビット 無効または完了.
    U1STAbits.UTXEN = 1; // 送信イネーブルビット:有効.
    U1STAbits.URXISEL = 0; //受信バッファが空きが1つでもあればで割込みする指定.
    U1STAbits.ADDEN = 0; //アドレス検出モードを無効にする.
    U1STAbits.OERR = 0; //受信バッファオーバーランエラーステータスビットクリア .
            // ハードウェアでセットされ、この代入のソフトウェアでのみでクリア.

    // 送受信共通のUART1用割込み優先度、サブ優先度の設定.
    IPC8bits.U1IP = 3; //Interrupt Priorty (IPC8 レジスタ設定).
    IPC8bits.U1IS = 1; //Interrupt sub-priority level = 1

    //割込み用フラグIFS1,IEC1の設定 [セクション 8. 割り込み:8.3 動作]参照
    //以下は受信関連
    IFS1bits.U1RXIF = 0; // Clear the interrupt status flag (1になって割込む)
    //IEC1bits.U1RXIE = 1; // UART1受信 Enable(割込み許可)
    IEC1bits.U1RXIE = 0; // UART1受信 割込み不許可 (ポーリング利用)

    //以下は送信関連
    IFS1bits.U1TXIF = 0; // Clear the interrupt status flag (1になって割込む)
    //IEC1bits.U1EIE = 1;// 送受信エラー用割込み
    IEC1bits.U1TXIE = 0; // UART1送信 Enable(割込み不許可)

    // 以下は、別途 USB シリアル変換ボードなどを利用してESP32に書き込む場合に使うコード--     
    //    U1MODE=0x0;// UART の無効設定
    //    U1STA=0;
    //    _RB4=1; // UART TX でプルアップされる出力端子をHiでワイヤードORを可能にする。
}

// ブートメッセージに返信する
// ESP32-WROOM-32Dの起動時のメッセージ出力を止める細工として作成
int reply_boot_message_status = 0; //一定時間後、受信に対して1回だけ改行で応答する制御用 :202503追加
int reply_boot_message() { 
    if (reply_boot_message_status == 0) {
        if (core_once_count1_val <= 0) {// 起動1秒後 
            //起動後の一定期間を無視し、その後、改行を1回だけ出して無視モードを終える
            reply_boot_message_status = 1;
            U1TXREG = '\r'; //UART送信バッファに入れる。
            U1TXREG = '\n'; //UART送信バッファに入れる。
            
        } // 上記改行の送出で、Boot Logが止まらない場合を想定した細工 
        //   として、(core_once_count2_val > 0)の間はまでの受信は無効にしている
    }
    if (core_once_count2_val > 440) {// ダウンカウンター起動後約1.5秒後まで
        return 0; // 無視
    } else if (core_once_count2_val > 0) {//  約1.5 ? 2秒で受信があれば
        debug_hex16(19,0x2001,1);// ESP32が 正しく起動していない警告音
        return 0; // 2秒まで、無視
    }
    return 1; // 応答終了のタイミング
}
//  :202503 下記を上記のように変更
//int reply_boot_message() {
//    static int flag = 1; //一定時間後、受信に対して1回だけ改行で応答する制御用
//    if (core_once_count2_val > 0) {
//        if (flag == 1) {
//            if (core_once_count1_val == 0) {// 起動1秒後 
//                //起動後の一定期間を無視し、その後、改行を1回だけ出して無視モードを終える
//                flag = 0;
//                U1TXREG = '\r'; //UART送信バッファに入れる。
//                U1TXREG = '\n'; //UART送信バッファに入れる。
//            } // 上記改行の送出で、Boot Kogが止まらない場合を想定した細工 
//            //   よって、(core_once_count2_val > 0)の間はまでの受信は無効にしている
//        }
//        return 0; // 2秒まで、無視
//    }
//    return 1; // 応答終了のタイミング
//}

// UART1からの1byte受信すると呼び出される。処理した場合は1、処理しない場合は0を返す。
int recv_uart1(uint8_t data) {
    // 起動時の受信を無視して、"\r\n"のメッセージを1回だけ送出する.
    if (_reply_boot_message() == 0) return 0; // :202503 マクロに変更

    // UARTから受信したデータを、USB出力バッファの余裕があって出力可能ならUSBに出力
    if (_get_capacity() < 20) {
        my_uart_set_err(MY_UART_ERR_REC_SET); // 容量が一杯に近い! .
        return 0;
    }
    send_char(data); // UARTで受信した1文字を USBへ出力する。
    return 1;
}

// UART1で送信するデータをセットする。セットできた時1、出来ない時0を返す.
// ユーザープログラムからのマクロ呼び出し可
// スルーモード時は、USBからの受信(my_usb.c:set_recive_data関数)で、呼び出される。.
int send_uart1(uint8_t data) {

    if (ringbuf_is_full(& uartSndBuf)) {
        my_uart_set_err(MY_UART_ERR_SND_SET);
        return 0;
    }
    ringbuf_set_data(& uartSndBuf, data); //UART送信用リングバッファにセット.       
    return 1;
}

// UART1のバッファで、格納可能は残りの容量(バイト数)を返す.
int get_uart1_capacity() {
    return RINGBUFFSIZE - uartSndBuf.numSndBytes;
}

// 文字列をuart1に送信します.
void send_string_to_uart1(char *s) {
    while (*s != NULL) send_uart1(*s++);
}

/* ========================================== :202503 以下をコメントで削除して、簡潔に書き直す。
int recive_and_send_uart_no_through() {
    static uint8_t data;

    if (U1STAbits.URXDA == 1) {//UART受信バッファ内にデータが存在する。
        data = U1RXREG; // 受信データ取得
        _recv_uart1(data); // 処理の置き換え可能な 1byte受信処理のマクロ
    }

    if (ringbuf_is_read(& uartSndBuf) // UARTへの送信データがある?  
            && U1STAbits.UTXBF == 0 // 送信バッファはフルではない
            && U1STAbits.TRMT == 1 //送信バッファが空?
            ) {
        data = ringbuf_get_data(& uartSndBuf); // UART送信バッファから取り出し
        U1TXREG = data; // チップ内UARTの送信バッファに入れる。
    }
}

// USB処理の中で呼び出されるUARTの送受信の処理(初期のデフォルトポーリング関数)
void recive_and_send_uart_with_polling()//uartのポーリング処理
{
    static uint8_t data;
    static int wait_count = 0;
    static recive_by_uart_mode = 0; //UARTからの受信モード

    check_uart_error(); //UART関連通信エラーチェック

//    if (flagThrough == 0) {// T.スルーモードでない?
        recive_and_send_uart_no_through(); // スルーモードでない場合のUART送受信  
//        return;
//    }

//    // 以下は、T.スルーモード処理時の入出力-------
//    if (recive_by_uart_mode == 0) {//UARTへ送信モード(USB受信)
//        // UARTへの送信する登録データがあれば、取り出してUARTへ出力
//        // (登録データは、スルーモードであれば、USB受信で行われる)
//        if (ringbuf_is_read(& uartSndBuf) // UARTへの送信データがある?  
//                && U1STAbits.UTXBF == 0 // 送信バッファはフルではない
//                && U1STAbits.TRMT == 1 //送信バッファが空?
//                ) {
//            wait_count = 0;
//            data = ringbuf_get_data(& uartSndBuf); // UART送信バッファから取り出し
//            U1TXREG = data; // チップ内UARTの送信バッファに入れる。
//
//            return;
//        }
//    }
//    // UARTからの受信(USB送信バッファへ登録)があれば、
//    // しばらく、このUARTからの受信モードを続ける。
//    if (U1STAbits.URXDA == 1 || recive_by_uart_mode == 1) {
//        recive_by_uart_mode = 1;
//        if (U1STAbits.URXDA == 1) {//チップのUART受信バッファ内にデータが存在する.
//            data = U1RXREG; // 受信データ取得
//            recv_uart1(data); // UARTで受信した1byteを USBへ出力する登録をする。
//            wait_count = 1;
//        } else {
//            wait_count++;
//            if (wait_count > 100) {
//                // UARTからしばらくデータがこなければ、UARTからの受信モードを終える
//                recive_by_uart_mode = 0;
//            }
//        }
//    }
//}
  :202503 上記範囲は、通常モードだけで使う処理で以下に作り直した ================================ */
// 通常モードだけで使う_def_polls_uart()マクロのUAR1受信処理
// (USB処理の中で呼び出されるUARTの送受信の処理で、デフォルトポーリング関数)
void recive_and_send_uart_with_polling()//uartのポーリング処理
{
    static uint8_t data;
    
    check_uart_error(); //UART関連通信エラーチェック

    if (U1STAbits.URXDA == 1) {//UART受信バッファ内にデータが存在する。
        data = U1RXREG; // 受信データ取得
        _recv_uart1(data); // 処理の置き換え可能な 1byte受信処理のマクロ
        // デフォルトは、recv_uart1関数が登録
    }

    if (ringbuf_is_read(& uartSndBuf) // UARTへの送信データがある?  
            && U1STAbits.UTXBF == 0 // 送信バッファはフルではない
            && U1STAbits.TRMT == 1 //送信バッファが空?
            ) {
        data = ringbuf_get_data(& uartSndBuf); // UART送信バッファから取り出し
        U1TXREG = data; // チップ内UARTの送信バッファに入れる。
    }    
}



// USB処理の中で呼び出されるUARTの送受信の処理
void uart_isr_buff_polling()//uartの割り込みリ利用時のポーリング処理
{
    //IEC1bits.U1RXIE = 0; // UART1受信割込み許可変更   
    if (request_acc_uartbuff(_ID_ACCESS_USBTASK) == false) {
        //IEC1bits.U1RXIE = 1; // UART1受信割込み許可変更   
        return;
    }
    if (get_size_rec_uart() > 0) {
        uint8_t data = ringbuf_get_data(& uartRecBuf);
        _recv_uart1(data); // 処理の置き換え可能な 1byte受信処理のマクロ
    }
    if (get_size_snd_uart() > 0) {
        release_acc_uartbuff(_ID_ACCESS_USBTASK);
        IEC1bits.U1TXIE = 1; // UART1送信割込み 割込みEnable     
    } else {
        IEC1bits.U1TXIE = 0; // UART1送信 割込みEnable OFF      
    }
    release_acc_uartbuff(_ID_ACCESS_USBTASK);
    //IEC1bits.U1RXIE = 1; // UART1受信割込み許可変更
}

// 割り込み 割り込みグループ優先度: 3にセット
// 優先度は1(最低優先度)から7(最優先)の間で選択できる。
// より高い優先度を持つ割り込みベクタから先に処理されます。
// (下記のIPL4SOFTが優先度で、このソースでは、「IPC8bits.U1IP」設定と連動が必要)
void __ISR(_UART_1_VECTOR, IPL3SOFT)Uart1Handler(void) {
    extern void send_string(char *s);
    char s[128];

    if (IFS1bits.U1RXIF == 1) {// 受信に対するインタラプト判定    
        if (request_acc_uartbuff(_ID_ACCESS_UARTASK) == false) {
            //IFS1bits.U1RXIF = 0; //mU1TXClearIntFlag()
            return;
        }
        uint8_t c = U1RXREG; //  UART受信データ取得
        ringbuf_set_data(& uartRecBuf, c); //受信バッファに入れる
        release_acc_uartbuff(_ID_ACCESS_UARTASK);
        IFS1bits.U1RXIF = 0; //mU1RXClearIntFlag() 

    } else if (IFS1bits.U1TXIF == 1) {// 送信バッファが空?インタラプト判定
        if (request_acc_uartbuff(_ID_ACCESS_UARTASK) == false) {
            IFS1bits.U1TXIF = 0; //mU1TXClearIntFlag()
            return;
        }
        if (ringbuf_is_read(& uartSndBuf) == false) {// 送信の必要がない?
            // 送信必要なしで、送信割り込みが起きた矛盾時のエラー
            my_app_set_err(MY_UART_ERR_SND_ISR);
            IEC1bits.U1TXIE = 0; // UART1送信 割込みEnable OFF      
        } else {
            uint8_t data = ringbuf_get_data(& uartSndBuf);
            U1TXREG = data; //送信バッファに入れる。
            if (ringbuf_is_read(& uartSndBuf) > 0) {// まだ送信の必要がある?
                IEC1bits.U1TXIE = 1; // UART1送信割込み 割込みEnable     
            } else {
                IEC1bits.U1TXIE = 0; // UART1送信 割込みEnable OFF      
            }
        }
        release_acc_uartbuff(_ID_ACCESS_UARTASK);
        IFS1bits.U1TXIF = 0; //mU1TXClearIntFlag()

    } else if (IFS1bits.U1EIF == 1) {//  エラーか?
        check_uart_error();
    }
}