STM32F7xx —— 串口通信

版权声明:原创不易,转载请注明出处:http://blog.csdn.net/wqx521 https://blog.csdn.net/a1314521531/article/details/86612039

                            STM32F7xx —— 串口通信

目录

STM32F7xx —— 串口通信

一、串口初始化过程

二、几个重要的串口函数

三、几个重要的结构

四、基本接口设计


一、串口初始化过程

1、时钟使能;

2、GPIO初始化;

3、串口波特率设置;

4、串口控制;

5、数据发送与接收

二、几个重要的串口函数

HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart); // 串口初始化

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); // 串口接收

__HAL_UART_ENABLE_IT(__HANDLE__, __INTERRUPT__)  // 串口中断使能

void HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority); // 设置中断优先级

void HAL_NVIC_EnableIRQ(IRQn_Type IRQn); // 使能中断

三、几个重要的结构

// 串口初始化结构体 包含了串口句柄 波特率配置 发送接收缓存 dma等
// 我们只描述前两个基本功能,对效率要求极高可以使用DMA。
typedef struct
{
  USART_TypeDef            *Instance;        /*!< UART registers base address        */

  UART_InitTypeDef         Init;             /*!< UART communication parameters      */

  UART_AdvFeatureInitTypeDef AdvancedInit;   /*!< UART Advanced Features initialization parameters */

  uint8_t                  *pTxBuffPtr;      /*!< Pointer to UART Tx transfer Buffer */

  uint16_t                 TxXferSize;       /*!< UART Tx Transfer size              */

  uint16_t                 TxXferCount;      /*!< UART Tx Transfer Counter           */

  uint8_t                  *pRxBuffPtr;      /*!< Pointer to UART Rx transfer Buffer */

  uint16_t                 RxXferSize;       /*!< UART Rx Transfer size              */

  uint16_t                 RxXferCount;      /*!< UART Rx Transfer Counter           */

  uint16_t                 Mask;             /*!< UART Rx RDR register mask          */

  DMA_HandleTypeDef        *hdmatx;          /*!< UART Tx DMA Handle parameters      */

  DMA_HandleTypeDef        *hdmarx;          /*!< UART Rx DMA Handle parameters      */

  HAL_LockTypeDef           Lock;            /*!< Locking object                     */

  __IO HAL_UART_StateTypeDef    gState;      /*!< UART state information related to global Handle management 
                                                  and also related to Tx operations.
                                                  This parameter can be a value of @ref HAL_UART_StateTypeDef */

  __IO HAL_UART_StateTypeDef    RxState;     /*!< UART state information related to Rx operations.
                                                  This parameter can be a value of @ref HAL_UART_StateTypeDef */

  __IO uint32_t             ErrorCode;   /*!< UART Error code                    */

}UART_HandleTypeDef;
// 串口的操作句柄 如 USART1 USART2 USART3等
typedef struct
{
  __IO uint32_t CR1;    /*!< USART Control register 1,                 Address offset: 0x00 */ 
  __IO uint32_t CR2;    /*!< USART Control register 2,                 Address offset: 0x04 */ 
  __IO uint32_t CR3;    /*!< USART Control register 3,                 Address offset: 0x08 */
  __IO uint32_t BRR;    /*!< USART Baud rate register,                 Address offset: 0x0C */                                               
  __IO uint32_t GTPR;   /*!< USART Guard time and prescaler register,  Address offset: 0x10 */
  __IO uint32_t RTOR;   /*!< USART Receiver Time Out register,         Address offset: 0x14 */  
  __IO uint32_t RQR;    /*!< USART Request register,                   Address offset: 0x18 */
  __IO uint32_t ISR;    /*!< USART Interrupt and status register,      Address offset: 0x1C */
  __IO uint32_t ICR;    /*!< USART Interrupt flag Clear register,      Address offset: 0x20 */
  __IO uint32_t RDR;    /*!< USART Receive Data register,              Address offset: 0x24 */
  __IO uint32_t TDR;    /*!< USART Transmit Data register,             Address offset: 0x28 */
} USART_TypeDef;
// 设置串口的各个参数 波特率 字长 停止位 奇偶校验 收发模式 硬件流 过采样
// 字长:8位/9位
// 停止位:1位/2位
typedef struct
{
  uint32_t BaudRate;                  /*!< This member configures the UART communication baud rate.
                                           The baud rate register is computed using the following formula:
                                           - If oversampling is 16 or in LIN mode,
                                              Baud Rate Register = ((PCLKx) / ((huart->Init.BaudRate)))
                                           - If oversampling is 8,
                                              Baud Rate Register[15:4] = ((2 * PCLKx) / ((huart->Init.BaudRate)))[15:4]
                                              Baud Rate Register[3] =  0
                                              Baud Rate Register[2:0] =  (((2 * PCLKx) / ((huart->Init.BaudRate)))[3:0]) >> 1      */

  uint32_t WordLength;                /*!< Specifies the number of data bits transmitted or received in a frame.
                                           This parameter can be a value of @ref UARTEx_Word_Length */

  uint32_t StopBits;                  /*!< Specifies the number of stop bits transmitted.
                                           This parameter can be a value of @ref UART_Stop_Bits */

  uint32_t Parity;                    /*!< Specifies the parity mode.
                                           This parameter can be a value of @ref UART_Parity
                                           @note When parity is enabled, the computed parity is inserted
                                                 at the MSB position of the transmitted data (9th bit when
                                                 the word length is set to 9 data bits; 8th bit when the
                                                 word length is set to 8 data bits). */

  uint32_t Mode;                      /*!< Specifies whether the Receive or Transmit mode is enabled or disabled.
                                           This parameter can be a value of @ref UART_Mode */

  uint32_t HwFlowCtl;                 /*!< Specifies whether the hardware flow control mode is enabled
                                           or disabled.
                                           This parameter can be a value of @ref UART_Hardware_Flow_Control */

  uint32_t OverSampling;              /*!< Specifies whether the Over sampling 8 is enabled or disabled, to achieve higher speed (up to fPCLK/8).
                                           This parameter can be a value of @ref UART_Over_Sampling */

  uint32_t OneBitSampling;            /*!< Specifies whether a single sample or three samples' majority vote is selected.
                                           Selecting the single sample method increases the receiver tolerance to clock
                                           deviations. This parameter can be a value of @ref UART_OneBit_Sampling */
}UART_InitTypeDef;

四、基本接口设计

我们使用中断接收,普通发送。中断接收到的数据放入队列中,在外部可配置每路串口的功能。

// 抽象出一个串口设备结构体
typedef struct
{
  UART_HandleTypeDef handle; // 串口句柄
  uart_queue_t recv;         // 接收队列
  uart_queue_t send;         // 发送队列
  uint8_t ret;               // 接收的值
} uart_dev_t;

static uart_dev_t uart1_dev;
static uart_dev_t uart2_dev;
// 对外只有通道 不再包含USART1...
typedef enum
{
  UART_CHANNEL_NONE,
  UART_CHANNEL_1,
  UART_CHANNEL_2,
  UART_CHANNEL_NUM
} uart_channel_t;

// 宏定义串口的基本信息 之所以这样写,方便移植修改
#define UART1_CHANNEL             USART1
#define UART1_PREEMPT_PRIO        UART1_PRIORITY
#define UART1_IRQ                 USART1_IRQn
#define UART1_IRQ_FUNC            USART1_IRQHandler
#define UART1_CLK_ENABLE()        __HAL_RCC_USART1_CLK_ENABLE()
#define UART1_TX_PORT             GPIOA
#define UART1_TX_PIN              GPIO_PIN_10
#define UART1_TX_AF               GPIO_AF7_USART1
#define UART1_TX_CONFIG()         GPIOConfigExt(UART1_TX_PORT, UART1_TX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, UART1_TX_AF)
#define UART1_RX_PORT             GPIOA
#define UART1_RX_PIN              GPIO_PIN_9
#define UART1_RX_AF               GPIO_AF7_USART1
#define UART1_RX_CONFIG()         GPIOConfigExt(UART1_RX_PORT, UART1_RX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, UART1_RX_AF)

#define UART2_CHANNEL             USART2
#define UART2_PREEMPT_PRIO        UART2_PRIORITY
#define UART2_IRQ                 USART2_IRQn
#define UART2_IRQ_FUNC            USART2_IRQHandler
#define UART2_CLK_ENABLE()        __HAL_RCC_USART2_CLK_ENABLE()
#define UART2_TX_PORT             GPIOA
#define UART2_TX_PIN              GPIO_PIN_2
#define UART2_TX_AF               GPIO_AF7_USART2
#define UART2_TX_CONFIG()         GPIOConfigExt(UART2_TX_PORT, UART2_TX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, UART2_TX_AF)
#define UART2_RX_PORT             GPIOA
#define UART2_RX_PIN              GPIO_PIN_3
#define UART2_RX_AF               GPIO_AF7_USART2
#define UART2_RX_CONFIG()         GPIOConfigExt(UART2_RX_PORT, UART2_RX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, UART2_RX_AF)
// 串口的基本操作 
// 串口1
static void uart1_var_init(void)
{
  uart1_dev.recv = uart1_queue_recv;
  uart1_dev.send = uart1_queue_send;

  UartQueueInit(&uart1_dev.recv);
  UartQueueInit(&uart1_dev.send);
}

static void uart1_gpio_init(void)
{
  UART1_RX_CONFIG();
  UART1_TX_CONFIG();
}

static void uart1_mode_init(uint32_t bound)
{
  UART1_CLK_ENABLE();

  uart1_dev.handle.Instance = UART1_CHANNEL;
  uart1_dev.handle.Init.BaudRate = bound;                // 波特率
  uart1_dev.handle.Init.WordLength = UART_WORDLENGTH_8B; // 字长为8位数据格式
  uart1_dev.handle.Init.StopBits = UART_STOPBITS_1;      // 一个停止位
  uart1_dev.handle.Init.Parity = UART_PARITY_NONE;       // 无奇偶校验位
  uart1_dev.handle.Init.HwFlowCtl = UART_HWCONTROL_NONE; // 无硬件流控
  uart1_dev.handle.Init.Mode = UART_MODE_TX_RX;          // 收发模式
  HAL_UART_Init(&uart1_dev.handle);                      // HAL_UART_Init()会使能UART1
}

static void uart1_nvic_init(void)
{
  HAL_NVIC_SetPriority(UART1_IRQ, UART1_PREEMPT_PRIO, 3);
  HAL_NVIC_EnableIRQ(UART1_IRQ);

  __HAL_UART_ENABLE_IT(&uart1_dev.handle, UART_IT_RXNE);
}

// 串口2
static void uart2_var_init(void)
{
  uart2_dev.recv = uart2_queue_recv;
  uart2_dev.send = uart2_queue_send;

  UartQueueInit(&uart2_dev.recv);
  UartQueueInit(&uart2_dev.send);
}

static void uart2_gpio_init(void)
{
  UART2_RX_CONFIG();
  UART2_TX_CONFIG();
}

static void uart2_mode_init(uint32_t bound)
{
  UART2_CLK_ENABLE();

  uart2_dev.handle.Instance = UART2_CHANNEL;
  uart2_dev.handle.Init.BaudRate = bound;
  uart2_dev.handle.Init.WordLength = UART_WORDLENGTH_8B;
  uart2_dev.handle.Init.StopBits = UART_STOPBITS_1;
  uart2_dev.handle.Init.Parity = UART_PARITY_NONE;
  uart2_dev.handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  uart2_dev.handle.Init.Mode = UART_MODE_TX_RX;
  HAL_UART_Init(&uart2_dev.handle);
}

static void uart2_nvic_init(void)
{
  HAL_NVIC_EnableIRQ(UART2_IRQ);
  HAL_NVIC_SetPriority(UART2_IRQ, UART2_PREEMPT_PRIO, 1);

  __HAL_UART_ENABLE_IT(&uart2_dev.handle, UART_IT_RXNE);
}
// 抽象出一个初始化的结构体 每个串口都有的操作
// 定义一个串口的列表
// 下面的函数就是扫描列表 到这里为止,这些接口都是给内部使用的,外部文件用不到。
typedef struct
{
  uint8_t channel;
  uart_dev_t *dev;
  void (* var_init_cb)(void);
  void (* gpio_init_cb)(void);
  void (* mode_init_cb)(uint32_t bound);
  void (* nvic_init_cb)(void);
} uart_config_t;

static const uart_config_t uart_configs[] =
{
  {UART_CHANNEL_1, &uart1_dev, uart1_var_init, uart1_gpio_init, uart1_mode_init, uart1_nvic_init},
  {UART_CHANNEL_2, &uart2_dev, uart2_var_init, uart2_gpio_init, uart2_mode_init, uart2_nvic_init},
};

static uart_dev_t *uart_dev_get(uint8_t channel)
{
  uint8_t i;

  for(i = 0; i < ARRAY_SIZE(uart_configs); ++i)
  {
    if(uart_configs[i].channel == channel)
    {
      return uart_configs[i].dev;
    }
  }

  return 0;
}

static void uart_var_init(uint8_t channel)
{
  uint8_t i;

  for(i = 0; i < ARRAY_SIZE(uart_configs); ++i)
  {
    if(uart_configs[i].channel == channel)
    {
      uart_configs[i].var_init_cb();
      break;
    }
  }
}

static void uart_gpio_init(uint8_t channel)
{
  uint8_t i;

  for(i = 0; i < ARRAY_SIZE(uart_configs); ++i)
  {
    if(uart_configs[i].channel == channel)
    {
      uart_configs[i].gpio_init_cb();
      break;
    }
  }
}

static void uart_mode_init(uint8_t channel, uint32_t bound)
{
  uint8_t i;

  for(i = 0; i < ARRAY_SIZE(uart_configs); ++i)
  {
    if(uart_configs[i].channel == channel)
    {
      uart_configs[i].mode_init_cb(bound);
      break;
    }
  }
}

static void uart_nvic_init(uint8_t channel)
{
  uint8_t i;

  for(i = 0; i < ARRAY_SIZE(uart_configs); ++i)
  {
    if(uart_configs[i].channel == channel)
    {
      uart_configs[i].nvic_init_cb();
      break;
    }
  }
}
// 这里的函数就是非常重要的了,都是给外部使用的。
// 初始化函数,同步发送 异步发送 接收处理
void UartInit(uint8_t channel, uint32_t bound)
{
  uart_var_init(channel);
  uart_gpio_init(channel);
  uart_mode_init(channel, bound);
  uart_nvic_init(channel);
}

void UartSendSync(uint8_t channel, uint8_t *buffer, uint16_t length)
{
  uart_dev_t *dev = uart_dev_get(channel);

  HAL_UART_Transmit(&dev->handle, buffer, length, 10);
}

void UartSendWriteAsyn(uint8_t channel, uint8_t *buffer, uint16_t length)
{
  uint16_t i;
  uart_dev_t *dev = uart_dev_get(channel);

  if(0 == dev)
  {
    return;
  }

  for(i = 0; i < length; ++i)
  {
    UartQueuePush(&dev->send, buffer[i]);
  }
}

uint8_t UartSendReadAsyn(uint8_t channel, uint8_t *c)
{
  uart_dev_t *dev = uart_dev_get(channel);

  if(0 == dev)
  {
    return 0;
  }

  return UartQueuePop(&dev->send, c);
}

uint8_t UartRecv(uint8_t channel, uint8_t *c)
{
  uart_dev_t *dev = uart_dev_get(channel);

  return UartQueuePop(&dev->recv, c);
}
// 这里我没有使用串口的回调函数。
// 中断服务函数 接收到数据就加入到队列中。在UartRecv读队列数据并处理。
void UART1_IRQ_FUNC(void)
{
  if(__HAL_UART_GET_IT(&uart1_dev.handle, UART_IT_RXNE) != RESET)
  {
    HAL_UART_Receive(&uart1_dev.handle, (uint8_t *)&uart1_dev.ret, 1, 1000);
    UartQueuePush(&uart1_dev.recv, uart1_dev.ret);
  }

  HAL_UART_IRQHandler(&uart1_dev.handle);
}

void UART2_IRQ_FUNC(void)
{
  if(__HAL_UART_GET_IT(&uart2_dev.handle, UART_IT_RXNE) != RESET)
  {
    HAL_UART_Receive(&uart2_dev.handle, (uint8_t *)&uart2_dev.ret, 1, 1000);
    UartQueuePush(&uart2_dev.recv, uart2_dev.ret);
  }

  HAL_UART_IRQHandler(&uart2_dev.handle);
}

到这里,串口的初始化,发送,接收的接口就封装好了。

裸机:裸机就在while(1)中调用UartRecv扫描数据;

系统:带系统就在任务中扫描并解析数据。(带系统可以使用信号量去同步数据 -- 这里只提出一种思路)

串口队列可参考:串口队列

猜你喜欢

转载自blog.csdn.net/a1314521531/article/details/86612039