私は単純なシリアルプロトコルを扱わなければなりません。プロトコルのフォーマットはStart byte、Length、Data bytes、Check sumです。 データ通信にUARTを使用しています。私はプロトコルを処理する最良の方法が何であるかを知りたい。 最初の方法では、ISR自体で受信を処理する予定でした。チェックサムの検証はISR内では処理されません。私のISRは以下のコードのように見えるかもしれません。しかし、ISRは少し時間がかかります(コードは長すぎますが、多くのif文があり、長すぎるとは限りません)。アトミック性を避けるためにISR内のプロトコルを処理する
2番目の方法では、ISRは受信バッファにデータをダンプするだけでメインプログラムが処理しますプロトコルを処理する。 ISRは短いですが、アトミック性の問題を避けるために、ISRを頻繁に無効/有効にする必要があります。これによりパフォーマンス上の問題が発生し、頻繁にISRを無効にするとデータが失われる可能性があります。
どの方法が最適ですか?このようなプロトコル実装の例はどれですか? 注:以下のコードは単なる概説であり、まだテストされていません。論理的なエラーはほとんどありません。
#ifndef TRUE
#define TRUE 1
#endif // TRUE
#ifndef FALSE
#define FALSE 0
#endif // TRUE
#define NUM_START_BYTES 1
#define LENGTH_BYTE_POSITION (NUM_START_BYTES)
#define START_BYTE1 0xAA
#define START_BYTE2 0x55
#define END_BYTE 0x0A
#ifdef CHECKSUM_DISABLED
#define CHECKSUM_BYTES 0
#elif defined SIMPLE_CHECKSUM
#define CHECKSUM_BYTES 1
#else
#define CHECKSUM_BYTES 2
#endif // CHECKSUM_DISABLED
#define NUM_START_BYTES 1
#define LENGTH_BYTE_POSITION (NUM_START_BYTES)
#define START_BYTE1 0xAA
#define START_BYTE2 0x55
#define END_BYTE 0x0A
#define UDR0 0 // Only temporarily declared it as 0. It is actually a register in processor.
enum FRAME_RECEIVE_STATUS
{
FRAME_SUCCESS=0,
START_BYTE_RECVD=1,
RECV_PROGRESS=2,
FRAME_RECEIVED=3,
CHECKSUM_ERROR=4,
FRAME_NOT_RECEIVED=5,
};
volatile enum FRAME_RECEIVE_STATUS frameStatus=FRAME_NOT_RECEIVED;
#define RX_MAX_SIZE 32 // size for received data buffer.
volatile uint8_t RxData[RX_MAX_SIZE];
volatile uint8_t RxHead=0; // Initialize the RxHead to 0
volatile uint8_t frameLength=0; // Overall length of the received data
/**RX Complete interrupt service routine
// Receive the data and write to buffer if buffer is not full
Initially frameStatus=FRAME_NOT_RECEIVED;
This protocol supports, 0, 1 or 2 start bytes and indicated by NUM_START_BYTES
As soon as first START_BYTE is verified, frameStatus changes to START_BYTE_RECVD.
As soon as second start byte is received, frameStatus changes to RECV_PROGRESS.
That means as soon as START Bytes are verified (It could be 0 1 or 2), frameStatus changes to RECV_PROGRESS
Packet Format:
Start Byte1 (optional), Start byte2 (optional), Length=n, data bytes = n-check sum bytes, one or two check sum bytes
Length includes data bytes and check sum
Checksum may be 0, 1 or 2 bytes and indicated by CHECKSUM_BYTES field
*/
void myRxISR()
{
// If buffer is full, we cannot transfer data. We probably want to discard the data if buffer is full.
// Yet to decide on this
if(RxHead<RX_MAX_SIZE)
{
RxData[RxHead++]=UDR0;
frameLength++;
if(frameStatus==RECV_PROGRESS) //Packet reception is already started
{
// We need to check if all bytes including checksum is received
//First verify the length field. Length field is immediately after START_BYTE fields
if(frameLength==CHECKSUM_BYTES+1)
{
//Minimum 1 byte must be there in any command excluding check sum
// In case the data length is less than 1+checksum bytes,
//we need to completely discard the transaction.
// Length is available in RxData[NUM_START_BYTES]
if(RxData[NUM_START_BYTES]<CHECKSUM_BYTES+1)
{
frameStatus=FRAME_NOT_RECEIVED; // Discard the data
RxHead=0; // Clear the received data buffer
}
}
else // Length is already received and verified. Receive other data bytes and CS
{
// Once the length is received, we need to count as many bytes as length
//and receive the complete the frame.
if(frameLength >= RxData[NUM_START_BYTES]+NUM_START_BYTES+1) //1 for length field itself
{
// Finished receiving the complete frame
//At the end, frameRecived flag must be set.
frameStatus=FRAME_RECEIVED;
}
else
{
//Nothing needs to be done. Just data bytes are being received
}
}
}
else
{
// Check if START_BYTE is present in this protocol or not.
// This code supports 0, 1 or 2 start bytes.
if(NUM_START_BYTES)
{
//First wait for the first START_BYTE. If first START_BYTE is received,
// check if second start byte is present and verify the second start byte.
// As soon as first start byte is received, status changes to START_BYTE_RECVD
if((frameStatus==START_BYTE_RECVD))
{
// first byte is received already. This is the second byte
// Need to verify the second Byte in case there are two bytes
// In case there is only one start byte, control will not come here anyway
if(RxData[RxHead-1]==START_BYTE2)
{
frameStatus=RECV_PROGRESS;
}
else
{
//Discard data
RxHead=0;
frameStatus=FRAME_NOT_RECEIVED;
}
}
else // Just First start Byte is received
{
if(RxData[RxHead-1]==START_BYTE1)
{
if(NUM_START_BYTES>1) // 2 start bytes only possible in this protocol
{
// We need to wait for start byte2 next
frameStatus=START_BYTE_RECVD;
}
else
{
// Only one start byte. So start byte reception is successful
frameStatus=RECV_PROGRESS;
}
}
else
{
//Discard data
RxHead=0;
//frameStatus already FRAME_NOT_RECEIVED
//frameStatus=FRAME_NOT_RECEIVED;
}
}
}
else // NUM_START_BYTES=0. Means we directly start reception without any start bytes
{
frameStatus=RECV_PROGRESS;
}
}
}
else
{
//In case buffer is full, we need to see what to do.
// May be discard the data received.
frameStatus=FRAME_NOT_RECEIVED; // Discard the data
RxHead=0; // Clear the received data buffer
}
}
*リングバッファ*または*キュー*を調べることができます。 –
isrを無効にする必要はありません。単純に書き込みバッファリングを使用します。読取りポインタ。可能なオーバーフローを正しく処理するだけです – Ctx
isrコードをできるだけ短くしておくことは、常にベスト・アイデアです。 – LPs