STM32两个按键控制跑马灯的开始和停止

 
1.题目具体内容:按键控制跑马灯停止,按下按键二跑马灯停止,所有灯熄灭,再按按键一跑马灯
从头开始运行。
 
使用定时器控制跑马灯,里面有一个参数相当于开关,当参数为1时启动流水灯,当参数为其他时流水灯熄灭。
按键控制参数,达到本题要求。
 
1.LED灯宏定义 按键宏定义
#define		LED1_ON()						GPIO_ResetBits(GPIOA , GPIO_Pin_8); 			//PA8 输出低电平,使其发光
#define		LED1_OFF()					GPIO_SetBits(GPIOA , GPIO_Pin_8); 			  //PA8 输出高电平,使其灭

#define		LED2_ON()						GPIO_ResetBits(GPIOB , GPIO_Pin_1); 			//PB1 输出低电平,使其发光
#define		LED2_OFF()					GPIO_SetBits(GPIOB , GPIO_Pin_1); 			  //PB1 输出高电平,使其灭

#define		LED3_ON()						GPIO_ResetBits(GPIOA , GPIO_Pin_7); 			//PA7 输出低电平,使其发光
#define		LED3_OFF()					GPIO_SetBits(GPIOA , GPIO_Pin_7); 			  //PA7 输出高电平,使其灭

#define		LED4_ON()						GPIO_ResetBits(GPIOB , GPIO_Pin_2); 			//PB2 输出低电平,使其发光
#define		LED4_OFF()					GPIO_SetBits(GPIOB , GPIO_Pin_2); 			  //PB2 输出高电平,使其灭

#define		KEY1()							GPIO_ReadInputDataBit(GPIOB , GPIO_Pin_5)
#define		KEY2()							GPIO_ReadInputDataBit(GPIOB , GPIO_Pin_0)
#define		KEY3()							GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_6)

 

2.LED灯初始化 按键初始化 定时器初始化
void LED_Pin_Init()
{
	GPIO_InitTypeDef  GPIO_InitStructure;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB , ENABLE);	   //使能PA\PB端口时钟
		
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		     //推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		     //IO口速度为50MHz
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8;	 //LED1-->PA8 LED3-->PA7端口配置, 推挽输出
  GPIO_Init(GPIOA, &GPIO_InitStructure);	  				       //推挽输出 ,IO口速度为50MHz
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		     //推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		     //IO口速度为50MHz
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 ;	 //LED2-->PB1 , LED4-->PB2端口配置, 推挽输出
  GPIO_Init(GPIOB, &GPIO_InitStructure);	
	
	LED1_OFF();
	LED2_OFF();
	LED3_OFF();
	LED4_OFF();
}

void KEY_Pin_Init()
{
	GPIO_InitTypeDef  GPIO_InitStructure;
 	
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);	   //使能PA\PB端口时钟
		
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; 		     	 //上拉输入
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		     //IO口速度为50MHz
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_0;	 //KEY1-->PB5 KEY2-->PB0端口配置
  GPIO_Init(GPIOB, &GPIO_InitStructure);	  				       //IO口速度为50MHz
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; 		     	 //上拉输入
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		     //IO口速度为50MHz
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 ;	 						 //KEY3-->PA6端口配置
  GPIO_Init(GPIOA, &GPIO_InitStructure);	

}
//初始化TIM2控制引脚及配置其中断方式、优先级
void TIM2_Int_Init(u16 arr , u16 psc)
{
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //使能定时器2时钟

	TIM_TimeBaseStructure.TIM_Period = arr; 		//设置在下一个更新事件装入活动的自动重装载寄存器周期的值	 计数到2000为2ms
	TIM_TimeBaseStructure.TIM_Prescaler = psc; 	//设置用来作为TIMx时钟频率除数的预分频值  1Mhz的计数频率  
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; 		 //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
 

	TIM_ITConfig(TIM2 , TIM_IT_Update , ENABLE ); //使能指定的TIM2中断,允许更新中断
	
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;  //TIM2中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;  //先占优先级2级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 		//IRQ通道被使能
	NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器

	TIM_Cmd(TIM2, ENABLE);  //使能TIM2外设,开始计数					 
}

3.编写中断服务函数即开关 设定三个变量,一个是开关mode,一个是tim2_count,由于定时器是每2ms运行一次,为达到流水灯的效果,令4000ms执行一次LED灯循环;最后一个为tim2_stats,令1000ms执行一次一个灯亮起

//TIM2中断服务处理函数
void TIM2_IRQHandler()
{
	if(TIM_GetITStatus(TIM2 , TIM_IT_Update) != RESET) //检查指定的TIM2中断发生与否:TIM 中断源 
	{
		TIM_ClearITPendingBit(TIM2 , TIM_IT_Update  );  //清除TIM2的中断待处理位:TIM 中断源 
		if(mode==1)
		{
		tim2_count++;							//对2毫秒中断进行累加,累计到1000毫秒即500次,
		if(tim2_count >= 500)
		{
			tim2_count = 0;
			tim2_stats++;						//对1秒时间进行累加
		  if (tim2_stats % 4 == 1 )
			{
				LED1_ON();
				LED2_OFF();
				LED3_OFF();
				LED4_OFF();
			
			}
			else if(tim2_stats % 4 == 2)
			{
				LED1_OFF();
				LED2_ON();
				LED3_OFF();
				LED4_OFF();
			}
			else if(tim2_stats % 4 == 3)
			{
				LED1_OFF();
				LED2_OFF();
				LED3_ON();
				LED4_OFF();
			}
				else if(tim2_stats % 4 == 0)
			{
				LED1_OFF();
				LED2_OFF();
				LED3_OFF();
				LED4_ON();
			}
		}
	}
		else
		{
			  LED1_OFF();
				LED2_OFF();
				LED3_OFF();
				LED4_OFF();
		}
}
}

最后一步就是编写主函数,通过按键控制mode即控制开关

#include "stm32f10x.h"
#include "delay.h"
int main()
{
	u8 key1stat = 0;
	
	delay_init();			//调用精确延时初始化函数
	LED_Pin_Init();		//调用LED引脚控制初始化函数
	KEY_Pin_Init();
	TIM2_Int_Init(2000 , 72 - 1);		//调用定时器2初始化函数,配置计数2000,进行72预分频
	while(1)  				//无限循环,等待TIM4中断产生
	{
			if(KEY1() == 0)						//判断KEY1是否已按下
		{
			delay_ms(3);						//延时消抖
			while(KEY1() == 0);			//等待KEY1松手
			delay_ms(3);						//再次延时消抖
			mode=1;
						tim2_stats=0;
		}
		if(KEY2()==0)
		{
			mode=0;
		}
	}
}

由于本题是按下KEY1流水灯从头开始,所以不要忘了将tim2_stats清零达到重新来过的效果呀

本题感悟:

题主在写本题时曾想用主函数是流水灯,令外部中断控制流水灯,可是外部中断只能控制一次流水灯就清除标志位了,无法达到永久的效;或者是在外部中断中编写流水灯,但是当中断发生时只能执行一次流水灯也被清除标志位了。这两种方法都是使用死循环来控制流水灯。从而达不到想要的效果,因为是两个永久,流水灯永久循环,消失永久循环。而定时器可以达到通过执行时间来控制流水灯,每两毫秒执行一次中断,达到流水灯循环的效果,并且也可以永久保存mode值,直到下一次按键改变mode才会改变。

如果有可以不使用定时器的方法来解决这个题,欢迎和题主交流。

 
 
  • 4
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
可以使用STM32的GPIO模块实现两个按键控制两个LED。具体的步骤如下: 1. 配置GPIO模块的输入输出模式,将按键连接到输入引脚,将LED连接到输出引脚。 2. 初始化GPIO模块,设置输入引脚的上拉/下拉电阻。 3. 在主函数中循环读取按键的状态,如果按键被按下,则将对应的LED输出高电平,否则输出低电平。 下面是一个简单的示例代码: ```c #include "stm32f10x.h" int main(void) { // 配置GPIO模块 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; // PA0和PA1引脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入模式 GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3; // PA2和PA3引脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出模式 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 速度50MHz GPIO_Init(GPIOA, &GPIO_InitStructure); while (1) { if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)) { // 如果PA0引脚状态为高电平 GPIO_SetBits(GPIOA, GPIO_Pin_2); // 输出高电平到PA2引脚 } else { GPIO_ResetBits(GPIOA, GPIO_Pin_2); // 输出低电平到PA2引脚 } if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1)) { // 如果PA1引脚状态为高电平 GPIO_SetBits(GPIOA, GPIO_Pin_3); // 输出高电平到PA3引脚 } else { GPIO_ResetBits(GPIOA, GPIO_Pin_3); // 输出低电平到PA3引脚 } } } ``` 在这个例子中,PA0和PA1引脚连接到按键,PA2和PA3引脚连接到LED。我们使用`GPIO_ReadInputDataBit()`函数读取输入引脚的状态,如果为高电平,则使用`GPIO_SetBits()`函数输出高电平到对应的LED,否则使用`GPIO_ResetBits()`函数输出低电平。在循环中不断读取按键状态并控制LED的亮灭。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值