文章目录[隐藏]
STM32-UART 空闲中断+DMA发送接收
cubemx配置
这里DMA的初始化一定要在串口初始化前面,否则会有问题
代码
main.c中加入这个,创建缓冲区,标志位等
//用于DMA接收
uint8_t u1_rec_buf[MAX_BUF];
uint8_t receive_num;
//用于DMA发送
uint8_t sendbuf[8000]={0};//创建一个发送缓冲区
uint8_t Tx_busy=0;//等于0表示dma-tx空闲中,可以发送,等于1说明发送中,需要等待
main.h中加入这个
#define MAX_BUF 200
extern uint8_t u1_rec_buf[];
extern uint8_t receive_num;
main()函数中,加入
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);//使能空闲中断
HAL_UART_Receive_DMA(&huart1,u1_rec_buf,MAX_BUF);//使能串口接收DMA
加入位置为初始化完成后如下
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);//使能空闲中断
HAL_UART_Receive_DMA(&huart1,u1_rec_buf,MAX_BUF);//使能串口接收DMA
/* USER CODE END 2 */
DMA发送示例
初始化时同时把发送数组填充满
for(uint16_t i=0;i<8000;i++)
{
sendbuf[i]='g';
}
while(1)里
while(1)
{
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,1);//点亮LED
while(Tx_busy==1)//等待标志位归零,即发送完成
{
}
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,0);//关闭LED
HAL_Delay(2000);
HAL_UART_Transmit_DMA(&huart1,sendbuf,8000);//使能DMA发送
Tx_busy=1;//发送标志位置1
}
重定义串口发送完成回调函数,我们在这里清空标志位
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance==USART1)
{
Tx_busy=0;//释放总线
}
}
试验现象:DMA发送时led会点亮,发送完成后led会熄灭,两秒一次循环
如果修改发送数组个数,现在是8000,改成4000,led亮的时间会缩短一半,不可以太小,要不观察不到了就
为什么一定要用led?而不用printf等,如果说printf也是用的串口1,那么会出现printf打印不出来的现象,因为dma已经占据了串口发送的位置,cpu不暂停dma的时候去抢发送的位置是抢不到了,也只有等到dma发送完成了端口被释放了才可以再printf出去,如果printf用的其它串口,那么是可以正常使用的
用到的API:
HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
串口DMA发送函数,正常会返回HAL_OK,不过在本例中没有使用返回值
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
原来是个弱定义,我们自己重新写,函数会在TX完成时被调用,我们用它清除标志位就可以了。
中断中建议使用标志位代替复杂操作,在主循环中去检测标志位进行相应措施就可以了,养成好习惯。
DMA空闲中断接收示例
在原有的串口1中断服务函数添加新代码
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE)==SET) //判断是否是空闲中断
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1); //清楚空闲中断标志
HAL_UART_DMAStop(&huart1); // 停止DMA传输
receive_num=MAX_BUF-__HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
HAL_UART_Receive_DMA(&huart1,u1_rec_buf,MAX_BUF);//重新打开DMA接收
}
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
mian()主循环中
while (1)
{
if(receive_num!=0)//有了接收
{
printf("\nreceive_num=%d\n",receive_num);//打印接收个数
HAL_UART_Transmit_DMA(&huart1,u1_rec_buf,receive_num);//将接收内容原封不动返还回去
receive_num=0;//清空标志位
}
}
实验现象:
版权声明:本文为CSDN博主「gxt_kt」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/my_id_kt/article/details/122412078
STM32-UART 空闲中断+DMA发送接收
cubemx配置
这里DMA的初始化一定要在串口初始化前面,否则会有问题
代码
main.c中加入这个,创建缓冲区,标志位等
//用于DMA接收
uint8_t u1_rec_buf[MAX_BUF];
uint8_t receive_num;
//用于DMA发送
uint8_t sendbuf[8000]={0};//创建一个发送缓冲区
uint8_t Tx_busy=0;//等于0表示dma-tx空闲中,可以发送,等于1说明发送中,需要等待
main.h中加入这个
#define MAX_BUF 200
extern uint8_t u1_rec_buf[];
extern uint8_t receive_num;
main()函数中,加入
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);//使能空闲中断
HAL_UART_Receive_DMA(&huart1,u1_rec_buf,MAX_BUF);//使能串口接收DMA
加入位置为初始化完成后如下
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);//使能空闲中断
HAL_UART_Receive_DMA(&huart1,u1_rec_buf,MAX_BUF);//使能串口接收DMA
/* USER CODE END 2 */
DMA发送示例
初始化时同时把发送数组填充满
for(uint16_t i=0;i<8000;i++)
{
sendbuf[i]='g';
}
while(1)里
while(1)
{
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,1);//点亮LED
while(Tx_busy==1)//等待标志位归零,即发送完成
{
}
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,0);//关闭LED
HAL_Delay(2000);
HAL_UART_Transmit_DMA(&huart1,sendbuf,8000);//使能DMA发送
Tx_busy=1;//发送标志位置1
}
重定义串口发送完成回调函数,我们在这里清空标志位
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance==USART1)
{
Tx_busy=0;//释放总线
}
}
试验现象:DMA发送时led会点亮,发送完成后led会熄灭,两秒一次循环
如果修改发送数组个数,现在是8000,改成4000,led亮的时间会缩短一半,不可以太小,要不观察不到了就
为什么一定要用led?而不用printf等,如果说printf也是用的串口1,那么会出现printf打印不出来的现象,因为dma已经占据了串口发送的位置,cpu不暂停dma的时候去抢发送的位置是抢不到了,也只有等到dma发送完成了端口被释放了才可以再printf出去,如果printf用的其它串口,那么是可以正常使用的
用到的API:
HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
串口DMA发送函数,正常会返回HAL_OK,不过在本例中没有使用返回值
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
原来是个弱定义,我们自己重新写,函数会在TX完成时被调用,我们用它清除标志位就可以了。
中断中建议使用标志位代替复杂操作,在主循环中去检测标志位进行相应措施就可以了,养成好习惯。
DMA空闲中断接收示例
在原有的串口1中断服务函数添加新代码
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE)==SET) //判断是否是空闲中断
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1); //清楚空闲中断标志
HAL_UART_DMAStop(&huart1); // 停止DMA传输
receive_num=MAX_BUF-__HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
HAL_UART_Receive_DMA(&huart1,u1_rec_buf,MAX_BUF);//重新打开DMA接收
}
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
mian()主循环中
while (1)
{
if(receive_num!=0)//有了接收
{
printf("\nreceive_num=%d\n",receive_num);//打印接收个数
HAL_UART_Transmit_DMA(&huart1,u1_rec_buf,receive_num);//将接收内容原封不动返还回去
receive_num=0;//清空标志位
}
}
实验现象:
版权声明:本文为CSDN博主「gxt_kt」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/my_id_kt/article/details/122412078
暂无评论