STM32利用中断实现LED亮灭和串口通信的收发

HAL库的中断函数学习

  • 一、题目要求
  • 二、实现LED亮灭
    • 01 CubeMx配置
    • 02 Keil配置
    • 03 实例演示
  • 三、串口中断通信
    • 01 CubeMx配置
    • 02 Keil配置
    • 03 实例演示
  • 四、DMA发送数据
    • 01 什么是DMA
    • 02 DMA传输参数
    • 03 DMA三种方式
    • 04 DMA方式特点
    • 05 CubeMX配置
    • 06 Keil配置
    • 07 实例演示
  • 总结
  • 参考资料

一、题目要求

学习stm32中断、DMA通信原理和编程方法。使用stm32cubemx的HAL库完成以下编程练习:

  1. 用stm32F103核心板的GPIOA端一管脚接一个LED,GPIOB端口一引脚接一个开关(用杜邦线模拟代替)。采用中断模式编程,当开关接高电平时,LED亮灯;接低电平时,LED灭灯。

  2. 采用串口中断方式重做串口通信,分别实现:

    • 1)当stm32接收到字符“s”时,停止持续发送“hello windows!”; 当接收到字符“t”时,持续发送“hello windows!”(提示:采用一个全局标量做信号灯);
    • 2)当stm32接收到字符“stop stm32!”时,停止持续发送“hello windows!”; 当接收到字符“go stm32!”时,持续发送“hello windows!”(提示:要将接收到的连续字符保存到一个字符数组里,进行判别匹配。写一个接收字符串的函数。)
  3. STM32采用串口DMA方式,用115200bps或更高速率向上位机连续发送数据。

二、实现LED亮灭

01 CubeMx配置

  1. 配置PB5引脚为输出,设置labelLEDSTM32利用中断实现LED亮灭和串口通信的收发_第1张图片
  2. PA1引脚为中断输出,类型为上升沿External Interrupt Mode with Rising edge trigger detection,设置labelA1_EXTISTM32利用中断实现LED亮灭和串口通信的收发_第2张图片
  3. 使能NVIC中断STM32利用中断实现LED亮灭和串口通信的收发_第3张图片
  4. 时钟设置为36MHzSTM32利用中断实现LED亮灭和串口通信的收发_第4张图片
  5. 生成Keil文件,进入Keil配置

02 Keil配置

  1. main.c中写入回调函数

    void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
    {
    	if( GPIO_Pin == A1_EXTI_Pin)//判断外部中断源
    	{
    		HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);//翻转LED状态
    	}
    }
    

    STM32利用中断实现LED亮灭和串口通信的收发_第5张图片

  2. 编译运行,没有错误。通过ST-Link烧录到板子上。

03 实例演示

使用杜邦线模拟按键开关,在上升沿触发中断,使LED状态转换一次(由于使用杜邦线模拟按键,所以在引脚悬空的时候,电平变化无法得知,LED呈现随机闪烁的样子)仅演示图片STM32利用中断实现LED亮灭和串口通信的收发_第6张图片

三、串口中断通信

01 CubeMx配置

  1. 配置RCC时钟STM32利用中断实现LED亮灭和串口通信的收发_第7张图片

  2. 设置串口USART1MODE为异步通信Asynchronous,基础参数(波特率为115200 Bits/s。传输数据长度为8 Bit。奇偶检验无,停止位1,接收和发送都使能)和GPIO引脚设置( USART1_RX/USART_TX)使用默认即可STM32利用中断实现LED亮灭和串口通信的收发_第8张图片

  3. 一定要使能中断,NVIC Settings 一栏使能接收中断STM32利用中断实现LED亮灭和串口通信的收发_第9张图片

  4. 配置时钟STM32利用中断实现LED亮灭和串口通信的收发_第10张图片

  5. 生成Keil文件,配置Keil代码

02 Keil配置

  1. printf函数设置,在main.cusart.c中添加头文件#include "stdio.h"之后,在usart.c文件中,添加如下代码,进行重定义

    /* USER CODE BEGIN 1 */
    
    //加入以下代码,支持printf函数,而不需要选择use MicroLIB	  
    //#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)	
    #if 1
    //#pragma import(__use_no_semihosting)             
    //标准库需要的支持函数                 
    struct __FILE 
    { 
    	int handle; 
    }; 
    
    FILE __stdout;       
    //定义_sys_exit()以避免使用半主机模式    
    void _sys_exit(int x) 
    { 
    	x = x; 
    } 
    //重定义fputc函数 
    int fputc(int ch, FILE *f)
    { 	
    	 HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0x0001);  
    	return ch;
    }
    #endif 
    
    
  2. main.c中设置两个字符型数组,用来存放需要判别的字符串(记得添加头文件#include "string.h")。同时设置FLAG标志变量,来判断电脑向stm32发送了哪一个字符串。STM32利用中断实现LED亮灭和串口通信的收发_第11张图片

  3. main.c主函数while(1)中添加一下内容(根据你要发送的字符串来修改)

      while (1)
      {
        /* USER CODE END WHILE */
    
        /* USER CODE BEGIN 3 */
    	  if(flag == 1){		
    	  		printf("go stm32 Hello windows!\r\n");}
    	  else{
    		  //printf("stop stm32 NO!\r\n");}
    		HAL_Delay(500);
    
  4. 重写回调函数,触发中断。在函数开始就判断字符串STM32利用中断实现LED亮灭和串口通信的收发_第12张图片
    代码如下:

    void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
    {
      /* Prevent unused argument(s) compilation warning */
      UNUSED(huart);
      /* NOTE: This function Should not be modified, when the callback is needed,
               the HAL_UART_TxCpltCallback could be implemented in the user file
       */
    	if (strcmp(Uart1_RxBuff, str1) == 0) flag = 0;
    	if (strcmp(Uart1_RxBuff, str2) == 0) flag = 1;
    
     	//if(Uart1_RxBuff[0]=='g') flag = 1;
    	//if(Uart1_RxBuff[0]=='s') flag = 0;
    	
    	if(Uart1_Rx_Cnt >= 255)  //溢出判断
    	{
    		Uart1_Rx_Cnt = 0;
    		memset(Uart1_RxBuff,0x00,sizeof(Uart1_RxBuff));
    		HAL_UART_Transmit(&huart1, (uint8_t *)&cAlmStr, sizeof(cAlmStr),0xFFFF);	
    	}
    	else
    	{
    		Uart1_RxBuff[Uart1_Rx_Cnt++] = aRxBuffer;   //接收数据转存
    	
    		if((Uart1_RxBuff[Uart1_Rx_Cnt-1] == 0x0A)&&(Uart1_RxBuff[Uart1_Rx_Cnt-2] == 0x0D)) //判断结束位
    		{
    			HAL_UART_Transmit(&huart1, (uint8_t *)&Uart1_RxBuff, Uart1_Rx_Cnt,0xFFFF); //将收到的信息发送出去
    			Uart1_Rx_Cnt = 0;
    			memset(Uart1_RxBuff,0x00,sizeof(Uart1_RxBuff)); //清空数组
    		}
    	}
    	
    	HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1);   //再开启接收中断
    }
    
  5. 编译运行,没有错误。通过ST-Link烧录到板子上。

03 实例演示

  1. XCOM串口助手发送接收字符串,观察实验结果。发送t,stm32停止发送;发送s,stm32恢复发送STM32利用中断实现LED亮灭和串口通信的收发_第13张图片STM32利用中断实现LED亮灭和串口通信的收发_第14张图片

  2. 修改Keil中str字符串,实现发送stop stm32,停止串口发送; 发送 go stm32,stm32开始发送。STM32利用中断实现LED亮灭和串口通信的收发_第15张图片STM32利用中断实现LED亮灭和串口通信的收发_第16张图片

四、DMA发送数据

01 什么是DMA

DMA(Direct Memory Access,直接存储器访问) 是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依赖于 CPU 的大量中断负载。否则,CPU 需要从来源把每一片段的资料复制到暂存器,然后把它们再次写回到新的地方。在这个时间中,CPU 对于其他的工作来说就无法使用。STM32利用中断实现LED亮灭和串口通信的收发_第17张图片

02 DMA传输参数

数据传输,首先需要的是1 数据的源地址, 2 数据传输位置的目标地址 ,3 传递数据多少的数据传输量 ,4 进行多少次传输的传输模式 DMA所需要的核心参数,便是这四个.
当用户将参数设置好,主要涉及源地址、目标地址、传输数据量这三个,DMA控制器就会启动数据传输,当剩余传输数据量为0时 达到传输终点,结束DMA传输 ,当然,DMA 还有循环传输模式 当到达传输终点时会重新启动DMA传输。  
也就是说只要剩余传输数据量不是0,而且DMA是启动状态,那么就会发生数据传输。STM32利用中断实现LED亮灭和串口通信的收发_第18张图片

03 DMA三种方式

数据块传送方式、周期挪用方式、交替访存方式

  • 数据块传送方式:在I/O接口电路中设置一个比较大的数据缓冲区,一般能存放一个数据块,I/O接口电路与内存之间的数据交换以数据块为单位。总线仲裁器判定究竟是DMA控制器还是CPU能获得总线的使用权。

  • 周期挪用方式:当I/O接口没有DMA请求时,CPU按程序要求访问内存;一旦I/P接口有DMA请求,则I/O接口挪用一个或几个周期。缺点是:数据输入或庶出过程中实际占用了CPU时间。

  • 交替访存方式:CPU与DMA控制器交替访问内存。不需要总线使用权的申请、建立和归还过程。
    效率高,但实现起来有困难,基本上不被使用。

04 DMA方式特点

  • 内存既可以被CPU访问也可以被DMA控制器访问,CPU和DMA控制器会竞争总线的使用权,因而需要仲裁机制
  • 外部设备与内存之间的整个数据交换过程全部在DMA控制器的控制下完成,CPU能够与外部设备并行工作,大大提高了效率
  • 在DMA方式开始之前CPU要对DMA控制器进行初始化,在DMA方式结束之后,CPU要申请中断,对内存缓冲区进行后处理。

05 CubeMX配置

  1. 设置RCCSTM32利用中断实现LED亮灭和串口通信的收发_第19张图片
  2. 设置串口STM32利用中断实现LED亮灭和串口通信的收发_第20张图片
  3. 使能中断STM32利用中断实现LED亮灭和串口通信的收发_第21张图片
  4. DMA设置在DMA Settings中点击Add添加通道,传输速率设置为中速MediumSTM32利用中断实现LED亮灭和串口通信的收发_第22张图片
  5. DMA后续设置STM32利用中断实现LED亮灭和串口通信的收发_第23张图片
  6. 选择DMASTM32利用中断实现LED亮灭和串口通信的收发_第24张图片
  7. 设置时钟STM32利用中断实现LED亮灭和串口通信的收发_第25张图片
  8. 生成Keil文件,继续配置Keil

06 Keil配置

  1. 定义数据发送数组uint8_t Senbuff[] = "Hello world!"; STM32利用中断实现LED亮灭和串口通信的收发_第26张图片
  2. 主函数中启用DMASTM32利用中断实现LED亮灭和串口通信的收发_第27张图片
  3. 编译文件,没问题。使用ST-Link烧录到板卡上

07 实例演示

通过XCOM串口助手观察,板卡在给电脑不断发送信息STM32利用中断实现LED亮灭和串口通信的收发_第28张图片

总结

HAl库学习已过大半,使用HAl库编程确实十分方便快捷,加速开发进程。但是大量的函数需要自己查找,开始阶段只能是慢慢去学习。嵌入式学习非一日之功,循序渐进,熟能生巧,百炼成钢。也要自己搭配库函数的方法继续学习,使用自己的硬件设备自己操作,体验板卡的乐趣。

参考资料

1、stm32中断原理编程
2、DMA通信原理与编程
3、什么是DMA-百度百科
4、DMA原理
5、古月居DMA博客

你可能感兴趣的:(stm32,单片机,arm)