STM32学习笔记 串口通信

第五章 串口通信

5.1 串口通信分类

5.1.1按照数据传送方向

单工:数据传输只支持数据在一个方向上传输;
半双工:允许数据在两个方向上传输。但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信;它不需要独立的接收端和发送端,两者可以合并一起使用一个端口。
全双工:允许数据同时在两个方向上传输。因此,全双工通信是两个单工通信方式的结合,需要独立的接收端和发送端。

5.1.2按照通信方式

**同步通信:**带时钟同步信号传输。比如:SPI,IIC通信接口。
**异步通信:**不带时钟同步信号。比如:UART(通用异步收发器),单总线。
在同步通讯中,收发设备上方会使用一根信号线传输信号,在时钟信号的驱动下双方进行协调,同步数据。在异步通讯中不使用时钟信号进行数据同步,它们直接在数据信号中穿插一些用于同步的信号位,或者将主题数据进行打包,以数据帧的格式传输数据。通讯中还需要双方规约好数据的传输速率(也就是波特率)等,以便更好地同步。常用的波特率有4800bps、9600bps、115200bps等。在同步通讯中,数据信号所传输的内容绝大部分是有效数据,而异步通讯中会则会包含数据帧的各种标识符,所以同步通讯效率高,但是同步通讯双方的时钟允许误差小,稍稍时钟出错就可能导致数据错乱,异步通讯双方的时钟允许误差较大。

5.2 STM32串口通信基础

STM32的串口通信接口有两种,分别是:UART(通用异步收发器)、USART(通用同步异步收发器)。而对于大容量STM32F10x系列芯片,分别有3个USART和2个UART。
UART引脚连接方法
RXD:数据输入引脚,数据接受;
TXD:数据发送引脚,数据发送。
在这里插入图片描述
对于两个芯片之间的连接,两个芯片GND共地,同时TXD和RXD交叉连接。这里的交叉连接的意思就是,芯片1的RxD连接芯片2的TXD,芯片2的RXD连接芯片1的TXD。这样,两个芯片之间就可以进行TTL电平通信了。
在这里插入图片描述
若是芯片与PC机(或上位机)相连,除了共地之外,就不能这样直接交叉连接了。尽管PC机和芯片都有TXD和RXD引脚,但是通常PC机(或上位机)通常使用的都是RS232接口(通常为DB9封装),因此不能直接交叉连接。RS232接口是9针(或引脚),通常是TxD和RxD经过电平转换得到的。故,要想使得芯片与PC机的RS232接口直接通信,需要也将芯片的输入输出端口也电平转换成rs232类型,再交叉连接。经过电平转换后,芯片串口和rs232的电平标准是不一样的:
单片机的电平标准(TTL电平):+5V表示1,0V表示0;
Rs232的电平标准:+15/+13 V表示0,-15/-13表示1。

5.3 UART HAL库

HAL库函数对每个外设都建立了一个初始化结构体,比UART_InitTypeDef,结构体成员用于设置外设工作参数,并由外设初始化配置函HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart)调用,这些设定参数将会设置外设相应的寄存器,达到配置外设工作环境的目的。

5.3.1串口发送\接收函数

●HALUARTTransmit();串口轮询模式发送,使用超时管理机制。
●HALUART_Receive();串口轮询模式接收,使用超时管理机制。
●HAL_ UART_ Transmit IT 0);串口中断模式发送。
●HAL UART_ Receive_ IT( );串口中断模式接收。
●HAL UART Transmit DMA( );串口DMA模式发送。
●HAL_ UART_ Transmit DMA( );串口DMA模式接收。

5.3.2 串口中断函数

●HAL UART TxHalfCpltCallback( );- -半数据发送完成时调用
●HAL UART TxCplItCallback( );数据完全发送完成后调用,
●HAL_ UART_ RxHalfCpltCallback( );- - 般数据接收完成时调用。
●HALUART_RxCpltCallback();数据完全接受完成后调用。
●HAL
UART_ ErrorCallback( );传输出现错误时调用。

5.3.3 常用函数

发送函数
1.阻塞式发送函数(推荐)
HAL_StatusTypeDef HAL_UART_Transmit(UART_Handle TypeDefhuart,unit8_tpData,unit16_t Size,unit32_t Timeout);
2.非阻塞式发送函数
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_Handle TypeDefhuart,unit8_tpData,unit16_t Size);
3.发送完毕中断回调函数
void HAL_UART_TxCpltCallback(UART_HandleTypeDef huart);
void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef huart);
接收函数
1.阻塞式发送函数
HAL_StatusTypeDef HAL_UART_Receive(UART_Handle TypeDef
huart,unit8_t
pData,unit16_t Size,unit32_t Timeout);
2.非阻塞式发送函数(推荐)
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_Handle TypeDefhuart,unit8_tpData,unit16_t Size);
3.发送完毕中断回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);

例:开机后,向串口1发送“hello world !";
串口1收到字节指令“0xA1",打开LED1,发送“LED1 Open!”;
串口1收到字节指令“0xA2”,关闭LED1,发送“LED1 Closed !”。
CubeMX配置
在这里插入图片描述
提醒:这里配置完以后看一眼原理图串口1的引脚是否和配置完自动生成的引脚一致!!!
代码:

//先定义需要发送的字符串
uint8_t Tx_str1[] = "hello world\r\n";
uint8_t Tx_str2[] = "LED1 open\r\n";
uint8_t Tx_str3[] = "LED1 close\r\n";
uint8_t Rx_dat = 0;   //定义串口接收的数据变量
//写好接收函数的回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance == USART1)
	{
		if(Rx_dat == 0xA1)
		{
			LED_Display(0x10);
	        HAL_UART_Transmit(&huart1,Tx_str2,sizeof(Tx_str2),10000);
		    HAL_UART_Receive_IT(&huart1,&Rx_dat,1); //记得再次调用
		}
		if(Rx_dat == 0xA2)
		{
			Cls_LED(0x10);
			HAL_UART_Transmit(&huart1,Tx_str3,sizeof(Tx_str3),10000);
			HAL_UART_Receive_IT(&huart1,&Rx_dat,1);
		}
	}
}
//主函数内部
//开机时发送hello world
HAL_UART_Transmit(&huart1,Tx_str1,sizeof(Tx_str1),10000);
//数据接收函数
HAL_UART_Receive_IT(&huart1,&Rx_dat,1);
//将串口发送的信息储存在Rx_dat中

5.4小结

!在串口实验中,数据线可能会出问题,导致串口不能进行正常收发操作。
串口通信重定向:

//fputc()函数的形参调用了C库的FILE,所以在程序中加入stdio.h这个头文件
UART_HandleTypeDef huart1;
int fputc(int ch, FILE *f)
{
	HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
    return ch;
}
//通过以上函数可以在串口中正常使用printf函数

串口接收数据多字符串检验:

unsigned int Uart2_Rx=0;
void result2(void)
{
		Uart2_Buffer[Uart2_Rx] = Rx_dat2;  
		//将串口接收的数据储存在Uart2_Buffer[Uart2_Rx]数组中
		Uart2_Rx++;
	    if(Uart2_Buffer[0] == 0xF1) // 判断数组中第一个数值,再执行相应操作
		{
			LED2_on();
			HAL_UART_Receive_IT(&huart2,&Rx_dat2,1);
		}
		if(Uart2_Buffer[Uart2_Rx-1] == 0xDE) //判断数组最后一个值再执行相应操作
		{
			HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
			HAL_UART_Transmit(&huart1,Tx_str4,sizeof(Tx_str4),1000);
			HAL_UART_Receive_IT(&huart2,&Rx_dat2,1);
			Uart2_Rx = 0; //记得数组清零
		}
}

版权声明:本文为qq_52670281原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。