stm32CubeMX+STM32F7串口空闲中断+发送DMA

参考:https://blog.csdn.net/youmeichifan/article/details/51750435?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.nonecase

参考:https://blog.csdn.net/chenjk10/article/details/106264940

参考:https://blog.csdn.net/wxc971231/article/details/83044189?utm_medium=distribute.pc_relevant.none-task-blog-title-1&spm=1001.2101.3001.4242

1.配置系统下载程序方式

 2.RCC外部晶振

 3.串口声明

 

4.系统时钟

 5.生成文件根据自己需求配置

 我这设置了所有库,可以选第二个仅需求的

 还加了其他功能,这里可不参考,DMA要放在串口前

6.生成后修改

6.1 usart.h

/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "string.h"
/* USER CODE END Includes */

 

/* USER CODE BEGIN Private defines */

#define USART1_DMA_REC_SIE 256
#define USART1_REC_SIE 512
#define USART_DMA_SENDING 1//DMA发送 
#define USART_DMA_SENDOVER 0//DMA发送结束
typedef struct
{
	uint8_t UsartRecFlag:1;//接收标志
	uint8_t dmaSend_flag;//发送标志
	uint16_t UsartDMAReclen;//DMA接收长度
	uint16_t UsartReclen;//串口数据缓存长度
	uint8_t Usart1DMARecBuffer[USART1_DMA_REC_SIE];//DMAbuffer缓存数据
	uint8_t Usart1RecBuffer [USART1_REC_SIE] ;//串口1缓存数据
 }teUsart1type;

extern teUsart1type Usart1type;//定义数据

void UsartReceive_IDLE(UART_HandleTypeDef *huart);
void Usart1SendData_DMA1(uint8_t *pdata, uint16_t Length);
void Analysis_Serial_Data(void);
void EnableUsart_IT(void);

/* USER CODE END Private defines */

6.2 usart.c,接收为双缓存方式,一般DMA接收放在,DMArec里,若不及时处理,下次接收会丢失,放入usartrec里,可避免,实现处理多少拿多少,dma接收的数据根据处理情况放入相应位置。

teUsart1type Usart1type;
/*****************************************************************************
 * 函 数 名  : EnableUsart_IT
 * 负 责 人  : by
 * 创建日期  : 2020年8月26日
 * 函数功能  : 串口2初始化函数,空闲与DMA中断
 * 输入参数  : 无
 * 输出参数  : 无
 * 返 回 值  : 
 * 调用关系  : 
 * 其    它  :   
*****************************************************************************/
void EnableUsart_IT(void)
{   
    __HAL_UART_ENABLE_IT(&huart2,UART_IT_IDLE); // 开启串口2 空闲接收中断
		HAL_UART_Receive_DMA(&huart2, Usart1type.Usart1DMARecBuffer, USART1_DMA_REC_SIE);//DMA中断
}
/*****************************************************************************
 * 函 数 名  : Usart1SendData_DMA
 * 负 责 人  : by
 * 创建日期  : 2020年8月26日
 * 函数功能  : 串口2DMA发送函数
 * 输入参数  : 无
 * 输出参数  : 无
 * 返 回 值  : 
 * 调用关系  : 
 * 其    它  :   
*****************************************************************************/
void Usart1SendData_DMA(uint8_t *pdata, uint16_t Length)  

{  
	//while(Usart1type.dmaSend_flag == USART_DMA_SENDING);  
	Usart1type.dmaSend_flag = USART_DMA_SENDING;  
	HAL_UART_Transmit_DMA(&huart2, pdata, Length);  
}  
/*****************************************************************************
 * 函 数 名  : HAL_UART_TxCpltCallback
 * 负 责 人  : by
 * 创建日期  : 2020年8月26日
 * 函数功能  : 串口2DMA发送回调函数
 * 输入参数  : 无
 * 输出参数  : 无
 * 返 回 值  : 
 * 调用关系  : 
 * 其    它  :   
*****************************************************************************/
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)  
{  
    __HAL_DMA_DISABLE(huart->hdmatx); 
    if(huart->Instance == huart2.Instance)	
    Usart1type.dmaSend_flag = USART_DMA_SENDOVER;  
}  
/*****************************************************************************
 * 函 数 名  : UsartReceive_IDLE
 * 负 责 人  : by
 * 创建日期  : 2020年8月27日
 * 函数功能  : 串口接受空闲中断处理函数
 * 输入参数  : UART_HandleTypeDef *huart  串口句柄
 * 输出参数  : 无
 * 返 回 值  : 
 * 调用关系  :DMA接收的数据缓存在USART接收中,释放DMA继续接收 
 * 其    它  : 
*****************************************************************************/
void UsartReceive_IDLE(UART_HandleTypeDef *huart)
{
	if((__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE) != RESET))
	{ 
	      if(huart->Instance == huart2.Instance)//判断是否为串口2
		{
		 if(RESET != __HAL_UART_GET_FLAG(&huart2, UART_FLAG_IDLE))   //是否为空闲中断
	           {
		   __HAL_UART_CLEAR_IDLEFLAG(&huart2);                     //清除空闲中断
		   HAL_UART_DMAStop(&huart2);                                                     //停止本次DMA传输
            Usart1type.UsartDMAReclen  = USART1_DMA_REC_SIE - huart2.hdmarx->Instance->NDTR;   //计算本次传输数据长度
						if(Usart1type.UsartReclen>0)
						 {
							memcpy(&Usart1type.Usart1RecBuffer[Usart1type.UsartReclen], Usart1type.Usart1DMARecBuffer, Usart1type.UsartDMAReclen);
							Usart1type.UsartReclen+=Usart1type.UsartDMAReclen;
						 } 
						else if(Usart1type.UsartReclen>USART1_REC_SIE)//如果串口接收数据溢出,从0开始记录
						 {
							 Usart1type.UsartReclen=0;
						 }
						else
						 {
							memcpy(Usart1type.Usart1RecBuffer, Usart1type.Usart1DMARecBuffer,Usart1type.UsartDMAReclen);
							Usart1type.UsartReclen=Usart1type.UsartDMAReclen;
						 }					
						memset(Usart1type.Usart1DMARecBuffer, 0x00, sizeof(Usart1type.Usart1DMARecBuffer ));//DMA数据清零										
						Usart1type.UsartRecFlag=1;//空闲标志位置1
		        HAL_UART_Receive_DMA(&huart2, Usart1type.Usart1DMARecBuffer, USART1_DMA_REC_SIE);//重新打开DMA
					}		
		  }
	}
}
/*****************************************************************************
 * 函 数 名  : Analysis_Serial_Data
 * 负 责 人  : by
 * 创建日期  : 2020年8月26日
 * 函数功能  : 串口接收数据直接打印
 * 输入参数  : void  无
 * 输出参数  : 无
 * 返 回 值  : void
 * 调用关系  : 
 * 其    它  : 
*****************************************************************************/
 void Analysis_Serial_Data(void)
 {
	 	if(Usart1type.UsartRecFlag)
		 {			 	
			 Usart1SendData_DMA(Usart1type.Usart1RecBuffer,Usart1type.UsartReclen);	
			 Usart1type.UsartRecFlag=0;
			 Usart1type.UsartReclen=0;//测试处理为将全部数据进行打印处理,若需解析,可将解析长度进行减少,多次处理	 
		 }
 }
/*****************************************************************************
 * 函 数 名  : fputc
 * 负 责 人  : by
 * 创建日期  : 2020年8月26日
 * 函数功能  : 串口2 printf重定义
 * 输入参数  : printf(d%/s%/%c,a)
 * 输出参数  : 无
 * 返 回 值  : 
 * 调用关系  : 
 * 其    它  :   
*****************************************************************************/
#ifdef __GNUC__
 
  /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
 set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
 
  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
	
PUTCHAR_PROTOTYPE
{
	HAL_UART_Transmit(&huart2,(uint8_t *)&ch, 1, 0xFFFF);
	return ch;
}


/* USER CODE END 1 */

 DMA发送函数,网上给的教程while是用来保证DMA收发节奏的,节奏错误会出现死循环情况,给注释掉了。。。。

//while(Usart1type.dmaSend_flag == USART_DMA_SENDING);  
    Usart1type.dmaSend_flag = USART_DMA_SENDING;

6.3  主函数,只用DMA通讯只需添加EnableUsart_IT();/*串口初始化*/,即可,对应usart.c里的函数

  /* USER CODE BEGIN 2 */
  HAL_TIM_Base_Start_IT(&htim3);/*使能定时器3中断***/
  HAL_TIM_Base_Start_IT(&htim2);/*使能定时器2中断*/
  HAL_CAN_Start(&hcan1);/*can初始化*/
  HAL_CAN_ActivateNotification(&hcan1,CAN_IT_RX_FIFO0_MSG_PENDING);			
  EnableUsart_IT();/*串口初始化*/
  CAN_User_Init(&hcan1);	
  /* USER CODE END 2 */

 循环,对应数据输出

 /* USER CODE BEGIN WHILE */
  while (1)
  {		
     Analysis_Serial_Data();
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

7、实验结果,间隔10ms,连续发送,未出现丢帧,或其他错误

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值