我必須處理簡單的串行協議。協議格式爲起始字節,長度,數據字節和校驗和。 我正在使用UART進行數據通信。我想知道處理協議的最佳方式是什麼。 在第一種方法中,我計劃在ISR內部處理接待。 ISR內部不會處理校驗和驗證。我的ISR可能看起來像下面的代碼(考慮通用微控制器)。但是ISR很少冗長(雖然代碼冗長,但有很多if語句,最終可能不會太冗長)處理ISR內部的協議,以避免原子性
在第二種方法中,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