https://liu-yaohua.github.io

0%

【STM32基础教程05】STM32的串口数据收发基础

串行接口相关知识点

并行通信、串行通信的概念。
单工、半双工、全双工的概念。
异步串行通信:通信双方在没有同步时钟的前提下,将一个字符(包括特定的附加位)按位进行传输的通信方式。
波特率:每秒钟传输的二进制位数,如9600bps。
TTL电平<—->RS232:MAX3232 SP3232
串口<———>USB接口:CH340 CP2012

STM32芯片的串口UASRT功能十分强大,但对于日常编程而言,使用最多的还是异步串行通信。
串口1:USART1_TXPA9复用,USART1_RXPA10复用。
串口2:USART2_TXPA2复用,USART2_RXPA3复用。

HAL库中串口发送的重要函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
////查询方式,阻塞式发送函数(初学者,推荐使用)   
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,函数执行状态。
typedef enum
{
HAL_OK = 0x00U,
HAL_ERROR = 0x01U,
HAL_BUSY = 0x02U,
HAL_TIMEOUT = 0x03U
} HAL_StatusTypeDef;

////中断方式,非阻塞式发送函数
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart,uint8_t *pData, uint16_t Size);
参数1:huart,串口实例的指针。
参数2:*pData,待发送数据缓冲区的指针。
参数3:Size,待发送数据的字节数。
返回值:HAL_StatusTypeDef,函数执行状态。

////串口发送完毕中断回调函数
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);
void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
应用举例:使用非阻塞式的串口发送函数,将发送缓数组dat_Txd中的前5个数据发送到USART1,在数据发送完成后,翻转PB9引脚的输出电平。   
//使用中断,非阻塞方式
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);
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9);

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
////查询方式,阻塞式接收函数

HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
参数1:huart,串口实例的指针。
参数2:*pData,数据接收据缓冲区的指针。
参数3:Size,待接收数据的字节数。
参数4:Timeout,超时时间值。
返回值:HAL_StatusTypeDef,函数执行状态。

非阻塞式接收函数(推荐使用)
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart,uint8_t *pData,uint16_t Size);
参数1:huart,串口实例的指针。
参数2:*pData,数据接收据缓冲区的指针。
参数3:Size,待接收数据的字节数。
返回值:HAL_StatusTypeDef,函数执行状态。

////串口接收完毕中断回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);
1
2
3
4
5
6
7
8
9
10
11
12
应用举例:使用非阻塞式的串口接收函数,接收USART1中的一个字节,将其保存在dat_Rxd变量中,在数据接收完成后,判断该字节,若为0x5A,则翻转PB8引脚的输出电平。
//使用中断,非阻塞方式
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_8);
}
}

实训案例:上位机通过串口控制LED灯开关

XMF07AXMF07C开发板上,利用STM32CubeMXKeil5协同开发,完成以下的功能:
【1】开机后,向串口1发送“hello world!”。
【2】串口1收到字节指令“0xA1”,打开LED1,发送“LED1 Open!”。
【3】串口1收到字节指令“0xA2”,关闭LED1,发送“LED1 Closed!”。
【4】在串口发送过程中,打开LED2作为发送数据指示灯

1
2
3
4
5
6
7
8
9
#define LED1_ON() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET)
#define LED1_OFF() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET)
#define LED2_ON() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET)
#define LED2_OFF() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET)

uint8_t Tx_str1[] = "hello world!\r\n";
uint8_t Tx_str2[] = "LED1 Open!\r\n";
uint8_t Tx_str3[] = "LED1 Closed!\r\n";
uint8_t Rx_dat = 0;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
if(Rx_dat == 0xa1)
{
LED1_ON();

LED2_ON();
HAL_UART_Transmit(&huart1,Tx_str2,sizeof(Tx_str2),10000);
LED2_OFF();
HAL_UART_Receive_IT(&huart1,&Rx_dat,1);
}
else if(Rx_dat == 0xa2)
{
LED1_OFF();

LED2_ON();
HAL_UART_Transmit(&huart1,Tx_str3,sizeof(Tx_str3),10000);
LED2_OFF();
HAL_UART_Receive_IT(&huart1,&Rx_dat,1);
}
}
}
1
2
3
4
5
//在mian()函数中添加以下代码:
LED2_ON();
HAL_UART_Transmit(&huart1,Tx_str1,sizeof(Tx_str1),10000); //向上位机发送“hello world!”
LED2_OFF();
HAL_UART_Receive_IT(&huart1,&Rx_dat,1); //启动串口1接收上位机1个字节