控制LED燈設備

本章分別使用C庫和系統調用的文件操作方式控制開發板的LED燈,展示如何在應用層通過系統提供的設備文件控制相關硬件。

本章的示例代碼目錄為:base_code/linux_app/led/sys_class_leds。

9.1.?LED子系統

在Linux系統中,絕大多數硬件設備都有非常成熟的驅動框架,驅動工程師使用這些框架添加與板子相關的硬件支持,建立硬件與Linux內核的聯系,內核再通過統一文件系統接口呈現給用戶,用戶通過對應的設備文件控制硬件。

對于LED設備,Linux提供了LED子系統驅動框架,在Linux內核源碼中的“Documentation/leds/leds-class.txt”有相關的描述,它實現了一個leds類,用戶層通過sysfs文件系統對LED進行控制。

9.1.1.?LED設備目錄

使用了LED子系統驅動的設備,會被展現在/sys/class/leds目錄下,可在主機和開發板使用如下命令查看,命令的輸出可能會因為硬件環境不同而不一樣:

 123456789
10
11
#在主機或ARM板的終端上執行如下命令:
ls /sys/class/leds/#根據具體的目錄內容繼續查看:#在主機上有input2::capslock目錄,可在主機執行如下命令查看
ls /sys/class/leds/input2::capslock#在開發板上有cpu目錄,可在開發板上執行如下命令查看ls /sys/class/leds/cpu

如下圖

未找到圖片02|

未找到圖片03|

上圖可看到,示例中的Ubuntu主機和開發板/sys/class/leds下包含了以LED設備名 字命名的目錄,如“input2::capslock”、“input2::numlock”和“blue”、“cpu”等LED燈,這 些目錄對應的具體LED燈如下表所示。

表 /sys/class/leds下目錄對應的設備

/sys/class/leds下的目錄

對應的LED燈設備

input2::capslock

鍵盤大寫鎖定指示燈(input后的數字編號可能不同)

input2::numlock

鍵盤數字鍵盤指示燈(input后的數字編號可能不同)

input2::scrolllock

鍵盤ScrollLock指示燈(input后的數字編號可能不同)

cpu

開發板的心跳燈

red

Pro開發板RGB燈的紅色,Mini開發板的用戶燈

green

Pro開發板RGB燈的綠色,Mini開發板的用戶燈

blue

Pro開發板RGB燈的藍色,Mini開發板的用戶燈

mmc0:

SD卡指示燈(出廠鏡像默認沒有啟用)

9.1.2.?LED設備屬性

上圖中,在具體的LED目錄下又包含brightness、max_brightness、trigger等文件,這些文件包含了LED設備的屬性和控制接口。

  • max_brightness文件:表示LED燈的最大亮度值。

  • brightness文件:表示當前LED燈的亮度值,它的可取 值范圍為[0~max_brightness],一些LED設備不支持多級亮度,直接以非0值來 表示LED為點亮狀態,0值表示滅狀態。

  • trigger文件:則指示了LED燈的觸發方式,查看該文件的內容時,該文件會 列出它的所有可用觸方式,而當前使用的觸發方式會以“[]”符號括起。常見的觸 發方式如下表所示。

表 trigger常見的觸發方式

觸發方式

說明

none

無觸發方式

disk-activity

硬盤活動

nand-disk

nand flash活動

mtd

mtd設備活動

timer

定時器

heartbeat

系統心跳

9.2.?控制LED實驗(C庫函數)

在《命令行點燈和檢測按鍵》章節中,我們演示了使用echo命令修改設備文件,實際上也可以使用gedit、Vim等編輯器進 行修改,修改時注意用戶權限即可。既然設備是以文件形式提供的,那么自然也可以使用C庫函數 或系統調用的方式讀寫文件,達到控制設備的目的。

9.2.1.?實驗代碼分析

本小節的示例代碼目錄為:led/sys_class_leds/c_stdio。

本小節先演示使用C庫函數控制LED,具體如下所示。

通過C庫函數控制LED(base_code/linux_app/led/sys_class_leds/c_stdio/sources/main.c文件)

 123456789
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>//ARM 開發板LED設備的路徑
#define RLED_DEV_PATH "/sys/class/leds/red/brightness"
#define GLED_DEV_PATH "/sys/class/leds/green/brightness"
#define BLED_DEV_PATH "/sys/class/leds/blue/brightness"//Ubuntu主機LED設備的路徑,具體請根據自己的主機LED設備修改
// #define RLED_DEV_PATH "/sys/class/leds/input2::capslock/brightness"
// #define GLED_DEV_PATH "/sys/class/leds/input2::numlock/brightness"
// #define BLED_DEV_PATH "/sys/class/leds/input2::scrolllock/brightness"int main(int argc, char *argv[])
{FILE *r_fd, *g_fd, *b_fd;printf("This is the led demo\n");//獲取紅燈的設備文件描述符r_fd = fopen(RLED_DEV_PATH, "w");if(r_fd < 0){printf("Fail to Open %s device\n", RLED_DEV_PATH);exit(1);}//獲取綠燈的設備文件描述符g_fd = fopen(GLED_DEV_PATH, "w");if(g_fd < 0){printf("Fail to Open %s device\n", GLED_DEV_PATH);exit(1);}//獲取藍燈的設備文件描述符b_fd = fopen(BLED_DEV_PATH, "w");if(b_fd < 0){printf("Fail to Open %s device\n", BLED_DEV_PATH);exit(1);}while(1){//紅燈亮fwrite("255",3,1,r_fd);fflush(r_fd);//延時1ssleep(1);//紅燈滅fwrite("0",1,1,r_fd);fflush(r_fd);//綠燈亮fwrite("255",3,1,g_fd);fflush(g_fd);//延時1ssleep(1);//綠燈滅fwrite("0",1,1,g_fd);fflush(g_fd);//藍燈亮fwrite("255",3,1,b_fd);fflush(b_fd);//延時1ssleep(1);//藍燈亮fwrite("0",1,1,b_fd);fflush(b_fd);}
}

可以發現,這個控制LED燈的過程就是一個普通的文件寫入流程:

  • 第5~13行:定義了三盞LED燈的brightness文件路徑。配套的程序默認使用 開發板RGB燈的路徑,如果要在Ubuntu主機上測試請根據自己主機上的設備文件修改10~13行的內容。

  • 第18~41行:使用fopen庫函數,以“w”的寫模式打開了三盞LED的brightness文件,并獲得文件描述符。

  • 第43~70行:在循環中分別對三盞燈寫入“255”和“0”的字符串來控制LED燈的亮 度,寫入后調用了fflush庫函數要求立刻把緩沖區的內容寫入到文件上。

本代碼有兩處值得注意的地方:

如果是普通文件,按代碼while循環的執行流程,運行一段時間后,由于多次 寫入,文件中的內容應該為“255025502550255”這樣的字符串,但對于此 處的brightness設備文件,它的最終內容只是“255”或“0”,而不是像普通 文件那樣記錄了一連串前面輸入的字符。這是因為在LED的設備驅動層中 ,brightness文件就相當于一個函數的參數接口,每次對文件執行寫入操 作時,會觸發驅動代碼以這次寫入的內容作為參數,修改LED燈的亮度;而每次讀 取操作時,則觸發驅動代碼更新當前LED燈亮度值到brightness文件,所以brightness始終 是一個0~255的亮度值,而不是“255025502550255”這樣的字符串。特別地, 如果在一次寫入操作中,直接寫入“0255025502550”這樣的 字符串,驅動層會把它當成數字255025502550,而該數字大于最大亮度值,所以它最終會以255的 亮度控制LED燈,若此時讀取brightness文件,也會發現它的值確實是255。關于這些細節, 在學習了LED子系統框架后查看驅動源碼可更好地了解。

另一處要注意的是代碼中調用fwrite函數寫入內容時,它可能只是把內容保存 到了C庫的緩沖區,并沒有執行真正的系統調用write函數把內容寫入到設備文件,這種情況下LED燈 的狀態是不會被改變的,代碼中在fwrite函數后調用了fflush要求立刻把緩沖區的內容寫入到文件,確保 執行了相應的操作。在實驗時可以嘗試把代碼中的fflush都注釋掉, 這種情況下有極大的幾率是無法正常改變LED燈狀態的。

如果不考慮操作的時間開銷,其實控制硬件更推薦的做法是,每次控制LED燈都使用fopen—fwrite—fclose的 流程,這樣就不需要考慮flseek、fflush的問題了。當然,我們最推崇的還是下一小節直接通過 系統調用來控制硬件的方式。

9.2.2.?編譯及測試

本實驗使用的Makefile由上一章節修改而來,修改了最終的可執行文件名為led_demo,以及C源 文件目錄改為了main.c文件所在的sources,其它方面沒有差異。

9.2.2.1.?x86架構

本工程的main.c實驗代碼使用的設備文件默認是開發板 上的RGB燈,在Ubuntu主機上并沒有這樣的設備,如果想嘗試在主機上使用, 可以根據自己Ubuntu主機上存的LED設備修改代碼中的LED路徑,然后使用make直接編譯測試。

1
2
3
4
5
6
7
#在主機的實驗代碼Makefile目錄下編譯
#默認編譯x86平臺的程序
make
#運行需要root權限,要使用sudo運行
#運行需要root權限,要使用sudo運行
sudo ./build_x86/led_demo
#程序運行后終端會輸出提示,相應的LED燈設備狀態會改變
9.2.2.2.?ARM架構

對于ARM架構的程序,可使用如下步驟進行編譯:

1
2
3
#在主機的實驗代碼Makefile目錄下編譯
#編譯arm平臺的程序
make ARCH=arm

編譯后生成的ARM平臺程序為build_arm/led_demo,使用網絡文件系統共享至開 發板,在開發板的終端上測試即可。

如下圖:

未找到圖片09|

程序執行后終端會有輸出,開發板上的三盞用戶LED燈也會輪流閃爍。

9.3.?控制LED實驗(系統調用)

由于使用C庫的文件操作函數存在緩沖機制,使用它來控制硬件時存在不 確定性,所以我們更喜歡直接以系統調用來控制硬件設備。

9.3.1.?實驗代碼分析

本小節的示例代碼目錄為:led/sys_class_leds/c_systemcall。

本小節通過系統調用的文件操作方式控制LED,具體如下所示。

通過系統調用控制LED(base_code/linux_app/led/sys_class_leds/c_systemcall/sources/main.c文件)

 123456789
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>//ARM 開發板LED設備的路徑
#define RLED_DEV_PATH "/sys/class/leds/red/brightness"
#define GLED_DEV_PATH "/sys/class/leds/green/brightness"
#define BLED_DEV_PATH "/sys/class/leds/blue/brightness"//Ubuntu主機LED設備的路徑,具體請根據自己的主機LED設備修改
// #define RLED_DEV_PATH "/sys/class/leds/input2::capslock/brightness"
// #define GLED_DEV_PATH "/sys/class/leds/input2::numlock/brightness"
// #define BLED_DEV_PATH "/sys/class/leds/input2::scrolllock/brightness"int main(int argc, char *argv[])
{int res = 0;int r_fd, g_fd, b_fd;printf("This is the led demo\n");//獲取紅燈的設備文件描述符r_fd = open(RLED_DEV_PATH, O_WRONLY);if(r_fd < 0){printf("Fail to Open %s device\n", RLED_DEV_PATH);exit(1);}//獲取綠燈的設備文件描述符g_fd = open(GLED_DEV_PATH, O_WRONLY);if(g_fd < 0){printf("Fail to Open %s device\n", GLED_DEV_PATH);exit(1);}//獲取藍燈的設備文件描述符b_fd = open(BLED_DEV_PATH, O_WRONLY);if(b_fd < 0){printf("Fail to Open %s device\n", BLED_DEV_PATH);exit(1);}while(1){//紅燈亮write(r_fd, "255", 3);//延時1ssleep(1);//紅燈滅write(r_fd, "0", 1);//綠燈亮write(g_fd, "255", 3);//延時1ssleep(1);//綠燈滅write(g_fd, "0", 1);//藍燈亮write(b_fd, "255", 3);//延時1ssleep(1);//藍燈亮write(b_fd, "0", 1);}
}

本實驗代碼與上一小節使用C庫函數操作的控制流程完全一樣,只是把C庫的文件操作 替換成了系統調用的文件操作方式,特別之處在于這種方式不需要調用fflush之類的 函數確保緩沖區的內容被寫出,而且系統調用也不存在類似這樣操作的函數。

相對C庫函數的操作方式,通過系統調用更加簡單直接,而且這種與設備文件聯系比較 緊密的應用,C庫函數兼容性好的優點也沒有用武之地,所以在編寫這類應用通常直接使用系統調用的方式。

9.3.2.?編譯及測試

本實驗使用的Makefile與上一小節的完全一樣,不再分析。

本實驗的x86和arm架構的編譯、測試步驟也與上一小節完全一樣,注意切換到對應的工程路徑即可。

對于ARM架構的程序,可使用如下步驟進行編譯:

1
2
3
#在主機的實驗代碼Makefile目錄下編譯
#編譯arm平臺的程序
make ARCH=arm

編譯后生成的ARM平臺程序為build_arm/led_demo,使用網絡文件系統共享至開發 板,在開發板的終端上測試即可。

如下圖:

未找到圖片10|

程序執行后終端會有輸出,開發板上的三盞用戶LED燈也會輪流閃爍,實驗現象 與使用C庫函數操作方式是一樣的。

Next??Previous

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

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

相關文章

SpringBoot學習(上) , SpringBoot項目的創建(IDEA2024版本)

目錄 1. SpringBoot介紹 SpringBoot特點 2. SpringBoot入門 2.1 創建SpringBoot項目 Spring Initialize 第一步: 選擇創建項目 第二步: 選擇起步依賴 第三步: 查看啟動類 2.2 springboot父項目 2.3 測試案例 2.3.1 數據庫 2.3.2 生成代碼 1. SpringBoot介紹 Spring B…

在 Ubuntu 中配置 Samba 實現「特定用戶可寫,其他用戶只讀」的共享目錄

需求目標 所有認證用戶可訪問 Samba 共享目錄 /path/to/home&#xff1b;**僅特定用戶&#xff08;如 developer&#xff09;**擁有寫權限&#xff1b;其他用戶僅允許讀取&#xff1b;禁止匿名訪問。 配置步驟 1. 設置文件系統權限 將目錄 /home3/guest 的所有權設為 develo…

ENSP-OSPF綜合實驗

AR4中通過ospf獲取的其他區域路由信息&#xff0c;并且通過路由匯總后簡化路由信息 實現全網通&#xff0c;以及單向重發布&#xff0c;以及通過缺省雙向訪問&#xff0c; 通過stub簡化過濾四類五類lsa&#xff0c;簡化ospf路由信息 通過nssa簡化ospf信息 區域匯總簡化R4路由信…

linux(centos)聯網情況下部署

nginx部署 1.linux(centos)聯網情況下部署 1.下載nginx所需依賴 # 安裝開發工具組&#xff08;若未安裝&#xff09; sudo yum groupinstall "Development Tools"# 安裝 OpenSSL 開發包 sudo yum install openssl-devel# 安裝 PCRE 開發包 sudo yum install pcre-…

LeetCode 1550.存在連續三個奇數的數組:遍歷

【LetMeFly】1550.存在連續三個奇數的數組&#xff1a;遍歷 力扣題目鏈接&#xff1a;https://leetcode.cn/problems/three-consecutive-odds/ 給你一個整數數組 arr&#xff0c;請你判斷數組中是否存在連續三個元素都是奇數的情況&#xff1a;如果存在&#xff0c;請返回 tr…

Android Framework學習四:init進程實現

文章目錄 init流程簡介init源碼執行順序執行順序 init進程的具體工作事項掛載文件系統設置 SELinuxSecondStageMaininit.rc啟動zygote和serviceManager進程的重要性serviceManager工作原理 Framework學習之系列文章 init流程簡介 下面圖片主要圍繞 Android 系統中init進程的運…

HTTP/3展望、我應該遷移到HTTP/2嗎

1. HTTP/3展望 HTTP/3 基于 QUIC 協議&#xff0c;完全解決了“隊頭阻塞”問題&#xff0c;弱網環境下的表現會優于 HTTP/2&#xff1b;QUIC 是一個新的傳輸層協議&#xff0c;建立在 UDP 之上&#xff0c;實現了可靠傳輸&#xff1b;QUIC 內含了 TLS1.3&#xff0c;只能加密通…

【大模型面試每日一題】Day 15:流水線并行的Bubble問題及其緩解方法

【大模型面試每日一題】Day 15&#xff1a;流水線并行的Bubble問題及其緩解方法 &#x1f4cc; 題目重現 &#x1f31f;&#x1f31f; 面試官&#xff1a;解釋流水線并行&#xff08;Pipeline Parallelism&#xff09;的bubble問題及其緩解方法。 #mermaid-svg-Uz7WGsO8akW5F…

Windows環境下maven的安裝與配置

1.檢查JAVA_HOME環境變量 Maven是使用java開發的&#xff0c;所以必須知道當前系統環境中的JDK的安裝目錄。 搜索欄直接輸入“cmd” 或者 WinR 輸入cmd 在打開的終端窗口輸入“echo %JAVA_HOME”&#xff0c;就可以看到jdk的位置了。 如果沒有的話&#xff0c;請參考我的文章&a…

Kubernetes 集群部署應用

部署 Nginx 應用 命令行的方式 1. 創建 deployment 控制器的 pod # --imagenginx&#xff1a;這個會從 docker.io 中拉取&#xff0c;這個網站拉不下來 # kubectl create deployment mynginx --imagenginx# 使用國內鏡像源拉取 kubectl create deployment mynginx --imaged…

如何使用依賴注入來實現依賴倒置原則?

依賴注入(Dependency Injection, DI)是實現依賴倒置原則(DIP)的具體技術手段,它通過將依賴對象的創建和管理交給外部容器,從而實現高層模塊與低層模塊的解耦。下面從原理、實現方式、框架應用及最佳實踐四個方面詳細解析: 一、依賴倒置原則(DIP)的核心思想 高層模塊不…

python使用AES進行加密和解密

如果需要加密和解密功能,可以使用AES算法。以下是使用Python實現AES加密和解密的示例: from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad from Crypto.Random import get_random_bytesdef aes_encrypt(data,

SaaS場快訂首頁的前端搭建【持續更新】

文章目錄 一、創建頁面二、配置路由三、寫接口文件&#xff08;api&#xff09;1.定位的接口函數&#xff08;騰訊地圖api&#xff09;實現代碼&#xff1a; 2.獲取場館分類的數據3.獲取附近場館列表的數據 四、開發首頁頁面1.頂部區域2.搜索框3.場館分類4.附近場館列表 五、難…

深入解析 MQTT 協議:物聯網通信的基石

在當今物聯網蓬勃發展的時代&#xff0c;設備之間高效、可靠的通信變得至關重要。MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;協議&#xff0c;作為一種輕量級的消息傳輸協議&#xff0c;正逐漸成為物聯網通信的基石&#xff0c;廣泛應用于各種場景中。 …

在Python中計算函數耗時并超時自動退出

更多內容請見: python3案例和總結-專欄介紹和目錄 文章目錄 方法1:使用裝飾器結合信號模塊(僅Unix-like系統)方法2:使用多線程(跨平臺解決方案)方法3:使用concurrent.futures(Python 3.2+)方法4:使用 multiprocessing + Process(跨平臺)?方法5:使用 time 手動計…

理解c++中explicit關鍵字的作用

理解c中explicit關鍵字的作用 explicit 關鍵字的作用是防止構造函數被隱式調用&#xff0c;從而避免意外的類型轉換 #include <iostream> class Vec3 { public://構造函數沒有被explicit修飾Vec3(float value): x(value), y(value), z(value){}Vec3(float val1, float …

不止是UI庫:React如何重塑前端開發范式?

React&#xff1a;引領現代前端開發的聲明式UI庫 在當今快速發展的前端世界&#xff0c;React以其聲明式、組件化和高效的特性&#xff0c;穩坐頭把交椅&#xff0c;成為構建交互式用戶界面的首選JavaScript庫。本文將帶你快速了解React的核心魅力、主要優勢以及生態發展&…

理解 Token 索引 vs 字符位置

以下是對“理解 Token 索引與字符位置的區別”的內容整理&#xff0c;條理清晰&#xff0c;結構完整&#xff0c;保持技術細節&#xff0c;方便閱讀&#xff0c;無多余解釋&#xff1a; &#x1f50d; 理解 Token 索引 vs 字符位置 文本分塊方法中返回的索引是 token 索引&…

《異常鏈機制詳解:如何優雅地傳遞Java中的錯誤信息?》

大家好呀&#xff01;&#x1f44b; 作為一名Java開發者&#xff0c;相信你一定見過各種奇奇怪怪的異常報錯。但有沒有遇到過這樣的情況&#xff1a;明明只調用了一個方法&#xff0c;卻看到異常信息像俄羅斯套娃一樣一層層展開&#xff1f;&#x1f914; 這就是我們今天要講的…

vector 常見用法及模擬

文章目錄 1. vector的介紹與使用1.1 vector的構造1.2 vector iterator 的使用1.3 有關大小和容量的操作1.4 vector 增刪查改1.5 vector 迭代器失效問題&#xff08;重點&#xff09;1.6 vector 中二維數組的使用 2. vector 的模擬實現2.1 拷貝構造和賦值重載的現代寫法2.2 memc…