精华内容
下载资源
问答
  • STM32 串口中断服务函数(学习笔记:2)
    千次阅读
    2021-08-06 15:43:15

    参考教程:野火 

    以串口1为例,在利用串口进行接受数据时,我们要对STM32进行串口的中断配置。

    先对进行宏定义(起个别名),方便移植:

    
    #define  DEBUG_USART_IRQ                USART1_IRQn        //串口中断的中断源
    #define  DEBUG_USART_IRQHandler         USART1_IRQHandler

    若要调用相关的中断功能,在NVIC中配置相关的中断优先级和中断号。

    以下是中断函数(有每一步操作的详细备注):

    //中断函数 
    static void NVIC_Configuration(void)
    {
    	/*定义一个名字为NVIC_InitStructure的结构体*/
      NVIC_InitTypeDef NVIC_InitStructure;
      
      /* 用NVIC_PriorityGroupConfig(NVIC_PriorityGroup_n)
    	                选择中断数量种类(n可取值0~4); */
      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
      
      /* 配置USART为中断源 */
      NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
      /* 抢断优先级 (抢占优先级)*/
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
      /* 子优先级(响应优先级) */
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
      /* 使能中断(IQR通道使能) */
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      /* 根据指定的参数初始化NVIC寄存器*/
      NVIC_Init(&NVIC_InitStructure);
    }

    接着在串口配置中写入以下函数:

    	// 完成串口的初始化配置
    	USART_Init(DEBUG_USARTx, &USART_InitStructure);
    	
    	// 串口中断优先级配置
    	NVIC_Configuration();
    	
    	// 使能串口接收中断
    	USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);
    				      //^^接收数据寄存器非空,接收到数据产生中断
    	
    	// 使能串口
    	USART_Cmd(DEBUG_USARTx, ENABLE);	    
    以下这段代码是存放在 stm32f4xx_it.c 文件中的,该文件用来集中存放外设中断服务函数。当我们使 能了中断并且中断发生时就会执行这里的中断服务函数。
    
    	//中断服务函数
    void DEBUG_USART_IRQHandler(void) 
    { 
    	
    	uint8_t ucTemp;
    	if (USART_GetITStatus(DEBUG_USARTx,USART_IT_RXNE)!=RESET)
    		{
    				ucTemp = USART_ReceiveData( DEBUG_USARTx );
    					USART_SendData(DEBUG_USARTx,ucTemp);
    		}
    }
    

    解释:1当外部设备(如串口调试助手)给单片机发数据时
    2单片机检测到接收数据寄存器非空:表示有数据
    3进中断服务函数调用USART_GetITStatus()再次检测标志位是否置1 防止产生误中断
    4再利用函数USART_ReceiveData()把数据放入变量ucTemp
    5最后利用函数USART_SendData()发送数据回来(回显功能)

    更多相关内容
  • 学习笔记——stm32串口中断函数的逻辑理解

    千次阅读 多人点赞 2020-12-10 22:04:51
    这片文章主要是讲解原子给的代码里面的串口中断中断函数,前面是我个人的学习路径。 关于stm32串口的学习,主要分为以下几个点 1.USART的功能和内部结构。 功能包括同步、异步模式、双工通信、半工通信等 内部结构...

    这片文章主要是讲解原子给的代码里面的串口中断的中断函数,前面是我个人的学习路径。

    关于stm32串口的学习,主要分为以下几个点
    1.USART的功能和内部结构。
    功能包括同步、异步模式、双工通信、半工通信等
    内部结构,参考这张图片,去把各个部分了解清楚就差不多了。
    在这里插入图片描述

    2.USART的相关寄存器,看一看有个映像就可以了,主要了解一下这些寄存器对应上面的图,设置哪一部分的就ok了。
    在这里插入图片描述
    3.USART的收发格式,波特率的设置,了解硬件流控制。
    4.USART的中断请求与模式配置,这个比较重要,要认真看一下,因为你要根据这个来配置串口发生什么中断。
    下面附一篇文章,供大家参考学习,文章的博主还是讲得挺详细的。
    添加链接描述
    剩下的,再翻一下参考手册,应该没什么问题。
    再附上一张USART的引脚图在这里插入图片描述

    这是我学习的路径。

    基本上stm32的串口配置都差不多,基本上都是直接参考的原子或者野火的代码,但是关于原子给的串口中断函数的理解,我找了找,基本没找到什么比较详细的文章。
    我也是花了一点点时间才搞清楚这段代码的逻辑。

    串口配置的代码直接用原子的,如果你已经很熟悉配置,可以直接跳过看后面串口中断函数解释。

    头文件

    #define USART1_REC_LEN		200  	//定义最大接收字节数 200
    extern u8  USART1_RX_BUF[USART1_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 
    extern u16 USART1_RX_STA;         		//接收状态标记
    void USART1_Init(u32 bound);
    

    配置代码

    /*******************************************************************************
    * 函 数 名         : USART1_Init
    * 函数功能		   : USART1初始化函数
    * 输    入         : bound:波特率
    * 输    出         : 无
    *******************************************************************************/ 
    void USART1_Init(u32 bound)
    {
       //GPIO端口设置
    	GPIO_InitTypeDef GPIO_InitStructure;
    	USART_InitTypeDef USART_InitStructure;
    	NVIC_InitTypeDef NVIC_InitStructure;
    	
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
     
    	
    	/*  配置GPIO的模式和IO口 */
    	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//TX			   //串口输出PA9
    	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;	    //复用推挽输出
    	GPIO_Init(GPIOA,&GPIO_InitStructure);  /* 初始化串口输入IO */
    	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//RX			 //串口输入PA10
    	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;		  //浮空输入
    	GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化GPIO */
    	
    
    	//USART1 初始化设置
    	USART_InitStructure.USART_BaudRate = bound;//波特率设置
    	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
    	USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
    	USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
    	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
    	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式
    	USART_Init(USART1, &USART_InitStructure); //初始化串口1
    	
    	USART_Cmd(USART1, ENABLE);  //使能串口1 
    	
    	USART_ClearFlag(USART1, USART_FLAG_TC);
    		
    	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启接收中断
    
    	//Usart1 NVIC 配置
    	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;		//子优先级3
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
    	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器、	
    }
    

    如果其中的一些函数不懂,查固件库手册就好了,固件库中有函数详细的说明。
    上面的配置代码中强调一点

    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启接收中断
    

    这行代码,这个串口中断函数第二个参数,要仔细去查一下固件库手册,它还有其他的参数,可以不配置成接收中断。

    下面是中断函数
    首先强调一点0x0d和0x0a在ASCII码表里面表示\r和\n,分别表示回车和换行

    
    /*******************************************************************************
    * 函 数 名         : USART1_IRQHandler
    * 函数功能		   : USART1中断函数
    * 输    入         : 无
    * 输    出         : 无
    *******************************************************************************/ 
    //0x0d和0x0a在ASCII码表里面表示\r和\n,分别表示回车和换行
    void USART1_IRQHandler(void)                	//串口1中断服务程序
    {
    1	u8 r;
    2	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断
    3	{
    4		r =USART_ReceiveData(USART1);//(USART1->DR);	//读取接收到的数据
    5		if((USART1_RX_STA&0x8000)==0)//接收未完成
    6		{
    7			if(USART1_RX_STA&0x4000)//接收到了0x0d
    8			{
    9				if(r!=0x0a)USART1_RX_STA=0;//接收错误,重新开始
    10				else USART1_RX_STA|=0x8000;	//接收完成了 
    11			}
    12			else //接收到0X0D之前或0x0D
    13			{	
    14				if(r==0x0d)USART1_RX_STA|=0x4000;
    15				else
    16				{
    17					USART1_RX_BUF[USART1_RX_STA&0X3FFF]=r;
    18					USART1_RX_STA++;
    19					if(USART1_RX_STA>(USART1_REC_LEN-1))USART1_RX_STA=0;//接收数据错误,重新开始接收	  
    				}		 
    			}
    		}   		 
    	} 
    } 	
    

    为了方便讲解,我在每行代码前加上了序号,移植的时候去掉就可以了。
    其中
    USART1_RX_BUF[],USART1_RX_STA在头文件中定义过了

    #define USART1_REC_LEN		200  	//定义最大接收字节数 200
    extern u8  USART1_RX_BUF[USART1_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 
    extern u16 USART1_RX_STA;         		//接收状态标记
    

    先说说这段代码的整体设计思路,这段代码是定义了一个协议,你所向单片机发送的字符必须以“/r/n”结尾(关于/r和/n,文章最后有补充说明),然后在中断函数里面通过判断\r和\n的ascll值使定义的 USART1_RX_STA 这个“状态寄存器”的相应位置1,然后在主函数里面判断 USART1_RX_STA这个“状态寄存器”的标志位的值,来发送数据。

    看完之后是不是觉得很神奇,USART1_RX_STA明明是定义的一个变量,怎么就变成“寄存器了”,这就是设计师奇妙的设计,定义的USART1_RX_STA是两个字节的变量,有16个位可以用,但是我们的最大接收字节只要200个,就算有1000个字节我们也用不到2的15次方的大小,字节再多stm32就没这么大的存储空间了,所以200个字节已经足够我们一次接收的数据了。显然16个位我们是用不完的,所以我们可以把USART1_RX_STA的高位设置成状态标志位,低位用来计数。如图所示
    在这里插入图片描述
    图中可以看到,0-13位用来记录字符的长度,高两位作为状态标志位。
    下面开始正式讲解代码。

    1.当接收到数据时,会产生接收中断,进入中断函数,将接收到的数据存入变量r中,注意,r只占一个字节。

    2.代码第5行,判断最高位的状态,USART1_RX_STA最高位是接收到\n(0x0a),才会置1的状态标志位,当它置1时,标志着整个数据已经接收完毕,main中就是判断这个位是否为1来进行发送数据的。很显然,能够进入中断,那说明接收还未完成,所以接下来就是执行第5行下面的代码。

    3.第7行是判断USART1_RX_STA次高位,USART1_RX_STA次高位是否置1,这要取决于是否接收到了倒数第2个字符0x0d。

    • 如果上一次接收中断接收到了0x0d,就会把次高位置1,代码第7行检测到了USART1_RX_STA次高位置1后,就会进入if里面(执行代码第9或者第10行),判断数据最后一位是否是0x0a(\n),如果最后一位不是0x0a,那说明这串字符不是按照程序所定义的协议发送给单片机的,单片机自然也就识别不了,这个数据就会被丢掉(代码第9行),USART1_RX_STA清零(包括里面的记录的数据长度和状态标志位),重新接收新的发送过来的数据;如果最后一位是0x0a,那这个字符串就是按照协议发送给单片机的,程序执行第10行,将USART1_RX_STA的最高位置1,标志这串字符串接收完毕。USART1_RX_STA最高位置1后,main函数中就可以检测它进行操作了。
    • 如果上一次接收中断未接收到了0x0d,那么USART1_RX_STA次高位就不会被置1,在程序走到第7行时,检测到USART1_RX_STA次高位为0,程序就会执行第12行的else。

    4.程序第12行的else中,要判断接收到的数据是0x0d还是0x0d之前的数据。

    • 如果这个数据是0x0d,那么就将USART1_RX_STA次高位置1,在下一次进入接收中断时,就会执行上述3中的步骤了,程序第7行就能够检测到USART1_RX_STA次高位的状态了。
    • 如果这个数据是0x0d之前的数据,就执行17-19行代码,这三行代码的作用是将这个字节存入USART1_RX_BUF[USART1_REC_LEN]数组(头文件中定义过了)中,记录字符的长度,判断字符长度是否发生溢出(最大200字节)。
    • USART1_RX_BUF[USART1_RX_STA&0X3FFF]=r;说明一下这行代码中的USART1_RX_STA&0X3FFF,USART1_RX_STA的0-13位时用来记录数据长度的,这句话的意思就是去掉了USART1_RX_STA中的高两位状态位,剩下的数据与数组的值相对应。

    5.看了上面4点解释脑子里是不是还是很乱,这也就是这段代码难的地方,不能够顺序的去看这个代码,不然还是理不清逻辑,这个串口中断,就相当于一个循环,要判断到接收数据完毕了才会结束这个循环,怎么判断结束是否完毕呢?就看USART1_RX_STA的高两位的状态。下面再来屡屡逻辑。

    • [0] 来了一串数据,假设有50个字符,占50个字节,再加上协议定义的结尾\r\n,一共是52个字节。

    • [1] 当接收到0x0d(\r,也是第51个字符)之前的字符,串口中断函数执行的过程是前4行执行完,第5行条件成立进入if,执行到第7行时,条件不成立,转至12行,此时14行进行判断,这个字符不是0x0d,条件不成立,执行17-19行,将数据存入数组中。

    • [2] 当0x0d前面的数据接收完时,下一个到来的字符是0x0d(\r)时,此时USART1_RX_STA的最高位和次高位都还是0,程序执行到第7行时,条件依然不会成立,程序会跳转置12行的else,此时程序14行的判断成立,会将USART1_RX_STA的次高位置1,然后结束这次中断。

    • [3] 接着上面的步骤,0x0d过了是最后一个字符0x0a(\n),当接收到这个字符时,第5行条件成立,进入if,执行到程序第7行时,由于上一步接收到了0x0d,已经把USART1_RX_STA的次高位置1了,程序就进入if,执行8-11行的代码,判断是否是0x0a,如果不是,执行程序第9行,如果是,执行第10行,将USART1_RX_STA最高位置1,此时整个数据接收就完成了,剩下的交给主函数处理了。

    接下来是主函数的处理程序了,把这个串口中断函数理解清楚了,主函数也就好理解了。

    int main()
    {
    	u16 t=0;
    	u16 len=0;
    	
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  //中断优先级分组 分2组
    	USART1_Init(115200);
    	
    	while(1)
    	{
    		if(USART1_RX_STA&0x8000)
    		{					   
    			len=USART1_RX_STA&0x3fff;//得到此次接收到的数据长度
    			for(t=0;t<len;t++)
    			{
    				USART_SendData(USART1, USART1_RX_BUF[t]);         //向串口1发送数据
    				while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
    			}
    			USART1_RX_STA=0;
    		}
    		
    }
    

    1.主函数while里面,首先判断USART1_RX_STA的最高位,看数据是否接收完毕,再进行操作。
    2.len是记下的数据长度,用于for循环中数据发送的次数(因为每次只能发送一个字节)。
    3.for循环中的while是用的串口发送完成的标志位来判断的是否发送完毕。
    4.最后一定要把USART1_RX_STA置0,方便下次的数据接收,这很重要!!!

    补充,关于\r和\n

    • 回车 \r 本义是光标重新回到本行开头,r的英文return,控制字符可以写成CR,即Carriage Return。ASCII码13(0x0d)。
    • 换行 \n 本义是光标往下一行(不一定到下一行行首),n的英文newline,控制字符可以写成LF,即Line Feed。ASCII码10(0x0a)。

    Windows系统中,我们键盘上的enter键,按下就是\r\n。所以也是为什么要在串口中定义这个协议。当输入一串字符之后按下回车键,点击发送,可以在右边的框中看到最后两个字符的十六进制码是0x0d和0x0a。
    在这里插入图片描述

    我问了老师,也可以定义\n\r的协议,但是在Windows中应该不行,键盘上每个字符都有个ascll码,\就有一个ascll码占一个字节,当你输入\n\r时,实际上不是两个字节,是4个字节。
    在这里插入图片描述
    当然,输入\r\n也不行,只要摁enter键。

    最后,总结一下吧,这里面用得最好的就是定义了一个“状态寄存器USART1_RX_STA”,我也是第一次见到,原来变量还可以这么用,在其他的开发板,或者实现其他的功能中都可以用这种方式来优化程序。

    展开全文
  • 自己实现STM32串口中断接收服务函数

    千次阅读 2020-04-12 15:12:20
    1. 初始化函数不变 void MX_USART6_UART_Init(void) { huart6.Instance = USART6; huart6.Init.BaudRate = 115200; huart6.Init.WordLength = UART_WORDLENGTH_8B; huart6.Init.StopBits = UART_STOPBITS_1; ...

    1. 初始化函数不变

    void MX_USART6_UART_Init(void)
    {
    
      huart6.Instance = USART6;
      huart6.Init.BaudRate = 115200;
      huart6.Init.WordLength = UART_WORDLENGTH_8B;
      huart6.Init.StopBits = UART_STOPBITS_1;
      huart6.Init.Parity = UART_PARITY_NONE;
      huart6.Init.Mode = UART_MODE_TX_RX;
      huart6.Init.HwFlowCtl = UART_HWCONTROL_NONE;
      huart6.Init.OverSampling = UART_OVERSAMPLING_16;
      if (HAL_UART_Init(&huart6) != HAL_OK)
      {
        _Error_Handler(__FILE__, __LINE__);
      }
    
    }
    

    2. MspInit函数中设置中断优先级,开启中断

    void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
    {
    
      GPIO_InitTypeDef GPIO_InitStruct;
      if(uartHandle->Instance==USART6)
      {
      /* USER CODE BEGIN USART6_MspInit 0 */
    
      /* USER CODE END USART6_MspInit 0 */
        /* USART6 clock enable */
        __HAL_RCC_USART6_CLK_ENABLE();
      
        /**USART6 GPIO Configuration    
        PC6     ------> USART6_TX
        PG9     ------> USART6_RX 
        */
        GPIO_InitStruct.Pin = GPIO_PIN_6;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF8_USART6;
        HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
    
        GPIO_InitStruct.Pin = GPIO_PIN_9;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF8_USART6;
        HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
    
      /* USER CODE BEGIN USART6_MspInit 1 */
        /* USART6 interrupt Init */
        HAL_NVIC_SetPriority(USART6_IRQn, 6, 0);
        HAL_NVIC_EnableIRQ(USART6_IRQn);
        /* Enable the UART Data Register not empty Interrupts */
        SET_BIT(uartHandle->Instance->CR1, USART_CR1_RXNEIE);
      /* USER CODE END USART6_MspInit 1 */
      }
    }
    

    3. MspDeInit中关闭中断

    void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
    {
    
      if(uartHandle->Instance==USART6)
      {
      /* USER CODE BEGIN USART6_MspDeInit 0 */
    
      /* USER CODE END USART6_MspDeInit 0 */
        /* Peripheral clock disable */
        __HAL_RCC_USART6_CLK_DISABLE();
      
        /**USART6 GPIO Configuration    
        PC6     ------> USART6_TX
        PG9     ------> USART6_RX 
        */
        HAL_GPIO_DeInit(GPIOC, GPIO_PIN_6);
    
        HAL_GPIO_DeInit(GPIOG, GPIO_PIN_9);
    
      /* USER CODE BEGIN USART6_MspDeInit 1 */
        /* USART6 interrupt Deinit */
        HAL_NVIC_DisableIRQ(USART6_IRQn);
        /* Disable the UART RXNE interrupt*/
        CLEAR_BIT(uartHandle->Instance->CR1, USART_CR1_RXNEIE);
      /* USER CODE END USART6_MspDeInit 1 */
      }
    } 
    

    4. 重写串口中断服务函数

    void USART6_IRQHandler(void)
    {
      uint32_t isrflags   = READ_REG(huart6.Instance->SR);
      uint32_t cr1its     = READ_REG(huart6.Instance->CR1);
      uint32_t errorflags = 0x00U;
      uint8_t dump;
      
      errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));   //检查所有错误,有错误就丢弃
      if(errorflags == RESET)
      {
        /* UART in mode Receiver -------------------------------------------------*/
        if(((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
        {
          Rx_Buf[0] = (uint8_t)(huart6.Instance->DR & (uint8_t)0x00FF);
        }
      }
      else
      {
        dump = (uint8_t)(huart6.Instance->DR & (uint8_t)0x00FF);    //发生错误,数据丢弃
      }
      
    }
    

    5. 测试串口各种错误

    溢出错误

    (RDR内容未及时读出,RDR内容将不会丢失。读USART_DR寄存器仍能得到先前的数据。USART_DR中数据有效。

    噪声错误(开始信号、数据3次采样值不同)、帧错误(没接收到STOP信号),

    无效数据从移位寄存器传送到USART_DR寄存器。USART_DR中数据无效。

    极性错误

    该错误一定要Parity = UART_PARITY_EVEN或者Parity = UART_PARITY_ODD。这样才能使能该错误。

    读完SR寄存器,哪些错误标志位会都清零。

    在这里插入图片描述

    5.1 测试极性错误(PE)

    以115200发送为例
    在这里插入图片描述
    先设置huart6.Init.Parity = UART_PARITY_EVEN;
    再按下图设置发送“0x31”

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

    5.2 测试帧错误(FE)

    按下图设置
    在这里插入图片描述
    发送“0x31”
    在这里插入图片描述

    5.3 测试溢出错误(ORE)

    连续发送“0x31 0x32”
    在这里插入图片描述

    5.4 噪声错误

    暂时不测试。

    展开全文
  • stm32串口中断

    在学习51单片机的时候,配置串口中断服务函数,只需要查看串口中断的中断号,然后在编写中断服务函数的时候,在函数名后面加上中断号。而在stm32中,中断的数量较多,对于中断的管理也会稍微复杂一点,而且中断服务函数名字不能自己随便乱取,已经有定义过,要通过查询找到你所使用的中断服务函数所需要用到的名字。

    CM3内核可以支持256个中断,其中包含有16个内核中断和240个外部中断。但是stm32只用到了其中的84个中断(16个内核中断和68个可屏蔽中断)。

    管理这么多的中断,stm32使用了几个寄存器来使他们有序的执行:

    ISER[8]:(Interrupt Set-Enable Registers),中断使能寄存器组,有ISER[0]~ISER[7]8个32位寄存器组成,每一位控制一个中断,总共可控制256个中断,而使用stm32,只用到了ISER[0~2],ISER[0]的 bit0~31 分别对应中断 0~31;ISER[1]bit0~32 对应中断 32~63ISER[2]bit0~3 对应中断 64~67。

    ICER[8]:(Interrupt Clear-Enable Registers),中断除能寄存器组。与上一个寄存器相反,不做赘述。

    ISPR[8]:(Interrupt Set-Pending Registers),中断挂起控制寄存器组。这个寄存器的作用是当有一个更高优先级的中断出现时,将低优先级正在执行的中断先挂起,让给高优先级的先。

    ICPR[8]:(Interrupt Clear-Pending Registers),中断解挂控制寄存器组。当一个中断因为高优先级的中断而被挂起的时候,那么当高优先级执行完,这个中断应该被解挂才能继续执行。
     

     IABR[8]:(Interrupt Active Bit Registers),中断激活标志位寄存器组。这是一个只读的寄存器,通过这个寄存器我们可以读出哪个中断在执行(对应的位为1则表示该中断正在执行)

    IP[240] :( Interrupt Priority Registers),中断优先级控制的寄存器组。这个组由240个8bit的寄存器组成,stm32只用到了IP[67]~IP[0], 分别对应中断 67~0。这个组主要是用来设置抢占优先级和响应优先级(这两个优先级是用来判断中断的优先级高低的,假如抢占优先级和响应优先级都相等,则哪个中断先发生,则哪个优先级高;如果不相等,就先判断抢占优先级,哪个抢占优先级高则哪个先,如果,连抢占优先级都相等,就判断响应优先级)。虽然寄存器有8个bit,但只用到4个bit

    由上表,由寄存器AIRCR来设定所用到的4位bit中到底分配几个bit来表示抢占优先级,像上面那样,AIRCR为0时,4位bit全部用来表示响应优先级。 

    从上面的知识可以看出,在串口中断中,像中断的使能由串口的状态来决定,比如像接收完毕时产生中断,而挂起和解挂则由系统根据优先级来设置,那么我们需要做的就是去配置中断的中断分组(就是上面表格说到的内容),以及优先级,然后编写产生中断后要做的事(即中断服务函数)

    //设置 NVIC 分组
    //NVIC_Group:NVIC 分组 0~4 总共 5 组 
    void MY_NVIC_PriorityGroupConfig(u8 NVIC_Group)
    { 
        u32 temp,temp1; 
        temp1=(~NVIC_Group)&0x07;//取后三位
        temp1<<=8;
        temp=SCB->AIRCR; //读取先前的设置
        temp&=0X0000F8FF; //清空先前分组
        temp|=0X05FA0000; //写入钥匙
        temp|=temp1;
        SCB->AIRCR=temp; //设置分组 
    }

    上面一段代码时配置分组的,在配置AIRCR时,需要先向AIRCR输入秘钥,为了保持AIRCR原先的值,先将AIRCR原先的值保留下来,然后向AIRCR输入秘钥,之后再把保留下来的值赋值回去。

    //设置 NVIC 
    //NVIC_PreemptionPriority:抢占优先级
    //NVIC_SubPriority :响应优先级
    //NVIC_Channel :中断编号
    //NVIC_Group :中断分组 0~4
    //注意优先级不能超过设定的组的范围!否则会有意想不到的错误
    //组划分:
    //组 0:0 位抢占优先级,4 位响应优先级
    //组 1:1 位抢占优先级,3 位响应优先级
    //组 2:2 位抢占优先级,2 位响应优先级
    //组 3:3 位抢占优先级,1 位响应优先级
    //组 4:4 位抢占优先级,0 位响应优先级
    //NVIC_SubPriority 和 NVIC_PreemptionPriority 的原则是,数值越小,越优先
    void MY_NVIC_Init(u8 NVIC_PreemptionPriority,u8 NVIC_SubPriority,u8 NVIC_Channel,
    u8 NVIC_Group)
    { 
        u32 temp;
        MY_NVIC_PriorityGroupConfig(NVIC_Group);//设置分组
        temp=NVIC_PreemptionPriority<<(4-NVIC_Group); 
        temp|=NVIC_SubPriority&(0x0f>>NVIC_Group);
        temp&=0xf; //取低四位 
        NVIC->ISER[NVIC_Channel/32]|=(1<<NVIC_Channel%32);
        //使能中断位(要清除的话,相反操作就 OK) 
        NVIC->IP[NVIC_Channel]|=temp<<4; //设置响应优先级和抢断优先级
    }

    上面一段代码则是用来设置优先级(抢占优先级和响应优先级)。上面的分组分好后,我们便知道IP寄存器中有4位bit用几位来表示抢占优先级,之后就该开始设置优先级的值了,比如我们分为组 1:1 位抢占优先级,3 位响应优先级,我们赋值1010,则表示抢占优先级为1,响应优先级为2.

    到这里,中断就配置完了,接下来就要自己写中断服务函数了。

    展开全文
  • 该程序编写了STM32F103三个串口初始化程序,可快速调用,同时支持接收和发送单个字符和多个字符,并存储数据,方便接收数据后的通信协议校验,支持自定义接收数据最大长度,重写printf函数
  • 今天在看stm32的中断,一时间不理解stm32主函数是如何进入中断函数的,按C编程的理解,会有个特定的入口之类的,但是看demo过程中没有发现入口。 以串口中断服务函数void USART1_IRQHandler(void) 为例,首先用到...
  • STM32Cube MX串口中断回调函数的研究.pdf
  • 关于如何配置通过中断的方式配置串口的收发 1.使能串口时钟、使能GPIO时钟 2.引脚复用映射 3.GPIO端口模式设置 4.串口参数初始化设置 5.开启中断初始化NVIC 6.使能串口 7.编写中断处理函数 8.编写收发数据...
  • STM32 串口中断总结

    万次阅读 多人点赞 2017-12-25 17:03:17
    本文以USART1为例,叙述串口中断的编程过程。 1、先来讲述一下在应用串口中断时涉及到的一些库文件。 首先对于STM32外设库文件的应用编程,misc.c和stm32f10x_rcc.c是肯定要添加到。 接下来就是我们要用到的相关...
  • STM32实现中断超时接收不定长度的数据,写入flash读出并返回
  • STM32串口中断接收

    千次阅读 2022-04-26 09:55:10
    串口中断的流程为: 1.在main.c文件中对串口进行初始化操作 MX_USART1_UART_Init(); MX_USART2_UART_Init(); 2.对中断回调函数进行改写 void HAL_UART_RxCpltCallback( UART_HandleTypeDef *UartHandle ) 记住...
  • stm32串口中断的接收

    千次阅读 2022-03-26 10:41:39
    利用之前的串口函数加上NVIC的中断函数结构体 定义结构体 定义 配置抢占优先级的组别 配置NVIC串口中断的结构体:中断的通道,配置抢占优先级和子优先级 使能CMD 结构体初始化 还有需要配置中断串口的配置: ...
  • 最近遇到需要MCU输出数字的问题,而STM32串口输出的是字符型,最先想到的方法是将整型数据转换为字符型输出,C库函数中提供了相关的函数
  • STM32串口中断使用

    2020-08-11 08:22:12
    STM32串口中断使用:配置串口时钟在void Rcc_Configuration(void)函数中实现,配置串口管脚在void UsartGPIO_Configuration(void)中实现;初始化参数设置串口中断配置。
  • STM32F103C8T6T6单片机上,利用串口空闲中断和DMA功能实现Modbus通信时数据检测功能。不再需要利用定时器中断去判断一帧数据是否接收完成。
  • STM32中断数据回调函数接收处理

    千次阅读 2021-05-23 08:50:42
    1.定义一个空的指针函数 指针函数的参数是uint8_t 类型chtypedef void (* usart_recv_callback)(uint8_t ch);...3.串口配置时,一个形参为串口中断接收回调void Usart_Config(USART_TypeDef* USARTx, uint32_t bau...
  • 现象:MCU为STM32L431,使用uCOS-III作为实时操作系统,使用串口接收升级数据包后,不能进行任务调度,发现程序没有跑飞,而是一直进入串口中断。串口的ISR寄存器如下: 串口中断服务函数的判断条件是: ```c if...
  • stm32中断服务函数文件位置

    千次阅读 2021-05-06 21:42:21
    stm32中断服务函数在md.s启动文件中
  • 问题表现 在MCU系统负载较重、串口收发数据频率很高、多个中断存在(如同时有定时器更新中断、外部中断、DMA中断、串口接收中断)的情况下,容易出现串口溢出错误(ORE)。该错误的主要显现形式是:...在STM32中断函数
  • STM32串口中断详解

    千次阅读 2022-01-28 15:07:15
    3. 可以选择的串口中断类型 此处定义 其他文件中的声明 extern u8 USART_RX_BUF[USART_REC_LEN] 最大接收字节数 extern u16 USART_RX_STA 接收状态标记 extern u16 USART_RX_STA bit15 bit...
  • STM32串口中断不能进入

    千次阅读 2022-04-16 16:20:12
    CPP文件串口中断不能进入
  • STM32串口通信相关寄存器状态寄存器 (USART_SR)数据寄存器 (USART_DR)波特率寄存器 (USART_BRR)控制寄存器 x (USART_CRx)控制寄存器 1 (USART_CR1)控制寄存器 2 (USART_CR2)控制寄存器 3 (USART_CR3)串口配置串口...
  • stm32f103RC;串口1和串口2;中断传输;修改fputc函数。基本可以做到串口1发送数据(数据量不大的前提下)串口2及时接收并通过串口2调试助手显示。如果串口2接收数据后会及时将数据通过串口2调试助手显示。
  • https://www.cnblogs.com/UnfriendlyARM/p/10321838.html
  • STM32f407串口中断函数

    2018-04-07 19:39:14
    基于STM32f407芯片的串口中断控制函数。能够实现按下按键后,通过串口向上位机发送字符。
  • 主控stm32f030c8t6芯片,采用stm32CubeMX软件生成代码,由于没有串口空闲中断接收,经过编程已加上了这个功能,供嵌入式同行借鉴使用。
  • stm32之串口使用和串口中断

    千次阅读 2021-03-21 00:55:50
    串口通讯(Serial Communication)是一种设备间非常常用的串行通讯方式,因为它简单便捷,因此大部分电子设备都支持该通讯方式,其通讯协议可分层为协议层和物理层。物理层规定通信协议中具有机械、电子功能的特性,...
  • STM32串口中断接收HAL库超详解析

    千次阅读 2021-11-19 16:52:28
    HAL库实现将接收逻辑全写在中断服务函数里面而不重定义回调函数,并且不会不进中断
  • STM32H750的IDLE串口空闲中断、DMA传输UART接收数据、STM32CUBEMX生成MDK5编译
  • STM32 串口接收流程-串口接收中断

    千次阅读 2021-09-21 16:09:49
    串口接收 串口接收流程 编程USARTx_CR1的M位来定义字长。...如果要使能接收中断(接收到数据后产生中断),使能USARTx_CR1的RXNEIE位为1。 当串口接收到数据时 USARTx_SR(ISR)的RXNE位置1。表明移

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 17,493
精华内容 6,997
关键字:

stm32串口中断服务函数