STM32中断和串口通信

目录

一.中断实现LED亮灭

1.新建工程

2.编译写程序

3. 烧录

4.实验结果

二.串口通信

 1.创建工程

2.重定向printf和scanf

 4. UART接收中断

4.1 代码实现:

4.2实验成果

 三、串口DMA接收发数据

1.创建工程 

2. 测试例程1

3. 测试结果

 4. 测试例程2

 5测试程序

四.心得

五.参考文献


一.中断实现LED亮灭

1.新建工程

1.1选择芯片

 1.2 设置led,PA5引脚和外部中断EXTI1,PB1

 1.3给中断设置下降沿触发,并且上拉电阻。

 1.4 配置中断优先级,因为此处只有一个中断,因此它的优先级为0,为最高

1.5配置时钟,设时钟频率为72MHZ

 1.6自动生成程序

2.编译写程序

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

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

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

3. 烧录

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

4.实验结果

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

 

二.串口通信

 1.创建工程

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

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

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

2.重定向printf和scanf

之后可以直接使用重定向的函数

  • 在 stm32f1xx_hal.c中包含#include <stdio.h>                                                                   #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中添加 

 

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

 3. 运行结果

 4. UART接收中断

4.1 代码实现:

 并在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); 
}

4.2实验成果

此处需要使用XCOM调试助手

 三、串口DMA接收发数据

1.创建工程 

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

以下为不同点

进入DMA Settings

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

DMA传输模式为正常模式

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

右侧点击System view 点击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的中断产生条件:在串口无数据接收的情况下,不会产生,当清除IDLE标志位后,必须有接收到第一个数据后,才开始触发,一但接收的数据断流,没有接收到数据,即产生IDLE中断

usart.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 */

 usart.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文件,需要在文件夹里寻找 

 mian.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减负。但是感觉还是迷迷糊糊的,没有搞明白他的原理。

五.参考文献

【STM32】HAL库 STM32CubeMX教程三----外部中断(HAL库GPIO讲解)_Z小旋-CSDN博客

【STM32】HAL库 STM32CubeMX教程十一---DMA (串口DMA发送接收)_Z小旋-CSDN博客

【STM32】HAL库 STM32CubeMX教程四---UART串口通信详解_Z小旋-CSDN博客_hal_uart_transmit stm32cubemx下stm32中断与串口DMA通信_Laul Ken-Yi的博客-CSDN博客


版权声明:本文为Yylife0609原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。