GPID和LED
筆記源自《朱老師物聯網大講堂》
《1.4.ARM裸機第四部分-GPIO和LED》
第一部分、章節目錄
1.4.1.裸機實驗體驗之usb啟動配合dnw工具下載
1.4.2.裸機實驗體驗之SD卡下載
1.4.3.自己動手安裝交叉編譯工具鏈1
1.4.4.自己動手安裝交叉編譯工具鏈2
1.4.5.Makefile大俠隆重登場
1.4.6.mkv210_image.c文件詳解1
1.4.7.mkv210_image.c文件詳解2
1.4.8.一步步點亮LED1_硬件工作原理及原理圖查閱
1.4.9.一步步點亮LED2_數據手冊查閱及相關寄存器瀏覽
1.4.10.一步步點亮LED3_從零開始手寫匯編點亮LED
1.4.11.一步步點亮LED4_使用位運算實現復雜點亮要求
1.4.12.一步步點亮LED5_匯編編寫延時函數并實現LED閃爍效果
1.4.13.一步步點亮LED6_再難一點的流水燈效果
1.4.14.反匯編工具objdump的使用簡介
第二部分、章節介紹
1.4.1.裸機實驗體驗之usb啟動配合dnw工具下載
本節的主要目的是學會從usb啟動,然后使用dnw工具下載裸機程序bin文件到開發板內部SRAM執行。學完本節要求大家能夠使用usb啟動方式進行裸機程序調試,以方便后面測試自己寫的代碼(本節會提供我編譯好的led.bin)。
1.4.2.裸機實驗體驗之SD卡下載
本節的主要目的是學會設置開發板從SD2啟動(需要事先將板載SD0通道的iNand上的bootloader破壞掉),并且學會在Windows中使用燒錄軟件、linux中使用dd命令2種方式來制作啟動SD卡。學完本節要求大家能夠使用SD卡啟動方式進行裸機程序的調試,以方便后面測試自己寫的代碼(本節會提供我編譯好的led.bin)。
1.4.3.自己動手安裝交叉編譯工具鏈1
本節首先介紹linux中裝軟件和windows中的不同,然后手把手教大家從零開始自己動手安裝交叉編譯工具鏈并作測試。
1.4.4.自己動手安裝交叉編譯工具鏈2
本節接上節講解如何將安裝的交叉編譯工具鏈導出到環境變量,并且為工具鏈制作arm-linux-符號鏈接。
1.4.5.Makefile大俠隆重登場
本節給大家引入Makefile,并且ubuntu環境下簡單介紹Makefile的書寫,目標、依賴等基本概念,最后分析了我們在裸機程序中使用到的Makefile。本節學完要求大家理解Makefile的基本用法,會自己根據需要修改Makefile。
1.4.6.mkv210_image.c文件詳解1
本節回顧第三部分中講到的S5PV210啟動知識,并且分析SD卡啟動時頭信息的技術要求,然后引入mkv210_image.c文件并作簡單分析。
1.4.7.mkv210_image.c文件詳解2
本節接上節繼續詳細分析mkv210_image.c文件的技術細節,目的是使大家深入理解本文件中C程序的工作原理和實現技巧。
1.4.8.一步步點亮LED1_硬件工作原理及原理圖查閱
本節從LED工作原理講起,通過查閱原理圖分析點亮LED的原理和方法。
1.4.9.一步步點亮LED2_數據手冊查閱及相關寄存器瀏覽
本節接上節內容,查閱SoC數據手冊中GPIO寄存器部分,找到板子上LED對應的GPIO并分析操作方法。
1.4.10.一步步點亮LED3_從零開始手寫匯編點亮LED
本節開始寫我們第一個匯編程序,從零開始用最少的代碼點亮LED,并且使用之前講過的Makefile編譯,然后使用之前實踐過的下載方法下載運行測試。至此,本章點亮LED的目標已經實現。
1.4.11.一步步點亮LED4_使用位運算實現復雜點亮要求
本節以上節的匯編代碼為基礎,進行必要修改,使用位運算的技巧來實現一些復雜的電燈要求(譬如隔一個亮一個)。學完本節要求大家對位運算有一定掌握,并基本掌握使用位運算來操作SoC寄存器
1.4.12.一步步點亮LED5_匯編編寫延時函數并實現LED閃爍效果
本節接上節并繼續復雜化。引入匯編編寫的延時函數,并通過延時達到LED閃爍顯示的效果。本節學習的目的是加深大家對匯編編程的理解,學會用匯編來寫函數并調用之,為以后編寫復雜匯編程序打基礎。
1.4.13.一步步點亮LED6_再難一點的流水燈效果
本節是點亮LED的最后一節了,實現的效果是流水燈(跑馬燈)。有了以上章節的學習,本節任務應該不難實現。
1.4.14.反匯編工具objdump的使用簡介
本節介紹交叉編譯工具鏈中的反匯編工具objdump。該工具是我們后面理解和分析鏈接地址、鏈接腳本的利器,在這里給大家先認識下,方便以后引入使用。
第三部分、隨堂記錄
1.4.1.裸機實驗體驗之usb啟動配合dnw工具下載
1.4.1.1、背景知識介紹
回顧S5PV210的啟動方式,必須將OM5打到VCC,才能從USB啟動。
S5PV210的啟動過程:開機時先執行內部的iROM中的BL0,然后BL0做了一系列的初始化后,再讀取外部OMpin的設置來確定用戶選擇了從哪里啟動。當檢測到我們設置的是USB啟動時,S5PV210就會從USB OTG接口試圖連接主機進行下載啟動。
1.4.1.2、dnw工具介紹
dnw是一個軟件,是三星公司編寫的,這個軟件的功能是通過USB線連接開發板和電腦主機,然后從主機下載文件鏡像到開發板中去燒錄系統。
dnw軟件使用注意1:dnw是需要裝usb驅動的,驅動在“X210光盤資料\A盤\tools\USB驅動”目錄中
dnw軟件使用注意2:dnw使用時通過usb線下載,所以一定要插USB線。
dnw軟件使用注意3:dnw下載時需要設置dnw下載內存地址。在dnw軟件的菜單“Configuration”中設置
Download Address為0xd0020010,確認即可。
1.4.1.3、dnw驅動安裝
X210開發板使用了軟開關,但是我們這里還沒到操作系統沒去處理開關,所以在整個裸機實驗中必須手工按下POWER鍵才能保持開機,只要手一抬起來就關機了····
dnw驅動裝好的標志是:開發板開機從usb啟動后,設備管理器中顯示已經安裝的設備,并且關鍵是dnw工具中USB:OK
1.4.1.4、裸機程序下載地址設置
從usb啟動做裸機實驗時,因為不需要16字節的校驗頭,所以直接下載到0xd0020010
1.4.1.5、usb啟動裸機實驗總結
usb啟動方式主要是用來調試程序的,其實分析S5PV210即可知道,我們這里是把裸機程序當作BL1來使用了。
擴充知識:Win7 X64版本驅動安裝非常麻煩,因為微軟啟用了USB設備驅動簽名政策。
1.4.2.裸機實驗體驗之SD卡下載
1.4.2.1、背景知識
一般情況下,用USB下載來調試裸機程序比較方便;但是有時候電腦使用dnw會頻繁藍屏,這時候用SD卡下載調試是不錯選擇。
把OM5打開GND,以從SD通道啟動。
從SD啟動時會先從iNand(SD0)啟動執行,當iNand啟動做校驗和時失敗才會轉為啟動SD2。而我們做裸機實驗時是通過SD2來提供裸機程序鏡像的,因此需要先破壞內部iNand的uboot才可以強迫開發板從SD2啟動去執行我們的裸機程序。
1.4.2.2、擦除開發板iNand中的uboot的方法
在linux和android系統下,擦除uboot的方法:
busybox dd if=/dev/zero of=/dev/block/mmcblk0 bs=512 seek=1 count=1 conv=sync
sync
在uboot底下如何擦除uboot:movi write u-boot 0x30000000
1.4.2.2、Windows下制作啟動SD卡
方法等同于我們第三部分講過的SD卡刷機時的操作
1.4.2.3、linux下制作啟動SD卡
后面章節再演示。
總結:SD卡啟動和usb啟動優劣勢對比:如果你的電腦本身支持usb啟動下載而且不藍屏,建議以后做實驗用usb下載調試;
1.4.3.自己動手安裝交叉編譯工具鏈1
1.4.3.1、Windows中裝軟件的特點
Windows中裝軟件使用安裝包,安裝包解壓后有2種情況:一種是一個安裝文件(.exe .msi),雙擊進行安裝,下一步直到安裝完畢。安裝完畢后會在桌面上生成快捷方式,我們平時使用快捷方式來啟動這些程序;另一種是所謂的綠色軟件、免安裝軟件。這種不用安裝,直接解壓開里面就有exe可以直接雙擊執行。
1.4.3.2、linux中裝軟件的特點
linux中安裝軟件比windows中復雜。linux中安裝軟件一般有以下幾種方法:
第一種:在線安裝。譬如ubuntu中使用apt-get install vim來安裝vim軟件。
第二種:自己下載安裝包來安裝。這種方式的缺陷就是你不知道你下載的安裝包和你的系統是否匹配。
第三種:最裝逼的一種方式,就是源代碼安裝。
總結:我們安裝交叉編譯工具鏈(arm-linux-gcc)實際采用第二種安裝方式。
1.4.3.3、交叉編譯工具鏈的選擇
我們選擇交叉編譯工具鏈的原則:和我們所使用的目標平臺(給哪款SoC編程)盡量去匹配。譬如我們開發S5PV210的程序就是用arm-2009q3這個版本,因為三星官方在開發S5pv210時就使用這個版本的交叉編譯工具鏈,這樣可以最大限度的避免稀奇古怪的問題出現。
1.4.3.4、交叉編譯工具鏈的安裝
步驟1:打開虛擬機,在/usr/local/下創建/usr/local/arm文件夾
步驟2:先將安裝包從Windows中弄到linux中去。可以用共享文件夾,也可以用Samba,也可以cuteftp。
步驟3:解壓。tar -jxvf arm-2009q3.tar.bz2
到此相當于程序已經安裝完畢,真正的應用程序安裝在/usr/local/arm/arm-2009q3/bin目錄下
注:linux中的目錄管理方法。技術角度來講,linux中所有目錄性質都是一樣的,所以技術角度來講我們把軟件安裝到哪里都行。但是因為如果胡亂放置,將來程序可能不好找。所以久而久之大家就總結了一個文件放置的一般定義,譬如說/bin目錄放置一些系統自帶的用戶使用的應用程序,/sbin目錄下存放的是系統自帶的系統管理方面的應用程序。
那我們裝軟件放在哪里?一般都在/usr目錄下。我們安裝arm-linux-gcc,就在/usr/local/底下創建一個arm文件夾,然后裝到里面。
1.4.3.5、安裝后的測試
到真正的應用程序的安裝目錄下(也就是/usr/local/arm/arm-2009q3/bin),去執行arm-linux-gcc -v
執行方法是:./arm-none-linux-gnueabi-gcc -v
執行后可以得到一長串輸出,其中有“gcc version 4.4.1 ”字樣,即表示安裝成功。
1.4.4.自己動手安裝交叉編譯工具鏈2
1.4.3.1、環境變量的意義
環境變量就是操作系統的全局變量。每一個環境變量對操作系統來說都是唯一的,名字和所代表的意義都是唯一的。linux系統可以有很多個環境變量。其中有一部分是linux系統自帶的,還有一些是我們自己來擴充的。我們這里涉及到的一個環境變量是
PATH。PATH這個環境變量是系統自帶的,它的含義就是系統在查找可執行程序時會搜索的路徑范圍。
1.4.3.2、將工具鏈導出到環境變量
export PATH=/usr/local/arm/arm-2009q3/bin:PATH在一個終端中執行以上命令后,該終端中就可以直接使用arm?linux?gcc了,但是只要關掉這個終端再另外打開一個立馬就不行了。原因是我們本次終端中執行時的操作只是針對本終端,以后再打開的終端并未被執行過這個命令所以沒導出。解決方案是在/.bashrc中,添加exportPATH=/usr/local/arm/arm?2009q3/bin:PATH 在一個終端中執行以上命令后,該終端中就可以直接使用arm-linux-gcc了,但是只要關掉這個終端再另外打開一個立馬就不行了。原因是我們本次終端中執行時的操作只是針對本終端,以后再打開的終端并未被執行過這個命令所以沒導出。 解決方案是在~/.bashrc中,添加export PATH=/usr/local/arm/arm-2009q3/bin:PATH在一個終端中執行以上命令后,該終端中就可以直接使用arm?linux?gcc了,但是只要關掉這個終端再另外打開一個立馬就不行了。原因是我們本次終端中執行時的操作只是針對本終端,以后再打開的終端并未被執行過這個命令所以沒導出。解決方案是在?/.bashrc中,添加exportPATH=/usr/local/arm/arm?2009q3/bin:PATH 即可。
注意:我們導出這個環境變量是在當前用戶,如果你登錄時在其他用戶下是沒用的。
1.4.3.3、為工具鏈創建arm-linux-xxx符號鏈接
ln arm-none-linux-gnueabi-addr2line -s arm-linux-addr2line
1.4.5.Makefile大俠隆重登場
1.4.5.1、為什么需要Makefile
Makefile是用來管理工程的。
在一個正式的軟件項目中,由很多個.c和.h文件構成,此時如果直接在命令行編譯,就會像這樣:gcc a.c b.c c.c d.c e.c f.c g.c -o exe 每次編譯都要輸入一堆東西很麻煩,這個問題嚴重影響工作效率,怎么辦?Makefile來解決
1.4.5.2、一個簡單的Makefile示例Y
見光盤下載文件夾下面的 隨堂代碼/1.4.5/Makefile1和Makefile2
1.4.5.3、Makefile中的一些基本概念
目標:目標定格寫,后面是冒號(冒號后面是依賴)
依賴:依賴是用來產生目標的原材料。
命令:命令前面一定是Tab,不能是定格,也不能說多個空格。命令就是要生成那個目標需要做的動作。
1.4.5.4、Makefile的基本工作原理
其一,當我們執行 make xx 的時候,Makefile會自動執行xx這個目標下面的命令語句。
其二,當我們make xx的時候,是否執行命令是取決于依賴的。依賴如果成立就會執行命令,否則不執行。
其三,我們直接執行make 和make 第一個目標 效果是一樣的。(第一個目標其實就是默認目標)
1.4.5.5、ARM裸機中用到的Makefile介紹
1.4.5.6、進一步學習Makefile的資料
我們學習Makefile的思路就是:先學會基本的概念和應用,先理解Makefile的概念和使用方法、工作原理。先自己會寫簡單的Makefile來管理工程。一般先學到這里就可以了,更深入的內容可以隨同稍后的課程一起來學習,我們講到課程的時候會再次提及并且逐步深入。
對于我們有一定基礎的同學,同時還有時間,可以深入學習Makefile,看《跟我一起學Makefile》(作者:陳皓)
1.4.6.mkv210_image.c文件詳解1
2.4.6.1、mkv210_image.c的使用演示
裸機程序中的Makefile(實際上真正的項目的Makefile都是這樣的)是把程序的編譯和鏈接過程分開的。(平時我們用gcc a.c -o exe這種方式來編譯時,實際上把編譯和鏈接過程一步完成了。在內部實際上編譯和鏈接永遠是分開獨立進行的,編譯要使用編譯器gcc,鏈接要使用鏈接器ld)
鏈接器得到led.elf其實就是我們的可執行程序,(如果是在操作系統下,這個led.elf就可以執行了)但是在嵌入式裸機中我們需要的是可以燒寫的文件(可燒寫的文件就叫鏡像image),因此我們需要用這個led.elf為原材料來制作鏡像,制作工具是交叉編譯工具鏈中的arm-linux-objcopy
我們使用arm-linux-objdump工具進行反編譯(反匯編),反匯編其實就是把編譯后的elf格式的可執行程序給反過來的到對應的匯編程序,的到它的匯編源代碼。我們使用反匯編主要是用來學習,見本部分最后一節。
mkv210_image.c這個程序其實最終不是在開發板上執行的,而是在主機linux(就是用來執行make對整個項目進行編譯的那個機器)中執行的,因此編譯這個程序用gcc而不是用arm-linux-gcc。這個.c文件編譯后得到一個可執行程序mkmini210,目的是通過執行這個mkmini210程序而由led.bin得到210.bin。(210.bin是通過SD卡啟動時的裸機鏡像,這個鏡像需要由led.bin來加工的到,加工的具體方法和原理要看mkv210_image.c)
1.4.6.2、背景知識:S5PV210的啟動過程回顧
分析啟動過程可知;210啟動后先執行內部iROM中的BL0,BL0執行完后會根據OMpin的配置選擇一個外部設備來啟動(有很多,我們實際使用的有2個:usb啟動和SD卡啟動)。在usb啟動時內部BL0讀取到BL1后不做校驗,直接從BL1的實質內部0xd0020010開始執行,因此usb啟動的景象led.bin不需要頭信息,因此我們從usb啟動時直接將鏡像下載到0xd0020010去執行即可,不管頭信息了;從SD啟動時,BL0會首先讀取sd卡得到完整的鏡像(完整指的是led.bin和16字節的頭),然后BL0會自己根據你的實際鏡像(指led.bin)來計算一個校驗和checksum,然后和你完整鏡像的頭部中的checksum來比對。如果對應則執行BL1,如果不對應則啟動失敗(會轉入執行2st啟動,即SD2啟動。如果這里已經是2st啟動了,這里校驗通不過就死定了)。
1.4.6.3、mkv210_image.c的作用:為BL1添加校驗頭
我們編譯鏈接時只得到了led.bin,這個210.bin的得到和交叉編譯工具鏈是完全無關的。由led.bin得到210.bin的過程是三星的S5PV210所特有的,因此需要我們自己去完成,為此我們寫了mkv210_image.c來完成。
1.4.6.4、整個程序工作流分析
整個程序中首先申請一個16KB大小的buffer,然后把所有內容按照各自的位置填充進去,最終把填充好的buffer寫入到一個文件(名叫210.bin)就形成了我們想要的鏡像。
1.4.7.mkv210_image.c文件詳解2
1.4.7.1、代碼詳解
第1步:檢驗用戶傳參是不是3個。
第2步:分配16K Bbuffer并且填充為0.
第3步:·········
1.4.7.2、main函數兩個形參的作用
main函數接收2個形參:argc和argv。
argc是用戶(通過命令行來)執行這個程序時,實際傳遞的參數個數。注意這個個數是包含程序執行本身的
argv是一個字符串數組,這個數組中存儲的字符串就是一個個的傳參。
譬如我們執行程序時使用./mkx210 led.bin 210.bin
則argc = 3
則argv[0] = “./mkx210” argv[1] = led.bin argv[2] = 210.bin
1.4.7.3、glibc讀寫文件接口
linux中要讀取一個文件,可以使用fopen打開文件,fread讀取文件,讀完之后fclose關閉文件。
要寫文件用fwrite來寫。這些函數是glibc的庫函數,在linux中用man 3 可以查找。
如果你本身就知道這些函數的用法,只是記不起來可以man查找;如果你本身根本就不會用這些接口,建議先去baidu。
1.4.7.4、校驗和的計算方法
算法:校驗和其實就是需要校驗的內存區域中,所有內存中的內容按照字節為單位來進行相加,最終相加的和極為校驗和。
實現時大家要注意指針的類型為char *
1.4.8.一步步點亮LED1_硬件工作原理及原理圖查閱
1.4.8.1、LED物理特性介紹
LED本身有2個接線點,一個是LED的正極,一個是LED的負極。LED這個硬件的功能就是點亮或者不亮,物理上想要點亮一顆LED只需要給他的正負極上加正電壓即可,要熄滅一顆LED只需要去掉電壓即可。
1.4.8.2、查閱原理圖了解板載LED硬件接法
查閱原理圖,發現開發板上一共有5顆LED。其中一顆D26的接法是:正極接5V,負極接地。因此這顆LED只要上電就會常亮。因此我們分析這顆LED是電源指示燈。
剩下4顆LED的接法是:正極接3.3V,負極接了SoC上的一個引腳(GPIO),具體詳細接法是:
D22:GPJ0_3
D23:GPJ0_4
D24:GPJ0_5
D25:PWMTOUT1(GPD0_1)
1.4.8.3、分析如何點亮及熄滅LED(GPIO)
分析:LED點亮的要求是:正極和負極之間有正向電壓差。
思考:在開發板上如何為LED制造這個電壓差讓它點亮呢?
解答:因為正極已經定了(3.3V),而負極接在了SoC的引腳上,可以通過SoC中編程來控制負極的電壓值,因此我們可以通過程序控制負極輸出低電平(0V),這樣在正負極上就有了壓差,LED即可點亮。
1.4.9.一步步點亮LED2_數據手冊查閱及相關寄存器瀏覽
1.4.9.1、GPIO概念的引入
GPIO:general purpose input output 通用輸入輸出
GPIO就是芯片的引腳(芯片上的引腳有些不是GPIO,只有一部分是),作為GPIO的這類引腳,他的功能和特點是可以被編程控制它的工作模式,也可以編程控制他的電壓高低等。
通過之前的分析我們知道,我們設計電路時就把LED接在了一個GPIO上,這樣我們就可以通過編程控制GPIO的模式和輸入輸出值來操控LED亮還是滅;如果你當時設計電路時把LED接在非GPIO上那就不可能了。
1.4.9.2、閱讀數據手冊中有關部分
當我們想要通過編程操控GPIO來操作LED時,我們首先需要通讀一下S5PV210的數據手冊中有關于GPIO的部分,這部分在數據手冊的Section2.2中。
1.4.9.3、GPIO相關的寄存器介紹
回憶下之前說過的,軟件操作硬件的接口是:寄存器。
我們當前要操作的硬件是LED,但是LED實際是通過GPIO來間接控制的,所以當前我們實際要操作的設備其實是SoC的GPIO。要操作這些GPIO,必須通過設置他們的寄存器。
1.4.10.一步步點亮LED3_從零開始手寫匯編點亮LED
1.4.10.1、GPxCON、GPxDAT寄存器分析
GPJ0端口一共有8個引腳,分別記住:GPJ0_0 ~ GPJ0_7,相關重要寄存器就是GPJ0CON和GPJ0DAT
GPJ0CON寄存器中設置8個引腳的工作模式(32/8=4,每個引腳可以分到4位,譬如GPJ0_0對應的bit位為bit0bit3,GPJ0_3對應的位為bit12bit15。工作方法是:給相應的寄存器位寫入相應的值,該引腳硬件就會按照相應的模式去工作。譬如給bit12~bit15寫入0b0001,GPJ0_3引腳就成為輸出模式了)
1.4.10.2、從零開始寫代碼操作寄存器
需要哪些先決條件才能寫呢?
1. 硬件接法和引腳:GPJ0_3 GPJ0_4 GPJ0_5 低電平亮/高電平滅
2. GPJ0CON(0xE0200240)寄存器和GPJ0DAT(0xE0200244)寄存器
3. 工程管理:Makefile等
根據以上分析,我們就知道代碼的寫法了,代碼所要完成的動作就是:
把相應的配置數據寫入相應的寄存器即可。
1.4.10.3、編譯、下載、運行看結果
編譯時用我們的工程管理,直接make編譯得到led.bin和210.bin
下載運行可以用usb啟動dnw下載;也可以用sd卡燒錄下載,根據自己的情況用
一般都用usb下載,因為方便。如果電腦主板插上dnw會死機沒法解決,那只有sd卡下載啟動了。
注意:開發板上按下電源鍵之后4顆LED默認都是半亮的,當我們下載程序后其中3顆變的很亮,這說明我們的程序已經運行了。
1.4.10.4、總結和回顧(軟件控制硬件思想、寄存器意義、原理圖數據手冊的作用)
軟件到底是怎么控制硬件的?為什么程序一運行硬件就能跟著動?
軟件編程控制硬件的接口就是:寄存器
1.4.11.一步步點亮LED4_使用位運算實現復雜點亮要求
上節回顧:代碼寫的更漂亮一些
1. 用宏定義來定義寄存器名字,再來操作。
2. 用 b . 來實現死循環
3. 用.global把_start鏈接屬性改為外部,消除鏈接時的警告
1.4.11.1、問題提出:如何只點亮中間1顆(兩邊是熄滅的)LED
分析:程序其實就是寫了GPJ0CON和GPJ0DAT這2個寄存器而已,功能更改也要從這里下手。
GPJ0CON寄存器不需要修改,GPJ0DAT中設置相應的輸出值即可。
1.4.11.2、直接解法(不使用位運算)和它的弊端
GPJ0DAT = 0x28
代碼見<3.led_s>
總結:1. 這樣寫可以完成任務。
2. 這樣寫有缺陷。缺陷就是需要人為的去計算這個特定的設置值,而且看代碼的也不容易看懂。
解決方案:在寫代碼時用位運算去讓編譯器幫我們計算這個特定值。
1.4.11.3、常用位運算:與、或、非、移位
位與(&) 位或(|) 位非(取反 ~) 移位(左移<< 右移>>)
1.4.11.4、使用位運算實現功能
1<<3 等于 0b1000
1<<5 等于 0b100000
(1<<3)|(1<<5) 等于 0b101000
1.4.11.5、擴展一下:如何只熄滅中間1顆而點亮旁邊2顆
ldr r0, =((0<<3) | (1<<4) | (0<<5))
1.4.12.一步步點亮LED5_匯編編寫延時函數并實現LED閃爍效果
1.4.12.1、閃爍效果原理分析
閃爍 = 亮 + 延時 + 滅 + 延時 + 亮 + 延時 ······
1.4.12.2、延時函數原理
在匯編中實現延時的方法:用一些沒有目的的代碼來執行消耗時間,達到延時的效果。
1.4.12.3、匯編編寫延時函數
匯編編寫延時函數的原理,用一個寄存器存放一個數字,然后在循環中每個循環里給數字減1,然后再判斷這個數字的值是否為0.如果為0則停止循環,如果不為0則繼續循環。
1.4.12.4、匯編編寫及調用函數的方式
匯編中整個匯編的主程序是一個死循環,這個死循環是我們匯編程序的主體,類似于C中的main函數。其他函數必須寫在這個主死循環程序的后面(死循環外),不然會出錯。
匯編編寫delay延時函數時,要注意函數的初始化和函數體的位置,不能把初始化寫在了循環體內。
匯編中調用函數用bl指令,子函數中最后用mov pc, lr來返回。
1.4.13.一步步點亮LED6_再難一點的流水燈效果
1.4.13.1、流水燈原理分析
流水燈又叫跑馬燈,實現的效果就是:挨著的LED一次點亮熄滅(同時只有1顆LED亮的)
1.4.13.2、流水燈編寫(使用循環)
LED1亮延時 + LED2亮延時 + LED3亮延時 + 循環
1.4.13.3、復雜點的實現
用位取反操作符來輕松愉快的實現單顆LED點亮流水效果
1.4.13.4、總結:一步步寫,根本不難
從一步一步點亮LED1開始到6,寫了8個示例代碼,一步步的實現了更復雜的效果,其間夾雜使用了位運算來給LED賦值,以實現想要的點亮效果。如果按部就班實際上非常簡單。
編程操控一個硬件的步驟:1 分析硬件工作原理 2 分析原理圖 3 分析數據手冊 4 找到相關的SFR 5 寫代碼設置寄存器得到想要的效果
1.4.13.5
作業:1、板子上有4顆LED的(還有個在GPD0_1),大家編程把LED4也點亮、熄滅
2、用4顆LED實現流水燈
1.4.14.反匯編工具objdump的使用簡介
1.4.14.1、反匯編的原理&為什么要反匯編
arm-linux-objdump -D led.elf > led_elf.dis
objdump是gcc工具鏈中的反匯編工具,作用是由編譯鏈接好的elf格式的可執行程序反過來得到匯編源代碼
-D表示反匯編 > 左邊的是elf的可執行程序(反匯編時的原材料),>右邊的是反匯編生成的反匯編程序
1.4.14.2、反匯編文件的格式和看法
(匯編 assembly 反匯編 dissembly)
標號地址、標號名字、指令地址、指令機器碼、指令機器碼反匯編到的指令
擴展:ARM匯編中用地址池方式來實現非法立即數
1.4.14.3、初識指令地址
下載燒錄執行的bin文件,內部其實是一條一條的指令機器碼。這些指令每一條都有一個指令地址,這個地址是連接的時候ld給指定的(ld根據我們寫的鏈接腳本來指定)
1.4.14.4、展望:反匯編工具幫助我們分析鏈接腳本
反匯編的時候得到的指令地址是鏈接器考慮了鏈接腳本之后得到的地址,而我們寫代碼時通過指定連接腳本來讓鏈接器給我們鏈接合適的地址。
但是有時候我們寫的鏈接腳本有誤(或者我們不知道這個鏈接腳本會怎么樣),這時候可以通過看反匯編文件來分析這個鏈接腳本的效果,看是不是我們想要的,如果不是可以改了再看。
外鏈內容:C語言位操作
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
- 上一篇: 激战服务器位置,如何选服务器 《激战2》
- 下一篇: 计算机考研没奖,备战考研本科期间没有什么