stm32F407串口通信Sample
stm32的串口,是很方便实验连接电脑的方式之一,大部分开发板都是串口通过ch340转接至电脑usb接口。
一、任务目标
- 通过串口向电脑发送消息,并控制led7的开关;
- 电脑通过串口向开发板发送消息,并控制led8的开关
二、硬件
- LED7<-->PF7:发送消息时闪烁
- LED8<-->PF8:接收到消息时闪烁
- USART1_TX<-->PA9:USART1的发送引脚,与PA9复用
- USART1_RX<-->PA10:USART1的接收引脚,与PA10服用
- USART1串口在我这个开发板上,是通过ch340转换为usb连接电脑上的
- RST按键用于复位,否则开发板上电即发送消息,串口无法调试
三、工具
- flymcu:烧录工具
- comtransmit:串口调试工具,用于接收和发送数据
四、配置
- sys,rcc同之前的默认设置;
- GPIO:两个LED等连接PF7/8,通用输出配置,无需其他设置
- USART1:在Connectivity标签下的USART1接口配置
- 模式(
mode
):设置为异步模式(Asynchronous
) - Parameter settings:波特率(
baud rate
):9600;字节长度(word length
)8位;无校验位(parity
);停止位(stop bits
)为1;通信方向(data direction
)为双向; - NVIC settings:启用USART1的全局中断功能
- GPIO settings:
GPIO MODE
:PA9/10均设置为端口复用(Alternate function
),注意,这里和开发板的教程不同,无需设置上拉/下拉模式,使用推挽模式即可。
- 模式(
五、运行流程
同之前的中断程序运行流程类似,通过调用回调函数实现功能(非阻塞模式)
main.c-->stm32f4xx_hal_uart.c-->main.c
main.c
- 发送消息(阻塞式)
这里先演示阻塞式发送消息,操作非常简单,只需要调用HAL_UART_Transmit函数即可。
led7_on();
HAL_UART_Transmit(&huart1, tx_led_open, sizeof(tx_led_open), 10000);
led7_off();
- 接收消息(非阻塞式,接收基本非阻塞式的)
在main.c中调用HAL_UART_Receive_IT函数。
//usart1接收到数据后,将数据存放在rx_data中
HAL_UART_Receive_IT(&huart1, &rx_data, 1);
stm32f4xx_hal_uart.c
USART的发送、接收函数均在此文件中,如上面main.c文件中调用的发送和接收消息函数 此文件在driver目录的src下 几乎所有的usart的执行都在这个文件中,接收的函数运行流程执行如下:
HAL_UART_Receive_IT-->UART_Start_Receive_IT-->UART_Receive_IT-->HAL_UART_RxCpltCallback
HAL_UART_RxCpltCallback
是接收消息的虚函数,HAL_UART_Receive_IT
就是通过回调此函数实现消息接收后的操作。如:消息接收后,点亮LED8灯- 剩下就是需要重写
HAL_UART_RxCpltCallback
函数即可
main.c
由于在main函数中调用
HAL_UART_Receive_IT
后,是通过重写回调函数HAL_UART_RxCpltCallback
来实现的。
- 在回调函数中首先要判断接收的消息是否来自USART1端口
- 对接收到的信息进行分析,然后根据信息开关led8
- 仔细观察代码中,
HAL_UART_Receive_IT
函数在每次发送消息完毕之后,都会再调用一次,目的是为了一直在监听是否有接收到消息。 代码如下:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if(huart->Instance==USART1) {
if(rx_data=='a') {
led8_on();
led7_on();
HAL_UART_Transmit(&huart1, tx_led_open, sizeof(tx_led_open), 10000);
led7_off();
HAL_UART_Receive_IT(&huart1, &rx_data, 1);
} else if(rx_data=='b') {
led8_off();
led7_on();
HAL_UART_Transmit(&huart1, tx_led_close, sizeof(tx_led_close), 10000);
led7_off();
HAL_UART_Receive_IT(&huart1, &rx_data, 1);
}
}
}
六、其他
- 其实这个例程非常简单,无非是配置USART端口,然后重写回调函数,实现功能;
- 这里有一个排查了很久的问题:
if(rx_data=='a')
,这个语句弄了很久,目前我的单片机上,必须比较字符,无法直接比较0x
这种形式的16进制(功力不够,没找到原因) - 注意调试工具的参数要和usart配置参数一直,另外就是调试工具和程序下载工具不能同时使用,当调试工具端口打开后,程序下载工具是无法下载程序的。
七、函数说明
发送函数
- 阻塞式发送函数
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart,uint8_t *pData,uint16_t Size, uint32_t Timeout)
- 参数1:huart,串口实例的指针。
- 参数2:*pData,待发送数据缓冲区的指针。
- 参数3:Size,待发送数据的字节数。
- 参数4:Timeout,超时时间值。
- 非阻塞式发送函数
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart,uint8_t *pData, uint16_t Size);
- 参数1:huart,串口实例的指针。
- 参数2:*pData,待发送数据缓冲区的指针。
- 参数3:Size,待发送数据的字节数。
- 非阻塞式发送完毕中断回调函数
//发送完毕后回调中断函数 void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart); //发送一半回调 void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart)
接收函数
非阻塞式接收函数(推荐使用)
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart,uint8_t *pData,uint16_t Size);
- 参数1:huart,串口实例的指针。
- 参数2:*pData,数据接收据缓冲区的指针。
- 参数3:Size,待接收数据的字节数。
接收完毕中断回调函数
//发送完毕回调中断函数 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart); //接收一半回调中断函数 void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);