用stm32的中断方式,通过两个按键分别控制流水灯的方向和亮灭
时间: 2023-06-15 13:05:01 浏览: 203
好的,我可以为您提供一个简单的示例代码,您可以根据您的具体硬件环境和需求进行修改和优化。
首先,您需要定义一些宏和变量来控制流水灯的状态和方向:
```c
#include "stm32f10x.h"
#define LED1_PIN GPIO_Pin_8
#define LED2_PIN GPIO_Pin_9
#define LED3_PIN GPIO_Pin_10
#define LED4_PIN GPIO_Pin_11
#define KEY1_PIN GPIO_Pin_0
#define KEY2_PIN GPIO_Pin_1
#define KEY1_PRESSED (GPIO_ReadInputDataBit(GPIOA, KEY1_PIN) == Bit_RESET)
#define KEY2_PRESSED (GPIO_ReadInputDataBit(GPIOA, KEY2_PIN) == Bit_RESET)
enum {LEFT, RIGHT} direction = LEFT;
uint8_t leds = 0x01;
```
其中,`LED1_PIN` 到 `LED4_PIN` 定义了流水灯使用的4个LED的引脚号码,`KEY1_PIN` 和 `KEY2_PIN` 定义了控制流水灯方向和亮灭的两个按键的引脚号码。`KEY1_PRESSED` 和 `KEY2_PRESSED` 判断按键是否被按下,`direction` 记录当前流水灯的方向,`leds` 记录当前流水灯的状态。
接下来,我们需要初始化GPIO和中断控制器:
```c
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/* LED pins configuration */
GPIO_InitStructure.GPIO_Pin = LED1_PIN | LED2_PIN | LED3_PIN | LED4_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Key pins configuration */
GPIO_InitStructure.GPIO_Pin = KEY1_PIN | KEY2_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void EXTI_Configuration(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable AFIO clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
/* Connect EXTI Line0 and Line1 to PA0 and PA1 pins */
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource1);
/* Configure EXTI Line0 and Line1 */
EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
/* Enable and set EXTI Line0 and Line1 Interrupt to the lowest priority */
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
```
在 `GPIO_Configuration` 函数中,我们初始化了GPIO引脚,将LED引脚设置为输出模式,将按键引脚设置为带上拉电阻的输入模式。在 `EXTI_Configuration` 函数中,我们初始化了中断控制器,将按键引脚连接到外部中断线0和1,并设置下降沿触发中断。同时,我们还将外部中断0和1的中断优先级设置为最低。
然后,我们需要编写中断服务函数:
```c
void EXTI0_IRQHandler(void)
{
if (KEY1_PRESSED) {
direction = LEFT;
}
EXTI_ClearITPendingBit(EXTI_Line0);
}
void EXTI1_IRQHandler(void)
{
if (KEY2_PRESSED) {
leds = 0x00;
}
EXTI_ClearITPendingBit(EXTI_Line1);
}
```
在 `EXTI0_IRQHandler` 函数中,我们检测到按键1被按下,将流水灯的方向设置为左移。在 `EXTI1_IRQHandler` 函数中,我们检测到按键2被按下,将流水灯的状态设置为全灭。
最后,我们编写主函数,使用定时器中断驱动流水灯的移动:
```c
int main(void)
{
GPIO_Configuration();
EXTI_Configuration();
/* Enable TIM2 clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* TIM2 Configuration */
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = 999;
TIM_TimeBaseStructure.TIM_Prescaler = 7199;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
/* TIM2 Interrupt Configuration */
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM2, ENABLE);
while(1);
}
void TIM2_IRQHandler(void)
{
switch (direction) {
case LEFT:
leds <<= 1;
if (leds == 0x00) leds = 0x01;
break;
case RIGHT:
leds >>= 1;
if (leds == 0x00) leds = 0x08;
break;
}
GPIO_Write(GPIOA, leds << 8);
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
```
在主函数中,我们初始化了定时器2,并将其设置为1ms的中断周期。在 `TIM2_IRQHandler` 函数中,我们根据当前的流水灯方向,移动流水灯的状态,并将状态写入LED引脚。
这样,您就可以通过按键控制流水灯的方向和亮灭了。需要注意的是,由于我们使用的是轮询方式,在按键被按下和中断服务函数被执行之间可能会有一定的时间延迟。如果您需要更加精确的响应时间,可以考虑使用DMA或者硬件定时器来处理输入事件。