stm32cubemx下stm32中断与串口DMA通信

目录

一、外部中断,实现LED的闪亮与熄灭

1.创建工程

2.编译与写程序

3.烧录

4.实验结果

二、串口中断实现串口通信

1.创建工程

2.重定向printf和scanf

3.运行结果

4.UART接收中断

三、串口DMA接收发数据

1.创建工程

2.测试例程1

3.测试结果

4.测试例程2

​ 

5. 测试程序

 四、总结

五、参考链接


 

一、外部中断,实现LED的闪亮与熄灭

1.创建工程

 

 

 

 

 

 

 

 然后自动生成程序。

2.编译与写程序

以看到生成的中断服务函数 void EXTI1_IRQHandler(void)

 

可以看到该函数又调用了HAL_GPIO_EXTI_IRQHandler(),于是继续跳转到下一函数 

 

可以看到在这之中调用了HAL_GPIO_EXTI_Callback(),接下来的函数可以看到是_weak开头,则需要用户自己写函数。 

 

此时到main.c中书写callback程序,用到的库函数是HAL_GPIO_TogglePin(),该函数的作用是翻转电平,即中断一产生,则翻转一次电平。

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{  
{HAL_GPIO_TogglePin(led1_GPIO_Port,led1_Pin);
}
}

 

 

接着进行编译。

3.烧录

 

通电下将boot0置0,然后再次reset后可运行

4.实验结果

此处因为stm32c8t6没有按键,因此选择使用杜邦线代替开关,每接触一次接地,则产生一次中断

 

二、串口中断实现串口通信

1.创建工程

RCC和SYS和CLOCK设置如上面一样

下面设置串口USART1,在MODE下选择Asynchronous(异步通信模式),并且使得USART1中断使能

接着就可以直接生成工程了

2.重定向printf和scanf

#include <stdio.h>
extern UART_HandleTypeDef huart1;   //声明串口

 

  • 在 stm32f1xx_hal.c 中重写fget和fput函数

 

/**
  * 函数功能: 重定向c库函数printf到DEBUG_USARTx
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
int fputc(int ch, FILE *f)
{
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
  return ch;
}
 
/**
  * 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
int fgetc(FILE *f)
{
  uint8_t ch = 0;
  HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
  return ch;
}

 

 

在main.c中添加

 

 #define RXBUFFERSIZE  256
char RxBuffer[RXBUFFERSIZE]; 

 

 

	printf("hello world\n");
			HAL_Delay(1000);

 

在target勾选Use MicroLIB,需要调用微型库

 

3.运行结果

 

4.UART接收中断

具体流程:

  1. 初始化串口
  2. 在main中第一次调用接收中断函数
  3. 进入接收中断,接收完数据  进入中断回调函数
  4. 修改HAL_UART_RxCpltCallback中断回调函数,处理接收的数据,
  5.  回调函数中要调用一次HAL_UART_Receive_IT函数,使得程序可以重新触发接收中

代码实现

并在main.c中添加下列定义:

#include <string.h>
 
#define RXBUFFERSIZE  256     //最大接收字节数
char RxBuffer[RXBUFFERSIZE];   //接收数据

 

在main()主函数中,调用一次接收中断函数

/* USER CODE BEGIN 2 */
	HAL_UART_Receive_IT(&huart1, RxBuffer, 1);
/* USER CODE END 2 */

 

在main.c下方添加中断回调函数

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) 
{
	if(huart->Instance==USART1)
	{	
		HAL_UART_Transmit(&huart1,RxBuffer,1,0xff);
	}
	HAL_UART_Receive_IT(&huart1, RxBuffer, 1); 
}

 

实验成果

 

  可以看到串口回显。

三、串口DMA接收发数据

1.创建工程

其余设置参考上面串口设置

以下为不同点

进入DMA Settings

点击add,选择USART_RX USART_TX 传输速率设置为中速 

DMA传输模式为正常模式

DMA内存地址自增,每次增加一个Byte(字节)

 

 

右侧点击System Core 点击DMA

点击add添加MENTOMEN 

 

Normal:正常模式
当一次DMA数据传输完后,停止DMA传送 ,也就是只传输一次

DMA指针递增设置

Increment Address:地址指针递增(上方有介绍)。

左侧Src Memory 表示外设地址寄存器

功能:设置传输数据的时候外设地址是不变还是递增。如果设置 为递增,那么下一次传输的时候地址加 Data Width个字节,

右侧Dst Memory 表示内存地址寄存器

功能:设置传输数据时候内存地址是否递增。如果设置 为递增,那么下一次传输的时候地址加 Data Width个字节,

这个Src Memory一样,只不过针对的是内存。

然后即可生成工程。

2.测试例程1

在main.C中添加:

 

 /* USER CODE BEGIN Init */
	uint8_t Senbuff[] = "HELLO WORLD";  //定义数据发送数组
  /* USER CODE END Init */

 

while循环:

  while (1)
  {
    /* USER CODE END WHILE */
			HAL_UART_Transmit_DMA(&huart1, Senbuff, sizeof(Senbuff));
	        HAL_Delay(1000);
    /* USER CODE BEGIN 3 */
  }

 

3.测试结果

 

4.测试例程2

STM32 IDLE 接收空闲中断

STM32的IDLE的中断产生条件:在串口无数据接收的情况下,不会产生,当清除IDLE标志位后,必须有接收到第一个数据后,才开始触发,一但接收的数据断流,没有接收到数据,即产生IDLE中断

代码:

uart.c

 

volatile uint8_t rx_len = 0;  //接收一帧数据的长度
volatile uint8_t recv_end_flag = 0; //一帧数据接收完成标志
uint8_t rx_buffer[100]={0};  //接收数据缓存数组

 

  /* USER CODE BEGIN USART1_Init 2 */
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); //使能IDLE中断
 
//DMA接收函数,此句一定要加,不加接收不到第一次传进来的实数据,是空的,且此时接收到的数据长度为缓存器的数据长度
	HAL_UART_Receive_DMA(&huart1,rx_buffer,BUFFER_SIZE);
 
  /* USER CODE END USART1_Init 2 */

 

 uart.h

extern UART_HandleTypeDef huart1;
extern DMA_HandleTypeDef hdma_usart1_rx;
extern DMA_HandleTypeDef hdma_usart1_tx;
/* USER CODE BEGIN Private defines */
 
 
#define BUFFER_SIZE  100  
extern  volatile uint8_t rx_len ;  //接收一帧数据的长度
extern volatile uint8_t recv_end_flag; //一帧数据接收完成标志
extern uint8_t rx_buffer[100];  //接收数据缓存数组

 

工程里没有.h文件,需要在文件夹里寻找 

 

 

 

 

 

main.c

 

 

/*
*********************************************************************************************************
* 函 数 名: DMA_Usart_Send
* 功能说明: 串口发送功能函数
* 形  参: buf,len
* 返 回 值: 无
*********************************************************************************************************
*/
void DMA_Usart_Send(uint8_t *buf,uint8_t len)//串口发送封装
{
 if(HAL_UART_Transmit_DMA(&huart1, buf,len)!= HAL_OK) //判断是否发送正常,如果出现异常则进入异常中断函数
  {
   Error_Handler();
  }
 
}
 
 
 
/*
*********************************************************************************************************
* 函 数 名: DMA_Usart1_Read
* 功能说明: 串口接收功能函数
* 形  参: Data,len
* 返 回 值: 无
*********************************************************************************************************
*/
void DMA_Usart1_Read(uint8_t *Data,uint8_t len)//串口接收封装
{
	HAL_UART_Receive_DMA(&huart1,Data,len);//重新打开DMA接收
}

这里需要定义在main函数前面,否则在main函数里调用会报错,也可以在main之前先声明函数。

 

while循环

 

 

 while (1)
  {
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
		 if(recv_end_flag == 1)  //接收完成标志
		{
			
			
			DMA_Usart_Send(rx_buffer, rx_len);
			rx_len = 0;//清除计数
			recv_end_flag = 0;//清除接收结束标志位
//			for(uint8_t i=0;i<rx_len;i++)
//				{
//					rx_buffer[i]=0;//清接收缓存
//				}
				memset(rx_buffer,0,rx_len);
  }
		HAL_UART_Receive_DMA(&huart1,rx_buffer,BUFFER_SIZE);//重新打开DMA接收
}

stm32f1xx_it.c中

#include "usart.h"
 
void USART1_IRQHandler(void)
{
	uint32_t tmp_flag = 0;
	uint32_t temp;
	tmp_flag =__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE); //获取IDLE标志位
	if((tmp_flag != RESET))//idle标志被置位
	{ 
		__HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位
		//temp = huart1.Instance->SR;  //清除状态寄存器SR,读取SR寄存器可以实现清除SR寄存器的功能
		//temp = huart1.Instance->DR; //读取数据寄存器中的数据
		//这两句和上面那句等效
		HAL_UART_DMAStop(&huart1); //
		temp  =  __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);// 获取DMA中未传输的数据个数   
		//temp  = hdma_usart1_rx.Instance->NDTR;//读取NDTR寄存器 获取DMA中未传输的数据个数,
		//这句和上面那句等效
		rx_len =  BUFFER_SIZE - temp; //总计数减去未传输的数据个数,得到已经接收的数据个数
		recv_end_flag = 1;	// 接受完成标志位置1	
	 }
  HAL_UART_IRQHandler(&huart1);
 
}

 

5. 测试程序

 

 四、总结

通过这次实验发现中断与串口DMA通信,可以提高程序的运行效率,DMA可以直接访问存储器,没有经过CPU,CPU负担减轻,熟悉了串口通信的基本函数和DMA通信的基本函数。

五、参考链接

 qq_60678931的博客_Laul Ken-Yi_CSDN博客

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值