STM32
直播中

恐龙之家

8年用户 806经验值
私信 关注
[问答]

怎样使用STM32CubeMX去配置USART串口通信呢

怎样使用VSPD去虚拟串口和XCOM串口调试工具呢?

怎样使用STM32CubeMX去配置USART串口通信呢?

回帖(2)

李秋年

2021-12-10 14:14:33
1
举报

刘继牛

2021-12-10 14:14:33
本文说明


功能要求

  • 开机后,向串口1发送“Welcome”
  • 串口1接收字节指令“0xA1",打开LED1,回传“LED1 ON”
  • 串口1接收字节指令“0xA2",关闭LED1,回传“LED1 OFF”
  • 在串口发送过程中,打开LED2作为发送数据指示灯
相关软件使用说明
STM32CubeMX+Keil+Proteus相关的安装、使用、配置等基础操作不再赘述,有关内容的详细介绍如下
串行接口相关知识点



  • 通信方式:串行通信和并行通信
  • 模式:单工、半双工、全双工(任意时刻是否能同时发送和接收数据)
  • 异步串行通信:通信双方在没有同步时钟的前提下,将一个字符按位进行传输的通信方式
  • 串口转USB接口:CH340、CP2012
  • STM32芯片的串口USART功能十分强大,大多时候采用异步串行通信
    USART1_TX与PA9复用, USART1_RX与PA10复用
    USART2_TX与PA2复用, USART2_RX与PA3复用
HAL库中串口发送的重要函数

阻塞式发送函数(要等待数据发完才能做其他任务)
HAL_UART_Transmit()
非阻塞式发送函数
HAL_UART_Transmit_IT()
看函数名,多了个_IT, 即在阻塞式发送的基础上可以中断(Interrupt)
串口发送完毕中断回调函数
void HAL_UART_TxCpltCallback()
举例说明串口发送函数的作用

假如我们使用非阻塞式的串口发送函数,将发送数组dat_Txd中的前5个数据发送到
HAL_UART_Transmit_IT(&huart1,dat_Txd,5);
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
        if(huart->Instance == USART1) //判断发送数据的串口
        {
                HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9);
        }
}


如果是使用阻塞式发送函数,则代码变为如下内容


HAL_UART_Transmit(&huart1,dat_Txd,5,10000);  //超时等待10000ms
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9);


HAL库中串口接收的重要函数

阻塞式接收函数(要等待数据接收完才能做其他任务,所以不推荐)
HAL_UART_Transmit()
非阻塞式接收函数(推荐使用)
HAL_UART_Transmit_IT()
串口发送完毕中断回调函数
void HAL_UART_RxCpltCallback()
举例说明串口接收函数的作用

假如使用非阻塞式的串口发送函数,接收USART1中的一个字节,将其保存在dat_Rxd,在发送完数据后,若该字节位0x5A,则翻转PB9引脚的输出电平

HAL_UART_Transmit_IT(&huart1,dat_Rxd,1);
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
        if(huart->Instance == USART1) //判断发送数据的串口
        {
                if(dat_Rxd == 0x5A)
                        HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9);
        }
}
STM32CubeMX配置USART

Mode选择Asynchronous(异步的)
Baud Rate(波特率)选择9600Bits/s
然后使能一下NVIC,勾选USART1 interrupt Enabled即可





其他的配置内容不再赘述,详情可查看本文开头写的本文说明一章
然后生成代码即可
Keil编写代码逻辑

首先定义一些变量

#define LED1_ON  HAL_GPIO_WritePin(GPIOA,LED1_Pin,GPIO_PIN_RESET);
#define LED1_OFF HAL_GPIO_WritePin(GPIOA,LED1_Pin,GPIO_PIN_SET);
#define LED2_ON  HAL_GPIO_WritePin(GPIOA,LED2_Pin,GPIO_PIN_RESET);
#define LED2_OFF HAL_GPIO_WritePin(GPIOA,LED2_Pin,GPIO_PIN_SET);


uint8_t Tx_str1[]= "Welcome!rn";
uint8_t Tx_str2[]= "LED1 ON!rn";
uint8_t Tx_str3[]= "LED1 OFF!rn";
uint8_t Tx_str4[]= "Command Not Found!rn";
uint8_t Rx_dat = 0; //接收字符变量


然后在主函数内实现开机发送Welcome


  /* USER CODE BEGIN 2 */
        LED2_ON;                                                                                                                                                                                         //发送指示灯LED2亮
        HAL_UART_Transmit(&huart1,Tx_str1,sizeof(Tx_str1),1000);    //阻塞式发送函数
        LED2_OFF;                                                                                                                                                                                 //发送结束时,指示灯LED2灭
  /* USER CODE END 2 */
发送函数执行结束后,要等待串口发来的字符

这里将HAL_UART_Receive_IT()函数写在循环体内
时时刻刻等待串口发来的字符


  while (1)
  {
    /* USER CODE END WHILE */
                HAL_UART_Receive_IT(&huart1,&Rx_dat,3);                     //等待接收字符
    /* USER CODE BEGIN 3 */
  }


而每当HAL_UART_Receive_IT()函数执行之后,则进入中断,进入回调函数HAL_UART_RxCpltCallback()


因此我们需要编辑我们的回调函数


void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
        if(huart->Instance == USART1)
        {               
                switch(Rx_dat)
                {
                        case 0x4f:
                                LED1_ON;
                                LED2_ON;                                                                                                                                                                                         //发送指示灯LED2亮
                                HAL_UART_Transmit(&huart1,Tx_str2,sizeof(Tx_str2),1000);   //阻塞式发送函数
                                LED2_OFF;                                                                                                                                                                                 //发送结束时,指示灯LED2灭
                        break;
                       
                        case 0x43:
                                LED1_OFF;
                                LED2_ON;                                                                                                                                                                                         //发送指示灯LED2亮
                                HAL_UART_Transmit(&huart1,Tx_str3,sizeof(Tx_str3),1000);   //阻塞式发送函数
                                LED2_OFF;                                                                                                                                                                                 //发送结束时,指示灯LED2灭                               
                        break;
                       
                        default:
                                LED2_ON;                                                                                                                                                                                         //发送指示灯LED2亮
                                HAL_UART_Transmit(&huart1,Tx_str4,sizeof(Tx_str4),1000);   //阻塞式发送函数
                                LED2_OFF;                                                   //发送结束时,指示灯LED2灭                       
                        break;
                }       
        }
}


简单解释一下程序,进行回调函数,根据接收的字符执行对应的操作
执行完相关操作,跳出switch case继续等待接收串口发来的字符
编译运行生成hex文件,准备仿真
Proteus仿真

原理图如下





第一次仿真串口,查了查,需要在元件库里找名为COMPIM的元件
COMPIM是Proteus中一个极其有用的虚拟元件,COMPIM可以建立起一种映射,把仿真威廉希尔官方网站 中的数字量映射到计算机的物理端口
找到这个元件,拖进原理图,编辑一些属性,如图
其中Physical Port(物理端口)就是我们要在计算机中建立的映射物理端口
波特率都设置成9600





除了虚拟串口,我们还需要一个虚拟终端来查看发送的数据信息
点击左侧长得像电流表的图标,找到VIRTUAL TERMIN(虚拟终端),放进原理图





第一次见比较陌生,介绍一下这个虚拟终端
这个虚拟终端有四个引脚,分别是
RXD 一 数据接收引脚
TXD 一 数据发送引脚
RTS 一 请求发送信号
CTS 一 清除传送,是对RTS的响应信号
左键这个虚拟终端,出现了一堆参数,如图





Baud Rate 一 传输波特率
Data Bits 一 数据传输位数
Parity 一 奇偶校验位
Stop Bits 一 数据传输的停止位
Send XON / XOFF 发送允许/禁止
这些好像哪里见过,找到usart.c文件的UART_Init函数中,发现完全一致
这也就是我们为什么要设置波特率为9600





一开始一脸茫然,不知道怎么将芯片的MCU和这两个元件连线
后来查了查才知道STM32芯片给了专门的TX引脚PA9和RX引脚PA10
那我们就把芯片的TX引脚和COMPIM的TXD相连,芯片的RX引脚和COMPIM的RXD相连,再将COMPIM的RXD与VIRTUAL TERMIN的RXD相连即可。详情可看上方的原理图
老规矩导入Hex文件,设置主频72MHz
虚拟串口VSPD

试用15天,使用方法官网里也有写
我自己用的是老版本的(反正能用就行,学习使用)




打开软件,创建COM3和COM4两个虚拟端口即可
两个串口已经可以正常通信了
串口调试工具XCOM

我用的是XCOM2.6版本的
由于软件是正点原子的
所以你也可以去正点原子的william hill官网 里下载最近发布的版本来使用
打开串口调试工具XCOM,选择串口COM4->COM3,打开串口
(刚才在Proteus里设置COMPIM的串口是COM3)





开始测试串口通信
开机发送Welcome,正确
发送字符O,回传LED1 ON,LED1亮,正确

发送字符C,回传LED1 OFF,LED1灭,正确





发送字符Z,回传Command Not Found,正确





总结



  • 主要学习了使用VSPD配置虚拟串口和XCOM串口调试工具
  • 熟悉使用Proteus里COMPIM串口元件和虚拟终端
  • 学习了串口通信的相关原理和主要函数的运行过程
  • 学习使用STM32CubeMX配置USART
  • 用一个具体项目来实现串口通信。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分