微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 STM32F1 Blue 药丸上的多个 USART 连接之间发出中继消息 编辑:

如何解决在 STM32F1 Blue 药丸上的多个 USART 连接之间发出中继消息 编辑:

我在 USART 连接上设置了一个 STM32F103C8T8 和两个模块(Sara 和 ESP82)。 我们目前正在使用 libopencm3 和 FreeRTOS 库。

目标

我希望 STM 向 Sara 模块发送 AT 命令,接收响应并将此消息从 Sara 模块转发到 ESP 模块。全部通过 USART 连接。

设置说明:

STM 连接到 USART2 上的 Sara R412 LTE-M/nb-iot 板,ESP8266 连接到 USART3。

Sara R412 的 PWR_ON 和 RST 分别连接到 A5 和 A4。这些用于重新启动以正确打开 Sara 模块。

STM32 有一些硬编码命令,这些命令被发送到 USART2 上的 Sara 模块,这些命令应该回答,然后这个回答应该由 STM32 中继到 USART3 上的 ESP8266。

出于测试目的,ESP 未连接 atm,我们只是使用 TTL 在同一个 USART 端口上侦听。

以下是 TTL 到 STM 连接的图像:

TTL to STM connection

下面是STM到Sara连接的图片Sara板上的RX和TX已切换):

STM to SARA connection

问题:

将来自 Sara 的消息应答中继到 ESP8266 时,出现问题。我们遇到了一些连接,消息被正确转发,但是它非常不一致,而且大多数时候它卡在一个字符上。

我们尝试过的: 我们正在使用 TTL 连接器和 minicom 来监听 USART 连接并查看问题出在哪里。我们观察到 Sara 模块正确地接收了来自 STM32 的命令,并正确地回答了相应的消息。接下来发生的事情是 STM32 应该正确接收消息,但是在侦听 USART3(ESP usart 连接)时,消息有时正确,有时不正确。

我们也尝试过降低波特率,但结果没有差异。

STM32 可以在 USART2 和 USART3 上正常发送命令,但是有时无法正确地(或根本没有)正确地传递应该中继的答案。

我们怀疑问题出在我们的 usart_get_string 方法中,该方法将来自一个 USART 的消息中继到另一个 USART 连接:

static void usart_get_string(uint32_t usartSrc,uint32_t usartDst,uint16_t str_max_size)
{
    uint8_t received = 'V';
    uint16_t itr = 0;
    uint8_t recvPrev;

    while (itr < str_max_size)
    {
        if (!((USART_SR(USART2) & USART_SR_RXNE) == 0))
        {
            received = usart_recv_blocking(usartSrc);
        }
        uart_putc(received,usartDst);

        if (recvPrev == 'O' && received == 'K')
        {
            break;
        }
        recvPrev = received;
        uart_putc_blocking(itr,usartDst); // Somehow doesn't work at all without this
        itr++;
    }
}

方法非常简单,received = usart_recv_blocking(usartSrc); 部分可能应该在第一个 if 语句中,但如果我们这样做,则不会返回任何内容

包括完整代码

#include <FreeRTOS.h>
#include <task.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/usart.h>

#define MSG_LENGTH 512

static void
uart_setup(void)
{

    // Sara SETUP
    rcc_periph_clock_enable(RCC_GPIOA);
    rcc_periph_clock_enable(RCC_USART2);

    gpio_set_mode(GPIOA,GPIO_MODE_OUTPUT_50_MHZ,GPIO_CNF_OUTPUT_ALTFN_PUSHPULL,GPIO_USART2_TX);

    usart_set_baudrate(USART2,115200);
    usart_set_databits(USART2,8);
    usart_set_stopbits(USART2,USART_STOPBITS_1);
    usart_set_mode(USART2,USART_MODE_TX_RX);
    usart_set_parity(USART2,USART_PARITY_NONE);
    usart_set_flow_control(USART2,USART_FLOWCONTROL_NONE);
    usart_enable(USART2);

    // ESP SETUP
    rcc_periph_clock_enable(RCC_GPIOB);
    rcc_periph_clock_enable(RCC_USART3);

    gpio_set_mode(GPIOB,GPIO_USART3_TX);

    usart_set_baudrate(USART3,115200);
    usart_set_databits(USART3,8);
    usart_set_stopbits(USART3,USART_STOPBITS_1);
    usart_set_mode(USART3,USART_MODE_TX_RX);
    usart_set_parity(USART3,USART_PARITY_NONE);
    usart_set_flow_control(USART3,USART_FLOWCONTROL_NONE);
    usart_enable(USART3);
}

static inline void
uart_putc(uint8_t ch,uint32_t usart_port)
{
    usart_send(usart_port,ch);
}

static inline void
uart_putc_blocking(uint8_t ch,uint32_t usart_port)
{
    usart_send_blocking(usart_port,ch);
}

static inline void uart_puts(uint8_t *s,uint32_t usart_port)
{
    while (*s != '\0')
    {
        uart_putc_blocking(*s,usart_port);
        gpio_toggle(GPIOC,GPIO13);
        vTaskDelay(pdMS_TO_TICKS(100));
        s++;
    }
    uart_putc_blocking('\r',usart_port);
    uart_putc_blocking('\n',usart_port);
}


static void usart_get_string(uint32_t usartSrc,usartDst); // Somehow doesn't work at all without this
        itr++;
    }
}

static void
task1(void *args __attribute__((unused)))
{

    uint8_t esp[] = "Hi ESP";
    uint8_t AT[] = "ATI";

    uart_puts(esp,USART3);

    // Power_on Start for Sara module
    vTaskDelay(pdMS_TO_TICKS(500));
    gpio_clear(GPIOA,GPIO5);
    vTaskDelay(pdMS_TO_TICKS(5000));
    gpio_set(GPIOA,GPIO5);

    gpio_set_mode(
        GPIOA,GPIO_MODE_OUTPUT_2_MHZ,GPIO_CNF_INPUT_FLOAT,GPIO4); //RESET_N
    gpio_set_mode(
        GPIOA,GPIO_CNF_OUTPUT_PUSHPULL,GPIO5); //PWR_ON

    vTaskDelay(pdMS_TO_TICKS(10000));

    for (;;)
    {
        uart_puts(esp,USART3);
        vTaskDelay(pdMS_TO_TICKS(500));

        uart_puts(AT,USART2);

        usart_get_string(USART2,USART3,MSG_LENGTH);
        vTaskDelay(pdMS_TO_TICKS(10000));
    }
}

int main(void)
{

    rcc_clock_setup_in_hse_8mhz_out_72mhz(); // Blue pill
    // PC13:
    rcc_periph_clock_enable(RCC_GPIOC);
    gpio_set_mode(
        GPIOC,GPIO13);

    uart_setup();

    xTaskCreate(task1,"task1",100,NULL,configMAX_PRIORITIES - 1,NULL);
    vTaskStartScheduler();

    for (;;)
        ;
    return 0;
}

以下是在 minicom 中监听 USART3 时观察到的输出示例。

enter image description here

我们通过与其他ESP等其他模块互换验证接线应该正确,接线应该正确。 电源来自 TTL(3v3)并进入面包板,STM32 和 Sara R412 板从这里获得电源。

编辑:

我按照建议测试了 FreeRTOS 计时器,但不幸的是无法解决我的问题:

我通过以下方式在 main 方法中创建了一个 FreeRTOS 计时器:

    timerHndl1 = xTimerCreate(
      "timer1",/* name */
      pdMS_TO_TICKS(400),/* period/time */
      pdFALSE,/* auto reload */
      (void*)0,/* timer ID */
      vTimerCallback1SecExpired); /* callback */

get_string() 方法中,我将计时器重置为第一件事。更新后的方法如下所示:

static bool usart_get_string(uint32_t usartSrc,uint16_t str_max_size)
{
    uint8_t received = 'V';
    uint16_t itr = 0;
    uint8_t recvPrev = 'Q';
    bool timeoutflag;



    // Todo for you: check the UART for error conditions here (like 
    // overrun or framing errors,and clear the errors if any have occurred
    // before we start the receive

    //restart timer:
    if ( xTimerReset(timerHndl1,10 ) != pdPASS )
    {
        timeoutflag = true;
    }
    else
    {
        timeoutflag = false;
    }

    while ((itr < str_max_size) && (!timeoutflag))
    {
        while ( (!((USART_SR(USART2) & USART_SR_RXNE) == 0)) &&
                (itr < str_max_size) )
        {
            received = usart_recv_blocking(usartSrc);
            uart_putc(received,usartDst);

            if (recvPrev == 'O' && received == 'K')
            {
                return;
            }
            recvPrev = received;
            itr++;
        }


        // if timer times out
        if ( xTimerIsTimerActive(timerHndl1) == pdFALSE )
        {
            timeoutflag = true;
        }
    }

    return !timeoutflag;
}

解决方法

看起来条件 (!((USART_SR(USART2) & USART_SR_RXNE) == 0)) 再也不会为真了。请记住,字符是在有限时间内接收的,您必须留出一些时间来接收它们。

我会考虑将 usart_get_string 函数修改为如下所示:

// timeout in ms
static bool usart_get_string(uint32_t usartSrc,uint32_t usartDst,uint16_t str_max_size,uint16_t timeout)
{
    uint8_t received = 'V';
    uint16_t itr = 0;
    uint8_t recvPrev;
    bool timeoutflag;

    // TODO for you: check the UART for error conditions here (like 
    // overrun or framing errors,and clear the errors if any have occurred
    // before we start the receive

    // add some code here
    // TODO: start a timer in the RTOS here (using timeout)
    // pseudo code
    Start a timer of "timeout" ms

    timeoutflag = false;

    while ((itr < str_max_size) && (!timeoutflag))
    {
        while ( (!((USART_SR(USART2) & USART_SR_RXNE) == 0)) &&
                (itr < str_max_size) )
        {
            received = usart_recv_blocking(usartSrc);
            uart_putc(received,usartDst);

            if (recvPrev == 'O' && received == 'K')
            {
                return;
            }
            recvPrev = received;
            itr++;
        }

        // psueudo code
        if (RTOS timer has timed out)
        {
            timeoutflag = true;
        }
    }

    return !timeoutflag;
}

我还删除了 uart_putc_blocking 函数的调用,因为它现在应该可以工作了。 (我怀疑这形成了某种延迟,刚好足以接收下一个字符。我还建议对 usart_get_string 函数设置某种超时。如果发生超时,该函数将返回 false。

您可能会考虑的另一个建议:目前您检查字母“O”和“K”,但您可能希望将 usart_get_string 例程扩展到 \r\n(或其他任何调制解调器发送的行尾序列)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。