Embedded 更改函数调用的位置会中断uart上的通信

Embedded 更改函数调用的位置会中断uart上的通信,embedded,stm32,microcontroller,Embedded,Stm32,Microcontroller,今天我遇到了一个非常令人困惑的问题。我通过UART将数据从pc发送到MCU,反之亦然。 我在使用中断。 我有两种不同版本的代码。它们看起来几乎一样,但其中一个工作不正常-数据没有发送回pc(第一个版本工作正常)。我不知道为什么,但我想知道,为了在将来更快地发现此类问题 代码的完整版本-> 分支机构: uart\u不工作\u版本 uart\u工作版本 重要文件位于:src/app/src 我可以让它保持工作版本的状态,但我想了解问题的本质,以避免将来出现此类问题 这两个版本之间的关键区别:

今天我遇到了一个非常令人困惑的问题。我通过UART将数据从pc发送到MCU,反之亦然。 我在使用中断。 我有两种不同版本的代码。它们看起来几乎一样,但其中一个工作不正常-数据没有发送回pc(第一个版本工作正常)。我不知道为什么,但我想知道,为了在将来更快地发现此类问题

代码的完整版本-> 分支机构:

  • uart\u不工作\u版本
  • uart\u工作版本
重要文件位于:src/app/src

我可以让它保持工作版本的状态,但我想了解问题的本质,以避免将来出现此类问题

这两个版本之间的关键区别:

  • 版本1->我一直在调用(主循环中的)函数server_check(),它检查MCU是否已经接收到64kb,如果已经接收到,那么这些字节将被复制到write_buffer,然后发送回pc
  • 版本2->我不使用function server_check,因为它的功能被移动到server_run,它从main调用一次,然后使用它自己的循环永不停止,在这个循环中几乎有与版本1中function server_check相同的代码
微控制器:STM32F103 我正在使用g++8.2

顺从标志:

设置(编译器\u CXX\u标志“-fno使用cxa-atexit-O1-fno异常-g”)

设置(编译器标志)-fdata节-fffunction节-DNDEBUG-Wall -Werror-g)

通常,改变函数调用的位置会破坏MCU的功能,这是怎么可能的

第1版。 //main.cpp

int main()
{
  //init clock etc

  server_init();
  server_run();

  while(true)
  {
    server_check();
  }
}
//server.cpp

extern "C" {
  #include <libopencm3/stm32/usart.h> 
  #include <libopencm3/stm32/gpio.h>
  #include <libopencm3/stm32/rcc.h>
  #include <libopencm3/cm3/nvic.h>
}

#include <server.hpp>
#include <stdint.h>
#include <ring_buffer.hpp>
#include <target.h>

static uint8_t w_buffer[1024]; // write buffer
static uint8_t r_buffer[1024]; // read buffer

utils::containers::RingBuffer write_rb{w_buffer, sizeof(w_buffer)};
utils::containers::RingBuffer read_rb{r_buffer, sizeof(r_buffer)};

static void sendData()
{
  if (write_rb.capacity() != 0)
  {
    usart_send(USART1, write_rb.read());
    usart_enable_tx_interrupt(USART1);
  }
  else 
  {
    usart_disable_tx_interrupt(USART1);
  }
}

static void readData()
{
  auto data = usart_recv(USART1);
  read_rb.write(static_cast<uint8_t>(data));

  // usart_enable_rx_interrupt(USART1);
}

void server_init()
{
  //RCC
  rcc_periph_clock_enable(RCC_USART1);

  //GPIO
  gpio_set_mode(GPIO_BANK_USART1_TX, GPIO_MODE_OUTPUT_50_MHZ, 
    GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART1_TX);

  gpio_set_mode(GPIO_BANK_USART1_RX, GPIO_MODE_INPUT, 
    GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, GPIO_USART1_RX);

  //USART
  usart_set_mode(USART1, USART_MODE_TX_RX);
  usart_set_baudrate(USART1, 9600);
  usart_set_parity(USART1, USART_PARITY_NONE);
  usart_set_databits(USART1, 8);
  usart_set_stopbits(USART1, 1);
  usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);
  usart_enable_rx_interrupt(USART1);

  //ISR
  nvic_enable_irq(NVIC_USART1_IRQ);
  
  //Enable 
  usart_enable(USART1);
}


void server_run()
{
}

void server_check()
{
    if (read_rb.capacity() == 64)
    {
      while (read_rb.capacity() != 0)
      {
        write_rb.write(read_rb.read());
      }

      sendData();
    }
}

void usart1_isr()
{
  if (usart_get_flag(USART1, USART_FLAG_TXE) != 0) 
  {
    sendData();
  }

  if (usart_get_flag(USART1, USART_FLAG_RXNE) != 0) // when data is ready to read
  {
    readData(); 
  }
} 
extern“C”{
#包括
#包括
#包括
#包括
}
#包括
#包括
#包括
#包括
静态uint8_t w_缓冲区[1024];//写缓冲区
静态uint8_t r_缓冲区[1024];//读取缓冲区
utils::containers::RingBuffer write_rb{w_buffer,sizeof(w_buffer)};
utils::containers::RingBuffer read_rb{r_buffer,sizeof(r_buffer)};
静态void sendData()
{
如果(写入容量()!=0)
{
usart_send(usart 1,write_rb.read());
usart_启用_发送_中断(USART1);
}
其他的
{
usart_禁用_发送_中断(USART1);
}
}
静态void readData()
{
自动数据=usart\U recv(USART1);
读写(静态转换(数据));
//usart_启用_接收_中断(USART1);
}
void server_init()
{
//碾压混凝土
rcc外围时钟启用(rcc USART1);
//GPIO
gpio_设置_模式(gpio_银行_USART1_发送,gpio_模式_输出_50_MHZ,
GPIO_CNF_输出_ALTFN_推拉,GPIO_USART1_TX);
gpio_设置_模式(gpio_银行_用户1_接收,gpio_模式_输入,
GPIO_CNF_输出_ALTFN_OPENDRAIN,GPIO_USART1_RX);
//乌萨特
usart_设置_模式(USART1、usart_模式_发送_接收);
usart\U set\U波特率(USART19600);
usart\U集合\U奇偶校验(USART1,usart\U奇偶校验\U无);
usart_集合_数据位(USART1,8);
usart\U set\U停止位(USART1,1);
usart\U设置\U流量控制(USART1,usart\U流量控制\U无);
usart_启用_接收_中断(USART1);
//ISR
nvic_启用_irq(nvic_USART1_irq);
//使能
usart_启用(USART1);
}
void server_run()
{
}
无效服务器检查()
{
如果(读取容量()==64)
{
while(read_rb.capacity()!=0)
{
write_rb.write(read_rb.read());
}
sendData();
}
}
无效usart1_isr()
{
如果(usart\U get\U标志(USART1,usart\U标志)!=0)
{
sendData();
}
如果(usart\U get\U flag(USART1,usart\U flag\U RXNE)!=0)//当数据准备好读取时
{
readData();
}
} 
版本2

main.cpp
int main()
{
  //init clock etc

  server_init();
  server_run();

  while(true)
  {

  }
}

server.cpp

extern "C" {
  #include <libopencm3/stm32/usart.h> 
  #include <libopencm3/stm32/gpio.h>
  #include <libopencm3/stm32/rcc.h>
  #include <libopencm3/cm3/nvic.h>
}

#include <server.hpp>
#include <stdint.h>
#include <ring_buffer.hpp>
#include <Os.hpp>
#include <target.h>

/**
 * 
 *  | MSG_TYPE | |
 * 
 */

static uint8_t w_buffer[1024]; // write buffer
static uint8_t r_buffer[1024]; // read buffer

utils::containers::RingBuffer write_rb{w_buffer, sizeof(w_buffer)};
utils::containers::RingBuffer read_rb{r_buffer, sizeof(r_buffer)};

static void sendData()
{
  if (write_rb.capacity() != 0)
  {
    usart_send(USART1, write_rb.read());
    usart_enable_tx_interrupt(USART1);
  }
  else 
  {
    usart_disable_tx_interrupt(USART1);
  }
}

static void readData()
{
  auto data = usart_recv(USART1);
  read_rb.write(static_cast<uint8_t>(data));

  // usart_enable_rx_interrupt(USART1);
}

void server_init()
{
  //RCC
  rcc_periph_clock_enable(RCC_USART1);

  //GPIO
  gpio_set_mode(GPIO_BANK_USART1_TX, GPIO_MODE_OUTPUT_50_MHZ, 
    GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART1_TX);

  gpio_set_mode(GPIO_BANK_USART1_RX, GPIO_MODE_INPUT, 
    GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, GPIO_USART1_RX);

  //USART
  usart_set_mode(USART1, USART_MODE_TX_RX);
  usart_set_baudrate(USART1, 9600);
  usart_set_parity(USART1, USART_PARITY_NONE);
  usart_set_databits(USART1, 8);
  usart_set_stopbits(USART1, 1);
  usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);
  usart_enable_rx_interrupt(USART1);

  //ISR
  nvic_enable_irq(NVIC_USART1_IRQ);
  
  //Enable 
  usart_enable(USART1);



}


void server_run()
{
  while(true)
  {
    if (read_rb.capacity() == 64)
    {
      while (read_rb.capacity() != 0)
      {
        write_rb.write(read_rb.read());
      }

      sendData();
    }
  }
  
}

void server_check()
{
 
}

void usart1_isr()
{
  if (usart_get_flag(USART1, USART_FLAG_TXE) != 0) 
  {
    sendData();
  }

  if (usart_get_flag(USART1, USART_FLAG_RXNE) != 0) // when data is ready to read
  {
    readData(); 
  }
} 
main.cpp
int main()
{
//初始化时钟等
server_init();
服务器运行();
while(true)
{
}
}
server.cpp
外部“C”{
#包括
#包括
#包括
#包括
}
#包括
#包括
#包括
#包括
#包括
/**
* 
*|味精|U型||
* 
*/
静态uint8_t w_缓冲区[1024];//写缓冲区
静态uint8_t r_缓冲区[1024];//读取缓冲区
utils::containers::RingBuffer write_rb{w_buffer,sizeof(w_buffer)};
utils::containers::RingBuffer read_rb{r_buffer,sizeof(r_buffer)};
静态void sendData()
{
如果(写入容量()!=0)
{
usart_send(usart 1,write_rb.read());
usart_启用_发送_中断(USART1);
}
其他的
{
usart_禁用_发送_中断(USART1);
}
}
静态void readData()
{
自动数据=usart\U recv(USART1);
读写(静态转换(数据));
//usart_启用_接收_中断(USART1);
}
void server_init()
{
//碾压混凝土
rcc外围时钟启用(rcc USART1);
//GPIO
gpio_设置_模式(gpio_银行_USART1_发送,gpio_模式_输出_50_MHZ,
GPIO_CNF_输出_ALTFN_推拉,GPIO_USART1_TX);
gpio_设置_模式(gpio_银行_用户1_接收,gpio_模式_输入,
GPIO_CNF_输出_ALTFN_OPENDRAIN,GPIO_USART1_RX);
//乌萨特
usart_设置_模式(USART1、usart_模式_发送_接收);
usart\U set\U波特率(USART19600);
usart\U集合\U奇偶校验(USART1,usart\U奇偶校验\U无);
usart_集合_数据位(USART1,8);
usart\U set\U停止位(USART1,1);
usart\U设置\U流量控制(USART1,usart\U流量控制\U无);
usart_启用_接收_中断(USART1);
//ISR
nvic_启用_irq(nvic_USART1_irq);
//使能
usart_启用(USART1);
}
void server_run()
{
while(true)
{
如果(读取容量()==64)
{
while(read_rb.capacity()!=0)
{
write_rb.write(read_rb.read());
}
sendData();
}
}
}
无效服务器检查()
{
}
无效usart1_isr()
{
如果(usart\U get\U标志(USART1,usart\U标志)!=0)
{
sendData();
}
如果(usart\U get\U flag(USART1,usart\U flag\U RXNE)!=0)//当数据准备好读取时
{
readData();
}
} 

您应该在版本2代码中尝试以下技巧:

  • main()
    函数中删除
    while(true)
  • ==64
    替换为
    =64
    ,以确保即使跳过一个值且容量变为65,也会处理缓冲区:
    if(read_rb.capacity()>=64)

此外,应避免在除main之外的其他函数中放入无限循环。

您应尝试以下技巧