串口通信

STM32串口通信有3种方式:轮询(阻塞式)、中断、DMA。我不亮堂搁浅模式的串口通信有怎样适合的利用场景:每接收/发送一个字节,就要暴发一次暂停,那对CPU反而是一种浪费。使用Cube
HAL,轮询式的串口通信最简便了,发送和接收数据分别有一个函数:

HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);

Timeout
参数给 HAL_MAX_DELAY
常量,则最为超时,函数一贯不通,直到暴发/接收数据达成。

STM32F303RE
有3个 USART 和 2个 UART,而 USART 也得以干活在异步情势,相当于一个
UART。Nucleo 的 ST-LINK 部分也还要落到实处了 USB-TTL 转换,与 MCU 的 USART2
连接。由此,将 C 的正式输入输出(<stdio.h>)重定向到 USART2
就像一个挺不错的调试选项。

ARM
GCC 使用的是 newlib-nano 标准 C 库。要利用 newlib-nano,并将 stdio
重定向到串口,gcc 选项和重定向的贯彻可参考 ARM GCC 附带的 retarget
示例,其路径为 share\gcc-arm-none-eabi\samples\src\retarget。概括起来:

  • 指定 C 编译器选项:
    -fno-builtin
  • 指定 linker(ld.exe)选项:
    –specs=nano.specs、–specs=nosys.specs
  • 贯彻函数 _read()、_write()
    ,其原型如下。_read() 函数从串口读取数据,_write()
    将数据写到串口。stdio 函数如 printf()、getchar()
    等将最终调用那三个函数完毕输入输出

 

int _read (int fd, char *ptr, int len);
int _write (int fd, char *ptr, int len);

 

在 main()
函数中,首先打印一个字符串,然后进入主循环,将接纳到的字符原样重回。如下:

 

    ...
    puts("Good judgments come from experiences. ");

    uint8_t buf[32];

    while (1) { 
        HAL_UART_Receive(&huart2, buf, 1, HAL_MAX_DELAY);
        putchar(buf[0]);
        fflush(stdout);
    }

 

我意识,在写出多少(字符/字符串)时,直到 \n
字符时,数据才真的写到串口。那应该是 stdio 的缓冲机制。puts()
自动在字符串末尾增添了一个 \n,由此都回立时写出到串口。而 putchar()
则须要显式 flush 一下。

_write()
重定向落成很简单,直接调用 HAL_UART_Transmit():

 

#include "main.h"
#include "stm32f3xx_hal.h"
#include "usart.h"

int _write (int fd, char *ptr, int len)
{
  /* Write "len" of char from "ptr" to file id "fd"
   * Return number of char written.
   * Need implementing with UART here. */

    HAL_UART_Transmit(&huart2, (uint8_t *) ptr, len, HAL_MAX_DELAY);

  return len;
}