如何在MCU的串行端口上接收数据包? [英] How to receive packets on the MCU's serial port?

查看:116
本文介绍了如何在MCU的串行端口上接收数据包?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑此代码在我的微控制器单元(MCU)上运行:

  while(1){

do_stuff;
if(packet_from_PC)
send_data_via_gpio(new_packet); //通过通用I / O引脚
发送
send_data_via_gpio(default_packet);
do_other_stuff;

}

MCU也通过UART连接到PC。每当PC将数据发送到MCU时,都会发送 new_packet ,否则发送
,否则发送 default_packet 。每个数据包可以是5个字节或更多字节,且带有预定义数据包结构。



我的问题是:



1。我应该从PC内使用PC接收整个数据包吗? UART中断服务程序(ISR)?在这种情况下,我必须在ISR内实现
a状态机来组装数据包(如果使用if-else或switch-case块,则可能很长)。

 

2。让PC发送某种一个REQUEST命令(一个字节),在我的ISR中检测到它,设置一个标志,单独禁用UART中断,并通过检查该标志并轮询UART在我的while(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; \
类型m_queue [queue_depth]; \
}

#define QUEUE_DECLARE(name)struct queue_type __ ## name name

#define QUEUE_SIZE(name)ARRAY_ELEMENTS((name).m_queue)

#定义QUEUE_CALC_NEXT(name,i)\
((((name).i ==(QUEUE_SIZE(name)-1)))?0:(((name).i + 1) ))

#定义QUEUE_INIT(名称)(名称).m_in =(名称).m_out = 0

#定义QUEUE_EMPTY(名称)((名称).m_in = =(名称).m_out)

#定义QUEUE_FULL(名称)(QUEUE_CALC_NEXT(名称,m_in)==(名称).m_out)

#定义QUEUE_NEXT_OUT(名称) ((名称).m_queue +(名称).m_out)
#定义QUEUE_NEXT_IN(名称)((名称).m_queue +(名称).m_in)

#定义QUEUE_PUSH(名称) ((name。 $ c>

像这样使用:

  QUEUE_DEFINE(bytes_received,64,unsigned char); 
QUEUE_DECLARE(bytes_received);

void isr(void)
{
/ *将接收到的字节移到'c'* /
/ *此代码使该字节入队,如果队列已满* /
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);
/ *视需要使用c ... * /
}
}
}


Consider this code running on my microcontroller unit(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;

}

The MCU is also interfaced to a PC via a UART.Whenever the PC sends data to the MCU, the new_packet is sent, otherwise the default_packet is sent.Each packet can be 5 or more bytes with a pre defined packet structure.

My question is:

1.Should i receive the entire packet from PC using inside the UART interrut service routine (ISR)? In this case, i have to implement a state machine inside the ISR to assemble the packet (which can be lengthy with if-else or switch-case blocks).

                  OR

2.Have the PC send some sort of a REQUEST command (one byte),detect it in my ISR set a flag, disable UART interrupt alone and form the packet in my while(1) loop by checking for the flag and polling the UART?In this case the UART interrupt would be re-enabled in the while(1) loop after the entire packet is formed.

解决方案

Those are not the only two choices, and the second one seems suboptimal.

My first approach would be to a simple circular queue, and push bytes into it from the ISR and read bytes from in your main loop. That way you have a small and simple ISR and you and do the processing in your main loop without disabling interrupts.

The first choice is possible assuming you can code the ISR sensibly. You probably want to have timeouts when dealing with constructing packets; you need to be able to handle that correctly in your ISR. It depends on the line speed, the speed of your MCU and what else you need to do.

Update:

Doing it in the ISR is certainly reasonable. However, using a circular queue is pretty straightforward with a standard implementation in your bag of tricks. Here is a circular queue implementation; readers and writers can operate independently.

#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))

Use it like this:

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 ... */
        }
    }
 }

这篇关于如何在MCU的串行端口上接收数据包?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆