藍橋杯嵌入式省一教程:(三)按鍵掃描與定時器中斷

在第一講中曾經提到,GPIO有輸入輸出兩種模式。在點亮LED時,我們已經使用了GPIO輸出模式,在按鍵識別中,我們將要使用GPIO輸入模式。首先來看看按鍵的電路原理圖(下圖在選手資源數據包——CT117E-M4產品手冊中):

5a14e3d2439242e7837513f285762649.png

其中,B1~B4為4個不同的按鍵,它們通過PB0、PB1、PB2、PA0四個端口以上拉電阻的方式連接到單片機中。當按鍵松開時,PB0等端口處于高電平狀態;當按鍵按下后,端口處于低電平狀態。因此,我們可以把這些端口設置為GPIO輸入+上拉電阻(pull-up)模式,通過讀取其電平的高低狀態來判斷按鍵是否被按下。(所謂上下拉電阻,其實決定的就是GPIO輸入端口斷路時的初始電平狀態,有關介紹可以自行搜索)

例如,需要判斷B1是否被按下時,我們只需要判斷PB0的電平狀態:

if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0) == GPIO_PIN_RESET)//讀取PB0的電平狀態,判斷是否為低電平
{/* 執行任務 */
}

在主循環中,利用按鍵掃描,我們就可以通過不同的按鍵操作來執行不一樣的任務,例如:

while (1)
{//B1按下,點亮LD1和LD2if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET){LED_On(LD1|LD2);}//B2按下,點亮LD3和LD4if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_RESET){LED_On(LD3|LD4);}//B3按下,點亮LD5和LD6if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) == GPIO_PIN_RESET){LED_On(LD5|LD6);}//B4按下,點亮LD7和LD8if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET){LED_On(LD7|LD8);}
}

不僅是按鍵,GPIO輸入模式與輸出模式一樣,均廣泛應用于各種需要讀取外部電路電平的場景。有關GPIO輸入的函數如下:

/*** @brief  Read the specified input port pin.* @param  GPIOx where x can be (A..G) to select the GPIO peripheral for STM32G4xx family* @param  GPIO_Pin specifies the port bit to read.*         This parameter can be any combination of GPIO_PIN_x where x can be (0..15).* @retval The input port pin value.*/
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)

然而,這種方法在實際中并不常用。可以想象,除了判斷按鍵是否按下以外,一個嵌入式系統一定還有其他的許多任務需要執行。倘若在主循環中一直判斷按鍵是否被按下,則會占用CPU,效率低下,同時也可能因為在執行其他任務,響應不及時。因此,我們更常用的是采用中斷的方式來判斷按鍵是否被按下。

先來普及一下什么是中斷。我們知道,CPU是按照順序依次執行主函數中的指令的。中斷是指打斷CPU當前正在執行的指令,跳到中斷程序中執行,隨后跳會主函數原來的位置繼續執行原指令。例如在生活中,我們的主程序是寫代碼,這時電話鈴響,我們不得不停下手中的工作,進入中斷——接電話,接完電話后又繼續回到寫代碼的工作中。正如打斷我們的有可能是電話鈴聲,有可能是門鈴聲,也有可能是短信鈴聲等等,打斷CPU的中斷方式也是多種多樣的,如GPIO外部中斷、定時器中斷、定時器捕獲中斷等等……

考慮到比賽中對按鍵的判斷涉及到長短按,我們在考慮程序執行效率而采用中斷的同時,要考慮判斷長短按的方法,這就涉及到按鍵按下的時間問題。在單片機中,與時間有關的問題,都是通過定時器來實現的。因此,下面我們來介紹定時器中斷

先來介紹一下與定時器有關的概念。在單片機中,有一個晶振(石英晶體振蕩器),它通常決定了單片機的時鐘頻率。通過對時鐘的分頻,可以得到許許多多的時鐘源。不同的硬件通過采用不同的時鐘源,再對其進行分頻,就得到了獨屬于這個硬件自己的時鐘頻率,定時器亦是如此。

參照官方例程(LCD的例程),我們按如下步驟配置時鐘樹:

(1)開啟外部高速時鐘

cb8dc1038b1546b88dc5c1b41c516b6e.png

(2)勾選HSE,將時鐘頻率設置為80MHz后按回車

9078d69cf972485a9e2ad26f543bfed5.png

(3)所得到的定時器頻率即可以在上圖右側圓圈處查看

這樣我們就得到了時鐘頻率為80MHz的定時器。

下面我們來開啟定時器中斷。我們設置TIM4如下:

86bc4ddd2d654419a32ea6b54841d70e.png

其中,定時器頻率按照如下公式計算:(具體原理請自行搜索)

eq?f%3D%5Cfrac%7Bf_%7B0%7D%7D%7B%5Cleft%20%28Prescaler+1%20%5Cright%20%29%5Cleft%20%28%20Counter%20Period+1%20%5Cright%20%29%7D%3D%5Cfrac%7B80%2C000%2C000%7D%7B80%5Ctimes%2010000%7D%3D100Hz

f0為時鐘頻率80MHz,Prescaler為預分頻系數,Counter Period為計數周期。這樣我們就把TIM4定時器的頻率設置為了100Hz,即周期為0.01s。最后,只需要打開中斷開關,就完成了定時器中斷的配置。

535b9bad5fed426eab77001ec3f2b3a9.png

在Cube中設置好后,想要使用定時器中斷,還要在主函數初始化時開啟定時器中斷(在此處是開啟TIM4的定時器中斷)

HAL_TIM_Base_Start_IT(&htim4);    //開啟TIM4的基本(Base)功能(定時)中斷(IT(InTerrupt))

然后編寫定時器中斷函數(注意:函數名和形參均是固定的,不能修改!!!可參照下圖尋找)

b1cf0f581f7d4138b9873108f1b1f9bb.png

?7f0688959f1549148ced2f462da3fb9c.png

0fa20f8f98754da0966acc3fb6c29f03.png

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)    //定時(Period)中斷(Elapsed)回調(Callback)函數,回調即從主程序中調到中斷程序中
{if (htim->Instance == TIM4)    //如果是TIM4定時器觸發的中斷{//B1按下,點亮LD1和LD2if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET){LED_On(LD1|LD2);}//B2按下,點亮LD3和LD4if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_RESET){LED_On(LD3|LD4);}//B3按下,點亮LD5和LD6if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) == GPIO_PIN_RESET){LED_On(LD5|LD6);}//B4按下,點亮LD7和LD8if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET){LED_On(LD7|LD8);}}
}

這樣,每當時間過去了0.01s,CPU就會進入定時中斷回調函數中,運行我們預先寫好的中斷程序(在此處是讀取按鍵端口的電平,隨后執行相應任務),即定時按鍵掃描,而不是一直循環掃描按鍵是否按下,這樣就為CPU節省下了大量的時間,大大提高了程序的運行效率。

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/40720.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/40720.shtml
英文地址,請注明出處:http://en.pswp.cn/news/40720.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Android CCodec (二十) CCodec Native服務實現分析

1、C2解碼服務registerAsService注冊流程 google實現CCodec的vendor默認解碼服務代碼路徑是在frameworks/av/media/codec2/hidl/services/vendor.cpp中,而其注冊的是HIDL服務,本文就對HIDL服務注冊做簡要分析。首先看下vendor.cpp中的代碼注冊流程。 int main(int /* argc *…

高等數學教材重難點題型總結(三)微分中值定理和導數的應用

第三章,微分中值定理的證明題等,非常重要,需要牢牢掌握 1.證明中值定理對某函數在給定區間上的正確性 2.與中值定理有關的證明題 3.微分中值定理應用于求證不等式 4.洛必達法則求極限 5.洛必達的經典錯誤反例 6.按某項實現多項式冪展開 7.求帶…

以 Java NIO 的角度理解 Netty

文章目錄 前言Java NIO 工作原理Selector 的創建ServerSocketChannel 的創建ServerSocketChannel 注冊 Selector對事件的處理總結 前言 上篇文章《Netty 入門指南》主要涵蓋了 Netty 的入門知識,包括 Netty 的發展歷程、核心功能與組件,并且通過實例演示…

rabbitmq的發布確認

生產者將信道設置成 confirm 模式,一旦信道進入 confirm 模式, 所有在該信道上面發布的 消息都將會被指派一個唯一的 ID (從 1 開始),一旦消息被投遞到所有匹配的隊列之后,broker 就會發送一個確認給生產者(包含消息的唯一 ID)&…

AI巨浪下,數據技術如何驅動智能未來?

引言 數據技術是大數據時代的核心驅動力,也是推動各行各業數字化轉型和智能化升級的關鍵因素。隨著云計算、人工智能、區塊鏈等新興技術的不斷發展和融合,數據技術也呈現出多模態、混合處理、自動化管理等新的趨勢和特點。 8 月 19 日(周六&…

域名和ip的關系

域名和ip的關系 一:什么是域名 域名,簡稱域名、網域,是由一串用點分隔的名字組成的上某一臺計算機或計算機組的名稱,用于在數據傳輸時標識 計算機的電子方位(有時也指地理位置)。網域名稱系統,有時也簡稱為域名…

【寶藏系列】嵌入式 C 語言代碼優化技巧【超詳細版】

【寶藏系列】嵌入式 C 語言代碼優化技巧【超詳細版】 文章目錄 【寶藏系列】嵌入式 C 語言代碼優化技巧【超詳細版】前言整形數除法和取余數合并除法和取余數通過2的冪次進行除法和取余數取模的一種替代方法使用數組下標全局變量使用別名變量的生命周期分割變量類型局部變量指針…

Centos下的tcpdump抓包用法

先查一下是否安裝, 無的話裝一下 (版本低的用yum install) : rpm -qa tcpdump dnf install tcpdump 1. 列出能抓包的網卡: tcpdump -D | --list-interfaces 2. 在eth0網卡上抓來源為10.1.1.1 的包, 只抓一個包 (-n這里是不解析DNS) : tcpdump -i eth0 -n src 10.1.1.1 -…

STM32 F103C8T6學習筆記3:串口配置—串口收發—自定義Printf函數

今日學習使用STM32 C8T6的串口,我們在經過學習筆記2的總結歸納可知,STM32 C8T6最小系統板上有三路串口,如下圖: 今日我們就著手學習如何配置開通這些串口進行收發,這里不講串口通信概念與基礎,可以自行網上…

一文讀懂HTML

文章目錄 HTML的歷史HTML的作用HTML的基本語言 HTML的歷史 HTML(HyperText Markup Language)的歷史可以追溯到20世紀90年代早期,它是互聯網發展的重要里程碑之一。以下是HTML的歷史概述: 早期階段(1980年代末 - 1990年…

FLatten Transformer 簡化版Transformer

今天在找論文時,看到一篇比較新奇的論文,在這里跟大家分享一下,希望可以給一些人提供一些思路。雖然現在Transformer 比較火,在分割上面也應用的比較多,但是我一直不喜歡用,其中一個原因是結構太復雜了&…

golang官方限流器rate包實踐

日常開發中,對于某些接口有請求頻率的限制。比如登錄的接口、發送短信的接口、秒殺商品的接口等等。 官方的golang.org/x/time/rate包中實現了令牌桶的算法。 封裝限流器可以將ip、手機號這種的作為限流器組的標識。 接下來就是實例化限流器和獲取令牌函數的實現…

C++:模擬實現list及迭代器類模板優化方法

文章目錄 迭代器模擬實現 本篇模擬實現簡單的list和一些其他注意的點 迭代器 如下所示是利用拷貝構造將一個鏈表中的數據挪動到另外一個鏈表中&#xff0c;構造兩個相同的鏈表 list(const list<T>& lt) {emptyinit();for (auto e : lt){push_back(e);} }void test_…

運動路徑規劃,ROS發布期望運動軌跡

目錄 一、Python實現&#xff08;推薦方法&#xff09; 1.1代碼cubic_spline_path.py 1.2使用方法 二、C實現 參考博客 想讓機器人/智能車無人駕駛&#xff0c;要有期望路徑&#xff0c;最簡單的是一條直線&#xff0c;或者是一條光滑曲線。 生成路徑的方法有兩種&#xf…

【網絡編程(二)】NIO快速入門

NIO Java NIO 三大核心組件 Buffer&#xff08;緩沖區&#xff09;&#xff1a;每個客戶端連接都會對應一個Buffer&#xff0c;讀寫數據通過緩沖區讀寫。Channel&#xff08;通道&#xff09;&#xff1a;每個channel用于連接Buffer和Selector&#xff0c;通道可以進行雙向讀…

Linux下C++開發

Linux下C開發 Linux 系統介紹 簡介 Linux屬于多用戶多任務操作系統&#xff0c;而Windows屬于單用戶多任務操作系統Linux一切皆文件目錄結構 bin 存儲二進制可執行文件dev 存放的是外接設備&#xff0c;例如磁盤&#xff0c;光盤等。在其中的外接設備是不能直接被使用的&…

Redis數據庫的可視化工具AnotherRedisDesktopManager使用+抖音直播小玩法實踐

一、它是什么 Another Redis DeskTop Manager 是一個開源項目&#xff0c;提供了以可視化的方式管理 Redis 的功能&#xff0c;可供免費下載安裝&#xff0c;也可以在此基礎上進行二次開發&#xff0c;主要特點有&#xff1a; 支持 Windows 平臺和 MacOS 平臺 支持查詢 Key、…

2023-08-17力扣每日一題

鏈接&#xff1a; 1444. 切披薩的方案數 題意&#xff1a; 給定一個矩陣&#xff0c;其中含有多個蘋果&#xff0c;需要切割k-1次,每次可以切割多行/多列&#xff0c;需要保證切割兩個部分都有蘋果&#xff0c;移除靠上/靠右的部分&#xff0c;對留下部分進行后續的切割&…

QT中的按鈕控件Buttons介紹

目錄 Buttons 按鈕控件 1、常用屬性介紹 2、按鈕介紹 2.1QPushButton 普通按鈕 2.2QtoolButton 工具按鈕 2.3Radio Button單選按鈕 2.4CheckButton復選按鈕 2.5Commam Link Button命令鏈接按鈕 2.6Dialog Button Box命令鏈接按鈕 Buttons 按鈕控件 在Qt里&#xff0c;…

Viobot開機指南

0.前言 本篇旨在讓每個拿到Viobot設備的用戶都能夠第一時間測試它的效果&#xff0c;以及將設備配置到自己的環境下面。 1.上電 首先&#xff0c;我們先要把設備接上電源線和網線&#xff0c;最簡單的方式就是網線直連電腦。 電源選用12V1.5A設備自帶的電源即可。 2.配置網…