用外部中断实现四个按键控制一个七段数码管的四个位选并显示数字0~9,基于STM32F103R6
时间: 2023-12-04 10:03:52 浏览: 91
外中断(按键)控制数码管显示
4星 · 用户满意度95%
这是一道比较典型的STM32F103R6的综合应用题,需要使用外部中断和七段数码管显示技术完成。下面是代码实现的步骤:
1. 定义四个按键GPIO口和四个七段数码管位选GPIO口,并初始化为输入或输出模式;
2. 定义一个变量来存储当前的位选值,初始化为0;
3. 设置四个按键GPIO口为外部中断触发模式,当按键按下时触发中断,并在中断服务函数中更新当前的位选值;
4. 在主循环中不断地以一定的时间间隔刷新七段数码管的显示,根据当前的位选值和数字0~9的对应关系来更新七段数码管的显示。
下面是代码实现的示例:
```
#include "stm32f10x.h"
#define SEG_A GPIO_Pin_0
#define SEG_B GPIO_Pin_1
#define SEG_C GPIO_Pin_2
#define SEG_D GPIO_Pin_3
#define SEG_E GPIO_Pin_4
#define SEG_F GPIO_Pin_5
#define SEG_G GPIO_Pin_6
#define SEG_DP GPIO_Pin_7
#define DIGIT_1 GPIO_Pin_8
#define DIGIT_2 GPIO_Pin_9
#define DIGIT_3 GPIO_Pin_10
#define DIGIT_4 GPIO_Pin_11
#define KEY_1 GPIO_Pin_12
#define KEY_2 GPIO_Pin_13
#define KEY_3 GPIO_Pin_14
#define KEY_4 GPIO_Pin_15
uint8_t digit = 0;
uint8_t seg_data[10] = {
SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F, // 0
SEG_B | SEG_C, // 1
SEG_A | SEG_B | SEG_G | SEG_E | SEG_D, // 2
SEG_A | SEG_B | SEG_G | SEG_C | SEG_D, // 3
SEG_F | SEG_G | SEG_B | SEG_C, // 4
SEG_A | SEG_F | SEG_G | SEG_C | SEG_D, // 5
SEG_A | SEG_F | SEG_E | SEG_D | SEG_C | SEG_G, // 6
SEG_A | SEG_B | SEG_C, // 7
SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G,// 8
SEG_A | SEG_B | SEG_C | SEG_F | SEG_G // 9
};
void EXTI15_10_IRQHandler(void)
{
if (EXTI_GetITStatus(EXTI_Line12) != RESET) {
digit = 1;
EXTI_ClearITPendingBit(EXTI_Line12);
} else if (EXTI_GetITStatus(EXTI_Line13) != RESET) {
digit = 2;
EXTI_ClearITPendingBit(EXTI_Line13);
} else if (EXTI_GetITStatus(EXTI_Line14) != RESET) {
digit = 3;
EXTI_ClearITPendingBit(EXTI_Line14);
} else if (EXTI_GetITStatus(EXTI_Line15) != RESET) {
digit = 4;
EXTI_ClearITPendingBit(EXTI_Line15);
}
}
void GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
// 数码管位选
GPIO_InitStructure.GPIO_Pin = DIGIT_1 | DIGIT_2 | DIGIT_3 | DIGIT_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 数码管段选
GPIO_InitStructure.GPIO_Pin = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G | SEG_DP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 按键
GPIO_InitStructure.GPIO_Pin = KEY_1 | KEY_2 | KEY_3 | KEY_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 外部中断
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource12);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource13);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource15);
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line12 | EXTI_Line13 | EXTI_Line14 | EXTI_Line15;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void delay_us(uint32_t us)
{
us *= 8;
while (us--) {
__NOP();
}
}
void SEG_Update(uint8_t digit, uint8_t num)
{
GPIO_SetBits(GPIOB, DIGIT_1 | DIGIT_2 | DIGIT_3 | DIGIT_4);
GPIO_SetBits(GPIOA, SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G | SEG_DP);
switch (digit) {
case 1:
GPIO_ResetBits(GPIOB, DIGIT_1);
break;
case 2:
GPIO_ResetBits(GPIOB, DIGIT_2);
break;
case 3:
GPIO_ResetBits(GPIOB, DIGIT_3);
break;
case 4:
GPIO_ResetBits(GPIOB, DIGIT_4);
break;
default:
break;
}
GPIO_Write(GPIOA, seg_data[num]);
delay_us(100);
}
int main(void)
{
GPIO_Config();
while (1) {
SEG_Update(1, digit);
SEG_Update(2, digit + 1);
SEG_Update(3, digit + 2);
SEG_Update(4, digit + 3);
digit++;
if (digit > 6) {
digit = 0;
}
delay_us(10000);
}
}
```
在上述代码中,我们首先定义了四个按键GPIO口和四个七段数码管位选GPIO口,并初始化为输入或输出模式。然后定义了一个变量digit来存储当前的位选值,初始化为0。接着设置四个按键GPIO口为外部中断触发模式,当按键按下时触发中断,并在中断服务函数中更新当前的位选值。在主循环中不断地以一定的时间间隔刷新七段数码管的显示,根据当前的位选值和数字0~9的对应关系来更新七段数码管的显示。需要注意的是,为了保证数码管显示的稳定,我们在SEG_Update函数中添加了一个简单的延时函数delay_us,用于控制数码管显示的时间。
需要注意的是,在STM32F103R6的外部中断配置中,需要使用GPIO_EXTILineConfig函数将外部中断与GPIO口进行绑定,否则外部中断可能无法正常触发。此外,在使用外部中断时,需要在中断服务函数中调用EXTI_ClearITPendingBit函数清除中断标志位,否则中断服务函数将一直被调用。最后,为了保证数码管的显示稳定,我们在SEG_Update函数中添加了一个简单的延时函数delay_us,用于控制每个位选的显示时间,具体的延时时间可以根据具体硬件环境进行调整。
阅读全文