基于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檢測到
-
輕按兩下:
while檢測、檢測到到第一次點選,此時 click=1,if為真,進行二次檢測檢測到第二次點選
If檢測、檢測到第一次點選,if為真,進行二次檢測檢測到二次點選 -
長按: 進入while檢測被識别 Bug情況:在if檢測被識别進入死循環語句 while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 0);