首页 > 编程语言 >外中断引脚测试NVIC中断系统功能&USART程序设计

外中断引脚测试NVIC中断系统功能&USART程序设计

时间:2025-01-19 18:59:22浏览次数:3  
标签:HAL USART 引脚 中断 void UART 优先级 RCC

文章目录

一、STM32之NVIC中断系统

(一)、中断处理机制:
NVIC的定义:NVIC又叫嵌套向量中断控制器,属于CM4内核。它控制着整个芯片中断相关的功能,是内核的一个外设,与内核紧密联系。

NVIC的作用:STM32G431总共有111个中断源,所以经常会出现两个及以上的中断同时进行或者一个中断正在执行,另一个中断突然来临的情况,因此微控制器都有一个处理中断的机制。而STM32G431引用的是NVIC。

NVIC寄存器:定义在core_cm4.h文件中,CM4内核支持256个中断,包含16个系统异常和240个外部中断,并具有256个可编程中断设置。而STM32芯片只有111个中断,包含9个系统中断和102个可屏蔽中断,具有16级可编程的中断优先级。

(二)、Cortex-M4优先级设定:

  1. 每一个中断都要被指定为抢占优先级或响应优先级(子优先级)。
  2. 每个中断的优先级有一个8位的寄存器来设定,分成高低两个位段。高位段表示抢占优先级,低位段表示响应优先级(子优先级)。而STM32通常只使用Bit7–Bit4四个比特位。
    在这里插入图片描述

(三)、优先级分组设置:

SCB_AIRCRNVIC_IPQx寄存器
抢占优先级响应优先级
01110 : 40位:04位:0~15
11101 : 31位:13位:0~7
21012 : 22位:0~32位:0~3
31003 : 13位:0~71位:1
40114 : 04位:0~150位:0

SCB_AIRCR:应用程序中断及复位控制器
在这里插入图片描述

  1. 中断嵌套:具有高抢占优先级的中断可以在具有低抢占优先级的中断处理过程中被响应。(即高抢占优先级中断可以嵌套在低抢占优先级的中断中)。
  2. 当两个中断源的抢占优先级相同时,这两个中断没有嵌套关系。
    (1). 当一个中断来临时,如果另一个中断正在处理中,则这个后到的中断就要等到前一个中断处理结束后才能开始处理。
    (2). 如果两个中断同时到达,中断控制器则根据它们的响应优先级(子优先级)高低来决定先处理哪一个。
    (3). 如果两个中断抢占优先级和响应优先级(子优先级)都相同,则根据它们在中断向量表中的排位顺寻来判断先处理哪一个。
    在这里插入图片描述

(四)、NVIC相关函数——设置中断优先级组
HAL_NVIC_SetPriority(IRQn_Type, uint32_t, uint32_t):第一个形参指定中断源,第二个形参指定抢占优先级,第三个形参指定响应优先级。
在这里插入图片描述 HAL_NVIC_EnableIRQ(IRQn_Type):用于在NVIC控制器中使能指定中断。
在这里插入图片描述 HAL_NVIC_DisableIRQ(IRQn_Type):用于在NVIC控制器中禁用指定中断。
在这里插入图片描述

二、外中断引脚测试NVIC中断系统功能

(一)、理论知识:
EXTI——外部中断/事件控制器
STM32芯片集成了一个外部中断/事件控制器,由23个能产生事件/中断请求的边沿检测器组成。每个输入线可以独立配置输入类型(事件/中断)和对应的触发事件(上升沿,下降沿或双边沿都触发),并且都可以独立的被屏蔽。

23个中断/事件请求包括:
引脚IO可以作为EXTI线(0-15)
EXTI线16连接到PVD(可编程电压检测器,用于掉电检测)输出
EXTI线17连接到RTC闹钟(一个独立计时器)事件
EXTI线18连接到USB OTG FS(双角色设备控制器)唤醒事件
EXTI线19连接到以太网唤醒事件
EXTI线20连接到USB OTG HS(配置在FS中)唤醒事件
EXTI线21连接到RTC入侵和时间戳事件
EXTI线22连接到RTC唤醒事件

挂起寄存器:保持状态线的中断请求。
在这里插入图片描述外部中断/事件产生过程:
首先,EXTI线输入一个外中断/事件请求到输入线中,经输入线到边沿检测电路中判断触发的类型(上升沿、下降沿或双边沿),然后传到软件中断/事件寄存器中判断是中断还是事件
a. 中断:请求传输到挂起请求寄存器中,再有挂起请求寄存器保存起来,传输到NVIC中断控制器中来判断中断类型激发中断服务函数。(若被中断屏蔽寄存器屏蔽则没有上述过程)
b. 事件:请求传输到脉波发生器中,再由脉波发生器产生事件。(若被事件屏蔽寄存器屏蔽则不产生事件)
(二)、程序设计:
步骤:

  1. 设计中断分组;
  2. 初始化引脚为中断模式;
  3. 配置中断优先级;
  4. 开启中断;
  5. 中断出发作用下,自动执行中断函数,中断函数都指向同一个函数;
  6. 再次判断是否某个GPIO是否产生中断标志?如果产生的话,中断回调。

以下为步骤为1-4步的STM32CubeMX设计展示:
在这里插入图片描述本程序设计主要是将PA0作为外中断传输到NVIC中断控制器中激发EXTI0_IRQHandler函数。

在这里插入图片描述设置优先组:抢占优先组和响应优先组各占2个比特位。
其中滴答计时器抢占优先级为0,响应优先级为1;EXT0的抢占优先级为1,响应优先级为1。

在这里插入图片描述激活EXTI0,为其使能。

以下为函数设计展示

在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述

三、STN32外设之USART

  1. 串口:STM32G431系列的单片机包含四个串口(3个USART,1个UART)。如下图,我们采用的是Link引脚(PA9,PA10),因此,在使用过程中,我们通常只会用到串口一。
    在这里插入图片描述

  2. 串口内部结构图:
    在这里插入图片描述
    发送(TX):TDR寄存器——TXFIFO——移位寄存器(TX)——引脚
    接收(RX):引脚——移位寄存器(RX)——RXFIFO——RDR寄存器

  3. 发送步骤:
    a. 向CR1的UE位置1,使串口使能。
    b.在CR1的M位定义字长。
    c.在CR2对停止位数量进行编程(STOP位)。
    d.对DMA进行配置。
    e.配置BRR寄存器的波特率
    f.发送器对TE位置1,发送一个空闲帧作为第一次数据发送。
    g.把要发送的数据写进USART_DR寄存器中,硬件自动发送,TXE清零。
    h.再写入最后一个数据字后,等待TC=1,表示最后一个数据帧的传输结束。

  4. 接收步骤
    a.向CR1的UE位置1,使串口使能。
    b.在CR1的M位定义字长。
    c.在CR2对停止位数量进行编程(STOP位)。
    d.对DMA进行配置。
    e.配置BRR寄存器的波特率
    f.将CR1的RE位置1,检测序列,当检测到数据字从1→0后开始接收(因为起始位为低电压)。
    g.接收到字符,RXNE置1,移位寄存器的内容传送到RDR寄存器中。
    h.如果RXNEIE置1,则产生中断。
    i.软件读取DR寄存器,RXNE自动清零(有些情况需要手动写入0来清零)。

*波特率:控制串口的接收和发送频率。

四、USART程序设计&总结详解

(一)、串口编程结构体介绍:

  1. 句柄结构体:与软件相关。
    在这里插入图片描述

  2. 串口初始化结构体:针对硬件串口的相关属性和硬件寄存器配置密切相关。
    在这里插入图片描述
    (二)、串口编程的实现——串口初始化
    在这里插入图片描述初始化运行过程:
    首先定义一个句柄结构体变量huart1;
    然后定义串口号和串口参数数值;
    同时在HAL_UART_Init()函数中调用HAL_UART_MspInit()对GPIOA进行初始化配置;
    最后进行串口中断的配置。
    (三)、串口编程的实现——串口发送函数【HAL_UART_Transmit()】
    在这里插入图片描述如上为串口发送的函数形式,具体过程在上文中已经讲到就不重复赘述,总之在程序设计时,我们只需要直接调用HAL_UART_Transmit()函数输入串口、数据、字节数和限定时间就即可。
    (四)、串口编程的实现——串口接收函数(中断形式)

在这里插入图片描述在这里插入图片描述

在这里插入图片描述串口接收函数采用了中断形式,首先在stm32g4xx_it.c中进行串口中断处理调用HAL_UART_IRQHandler()函数,如果没有错误发生则调用中断指针函数huart->RxISR()跳转到HAL_UART_Receive_IT()中指向UART_RxISR_16BIT_FIFOEN或UART_RxISR_8BIT_FIFOEN,最后调用执行回调函数HAL_UART_RxCpltCallback()到main。

(五)、代码部分
1.main.c

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "led\bsp_led.h"
#include "key\bsp_key.h"
#include "lcd\bsp_lcd.h"
#include "usart\bsp_usart.h"

//变量创建区
__IO uint32_t uwTick_Key_Set_Point = 0;//控制Key_Proc的执行速度
__IO uint32_t uwTick_Lcd_Set_Point = 0;//控制Lcd_Proc的执行速度
__IO uint32_t uwTick_Usart_Set_Point = 0;//控制Usart_Proc的执行速度

//按键扫描专用变量
unsigned char ucKey_Val, ucKey_Down, ucKey_Up, ucKey_Old;
//LCD显示专用变量
unsigned char Lcd_Disp_String[25];
//串口专用变量
	int counter = 0;
	char str[40];
	unsigned char rx_buffer;
	
//子函数声明区
void SystemClock_Config(void);
void Key_Proc(void);
void Lcd_Proc(void);
void Usart_Proc(void);

//主函数
int main(void)
{
  //内核和时钟的初始化
  HAL_Init();
  SystemClock_Config();

  //外设函数的初始化
  LED_Init();
  KEY_Init();
  LCD_Init();
	
  USART1_Init();
	HAL_UART_Receive_IT(&huart1, &rx_buffer, 1);	
	
  while (1)
  {
		
	  Key_Proc();
	  Lcd_Proc();
	  Usart_Proc();
		
  }
  
}

void Key_Proc()
{
	
	if((uwTick - uwTick_Key_Set_Point) < 100) return;//减速函数
	uwTick_Key_Set_Point = uwTick;
	
	ucKey_Val = Key_Scan();
	ucKey_Down = ucKey_Val & (ucKey_Old ^ ucKey_Val);
	ucKey_Up = ~ucKey_Val & (ucKey_Old ^ ucKey_Val);
	ucKey_Old = ucKey_Val;
	
	if(ucKey_Down == 4)
	{
		LED_Disp(0xFF);
		
	}
	
	if(ucKey_Down == 3)
	{
		
		LED_Disp(0x00);
		
	}

}

void Lcd_Proc(void)
{
	
	if((uwTick - uwTick_Lcd_Set_Point) < 1000) return;//减速函数
	uwTick_Lcd_Set_Point = uwTick;
	
}

void Usart_Proc(void)
{
	
	if((uwTick - uwTick_Usart_Set_Point) < 500) return;//减速函数
	uwTick_Usart_Set_Point = uwTick;	
	
	sprintf(str, "%04d:Hello,world.\r\n", counter);
	HAL_UART_Transmit(&huart1,(unsigned char *)str, strlen(str), 50);
	HAL_Delay(500);
	
	if(++counter == 10000){
		counter = 0;
	}
	
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	
	LED_Disp(0xFF);
	HAL_Delay(300);
	LED_Disp(0X00);
	
	HAL_UART_Receive_IT(&huart1, &rx_buffer, 1);
}

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV3;
  RCC_OscInitStruct.PLL.PLLN = 20;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

void Error_Handler(void)
{
	
  __disable_irq();
  while (1)
  {
  }

}

#ifdef  USE_FULL_ASSERT

void assert_failed(uint8_t *file, uint32_t line)
{
	
}
#endif

  1. bsp_usart.c
#include "usart\bsp_usart.h"

UART_HandleTypeDef huart1;

void USART1_Init(void)
{
	
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 9600;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
  huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_SetTxFifoThreshold(&huart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_SetRxFifoThreshold(&huart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_DisableFifoMode(&huart1) != HAL_OK)
  {
    Error_Handler();
  }

}

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(uartHandle->Instance==USART1)
  {

    __HAL_RCC_USART1_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART1 GPIO Configuration
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    HAL_NVIC_SetPriority(USART1_IRQn, 1, 0);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
 
  }
	
}

void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{

  if(uartHandle->Instance==USART1)
  {

    __HAL_RCC_USART1_CLK_DISABLE();

    /**USART1 GPIO Configuration
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);

    HAL_NVIC_DisableIRQ(USART1_IRQn);

  }
	
}

  1. bsp_usart.h
#include "main.h"

extern UART_HandleTypeDef huart1;

void USART1_Init(void);

标签:HAL,USART,引脚,中断,void,UART,优先级,RCC
From: https://blog.csdn.net/2301_81433986/article/details/144539639

相关文章

  • 求助,51单片机定时器中断控制数码管
    遇到的问题是:动态显示时,如果位选变化间隔太小,会导致计数的部分失效,数码管一直显示0000,间隔在30时数字会有变化,但是显示闪烁的效果太明显了代码如下:#defineuintunsignedint#defineucharunsignedchar//位选定义sbitwei0=P1^3;sbitwei1=P1^4;sbitwei2=P1^5;sbi......
  • 【STM32-学习笔记-7-】USART串口通信
    文章目录USART串口通信Ⅰ、硬件电路Ⅱ、常见的电平标准Ⅲ、串口参数及时序Ⅳ、STM32的USART简介数据帧起始位侦测数据采样波特率发生器Ⅴ、USART函数介绍Ⅵ、USART_InitTypeDef结构体参数1、USART_BaudRate2、USART_WordLength3、USART_StopBits4、USART_Parity5、USART......
  • 27 Xbox蓝牙连接不稳定,游戏中断联,新手柄,反映延持,忽然失联的解决方法,蓝牙连接后无法自
    27新买了一个Xbox,蓝牙连接后有时会突然断联,游戏中会忽然失灵一般新手柄硬件绝对没问题,电脑自己的硬件以及软件驱动也没问题,那就是手柄自带驱动不行,!更新!一个新手柄驱动的即可解决方法1.下载一个软件“XboxAccessories”,微软商店或者网上直接找均可,我这用的网络的网址,因为微软......
  • don‘t sleep一款阻止系统意外中断,保证工作娱乐安全运行的软件!
    软件介绍给大家分享一款大小仅500多KB,用于防止系统进入关机、重启、待机、睡眠、休眠、注销、屏幕保护等状态功能的软件,避免工作或者娱乐受到打扰。软件主要由阻止和允许功能构成。例如当你在下载、暂时离开、工作的时候使用阻止功能可以避免系统进入不同的电源管理模式......
  • 第七章 中断
    第七章中断本文是对《操作系统真象还原》第七章学习的笔记,欢迎大家一起交流。a启用中断本节的主要任务是打开中断,并且使用时钟中断测试知识部分中断分类中断可以分为外部中断和内部中断,这已经是老生常谈的话题了,不再多说。外部中断又可以分为可屏蔽中断和不可屏蔽中断,其......
  • 如何处理Redis连接中断的问题?
    当您遇到Redis连接中断(如“Rediswentaway”)的问题时,这通常是由于网络连接不稳定、配置参数不合理或资源不足等原因引起的。为了解决这个问题,您可以按照以下步骤进行排查和优化:检查网络连接:确保服务器与Redis实例之间的网络连接稳定可靠。可以通过ping命令测试延迟情况,或者使......
  • 如何解决服务器连接卡机和远程控制端口频繁中断的问题?
    用户反映服务器CPU和内存使用率不高,但客户端连接服务器时经常出现卡机现象,远程控制端口也频繁中断。用户怀疑是网络故障,请求服务商协助排查。解决方案:针对您提到的服务器连接卡机和远程控制端口频繁中断的问题,我们进行了初步排查。测试结果显示,远程登录操作本身并不慢,可能是由于......
  • 蓝桥杯单片机基础部分——2、定时器中断
    一、介绍关于蓝桥杯单片机定时器中断部分的一些代码,本期主要讲应用,就是看着题目可以写出相对应的代码,至于原理后面会详细讲,在这了解一下二、中断首先我们先来了解什么是中断,官方给出的是“中断系统是为使CPU具有对外界紧急事件的实时处理能力而设置的”,这里相对好理解,就......
  • 如何解决20GB数据远程下载频繁中断的问题?
    遇到20GB数据远程下载频繁中断的问题,通常是由于网络连接不稳定、服务器配置不当或下载方式不理想所导致的。为了帮助您顺利解决问题,您可以按照以下步骤进行排查和处理:检查网络稳定性:首先,请确认您的网络连接是否稳定。由于下载大文件需要长时间保持稳定的网络连接,任何网络波动......
  • 浅述中断机制
    写在前面本文重在讨论8086处理器的中断的原理与分类,以及一些中断向量表的内容。由于笔者水平有限,随笔中难免有些许纰漏和错误,希望广大读者能指正。中断的分类我们先来看看中断的分类。大体上来说,中断可以分为外部硬件中断、内部中断、软中断。中断就是打断、暂停的意思,中断让C......