STM32 GPIO Basic Operation: key input (+ external interrupt scanning)

(Proper noun involving more inevitable interpretation is not in place, if there is an error, please also pointed out that, thank you!)

Hardware connection is as follows:

First, scan

The idea is the main function in an endless loop through the scanning condition detection level of the port in order to determine whether the key is pressed. Relatively simple to achieve.

1. Initialize (Note C language variable declarations need to be placed at the beginning of the function)

The following is the initialization port PB5 (LED lights) code, the meaning of each statement in my blog in another article

GPIO_InitTypeDef GPIO_Init1;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

GPIO_Init1.GPIO_Pin = GPIO_Pin_5;
GPIO_Init1.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init1.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_SetBits(GPIOB, GPIO_Pin_5);                       //先熄灯

GPIO_Init(GPIOB, &GPIO_Init1);

The following is the initialization PE3 port (key) code

GPIO_InitTypeDef GPIO_Init2;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);

GPIO_Init2.GPIO_Pin = GPIO_Pin_3;           // 设置GPIO端口号为5
GPIO_Init2.GPIO_Mode = GPIO_Mode_IPU;       // 设置端口模式为输入上拉
// 设置为输入端口时不需要指定GPIO_Speed参数

GPIO_Init(GPIOE, &GPIO_Init2);

The difference between the input and the input pull-pull-down:
the pull-input (GPIO_Mode_IPU): When the port VCC via a resistor in series, so there is no input or high input port is high, a low level when the input port is low
input pulldown (GPIO_Mode_IPD): port GND through a resistor in series, so there is no input or input port is low at a low level, high level when the input port is high

When that is connected to GND from the hardware buttons and FIG, if the input port is set to pull, then release the button port is high, when the key is pressed port is low, the two states can be distinguished
if the input port is set to pull-down, then either pressed or when the key is released the total port is low, can not distinguish between two states
Similarly, if the key is connected to VCC, the port needs to be set in order to distinguish the input pulldown press / release the two states

2. Scan

Read the status of the port PE3:

GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)

The return value is the SET port is high, the return value is the RESET port of the low-potential

The following code is placed in the infinite loop to achieve the main function and lighting port scanning function PE3

while (1)
{
    if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)==SET) // 如果按键对应端口为高电平
    {
        GPIO_SetBits(GPIOB, GPIO_Pin_5);             // 熄灯(LED负极连接PB5,LED正极连接VCC,PB5高电平熄灯)
    }
    else                                             // 否则
    {
        GPIO_ResetBits(GPIOB, GPIO_Pin_5);           // 亮灯
    }
    delay_ms(10);                                    // 一些开发板例程当中提供了delay函数,需要通过delay_init()初始化后才可使用
                                                     // 若无现成delay函数,可通过一定次数的for循环来代替
}

3. Routine

code show as below:

int main(void)
{
    GPIO_InitTypeDef GPIO_Init1, GPIO_Init2;
    delay_init();

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    GPIO_Init1.GPIO_Pin = GPIO_Pin_5;
    GPIO_Init1.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init1.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_Init1);
    GPIO_SetBits(GPIOB, GPIO_Pin_5);                       //先熄灯

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
    GPIO_Init2.GPIO_Pin = GPIO_Pin_3;
    GPIO_Init2.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOE, &GPIO_Init2);
    
    delay_ms(200);

    while (1)
    {
        if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)==SET)
        {
            GPIO_SetBits(GPIOB, GPIO_Pin_5);
        }
        else
        {
            GPIO_ResetBits(GPIOB, GPIO_Pin_5);
        }
        delay_ms(10);
    }
}

Second, interrupted

0. concepts

Interrupt: the program is running, if external systems, internal systems or existing program itself event of an emergency, the processor immediately suspend the operation of current procedures, automatically transferred to the appropriate handler (interrupt service routine), after pending, then return the original program runs
in a nutshell is to trigger an event can make the jump MCU execution handler for the event, while the release button is pressed or (GPIO port level changes) can be used as an external interrupt, by writing this handler for the event so as to achieve the purpose of changing the lamp on or off state
( "events" referred to here is not a proper noun STM32 among the "event", but generally refers to the occurrence of a certain thing)

Key input using scanning idea obtained as follows:

主函数()
{
    初始化()
    死循环
    {
        如果(按键按下)
        {……}
        否则
        {……}
    }
}

The obtained using a key input interrupt roadmap is as follows:

主函数()
{
    初始化()
    其它操作()
}

中断处理函数()
{
    如果(按键按下)
    {……}
    否则
    {……}
}

Comparative understood scanning manner so that the chip can not be (hard) for other transactions

NVIC: full name "embedded vector interrupt controller", the main priority is used in many places will use (serial communication, SPI communication, timers, I C communications, real-time processing related to the control of each chip interrupted? the function will interrupt-related)

Detection full name is "External Interrupt / Event Controller", you can achieve detection of input signal rising and falling edges: EXTI (not EXIT)

1. Initialize (Note C language variable declarations need to be placed at the beginning of the function)

1.1 NVIC

Need to use initialization statement is as follows:

NVIC_InitTypeDef NVIC_I;                           //定义初始化结构体

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);    //设置整个系统的中断优先级分组

NVIC_I.NVIC_IRQChannel=EXTI3_IRQn;                 //设置初始化哪个中断
NVIC_I.NVIC_IRQChannelPreemptionPriority=0x02;     //设置中断抢占优先级
NVIC_I.NVIC_IRQChannelSubPriority=0x02;            //设置中断响应优先级(子优先级)
NVIC_I.NVIC_IRQChannelCmd=ENABLE;                  //中断使能(启动)

NVIC_Init(&NVIC_I);                                //初始化

Interrupt priority grouping, seize between the priority and sub-priority:
the STM32 family of chips which generally have a lot of interruption, and when multiple interrupts occur at the same time we need a mechanism to control the scheduling of their execution order, and therefore have a break the concept of priority. Follow the following priorities:
1. priority The smaller the number the higher the priority
2. seize the high priority interrupt will be executed first, it can also break preempt low-priority interrupt
3. When the same preemption priority in response to a high priority interrupt will be performed first, but it can not be interrupted in response to a low-priority interrupt
4. when preemption priority and in response to two priority interrupts are the same, the first interrupt generated before execution (in time order)

For example, there are three interrupts:
Interrupt 1: preemption priority 2, in response to priority 1
interrupt 2: preemption priority 3, in response to priority 0
Interrupt 3: preemption priority 2, in response to priority 0
rule 3 interrupt is an interrupt priority order 3> interrupt 1> 2 interrupt, and interrupt can interrupt interrupt 2, 3, 3 can not interrupt interrupt interrupt 1

The two types of priorities can be set to what value it? It depends on the entire system interrupt priority grouping. by

NVIC_PriorityGroupConfig();

You can set the entire system interrupt priority grouping, its parameters can be NVIC_PriorityGroup_0, NVIC_PriorityGroup_1, NVIC_PriorityGroup_2, NVIC_PriorityGroup_3, one NVIC_PriorityGroup_4. Specific relationship is as follows:
NVIC_PriorityGroup_0: preemption priority bit 0 (invalid) +4 response priority (0 to 15)
NVIC_PriorityGroup_1: preemption priority 1 bit (0 or 1) + 3 bits in response to the priority (0. 7)
NVIC_PriorityGroup_2: 2 preemption priority (0-3) + 2 in response to the priority (0 to 3)
NVIC_PriorityGroup_3: 3 preemption priority bits (0 to 7) +1 bits in response to the priority (0. 1)
NVIC_PriorityGroup_4: preemption priority bits. 4 level (0 to 15) in response to the priority bit +0 (invalid)

E.g. interrupt packet is set to 3, then all preemption priority interrupts may be set from 0 to 7, priority may be set in response to 0
Note that if a program library uses some of the secondary package (such as development board vendors routine for beginners write serial libraries, etc.), then NVIC_PriorityGroupConfig () might have been called, and this time again changes may lead to other problems

1.2 extiti

Need to use initialization statement is as follows:

EXTI_InitTypeDef EXTI_I;                           //定义初始化结构体

EXTI_I.EXTI_Line=EXTI_Line3;                       //设置初始化哪条中断/事件线
EXTI_I.EXTI_Mode = EXTI_Mode_Interrupt;            //设置为产生中断(EXTI_Mode_Event为产生事件)
EXTI_I.EXTI_Trigger = EXTI_Trigger_Falling;        //设置为下降沿触发
EXTI_I.EXTI_LineCmd = ENABLE;                      //使能

EXTI_Init(&EXTI_I);                                //初始化

Interrupt difference / events:
processing (software level) after an interrupt is generated to MCU via NVIC
event final as a pulse signal directly trigger other hardware (hardware level)
attached EXTI a block diagram of ease of understanding, blue is interrupted, red is event

EXTI, NVIC correspondence relationship with the GPIO:
shown in FIG.

Rising / falling edge:
Low High rising edge jump, high jump to a low level falling

1.3 GPIO

Initialization code scanning system with the same

GPIO_InitTypeDef GPIO_Init1, GPIO_Init2;

GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_Init1.GPIO_Pin = GPIO_Pin_5;
GPIO_Init1.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init1.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_Init1);
GPIO_SetBits(GPIOB, GPIO_Pin_5);                       //先熄灯

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
GPIO_Init2.GPIO_Pin = GPIO_Pin_3;
GPIO_Init2.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOE, &GPIO_Init2);
1.4 Other

It is not clear at present two statements role

GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);          //开启端口复用,涉及到GPIO口做外部中断时都需要这一条语句

2. The interrupt handler

And interrupt function name / event line has a corresponding relationship can be a reference to a table

void EXTI3_IRQHandler(void)
{
    if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)==SET)
    {
        GPIO_SetBits(GPIOB, GPIO_Pin_5);
    }
    else
    {
        GPIO_ResetBits(GPIOB, GPIO_Pin_5);
    }
    EXTI_ClearITPendingBit(EXTI_Line3);
}

Last EXTI_ClearITPendingBit () is used to clear the interrupt flag before they impact after the break

3. Routine

code show as below:

int main(void)
{
    GPIO_InitTypeDef GPIO_Init1, GPIO_Init2;
    NVIC_InitTypeDef NVIC_I;
    EXTI_InitTypeDef EXTI_I;

    GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
    
    NVIC_I.NVIC_IRQChannel=EXTI3_IRQn;
    NVIC_I.NVIC_IRQChannelPreemptionPriority=0x02;
    NVIC_I.NVIC_IRQChannelSubPriority=0x02;
    NVIC_I.NVIC_IRQChannelCmd=ENABLE;
    NVIC_Init(&NVIC_I);

    EXTI_I.EXTI_Line=EXTI_Line3;
    EXTI_I.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_I.EXTI_Trigger = EXTI_Trigger_Falling;
    EXTI_I.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_I);

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    GPIO_Init1.GPIO_Pin = GPIO_Pin_5;
    GPIO_Init1.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init1.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_Init1);
    GPIO_SetBits(GPIOB, GPIO_Pin_5);                       //先熄灯

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
    GPIO_Init2.GPIO_Pin = GPIO_Pin_3;
    GPIO_Init2.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOE, &GPIO_Init2);

}

void EXTI3_IRQHandler(void)
{
    if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)==SET)
    {
        GPIO_SetBits(GPIOB, GPIO_Pin_5);
    }
    else
    {
        GPIO_ResetBits(GPIOB, GPIO_Pin_5);
    }
    EXTI_ClearITPendingBit(EXTI_Line3);
}

2019.12.22

Guess you like

Origin www.cnblogs.com/wh201906/p/12079997.html