天天看點

基于STM32CubeMX和Keil5-MDK的STM32F103C8點燈程式(純C語言,無中斷)

基于STM32CubeMX和Keil5-MDK的STM32F103C8點燈程式(純C語言,無中斷)

一、任務要求:

1.用按鍵實作按一次(按下松開)燈閃爍一次;
2.連續按兩次(每次按下松開)按鍵之後燈的狀态切換為隔兩秒閃一下; 
3.長按按鍵(不松開)燈的閃爍速度逐漸變快,按鍵松開後燈長亮;
           

二、最後實作效果:

能有效識别按鍵狀态,并且在三種指令之間任意切換(由每兩秒閃爍切換到單擊閃		爍識别率不高 = = )
           

三、主要思路:

檢測按鍵狀态—》改變click的值—》分别實作對“長按、單擊、輕按兩下”這三種狀态的辨識。(個人認為的難點)

接下來定義一下單擊、輕按兩下、長按
單擊:在2秒内隻點選一次按鍵(按下,松開)
輕按兩下:在2秒内點選兩次按鍵

首先因為程式逐句執行,是以我們的按鍵檢測都在循環中,讓程式循環執行,檢測按鍵是否被按下
click:最重要的一個參數,通過click的值識别此時應該執行什麼部分,click初始值為0,按鍵每按下一次click就自增一次

在理想狀态下(理想狀态指隻進行單擊,輕按兩下,長按這三種操作)click隻有三種狀态分别為(0,1,2)
但是考慮誤操作(比如在很短時間内點選三次,等等)為了提高程式穩定性,故将範圍擴大為(0,奇數,非0偶數)
“本次實驗代碼采用第二種,但是為了友善解釋,文本中将啟用第一種進行描述”click的三值分别對應程式的三種狀态
(檢測狀态此時燈常亮,執行單擊内容閃爍一次,執行輕按兩下内容燈切換為每隔2秒閃一次)
           

四、引腳設定

基于STM32CubeMX和Keil5-MDK的STM32F103C8點燈程式(純C語言,無中斷)

五、代碼部分

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被檢測到按鍵按下

基于STM32CubeMX和Keil5-MDK的STM32F103C8點燈程式(純C語言,無中斷)

可能在while檢測到

基于STM32CubeMX和Keil5-MDK的STM32F103C8點燈程式(純C語言,無中斷)
  1. 輕按兩下:

    while檢測、檢測到到第一次點選,此時 click=1,if為真,進行二次檢測檢測到第二次點選

    基于STM32CubeMX和Keil5-MDK的STM32F103C8點燈程式(純C語言,無中斷)
    If檢測、檢測到第一次點選,if為真,進行二次檢測檢測到二次點選
    基于STM32CubeMX和Keil5-MDK的STM32F103C8點燈程式(純C語言,無中斷)
  2. 長按:
     進入while檢測被識别
     Bug情況:在if檢測被識别進入死循環語句
     while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 0);
               

繼續閱讀