精华内容
下载资源
问答
  • STM32—中断详解(配合按键中断代码,代码亲测)

    万次阅读 多人点赞 2019-07-25 17:35:23
    (注:本文章所用代码中断按键代码,实现了按键进入中断从而控制LED亮灭) 配置NVIC_Config()函数 NVIC 是嵌套向量中断控制器,控制着整个芯片中断相关的功能,它跟内核紧密耦合,是内核里面的一个外设。 NVIC_...

    在STM32中执行中断主要分三部分:
    1.配置NVIC_Config()函数
    2.配置EXTI_Config()函数
    3.编写中断服务函数

    (注:本文章所用代码为中断按键代码,实现了按键进入中断从而控制LED亮灭)

    配置NVIC_Config()函数

    NVIC 是嵌套向量中断控制器,控制着整个芯片中断相关的功能,它跟内核紧密耦合,是内核里面的一个外设。
    NVIC_Config()函数代码如下

    static void NVIC_Config(void) /* 主要是配置中断源的优先级与打开使能中断通道 */
    {
    	NVIC_InitTypeDef NVIC_InitStruct ;
    	
    	/* 配置中断优先级分组(设置抢占优先级和子优先级的分配),在函数在misc.c */
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1) ;
    	
    	/* 配置初始化结构体 在misc.h中 */
    	/* 配置中断源 在stm32f10x.h中 */
    	NVIC_InitStruct.NVIC_IRQChannel = KEY1_EXTI_IRQN ;
    	/* 配置抢占优先级 */
    	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1 ;
    	/* 配置子优先级 */
    	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0 ;
    	/* 使能中断通道 */
    	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE ;
    	/* 调用初始化函数 */
    	NVIC_Init(&NVIC_InitStruct) ;
    	
    	/* 对key2执行相同操作 */
    	NVIC_InitStruct.NVIC_IRQChannel = KEY2_EXTI_IRQN ;
    	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1 ;
    	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1 ;
    	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE ;
    	NVIC_Init(&NVIC_InitStruct) ;
    	
    }
    

    配置NVIC_Config()的目的是选择中断源的优先级以及打开中断通道,主要功能通过配置NVIC初始化结构体NVIC_InitStruct来完成。通俗的讲,STM32中有很多中断,而当有多个中断同时发生时就涉及到中断执行的先后问题了,所以引入了中断优先级的概念,中断优先级越高中断就越先执行。在这里我们只讨论外部中断的优先级,在 NVIC 有一个专门的寄存器:中断优先级寄存器 NVIC_IPRx,用来配置外部中断的优先级。优先级高低的比较包括抢占优先级和子优先级,先比较抢占优先级,如果抢占优先级相同就比较子优先级,从而得出中断之间的优先级高低。NVIC的主要任务就是给对应的中断源分配中断优先级。 中断优先级分配的原理繁杂,但固件库编程的好处就是化繁为简,我们只需要按照NVIC_InitStruct()中的内容进行配置就行。

    接下来简单讲解一下NVIC_Config()函数的内容:
    1.首先设置中断优先级分组
    中断优先级分组其实是确立一个大纲,中断优先级寄存器 NVIC_IPRx中有4个位用来确定优先级,中断优先级的分组就是把这4个位分配在抢占优先级和子优先级中。比如设定一个位配置抢占优先级,其余三个位配置子优先级。通过函数NVIC_PriorityGroupConfig() ; 实现分组,详细代码如下:

    1 /**
    2 * 配置中断优先级分组:抢占优先级和子优先级
    3 * 形参如下:
    4 * @arg NVIC_PriorityGroup_0: 0bit for 抢占优先级
    5 *                   		   4 bits for 子优先级
    6 * @arg NVIC_PriorityGroup_1: 1 bit for 抢占优先级
    7 *                            3 bits for 子优先级
    8 * @arg NVIC_PriorityGroup_2: 2 bit for 
    9 *                            2 bits for 子优先级
    10 * @arg NVIC_PriorityGroup_3: 3 bit for 抢占优先级
    11 *                           1 bits for 子优先级
    12 * @arg NVIC_PriorityGroup_4: 4 bit for 抢占优先级
    13 *                           0 bits for 子优先级
    14 * @注意 如果优先级分组为 0,则抢占优先级就不存在,优先级就全部由子优先级控制
    15 */
    16 void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
    17 {
    18 // 设置优先级分组
    19 SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;
    20 }
    

    2.优先级分组完毕后,是配置NVIC初始化结构体

    typedef struct {
    2 uint8_t NVIC_IRQChannel; // 中断源
    3 uint8_t NVIC_IRQChannelPreemptionPriority; // 抢占优先级
    4 uint8_t NVIC_IRQChannelSubPriority; // 子优先级
    5 FunctionalState NVIC_IRQChannelCmd; // 中断使能或者失能
    6 } NVIC_InitTypeDef;
    

    初始化结构体的作用是,收集中断源的信息(包括配置的是哪一个中断源、中断源的抢占优先级是多少、中断源的子优先级是多少、中断源的使能是否开启)。
    NVIC_IROChannel:用来设置中断源,不同的中断中断源不一样,且不可写错,即使写错了程序也不会报错,只会导致不响应中断。 stm32f10x.h 头文件里面的 IRQn_Type 结构体定义,这个结构体包含了所有的中断源。
    NVIC_IRQChannelPreemptionPriority和NVIC_IRQChannelSubPriority 分别设置抢占优先级和子优先级,具体的值要根据中断优先级分组来确定。
    NVIC_IRQChannelCmd:设置中断使能(ENABLE)或者失能(DISABLE),相当于一个电源总开关。
    3.最后借助NVIC初始化函数将NVIC初始化结构体中的信息写入相应的寄存器中 (体现了固件库编程的优点,不需要我们深入到寄存器层次去,只需要掌握相应函数的配置即可)

    配置EXTI_Config()函数

    EXTI(External interrupt/event controller):外部中断/事件控制器,管理了控制器的 20个中断/事件线。每个中断/事件线都对应有一个边沿检测器,可以实现输入信号的上升沿检测和下降沿的检测。 EXTI 可以实现对每个中断/事件线进行单独配置,可以单独配置为中断或者事件,以及触发事件的属性。
    按我的理解,EXTI是一个有着多达20个接口的控制器,它可以为每一个接入接口的信号源配置中断(或事件)线、设置信号的检测方式、设置触发事件的性质,也就是说,传入EXTI的仅仅是一个信号,EXTI的功能就是根据信号传入的“线”对信号做出相应的处理,然后将处理后的信号转向NVIC。 就像一个分拣机器,传入的东西经过筛选处理被送往不同的地方,只是EXTI分拣的是信号罢了。 如果说NVIC是配置中断源,那么EXTI就是向NVIC传送中断信号。

    EXTI功能框图:
    在这里插入图片描述EXTI 可分为两大部分功能,一个是产生中断,另一个是产生事件,线路1-2-4-5是产生中断的流程,20/代表着有20条相同的线路。

    接下来讲解一下EXTI_Config()函数代码:

    void EXTI_Config() /* 主要是连接EXTI与GPIO */
    {
    	GPIO_InitTypeDef GPIO_InitStruct ;
    	EXTI_InitTypeDef EXTI_InitStruct ;
    	
    	NVIC_Config();
    
    	/* 初始化要与EXTI连接的GPIO */
    	/* 开启GPIOA与GPIOC的时钟 */
    	RCC_APB2PeriphClockCmd(KEY1_EXTI_GPIO_CLK | KEY2_EXTI_GPIO_CLK, ENABLE) ;
    	
    	GPIO_InitStruct.GPIO_Pin = KEY1_EXTI_GPIO_PIN ;
    	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING ;
    	GPIO_Init(KEY1_EXTI_GPIO_PORT , &GPIO_InitStruct) ;
    	
    	GPIO_InitStruct.GPIO_Pin = KEY2_EXTI_GPIO_PIN ;
    	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING ;
    	GPIO_Init(KEY2_EXTI_GPIO_PORT , &GPIO_InitStruct) ;
    	
    	/* 初始化EXTI外设 */
    	/* EXTI的时钟要设置AFIO寄存器 */
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE) ;
    	/* 选择作为EXTI线的GPIO引脚 */
    	GPIO_EXTILineConfig( KEY1_GPIO_PORTSOURCE , KEY1_GPIO_PINSOURCE) ;
    	/* 配置中断or事件线 */
    	EXTI_InitStruct.EXTI_Line = KEY1_EXTI_LINE ;
    	/* 使能EXTI线 */
    	EXTI_InitStruct.EXTI_LineCmd = ENABLE ;
    	/* 配置模式:中断or事件 */
    	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt ;
    	/* 配置边沿触发 上升or下降 */
    	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising ;
    	EXTI_Init(&EXTI_InitStruct) ;
    	
    	GPIO_EXTILineConfig( KEY2_GPIO_PORTSOURCE , KEY2_GPIO_PINSOURCE) ;
    	EXTI_InitStruct.EXTI_Line = KEY2_EXTI_LINE ;
    	EXTI_InitStruct.EXTI_LineCmd = ENABLE ;
    	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt ;
    	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling ;
    	EXTI_Init(&EXTI_InitStruct);
    }
    
    

    代码可大体分为三部分:
    配置GPIO相应引脚、配置EXTI并连接GPIO引脚、传入NVIC_Config()
    1.配置GPIO相应引脚
    该代码是通过按键产生一个电平信号,然后经EXTI处理传入NVIC产生中断的,所以要配置连接按键的GPIO引脚,主要是设置相应的引脚模式为浮空输入 。老规矩,先开启相应GPIO的时钟,然后配置引脚初始化结构体,再利用初始化函数将初始化结构体写入寄存器中。
    2.配置EXTI并连接GPIO引脚
    要操作外设,首先要打开相关的时钟,EXTI挂载在APB2总线上,并且开启时钟时要操作AFIO寄存器 ,准备工作就绪后连接GPIO相应的引脚到EXTI中,前面说了EXTI有20个接口,所以特定的引脚有特定的接口,所以要根据GPIO_EXTILineConfig();函数选择用作EXTI线的GPIO引脚,函数说明如下

    /**
      * @brief  Selects the GPIO pin used as EXTI Line.
      * @param  GPIO_PortSource: selects the GPIO port to be used as source for EXTI lines.
      *   This parameter can be GPIO_PortSourceGPIOx where x can be (A..G).
      * @param  GPIO_PinSource: specifies the EXTI line to be configured.
      *   This parameter can be GPIO_PinSourcex where x can be (0..15).
      * @retval None
      */
    void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)
    {
      uint32_t tmp = 0x00;
      /* Check the parameters */
      assert_param(IS_GPIO_EXTI_PORT_SOURCE(GPIO_PortSource));
      assert_param(IS_GPIO_PIN_SOURCE(GPIO_PinSource));
      
      tmp = ((uint32_t)0x0F) << (0x04 * (GPIO_PinSource & (uint8_t)0x03));
      AFIO->EXTICR[GPIO_PinSource >> 0x02] &= ~tmp;
      AFIO->EXTICR[GPIO_PinSource >> 0x02] |= (((uint32_t)GPIO_PortSource) << (0x04 * (GPIO_PinSource & (uint8_t)0x03)));
    }
    

    其实对应的EXTI线就对应GPIO引脚号,这样看起来还比较直观。
    连接好GPIO引脚与EXTI后就该配置EXTI的初始化结构体了,结构体如下:

    typedef struct 
    {
    	 uint32_t EXTI_Line; // 中断/事件线
    	 EXTIMode_TypeDef EXTI_Mode; // EXTI 模式
    	 EXTITrigger_TypeDef EXTI_Trigger; // 触发类型
    	 FunctionalState EXTI_LineCmd; // EXTI 使能
     } EXTI_InitTypeDef;
    

    配置此结构体主要是:选择相应的EXTI线 、选择触发模式、选择产生的结果(中断还是事件)、是否使能EXTI线。
    EXTI_Line:中断线选择,可选 EXTI_0 至 EXTI_19(一共20个)。既然刚才配置好了与GPIO引脚对应的EXTI线,所以初始化结构体中的EXTI线就是与GPIO连接的那个线。
    EXTI_Mode: EXTI 模式选择,可选为产生中断或者产生事件。就是决定信号的发展方向,是产生中断呢?还是产生事件呢?此处是中断。
    EXTI_Trigger: EXTI 边沿触发模式,可选上升沿触发、下降 沿 触 发 或 者 上 升 沿 和 下 降 沿 都 触 发。触发信号。
    EXTI_LineCmd:控制是否使能 EXTI 线,可选使能 EXTI 线或禁用。
    初始化结构体配置完毕后交由初始化函数写入相应的寄存器中。
    3.传入NVIC_Config()
    之后就自动传入NVIC中了。。。

    编写中断服务函数

    到这里就万事俱备只欠东风了,中断的触发与处理及优先级定义都已经安排上了,最后一步就是编写中断函数的内容了,只要进入中断就会执行中断函数中的代码,所以这是收尾工作。STM32的中断服务函数不同于51单片机中的中断服务函数,STM32的所有中断函数都被偷偷安排了,每个中断都有其固定的名字,只有找到这个名字,在这个固定的函数名下编写中断服务函数才是有效的,所有中断函数的编写都要在stm32f10x_it.c 中,如示:
    在这里插入图片描述
    从所给的信息可得知外设的中断服务函数的名字都存放在startup_stm32f10x_xx.s 中,而且是由汇编语言编写,如示:在这里插入图片描述
    可知EXTI线0到EXTI线4线都是单独的中断函数名、EXTI线5到EXTI线9共用一个中断函数名、EXTI线10线到EXTI线15线共用一个中断函数名。
    我们要做的就是以相应的EXTI线的中断函数名字在stm32f10x_it.c中编写中断函数 如下:

    void EXTI0_IRQHandler(void)
    {
    	if(  EXTI_GetITStatus(KEY1_EXTI_LINE)!=RESET)
    	{
    		LED1_TOGGLE;   //LED1的亮灭状态反转
    	}
    		
    	EXTI_ClearITPendingBit(KEY1_EXTI_LINE);
    		
    }
    
    
    void EXTI15_10_IRQHandler(void)
    {
    	if(  EXTI_GetITStatus(KEY2_EXTI_LINE)!=RESET)
    	{
    		LED2_TOGGLE;   //LED2的亮灭状态反转
    	}
    		
    	EXTI_ClearITPendingBit(KEY2_EXTI_LINE);
    		
    }
    
    

    每次进入中断函数后,靠ITStatus EXTI_GetITStatus(uint32_t EXTI_Line)读取中断是否执行 ,执行完之后要利用void EXTI_ClearITPendingBit(uint32_t EXTI_Line)清除清除中断标志位,以免不断进入中断

    大功告成

    到此完整的中断系统就已经完成,主函数只需调用即可!!!
    (附上主函数及俩个头文件)
    希望可以一起交流学习
    qq:2723808286

    #include "stm32f10x.h"
    #include "bsp_led.h"
    #include "bsp_key.h"
    
    int main(void)
    { 
    	LED_GPIO_Config();
    	EXTI_Config();
    	
    	while(1) 
    	{
    	}
    }
    
    
    
    #ifndef __BSP_KEY_H
    #define __BSP_KEY_H
    
    #include "stm32f10x.h"
    
    #define KEY1_EXTI_GPIO_CLK      RCC_APB2Periph_GPIOA
    #define KEY1_EXTI_GPIO_PORT     GPIOA
    #define KEY1_EXTI_GPIO_PIN      GPIO_Pin_0
    #define KEY1_EXTI_IRQN          EXTI0_IRQn      /* 对应着引脚号 */
    #define KEY1_EXTI_LINE          EXTI_Line0      /* 中断、事件线对应引脚号 */
    #define KEY1_GPIO_PORTSOURCE    GPIO_PortSourceGPIOA
    #define KEY1_GPIO_PINSOURCE     GPIO_PinSource0
    #define  KEY1_EXTI_IRQHANDLER       EXTI0_IRQHandler
    
    #define KEY2_EXTI_GPIO_CLK      RCC_APB2Periph_GPIOC
    #define KEY2_EXTI_GPIO_PORT     GPIOC
    #define KEY2_EXTI_GPIO_PIN      GPIO_Pin_13
    #define KEY2_EXTI_IRQN          EXTI15_10_IRQn
    #define KEY2_EXTI_LINE          EXTI_Line13
    #define KEY2_GPIO_PORTSOURCE    GPIO_PortSourceGPIOC
    #define KEY2_GPIO_PINSOURCE     GPIO_PinSource13
    #define  KEY2_EXTI_IRQHANDLER       EXTI15_10_IRQHandler
    
    
    void EXTI_Config(void);
    	
    #endif
    
    
    #ifndef __BSP_LED_H
    #define __BSP_LED_H
    
    #include "stm32f10x.h"
    
    
    
    #define LED1_GPIO_CLK   RCC_APB2Periph_GPIOC   /*时钟*/
    #define LED1_GPIO_PORT  GPIOC                  /*端口*/
    #define LED1_GPIO_PIN   GPIO_Pin_2             /*引脚*/
    
    
    #define LED2_GPIO_PIN   GPIO_Pin_3
    #define LED2_GPIO_CLK   RCC_APB2Periph_GPIOC
    #define LED2_GPIO_PORT  GPIOC
    
    #define digitalTOGGLE(p,i)     {p->ODR ^=i;}
    #define LED1_TOGGLE            digitalTOGGLE(LED1_GPIO_PORT,LED1_GPIO_PIN)
    #define LED2_TOGGLE            digitalTOGGLE(LED2_GPIO_PORT,LED2_GPIO_PIN)  /* LED状态反转 */
     void LED_GPIO_Config(void);                   
    
    #endif
    
    
    
    展开全文
  • 单片机中断代码练习

    千次阅读 2011-10-29 18:57:26
    外部中断1的练习 #include #include #define uchar unsigned char #define uint unsigned int sbit P3_3 = P3^3 ; sbit P3_4 = P3^4 ; sbit P1_7 = P1^7 ; //位定义 void init_interrupt(); //初始化函数,...
     外部中断1的练习
    

    #include<reg52.h>
    #include<intrins.h>
    #define uchar unsigned char
    #define uint unsigned int
    sbit P3_3 = P3^3 ;
    sbit P3_4 = P3^4 ;
    sbit P1_7 = P1^7 ;   //位定义

    void init_interrupt(); //初始化函数,进行相应的中断寄存器的设置
    void delay(uint x);    //不是很准的延时函数
    void main(void )
    {
      uchar m = 0xfe;
      uchar n = 0;
      init_interrupt();
       while(P3_4 == 0);                 //总开关控制主程序的流程,这是系统的要求
       while(1)
      {   
         while(P3_4 == 0);
               m = _crol_(m,1);           //7只发光二极管的轮流显示
            if(m == 0x7f)
               m = _crol_(m,1);
               n = m;
               n = n | 0x80;
              P1 = n;    
           delay(33333);
      }
    }

    void init_interrupt()
    {
       EA  = 1;  //cpu开中断
       EX1 = 1; //中断允许寄存器IE中的EA和EX1  允许外部中断1
       IT1 = 0; // 外部中断1的设置为电平触发方式
    }
    void delay(uint x)
    {
     uint y = 3333;
     for(;y > 0;y--)
      for(;x > 0;x--);
    }
    //void exter1() interrupt 1     要细心
    void exter1() interrupt 2    

    /*

    *interrupt 0是外部中断 0   P3_2

    *interrupt 1是定时器      0   P3_4

    *interrupt  2是外部中断1    P3_3

    *interrupt  3是定时器     1    P3_5

    *interrupt  4是串行口            P3.0 RXD

                                                     P3.1 TXD

    *interrupt是关键字

    *exter1是函数名,可以自行定义

    */
    {
     uchar b;
     EA = 0;
     b  = P1;
     while(P3_3 == 0)   //一开始为高,为低的话触发中断
     {
          P1_7 = !P1_7;
       delay(56667);
     }
     P1 = b;
     EA = 1;
    }

     

     

    总结记忆:

    一:
    1、(P3.2)可由IT0(TCON.0)选择其为低电平有效还是下降沿有效。(外部中断0)
           当CPU检测到P3.2引脚上出现有效的中断信号时,中断标志IE0(TCON.1)置1,向CPU申请中断。
    2、(P3.3)可由IT1(TCON.2)选择其为低电平有效还是下降沿有效。    (外部中断1)
           当CPU检测到P3.3引脚上出现有效的中断信号时,中断标志IE1(TCON.3)置1,向CPU申请中断。
    3、TF0(TCON.5),片内定时/计数器T0溢出中断请求标志。               (定时器中断0)
            当定时/计数器T0发生溢出时,置位TF0,并向CPU申请中断。
    4、TF1(TCON.7),片内定时/计数器T1溢出中断请求标志。                (定时器中断1)
           当定时/计数器T1发生溢出时,置位TF1,并向CPU申请中断。
    5、RI(SCON.0)或TI(SCON.1),串行口中断请求标志。                     (串行口)
           当串行口接收完一帧串行数据时置位RI或当串行口发送完一帧串行数据时置位TI,向CPU申请中断。
     
    其实就与TCON寄存器的设置密切相关

    TCON :0x88h  地址

           IT0(TCON.0),外部中断0触发方式控制位。 
           当IT0=0时,为电平触发方式。
           当IT0=1时,为边沿触发方式(下降沿有效)。
           IE0(TCON.1),外部中断0中断请求标志位。
           IT1(TCON.2),外部中断1触发方式控制位。
           IE1(TCON.3),外部中断1中断请求标志位。
           TF0(TCON.5),定时/计数器T0溢出中断请求标志位。
           TF1(TCON.7),定时/计数器T1溢出中断请求标志位。      

    二:

       SCON:0x98  地址

       §RI(SCON.0),串行口接收中断标志位。
           当允许串行口接收数据时,每接收完一个串行帧,由硬件置位RI。注意,RI必须由软件清除。
        §TI(SCON.1),串行口发送中断标志位。
           当CPU将一个发送数据写入串行口发送缓冲器时,就启动了发送过程。每发送完一个串行帧,由硬件置位TI。CPU响应中断时,不能自动清除TI,TI必须由软件清除。       

            

    三:

        IE:0xA8h   地址

       CPU对中断系统所有中断以及某个中断源的开放和屏蔽是由中断允许寄存器IE控制的。
       §EX0(IE.0),外部中断0允许位;
       §ET0(IE.1),定时/计数器T0中断允许位;
       §EX1(IE.2),外部中断0允许位;
       §ET1(IE.3),定时/计数器T1中断允许位;
       §ES(IE.4),串行口中断允许位;
       §EA (IE.7), CPU中断允许(总允许)位。

    四:(不是必须设置的)

       IP:0xB8h  地址

       §PX0(IPH.0),外部中断0优先级设定位;
       §PT0(IPH.1),定时/计数器T0优先级设定位;
       §PX1(IPH.2),外部中断0优先级设定位;
       §PT1(IPH.3),定时/计数器T1优先级设定位;
       §PS  (IPH.4),串行口优先级设定位; 
       §PT2  (IPH.5)    ,定时/计数器T2优先级设定位。
      
    五:(中断嵌套,也不是必须的)
       IPH:0xB7H   地址
       §PX0(IPH.0),外部中断0优先级设定位;
       §PT0(IPH.1),定时/计数器T0优先级设定位;
       §PX1(IPH.2),外部中断0优先级设定位;
       §PT1(IPH.3),定时/计数器T1优先级设定位;
       §PS  (IPH.4),串行口优先级设定位;
       §PT2  (IPH.5)    ,定时/计数器T2优先级设定位。

     

    有个小问题,貌似不知道怎么修改单片机的默认的中断优先级啊??????以后有机会得想想
    展开全文
  • STM32 串口接收中断 代码

    千次阅读 2014-04-30 15:40:31
    1、代码介绍

    1、代码介绍

    今天做项目,要用到串口中断接收,在网上一搜,大量代码,copy过来编译没问题,但是运行起来才发现不能产生中断,于是决定自己搞搞,用了半天的功夫,终于有结果了。

    2、共同讨论

    代码属个人编写,自有不足之处,望大家指出。

    3、单片机型号

    代码基于HY--Stm32_100p单片机编写


    #include "stm32f10x.h"

    /*************************************************
    函数: void RCC_Configuration(void)
    功能: 复位和时钟控制 配置
    参数: 无
    返回: 无
    **************************************************/
    void RCC_Configuration(void)
    {
        ErrorStatus HSEStartUpStatus;                    //定义外部高速晶体启动状态枚举变量
        RCC_DeInit();                                    //复位RCC外部设备寄存器到默认值
        RCC_HSEConfig(RCC_HSE_ON);                       //打开外部高速晶振
        HSEStartUpStatus = RCC_WaitForHSEStartUp();      //等待外部高速时钟准备好
        if(HSEStartUpStatus == SUCCESS)                  //外部高速时钟已经准别好
        {
              FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //开启FLASH预读缓冲功能,加速FLASH的读取。所有程序中必须的用法.位置:RCC初始化子函数里面,时钟起振之后
              FLASH_SetLatency(FLASH_Latency_2);                    //flash操作的延时
                  
              RCC_HCLKConfig(RCC_SYSCLK_Div1);               //配置AHB(HCLK)时钟等于==SYSCLK
              RCC_PCLK2Config(RCC_HCLK_Div1);                //配置APB2(PCLK2)钟==AHB时钟
              RCC_PCLK1Config(RCC_HCLK_Div2);                //配置APB1(PCLK1)钟==AHB1/2时钟
                   
              RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);  //配置PLL时钟 == 外部高速晶体时钟 * 9 = 72MHz
              RCC_PLLCmd(ENABLE);                                   //使能PLL时钟
         
              while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);  //等待PLL时钟就绪
              RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);            //配置系统时钟 = PLL时钟
              while(RCC_GetSYSCLKSource() != 0x08) ;                 //检查PLL时钟是否作为系统时钟
        }
    }


    /*******************************************************************************
    * Function Name   : NVIC_Configuration
    * Description        : Configures NVIC and Vector Table base location.
    * Input                    : None
    * Output                 : None
    * Return                 : None
    *******************************************************************************/
    void NVIC_Configuration(void)
    {
           NVIC_InitTypeDef NVIC_InitStructure;
          
           /* Set the Vector Table base location at 0x08000000 */
           NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
          
           /* Configure the NVIC Preemption Priority Bits */  
           NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
          
           /* Enable the USART2 Interrupt */
           NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;       //通道设置为串口2中断
           NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  //中断响应优先级0
           NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  //打开中断
           NVIC_Init(&NVIC_InitStructure);   //初始化
    }

    /*******************************************************************************
    函数名:USART2_Configuration
    输  入:
    输  出:
    功能说明:
    初始化串口硬件设备,启用中断
    配置步骤:
    (1)打开GPIO和USART2的时钟
    (2)设置USART2两个管脚GPIO模式
    (3)配置USART2数据格式、波特率等参数
    (4)使能USART2接收中断功能
    (5)最后使能USART2功能
    */
    void USART2_GPIO_Configuration(void)
    {
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;


    /* 第1步:打开GPIO和USART部件的时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
            


    /* 第2步:将USART Tx的GPIO配置为推挽复用模式 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);


    /* 第3步:将USART Rx的GPIO配置为浮空输入模式
    由于CPU复位后,GPIO缺省都是浮空输入模式,因此下面这个步骤不是必须的
    但是,我还是建议加上便于阅读,并且防止其它地方修改了这个口线的设置参数
    */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    /*  第3步已经做了,因此这步可以不做
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    */
    GPIO_Init(GPIOA, &GPIO_InitStructure);




    /* 第4步:配置USART2参数
       - BaudRate = 115200 baud
       - Word Length = 8 Bits
       - One Stop Bit
       - No parity
       - Hardware flow control disabled (RTS and CTS signals)
       - Receive and transmit enabled
    */
    USART_InitStructure.USART_BaudRate = 9600;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    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(USART2, &USART_InitStructure);


            /* 若接收数据寄存器满,则产生中断 */
            USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);


    /* 第5步:使能 USART2, 配置完毕 */
    USART_Cmd(USART2, ENABLE);


            /* 如下语句解决第1个字节无法正确发送出去的问题 */
            USART_ClearFlag(USART2, USART_FLAG_TC);     // 清标志
    }

    void LED_GPIO_Configure(void)
    {
            GPIO_InitTypeDef GPIO_InitStructure;
      
            RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC , ENABLE);
            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;       
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    }

    /******************************************************************
                    STM32在串口2接收1字节                                           
                    说明:串口2接收中断                                             
    ******************************************************************/
    void USART2_IRQHandler(void)     //在中断服务程序中,由于主机响应中断时并不知道是哪个中断源发出中断请求,因此必须在中断服务程序中对中断源进行判别,然后分别进行处理。当然,如果只涉及到一个中断请求,是不用做上述判别的。但是无论什么情况,做上述判别是个好习惯
    {
              GPIO_SetBits(GPIOC, GPIO_Pin_6);// D1亮        
     if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)    //若接收数据寄存器满
     {
                USART_ClearITPendingBit(USART1,USART_IT_RXNE);
                USART_SendData(USART2, USART_ReceiveData(USART2));
                while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
             } 
              GPIO_ResetBits(GPIOC, GPIO_Pin_6); //D1灭 


    void main(void)
    {
     RCC_Configuration();
     NVIC_Configuration();
     USART2_GPIO_Configuration();
              LED_GPIO_Configure();
              while(1);
    }

    展开全文
  • -中断代码调式原文链接:http://blog.csdn.net/alajl关于attachInterrupt(),我想说点什么:这个是一个中断函数,由于许多数字传感器的状态只有0, 1,两种状态,所以用这个方法来触发一个事件,是相当好不过了,...

    作者 :alajl

    日期: 2011-4-18

    标题: Arduino第四次实验自动垃圾清除车 -中断代码调式

    原文链接: http://blog.csdn.net/alajl

     

    关于 attachInterrupt(),我想说点什么:

    这个是一个中断函数,由于许多数字传感器的状态只有 0 1,两种状态,所以用这个方法来触发一个事件,是相当好不过了,例如:

    1、寻线传感器,从线内到了线外, 0 1的改变,或者是 1 0的改变,这个改变取决于你线的颜色,一般黑色是 0,白色是 1

    2、红外障碍传感器:有障碍和没障碍的感应,同样是 0 1的改变,或者是 1 0的改变

     

    所以这个函数,可以异步处理这些传感器的值,因此你不用不断的去轮询那些传感器的状态了,而把主程序释放出来去控制别的逻辑。

     

    Arduino的控制板,只提供了 2个数字口的中断,请看红色的标注部分,所以如果你想用中断,那么 D2 D3就不要被占用了。

    它支持 4种模式的触发,如下:

    • LOW :只要是低电平就触发
    • CHANGE 只要电平的值改变了就出发,不管是 0 1,还是 1 0
    • RISING 由低电平到高电平触发
    • FALLING 当高电平到低电平触发

     

     

    该函数文档如下:(摘自 http://arduino.cc/en/Reference/AttachInterrupt

    attachInterrupt(interrupt, function, mode)

    Description

    Specifies a function to call when an external interrupt occurs. Replaces any previous function that was attached to the interrupt. Most Arduino boards have two external interrupts: numbers 0 (on digital pin 2) and 1 (on digital pin 3). The Arduino Mega has an additional four: numbers 2 (pin 21), 3 (pin 20), 4 (pin 19), and 5 (pin 18).

    Parameters

    interrupt : the number of the interrupt (int )

    function : the function to call when the interrupt occurs; this function must take no parameters and return nothing. This function is sometimes referred to as an interrupt service routine.

    mode defines when the interrupt should be triggered. Four contstants are predefined as valid values:

    • LOW to trigger the interrupt whenever the pin is low,
    • CHANGE to trigger the interrupt whenever the pin changes value
    • RISING to trigger when the pin goes from low to high,
    • FALLING for when the pin goes from high to low.

     

    写在最后:

    当我真机测试时,晕倒!由于电机的干扰,我的中断完全乱序,当我停止电机时,中断工作良好, google 一下,有可能是因为,我的电机板和传感板公用的一块电源,导致了这个原因,只是可能啊,所以建议是分开供电,而我手上确没有单独的多余供电模块(也就是 9V 电池和电池盒),所以就只好把代码改回了轮询的方式了,以后有机会在试试这个方式

     

    展开全文
  • stm32 usart空闲中断代码(hal库)

    千次阅读 2020-03-11 11:45:43
  • 简单的定时器0中断代码

    千次阅读 2011-03-28 22:21:00
    EA:是总中断的控制端。ET0:定时器0开启控制端。TR0:定时器0启动控制端。 一下是代码: #include<reg52.h><br />#define uint unsigned int #define uchar unsigned char sbit wela=P2^7;...
  • 临界代码区 与 中断

    千次阅读 2015-02-12 10:58:10
    为确保临界段代码的执行,在进入临界段之前要关中断,而临界段代码执行完以后要立即开中断。如下关于A/D采样的代码中有这么一段: Int main() { _DINT(); WDTCTL=WDTPW+WDTHOLD; InitClock(); InitAD12
  • 中断,(好像)系统自带的,硬件芯片BIOS...触发之后,根据中断向量,调用对应的中断代码进行处理。在内存0-3ffh内存放的是中断向量。一个中断向量4个字节,分别2字节的cs和2字节的ip——指向对应的中断处理代码。  在
  • 中断控制 ( 基于 S3C6410 开发板 ) 1. 关闭中断的两个步骤 (1) 关闭中断步骤 2. CPRS 寄存器中的中断控制位 (1) CPRS 寄存器位 3. (1) CPRS 寄存器位 一. 中断控制 ( 基于 S3C6410 开发板 ) ...
  • 通信中中断概率及代码表示

    千次阅读 热门讨论 2020-10-17 09:32:31
    通信中中断概率及代码表示 在这里接收信号的形式为:yAN=yh+ni;(y 在通信中,如果得到的随机变化的信息传输速率低于一定的水平,即业务可靠速率,则会发生“中断”。实际通信系统中,收发信号的互信息量小于预期频谱...
  • 代码中断

    千次阅读 2011-03-26 19:36:00
    但是在内核编程中,就常常出现运行的代码处在不同的中断级的情况。 本书不探讨中断级的本质,只说明中断级的判断方法。读者现在需要了解的中断级主要有Passive级和Dispatch级两种,Dispatch级比Passive级高。在...
  • 3.在代码中获得中断 参考: 内核Documentation\devicetree\bindings\interrupt-controller\interrupts.txt 1.设备树里中断节点的语法 1.1 设备树里的中断控制器 中断的硬件框图如下: 在硬件上,“中断控制器”只有...
  • 中断代码;单步执行代码;运行到光标处;运行到调用堆栈上的函数;设置下一语句;单步执行“仅我的代码”;停止并重新开始调试;从调试的进程分离。 内容 Start debugging a VS project; ...
  • div溢出中断处理代码

    千次阅读 2012-06-13 15:48:14
    2.发生中断时,将引起中断的指令的cs:ip存入栈中,然后中断处理程序执行完毕,如果中断处理程序不使程序结束,而试图使用iret返回引起中断的指令,则回到引起中断的指令会再次引起中断。这里,我们在中断处理程序内...
  • 博主把今天学到的基于三星S5PV210核心板的简单IRQ中断框架代码加上个人的理解在这里总结了一下,如有错误理解,欢迎大家指正交流。本文以基于Cortex-A8的三星s5pv210实现外部中断16来点亮LED灯为例子。
  •  首先要确定如果一个外设发出中断请求,它到底做了什么,设备是不能直接发出中断的,而是借助中断控制器,设备向中断控制器请求中断,这就是IRQ的来历。  对于龙芯1B处理器来说,中断控制器有四条输出线接在了...
  • #define _1231_C_ #include "reg51.h" #include "1231.h" //sbit OE=P2^3; unsigned int SystemTime;...void timer0(void) interrupt 1 using 3 //中断部分代码,见下文的释疑 {  TH0 = 0xdb;  TL0 = 0xff; // TF
  • MSI/MSI-x中断
  • 中断在内核启动的过程中就初始化完成,中断的注册一般是在设备被打开的时候进行,而不是在设备驱动初始化的时候进行,这个是有原因的,在linux设备驱动一书中提到过这个问题,可以在设备驱动初始化过程中注册中断,...
  • STM32 外部中断详解(原理+配置代码

    万次阅读 多人点赞 2020-02-27 22:24:38
    本文介绍了STM32基于标准外设库的外部中断配置,以及基于参考手册如何更加寄存器配置外部中断
  • 中断

    万次阅读 2018-10-03 18:54:31
    整个过程称为中断处理,简称中断,而引起这一过程的事件称为中断事件。中断是计算机实现并发执行的关键,也是操作系统工作的根本。 分类  中断按事件来源分类,可以分为外部中断和内部中断中断事件来自于CPU...
  • OK6410 裸机中断最简单代码

    千次阅读 热门讨论 2011-09-01 22:52:51
    近来想学ARM开发,使用了S3C6410核的OK6410开发板,为了学习ARM的底层技术...中断,我认为在初学单片机开发的时候是一个比较麻烦的事情,所有想把这个东西弄懂,结果在网上找了遍,都没有找到可以用的代码!为什么呢?因
  • 【Java并发编程】之二:线程中断(含代码

    万次阅读 多人点赞 2013-12-03 16:08:06
    转载请注明出处: 使用interrupt()中断线程   当一个线程运行时,另一个线程可以调用对应的Thread对象的... 下面一段代码演示了休眠线程的中断 public class SleepInterrupt extends Object implements Runnab
  • Linux程序的常用信号中断捕获代码

    千次阅读 2011-04-06 22:25:00
    Linux程序经常需要捕获一些中断信号,如按下CTRL+C就会触发SIGTERM信号等, if (atexit(&cleanup)) //atexit现在不鼓励用了,常用来做程序退出的后处理工作 { fprintf(stderr, "cannot set exit ...
  • 一、什么是中断? 打断当前的操作,执行中断需要做的事情。 中断的作用:中断机制不仅赋予了系统处理意外情况的能力,就可以“同时”完成多个任务,提高了并发“处理”能力。 和线程的区别:线程是同时执行多个...
  • 此文详细描述了中断产生到中断处理程序执行、中断处理程序返回以及中断描述符初始化整个过程,结合linux-0.00源代码片断学习将会更直观易懂。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 519,913
精华内容 207,965
关键字:

中断代码