你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32F7xx —— 串口通信

[复制链接]
STMCU小助手 发布时间:2021-12-12 21:37
一、串口初始化过程
1、时钟使能;

2、GPIO初始化;

3、串口波特率设置;

4、串口控制;

5、数据发送与接收


二、几个重要的串口函数
  1. HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart); // 串口初始化

  2. HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout); // 串口发送

  3. HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout); // 串口接收

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

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

  6. void HAL_NVIC_EnableIRQ(IRQn_Type IRQn); // 使能中断
复制代码

三、几个重要的结构

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

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

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

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

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

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

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

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

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

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

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

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

  17.   HAL_LockTypeDef           Lock;            /*!< Locking object                     */

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

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

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

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

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

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

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

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

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

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

  31.   uint32_t OneBitSampling;            /*!< Specifies whether a single sample or three samples' majority vote is selected.
  32.                                            Selecting the single sample method increases the receiver tolerance to clock
  33.                                            deviations. This parameter can be a value of @ref UART_OneBit_Sampling */
  34. }UART_InitTypeDef;
复制代码
四、基本接口设计
我们使用中断接收,普通发送。中断接收到的数据放入队列中,在外部可配置每路串口的功能。

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

  9. static uart_dev_t uart1_dev;
  10. static uart_dev_t uart2_dev;
复制代码
  1. // 对外只有通道 不再包含USART1...
  2. typedef enum
  3. {
  4.   UART_CHANNEL_NONE,
  5.   UART_CHANNEL_1,
  6.   UART_CHANNEL_2,
  7.   UART_CHANNEL_NUM
  8. } uart_channel_t;

  9. // 宏定义串口的基本信息 之所以这样写,方便移植修改
  10. #define UART1_CHANNEL             USART1
  11. #define UART1_PREEMPT_PRIO        UART1_PRIORITY
  12. #define UART1_IRQ                 USART1_IRQn
  13. #define UART1_IRQ_FUNC            USART1_IRQHandler
  14. #define UART1_CLK_ENABLE()        __HAL_RCC_USART1_CLK_ENABLE()
  15. #define UART1_TX_PORT             GPIOA
  16. #define UART1_TX_PIN              GPIO_PIN_10
  17. #define UART1_TX_AF               GPIO_AF7_USART1
  18. #define UART1_TX_CONFIG()         GPIOConfigExt(UART1_TX_PORT, UART1_TX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, UART1_TX_AF)
  19. #define UART1_RX_PORT             GPIOA
  20. #define UART1_RX_PIN              GPIO_PIN_9
  21. #define UART1_RX_AF               GPIO_AF7_USART1
  22. #define UART1_RX_CONFIG()         GPIOConfigExt(UART1_RX_PORT, UART1_RX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, UART1_RX_AF)

  23. #define UART2_CHANNEL             USART2
  24. #define UART2_PREEMPT_PRIO        UART2_PRIORITY
  25. #define UART2_IRQ                 USART2_IRQn
  26. #define UART2_IRQ_FUNC            USART2_IRQHandler
  27. #define UART2_CLK_ENABLE()        __HAL_RCC_USART2_CLK_ENABLE()
  28. #define UART2_TX_PORT             GPIOA
  29. #define UART2_TX_PIN              GPIO_PIN_2
  30. #define UART2_TX_AF               GPIO_AF7_USART2
  31. #define UART2_TX_CONFIG()         GPIOConfigExt(UART2_TX_PORT, UART2_TX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, UART2_TX_AF)
  32. #define UART2_RX_PORT             GPIOA
  33. #define UART2_RX_PIN              GPIO_PIN_3
  34. #define UART2_RX_AF               GPIO_AF7_USART2
  35. #define UART2_RX_CONFIG()         GPIOConfigExt(UART2_RX_PORT, UART2_RX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, UART2_RX_AF)
复制代码
  1. // 串口的基本操作
  2. // 串口1
  3. static void uart1_var_init(void)
  4. {
  5.   uart1_dev.recv = uart1_queue_recv;
  6.   uart1_dev.send = uart1_queue_send;

  7.   UartQueueInit(&uart1_dev.recv);
  8.   UartQueueInit(&uart1_dev.send);
  9. }

  10. static void uart1_gpio_init(void)
  11. {
  12.   UART1_RX_CONFIG();
  13.   UART1_TX_CONFIG();
  14. }

  15. static void uart1_mode_init(uint32_t bound)
  16. {
  17.   UART1_CLK_ENABLE();

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

  27. static void uart1_nvic_init(void)
  28. {
  29.   HAL_NVIC_SetPriority(UART1_IRQ, UART1_PREEMPT_PRIO, 3);
  30.   HAL_NVIC_EnableIRQ(UART1_IRQ);

  31.   __HAL_UART_ENABLE_IT(&uart1_dev.handle, UART_IT_RXNE);
  32. }

  33. // 串口2
  34. static void uart2_var_init(void)
  35. {
  36.   uart2_dev.recv = uart2_queue_recv;
  37.   uart2_dev.send = uart2_queue_send;

  38.   UartQueueInit(&uart2_dev.recv);
  39.   UartQueueInit(&uart2_dev.send);
  40. }

  41. static void uart2_gpio_init(void)
  42. {
  43.   UART2_RX_CONFIG();
  44.   UART2_TX_CONFIG();
  45. }

  46. static void uart2_mode_init(uint32_t bound)
  47. {
  48.   UART2_CLK_ENABLE();

  49.   uart2_dev.handle.Instance = UART2_CHANNEL;
  50.   uart2_dev.handle.Init.BaudRate = bound;
  51.   uart2_dev.handle.Init.WordLength = UART_WORDLENGTH_8B;
  52.   uart2_dev.handle.Init.StopBits = UART_STOPBITS_1;
  53.   uart2_dev.handle.Init.Parity = UART_PARITY_NONE;
  54.   uart2_dev.handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  55.   uart2_dev.handle.Init.Mode = UART_MODE_TX_RX;
  56.   HAL_UART_Init(&uart2_dev.handle);
  57. }

  58. static void uart2_nvic_init(void)
  59. {
  60.   HAL_NVIC_EnableIRQ(UART2_IRQ);
  61.   HAL_NVIC_SetPriority(UART2_IRQ, UART2_PREEMPT_PRIO, 1);

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

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

  18. static uart_dev_t *uart_dev_get(uint8_t channel)
  19. {
  20.   uint8_t i;

  21.   for(i = 0; i < ARRAY_SIZE(uart_configs); ++i)
  22.   {
  23.     if(uart_configs<i>.channel == channel)
  24.   </i>  {
  25.       return uart_configs.dev;
  26.     }
  27.   }

  28.   return 0;
  29. }

  30. static void uart_var_init(uint8_t channel)
  31. {
  32.   uint8_t i;

  33.   for(i = 0; i < ARRAY_SIZE(uart_configs); ++i)
  34.   {
  35.     if(uart_configs.channel == channel)
  36.     {
  37.       uart_configs.var_init_cb();
  38.       break;
  39.     }
  40.   }
  41. }

  42. static void uart_gpio_init(uint8_t channel)
  43. {
  44.   uint8_t i;

  45.   for(i = 0; i < ARRAY_SIZE(uart_configs); ++i)
  46.   {
  47.     if(uart_configs.channel == channel)
  48.     {
  49.       uart_configs.gpio_init_cb();
  50.       break;
  51.     }
  52.   }
  53. }

  54. static void uart_mode_init(uint8_t channel, uint32_t bound)
  55. {
  56.   uint8_t i;

  57.   for(i = 0; i < ARRAY_SIZE(uart_configs); ++i)
  58.   {
  59.     if(uart_configs.channel == channel)
  60.     {
  61.       uart_configs.mode_init_cb(bound);
  62.       break;
  63.     }
  64.   }
  65. }

  66. static void uart_nvic_init(uint8_t channel)
  67. {
  68.   uint8_t i;

  69.   for(i = 0; i < ARRAY_SIZE(uart_configs); ++i)
  70.   {
  71.     if(uart_configs.channel == channel)
  72.     {
  73.       uart_configs.nvic_init_cb();
  74.       break;
  75.     }
  76.   }
  77. }
复制代码
  1. // 这里的函数就是非常重要的了,都是给外部使用的。
  2. // 初始化函数,同步发送 异步发送 接收处理
  3. void UartInit(uint8_t channel, uint32_t bound)
  4. {
  5.   uart_var_init(channel);
  6.   uart_gpio_init(channel);
  7.   uart_mode_init(channel, bound);
  8.   uart_nvic_init(channel);
  9. }

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

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

  15. void UartSendWriteAsyn(uint8_t channel, uint8_t *buffer, uint16_t length)
  16. {
  17.   uint16_t i;
  18.   uart_dev_t *dev = uart_dev_get(channel);

  19.   if(0 == dev)
  20.   {
  21.     return;
  22.   }

  23.   for(i = 0; i < length; ++i)
  24.   {
  25.     UartQueuePush(&dev->send, buffer<span style="font-style: italic;"><span style="font-style: normal;">);
  26.   }
  27. }

  28. uint8_t UartSendReadAsyn(uint8_t channel, uint8_t *c)
  29. {
  30.   uart_dev_t *dev = uart_dev_get(channel);

  31.   if(0 == dev)
  32.   {
  33.     return 0;
  34.   }

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

  37. uint8_t UartRecv(uint8_t channel, uint8_t *c)
  38. {
  39.   uart_dev_t *dev = uart_dev_get(channel);

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

  51.   HAL_UART_IRQHandler(&uart1_dev.handle);
  52. }

  53. void UART2_IRQ_FUNC(void)
  54. {
  55.   if(__HAL_UART_GET_IT(&uart2_dev.handle, UART_IT_RXNE) != RESET)
  56.   {
  57.     HAL_UART_Receive(&uart2_dev.handle, (uint8_t *)&uart2_dev.ret, 1, 1000);
  58.     UartQueuePush(&uart2_dev.recv, uart2_dev.ret);
  59.   }

  60.   HAL_UART_IRQHandler(&uart2_dev.handle);
  61. }</span></span>
复制代码

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

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

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

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





收藏 评论0 发布时间:2021-12-12 21:37

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版