精华内容
下载资源
问答
  • 【STM32】NVIC中断优先级管理(中断向量表)

    万次阅读 多人点赞 2018-04-08 19:55:22
    STM32F1xx官方资料: 《STM32中文参考手册V10》-第9章 中断和事件 Cortex-M3内核支持256个中断,其中包含...STM32有84个中断,包括16个内核中断(异常)和68个可屏蔽中断,具有16级可编程的中断优先级。而STM32F10...

    STM32F1xx官方资料:
    《STM32中文参考手册V10》-第9章 中断和事件

    Cortex-M3内核支持256个中断,其中包含了16个内核中断(异常)和240个外部中断,并且具有256级的可编程中断设置。但是,STM32并没有使用CM3内核的全部东西,而是只用了它的一部分。STM32有84个中断,包括16个内核中断(异常)和68个可屏蔽中断,具有16级可编程的中断优先级。而STM32F103系列上面,16个内核中断(异常)不变,而可屏蔽中断只有60个(在107系列才有68个)。

    注意一下:CM3的外部中断和STM32的外部中断不是一个概念。CM3:除了内核异常之外的都是外部中断;STM32:外部中断EXTI只有6个

    其实,内核中断也叫内核异常。

    • 中断是指系统停止当前正在运行的程序转而其他服务,可能是程序接收了比自身高优先级的请求,或者是人为设置中断,中断是属于正常现象。 
    • 异常是指由于cpu本身故障、程序故障或者请求服务等引起的错误,异常属于不正常现象。

    因此,下面就直接介绍一下STM32F103系列的16个内核中断(异常)、60个中断:

    在中断向量表中从优先级7-66(中断号从0-59)代表着STM32F103的60个中断。优先级号越小,优先级越高。当表中的某处异常或中断被触发,程序计数器指针(PC)将跳转到该异常或中断的地址处执行,该地址处存放这一条跳转指令,跳转到该异常或中断的服务函数处执行相应的功能。因此,异常和中断向量表只能用汇编语言编写。

    在MDK中,有标准的异常和中断向量表文件可以使用(startup_stm32f10x_hd.s),在其中标明了中断处理函数的名称,不能随意定义。而中断通道NVIC_IRQChannel(即IRQn_Type类型)是在stm32f10x.h文件中进行了宏定义。

    什么是NVIC?即嵌套向量中断控制器(Nested Vectored Interrupt Controller)。CM3的中有一个强大而方便的NVIC,它是属于Cortex内核的器件,中断向量表中60个中断都由它来处理。NVIC是Cortex-M3核心的一部分,关于它的资料不在《STM32的技术参考手册》中,应查阅ARM公司的《Cortex-M3技术参考手册》Cortex-M3的向量中断统一由NVIC管理。

    NVIC的核心功能是中断优先级分组、中断优先级的配置、读中断请求标志、清除中断请求标志、使能中断、清除中断等,它控制着STM32中断向量表中中断号为0-59的60个中断!!外部中断信号从核外发出,信号最终要传递到NVIC(嵌套向量中断控制器)。NVIC跟内核紧密耦合,它控制着整个芯片中断的相关功能。

     

    STM32中断优先级分组

    中断优先级分组寄存器

    这60个中断,怎么管理呢?这就涉及到STM32的中断分组。STM32可以将中断分成5个组,分别为组0-4;同时,对每个中断设置一个抢占优先级和响应优先级。分组配置是由SCB->AIRCR寄存器的bit10-8来定义的。SCB->AIRCR是在哪里的呢?由于这是CM3内核定义的,在文档《Cortex-M3权威指南(中文)》中能查找到。

    具体的分配关系如下所示:

    AIRCR中断分组设置表
    AIRCR[10:8] IP bit[7:4]分配情况 分配结果
    0 111 0:4 0位抢占优先级,4位响应优先级
    1 110 1:3 1位抢占优先级,3位响应优先级
    2 101 2:2 2位抢占优先级,2位响应优先级
    3 100 3:1 3位抢占优先级,1位响应优先级
    4 011 4:0 4位抢占优先级,0位响应优先级

    其中AIRCR寄存器来确定是用哪种分组,IP寄存器是相对应于那种分组抢占优先级和响应优先级的分配比例。例如组设置成3,那么此时所有的60个中断优先寄存器高4位中的最高3位是抢占优先级,低1位为响应优先级。CM3中定义了8个Bit用于设置中断源的优先级,而STM32只选用其中的4个Bit。

    抢占优先级的级别高于响应优先级,而数值越小所代表的的优先级越高。 

    介绍一下抢占优先级、响应优先级的区别:

    1. 高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的;
    2. 抢占优先级相同的中断,高响应优先级不可以打断低响应优先级的中断;
    3. 抢占优先级相同的中断,当两个中断同时发生的情况下,哪个响应优先级高,哪个先执行;
    4. 如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;

    除此之外有两点需要注意:

    1. 打断的情况只会与抢占优先级有关, 和响应优先级无关!
    2. 一般情况下,系统代码执行过程中,只设置一次中断优先级分组,比如分组2,设置好分组之后一般不会再改变分组。随意改变分组会导致中断管理混乱,程序出现意想不到的执行结果。

    中断优先级分组库函数

    CM3核的优先级分组方式,使用的设置函数NVIC_SetPriorityGrouping()

    接下来介绍STM32的中断优先级分组函数NVIC_PriorityGroupConfig(),用来进行中断分组设置的,此函数是在固件库下misc.c文件中(文件目录是:

    STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\STM32F10x_StdPeriph_Driver\src\misc.c):

    void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
    {
      /* Check the parameters */
      assert_param(IS_NVIC_PRIORITY_GROUP(NVIC_PriorityGroup));
      
      /* Set the PRIGROUP[10:8] bits according to NVIC_PriorityGroup value */
      SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;
    }

    函数的参数的取值,是在同文件中进行宏定义的:

    #define NVIC_PriorityGroup_0         ((uint32_t)0x700) /*!< 0 bits for pre-emption priority
                                                                4 bits for subpriority */
    #define NVIC_PriorityGroup_1         ((uint32_t)0x600) /*!< 1 bits for pre-emption priority
                                                                3 bits for subpriority */
    #define NVIC_PriorityGroup_2         ((uint32_t)0x500) /*!< 2 bits for pre-emption priority
                                                                2 bits for subpriority */
    #define NVIC_PriorityGroup_3         ((uint32_t)0x400) /*!< 3 bits for pre-emption priority
                                                                1 bits for subpriority */
    #define NVIC_PriorityGroup_4         ((uint32_t)0x300) /*!< 4 bits for pre-emption priority
                                                                0 bits for subpriority */

     

    STM32中断优先级管理

    中断优先级设置寄存器

    分组设置好了之后,怎么设置单个中断的抢占优先级和响应优先级?

    MDK为与NVIC相关的寄存器定义了如下的结构体,控制着中断向量表中60个中断(由于与中断内核有关,定义在core_cm3.h文件中):

    typedef struct
    {
      __IO uint32_t ISER[8];                      /*!< Offset: 0x000  Interrupt Set Enable Register           */
           uint32_t RESERVED0[24];                                   
      __IO uint32_t ICER[8];                      /*!< Offset: 0x080  Interrupt Clear Enable Register         */
           uint32_t RSERVED1[24];                                    
      __IO uint32_t ISPR[8];                      /*!< Offset: 0x100  Interrupt Set Pending Register          */
           uint32_t RESERVED2[24];                                   
      __IO uint32_t ICPR[8];                      /*!< Offset: 0x180  Interrupt Clear Pending Register        */
           uint32_t RESERVED3[24];                                   
      __IO uint32_t IABR[8];                      /*!< Offset: 0x200  Interrupt Active bit Register           */
           uint32_t RESERVED4[56];                                   
      __IO uint8_t  IP[240];                      /*!< Offset: 0x300  Interrupt Priority Register (8Bit wide) */
           uint32_t RESERVED5[644];                                  
      __O  uint32_t STIR;                         /*!< Offset: 0xE00  Software Trigger Interrupt Register     */
    }  NVIC_Type;     

    我们依次介绍一下这些寄存器:

    先介绍几个寄存器组长度为8,这些寄存器是32位寄存器。由于STM32只有60个可屏蔽中断,8个32位寄存器中只需要2个就有64位了,每1位控制一个中断。

    • ISER[8](Interrupt Set-Enable Registers):中断使能寄存器。其中只使用到了ISER[0]和ISER[1],ISER[0]的bit0~bit31分别对应中断0~31。ISER[1]的bit0~27对应中断32~59。要使能某个中断,就必须设置相应的ISER位为1,使该中断被使能(这仅仅是使能,还要配合中断分组、屏蔽、I/O口映射等设置才算完整)。具体每一位对应哪个中断参考stm32f103x.h里面第140行。
    • ICER[8](Interrupt Clear-Enable Registers):中断移除寄存器。该寄存器的作用于ISER相反。这里专门设置一个ICER来清除中断位,而不是向ISER位写0,是因为NVIC的寄存器写1有效,写0无效。
    • ISPR[8](Interrupt Set-Pending Registers):中断挂起控制寄存器。通过置1可以将正在进行的中断挂起,执行同级或者更高级别的中断。写0无效。
    • ICPR[8](Interrupt Clear-Pending Registers):中断解挂控制寄存器。通过置1可以将正在挂起的中断解挂。写0无效。
    • IABR[8](Interrupt Active-Bit Registers):中断激活标志位寄存器。这是一个只读寄存器,可以知道当前在执行的中断是哪一个(为1),在中断执行完后硬件自动清零。

    最后,介绍一个寄存器组长度为240,这个寄存器为8位寄存器。240个8位寄存器,每个中断使用一个寄存器来确定优先级。由于CM3由240个外部中断,所以这个寄存器组的数目就是240(注意与上面寄存器的区别,一个是一个寄存器控制一个,一个是一位控制一个)。

    • IP[240](Interrupt Priority Registers):中断优先级控制的寄存器。这是用来控制每个中断的优先级。由于STM32F10x系列一共60个可屏蔽中断,故使用IP[59]~IP[0]。其中每个IP寄存器的高4位[7:4]用来设置抢占和响应优先级(根据分组),低4位没有用到。而两个优先级各占几个位又要由上面讲到的中断优先级分组决定。

    中断优先级设置库函数

    接下来介绍如何使用库函数实现中断优先级管理,这里使用NVIC_Init()函数来进行对每个中断优先级的设置(misc.c文件中):

    void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)
    {
      uint32_t tmppriority = 0x00, tmppre = 0x00, tmpsub = 0x0F;
      
      /* Check the parameters */
      assert_param(IS_FUNCTIONAL_STATE(NVIC_InitStruct->NVIC_IRQChannelCmd));
      assert_param(IS_NVIC_PREEMPTION_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority));  
      assert_param(IS_NVIC_SUB_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelSubPriority));
        
      if (NVIC_InitStruct->NVIC_IRQChannelCmd != DISABLE)
      {
        /* Compute the Corresponding IRQ Priority --------------------------------*/    
        tmppriority = (0x700 - ((SCB->AIRCR) & (uint32_t)0x700))>> 0x08;
        tmppre = (0x4 - tmppriority);
        tmpsub = tmpsub >> tmppriority;
    
        tmppriority = (uint32_t)NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << tmppre;
        tmppriority |=  NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub;
        tmppriority = tmppriority << 0x04;
            
        NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel] = tmppriority;
        
        /* Enable the Selected IRQ Channels --------------------------------------*/
        NVIC->ISER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =
          (uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);
      }
      else
      {
        /* Disable the Selected IRQ Channels -------------------------------------*/
        NVIC->ICER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =
          (uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);
      }
    }

    其中,NVIC_InitTypeDef为一个结构体,它的成员变量为

    typedef struct
    {
      uint8_t NVIC_IRQChannel;                    /*!< Specifies the IRQ channel to be enabled or disabled.
                                                       This parameter can be a value of @ref IRQn_Type 
                                                       (For the complete STM32 Devices IRQ Channels list, please
                                                        refer to stm32f10x.h file) */
    
      uint8_t NVIC_IRQChannelPreemptionPriority;  /*!< Specifies the pre-emption priority for the IRQ channel
                                                       specified in NVIC_IRQChannel. This parameter can be a value
                                                       between 0 and 15 as described in the table @ref NVIC_Priority_Table */
    
      uint8_t NVIC_IRQChannelSubPriority;         /*!< Specifies the subpriority level for the IRQ channel specified
                                                       in NVIC_IRQChannel. This parameter can be a value
                                                       between 0 and 15 as described in the table @ref NVIC_Priority_Table */
    
      FunctionalState NVIC_IRQChannelCmd;         /*!< Specifies whether the IRQ channel defined in NVIC_IRQChannel
                                                       will be enabled or disabled. 
                                                       This parameter can be set either to ENABLE or DISABLE */   
    } NVIC_InitTypeDef;

    NVIC_InitTypeDef结构体有4个成员变量:

    1. NVIC_IRQChannel:定义初始化的是哪一个中断,这个可以在stm32f10x.h文件中查到每个中断对应的名字,如USART1_IRQn;
    2. NVIC_IRQChannelPreemptionPriority:定义此中断的抢占优先级别;
    3. NVIC_IRQChannelSubPriority:定义此中断的响应优先级别;
    4. NVIC_IRQChannelCmd:该中断是否使能。

    其实我们看NVIC_Init()函数内部使能中断,也是通过ISER寄存器配置的。这与我么之前的内容并不矛盾。函数内部使用NVIC->ISER,而NVIC是一个宏定义,

    #define NVIC     ((NVIC_Type *) NVIC_BASE)     /*!< NVIC configuration struct         */

    也就是直接操作结构体来实现操作ISER寄存器。具体原理见【STM32】MDK中寄存器地址名称映射分析

    比如,使能串口1中断,抢占优先级为1,响应优先级为2,初始化的方法为:

    NVIC_InitTypeDef   NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;// 抢占优先级为1
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;// 子优先级位2
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);	//根据上面指定的参数初始化NVIC寄存器

     

    总结与分析

    最后总结一下中断优先级设置的步骤:

    1、系统运行后先设置中断优先级分组。调用函数:

    void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);

    整个系统执行过程中,只设置一次中断分组;

    2、针对每个中断,设置对应的抢占优先级和响应优先级:

    void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);

    3、如果需要挂起/解挂,查看中断当前激活状态,分别调用相关函数即可。

     

    展开全文
  • stm32中断优先级分组

    千次阅读 2016-12-27 08:29:06
    STM32中断优先级和开关总中断一,中断优先级:STM32(Cortex-M3)中的优先级概念 STM32(Cortex-M3)中有两个优先级的概念——抢占式优先级和响应优先级,有人把响应优先级称作'亚优先级'或'副优先级',每个中断源都需要...
    STM32中断优先级和开关总中断
    
    一,中断优先级:
    
    STM32(Cortex-M3)中的优先级概念
    STM32(Cortex-M3)中有两个优先级的概念——抢占式优先级和响应优先级,有人把响应优先级称作'亚优先级''副优先级',每个中断源都需要被指定这两种优先级。
    
    具有高抢占式优先级的中断可以在具有低抢占式优先级的中断处理过程中被响应,即中断嵌套,或者说高抢占式优先级的中断可以嵌套低抢占式优先级的中断。
    
    当两个中断源的抢占式优先级相同时,这两个中断将没有嵌套关系,当一个中断到来后,如果正在处理另一个中断,这个后到来的中断就要等到前一个中断处理完之后才能被处理。如果这两个中断同时到达,则中断控制器根据他们的响应优先级高低来决定先处理哪一个;如果他们的抢占式优先级和响应优先级都相等,则根据他们在中断表中的排位顺序决定先处理哪一个。
    
    既然每个中断源都需要被指定这两种优先级,就需要有相应的寄存器位记录每个中断的优先级;在Cortex-M3中定义了8个比特位用于设置中断源的优先级,这8个比特位可以有8种分配方式,如下:
    
    所有8位用于指定响应优先级
    最高1位用于指定抢占式优先级,最低7位用于指定响应优先级
    最高2位用于指定抢占式优先级,最低6位用于指定响应优先级
    最高3位用于指定抢占式优先级,最低5位用于指定响应优先级
    最高4位用于指定抢占式优先级,最低4位用于指定响应优先级
    最高5位用于指定抢占式优先级,最低3位用于指定响应优先级
    最高6位用于指定抢占式优先级,最低2位用于指定响应优先级
    最高7位用于指定抢占式优先级,最低1位用于指定响应优先级
    
    这就是优先级分组的概念。
    
    
    
    
    --------------------------------------------------------------------------------
    Cortex-M3允许具有较少中断源时使用较少的寄存器位指定中断源的优先级,因此STM32把指定中断优先级的寄存器位减少到4位,这4个寄存器位的分组方式如下: 
    
    第0组:所有4位用于指定响应优先级
    第1组:最高1位用于指定抢占式优先级,最低3位用于指定响应优先级
    第2组:最高2位用于指定抢占式优先级,最低2位用于指定响应优先级
    第3组:最高3位用于指定抢占式优先级,最低1位用于指定响应优先级
    第4组:所有4位用于指定抢占式优先级
    
    可以通过调用STM32的固件库中的函数NVIC_PriorityGroupConfig()选择使用哪种优先级分组方式,这个函数的参数有下列5种:
    
    NVIC_PriorityGroup_0 => 选择第0组
    NVIC_PriorityGroup_1 => 选择第1组
    NVIC_PriorityGroup_2 => 选择第2组
    NVIC_PriorityGroup_3 => 选择第3组
    NVIC_PriorityGroup_4 => 选择第4组 
    
    接下来就是指定中断源的优先级,下面以一个简单的例子说明如何指定中断源的抢占式优先级和响应优先级:
    
    // 选择使用优先级分组第1组
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
    
    // 使能EXTI0中断
    NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQChannel;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 指定抢占式优先级别1
    
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 指定响应优先级别0
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    
    // 使能EXTI9_5中断
    NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 指定抢占式优先级别0
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 指定响应优先级别1
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    
    要注意的几点是:
    
    1)如果指定的抢占式优先级别或响应优先级别超出了选定的优先级分组所限定的范围,将可能得到意想不到的结果;
    
    2)抢占式优先级别相同的中断源之间没有嵌套关系;
    
    3)如果某个中断源被指定为某个抢占式优先级别,又没有其它中断源处于同一个抢占式优先级别,则可以为这个中断源指定任意有效的响应优先级别。
    
    二,开关总中断:
    
    在STM32/Cortex-M3中是通过改变CPU的当前优先级来允许或禁止中断。
    PRIMASK位:只允许NMI和hard fault异常,其他中断/异常都被屏蔽(当前CPU优先级=0)。
    FAULTMASK位:只允许NMI,其他所有中断/异常都被屏蔽(当前CPU优先级=-1)。
    
    在STM32固件库中(stm32f10x_nvic.c和stm32f10x_nvic.h) 定义了四个函数操作PRIMASK位和FAULTMASK位,改变CPU的当前优先级,从而达到控制所有中断的目的。
    
    下面两个函数等效于关闭总中断:
    void NVIC_SETPRIMASK(void);
    void NVIC_SETFAULTMASK(void);
    
    下面两个函数等效于开放总中断:
    void NVIC_RESETPRIMASK(void);
    void NVIC_RESETFAULTMASK(void);
    
    上面两组函数要成对使用,不能交叉使用。
    
    例如:
    
    第一种方法:
    NVIC_SETPRIMASK();   //关闭总中断
    NVIC_RESETPRIMASK();//开放总中断
    
    第二种方法:
    NVIC_SETFAULTMASK();   //关闭总中断
    NVIC_RESETFAULTMASK();//开放总中断
    
    常常使用
    
    NVIC_SETPRIMASK();                    // Disable Interrupts
    NVIC_RESETPRIMASK();                  // Enable Interrupts
    
    
    
    
    
    STM32时钟系统
    
    STM32资料   2009-09-23 14:53   阅读72   评论0   
    字号: 大大  中中  小小 
    在STM32中,有五个时钟源,为HSI、HSE、LSI、LSE、PLL。
    
    
    
    ①、HSI是高速内部时钟,RC振荡器,频率为8MHz。
    
    ②、HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。
    
    ③、LSI是低速内部时钟,RC振荡器,频率为40kHz。
    
    ④、LSE是低速外部时钟,接频率为32.768kHz的石英晶体。
    
    ⑤、PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。
    
    
    
    
    
    图1 HSE/LSE时钟源
    
    其中40kHz的LSI供独立看门狗IWDG使用,另外它还可以被选择为实时时钟RTC的时钟源。另外,实时时钟RTC的时钟源还可以选择LSE,或者是HSE的128分频。RTC的时钟源通过RTCSEL[1:0]来选择。
    
    STM32中有一个全速功能的USB模块,其串行接口引擎需要一个频率为48MHz的时钟源。该时钟源只能从PLL输出端获取,可以选择为1.5分频或者1分频,也就是,当需要使用USB模块时,PLL必须使能,并且时钟频率配置为48MHz或72MHz。
    
    另外,STM32还可以选择一个时钟信号输出到MCO脚(PA8)上,可以选择为PLL输出的2分频、HSI、HSE、或者系统时钟。
    
    系统时钟SYSCLK,它是供STM32中绝大部分部件工作的时钟源。系统时钟可选择为PLL输出、HSI或者HSE。系统时钟最大频率为72MHz,它通过AHB分频器分频后送给各模块使用,AHB分频器可选择12481664128256512分频。其中AHB分频器输出的时钟送给5大模块使用:
    
    ①、送给AHB总线、内核、内存和DMA使用的HCLK时钟。
    
    ②、通过8分频后送给Cortex的系统定时器时钟。
    
    ③、直接送给Cortex的空闲运行时钟FCLK。
    
    ④、送给APB1分频器。APB1分频器可选择124816分频,其输出一路供APB1外设使用(PCLK1,最大频率36MHz),另一路送给定时器(Timer)234倍频器使用。该倍频器可选择1或者2倍频,时钟输出供定时器234使用。
    
    ⑤、送给APB2分频器。APB2分频器可选择124816分频,其输出一路供APB2外设使用(PCLK2,最大频率72MHz),另一路送给定时器(Timer)1倍频器使用。该倍频器可选择1或者2倍频,时钟输出供定时器1使用。另外,APB2分频器还有一路输出供ADC分频器使用,分频后送给ADC模块使用。ADC分频器可选择为2468分频。
    
    在以上的时钟输出中,有很多是带使能控制的,例如AHB总线时钟、内核时钟、各种APB1外设、APB2外设等等。当需要使用某模块时,记得一定要先使能对应的时钟。
    
    需要注意的是定时器的倍频器,当APB的分频为1时,它的倍频值为1,否则它的倍频值就为2。连接在APB1(低速外设)上的设备有:电源接口、备份接口、CAN、USB、I2C1、I2C2、UART2、UART3、SPI2、窗口看门狗、Timer2、Timer3、Timer4。注意USB模块虽然需要一个单独的48MHz时钟信号,但它应该不是供USB模块工作的时钟,而只是提供给串行接口引擎(SIE)使用的时钟。USB模块工作的时钟应该是由APB1提供的。连接在APB2(高速外设)上的设备有:UART1、SPI1、Timer1、ADC1、ADC2、所有普通IO口(PA~PE)、第二功能IO口。
    
    下图是STM32用户手册中的时钟系统结构图,通过该图可以从总体上掌握STM32的时钟系统。
    
    
    
    
    
    STM32外部中断之二
    
    STM32资料   2009-09-10 21:18   阅读243   评论0   
    字号: 大大  中中  小小 
    STM32 外部中断配置
    
    
    1配置中断
    
    1、 分配中断向量表:
    
    /* Set the Vector Table base location at 0x20000000 */ 
    
    NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
    
    2、 设置中断优先级:
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); //设置中断优先级
    
    3、 初始化外部中断:
    
    /*允许EXTI4中断 */
    
           NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQChannel; //中断通道
    
           NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = PreemptionPriorityValue;//强占优先级
    
           NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //次优先级
    
           NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //通道中断使能
    
           NVIC_Init(&NVIC_InitStructure);       //初始化中断
    
    注意:如果我们配置的外部针脚为PA4,或PB4,或PC4,PD4等,那么采用的外部中断也必须是EXTI4,同样,如果外部中断针脚是PA1,PB1,PC1,PD1 那么中断就要用EXTI1,其他类推。
    
    2配置GPIO针脚作为外部中断的触发事件 
    
    1、 选择IO针脚
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    
    注意,如果的针脚是端口的4号针脚,配置的中断一定是EXTI4
    
    2、 配置针脚为输入
    
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    
    3、 初始化针脚
    
    GPIO_Init(GPIOD,&GPIO_InitStructure);
    
    
    3配置EXTI线,使中断线和IO针脚线连接上
    
    1、 将EXTI线连接到IO端口上
    
    将EXTI线4连接到端口GPIOD的第4个针脚上
    
           GPIO_EXTILineConfig(GPIO_PortSourceGPIOD,GPIO_PinSource4);
    
           注意:如果配置的针脚是4号,那么参数必须是GPIO_PinSource4
    
                  如果配置的针脚是3号,那么参数必须是GPIO_PinSource3
    
    2、配置中断边沿
    
           /*配置EXTI线0上出现下降沿,则产生中断*/
    
           EXTI_InitStructure.EXTI_Line = EXTI_Line4;
    
           注意:如果配置的4号针脚,那么EXTI_Line4是必须的
    
           EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    
           EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发
    
           EXTI_InitStructure.EXTI_LineCmd = ENABLE;     //中断线使能
    
           EXTI_Init(&EXTI_InitStructure);                 //初始化中断
    
           EXTI_GenerateSWInterrupt(EXTI_Line4);         //EXTI_Line4中断允许
    
    到此中断配置完成,可以写中断处理函数。
    
    举例:
    
    配置函数
    
    /*************************************************************************
    
    * 函数名      NVIC_Configration
    
    * 描述          配置各个中断寄存器
    
    * 输入           无 
    
    * 输出           无
    
    * 返回值       无
    
    ****************************************************************************/
    
    void NVIC_Configration(void)
    
    {
    
            NVIC_InitTypeDef NVIC_InitStructure; 
    
    //#ifdef VECT_TAB_RAM 
    
          /* Set the Vector Table base location at 0x20000000 */ 
    
          NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); 
    
    //#else /* VECT_TAB_FLASH */
    
          /* Set the Vector Table base location at 0x08000000 */ 
    
          //NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   
    
    //#endif   
    
           NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); //设置中断优先级
    
           /*允许EXTI4中断 */
    
           NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQChannel;
    
           NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = PreemptionPriorityValue;
    
           NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    
           NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    
           NVIC_Init(&NVIC_InitStructure);       
    
           /*允许EXTI9中断*/
    
           NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel;
    
           NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    
           NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    
           NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    
           NVIC_Init(&NVIC_InitStructure);       
    
           /*配置SysTick处理优先级:优先级以及子优先级*/
    
    
    
    }
    
    /************************************************************************
    
    * 函数名       :GPIO_Configuration(void)
    
    * 描述           :配置TIM2阵脚
    
    * 输入           :无
    
    * 输出      :无
    
    * 返回           :无
    
    ************************************************************************/
    
    void GPIO_Configuration(void){
    
    /*    GPIO_InitTypeDef GPIO_InitStructure;
    
           GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
    
           GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    
           GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    
           GPIO_Init(GPIOA,&GPIO_InitStructure); */
    
           GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
    
           GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    
           GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
    
           GPIO_Init(GPIOC,&GPIO_InitStructure);
    
           /*配置GPIOD的第一个管角为浮动输入*/
    
           GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    
           GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    
           GPIO_Init(GPIOD,&GPIO_InitStructure);
    
           /*配置GPIOB的第9个管脚为浮动输入*/
    
           GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    
           GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    
           GPIO_Init(GPIOB,&GPIO_InitStructure); 
    
    }
    
    
    /**************************************************************
    
    * 函数           SysTick_Configuration
    
    * 描述          设置SysTick
    
    * 输入           无
    
    * 输出          无
    
    * 返回值      无
    
    ***************************************************************/
    
    void SysTick_Configuration(void)
    
    {
    
          /*配置 HCLK 时钟做为SysTick 时钟源*/
    
           SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //系统时钟8分频 72MHz
    
           NVIC_SystemHandlerPriorityConfig(SystemHandler_SysTick, 8,2);
    
           /*SysTick Interrupt each 1000Hz with HCLK equal to 72MHz*/
    
           SysTick_SetReload(9000);//中断周期1ms
    
           /*Enable the SysTick Interrupt */
    
           SysTick_ITConfig(ENABLE);//打开中断           
    
           SysTick_CounterCmd(SysTick_Counter_Enable);
    
           SysTick_CounterCmd(SysTick_Counter_Clear);                 
    
    }
    
    
    /******************************************************************************
    
    * 函数名       EXTI_Configuration
    
    * 描述           配置EXTI线
    
    * 输入           无 
    
    * 输出           无
    
    * 返回值       无
    
    ******************************************************************************/
    
    void EXTI_Configuration(void){
    
           /*将EXTI线0连接到PA0*/
    
           GPIO_EXTILineConfig(GPIO_PortSourceGPIOD,GPIO_PinSource4);
    
           /*配置EXTI线0上出现下降沿,则产生中断*/
    
           EXTI_InitStructure.EXTI_Line = EXTI_Line4;
    
           EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    
           EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    
           EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    
           EXTI_Init(&EXTI_InitStructure);
    
           EXTI_GenerateSWInterrupt(EXTI_Line4);
    
    
    
           /*将EXTI线9连接到PB9上*/
    
           GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource9);
    
           /*将EXTI线9上出现下降沿产生中断*/
    
           EXTI_InitStructure.EXTI_Line = EXTI_Line9;
    
           EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    
           EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    
           EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    
           EXTI_Init(&EXTI_InitStructure);
    
           EXTI_GenerateSWInterrupt(EXTI_Line9);        
    
    }
    
    中断函数:
    
    void EXTI4_IRQHandler(void)
    
    {
    
           if(EXTI_GetITStatus(EXTI_Line4)!= RESET){
    
                  EXTI_ClearITPendingBit(EXTI_Line4);
    
                  if(Ledflag == 0){
    
                         Ledflag = 1;
    
                         GPIOC->ODR |= 0X00000080;
    
                  }
    
                  else{
    
                         Ledflag = 0;           
    
                         GPIOC->ODR &= 0XFFFFFF7F;
    
                  }
    
           }
    
    }
    
    注:时钟设置的时候最好加上这句: 
    
    RCCRCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // 使能AFIO时钟
    
    
    
    
    
    STM32中定时器的时钟源
    
    STM32资料   2009-07-24 21:34   阅读277   评论0   
    字号: 大大  中中  小小 
    
    
    
    STM32中有多达8个定时器,其中TIM1和TIM8是能够产生三对PWM互补输出的高级定时器,常用于三相电机的驱动,它们的时钟由APB2的输出产生。其它6个为普通定时器,时钟由APB1的输出产生。
    
    下图是STM32参考手册上时钟分配图中,有关定时器时钟部分的截图:
    
    
    
    从图中可以看出,定时器的时钟不是直接来自APB1或APB2,而是来自于输入为APB1或APB2的一个倍频器,图中的蓝色部分。
    
    下面以定时器2~7的时钟说明这个倍频器的作用:当APB1的预分频系数为1时,这个倍频器不起作用,定时器的时钟频率等于APB1的频率;当APB1的预分频系数为其它数值(即预分频系数为24816)时,这个倍频器起作用,定时器的时钟频率等于APB1的频率两倍。
    
    假定AHB=36MHz,因为APB1允许的最大频率为36MHz,所以APB1的预分频系数可以取任意数值;当预分频系数=1时,APB1=36MHz,TIM2~7的时钟频率=36MHz(倍频器不起作用);当预分频系数=2时,APB1=18MHz,在倍频器的作用下,TIM2~7的时钟频率=36MHz。
    
    有人会问,既然需要TIM2~7的时钟频率=36MHz,为什么不直接取APB1的预分频系数=1?答案是:APB1不但要为TIM2~7提供时钟,而且还要为其它外设提供时钟;设置这个倍频器可以在保证其它外设使用较低时钟频率时,TIM2~7仍能得到较高的时钟频率。
    
    再举个例子:当AHB=72MHz时,APB1的预分频系数必须大于2,因为APB1的最大频率只能为36MHz。如果APB1的预分频系数=2,则因为这个倍频器,TIM2~7仍然能够得到72MHz的时钟频率。能够使用更高的时钟频率,无疑提高了定时器的分辨率,这也正是设计这个倍频器的初衷。
    
    STM32笔记之外部中断GPIO
    
    STM32资料   2009-07-14 13:35   阅读331   评论0   
    字号: 大大  中中  小小 
    b)        初始化函数定义:
    void EXTI_Configuration(void); //定义IO中断初始化函数
    c)        初始化函数调用:
    EXTI_Configuration();//IO中断初始化函数调用简单应用:
    d)        初始化函数:
    void EXTI_Configuration(void)
    {
      EXTI_InitTypeDef EXTI_InitStructure;        //EXTI初始化结构定义
    
    EXTI_ClearITPendingBit(EXTI_LINE_KEY_BUTTON);//清除中断标志
       GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource3);//管脚选择
       GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource4);
         GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource5);
         GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource6);
    
        EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//事件选择
      EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//触发模式
      EXTI_InitStructure.EXTI_Line = EXTI_Line3 | EXTI_Line4; //线路选择
      EXTI_InitStructure.EXTI_LineCmd = ENABLE;//启动中断
      EXTI_Init(&EXTI_InitStructure);//初始化
    }
    
    e)        RCC初始化函数中开启I/O时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
    
    GPIO初始化函数中定义输入I/O管脚。
    //IO输入,GPIOA的4脚输入
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;         //上拉输入
      GPIO_Init(GPIOA, &GPIO_InitStructure);                //初始化
    f)        在NVIC的初始化函数里面增加以下代码打开相关中断:
      NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel;        //通道
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//占先级
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;                        //响应级
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                        //启动
      NVIC_Init(&NVIC_InitStructure);                                                                //初始化
    
    g)        在stm32f10x_it.c文件中找到void USART1_IRQHandler函数,在其中添入执行代码。一般最少三个步骤:先使用if语句判断是发生那个中断,然后清除中断标志位,最后给字符串赋值,或做其他事情。
      if(EXTI_GetITStatus(EXTI_Line3) != RESET)                                  //判断中断发生来源
       { EXTI_ClearITPendingBit(EXTI_Line3);                                          //清除中断标志
        USART_SendData(USART1, 0x41);                                              //发送字符“a”
        GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)(1-GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_2)));//LED发生明暗交替
    }
    h)        中断注意事项:
    中断发生后必须清除中断位,否则会出现死循环不断发生这个中断。然后需要对中断类型进行判断再执行代码。
    使用EXTI的I/O中断,在完成RCC与GPIO硬件设置之后需要做三件事:初始化EXTI、NVIC开中断、编写中断执行代码。 
    
    STM32的USART
    
    STM32资料   2009-07-14 13:33   阅读489   评论4   
    字号: 大大  中中  小小 
    b)        初始化函数定义:
    void USART_Configuration(void);        //定义串口初始化函数
    c)        初始化函数调用:
    void UART_Configuration(void);        //串口初始化函数调用
    初始化代码:
    void USART_Configuration(void)                        //串口初始化函数
    {
    //串口参数初始化  
      USART_InitTypeDef USART_InitStructure;              //串口设置恢复默认参数
    
    //初始化参数设置
      USART_InitStructure.USART_BaudRate = 9600;                                     //波特率9600
       USART_InitStructure.USART_WordLength = USART_WordLength_8b;   //字长8位
      USART_InitStructure.USART_StopBits = USART_StopBits_1;                 //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;//打开Rx接收和Tx发送功能
    
        USART_Init(USART1, &USART_InitStructure);                                         //初始化
      USART_Cmd(USART1, ENABLE);                                                          //启动串口
    }
    
    RCC中打开相应串口
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 , ENABLE);
    
    GPIO里面设定相应串口管脚模式
    //串口1的管脚初始化  
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;                        //管脚9
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;       //复用推挽输出
      GPIO_Init(GPIOA, &GPIO_InitStructure);                               //TX初始化
    
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;                    //管脚10
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
      GPIO_Init(GPIOA, &GPIO_InitStructure);                             //RX初始化
    
    d)        简单应用:
    发送一位字符
    USART_SendData(USART1, 数据);                //发送一位数据
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){}                                                                                        //等待发送完毕
    接收一位字符
    while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET){}                                                                                        //等待接收完毕
    变量= (USART_ReceiveData(USART1));        //接受一个字节
    
    发送一个字符串
        先定义字符串:char rx_data[250];
          然后在需要发送的地方添加如下代码
      int i;                                                                     //定义循环变量
        while(rx_data!='\0')                                           //循环逐字输出,到结束字'\0'
        {USART_SendData(USART1, rx_data);            //发送字符
         while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){} //等待字符发送完毕
         i++;} 
    
    e)        USART注意事项:
    发动和接受都需要配合标志等待。
    只能对一个字节操作,对字符串等大量数据操作需要写函数
    
    使用串口所需设置:RCC初始化里面打开RCC_APB2PeriphClockCmd
    (RCC_APB2Periph_USARTx);GPIO里面管脚设定:串口RX(50Hz,IN_FLOATING);串口TX(50Hz,AF_PP); 
    
    f)        printf函数重定义(不必理解,调试通过以备后用)
    (1)        需要c标准函数:
    #include "stdio.h"2)        粘贴函数定义代码
    #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)  //定义为putchar应用3)        RCC中打开相应串口
    (4)        GPIO里面设定相应串口管脚模式
    (6)        增加为putchar函数。
    int putchar(int c)                                              //putchar函数
    {
      if (c == '\n'){putchar('\r');}                                //将printf的\n变成\r
      USART_SendData(USART1, c);                                    //发送字符
      while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){} //等待发送结束
      return c;                                                     //返回值
    }
    
    (8)        通过,试验成功。printf使用变量输出:%c字符,%d整数,%f浮点数,%s字符串,/n或/r为换行。注意:只能用于main.c中。
    
    3、        NVIC串口中断的应用
    a)        目的:利用前面调通的硬件基础,和几个函数的代码,进行串口的中断输入练习。因为在实际应用中,不使用中断进行的输入是效率非常低的,这种用法很少见,大部分串口的输入都离不开中断。
    b)        初始化函数定义及函数调用:不用添加和调用初始化函数,在指定调试地址的时候已经调用过,在那个NVIC_Configuration里面添加相应开中断代码就行了。
    c)        过程:
    i.        在串口初始化中USART_Cmd之前加入中断设置:
    USART_ITConfig(USART1, USART_IT_TXE, ENABLE);//TXE发送中断,TC传输完成中断,RXNE接收中断,PE奇偶错误中断,可以是多个。
    ii.        RCC、GPIO里面打开串口相应的基本时钟、管脚设置
    iii.        NVIC里面加入串口中断打开代码:
    NVIC_InitTypeDef NVIC_InitStructure;//中断默认参数
    
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;//通道设置为串口1中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;   //中断占先等级0
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;              //中断响应优先级0
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;             //打开中断
    NVIC_Init(&NVIC_InitStructure);                                                //初始化
    
    iv.        在stm32f10x_it.c文件中找到void USART1_IRQHandler函数,在其中添入执行代码。一般最少三个步骤:先使用if语句判断是发生那个中断,然后清除中断标志位,最后给字符串赋值,或做其他事情。
    void USART1_IRQHandler(void)                              //串口1中断
    {
    char RX_dat;                                                          //定义字符变量
    
      if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //判断发生接收中断
      {USART_ClearITPendingBit(USART1,  USART_IT_RXNE);          //清除中断标志
    
       GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)0x01);             //开始传输
       RX_dat=USART_ReceiveData(USART1) & 0x7F;                       //接收数据,整理除去前两位
       USART_SendData(USART1, RX_dat);                                       //发送数据
       while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){}//等待发送结束
      }
    }
    
    d)        中断注意事项:
    可以随时在程序中使用USART_ITConfig(USART1, USART_IT_TXE, DISABLE);来关闭中断响应。
    NVIC_InitTypeDef NVIC_InitStructure定义一定要加在NVIC初始化模块的第一句。
    全局变量与函数的定义:在任意.c文件中定义的变量或函数,在其它.c文件中使用extern+定义代码再次定义就可以直接调用了。 
    
    STM32运行的必要硬件库
    
    STM32资料   2009-07-14 13:31   阅读163   评论0   
    字号: 大大  中中  小小 
    0、        实验之前的准备
    a)        接通串口转接器
    b)        下载IO与串口的原厂程序,编译通过保证调试所需硬件正常。
    
    1、        flash,lib,nvic,rcc和GPIO,基础程序库编写
    a)        这几个库函数中有一些函数是关于芯片的初始化的,每个程序中必用。为保障程序品质,初学阶段要求严格遵守官方习惯。注意,官方程序库例程中有个platform_config.h文件,是专门用来指定同类外设中第几号外设被使用,就是说在main.c里面所有外设序号用x代替,比如USARTx,程序会到这个头文件中去查找到底是用那些外设,初学的时候参考例程别被这个所迷惑住。
    b)        全部必用代码取自库函数所带例程,并增加逐句注释。
    c)        习惯顺序——Lib(debug),RCC(包括Flash优化),NVIC,GPIO
    d)        必用模块初始化函数的定义:
    void RCC_Configuration(void);        //定义时钟初始化函数
    void GPIO_Configuration(void);        //定义管脚初始化函数
    void NVIC_Configuration(void);        //定义中断管理初始化函数
    void Delay(vu32 nCount);                        //定义延迟函数
    e)        Main中的初始化函数调用:
    RCC_Configuration();                //时钟初始化函数调用
    NVIC_Configuration();        //中断初始化函数调用
    GPIO_Configuration();        //管脚初始化函数调用
    f)        Lib注意事项:
    属于Lib的Debug函数的调用,应该放在main函数最开始,不要改变其位置。
    
    g)        RCC注意事项:
    Flash优化处理可以不做,但是两句也不难也不用改参数……
    根据需要开启设备时钟可以节省电能
    时钟频率需要根据实际情况设置参数
    h)        NVIC注意事项
    注意理解占先优先级和响应优先级的分组的概念
    i)        GPIO注意事项
    注意以后的过程中收集不同管脚应用对应的频率和模式的设置。
    
    作为高低电平的I/O,所需设置:RCC初始化里面打开RCC_APB2
    PeriphClockCmd(RCC_APB2Periph_GPIOA);GPIO里面管脚设定:IO输出(50MHz,Out_PP);IO输入(50MHz,IPU);
    
    j)        GPIO应用
    GPIO_WriteBit(GPIOB, GPIO_Pin_2, Bit_RESET);//重置
    GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x01);//写入1
    GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x00);//写入0
    GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6) ;//读入IO
    k)        简单Delay函数
    void Delay(vu32 nCount)//简单延时函数
    {for(; nCount != 0; nCount--);} 
    
    基于STM32的PWM输出
    
    STM32资料   2009-07-14 13:30   阅读449   评论2   
    字号: 大大  中中  小小 
    c)        初始化函数定义:
    void TIM_Configuration(void);  //定义TIM初始化函数
    d)        初始化函数调用:
    TIM_Configuration();  //TIM初始化函数调用
    e)        初始化函数,不同于前面模块,TIM的初始化分为两部分——基本初始化和通道初始化:
    void TIM_Configuration(void)//TIM初始化函数
    { 
      TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;//定时器初始化结构
      TIM_OCInitTypeDef  TIM_OCInitStructure;//通道输出初始化结构
    
    //TIM3初始化
      TIM_TimeBaseStructure.TIM_Period = 0xFFFF;        //周期0~FFFF
      TIM_TimeBaseStructure.TIM_Prescaler = 5;          //时钟分频
      TIM_TimeBaseStructure.TIM_ClockDivision = 0;      //时钟分割
      TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//模式
      TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);   //基本初始化
      TIM_ITConfig(TIM3, TIM_IT_CC4, ENABLE);//打开中断,中断需要这行代码
    
    //TIM3通道初始化
      TIM_OCStructInit(& TIM_OCInitStructure);                                                //默认参数
      TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;                    //工作状态
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;         //设定为输出,需要PWM输出才需要这行代码
      TIM_OCInitStructure.TIM_Pulse = 0x2000;                                 //占空长度
      TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;                 //高电平
      TIM_OC4Init(TIM3, &TIM_OCInitStructure);                                 //通道初始化
    
      TIM_Cmd(TIM3, ENABLE);                                                                        //启动TIM3
    }
    
    f)        RCC初始化函数中加入TIM时钟开启:
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM3, ENABLE);
    g)        GPIO里面将输入和输出管脚模式进行设置。信号:AF_PP,50MHz。
    h)        使用中断的话在NVIC里添加如下代码:
    
    //打开TIM2中断
      NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel;  //通道
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;//占先级
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;           //响应级
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         //启动
      NVIC_Init(&NVIC_InitStructure);                                            //初始化
    
    中断代码:
    void TIM2_IRQHandler(void)
    {
      if (TIM_GetITStatus(TIM2, TIM_IT_CC4) != RESET)       //判断中断来源
      {
        TIM_ClearITPendingBit(TIM2, TIM_IT_CC4);            //清除中断标志
        GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)(1-GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_11)));//变换LED色彩
        IC4value = TIM_GetCapture4(TIM2);                   //获取捕捉数值
      }  
    }
    
    i)        简单应用:
    //改变占空比
    TIM_SetCompare4(TIM3, 变量);
    
    j)        注意事项:
    管脚的IO输出模式是根据应用来定,比如如果用PWM输出驱动LED则应该将相应管脚设为AF_PP,否则单片机没有输出。 
    
    STM32资料一(转载)
    
    STM32资料   2009-06-14 20:15   阅读766   评论1   
    字号: 大大  中中  小小 
    
    
    注:下面是一些常用的代码,网上很多但是大多注释不全。高手看没问题,对于我们这些新手就费劲了……所以我把这些代码集中,进行了逐句注释,希望对新手们有价值。
    
     阅读flash: 芯片内部存储器flash操作函数
    
    我的理解——对芯片内部flash进行操作的函数,包括读取,状态,擦除,写入等等,可以允许程序去操作flash上的数据。
    
    基础应用1,FLASH时序延迟几个周期,等待总线同步操作。推荐按照单片机系统运行频率,024MHz时,取Latency=02448MHz时,取Latency=148~72MHz时,取Latency=2。所有程序中必须的
    
    用法:FLASH_SetLatency(FLASH_Latency_2);
    
    位置:RCC初始化子函数里面,时钟起振之后。
    
    基础应用2,开启FLASH预读缓冲功能,加速FLASH的读取。所有程序中必须的
    
    用法:FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
    
    位置:RCC初始化子函数里面,时钟起振之后。
    
    3、        阅读lib:调试所有外设初始化的函数。
    
    我的理解——不理解,也不需要理解。只要知道所有外设在调试的时候,EWRAM需要从这个函数里面获得调试所需信息的地址或者指针之类的信息。
    
    基础应用1,只有一个函数debug。所有程序中必须的。
    
    用法:        #ifdef DEBUG
    
                      debug();
    
    #endif
    
            位置:main函数开头,声明变量之后。
    
    4、        阅读nvic:系统中断管理。
    
    我的理解——管理系统内部的中断,负责打开和关闭中断。
    
    基础应用1,中断的初始化函数,包括设置中断向量表位置,和开启所需的中断两部分。所有程序中必须的。
    
    用法:        void NVIC_Configuration(void)
    
    {
    
    NVIC_InitTypeDef NVIC_InitStructure;                     //中断管理恢复默认参数
    
    #ifdef  VECT_TAB_RAM   //如果C/C++ Compiler\Preprocessor\Defined symbols中的定义了VECT_TAB_RAM(见程序库更改内容的表格)
    
    NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); //则在RAM调试
    
    #else                                                                      //如果没有定义VECT_TAB_RAM
    
    NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);//则在Flash里调试
    
    #endif                                                                      //结束判断语句
    
    //以下为中断的开启过程,不是所有程序必须的。
    
    //NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 
    
    //设置NVIC优先级分组,方式。
    
    //注:一共16个优先级,分为抢占式和响应式。两种优先级所占的数量由此代码确定,NVIC_PriorityGroup_x可以是0、1、2、3、4,分别代表抢占优先级有1、2、4、8、16个和响应优先级有16、8、4、2、1个。规定两种优先级的数量后,所有的中断级别必须在其中选择,抢占级别高的会打断其他中断优先执行,而响应级别高的会在其他中断执行完优先执行。
    
    //NVIC_InitStructure.NVIC_IRQChannel = 中断通道名;  //开中断,中断名称见函数库
    
    //NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级
    
    //NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;         //响应优先级
    
    //NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;    //启动此通道的中断
    
    //NVIC_Init(&NVIC_InitStructure);                                        //中断初始化
    
    }
    
    5、        阅读rcc:单片机时钟管理。
    
    我的理解——管理外部、内部和外设的时钟,设置、打开和关闭这些时钟。
    
    基础应用1:时钟的初始化函数过程——
    
    用法:void RCC_Configuration(void)                                //时钟初始化函数
    
    {
    
      ErrorStatus HSEStartUpStatus;                                        //等待时钟的稳定
    
      RCC_DeInit();                                                                   //时钟管理重置
    
      RCC_HSEConfig(RCC_HSE_ON);                                    //打开外部晶振
    
      HSEStartUpStatus = RCC_WaitForHSEStartUp();             //等待外部晶振就绪
    
    if (HSEStartUpStatus == SUCCESS)
    
      {
    
    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
    
    //flash读取缓冲,加速
    
        FLASH_SetLatency(FLASH_Latency_2);                        //flash操作的延时
    
    RCC_HCLKConfig(RCC_SYSCLK_Div1);                       //AHB使用系统时钟
    
        RCC_PCLK2Config(RCC_HCLK_Div2);                          //APB2(高速)为HCLK的一半
    
        RCC_PCLK1Config(RCC_HCLK_Div2);                          //APB1(低速)为HCLK的一半
    
    //注:AHB主要负责外部存储器时钟。PB2负责AD,I/O,高级TIM,串口1。APB1负责DA,USB,SPI,I2C,CAN,串口2345,普通TIM。
    
        RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);  //PLLCLK = 8MHz * 9 = 72 MH
    
        RCC_PLLCmd(ENABLE);                                                //启动PLL
    
    while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET){}    //等待PLL启动
    
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);  //将PLL设置为系统时钟源
    
     while (RCC_GetSYSCLKSource() != 0x08){}    //等待系统时钟源的启动
    
      }
    
    //RCC_AHBPeriphClockCmd(ABP2设备1 | ABP2设备2 |, ENABLE); //启动AHP设备
    
    //RCC_APB2PeriphClockCmd(ABP2设备1 | ABP2设备2 |, ENABLE);//启动ABP2设备
    
      //RCC_APB1PeriphClockCmd(ABP2设备1 | ABP2设备2 |, ENABLE); //启动ABP1设备
    
    }
    
    6、        阅读exti:外部设备中断函数
    
    我的理解——外部设备通过引脚给出的硬件中断,也可以产生软件中断,19个上升、下降或都触发。EXTI0~EXTI15连接到管脚,EXTI线16连接到PVD(VDD监视),EXTI线17连接到RTC(闹钟),EXTI线18连接到USB(唤醒)。
    
     基础应用1,设定外部中断初始化函数。按需求,不是必须代码。
    
            用法: void EXTI_Configuration(void)
    
    {
    
    EXTI_InitTypeDef EXTI_InitStructure;                                  //外部设备中断恢复默认参数
    
    EXTI_InitStructure.EXTI_Line = 通道1|通道2;  //设定所需产生外部中断的通道,一共19个。
    
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;     //产生中断
    
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //上升下降沿都触发 
    
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;                   //启动中断的接收 
    
    EXTI_Init(&EXTI_InitStructure);                           //外部设备中断启动
    
    }
    
            7、        阅读dma:通过总线而越过CPU读取外设数据
    
    我的理解——通过DMA应用可以加速单片机外设、存储器之间的数据传输,并在传输期间不影响CPU进行其他事情。这对于入门开发基本功能来说没有太大必要,这个内容先行跳过。
    
    8、        阅读systic:系统定时器
    
    我的理解——可以输出和利用系统时钟的计数、状态。
    
    基础应用1,精确计时的延时子函数。推荐使用的代码。
    
            用法:
    
    static vu32 TimingDelay;                                                                                 //全局变量声明
    
    void SysTick_Config(void)                                                                               //systick初始化函数
    
    {
    
        SysTick_CounterCmd(SysTick_Counter_Disable);                                     //停止系统定时器
    
        SysTick_ITConfig(DISABLE);                                //停止systick中断
    
              SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //systick使用HCLK作为时钟源,频率值除以8。
    
        SysTick_SetReload(9000);                                                                       //重置时间1毫秒(以72MHz为基础计算)
    
        SysTick_ITConfig(ENABLE);                                                                     //开启systic中断
    
    }
    
    void Delay (u32 nTime)                                                                                   //延迟一毫秒的函数
    
    {
    
        SysTick_CounterCmd(SysTick_Counter_Enable);                            //systic开始计时
    
       TimingDelay = nTime;                                            //计时长度赋值给递减变量
    
        while(TimingDelay != 0);                                //检测是否计时完成
    
        SysTick_CounterCmd(SysTick_Counter_Disable);                                             //关闭计数器
    
        SysTick_CounterCmd(SysTick_Counter_Clear);                            //清除计数值
    
    }
    
    void TimingDelay_Decrement(void)  //递减变量函数,函数名由“stm32f10x_it.c”中的中断响应函数定义好了。
    
    {
    
        if (TimingDelay != 0x00)                                //检测计数变量是否达到0
    
                { TimingDelay--;                                //计数变量递减
    
                }
    
    }
    
    注:建议熟练后使用,所涉及知识和设备太多,新手出错的可能性比较大。新手可用简化的延时函数代替:
    
    void Delay(vu32 nCount)                                                                                 //简单延时函数
    
    {
    
      for(; nCount != 0; nCount--);                                                                          //循环变量递减计数
    
    }
    
    当延时较长,又不需要精确计时的时候可以使用嵌套循环:
    
    void Delay(vu32 nCount)                                             //简单的长时间延时函数
    
    {int i;                                                //声明内部递减变量
    
      for(; nCount != 0; nCount--)                                                                    //递减变量计数
    
    {for (i=0; i<0xffff; i++)}                                                                                        //内部循环递减变量计数
    
    }
    
    9、        阅读gpio:I/O设置函数
    
    我的理解——所有输入输出管脚模式设置,可以是上下拉、浮空、开漏、模拟、推挽模式,频率特性为2M,10M,50M。也可以向该管脚直接写入数据和读取数据。
    
            基础应用1,gpio初始化函数。所有程序必须。
    
            用法:void GPIO_Configuration(void)
    
    {
    
    GPIO_InitTypeDef GPIO_InitStructure;                            //GPIO状态恢复默认参数
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_标号 | GPIO_Pin_标号 ;  //管脚位置定义,标号可以是NONE、ALL、0至15。
    
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;//输出速度2MHz
    
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;        //模拟输入模式
    
    GPIO_Init(GPIOC, &GPIO_InitStructure);                //C组GPIO初始化
    
    //注:以上四行代码为一组,每组GPIO属性必须相同,默认的GPIO参数为:ALL,2MHz,FLATING。如果其中任意一行与前一组相应设置相同,那么那一行可以省略,由此推论如果前面已经将此行参数设定为默认参数(包括使用GPIO_InitTypeDef GPIO_InitStructure代码),本组应用也是默认参数的话,那么也可以省略。以下重复这个过程直到所有应用的管脚全部被定义完毕。
    
    ……
    
    }
    
     基础应用2,向管脚写入01
    
            用法:GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x01);      //写入1
    
    基础应用3,从管脚读入01
    
            用法:GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6)
    
    STM32笔记之七:让它跑起来,基本硬件功能的建立
    
    0、        实验之前的准备
    
    a)        接通串口转接器
    
    b)        下载IO与串口的原厂程序,编译通过保证调试所需硬件正常。
    
    1、        flash,lib,nvic,rcc和GPIO,基础程序库编写
    
    a)        这几个库函数中有一些函数是关于芯片的初始化的,每个程序中必用。为保障程序品质,初学阶段要求严格遵守官方习惯。注意,官方程序库例程中有个platform_config.h文件,是专门用来指定同类外设中第几号外设被使用,就是说在main.c里面所有外设序号用x代替,比如USARTx,程序会到这个头文件中去查找到底是用那些外设,初学的时候参考例程别被这个所迷惑住。
    
    b)        全部必用代码取自库函数所带例程,并增加逐句注释。
    
    c)        习惯顺序——Lib(debug),RCC(包括Flash优化),NVIC,GPIO
    
    d)        必用模块初始化函数的定义:
    
    void RCC_Configuration(void);        //定义时钟初始化函数
    
    void GPIO_Configuration(void);        //定义管脚初始化函数
    
    void NVIC_Configuration(void);        //定义中断管理初始化函数
    
    void Delay(vu32 nCount);                        //定义延迟函数
    
    e)        Main中的初始化函数调用:
    
    RCC_Configuration();                //时钟初始化函数调用
    
    NVIC_Configuration();        //中断初始化函数调用
    
    GPIO_Configuration();        //管脚初始化函数调用
    
    f)        Lib注意事项:
    
    属于Lib的Debug函数的调用,应该放在main函数最开始,不要改变其位置。
    
    g)        RCC注意事项:
    
    Flash优化处理可以不做,但是两句也不难也不用改参数……
    
    根据需要开启设备时钟可以节省电能
    
    时钟频率需要根据实际情况设置参数
    
    h)        NVIC注意事项
    
    注意理解占先优先级和响应优先级的分组的概念
    
    i)        GPIO注意事项
    
    注意以后的过程中收集不同管脚应用对应的频率和模式的设置。
    
    作为高低电平的I/O,所需设置:RCC初始化里面打开RCC_APB2
    
    PeriphClockCmd(RCC_APB2Periph_GPIOA);GPIO里面管脚设定:IO输出(50MHz,Out_PP);IO输入(50MHz,IPU);
    
    j)        GPIO应用
    
    GPIO_WriteBit(GPIOB, GPIO_Pin_2, Bit_RESET);//重置
    
    GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x01);//写入1
    
    GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x00);//写入0
    
    GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6) ;//读入IO
    
    k)        简单Delay函数
    
    void Delay(vu32 nCount)//简单延时函数
    
    {for(; nCount != 0; nCount--);}
    
    实验步骤:
    
    RCC初始化函数里添加:RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB , ENABLE);
    
    不用其他中断,NVIC初始化函数不用改
    
    GPIO初始化代码:
    
    //IO输入,GPIOB的2、10、11脚输出
    
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 ;//管脚号
    
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   //输出速度
    
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;    //输入输出模式
    
         GPIO_Init(GPIOB, &GPIO_InitStructure);              //初始化
    
    简单的延迟函数:
    
    void Delay(vu32 nCount)                     //简单延时函数
    
    { for (; nCount != 0; nCount--);}           //循环计数延时
    
    完成之后再在main.c的while里面写一段:
    
    GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x01);//写入1
    
    Delay(0xffff);
    
    GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x00);//写入0
    
    Delay(0xffff);
    
    就可以看到连接在PB2脚上的LED闪烁了,单片机就跑起来了。
    
    STM32笔记之八:来跟PC打个招呼,基本串口通讯
    
    a)        目的:在基础实验成功的基础上,对串口的调试方法进行实践。硬件代码顺利完成之后,对日后调试需要用到的printf重定义进行调试,固定在自己的库函数中。
    
    b)        初始化函数定义:
    
    void USART_Configuration(void);        //定义串口初始化函数
    
    c)        初始化函数调用:
    
    void UART_Configuration(void);        //串口初始化函数调用
    
    初始化代码:
    
    void USART_Configuration(void)                        //串口初始化函数
    
    {
    
    //串口参数初始化  
    
      USART_InitTypeDef USART_InitStructure;              //串口设置恢复默认参数
    
    //初始化参数设置
    
      USART_InitStructure.USART_BaudRate = 9600;                                     //波特率9600
    
       USART_InitStructure.USART_WordLength = USART_WordLength_8b;   //字长8位
    
      USART_InitStructure.USART_StopBits = USART_StopBits_1;                 //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;//打开Rx接收和Tx发送功能
    
     USART_Init(USART1, &USART_InitStructure);                                         //初始化
    
      USART_Cmd(USART1, ENABLE);                                                          //启动串口
    
    }
    
    RCC中打开相应串口
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 , ENABLE);
    
    GPIO里面设定相应串口管脚模式
    
    //串口1的管脚初始化  
    
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;                        //管脚9
    
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;       //复用推挽输出
    
      GPIO_Init(GPIOA, &GPIO_InitStructure);                               //TX初始化
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;                    //管脚10
    
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
    
      GPIO_Init(GPIOA, &GPIO_InitStructure);                             //RX初始化
    
    d)        简单应用:
    
    发送一位字符
    
    USART_SendData(USART1, 数据);                //发送一位数据
    
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){}                                                                                        //等待发送完毕
    
    接收一位字符
    
    while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET){}                                                                                        //等待接收完毕
    
    变量= (USART_ReceiveData(USART1));        //接受一个字节
    
    发送一个字符串
    
        先定义字符串:char rx_data[250];
    
          然后在需要发送的地方添加如下代码
    
      int i;                                                                     //定义循环变量
    
        while(rx_data!='\0')                                           //循环逐字输出,到结束字'\0'
    
        {USART_SendData(USART1, rx_data);            //发送字符
    
         while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){} //等待字符发送完毕
    
         i++;} 
    
    e)        USART注意事项:
    
    发动和接受都需要配合标志等待。
    
    只能对一个字节操作,对字符串等大量数据操作需要写函数
    
    使用串口所需设置:RCC初始化里面打开RCC_APB2PeriphClockCmd
    
    (RCC_APB2Periph_USARTx);GPIO里面管脚设定:串口RX(50Hz,IN_FLOATING);串口TX(50Hz,AF_PP); 
    
    f)        printf函数重定义(不必理解,调试通过以备后用)
    
    (1)        需要c标准函数:
    
    #include "stdio.h"2)        粘贴函数定义代码
    
    #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)  //定义为putchar应用3)        RCC中打开相应串口
    
    (4)        GPIO里面设定相应串口管脚模式
    
    (6)        增加为putchar函数。
    
    int putchar(int c)                                              //putchar函数
    
    {
    
      if (c == '\n'){putchar('\r');}                                //将printf的\n变成\r
    
      USART_SendData(USART1, c);                                    //发送字符
    
      while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){} //等待发送结束
    
      return c;                                                     //返回值
    
    }
    
    (8)        通过,试验成功。printf使用变量输出:%c字符,%d整数,%f浮点数,%s字符串,/n或/r为换行。注意:只能用于main.c中。
    
    3、        NVIC串口中断的应用
    
    a)        目的:利用前面调通的硬件基础,和几个函数的代码,进行串口的中断输入练习。因为在实际应用中,不使用中断进行的输入是效率非常低的,这种用法很少见,大部分串口的输入都离不开中断。
    
    b)        初始化函数定义及函数调用:不用添加和调用初始化函数,在指定调试地址的时候已经调用过,在那个NVIC_Configuration里面添加相应开中断代码就行了。
    
    c)        过程:
    
    i.        在串口初始化中USART_Cmd之前加入中断设置:
    
    USART_ITConfig(USART1, USART_IT_TXE, ENABLE);//TXE发送中断,TC传输完成中断,RXNE接收中断,PE奇偶错误中断,可以是多个。
    
    ii.        RCC、GPIO里面打开串口相应的基本时钟、管脚设置
    
    iii.        NVIC里面加入串口中断打开代码:
    
    NVIC_InitTypeDef NVIC_InitStructure;//中断默认参数
    
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;//通道设置为串口1中断
    
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;   //中断占先等级0
    
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;              //中断响应优先级0
    
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;             //打开中断
    
    NVIC_Init(&NVIC_InitStructure);                                                //初始化
    
    iv.        在stm32f10x_it.c文件中找到void USART1_IRQHandler函数,在其中添入执行代码。一般最少三个步骤:先使用if语句判断是发生那个中断,然后清除中断标志位,最后给字符串赋值,或做其他事情。
    
    void USART1_IRQHandler(void)                              //串口1中断
    
    {
    
    char RX_dat;                                                          //定义字符变量
    
        if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //判断发生接收中断
    
      {USART_ClearITPendingBit(USART1,  USART_IT_RXNE);          //清除中断标志
    
       GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)0x01);             //开始传输
    
       RX_dat=USART_ReceiveData(USART1) & 0x7F;                       //接收数据,整理除去前两位
    
       USART_SendData(USART1, RX_dat);                                       //发送数据
    
       while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){}//等待发送结束
    
      }
    
    }
    
    d)        中断注意事项:
    
    可以随时在程序中使用USART_ITConfig(USART1, USART_IT_TXE, DISABLE);来关闭中断响应。
    
    NVIC_InitTypeDef NVIC_InitStructure定义一定要加在NVIC初始化模块的第一句。
    
    全局变量与函数的定义:在任意.c文件中定义的变量或函数,在其它.c文件中使用extern+定义代码再次定义就可以直接调用了。
    
    STM32笔记之九:打断它来为我办事,EXIT (外部I/O中断)应用
    
    a)        目的:跟串口输入类似,不使用中断进行的IO输入效率也很低,而且可以通过EXTI插入按钮事件,本节联系EXTI中断。
    
    b)        初始化函数定义:
    
    void EXTI_Configuration(void); //定义IO中断初始化函数
    
    c)        初始化函数调用:
    
    EXTI_Configuration();//IO中断初始化函数调用简单应用:
    
    d)        初始化函数:
    
    void EXTI_Configuration(void)
    
    { EXTI_InitTypeDef EXTI_InitStructure;        //EXTI初始化结构定义
    
    EXTI_ClearITPendingBit(EXTI_LINE_KEY_BUTTON);//清除中断标志
    
       GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource3);//管脚选择
    
       GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource4);
    
         GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource5);
    
         GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource6);
    
     EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//事件选择
    
      EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//触发模式
    
      EXTI_InitStructure.EXTI_Line = EXTI_Line3 | EXTI_Line4; //线路选择
    
      EXTI_InitStructure.EXTI_LineCmd = ENABLE;//启动中断
    
      EXTI_Init(&EXTI_InitStructure);//初始化
    
    }
    
    e)        RCC初始化函数中开启I/O时钟
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
    
    GPIO初始化函数中定义输入I/O管脚。
    
    //IO输入,GPIOA的4脚输入
    
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;         //上拉输入
    
      GPIO_Init(GPIOA, &GPIO_InitStructure);                //初始化
    
    f)        在NVIC的初始化函数里面增加以下代码打开相关中断:
    
      NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel;        //通道
    
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//占先级
    
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;                        //响应级
    
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                        //启动
    
      NVIC_Init(&NVIC_InitStructure);                                                                //初始化
    
    g)        在stm32f10x_it.c文件中找到void USART1_IRQHandler函数,在其中添入执行代码。一般最少三个步骤:先使用if语句判断是发生那个中断,然后清除中断标志位,最后给字符串赋值,或做其他事情。
    
      if(EXTI_GetITStatus(EXTI_Line3) != RESET)                                  //判断中断发生来源
    
       { EXTI_ClearITPendingBit(EXTI_Line3);                                          //清除中断标志
    
        USART_SendData(USART1, 0x41);                                              //发送字符“a”
    
        GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)(1-GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_2)));//LED发生明暗交替
    
    }
    
    h)        中断注意事项:
    
    中断发生后必须清除中断位,否则会出现死循环不断发生这个中断。然后需要对中断类型进行判断再执行代码。
    
    使用EXTI的I/O中断,在完成RCC与GPIO硬件设置之后需要做三件事:初始化EXTI、NVIC开中断、编写中断执行代码。
    
    STM32笔记之十:工作工作,PWM输出
    
    a)        目的:基础PWM输出,以及中断配合应用。输出选用PB1,配置为TIM3_CH4,是目标板的LED6控制脚。
    
    b)        对于简单的PWM输出应用,暂时无需考虑TIM1的高级功能之区别。
    
    c)        初始化函数定义:
    
    void TIM_Configuration(void);  //定义TIM初始化函数
    
    d)        初始化函数调用:
    
    TIM_Configuration();  //TIM初始化函数调用
    
    e)        初始化函数,不同于前面模块,TIM的初始化分为两部分——基本初始化和通道初始化:
    
    void TIM_Configuration(void)//TIM初始化函数
    
    { 
    
      TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;//定时器初始化结构
    
      TIM_OCInitTypeDef  TIM_OCInitStructure;//通道输出初始化结构
    
    //TIM3初始化
    
      TIM_TimeBaseStructure.TIM_Period = 0xFFFF;        //周期0~FFFF
    
      TIM_TimeBaseStructure.TIM_Prescaler = 5;          //时钟分频
    
      TIM_TimeBaseStructure.TIM_ClockDivision = 0;      //时钟分割
    
      TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//模式
    
      TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);   //基本初始化
    
      TIM_ITConfig(TIM3, TIM_IT_CC4, ENABLE);//打开中断,中断需要这行代码
    
      //TIM3通道初始化
    
      TIM_OCStructInit(& TIM_OCInitStructure);                                                //默认参数
    
      TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;                    //工作状态
    
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;         //设定为输出,需要PWM输出才需要这行代码
    
      TIM_OCInitStructure.TIM_Pulse = 0x2000;                                 //占空长度
    
      TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;                 //高电平
    
      TIM_OC4Init(TIM3, &TIM_OCInitStructure);                                 //通道初始化
    
     TIM_Cmd(TIM3, ENABLE);                                                                        //启动TIM3
    
    }
    
    f)        RCC初始化函数中加入TIM时钟开启:
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM3, ENABLE);
    
    g)        GPIO里面将输入和输出管脚模式进行设置。信号:AF_PP,50MHz。
    
    h)        使用中断的话在NVIC里添加如下代码:
    
    //打开TIM2中断
    
      NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel;  //通道
    
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;//占先级
    
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;           //响应级
    
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         //启动
    
      NVIC_Init(&NVIC_InitStructure);                                            //初始化
    
    中断代码:
    
    void TIM2_IRQHandler(void)
    
    {
    
      if (TIM_GetITStatus(TIM2, TIM_IT_CC4) != RESET)       //判断中断来源
    
      {
    
        TIM_ClearITPendingBit(TIM2, TIM_IT_CC4);            //清除中断标志
    
        GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)(1-GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_11)));//变换LED色彩
    
        IC4value = TIM_GetCapture4(TIM2);                   //获取捕捉数值
    
      }  
    
    }
    
    i)        简单应用:
    
    //改变占空比
    
    TIM_SetCompare4(TIM3, 变量);
    
    j)        注意事项:
    
    管脚的IO输出模式是根据应用来定,比如如果用PWM输出驱动LED则应该将相应管脚设为AF_PP,否则单片机没有输出
    
    我的测试程序可以发出不断循环三种波长并捕获,对比结果如下:
    
    捕捉的稳定性很好,也就是说,同样的方波捕捉到数值相差在一两个数值。
    
    捕捉的精度跟你设置的滤波器长度有关,在这里
    
    TIM_ICInitStructure.TIM_ICFilter = 0x4;        //滤波设置,经历几个周期跳变认定波形稳定0x0~0xF
    
    这个越长就会捕捉数值越小,但是偏差几十个数值,下面是0416个周期滤波的比较,out是输出的数值,in是捕捉到的。
    
    现在有两个疑问:
    
    1、在TIM2的捕捉输入通道初始化里面这句
    
    TIM_SelectInputTrigger(TIM2, TIM_TS_TI2FP2);   //选择时钟触发源
    
    按照硬件框图,4通道应该对应TI4FP4。可是实际使用TI1FP1,TI2FP2都行,其他均编译错误未注册。这是为什么?
    
    2、关闭调试器和IAR程序,直接供电跑出来的结果第一个周期很正常,当输出脉宽第二次循环变小后捕捉的数值就差的远了。不知道是为什么
    
    STM32笔记之十二:时钟不息工作不止,systic时钟应用
    
    a)        目的:使用系统时钟来进行两项实验——周期执行代码与精确定时延迟。
    
    b)        初始化函数定义:
    
    void SysTick_Configuration(void);
    
    c)        初始化函数调用:
    
    SysTick_Configuration();
    
    d)        初始化函数:
    
    void SysTick_Configuration(void)
    
    {
    
      SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//时钟除8
    
      SysTick_SetReload(250000);                                                    //计数周期长度
    
      SysTick_CounterCmd(SysTick_Counter_Enable);                   //启动计时器
    
      SysTick_ITConfig(ENABLE);                                                     //打开中断
    
    }
    
    e)        在NVIC的初始化函数里面增加以下代码打开相关中断:
    
    NVIC_SystemHandlerPriorityConfig(SystemHandler_SysTick, 1, 0);//中断等级设置,一般设置的高一些会少受其他影响
    
    f)        在stm32f10x_it.c文件中找到void SysTickHandler 函数
    
    void SysTickHandler(void)
    
    {
    
    执行代码
    
    }
    
    g)        简单应用:精确延迟函数,因为systic中断往往被用来执行周期循环代码,所以一些例程中使用其中断的启动和禁止来编写的精确延时函数实际上不实用,我自己编写了精确计时函数反而代码更精简,思路更简单。思路是调用后,变量清零,然后使用时钟来的曾变量,不断比较变量与延迟的数值,相等则退出函数。代码和步骤如下:
    
    i.        定义通用变量:u16 Tic_Val=0; //变量用于精确计时
    
    ii.        在stm32f10x_it.c文件中相应定义:
    
    extern u16 Tic_Val;//在本文件引用MAIN.c定义的精确计时变量
    
    iii.        定义函数名称:void Tic_Delay(u16 Tic_Count);//精确延迟函数
    
    iv.        精确延时函数:
    
    void Tic_Delay(u16 Tic_Count)               //精确延时函数
    
    {         Tic_Val=0;                           //变量清零
    
      while(Tic_Val != Tic_Count){printf("");}//计时
    
    }
    
    v.        在stm32f10x_it.c文件中void SysTickHandler 函数里面添加
    
         Tic_Val++;//变量递增
    
    vi.        调用代码:Tic_Delay(10);   //精确延时
    
    vii.        疑问:如果去掉计时行那个没用的printf("");函数将停止工作,这个现象很奇怪
    
    C语言功底问题。是的,那个“注意事项”最后的疑问的原因就是这个
    
    Tic_Val应该改为vu16
    
    while(Tic_Val != Tic_Count){printf("");}//计时
    
    就可以改为:
    
    while(Tic_Val != Tic_Count);              //检查变量是否计数到位
    
    STM32笔记之十三:恶搞,两只看门狗
    
    a)        目的:
    
    了解两种看门狗(我叫它:系统运行故障探测器和独立系统故障探测器,新手往往被这个并不形象的象形名称搞糊涂)之间的区别和基本用法。
    
    b)        相同:
    
    都是用来探测系统故障,通过编写代码定时发送故障清零信号(高手们都管这个代码叫做“喂狗”),告诉它系统运行正常。一旦系统故障,程序清零代码(“喂狗”)无法执行,其计数器就会计数不止,直到记到零并发生故障中断(狗饿了开始叫唤),控制CPU重启整个系统(不行啦,开始咬人了,快跑……)。
    
    c)        区别:
    
    独立看门狗Iwdg——我的理解是独立于系统之外,因为有独立时钟,所以不受系统影响的系统故障探测器。(这条狗是借来的,见谁偷懒它都咬!)主要用于监视硬件错误。
    
    窗口看门狗wwdg——我的理解是系统内部的故障探测器,时钟与系统相同。如果系统时钟不走了,这个狗也就失去作用了。(这条狗是老板娘养的,老板不干活儿他不管!)主要用于监视软件错误。
    
    d)        初始化函数定义:鉴于两只狗作用差不多,使用过程也差不多初始化函数栓一起了,用的时候根据情况删减。
    
    void WDG_Configuration(void);
    
    e)        初始化函数调用:
    
    WDG_Configuration();
    
    f)        初始化函数
    
    void WDG_Configuration()                //看门狗初始化
    
    {
    
    //软件看门狗初始化
    
      WWDG_SetPrescaler(WWDG_Prescaler_8); //时钟8分频4ms
    
    // (PCLK1/4096)/8= 244 Hz (~4 ms)
    
       WWDG_SetWindowValue(65);                    //计数器数值
    
      WWDG_Enable(127);                   //启动计数器,设置喂狗时间
    
    // WWDG timeout = ~4 ms * 64 = 262 ms
    
       WWDG_ClearFlag();                   //清除标志位
    
      WWDG_EnableIT();                    //启动中断
    
    //独立看门狗初始化
    
      IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);//启动寄存器读写
    
      IWDG_SetPrescaler(IWDG_Prescaler_32);//40K时钟32分频
    
      IWDG_SetReload(349);                 //计数器数值
    
      IWDG_ReloadCounter();                //重启计数器
    
      IWDG_Enable();                       //启动看门狗
    
    }
    
    g)        RCC初始化:只有软件看门狗需要时钟初始化,独立看门狗有自己的时钟不需要但是需要systic工作相关设置。
    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
    
    h)        独立看门狗使用systic的中断来喂狗,所以添加systic的中断打开代码就行了。软件看门狗需要在NVIC打开中断添加如下代码:
    
      NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQChannel; //通道
    
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //占先中断等级
    
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;      //响应中断优先级
    
      NVIC_Init(&NVIC_InitStructure);                        //打开中断
    
    i)        中断程序,软件看门狗在自己的中断中喂狗,独立看门狗需要使用systic的定时中断来喂狗。以下两个程序都在stm32f10x_it.c文件中。
    
    void WWDG_IRQHandler(void)
    
    {
    
      WWDG_SetCounter(0x7F);          //更新计数值
    
    WWDG_ClearFlag();               //清除标志位
    
    }
    
    void SysTickHandler(void)
    
    {  IWDG_ReloadCounter();         //重启计数器(喂狗)
    
    }
    
    j)        注意事项:
    
    i.        有狗平常没事情可以不理,但是千万别忘了喂它,否则死都不知道怎么死的!
    
    ii.        初始化程序的调用一定要在systic的初始化之后。
    
    iii.        独立看门狗需要systic中断来喂,但是systic做别的用处不能只做这件事,所以我写了如下几句代码,可以不影响systic的其他应用,其他systic周期代码也可参考:
    
    第一步:在stm32f10x_it.c中定义变量
    
    int Tic_IWDG;           //喂狗循环程序的频率判断变量
    
    第二步:将SysTickHandler中喂狗代码改为下面:
    
    Tic_IWDG++;             //变量递增
    
    if(Tic_IWDG>=100)       //每100个systic周期喂狗
    
    {  IWDG_ReloadCounter();//重启计数器(喂狗)
    
      Tic_IWDG=0;          //变量清零
    
    }
    
    
    展开全文
  • AVR中断优先级

    2014-02-09 20:52:32
    AVR单片机在同一个优先级中,中断向量入口地址越低,其优先级越高。AVR单片机在响应中 断以后,会禁止系统响应其余中断。如果程序需要在某个中断服务程序中响应其它中断事 件,可以在该中断服务程序中用SEI指令或_SEI...
    AVR中断优先级 - 微水(露点)仪之家 - 微水(露点)测量仪

     


     


    AVR单片机在同一个优先级中,中断向量入口地址越低,其优先级越高。AVR单片机在响应中
    断以后,会禁止系统响应其余中断。如果程序需要在某个中断服务程序中响应其它中断事
    件,可以在该中断服务程序中用SEI指令或_SEI()(IAR)、 SEI()(
    ICCAVR)重新使能全局
    中断即可。否则,AVR单片机只有在退出中断进程时,才重新使能全局中断。

    AVR(至少是ATmega16)单片机采用固定的硬件优先级方式,不支持通过软件对中断优先级重新设定。

    AVR有不同的中断源。每个中断和复位在程序空间都有独立的中断向量。所有的中断事件都有自己的使能位。当使能位置位,且状态寄存器的全局中断使能位I 也置位时,中断可以发生。根据程序计数器PC 的不同,在引导锁定位BLB02 或BLB12 被编程的情况下,中断可能被自动禁止。这个特性提高了软件的安全性。详见 P247“ 存储器编程” 的描述。
    程序存储区的最低地址缺省为复位向量和中断向量。完整的向量列表请参见 P43“中断”。列表也决定了不同中断的优先级。向量所在的地址越低,优先级越高。RESET 具有最高的优先级,第二个为INT0 – 外部中断请求0。通过置位MCU 控制寄存器 (MCUCR) 的IVSEL,中断向量可以移至引导Flash的起始处。编程熔丝位BOOTRST也可以将复位向量移至引导Flash的起始处。具体参见P234“支持引导装入程序 – 在写的同时可以读(RWW,Read-While-Write) 的自我编程能力”。
    任一中断发生时全局中断使能位I 被清零,从而禁止了所有其他的中断。用户软件可以在中断程序里置位I 来实现中断嵌套。此时所有的中断都可以中断当前的中断服务程序。执行RETI 指令后I 自动置位。
    从根本上说有两种类型的中断。第一种由事件触发并置位中断标志。对于这些中断,程序计数器跳转到实际的中断向量以执行中断处理程序,同时硬件将清除相应的中断标志。中断标志也可以通过对其写”1” 的方式来清除。当中断发生后,如果相应的中断使能位为“0”,则中断标志位置位,并一直保持到中断执行,或者被软件清除。类似的,如果全局中断标志被清零,则所有已发生的中断都不会被执行,直到I 置位。然后挂起的各个中断按中断优先级依次执行。
    第二种类型的中断则是只要中断条件满足,就会一直触发。这些中断不需要中断标志。若中断条件在中断使能之前就消失了,中断不会被触发。
    AVR 退出中断后总是回到主程序并至少执行一条指令才可以去执行其他被挂起的中断。要注意的是,进入中断服务程序时状态寄存器不会自动保存,中断返回时也不会自动恢复。这些工作必须由用户通过软件来完成。
    使用CLI 指令来禁止中断时,中断禁止立即生效。没有中断可以在执行CLI 指令后发生,即使它是在执行CLI 指令的同时发生的。

    展开全文
  • TI C66x DSP中断类型及其优先级

    千次阅读 2014-05-19 12:15:24
    There are four types of interrupts on the CPU. • Reset ...• Exception(异常也可视为中断) These first three types are differentiated by their priorities. The reset interrupt has t
    
    

    There are four types of interrupts on the CPU.

    • Reset

    • Maskable

    • Nonmaskable

    • Exception(异常也可视为中断)

    These first three types are differentiated by their priorities. The reset interrupt has the highest priority and corresponds to the RESET signal. The nonmaskable interrupt (NMI) has the second highest priority and corresponds to the NMI signal. The lowest priority interrupts are interrupts 4-15 corresponding to the INT4-INT15 signals. RESET, NMI, and some of the INT4-INT15 signals are mapped to pins on C6000 devices.

    The CPU supports exceptions as another type of interrupt. When exceptions are enabled, the NMI input behaves as an exception.

    Priority    Interrupt Name    Interrupt Type
    Highest     Reset                 Reset
                       NMI                     Nonmaskable
                       INT4                   Maskable
                       INT5                   Maskable
                       INT6                   Maskable
                       INT7                   Maskable
                       INT8                   Maskable
                       INT9                   Maskable
                       INT10                 Maskable
                       INT11                 Maskable
                       INT12                 Maskable
                       INT13                 Maskable
                       INT14                 Maskable
    Lowest     INT15                  Maskable

    在基于OSEck RTOS的TI C66x DSP系统中, 这些中断的优先级将高于所有user定义的APP进程(即prioritied process),从而使中断能够在第一时间处理。
    展开全文
  • 中断类型 Cortex‐M3 在内核水平上搭载了一个中断响应系统, 支持为数众多的系统异常和外部中 断。其中,编号为 1-15 的对应系统异常,大于等于 16 的则全是外部中断,支持240个IRQ(中断请求)。除了个别异常的...
  • 相关类型05. 相关函数06. 附录07. 声明 01. 概述 CM4 内核支持 256 个中断,其中包含了 16 个内核中断和 240 个外部中断,并且具有256 级的可编程中断设置。但 STM32F4 并没有使用 CM4 内核的全部东西,而是只用了...
  • STM32学习笔记(4)——NVIC中断优先级管理和外部中断EXTI一、NVIC中断优先级管理1. 中断简介2. 中断向量表3. 嵌套向量中断控制器(NVIC)4. NVIC的定义以及库函数 一、NVIC中断优先级管理 1. 中断简介 在Cortex-M3...
  • STM32中断及其优先级

    千次阅读 2017-12-15 08:12:18
    1、异常与中断 2、优先级分组,NVIC_PriorityGroupConfig 3、抢占优先级,NVIC_IRQChannelPreemptionPriority 4、子(亚)优先级,NVIC_IRQChannelSubPriority 5、中断号定义,NVIC_IRQChannel 6、优先级配置的寄存器...
  • 很多人在配置STM32中断时对固件库中的这个函数NVIC_PriorityGroupConfig()——配置优先级分组方式,会很不理解,尤其是看中文翻译版的,因为中文翻译版里把这里翻译成“先占优先级和从优先级”这样翻译其实是不对的...
  • STM32 NVIC 中断 优先级

    2018-05-12 21:02:15
    中断 优先级 管理CM3 内核支持 256 个中断,其中包含了 16 个内核中断和 240 个外部中断,并且具有 256级的可编程中断设置。但 STM32 并没有使用 CM3 内核的全部东西,而是只用了它的一部分。STM32 有 84 个中断,...
  • STM32中断优先级

    2012-11-26 15:05:00
    STM32中断优先级 本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明.... ...在Cortex-M3中定义了8个比特位用于设置中断源的优先级,而STM32用4位指定指定中断优先级 STM32中优先级分组: 第0组:所...
  • NVIC 中断优先级管理

    2019-03-24 12:40:58
    CM4 内核支持 256 个中断,其中包含了 16 个内核中断和 240 个外部中断,并且具有256 级的可编程中断设置。但 STM32F4 并没有使用 CM4 内核的全部东西,而是只用了它的一部分: STM32F40xx/STM32F41xx 总共有 92 个...
  • STM32中断优先级概念

    千次阅读 2014-10-24 11:09:03
    一:综述 STM32 目前支持的中断共为 84 个(16 个内核+68 个外部),...STM32(Cortex-M3)中有两个优先级的概念——抢占式优先级和响应优先级,有人把响应优先级称作'亚优先级'或'副优先级',每个中断源都需要被指定这两
  • 最近在使用STM32F3芯片的时候,遇到这样一个问题:如果外部中断来的频率足够快,上一个中断没有处理完成,新来的中断如何处理? 在调试时,发现有中断有 挂起、激活、失能等状态,考虑这些状态都是干啥用的呢!他们...
  • 中断优先级设计PS: 这片文章仅仅基于库函数开发区别于51单片机的可怜的中断资源而言,cortex-M3内核拥有256个中断,其中包括16个内核中断和240个可屏蔽中断,但是stm32f103系列的单片机只保留了CM3内核的一部分资源...
  • 文章目录第八章 中断系统8.1 中断的基本概念8.1.1 中断概念的引入及描述中断方式示意(以输入中断为例)**中断**的定义8.1.2 中断源及中断分类中断的分类8.1.3 中断类型中断类型码中断向量中断向量表中断向量表的...
  • 1、中断类型 从之前的串口实验可以看出,STM32总共分为内部中断和外部中断,内部和外部的配置差别不是很大,外部中断只是多了一步,需要通过 GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)...
  • 51单片机中断的使用及优先级设置 51单片机有两个外部中断,两个定时器/计数器,两个外部中断分别是int0,int1。定时器/计数器分别是t0,t1,还有一个串口中断TI/RI,加起来有五个中断。它们在硬件上的排列顺序是INT0...
  • 最近在使用STM32进行一些开发,外部中断一直是我困扰的一个问题,特别是中断嵌套中先占优先级和从占优先级的内容,更是让我头疼,今天查阅了一些资料,感觉有些收获,先写下来,一来可以让自己以后忘记的时候可以...
  • 我对STM32F10x NVIC中断优先级的理解

    千次阅读 2012-11-05 10:02:38
     CM3支持硬件中断嵌套,分为抢占式优先级和亚优先级,使用规则主要有,抢占优先级高级别的可以打断低级别的,同一级别的抢占优先级同时发生时,亚当优先级高的先发生中断,若是相同,则按硬件排列顺序发生。...
  • NVIC中断优先级管理: 首先是中断分组,我们知道所用的CM3内核支持256个中断,其中包含了16个内核中断和240个外部中断,并且具有256级的可编程中断设置。然而STM32并没有使用CM3内核的全部东西,而是只用了它的一...
  • 51单片机中断号对应的中断类型

    千次阅读 2019-08-07 08:36:08
    中断源 默认中断级别 外部中断0 INT0 最高 interrupt 0 定时器0中断 T0 ...
  • 运算符优先级

    2019-01-22 11:06:00
    1、该表中优先级按照从高到低的顺序书写,也就是优先级为1的优先级最高,优先级14的优先级最低。 2、结合性是指运算符结合的顺序,通常都是从左到右。从右向左的运算符最典型的就是负号,例如3+-4,则意义为3加-4,...
  • Wince 6.0物理中断类型

    2009-08-13 17:22:00
    该函数调用OALIntrInit()完成对中断的初始化.2 OALIntrInit()对中断的初始化做了如下工作:2.1 通过配置IPR0-IPR33设置中断优先级,优先级定义在g_IntPriorities和g_IntPriorities2中,其中IRQ_OSMR0为最高优先级, IRQ_...
  • DSP中断类型和中断信号简记(转)

    千次阅读 2011-04-01 17:11:00
    中断类型和中断信号简记 http://hi.baidu.com/lhjwd0322/blog/item/75c5f42dfd50653c359bf77b.html<br />中断类型和中断信号如下: 三种中断类型:RESET#,NMI,INT4-INT15,优先顺序如下:   ...
  • 需要使用STM32的CAN进行通信,经过一系列配置后,已可正常收发,还剩下一个CAN... 误中断使能寄存器已经配置使能了,出错后就是无法进入"CAN1_SCE_IRQHandler"中断。(让CAN通信出错的的 办法很简单,将"CAN_...
  • STM32中断(外部中断和定时器中断)

    千次阅读 多人点赞 2019-05-27 17:22:00
    一、外部中断 spi,iic的中断和51单片机...抢占式优先级:高抢占式优先级中断事件会打断当前主程序以及中断程序运行,俗称中断嵌套。 响应优先级:在抢占式优先级相同的情况下,高响应优先级中断优先被响应; ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 27,078
精华内容 10,831
关键字:

优先级最高的中断类型