基于中断/DMA方式的串口通信

串口协议
STM32F103串口通信协议
STM32F103微控制器的串口通信协议,该协议使用UART串口通信进行数据传输,并定义了数据帧格式、通信流程和错误处理等内容。
数据帧格式
数据帧采用以下格式进行传输:
起始位:1位
数据位:8位
奇偶校验位:1位
停止位:1位
起始位:逻辑低电平表示起始位,用于标识数据帧的开始。
数据位:8位数据位用于传输实际的数据。
奇偶校验位:用于检测数据传输过程中的错误,可以选择奇校验、偶校验或无校验。
停止位:逻辑高电平表示停止位,用于标识数据帧的结束。
通信流程
初始化串口通信参数,包括波特率、数据位、校验位和停止位等。
发送端准备数据,将数据按照数据帧格式组织,并发送给接收端。
接收端接收数据,检查起始位、校验位和停止位的正确性。
如果数据校验正确,接收端将数据提取出来进行处理;如果数据校验错误,接收端发送错误消息给发送端。
发送端和接收端通过该协议进行连续的数据传输。
错误处理
在数据传输过程中,可能会发生以下错误情况:
起始位错误:接收端未正确检测到起始位,导致数据解析错误。
校验位错误:接收端在校验数据时发现错误,表明数据传输过程中发生了错误。
停止位错误:接收端未正确检测到停止位,导致数据解析错误。
在出现错误时,接收端应向发送端发送错误消息,以便重新发送数据或采取其他纠错措施。
RS-232标准
RS-232(Recommended Standard 232)是一种常用的串行通信标准,用于在计算机和外部设备之间进行数据传输。它定义了电气特性、信号传输方式和接口连接等方面的规范。
电气特性
RS-232标准规定了通信线路的电气特性,包括信号电平、波特率和时钟频率等。根据RS-232标准,信号电平分为正负两种,分别表示逻辑1和逻辑0。通常,正电平表示逻辑0,负电平表示逻辑1。波特率是指数据传输的速率,通常以每秒传输的位数(bps)表示。时钟频率则是指传输中使用的时钟信号频率。
信号传输方式
RS-232标准使用异步传输方式,即每个数据字节之间没有固定的时间间隔。数据传输以数据帧为单位,每个数据帧包括起始位、数据位、校验位和停止位。起始位用于标识数据帧的开始,停止位用于标识数据帧的结束。数据位用于传输实际的数据,校验位用于检测数据传输中的错误。
接口连接
RS-232标准规定了连接计算机和外部设备的接口连接方式和引脚定义。一般来说,RS-232标准使用9针或25针的D型插座连接器。其中,9针的连接器常用于较新的设备,而25针的连接器则常用于较旧的设备。接口连接的引脚定义包括数据线、控制线和地线等。
应用领域
由于其广泛的应用和成熟的技术,RS-232标准在许多领域中仍然被广泛使用。它常用于计算机与打印机、调制解调器、终端设备和工业自动化设备等外部设备之间的通信。尽管现在有许多新的通信标准和接口出现,但RS-232标准仍然在许多传统应用和设备中发挥着重要作用。
RS232电平与TTL电平的区别
RS232电平和TTL电平是两种常见的串行通信电平标准,它们在电气特性、电平范围和使用环境等方面存在一些区别。RS232电平
电气特性;
RS232电平使用正负电平表示逻辑1和逻辑0,通常正电平表示逻辑0,负电平表示逻辑1。根据RS232标准,信号电平范围在-15V至+15V之间。
电平范围:RS232电平的电压范围较大,可以在较长距离上进行可靠的数据传输。
使用环境:由于RS232电平的电压范围较大,它主要用于长距离和工业环境中的通信应用。
TTL电平
电气特性:TTL电平使用0V和5V(或3.3V)的电平表示逻辑1和逻辑0。通常0V表示逻辑0,5V(或3.3V)表示逻辑1。
电平范围:TTL电平的电压范围较小,一般在0V至5V(或3.3V)之间。
使用环境:由于TTL电平的电压范围较小,它主要用于短距离和低功耗的通信应用,如嵌入式系统和电子设备之间的通信。
RS232和TTL电平在电气特性、电平范围和使用环境方面存在明显的区别。根据具体的应用需求,我们可以选择适合的电平标准来进行串行通信。需要注意的是,在使用不同电平标准时,需要进行电平转换以确保正常的数据传输。
基于HAL库中断方式进行串口通信
STM32CubeMX配置
在这里插入图片描述

设置RCC,使用外部高速时钟
在这里插入图片描述

设置SYS
在这里插入图片描述

设置USART(波特率,校验位等参数)
在这里插入图片描述

设置NVIC,使USART使能
在这里插入图片描述

创建代码
在这里插入图片描述

在main函数前面定义全局变量`

char c;//指令 0:停止  1:开始
char message[]="hello Windows\n";//输出信息
char tips[]="CommandError\n";//提示1
char tips1[]="Start.....\n";//提示2
char tips2[]="Stop......\n";//提示3
int flag=0;//标志 0:停止发送 1.开始发送
在main函数中设置接收中断
函数:
HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
程序
在main函数下面添加以下代码:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{	//当输入的指令为0时,发送提示并改变flag	if(c=='0')	{		flag=0;		HAL_UART_Transmit(&huart1, (uint8_t *)&tips2, strlen(tips2),0xFFFF); 	}	//当输入的指令为1时,发送提示并改变flag	else if(c=='1')	{		flag=1;		HAL_UART_Transmit(&huart1, (uint8_t *)&tips1, strlen(tips1),0xFFFF); 	}	//当输入不存在指令时,发送提示并改变flag	else 	{		flag=0;		HAL_UART_Transmit(&huart1, (uint8_t *)&tips, strlen(tips),0xFFFF); 	}	//重新设置中断	HAL_UART_Receive_IT(&huart1, (uint8_t *)&c, 1)

实验效果
编译
在这里插入图片描述

基于HAL库实现DMA串口通信
STM32CubeMX配置
选择和上面相同的单片机,创建工程
配置RCC,开启外部高速时钟
在这里插入图片描述

配置USART1,选择异步通
在这里插入图片描述

其余参数默认即可
添加两个通信信道
在这里插入图片描述

生成代码
实验任务
STM32系统给上位机(win10)连续发送“hello windows!”;当上位机给stm32发送字符“stop”后,stm32暂停发送“hello windows!”;发送一个字符“start”后,stm32继续发送;
代码:`

#include "main.h"
#include "dma.h"#include "usart.h"#include "gpio.h" void SystemClock_Config(void);uint8_t flag=1;uint8_t rx_buf[6];//接收串口数据存放的数组int strEqual(char rcData[6],char rcData2[6])	{	for(uint8_t i = 0 ; i < 6 ; i++){		if (rcData[i] != rcData2[i]) return 0;	}	return 1;} void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){	//当输入的指令为“stop!"时,发送提示并改变flag=0	if(strEqual(rx_buf,"stop!"))	{		flag=0;	}	
	//当输入的指令为"start"时,发送提示并改变flag=1	else if(strEqual(rx_buf,"start"))	{		flag=1;	}	HAL_UART_Receive_DMA(&huart1,(uint8_t*)rx_buf,5);}int main(void){  HAL_Init();  uint8_t message[] = "hello windows!\n";  //定义数据发送数组  SystemClock_Config();  MX_GPIO_Init();  MX_DMA_Init();  MX_USART1_UART_Init();  HAL_UART_Receive_DMA(&huart1,(uint8_t*)rx_buf,5);//设置DMA接收到的数据存放在rx_buf中  while (1)  {      if(flag==1)	  {	    HAL_UART_Transmit_DMA(&huart1, (uint8_t *)message, sizeof(message));	    HAL_Delay(600);	  }  }}void SystemClock_Config(void){  RCC_OscInitTypeDef RCC_OscInitStruct = {0};  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};  /** Initializes the RCC Oscillators according to the specified parameters  * in the RCC_OscInitTypeDef structure.  */  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;  RCC_OscInitStruct.HSIState = RCC_HSI_ON;  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)  {    Error_Handler();  }  /** Initializes the CPU, AHB and APB buses clocks  */  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)  {    Error_Handler();  }}void Error_Handler(void){  /* USER CODE BEGIN Error_Handler_Debug */  /* User can add his own implementation to report the HAL error return state */  __disable_irq();  while (1)  {  }  /* USER CODE END Error_Handler_Debug */}#ifdef  USE_FULL_ASSERT/**  * @brief  Reports the name of the source file and the source line number  *         where the assert_param error has occurred.  * @param  file: pointer to the source file name  * @param  line: assert_param error line source number  * @retval None  */void assert_failed(uint8_t *file, uint32_t line){  /* USER CODE BEGIN 6 */  /* User can add his own implementation to report the file name and line number,     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */  /* USER CODE END 6 */}#endif /* USE_FULL_ASSERT */`

实验效果:
在这里插入图片描述

用Keil的软件仿真逻辑分析仪功能观察串口输出波形
参考文章:
链接:
https://blog.youkuaiyun.com/m0_72338354/article/details/133858992

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值