考虑在我的微控制器单元(MCU)上运行的代码:
while(1){
do_stuff;
if(packet_from_PC)
send_data_via_gpio(new_packet); //send via general purpose i/o pins
else
send_data_via_gpio(default_packet);
do_other_stuff;
}
MCU也通过UART连接到PC。无论何时PC向MCU发送数据,都会发送 new_packet , 否则发送 default_packet 。每个数据包可以是5个或更多字节,具有预定义的数据包结构。
我的问题是:
1.我应该在UART中间服务程序(ISR)中使用PC收到整个数据包吗?在这种情况下,我必须实施 ISR中的状态机来组装数据包(if-else或switch-case块可能很长)。
OR
2.让PC发送某种REQUEST命令(一个字节),在我的ISR中检测它设置一个标志,单独禁用UART中断并通过检查标志和我的while(1)循环形成数据包轮询UART?在这种情况下,UART中断将在整个数据包形成后的while(1)循环中重新启用。
答案 0 :(得分:1)
这不是唯一的两个选择,第二个似乎不是最理想的。
我的第一种方法是一个简单的循环队列,并从ISR将字节推入其中,并从主循环中读取字节。这样你就可以获得一个小而简单的ISR,并且可以在主循环中进行处理而不会禁用中断。
假设您可以明智地编码ISR,那么第一种选择是可能的。您可能希望在处理构造数据包时有超时;您需要能够在ISR中正确处理。这取决于线路速度,MCU的速度以及您还需要做什么。
更新
在ISR中这样做当然是合理的。但是,使用循环队列非常简单,在您的技巧包中有标准实现。这是一个循环队列实现;读者和作家可以独立运作。
#ifndef ARRAY_ELEMENTS
#define ARRAY_ELEMENTS(x) (sizeof(x) / sizeof(x[0]))
#endif
#define QUEUE_DEFINE(name, queue_depth, type) \
struct queue_type__##name { \
volatile size_t m_in; \
volatile size_t m_out; \
type m_queue[queue_depth]; \
}
#define QUEUE_DECLARE(name) struct queue_type__##name name
#define QUEUE_SIZE(name) ARRAY_ELEMENTS((name).m_queue)
#define QUEUE_CALC_NEXT(name, i) \
(((name).i == (QUEUE_SIZE(name) - 1)) ? 0 : ((name).i + 1))
#define QUEUE_INIT(name) (name).m_in = (name).m_out = 0
#define QUEUE_EMPTY(name) ((name).m_in == (name).m_out)
#define QUEUE_FULL(name) (QUEUE_CALC_NEXT(name, m_in) == (name).m_out)
#define QUEUE_NEXT_OUT(name) ((name).m_queue + (name).m_out)
#define QUEUE_NEXT_IN(name) ((name).m_queue + (name).m_in)
#define QUEUE_PUSH(name) ((name).m_in = QUEUE_CALC_NEXT((name), m_in))
#define QUEUE_POP(name) ((name).m_out = QUEUE_CALC_NEXT((name), m_out))
像这样使用:
QUEUE_DEFINE(bytes_received, 64, unsigned char);
QUEUE_DECLARE(bytes_received);
void isr(void)
{
/* Move the received byte into 'c' */
/* This code enqueues the byte, or drops it if the queue is full */
if (!QUEUE_FULL(bytes_received)) {
*QUEUE_NEXT_IN(bytes_received) = c;
QUEUE_PUSH(bytes_received);
}
}
void main(void)
{
QUEUE_INIT(bytes_received);
for (;;) {
other_processing();
if (!QUEUE_EMPTY(bytes_received)) {
unsigned char c = *QUEUE_NEXT_OUT(bytes_received);
QUEUE_POP(bytes_received);
/* Use c as you see fit ... */
}
}
}