基于STM32CubeMX和Keil5-MDK的STM32F103C8点灯程序(纯C语言,无中断)

本文介绍了一个基于STM32CubeMX和Keil5-MDK的STM32F103C8点灯程序,通过按键控制LED灯的不同状态变化,包括单次闪烁、两秒闪烁及长按加速闪烁等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基于STM32CubeMX和Keil5-MDK的STM32F103C8点灯程序(纯C语言,无中断)

一、任务要求:

1.用按键实现按一次(按下松开)灯闪烁一次;
2.连续按两次(每次按下松开)按键之后灯的状态切换为隔两秒闪一下; 
3.长按按键(不松开)灯的闪烁速度逐渐变快,按键松开后灯长亮;

二、最后实现效果:

能有效识别按键状态,并且在三种命令之间任意切换(由每两秒闪烁切换到单击闪		烁识别率不高 = = )

三、主要思路:

检测按键状态—》改变click的值—》分别实现对“长按、单击、双击”这三种状态的辨别。(个人认为的难点)

接下来定义一下单击、双击、长按
单击:在2秒内只点击一次按键(按下,松开)
双击:在2秒内点击两次按键

首先因为程序逐句执行,所以我们的按键检测都在循环中,让程序循环执行,检测按键是否被按下
click:最重要的一个参数,通过click的值识别此时应该执行什么部分,click初始值为0,按键每按下一次click就自增一次

在理想状态下(理想状态指只进行单击,双击,长按这三种操作)click只有三种状态分别为(0,1,2)
但是考虑误操作(比如在很短时间内点击三次,等等)为了提高程序稳定性,故将范围扩大为(0,奇数,非0偶数)
“本次实验代码采用第二种,但是为了方便解释,文本中将启用第一种进行描述”click的三值分别对应程序的三种状态
(检测状态此时灯常亮,执行单击内容闪烁一次,执行双击内容灯切换为每隔2秒闪一次)

四、引脚设置

在这里插入图片描述

五、代码部分

while(1){
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 0)//HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)此函数可以读取引脚PA0的状态若为低电平返回0,高电平返回1。
{
	click++;
	time_interval = 500;
	while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 0)
	{

		HAL_Delay(time_interval);		//bug1(可能导致检测不到第二次点击)(但是此处延时不可或缺)
//如果缺少此延时函数,而可能我要实现双击,但是第一次点击之后由于没有延时我的函数会马上执行If,然而此时按键在短时间内肯定时没有抬起,所以if条件为真,执行if内部内容,识别失败。
//但是当我把延时提前后:此时按键按下进入while延时500毫秒,此时由于延时500毫秒,按键必定已经抬起,所以if为假if内部内容不执行,第一次点击识别成功
		if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 0)
		{

			click--;				//若程序执行到此处,说明此次按键为长按,由于此次按键导致的click自增应为无效 (不为单击或者双击中的任何一种)
			HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
			HAL_Delay(time_interval);
			HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);		
//(此处本应为延时所处位置)但是提前更好
			i -= 20;
			if (i <= 0)
{
click=0//重置click,防止无法退出两秒延时闪烁状态
				break;
}
		}
	}
	HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, 0);
	HAL_Delay(20);
	while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 0)
		;
}



if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 0 || click % 2)//说明一下click%2的意义:
//为什么要加入click%2这个条件呢?因为当我按下按键的时候,程序跑到的位置是随机的可能在第一部分
//(即上方检测部分)检测到按键按下:如果不添加click%2,此时如果我想双击按键,并且第一次按键在
//上方被检测到,那么此时click==1,if条件为假,if不执行,click=1,此次点击被识别为单击,识别失败
//同样当我添加click%2条件时,同上方的情况下,此时click==1,if条件为真,if执行,由于程序运行速度快,
//所以会立即进入while进行的二次按键检测,如果此刻按下按键,click自增,此时click==2,识别成功
{
	HAL_Delay(5);
	if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 0)
	{
		while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 0); //bug2(可能导致长按无法识别)
		click++;
		HAL_Delay(5);
		j = 300000;
		while (j--)
		{
			if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 0)
			{
				HAL_Delay(5);
				if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 0)
				{
					while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 0);
					click++;
				}
			}
		}
	}
}
if (click % 2)
{
	HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
	HAL_Delay(500);
	HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
	HAL_Delay(500);
	click = 0;//执行完相应程序之后click重置,为了跳出循环
}


if (!(click % 2) && click != 0)
//此函数通过死循环实现
//如果click为偶数执行if,进入死循环,并且此if是与外部检测按键状态的if并行的,
//意思就是我每次此if执行之后会回到开头检测按键状态,也就是说即使进入死循环,
//我还可以通过按键状态改变click的值,实现跳出死循环执行其他的命令,回到初始状态

{
	HAL_Delay(2000);				//bug3(延时时间可能导致程序无法检测按键状态)
	HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
}
}

Click增长的情况详解:即命令识别详解

将代码分为三个部分
1.	while检测
2.	if双击检测
3.	实现部分

(1).单击:

可能在if被检测到按键按下
在这里插入图片描述
可能在while检测到
在这里插入图片描述

  1. 双击:
    while检测、检测到到第一次点击,此时 click=1,if为真,进行二次检测检测到第二次点击
    在这里插入图片描述

    If检测、检测到第一次点击,if为真,进行二次检测检测到二次点击
    在这里插入图片描述

  2.  长按:
     进入while检测被识别
     Bug情况:在if检测被识别进入死循环语句
     while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 0);
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值