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

串口协议和RS-232标准:

串口协议:

串口通信是一种通过串行数据传输的方式进行的通信。它使用一对引脚(发送线TX和接收线RX)进行单向或双向的数据传输。
常见的串口协议包括UART(通用异步收发传输)和USART(通用同步异步收发传输),它们定义了数据传输的格式、速率、起始位、停止位等参数。
RS-232标准:

RS-232(Recommended Standard 232)是一种广泛用于串行通信的标准,定义了连接设备之间串行通信时的电气特性、信号极性、机械接口等。
RS-232标准规定了常见的串口参数,如波特率、数据位、停止位和奇偶校验等。
RS232电平与TTL电平的区别:

RS232电平通常采用负逻辑,即高电平表示逻辑0,低电平表示逻辑1。而TTL电平通常是正逻辑,高电平表示逻辑1,低电平表示逻辑0。
RS232电平的电压范围更大,一般为-15V至+15V,而TTL电平的电压范围通常在0V至5V。
RS232标准使用的连接器通常是DB-9或DB-25,而TTL通常使用的是0.1英寸间距的引脚。
"USB/TTL转232"模块(以CH340芯片模块为例)的工作原理:

CH340芯片:

CH340是一款USB转串口的芯片,常用于制作USB转TTL(UART)的模块,例如USB/TTL转232模块。
它提供了USB与串口之间的桥接功能,使得计算机可以通过USB接口与串口设备进行通信。
工作原理:

当连接USB/TTL转232模块到计算机的USB端口时,CH340芯片会被激活。
CH340通过USB接口与计算机通信,驱动程序将其识别为一个虚拟串口设备。
用户通过计算机的串口终端或软件向虚拟串口发送数据,CH340芯片将数据转换为串口信号并通过TTL电平输出到模块的TX引脚。
接收方向上,CH340芯片接收TTL电平的串口信号,将其转换为USB可识别的信号,通过USB接口发送到计算机。
这种模块的优势在于方便连接串口设备到计算机,而不需要计算机具备物理串口。它常用于与嵌入式系统、单片机等设备进行调试和通信。用户可以通过USB/TTL转232模块在计算机上模拟一个串口,使得与串口设备的通信变得更加简便。

DMA简介

DMA,即直接内存访问(Direct Memory Access),是一种计算机系统中的数据传输技术,旨在提高数据传输的效率和性能。DMA允许外设(如硬盘驱动器、网络适配器、图形卡等)直接访问系统内存,而不需要通过中央处理器(CPU)的干预,从而减轻CPU的负担。

以下是DMA的主要特点和工作原理:

特点和优势:

提高性能: DMA允许外设与内存之间的数据传输在不干扰CPU正常运行的情况下进行。这可以大大提高数据传输速度和整体系统性能。

减少CPU开销: 在传统的CPU控制数据传输中,CPU需要不断地介入数据传输过程,处理每个数据包。DMA可以减轻CPU的负担,使其能够专注于其他重要任务。

支持大数据传输: DMA适用于需要大规模数据传输的应用,如音频/视频处理、网络通信等。

降低延迟: DMA可以显著降低数据传输的延迟,因为数据可以直接从外设到内存,或者反之,而无需等待CPU的干预。

工作原理:

DMA的工作原理通常包括以下步骤:

初始化DMA控制器: CPU首先初始化DMA控制器,配置数据传输的源地址、目标地址、传输长度等参数。

DMA请求: 当外设需要进行数据传输时,它会发送一个DMA请求信号给DMA控制器,指示需要启动数据传输。

DMA控制器操作: DMA控制器接收到DMA请求后,会启动数据传输,并控制数据的流向,将数据从源地址传输到目标地址。这一过程完全独立于CPU。

数据传输完成: DMA控制器在数据传输完成后,会发送一个中断信号给CPU,以便CPU知道数据传输已经完成。

CPU处理中断: CPU在接收到DMA完成的中断信号后,可以进行相关的处理,例如更新数据结构或继续执行其他任务。

总之,DMA是一项关键的系统性能优化技术,特别是在需要高速数据传输的应用中,如多媒体处理、高速网络通信和大规模数据存储中,它能够显著提高系统的效率和性能。

创建新工程
在这里插入图片描述
选择芯片
在这里插入图片描述

配置RCC,开启外部高速时钟
在这里插入图片描述
配置USART1,选择异步通信
在这里插入图片描述
添加两个通信信道
在这里插入图片描述
然后生成keil代码即可
最终代码如下:


#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的软件仿真逻辑分析仪功能观察串口输出波形
可以参考前文

总结

基于中断(Interrupt)和DMA(Direct Memory Access)方式的串口通信是计算机系统中常见的数据传输方式。这两种方式在串口通信中的应用有着不同的特点和优势:

基于中断的串口通信:

工作原理: 在中断方式下,当串口接收到数据时,会触发一个中断信号,中断控制器会中断CPU的正常执行,CPU会跳转到特定的中断处理程序中,处理接收到的数据。

优势:

实时性强: 中断可以实现实时响应,及时处理接收到的数据,适用于对实时性要求较高的应用。
灵活性: 中断可以根据需要动态配置,可以处理不同优先级的中断请求,提供了较好的灵活性。
缺点:

CPU开销较高: 中断需要不断地中断CPU的正常执行,处理中断请求,可能会引起较大的CPU开销。
延迟相对较高: 由于需要中断CPU的执行,中断方式的串口通信可能引入较高的延迟。
基于DMA的串口通信:

工作原理: 在DMA方式下,当串口接收到数据时,DMA控制器会直接将数据传输到内存中的指定位置,无需CPU的干预,从而减轻了CPU的负担。

优势:

降低CPU开销: DMA方式可以显著降低CPU的开销,使CPU能够专注于其他任务,提高系统的整体性能。
减小延迟: 由于数据直接传输到内存,DMA方式可以降低数据传输的延迟,提高响应速度。
适用于大数据传输: DMA适用于需要大规模数据传输的情况,能够高效地传输大量数据。
缺点:

配置复杂: DMA的配置可能相对较复杂,需要确保DMA控制器的正确配置,以及避免DMA冲突等问题。
综上所述,基于中断的串口通信适用于对实时性要求较高,且数据量不大的场景,而基于DMA的串口通信适用于大数据传输、降低CPU开销和提高响应速度的场景。选择合适的方式取决于应用的具体需求和系统性能要求。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在使用STM32 HAL库进行串口通信时,可以使用中断接收和DMA发送的方式来提高通信效率。 首先需要初始化串口,并配置接收中断DMA发送。以下是一个示例代码: ``` UART_HandleTypeDef huart1; void MX_USART1_UART_Init(void) { huart1.Instance = USART1; huart1.Init.BaudRate = 115200; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; if (HAL_UART_Init(&huart1) != HAL_OK) { Error_Handler(); } /* Enable the UART Parity Error Interrupt */ HAL_UART_Receive_IT(&huart1, rxBuffer, 1); /* Enable the DMA transfer for transmit */ HAL_UART_Transmit_DMA(&huart1, txBuffer, strlen((char *)txBuffer)); } void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart == &huart1) { /* process received data */ HAL_UART_Receive_IT(&huart1, rxBuffer, 1); } } void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) { if (huart == &huart1) { /* transmit completed */ } } void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) { if (huart == &huart1) { /* handle UART error */ } } ``` 在上面的代码中,`USART1`是串口的实例,`rxBuffer`和`txBuffer`是接收和发送缓冲区。在串口初始化时,使用`HAL_UART_Receive_IT`函数开启接收中断,并使用`HAL_UART_Transmit_DMA`函数开启DMA发送。在接收中断回调函数`HAL_UART_RxCpltCallback`中,可以对接收到的数据进行处理,并继续接收下一个字节。在发送完成回调函数`HAL_UART_TxCpltCallback`中,可以进行一些操作,例如将发送缓冲区中的数据更新,等待下一次发送。在出现UART错误时,`HAL_UART_ErrorCallback`函数会被调用,可以在该函数中处理错误。 需要注意的是,在使用DMA发送时,需要保证发送缓冲区的数据不会被修改,直到DMA发送完成。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值