我在 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 端口。
下面是 STM 到 SARA 连接的图像(SARA 板上的 RX 和 TX 已切换):
问题:
将 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_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL,
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, 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++;
}
}
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_MODE_OUTPUT_2_MHZ,
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,
GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL,
GPIO13);
uart_setup();
xTaskCreate(task1, "task1", 100, NULL, configMAX_PRIORITIES - 1, NULL);
vTaskStartScheduler();
for (;;)
;
return 0;
}
以下是在 USART3 上收听时 在minicom中观察到的输出示例。
我们已经通过与其他模块(例如其他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, uint32_t usartDst, 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;
}