STM32:配置中断初始化函数

#include "stm32f10x.h"                  // Device header
// 学习EXTI 外部中断的配置与使用。
/*
    // GPIOB 是APB2的外设。APB2, APB1, AHB
    // 如果不确定外设挂载在那个总线上,不知道开启那个总线的时钟,就跳转到函数定义,看参数取值范围,既可以确定该总线上有哪些外设。
    1,配置RCC,把使用到的GPIO外设时钟开启。
    2,配置GPIO,端口选择输入模式。
    3,配置AFIO,选择我们用的这一路GPIO PIn ,连接到后面的EXTI。
    4,配置EXTI,选择边沿触发方式。触发响应方式(中断响应)
    5,配置NVIC,优先级的配置。
    6,最后根据NVIC,外部中断信号就能进CPU了。
*/
/*
void GPIO_AFIODeInit(void); 复位AFIO
void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); 锁定GPIO配置的。防止意外更改。
void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
void GPIO_EventOutputCmd(FunctionalState NewState); 配置AFIO事件输出功能。
void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState); // 用来进行引脚重映射。(重映射的方式, 新的状态)
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource); // 用来进行配置AFIO的数据选择器,来选择中断源来自那个引脚。(配置中断用到的函数)
void GPIO_ETH_MediaInterfaceConfig(uint32_t GPIO_ETH_MediaInterface);   // 和以太网有关的。

void EXTI_DeInit(void); // 把exti配置都清除,恢复成上电默认的状态。// 外设初始化基本都有着三个函数。很像。
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct); // 根据结构体里的参数,初始化exti。配置中断主要用的就是这个函数。
void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct); // 调用这个函数可以把参数传递的结构体变量赋一个默认值。
void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line); // 软件触发外部中断。调用这个函数,参数给一个指定的中断线,就能软件触发一次这个外部中断。
FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line); // 库函数的模板函数。可以获取指定的标志位是否置1.
void EXTI_ClearFlag(uint32_t EXTI_Line); // 对置1的标志位清楚。 在主函数中查看或清除挂起标志位。
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line); // 获取中断标志位是否被置1。在中断中查看或清除标志位/
void EXTI_ClearITPendingBit(uint32_t EXTI_Line); // 清除中断挂起标志位。都是对状态寄存器的读写。下两个只能读取跟中断有关的标志位,并且对中断是否允许做了判断。
// 上两个是一般的读取状态寄存器,没有额外的处理,能不能触发中断标志位都能读取。

void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup); // 中断分组
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct); // 根据结构图里面指定的参数,初始化NVIC 
void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset); // NVIC,设置中断向量表
void NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState NewState); // 系统低功耗配置
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource); // 

*/
void count_sensor_init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  // 开启APB2外设时钟。
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);// 开启AFIO 时钟.
    // EXTI  (NVIC内核的外设)时钟一直是开启的。
    
    // 2配置GPIO
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_14;                // 用的PIN14
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStruct);
    
    // 配置AFIO
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,  GPIO_PinSource14); // 由于用到的是GPIOB所以把X改成B,PIN14 .代表链接PB14号口的第14个中断线路。
    // 配置EXTI
    EXTI_InitTypeDef EXTI_InitStruct;
    EXTI_InitStruct.EXTI_Line = EXTI_Line14; // 中断线
    EXTI_InitStruct.EXTI_LineCmd = ENABLE; // 开启中断
    EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt; // 中断模式
    EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising; // 触发方式
    EXTI_Init(&EXTI_InitStruct); 
    /*
    EXTI_Trigger_Rising = 0x08,
    EXTI_Trigger_Falling = 0x0C,  
    EXTI_Trigger_Rising_Falling = 0x10
    */
    // 配置NVIC
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  // 两位抢占,两位响应。分组方式,整个芯片只能用一种。
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel = EXTI15_10_IRQn; // 指定中断通道,开启或关闭。
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; // 指定中断通道使能或失能。
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; // 指定所选通道的抢占优先级
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; // 与响应优先级。
    NVIC_Init(&NVIC_InitStruct);  
}
    uint16_t num ; 
// 在stm32中中断函数名字都是固定的。中断函数都是无参数,无返回值的。名字不要写错。
void EXTI15_10_IRQHandler(void)
{
    if(EXTI_GetITStatus(EXTI_Line14) == SET) // 判断EXTI_Line14的中断标志位是否为1,
    {                                                                   // 为1,就是触发中断了;为1,就可以执行中断了。
        num++ ;
        // 清除中断标志位。因为只要中断标志位置1了,程序就会跳到中断函数,不清除中断,程序会卡死在中断函数中。
        EXTI_ClearITPendingBit(EXTI_Line14);
    }
}

uint16_t get_num (void)
{
    return num ;
}
    
    

 

#include "stm32f10x.h"                  // Device header

int16_t encoder_count;

// AB 相都触发中断,只有B下降沿,a为低:正转。
// A下降沿,B低,反转。这样正反转,都转到位了才进中断执行加减。int16_t encoder_count = 0;
void encoder_init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  // 开启APB2外设时钟。
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);// 开启AFIO 时钟.
    // EXTI  (NVIC内核的外设)时钟一直是开启的。
    
    // 2配置GPIO
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; // pin0 A相;PIN1B相。
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStruct);
    
    // 配置AFIO
    //GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,  GPIO_PinSource0 | GPIO_PinSource1); // 由于用到的是GPIOB所以把X改成B,PIN14 .代表链接PB14号口的第14个中断线路。
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,  GPIO_PinSource0 );
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,  GPIO_PinSource1 );
    // 配置EXTI
    EXTI_InitTypeDef EXTI_InitStruct;
    EXTI_InitStruct.EXTI_Line = EXTI_Line0 | EXTI_Line1; // 中断线
    EXTI_InitStruct.EXTI_LineCmd = ENABLE; // 开启中断
    EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt; // 中断模式
    EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling; // 触发方式
    EXTI_Init(&EXTI_InitStruct); 
    /*
    EXTI_Trigger_Rising = 0x08,
    EXTI_Trigger_Falling = 0x0C,  
    EXTI_Trigger_Rising_Falling = 0x10
    */
    // 配置NVIC 
    // 同时初始化exti0 与 exti1 
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  // 两位抢占,两位响应。分组方式,整个芯片只能用一种。
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn; // 指定中断通道,开启或关闭。EXTI0_IRQHandler
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; // 指定中断通道使能或失能。
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; // 指定所选通道的抢占优先级
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; // 与响应优先级。
    NVIC_Init(&NVIC_InitStruct);  
    
    NVIC_InitStruct.NVIC_IRQChannel = EXTI1_IRQn; // 指定中断通道,开启或关闭。EXTI1_IRQHandler
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; // 指定中断通道使能或失能。
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; // 指定所选通道的抢占优先级
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2; // 与响应优先级。
    NVIC_Init(&NVIC_InitStruct);  
}


int16_t get_encoder(void)
{
    int16_t temp;
    temp = encoder_count;
    encoder_count = 0;
    return temp;
}
// 写对应中断的执行函数。
void EXTI0_IRQHandler(void)
{
    if(EXTI_GetITStatus(EXTI_Line0) ==  SET)
    {
        if(GPIO_ReadInputDataBit(GPIOB,  GPIO_Pin_1) == RESET) // A相的下降沿,B为低电平,代表正转。
        {
            encoder_count++;
        }
        EXTI_ClearITPendingBit(EXTI_Line0); // 标志位置0
    }
}
void EXTI1_IRQHandler(void)
{
    if(EXTI_GetITStatus(EXTI_Line1) ==  SET)
    {
        if(GPIO_ReadInputDataBit(GPIOB,  GPIO_Pin_0) == RESET) // B相的下降沿,A为低电平,代表反转。
        {
            encoder_count-- ;
        }
        EXTI_ClearITPendingBit(EXTI_Line1);
    }
}

 

#include "stm32f10x.h"                  // Device header
#include "delay.h"
#include "led.h"
#include "key.h"
#include "buzzer.h"
#include "light.h"
#include "oled.h"
#include "countSensor.h"
#include "encoder.h"

/*
    中断函数尽量简短快速。中断是用来处理突发事件,如果长时间在中断函数里主程序会受到严重的阻塞。
    最好不要在主函数与中断函数调用相同的函数,或者操作同一个硬件。
    在中断函数中操作变量或标志位,减少代码之间的耦合性,让各个模块之间相互独立,仅使用变量,标志位作为接口。使结构清晰,代码强健。
*/
int main (void)
{
    int16_t num ;
    OLED_Init();
    key_init();
    encoder_init();
    OLED_ShowString(1, 1, "Count:");

    while(1)
    {
        // num = get_num();
        num += get_encoder();
        OLED_ShowSignedNum(1, 7, num, 5); // 因为16bit最大值65535
    }
}

你可能感兴趣的:(STM32江协科技,stm32,单片机,嵌入式硬件)