11-CubeMx+Keil+Proteus仿真STM32 - 串口单字节通信
本文例子参考《STM32单片机开发实例——基于Proteus虚拟仿真与HAL/LL库》
源代码:https://github.com/LanLinnet/STM32F103R6
项目要求
实现通过串口助手发送单字节数据,单片机收到数据后,交换高4位与低4位,将新的数据通过串口发回串口助手。例如,串口助手发送数据“AB”,单片机返回数据“BA”。
硬件设计
-
在第一节的基础上,在Proteus中添加电路如下图所示。其中我们添加了:串口组件
COMPIM
,用于连接计算机虚拟串口;
一个虚拟仪器VIRTUAL TERMINAL
,用来查看单片机收到的串口数据。
由于要实现串口通信,我们要将其波特率、字长、校验方式、停止位等都设置一下,具体参数如下图所示,相关内容的解释会在下文中进行。
COMPIM设置
VIRTUAL TERMINAL设置
现实中,STM32单片机串口通信采用TTL电平,高电平+3.3V代表逻辑“1”,低电平0V代表逻辑“0”。而RS232标准规定-15V~-3V
代表逻辑“1”,+3V~15V
代表逻辑“0”,虽然与单片机串口通信逻辑一致,但是逻辑电平不匹配,需要进行电平转换。通常我们使用MAX232芯片设计电平转换电路。不过此处我们使用Proteus进行仿真,可以省略这一步骤(COMPIM带有电平转换功能)。 -
串口通信简介:计算机系统内部,计算机与外设之间若要进行数据交换,则必须使用通信技术。
1)通信的基本方式有并行通信和串行通信两种:并行通信数据传送速率快,但需要耗费较多的数据线;串行通信只需要一对数据线,但传输速率较慢。
2)异步通信与同步通信:在异步通信中,数据通常以字节为最小单位组成数据帧传送,数据帧按照固定波特率通过发送端逐帧发送,接收端则逐帧接收。异步通信发送端与接收端采用不同的时钟信号,一般来说,只要发送端和接收端的波特率误差相差不超过1%就可以顺利通信。同步通信与异步通信相比对双方时钟要求更高。
3)数据传输模式:单工模式、半双工模式、全双工模式。
本次项目中,我们采用串行异步通信方式。 -
由于我们采用仿真的方式进行,还需要下载两个软件进行串口的模拟和串口的调试。
Visual Serial Port Driver
(简称VSPD),可在官网中进行下载。
串口调试助手
,我在论坛中下载(首次可能需要注册),也可自行寻找下载。
-
打开VSPD,点击“Add Pair”添加一对虚拟串口,这里添加的是
COM3
和COM4
,二者互相收发数据。
添加后可以在计算机的“设备管理器”中查看到虚拟串口如下,这里我们将单片机的串口设置为COM3,串口调试助手的串口设置为COM4。
-
打开CubeMX,建立工程。点击“Connectivity”列表中的“USART”进行串口配置。将Mode设置为
Asynchronous
(异步),波特率设为19200Bits/s
,字长设为8Bits
,校验设为None
,停止位设为1
,数据传送设为Receive and Transmit
(接收与发送)。设置完成后,会看到右侧的PA9和PA10引脚被自动设置为USART1_TX
和USART1_RX
,即USART1的发送端和接收端。
随后,再点击“NVIC Settings”,选中“USART global interrupt”,使能“Enabled”串口1的中断功能。
-
点击“Generator Code”生成Keil工程。
软件编写
-
本次我们需要实现串口助手发送单字节数据,单片机收到数据后交换高低4位,将新的数据通过串口发回串口助手,需要用到串口相关函数其API文档如下:
HAL_UART_Receive_IT 串口中断接收设定函数
,该函数再每次接收前都需要调用一次
HAL_UART_Transmit 串口数据发送函数
HAL_UART_RxCpltCallback 串口接收完毕回调函数
-
点击“Open Project”在Keil中打开工程,双击“main.c”文件。
-
首先我们需要在main.c文件中设置两个全局变量,一个用于代表接收完毕的标志位,一个用于存放接收数据的数组。
/* USER CODE BEGIN PV */ uint8_t rf = 0; //接收完毕标志位 uint8_t dat[1] = {0xab}; //用于存放接收数据的数组 /* USER CODE END PV */
然后,在
main
函数中中插入代码如下,打开串口1接收中断/* USER CODE BEGIN 2 */ //打开串口1接收中断,接收数据存入dat数组,数组长度为1 HAL_UART_Receive_IT(&huart1, dat, 1); /* USER CODE END 2 */
随后,在
/* USER CODE BEGIN 4 */
和/* USER CODE END 4 */
中插入接收完毕回调函数代码如下/* USER CODE BEGIN 4 */ //接收完毕回调函数 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart==&huart1) //如果串口接收中断完毕 { rf = 1; //接收完毕,标志位置1 } } /* USER CODE END 4 */
最后,在
while(1)
中插入代码如下,进行高低4位的交换/* USER CODE BEGIN WHILE */ while (1) { uint8_t x; //中间变量x if(rf==1) //若接收完成 { rf = 0; //将标志位清0 x = dat[0]; //将接收的数据存入中间变量x dat[0]=(x<<4)|(x>>4); //高低4位互换 HAL_UART_Transmit(&huart1, dat, 1, 1); //由串口1发送存储在dat数组中的数据包,数组长度为1,超时1ms HAL_UART_Receive_IT(&huart1, dat, 1); //接收前每次都需调用该函数 } /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */
联合调试
-
点击运行,生成HEX文件。
-
在Proteus中加载相应HEX文件,点击运行。
-
打开串口调试助手“XCOM”,选择
COM4
,设置相应的波特率、停止位、数据位、奇偶校验等,勾选“16进制显示”和“16进制发送”,点击“打开串口”。在发送框输入“AB”,点击“发送”。在Proteus中我们可以看到“VIRTUAL TERMINAL”接收到数据“AB”。同时再观察串口调试助手“XCOM”,可以看到接收窗口收到高低4位互换的数据“BA”。
注意
如果你发送“AB”1个字节,接收到的却有多个字节:
因为0x0D、0x0A代表的分别是回车符号和换行符号,请查看是否在串口调试助手“XCOM”中勾选了“发送新行”,取消勾选即可。