当前位置:网站首页>External interrupt to realize key experiment

External interrupt to realize key experiment

2022-07-07 08:58:00 A big cat 1201

author : A big cat 1201
special column :《STM32 Study 》
Maxim : You just try to , Leave the rest to time !
 Please add a picture description

describe

In the previous article control LED And buzzer button experiment It explains in detail how to pass GPIO Input mode to control LED Status of lights and buzzers . This article is also to realize the function of appeal , But the method is realized by external interrupt , That is to say 4 Each key corresponds to an external interrupt , Control a state in an interrupt program .

Overview of external interrupts

Used by benmew STM32F103ZET6 The chip has 7 Group GPIO, Each group GPIO And then there is 16 individual IO mouth , and STM32 The strength of is , Every one of it IO Both ports support the response of external interrupts , In this way, it has 112 individual IO Port can realize interrupt response , So much IO There are also ways to manage mouth .

  • The chip has 19 External interrupt line , Namely :
  • Line 0~15: Corresponding to the outside IO The input of the port is interrupted .
  • Line 16: Connect to PVD Output .
  • Line 17: Connect to RTC Alarm clock event .
  • Line 18: Connect to USB Wake Events .

This experiment only uses lines 0 To 15, That is, the interrupt line of external interrupt , other 3 Ben meow will explain in detail when using the broken wire in the root .

You can see , The external interrupt line has 16 root , and IO Oral 112 individual , So there is a mapping relationship between them :
 chart
You can see , External interrupt line and GPIO The mapping relationship between is :

  • EXIT0 Can be mapped to PA0,PB0,PC0,PD0,PE0,PF0,PG0
  • EXIT1 Can be mapped to PA1,PB1,PC1,PD1,PE1,PF1,PG1
  • EXIT2 Can be mapped to PA2,PB2,PC2,PD2,PE2,PF2,PG2
  • EXIT3 Can be mapped to PA3,PB0,PC3,PD3,PE3,PF3,PG3
  • EXIT14 Can be mapped to PA14,PB14,PC14,PD14,PE14,PF14,PG14
  • EXIT15 Can be mapped to PA15,PB15,PC15,PD15,PE15,PF15,PG15

That is to say IO The number of subscript corresponding to the port can be used as the mapping port corresponding to the external interrupt line .
Be careful :

  • An external break line can only be mapped to one IO On the mouth , such as EXIT0 Mapped to PA0 On the mouth , here PB0 Can no longer act EXIT0 Mapping port of .
  • IO After the port is used as the mapping port , It does not affect reading the IO Port data .

We know , Interrupts have interrupt service functions , Then when the interruption occurs , yes CPU How to execute the corresponding interrupt function ?

 chart
The above figure is a table of interrupt vectors , After different external interrupt lines generate interrupt requests and are responded, they will behave like the corresponding interrupt program , The entry of the program is at the corresponding vector address .

  • EXIT0 To EXIT4 this 5 Corresponding to external interrupts 5 Two interrupt service functions . After an interrupt occurs and is responded to, it will execute the corresponding interrupt service function .
  • EXIT5 To EXIT9 Share an interrupt service function . this 5 After an external interrupt occurs and is responded to, it will enter the same external interrupt service function , So you need to write the judgment code of the response in the function , Determine which interrupt .
  • EXIT10 To EXIT15 It also shares an interrupt service function . this 5 After an interrupt occurs and is responded to, it will also enter an interrupt service function .

External interrupt configuration register

External interrupt line and GPIO The mapping relationship of is realized by configuring the external interrupt configuration register , stay AFIO( Auxiliary function register ) The registers in which external interrupts are configured are 3 individual .

  1. AFIO_EXTICR1

 chart
The above figure shows the distribution and specific control of each bit .

  1. AFIO_EXTICR2

 chart
The above figure shows the distribution and specific control of each bit .

  1. AFIO_EXTICR3

 chart
The above figure shows the distribution and specific control of each bit .

ST The official also provides corresponding library functions to configure external interrupt lines and GPIO The mapping relation of

void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);

Using library functions, we don't have to configure each register one by one , The specific use of this function is demonstrated in the code process later in this article .

Experimental code

Since the external interrupt is used to realize the key , Then interrupt service function is essential , And because of the use of LED The lamp , Buzzer , Key , And serial port , Therefore, we also need the initialization functions of these hardware and serial port peripherals .

LED initialization

 chart
 chart

Through the schematic diagram, we can see LED0 Is with the PB5 Connected ,LED1 Is with the PE5 Connected .
 chart
LED0 and LED1 It is the common anode connection method , That is to say PB5 Mouth and PE5 When the port is low LED0 and LED1 bright .
The code is as follows
led.h The code in :

#ifndef __LED_H
#define __LED_H

#include "sys.h"// Bit operation header file reference 
#define LED0 PBout(5)
#define LED1 PEout(5)

// For ease of use , Directly use the hardware name to control the state of the lamp 

void LED_Init(void);// Function declaration 

#endif

led.c The code in :

#include "stm32f10x.h"// Reference top-level header file 
#include "led.h"// quote led Initialize header file 


void LED_Init()
{
    
	GPIO_InitTypeDef GPIO_InitStructe;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE,ENABLE);// take GPIOB and GPIOE Clock enable 
	
	//PB5 initialization 
	GPIO_InitStructe.GPIO_Mode=GPIO_Mode_Out_PP;// Push pull output mode 
	GPIO_InitStructe.GPIO_Pin=GPIO_Pin_5;
	GPIO_InitStructe.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStructe);
	//PE5 initialization 
	GPIO_InitStructe.GPIO_Mode=GPIO_Mode_Out_PP;// Push pull output mode 
	GPIO_InitStructe.GPIO_Pin=GPIO_Pin_5;
	GPIO_InitStructe.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOE,&GPIO_InitStructe);
	
	// The initial state is that the lights are all off 
	LED0=1;
	LED1=1;
}

Buzzer initialization

 chart
You can see , The buzzer is connected with PB8 Connected .
 chart
When PB8 When it's high , The buzzer makes a sound .
beep.h The code in :

#ifndef __BEEP_H
#define __BEEP_H

#include "sys.h"
#define beep PBout(8)

void BEEP_Init(void);

#endif

beep.c The code in :

#include "stm32f10x.h"
#include "beep.h"

void BEEP_Init()
{
    
	GPIO_InitTypeDef GPIO_InitStructe;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);// take GPIOB and GPIOE Clock enable 
	
	//PB5 initialization 
	GPIO_InitStructe.GPIO_Mode=GPIO_Mode_Out_PP;// Push pull output mode 
	GPIO_InitStructe.GPIO_Pin=GPIO_Pin_8;
	GPIO_InitStructe.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStructe);
	// The buzzer is initialized not to sound 
	beep=0;
}

Key initialization

 chart
You can see ,KEY0 And PE4 Connected to a ,KEY1 And PE3 Connected to a ,KEY2 And PE2 Connected to a .

 chart
WK_UP Keys and PA0 Connected to a .
 chart

  • KEY0 To KEY2 The other end of the is connected to the ground , When the key is pressed, it is low , So this 3 Keys should be set to pull-up input mode .
  • WK_UP Connected to high level , When the key is pressed, it is high , So this button should be set to the pull-down input mode .

key.h The code in :

#ifndef __KEY_H

#define __KEY_H
#include "stm32f10x.h"
#define KEY0 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)
#define KEY1 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)
#define KEY2 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2)
#define WK_UP GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)

#define KEY0_PRES 1
#define KEY1_PRES 2
#define KEY2_PRES 3
#define WK_UP_PRES 4

void KEY_Init(void);


#endif

key.c The code in :

#include "stm32f10x.h"
#include "key.h"
#include "delay.h"


void KEY_Init(void)
{
    
	GPIO_InitTypeDef GPIO_InitStructe;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE,ENABLE);// take GPIOA and GPIOE Clock enable 
	
	//KEY0 To KEY2 Set to pull-up input mode 
	GPIO_InitStructe.GPIO_Mode=GPIO_Mode_IPU;
	GPIO_InitStructe.GPIO_Pin=GPIO_Pin_4|GPIO_Pin_3|GPIO_Pin_2;
	GPIO_Init(GPIOE,&GPIO_InitStructe);
	
	//WK_UP Set it to the pull-down input mode 
	GPIO_InitStructe.GPIO_Mode=GPIO_Mode_IPD;
	GPIO_InitStructe.GPIO_Pin=GPIO_Pin_0;
	GPIO_Init(GPIOA,&GPIO_InitStructe);
	
	
}

Serial initialization

 chart
We can see ,USART1_TX The port multiplexing pin is PA9,USART1_RX The port multiplexing pin is PA10.
as for PB6 and PB7 Is the port remapping pin , Generally, it cannot be used , Interested friends can read this article Port reuse and remapping .
After knowing which pin the serial port is, we need to configure the serial port , Give Way CPU Know that this pin is used as a serial port .
 chart

  • Pictured above , We use full duplex mode , Need to be aligned PA9 The port is configured as push-pull multiplex output . Yes PA10 Configure as floating or pull-up input .
  • Conduct GPIOA and USART1 Clock enable
  • Serial port initialization configuration
  • Interrupt priority configuration
  • Enable receive interrupt
  • Open the serial port

After configuring the serial port, you need to write the serial port interrupt service function .
See benmew's article for the agreement of serial communication Serial port experiment —— Simple data sending and receiving .
Ben meow won't explain how to write in detail here , Go straight to the code :
usart.h The code in :

#include "sys.h"
#include "usart.h" 
#if SYSTEM_SUPPORT_OS
#include "includes.h" //ucos  Use  
#endif
#ifndef __USART_H
#define __USART_H

#include "stdio.h"
#include "sys.h"

#define USART_REC_LEN 200 // Define the maximum number of bytes received  200
#define EN_USART1_RX 1 // Can make (1)/ prohibit (0) A serial port 1 receive 
extern u8  USART_RX_BUF[USART_REC_LEN]; // Receive buffer , Maximum USART_REC_LEN Bytes . The last byte is a newline character  
extern u16 USART_RX_STA;         		// Receive status flag  
void uart_init(u32 bound);


#endif

usart.c The code in :

#if 1
#pragma import(__use_no_semihosting) 
// Support functions required by the standard library  
struct __FILE 
{
     
	int handle; 

}; 

FILE __stdout;       
// Definition _sys_exit() To avoid using semi host mode  
void _sys_exit(int x) 
{
     
	x = x; 
} 
// redefinition fputc function  
int fputc(int ch, FILE *f)
{
          
	while((USART1->SR&0X40)==0);// Cycle to send , Until it's sent  
    USART1->DR = (u8) ch;      
	return ch;
}
#endif 

/* Use microLib Methods */
 /* int fputc(int ch, FILE *f) { USART_SendData(USART1, (uint8_t) ch); while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) {} return ch; } int GetKey (void) { while (!(USART1->SR & USART_FLAG_RXNE)); return ((int)(USART1->DR & 0x1FF)); } */
 
#if EN_USART1_RX // If enabled, receive 
// A serial port 1 Interrupt service routine 
// Be careful , Read USARTx->SR Can avoid inexplicable mistakes  
u8 USART_RX_BUF[USART_REC_LEN];     // Receive buffer , Maximum USART_REC_LEN Bytes .
// Reception status 
//bit15,  Receive completion flag 
//bit14,  Received 0x0d
//bit13~0,  Number of valid bytes received 
u16 USART_RX_STA=0;       // Receive status flag  
  
void uart_init(u32 bound)
{
    
	GPIO_InitTypeDef GPIO_InitStructe;
	USART_InitTypeDef USART_InitStructe;
	NVIC_InitTypeDef NVIC_InitStructe;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);
	
	//PA9 Initialize to multiplex push-pull output , Reuse as USART1_TX
	GPIO_InitStructe.GPIO_Pin=GPIO_Pin_9;
	GPIO_InitStructe.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_InitStructe.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_Init(GPIOA,&GPIO_InitStructe);
	
	//PA10 Initialize as floating input , Reuse as USART1_RX
	GPIO_InitStructe.GPIO_Pin=GPIO_Pin_10;
	GPIO_InitStructe.GPIO_Mode=GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOA,&GPIO_InitStructe);
	
	//USART1 initialization 
	USART_InitStructe.USART_BaudRate=bound;// Baud rate 
	USART_InitStructe.USART_WordLength=USART_WordLength_8b;// The word is 8 Bytes 
	USART_InitStructe.USART_StopBits=USART_StopBits_1;// Stop bit 1 position 
	USART_InitStructe.USART_Parity=USART_Parity_No;// No parity bit 
	USART_InitStructe.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;// Receive and send 
	USART_InitStructe.USART_HardwareFlowControl=USART_HardwareFlowControl_None;// V. hardware flow control 
	USART_Init(USART1,&USART_InitStructe);
	
	// Interrupt priority initialization 
	NVIC_InitStructe.NVIC_IRQChannel=USART1_IRQn;//USART1 Channel interrupt 
	NVIC_InitStructe.NVIC_IRQChannelPreemptionPriority=3;// Preemption priority is 3
	NVIC_InitStructe.NVIC_IRQChannelSubPriority=3;// The response priority is 3
	NVIC_InitStructe.NVIC_IRQChannelCmd=ENABLE;// Channel enable 
	NVIC_Init(&NVIC_InitStructe);
	
	// Receive interrupt enable 
	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
	
	// Can make USART1
	USART_Cmd(USART1,ENABLE);
}

void USART1_IRQHandler(void)
{
    
	u8 res=0;
#if SYSTEM_SUPPORT_OS // If SYSTEM_SUPPORT_OS It's true , Support is needed OS.
	OSIntEnter();    
#endif
	// Judge whether the reception interrupt occurs 
	if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)
	{
    
		res=USART_ReceiveData(USART1);// Receive the read data 
		if((USART_RX_STA&0x8000)==0)// Whether the reception is incomplete 
		{
    
			if(USART_RX_STA&0x4000)// Did you receive it 0x0d
			{
    
				// If you receive 0x0a
				if(res!=0x0a)
					USART_RX_STA=0;// If not , Description receive error , The whole sign is clear 0
				else
					USART_RX_STA|=0x8000;// The reception is complete 
			}
			else// I haven't received 0x0d
			{
    
				// If you receive 0x0d
				if(res==0x0d)
					USART_RX_STA|=0x0400;// receive 0x0d Logo location 1
				else// Received is not 0x0d
				{
    
					// Store the received data in the array 
					USART_RX_BUF[USART_RX_STA&0x3FFF]=res;
					USART_RX_STA++;
					// If the number of data is greater than the maximum receiving length 
					if(USART_RX_STA>(USART_REC_LEN-1))
						USART_RX_STA=0;// Receive error , The flag is clear 0
				}
			}
		}
	}
#if SYSTEM_SUPPORT_OS // If SYSTEM_SUPPORT_OS It's true , Support is needed OS.
	OSIntExit();  											 
#endif
}
#endif 

External interrupt initialization

Next is the most important step , Initialization of external interrupt

  1. Make it usable GPIO mouth

Here we use the PE4,PE3,PE2,PA0 four GPIO mouth

  1. What will be used GPIO Set to input mode

  2. Can make AFIO Register clock

This register controls the mapping of interrupt lines , So it must be enabled

  1. Set the mapping relationship of the external break line
  • EXIT4 Mapping to PE4
  • EXIT3 Mapping to PE3
  • EXIT2 Mapping to PE2
  • EXIT0 Mapping to PA0
  1. External interrupt initialization
  • PE4,PE3,PE2 this 3 individual IO The port adopts the pull-up input mode , When a key is pressed , The IO The port is low
  • therefore 3 individual IO The port should be set as the falling edge to trigger the interrupt .
  • PA0 It adopts the pull-down input mode , When a key is pressed , The IO The port is high
  • therefore PA0 To set the rising edge to trigger interrupt .
  1. Interrupt priority initialization
  • The interrupt channel is EXIT0,EXIT4,EXIT3,EXIT2, altogether 4 Channels
  • The preemption priority is set to 2
  • The response priority is set to 2
  • Enable interrupt channel
  1. Write interrupt service function
  • External interrupt line 0 The corresponding is WK_UP Key interrupt , When the key is pressed, the state of the buzzer reverses .
  • External interrupt line 4 The corresponding is KEY0 Key interrupt , When the last two keys are pressed LED The state of is reversed at the same time .
  • External interrupt line 3 The corresponding is KEY1 Key interrupt , When the key is pressed LED0 The state of is reversed .
  • External interrupt line 2 The corresponding is KEY2 Key interrupt , When the key is pressed LED1 The state of is reversed .
  1. Clears the interrupt flag bit

The interrupt flag bit of the external interrupt will be set by the hardware after the interrupt occurs 1, However, the hardware will not be reset automatically after the interrupt service function is executed , So we need to manually clear the flag at the end of the interrupt service function 0.

exit.h The code in :

#ifndef __EXIT_H
#define __EXIT_H

void EXIT_Init(void);

#endif

exit.c The code in :

#include "exit.h"
#include "stm32f10x.h"
#include "led.h"
#include "beep.h"
#include "delay.h"
#include "key.h"

void EXIT_Init(void)
{
    
	EXTI_InitTypeDef EXTI_InitStructe;
	NVIC_InitTypeDef NVIC_InitStructe;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE|RCC_APB2Periph_GPIOA,ENABLE);// Can make GPIOA and GPIOE Group clock 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);// Can make AFIO The clock 
	
	KEY_Init();
	
	// External interrupt line 4 initialization 
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4);//exit4
	EXTI_InitStructe.EXTI_Line=EXTI_Line4;// trunk 4
	EXTI_InitStructe.EXTI_LineCmd=ENABLE;
	EXTI_InitStructe.EXTI_Mode=EXTI_Mode_Interrupt;// The mode is interrupt 
	EXTI_InitStructe.EXTI_Trigger=EXTI_Trigger_Falling;// Falling edge trigger mode 
	EXTI_Init(&EXTI_InitStructe);
	
	// External interrupt line 3 initialization 
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);//exit3
	EXTI_InitStructe.EXTI_Line=EXTI_Line3;// trunk 3
	EXTI_Init(&EXTI_InitStructe);
	
	// External interrupt line 2 initialization 
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2);//exit2
	EXTI_InitStructe.EXTI_Line=EXTI_Line2;// trunk 2
	EXTI_Init(&EXTI_InitStructe);
	
	// External interrupt line 0 initialization 
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);//exit0
	EXTI_InitStructe.EXTI_Line=EXTI_Line0;// trunk 0
	EXTI_InitStructe.EXTI_Trigger=EXTI_Trigger_Rising;// Rising edge trigger mode 
	EXTI_Init(&EXTI_InitStructe);
	
	// Interrupt initialization 
	NVIC_InitStructe.NVIC_IRQChannel=EXTI0_IRQn;// Channel external channel 0
	NVIC_InitStructe.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructe.NVIC_IRQChannelPreemptionPriority=0x02;// The preemption priority is set to 2
	NVIC_InitStructe.NVIC_IRQChannelSubPriority=0x00;// The response priority is set to 2
	
	NVIC_Init(&NVIC_InitStructe);
	NVIC_InitStructe.NVIC_IRQChannel=EXTI4_IRQn;// Channel external channel 4
	NVIC_InitStructe.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructe.NVIC_IRQChannelPreemptionPriority=0x02;// The preemption priority is set to 2
	NVIC_InitStructe.NVIC_IRQChannelSubPriority=0x01;// The response priority is set to 2
	NVIC_Init(&NVIC_InitStructe);
	NVIC_InitStructe.NVIC_IRQChannel=EXTI3_IRQn;// Channel external channel 3
	NVIC_InitStructe.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructe.NVIC_IRQChannelPreemptionPriority=0x02;// The preemption priority is set to 2
	NVIC_InitStructe.NVIC_IRQChannelSubPriority=0x02;// The response priority is set to 2
	NVIC_Init(&NVIC_InitStructe);
	NVIC_InitStructe.NVIC_IRQChannel=EXTI2_IRQn;// Channel external channel 2
	NVIC_InitStructe.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructe.NVIC_IRQChannelPreemptionPriority=0x02;// The preemption priority is set to 2
	NVIC_InitStructe.NVIC_IRQChannelSubPriority=0x03;// The response priority is set to 2
	NVIC_Init(&NVIC_InitStructe);
}

void EXTI0_IRQHandler(void)
{
    
	delay_ms(10);// Delay chattering 
	// Determine if it is WK_UP Key pressed 
	if(WK_UP==1)
	{
    
		beep=!beep;// The buzzer state is reversed 
	}
	EXTI_ClearITPendingBit(EXTI_Line0);
}

void EXTI4_IRQHandler(void)
{
    
	delay_ms(10);// Delay chattering 
	// Determine if it is KEY0 Key pressed 
	if(KEY0==0)
	{
    
		LED0=!LED0;
		LED1=!LED1;// Two LED The light state is reversed at the same time 
	}
	EXTI_ClearITPendingBit(EXTI_Line4);
}

void EXTI3_IRQHandler(void)
{
    
	delay_ms(10);// Delay chattering 
	// Determine if it is KEY1 Key pressed 
	if(KEY1==0)
	{
    
		LED0=!LED0;//LED0 The state is reversed 
	}
	EXTI_ClearITPendingBit(EXTI_Line3);
}

void EXTI2_IRQHandler(void)
{
    
	delay_ms(10);// Delay chattering 
	// Determine if it is KEY2 Key pressed 
	if(KEY2==0)
	{
    
		LED1=!LED1;//LED1 The state is reversed 
	}
	EXTI_ClearITPendingBit(EXTI_Line2);
}

Effect display

It takes a long time to upload videos , The effect of this experiment is similar to control LED Lamp and buzzer experiment The effect is the same , The serial port part of the experiment has the same effect as Serial port experiment —— Simple data sending and receiving The effect is the same .
If you want to see the experimental results, you can move to the two articles mentioned above .

原网站

版权声明
本文为[A big cat 1201]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/188/202207070626298326.html