全体の構成
EUSARTの受信/送信は、マイコンのペリフェラルに任せます。これにより、データの受信、送信をハードウェアで処理させ、ソフトウェア処理の負荷を抑えることができます。
フローチャートを示します。
main()では、EUSARTの初期化をし、メインループ(無限ループ)の中で受信と送信操作を行います。

受信操作は、receive_data()によって、グローバル変数配列のバッファから受信データを読み出しています。

送信操作は、transmit_data()で送信データをグローバル変数配列のバッファにセットし、EUSART TX 割り込みを許可します。

受信バッファ、送信バッファはそれぞれ割り込み処理の中で処理されます。
- 受信では、シリアル通信ポートに入ってきたデータが受信バッファに取り込まれると、割り込み要求が出されます。割り込み要求によって割り込み処理に入り、受信バッファのデータをグローバル変数配列のバッファにコピーします。
- 送信では、送信バッファが空になっていると、割り込み要求が出され、割り込み処理の中でグローバル変数配列のバッファのデータを送信バッファに格納します。送信データがなければ、EUSART TX割り込みを禁止して終了します。
以下、それぞれの処理の実装例を示します。なお、実装例(レジスタ)はPIC16f15245の例です。
EUSARTの初期化
PICマイコンはPPS(Peripheral Pin Select)で、EUSARTのTX, RXピンの割当を設定することができます。以下の例では、RB6(PORTBの6pin)ピンをEUSARTのTXに、RB5(PORTBの5pin)をRXに割り当てています。
#define RX1PORT 0x0d // RB5(01:101) for RX
#define TX1PORT RB6PPS // RB6 for TX
void EUSART_init() {
BADUD1CON = 0x08; // bit4:SCKP(Clock/Transmit Polarity) = 0,
// bit3:BRG16(16-bit Baud Rate Generator) = 1,
// bit0:ABDEN(Auto-Baud Detect) = 0
RC1STA = 0x90; // bit7:SPEN(Serial Port Enable) = 1
// bit6:RX9(9-Bit Receive Enable) = 0
// bit5:SREN(Single Receive Enable) = 0
// bit4:CREN(Continuous Receive Enable) = 1
SP1BRG = 25; // Baud Rate Register
TX1STA = 0x00; // bit7:CSRC(Clock Source Select) = 0
// bit6:TX9(9-Bit Transmit Enable) = 0
// bit5:TXEN(Transmit Enable) = 0
// bit4:SYNC(EUSART Mode Select) = 0
// bit2:BRGH(High Baud Rate Select) = 0
RX1PPS = RX1PORT; //
TX1PORT = 0x05; //
PIE1 |= 0x10; // bit4:RC1IE(EUSART1 Receive Interrupt) = 1
}
受信
受信は、グローバル変数のrxBuf[]のデータを読み出します。rxBuf[]には、EUSARTの受信割り込みで、受信バッファからデータをコピーしており、そのデータを読み出すことができます。
rxBufはリングバッファとなっており、バッファ内の最古のデータ位置がrxBufHead、最新のデータ位置の次がrxBufTailとしています。したがって、バッファ内のまだ読みだしていないデータは、rxBufHead~rxBufTail-1のデータとなります。
#define RX_BUF_SIZE 8
unsigned char rxBuf[RX_BUF_SIZE]; // receive data buffer
unsigned char rxBufHead = 0; // receive data head index
unsigned char rxBufTail = 0; // receive data tail index
void receive_data(unsinged char data[]) {
int i = 0;
while (rxBufHead != rxBufTail) {
data[i] = rxBuf[rxBufHead];
rxBufHead++;
if (rxBufHead >= RX_BUF_SIZE) {
rxBufHead = 0;
}
}
}
送信
送信は、グローバル変数のtxBuf[]に送信データをセットし、EUSARTの送信を許可、EUSARTの送信割り込みを許可すれば、後は割り込み処理でrxBuf[]のデータを送信します。
unsigned char txBuf[8]; // transmit data buffer
unsigned char txBufIdx = 0; // transmit data index
void transmit_data(unsigned char txData[], int nTxData) {
/* txDAta : transmit data array */
/* nTxData: number of transmit data */
for (int i = 0; i < nTxData; i++) {
txBuf[nTxData - 1 - i] = txData[i];
}
RC1STA &= ~0x10; // bit4:CREN(Continuous Receive) = 0 to transmit
TX1STA |= 0x20; // bit5:TXEN(Transmit Enable) = 1
PIE1 |= 0x04; // bit3:TX1IE(Transmit Interrupt) = 1
}
割り込み処理
EUSARTの受信バッファ(RC1REG)、送信バッファ(TX1REG)の操作は、割り込みで行います。
受信は、EUSARTの受信バッファ(RC1REG)のデータを読み出して、グローバル変数rxBuf[]に格納します。ただし、EUSARTの受信バッファのオーバーフロー、フレーミングエラーの処理を行っています。オーバーフローについては、受信できなかったデータはしかたないので、オーバーフローフラグ(RC1STA, bit1)をクリアする(CRENまたはSRENを一旦クリアする)のみ行います。
フレーミングエラーについては、エラー情報(RC1STA, bit2)をグローバル変数(ferr)にセットしておきます。
unsigned char ferr = 0;
void __interrupt() isr(void) {
if (PIR1 & 0x10 != 0) { // EUSART1 Receive Interrupt
if (RC1STA & 0x02 != 0) {
RC1STA &= ~0x10;
RC1STA |= 0x10;
}
ferr = RC1STA & 0x04; // set framing error flag
rxBuf[rxBufTail] = RC1REG; // read receive buffer
}
if (PIR1 & 0x08 != 0) { // EUSART1 Transmit Interrupt
if (txBufIdx == 0) {
TX1STA &= ~0x20; // bit5:TXEN(Transmit Enable) = 0
RC1STA |= 0x10; // bit4:CREN(Continuous Receive) = 1 to receive
PIE1 &= ~0x04; // bit3:TX1IE(Transmit Interrupt) = 0
return;
}
txBufIdx--;
TX1REG = txBuf[txBufIdx]; // set transmit buffer
}
}
メイン関数
ここまでの処理が実装できていれば、メイン関数で、EUSARTの初期化と受信操作、送信操作を行うのみとなります。
#include "pic16f15245.h" // head file for mpu
void EUSART_init(void);
void receive_data(unsigned char[]);
void transmit_data(void);
int main() {
int n = 10; // number of data
unsigned char data[n];
EUSART_init();
INTCOPN |= 0xc0; // bit7:GIE(Global Interrupt Enable) = 1
// bit6:PIE(Peripheral Interrupt Enable) = 1
while (1) {
receive_data(data); // read -> data[]
/* make sample data to transmit */
for (int i = 0; i < n; i++) {
data[i] = 'a' + i;
}
/* */
transmit_data(data, n); // transmit data[]
}
return 0;
}
