问题描述
我有一个项目,我想在 dsPIC 上构建一个简单的接口,它允许我通过 UART 以 ASCII 格式向微控制器发送命令。它将仅用于调试,所以目前我不关心错误检查和确认。目的是能够使用终端,向 mcu 发送命令(可能是参数化的),并接收响应。
目前我在 UART1 RX ISR 中有一个状态机,它查找 FRAME_START
符号,然后将所有后续字符放入循环缓冲区,直到遇到 FRAME_END
字符。如果发送方在传输时有很大的延迟,我还使用计时器来重新启动状态机。
即使代码最初仅用于调试,它也可能需要扩展为更健壮的解决方案,以便进入生产环境,或作为其他项目的调试模板,所以我想制作它更健壮,我很乐意收到有关如何做到这一点的评论。我(目前)关注的要点是:
- 我应该在 UART ISR 中使用循环缓冲区,还是简单地填充一个大小等于最大命令长度的线性缓冲区
- 如何接收和存储多个命令 - 我应该吗
- 如何解析传入命令的参数 - 例如,如果它是类似
$WRITE_REGISTER,100,4;
的东西,那么获取参数 100 和 4 (atoi
?) 的好方法是什么? - 接收命令时调用函数的好模式是什么
代码示例如下。我也读过一些关于 here 和 here 类似主题的优秀帖子,但这些更关注协议实现,我离这还很远。
/* State machine states */
#define IDLE 0x01
#define COMMAND 0x02
#define AFTER_ESCAPE 0x03
/* Message delimiters */
#define FRAME_START 0x24 // '$'
#define ESCAPE_SYMBOL 0x2F // '/'
#define FRAME_END 0x3B // '/'
// UART ISR variables
#define SER_FIFO_MASK 0x10
volatile uint16_t rxfifo[8];
volatile uint16_t rxiptr = 0;
volatile uint16_t command_received = 0;
// Static variables for the TMR2 ISR
static volatile uint16_t tmr2_isr_counter = 0;
static volatile uint16_t tmr2_char_timeout = 0;
/*
* TMR2 ISR
*/
void __attribute__((__interrupt__,no_auto_psv)) _T2Interrupt(void)
{
IFS0bits.T2IF = 0; // Clear interrupt flag
tmr2_isr_counter++;
if (tmr2_isr_counter == 100) // 10 seconds
{
T2CONbits.TON = 0; // Stop timer
tmr2_char_timeout = 1; // Set flag
}
}
/*
* UART1 TX ISR
*/
void __attribute__((interrupt,no_auto_psv)) _U1RXInterrupt(void)
{
static unsigned short state = IDLE; // A static state to keep track of the message
uint8_t ch = U1RXREG; // copy char from buffer to temporary variable
if (U1STAbits.OERR) _OERR = 0; // If overflow,clear flag and buffer
_U1RXIF = 0; // Clear IF
if (ch <= 0x1F || ch >= 0x60) return; // discard char if it's outside allowed charset
// Reset state machine on timeout
if (tmr2_char_timeout == 1)
{
state = IDLE; // Set flag to be polled in main,which should send an error message? And reset state
rxiptr = 0;
}
switch (state) {
case IDLE: // If state is IDLE,examine char; if char is equal to $,change state
if (ch == (char) FRAME_START) {
state = COMMAND;
START_CHAR_TIMER();
}
break;
case COMMAND: // While COMMAND state,every char is put into the buffer,which is free to overflow.
START_CHAR_TIMER();
if (ch == (char) ESCAPE_SYMBOL) { // Escape char is #
state = AFTER_ESCAPE;
} else if (ch == (char) FRAME_END) { // If FRAME_END (;) char is received,raise the flag and change state back to WAIT HEADER
state = IDLE;
command_received = 1; // main() should poll and clear that flag
} else {
rxfifo[rxiptr] = ch;
rxiptr++;
if(rxiptr == SER_FIFO_MASK) rxiptr = 0; // Wrap-around buffer head
}
break;
case AFTER_ESCAPE: // Put the character following the escape symbol in the command buffer
START_CHAR_TIMER();
rxfifo[rxiptr] = ch;
rxiptr++;
if(rxiptr == SER_FIFO_MASK) rxiptr = 0;
break;
default: break;
}
}
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)