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

STM32CubeIDE调试串口通信输出经验分享

[复制链接]
攻城狮Melo 发布时间:2023-4-7 14:54
    关于cubeIDE开发基本技巧及流程,本文不详细叙述,请参考:cubeIDE快速开发流程_py_free的博客-CSDN博客_cubeide汉化

一、stm32串口配置
        本文采用的开发板是stm32L496VGT3,其有两个 USB 接口,一个为 USB ST-link 复用接口,作用为软件下载/调试/ 系统供电输入口。另一个为 USB OTG,用户可以外接 USB 设备,支持 1000mA,USB2.0 设备接入。本文就采用 USB ST-link口实现串口上下行通信及调试信息输出显示。

        USB ST-Link(USB1) 接口的串口通信及调试信息需要我们映射实现。

592d4fa29dee4055af279d23af80957e.png

         打开cubeMX配置界面,配置串口映射,开启LPUART串口或其他USART*(1)的异步传输模式(2),配置串口参数(3),并将串口收发数据端口映射到PB10、PB11上(4),并开启中断功能(5),最后点击保存或生成代码按钮生成代码。

ec931c27fcd446f6a1097316ae839088.png

        开启外部中断:

2a34857c12e342b2b2194ab4de4b82d5.png

        设置上拉输出:

261470160ebc4b83a1ccb1a5207928dd.png

  二、串口驱动设计及代码实现

        重新构建系统的printf函数,将其映射到LPUART串口。

        【1】首先禁用CubeIDE生成syscall.c文件

a742569ba23b4ec788c49ae6a096ca1e.png

         【2】创建print.h和print.c两个驱动文件来取代syscall.c内的函数_read、_write等实现,本文是将这两个文件放置在ICore目录内

ce2935da5ac3492992b5bfe084c4790a.png

         print.h内容如下:
  1. /*
  2. * print.h
  3. *
  4. *  Created on: 2021年11月16日
  5. *      Author: Administrator
  6. */

  7. #ifndef INC_RETARGET_H_
  8. #define INC_RETARGET_H_

  9. #include "stm32l4xx_hal.h"
  10. #include "stdio.h"//用于printf函数串口重映射
  11. #include <sys/stat.h>

  12. void ResetPrintInit(UART_HandleTypeDef  *huart);//将printf()函数映射到指定串口上

  13. int _isatty(int fd);
  14. int _write(int fd, char* ptr, int len);
  15. int _close(int fd);
  16. int _lseek(int fd, int ptr, int dir);
  17. int _read(int fd, char* ptr, int len);
  18. int _fstat(int fd, struct stat* st);

  19. #endif /* INC_RETARGET_H_ */
复制代码

        print.c内容如下,主要是将syscall.c内的空实现函数通过串口实现数据收发处理
  1. /*
  2. * print.c
  3. *
  4. *  Created on: 2021年11月16日
  5. *      Author: Administrator
  6. */

  7. #include <_ansi.h>
  8. #include <_syslist.h>
  9. #include <errno.h>
  10. #include <sys/time.h>
  11. #include <sys/times.h>
  12. #include <limits.h>
  13. #include <signal.h>
  14. #include <stdint.h>
  15. #include <stdio.h>

  16. #include "print.h"

  17. #if !defined(OS_USE_SEMIHOSTING)
  18. #define STDIN_FILENO  0
  19. #define STDOUT_FILENO 1
  20. #define STDERR_FILENO 2

  21. UART_HandleTypeDef *gHuart;

  22. void ResetPrintInit(UART_HandleTypeDef *huart)  {
  23.   gHuart = huart;
  24.   /* Disable I/O buffering for STDOUT  stream, so that
  25.    * chars are sent out as soon as they are  printed. */
  26.   setvbuf(stdout, NULL, _IONBF, 0);
  27. }
  28. int _isatty(int fd) {
  29.   if (fd >= STDIN_FILENO && fd <=  STDERR_FILENO)
  30.     return 1;
  31.   errno = EBADF;
  32.   return 0;
  33. }
  34. int _write(int fd, char* ptr, int len) {
  35.   HAL_StatusTypeDef hstatus;
  36.   if (fd == STDOUT_FILENO || fd ==  STDERR_FILENO) {
  37.     //串口发送数据实现,可以main.c等功能代码中直接调用HAL_UART_Transmit也能实现串口发送数据
  38.     hstatus = HAL_UART_Transmit(gHuart,  (uint8_t *) ptr, len, HAL_MAX_DELAY);
  39.     if (hstatus == HAL_OK)
  40.       return len;
  41.     else
  42.       return EIO;
  43.   }
  44.   errno = EBADF;
  45.   return -1;
  46. }
  47. int _close(int fd) {
  48.   if (fd >= STDIN_FILENO && fd <=  STDERR_FILENO)
  49.     return 0;
  50.   errno = EBADF;
  51.   return -1;
  52. }
  53. int _lseek(int fd, int ptr, int dir) {
  54.   (void) fd;
  55.   (void) ptr;
  56.   (void) dir;
  57.   errno = EBADF;
  58.   return -1;
  59. }
  60. int _read(int fd, char* ptr, int len) {
  61.   HAL_StatusTypeDef hstatus;
  62.   if (fd == STDIN_FILENO) {
  63.     hstatus = HAL_UART_Receive(gHuart,  (uint8_t *) ptr, 1, HAL_MAX_DELAY);
  64.     if (hstatus == HAL_OK)
  65.       return 1;
  66.     else
  67.       return EIO;
  68.   }
  69.   errno = EBADF;
  70.   return -1;
  71. }
  72. int _fstat(int fd, struct stat* st) {
  73.   if (fd >= STDIN_FILENO && fd <=  STDERR_FILENO) {
  74.     st->st_mode = S_IFCHR;
  75.     return 0;
  76.   }
  77.   errno = EBADF;
  78.   return 0;
  79. }

  80. #endif //#if !defined(OS_USE_SEMIHOSTING)
复制代码

        【3】创建串口驱动接口,主要就是实现串口回调函数

        前面print.h/c实现串口输出能力,但其输入能力由于lpusart开启了外部中断功能,还需我们实现其回调函数,因为cubeMX生成的HAL库(stm32l4xx_hal_uart.c,文件名因芯片不同有所区别)的串口接收回调函数是个弱声明函数,其实现源码没有做什么事。

210c0fff01e4454a9ec8742d5287d900.png

         现在创建usart.h、usart.c两个串口驱动文件,放置ICore目录下

        usart.h内容如下,HAL_UART_RxCpltCallback会覆盖stm32l4xx_hal_uart.c的同名回调函数:
  1. /*
  2. * usart.h
  3. *
  4. *  Created on: Oct 20, 2022
  5. *      Author: Administrator
  6. */

  7. #ifndef INC_USART_H_
  8. #define INC_USART_H_

  9. #include "stm32l4xx_hal.h" //HAL库文件声明
  10. #include <string.h>//用于字符串处理的库
  11. #include "print.h"//用于printf函数串口重映射

  12. extern UART_HandleTypeDef hlpuart1;//声明USART1的HAL库结构体

  13. #define HLPUSART_REC_LEN  256//定义USART1最大接收字节数

  14. extern uint8_t  HLPUSART_RX_BUF[HLPUSART_REC_LEN];//接收缓冲,最大HLPUSART_REC_LEN个字节.末字节为换行符
  15. extern uint16_t HLPUSART_RX_STA;//接收状态标记
  16. extern uint8_t HLPUSART_NewData;//当前串口中断接收的1个字节数据的缓存


  17. void  HAL_UART_RxCpltCallback(UART_HandleTypeDef  *huart);//串口中断回调函数声明

  18. #endif /* INC_USART_H_ */
复制代码

        usart.c内容如下:
  1. /*
  2. * usart.c
  3. *
  4. *  Created on: Oct 20, 2022
  5. *      Author: Administrator
  6. */

  7. #include "usart.h"

  8. uint8_t  HLPUSART_RX_BUF[HLPUSART_REC_LEN];//接收缓冲,最大HLPUSART_REC_LEN个字节.末字节为换行符
  9. /*
  10. * bit15:接收到回车(0x0d)时设置HLPUSART_RX_STA|=0x8000;
  11. * bit14:接收溢出标志,数据超出缓存长度时,设置HLPUSART_RX_STA|=0x4000;
  12. * bit13:预留
  13. * bit12:预留
  14. * bit11~0:接收到的有效字节数目(0~4095)
  15. */
  16. uint16_t HLPUSART_RX_STA=0;接收状态标记//bit15:接收完成标志,bit14:接收到回车(0x0d),bit13~0:接收到的有效字节数目
  17. uint8_t HLPUSART_NewData;//当前串口中断接收的1个字节数据的缓存

  18. void  HAL_UART_RxCpltCallback(UART_HandleTypeDef  *huart)//串口中断回调函数
  19. {
  20.         if(huart ==&hlpuart1)//判断中断来源(串口1:USB转串口)
  21.     {
  22.                 if(HLPUSART_RX_STA&0x4000){//溢出,重新开始
  23.                         HLPUSART_RX_STA=0;//接收错误,重新开始
  24.                 }
  25.                 if(HLPUSART_NewData==0x0d){//回车标记
  26.                printf("getdata:%.*s  \r\n", HLPUSART_RX_STA&0X0FFF, HLPUSART_RX_BUF);
  27.                HLPUSART_RX_STA|=0x8000;//标记接到回车
  28.                 }else{
  29.                         if((HLPUSART_RX_STA&0X0FFF)<HLPUSART_REC_LEN){
  30.                                 HLPUSART_RX_BUF[HLPUSART_RX_STA&0X0FFF]=HLPUSART_NewData; //将收到的数据放入数组
  31.                                 HLPUSART_RX_STA++;  //数据长度计数加1
  32.                         }else{
  33.                                 HLPUSART_RX_STA|=0x4000;//数据超出缓存长度,标记溢出
  34.                         }
  35.         }
  36.        HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData,1); //再开启接收中断
  37.     }
  38. }
复制代码

三、串口驱动功能调用及编译实现
        在原来的key.h/key.c中添加按键按下识别函数,

        key.h:
  1. /*
  2. * key.h
  3. *
  4. *  Created on: Sep 29, 2022
  5. *      Author: py_hp
  6. */

  7. #ifndef KEY_H_
  8. #define KEY_H_

  9. #include "main.h"
  10. #include "gpio.h"

  11. GPIO_PinState get_key0_val();
  12. GPIO_PinState get_key1_val();
  13. GPIO_PinState get_key2_val();

  14. uint8_t KEY_0(void);
  15. uint8_t KEY_1(void);
  16. uint8_t KEY_2(void);

  17. #endif /* KEY_H_ */
复制代码

        key.c内容如下:
  1. /*
  2. * key.c
  3. *
  4. *  Created on: Sep 29, 2022
  5. *      Author: py_hp
  6. */
  7. #include "key.h"

  8. GPIO_PinState get_key0_val()
  9. {
  10.         return HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin);
  11. };

  12. GPIO_PinState get_key1_val()
  13. {
  14.         return HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin);
  15. };

  16. GPIO_PinState get_key2_val()
  17. {
  18.         return HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin);
  19. };

  20. uint8_t KEY_0(void)
  21. {
  22.         uint8_t a;
  23.         a=0;//如果未进入按键处理,则返回0
  24.         if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)==GPIO_PIN_RESET){//读按键接口的电平
  25.                 HAL_Delay(20);//延时去抖动
  26.                 if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)==GPIO_PIN_RESET){ //读按键接口的电平
  27.                         a=1;//进入按键处理,返回1
  28.                 }
  29.         }
  30.         while(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)==GPIO_PIN_RESET); //等待按键松开
  31.         return a;
  32. }

  33. uint8_t KEY_1(void)
  34. {
  35.         uint8_t a;
  36.         a=0;//如果未进入按键处理,则返回0
  37.         if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==GPIO_PIN_RESET){//读按键接口的电平
  38.                 HAL_Delay(20);//延时去抖动
  39.                 if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==GPIO_PIN_RESET){ //读按键接口的电平
  40.                         a=1;//进入按键处理,返回1
  41.                 }
  42.         }
  43.         while(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==GPIO_PIN_RESET); //等待按键松开
  44.         return a;
  45. }

  46. uint8_t KEY_2(void)
  47. {
  48.         uint8_t a;
  49.         a=0;//如果未进入按键处理,则返回0
  50.         if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)==GPIO_PIN_RESET){//读按键接口的电平
  51.                 HAL_Delay(20);//延时去抖动
  52.                 if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)==GPIO_PIN_RESET){ //读按键接口的电平
  53.                         a=1;//进入按键处理,返回1
  54.                 }
  55.         }
  56.         while(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)==GPIO_PIN_RESET); //等待按键松开
  57.         return a;
  58. }
复制代码

        在main.c中调用串口驱动,其部分代码如下:
  1. /* USER CODE END Header */
  2. /* Includes ------------------------------------------------------------------*/
  3. #include "main.h"
  4. #include "usart.h"
  5. #include "gpio.h"

  6. /* Private includes ----------------------------------------------------------*/
  7. /* USER CODE BEGIN Includes */
  8. //用户代码1
  9. #include "../../ICore/key.h"
  10. #include "../../ICore/led.h"
  11. #include "../../ICore/print.h"
  12. #include "../../ICore/usart.h"
  13. /* USER CODE END Includes */

  14. /* Private typedef -----------------------------------------------------------*/
  15. /* USER CODE BEGIN PTD */

  16. /* USER CODE END PTD */

  17. /* Private define ------------------------------------------------------------*/
  18. /* USER CODE BEGIN PD */
  19. /* USER CODE END PD */

  20. /* Private macro -------------------------------------------------------------*/
  21. /* USER CODE BEGIN PM */

  22. /* USER CODE END PM */

  23. /* Private variables ---------------------------------------------------------*/

  24. /* USER CODE BEGIN PV */

  25. /* USER CODE END PV */

  26. /* Private function prototypes -----------------------------------------------*/
  27. void SystemClock_Config(void);
  28. /* USER CODE BEGIN PFP */

  29. /* USER CODE END PFP */

  30. /* Private user code ---------------------------------------------------------*/
  31. /* USER CODE BEGIN 0 */

  32. /* USER CODE END 0 */

  33. /**
  34.   * @brief  The application entry point.
  35.   * @retval int
  36.   */
  37. int main(void)
  38. {
  39.   /* USER CODE BEGIN 1 */

  40.   /* USER CODE END 1 */

  41.   /* MCU Configuration--------------------------------------------------------*/

  42.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  43.   HAL_Init();

  44.   /* USER CODE BEGIN Init */

  45.   /* USER CODE END Init */

  46.   /* Configure the system clock */
  47.   SystemClock_Config();

  48.   /* USER CODE BEGIN SysInit */

  49.   /* USER CODE END SysInit */

  50.   /* Initialize all configured peripherals */
  51.   MX_GPIO_Init();
  52.   MX_LPUART1_UART_Init();
  53.   /* USER CODE BEGIN 2 */
  54. //用户代码2
  55.   ResetPrintInit(&hlpuart1);
  56.   HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData, 1); //再开启接收中断
  57.   HLPUSART_RX_STA = 0;
  58.   set_led0_val(0);
  59.   set_led1_val(get_key0_val());
  60.   /* USER CODE END 2 */

  61.   /* Infinite loop */
  62.   /* USER CODE BEGIN WHILE */
  63.   while (1)
  64.   {
  65.       //用户代码3
  66.           if(KEY_1()) //按键KEY1判断为1时按键按下
  67.           {
  68.                   set_led0_val(1);//LED1灯控制(1点亮,0熄灭)
  69.                   set_led1_val(0);//LED2灯控制(1点亮,0熄灭)
  70.               printf("KEY1\r\n");//向USART1串口发送字符串
  71.           }
  72.           if(KEY_2()) //按键KEY2判断为1时按键按下
  73.           {
  74.                   set_led0_val(0);//LED1灯控制(1点亮,0熄灭)
  75.                   set_led1_val(1);//LED2灯控制(1点亮,0熄灭)
  76.                   printf("KEY2\r\n");//向USART1串口发送字符串
  77.           }
  78.           if(HLPUSART_RX_STA&0xC000){//串口1判断中断接收标志位
  79.                   printf("read flag HLPUSART_RX_STA&0XC000\r\n");//向USART1串口发送字符串
  80.                   if(HLPUSART_RX_BUF[0]=='1'){
  81.                           set_led0_val(1);//LED1灯控制(1点亮,0熄灭)
  82.                           set_led1_val(1);//LED2灯控制(1点亮,0熄灭)
  83.                   }
  84.                   if(HLPUSART_RX_BUF[0]=='0'){
  85.                           set_led0_val(0);//LED1灯控制(1点亮,0熄灭)
  86.                           set_led1_val(0);//LED2灯控制(1点亮,0熄灭)
  87.                   }
  88.                   HLPUSART_RX_STA=0;//串口接收标志清0,即开启下一轮接收
  89.           }
  90.     /* USER CODE END WHILE */

  91.     /* USER CODE BEGIN 3 */
  92.   }
  93.   /* USER CODE END 3 */
  94. }
复制代码

四、编译测试
        编译及加载程序到开发板:

29acb9bf23dc456a94e90e33302641ca.png

         验证数据收发,按键1和按键2按下,顺利传输数据,输入“1”和“0”字段,可下行控制LED灯

c881fb4eb2a84981946d2fb129db4c22.png


————————————————
版权声明:py_free-物联智能
如有侵权请联系删除


收藏 评论0 发布时间:2023-4-7 14:54

举报

0个回答

所属标签

相似分享

官网相关资源

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