日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

起航,第一个程序——还是LED灯

發布時間:2025/3/19 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 起航,第一个程序——还是LED灯 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

如同學基本語言一樣,helloworld是很多語言的第一個程序。在嵌入式開發中,點亮LED燈也是各種架構和開發板的第一個程序,其中很多東西是和單片機例如stm32是類似的,只是,現在我們沒有了庫函數,我們要自己完成一些東西。

先說啟動文件,st官方已結給我們做好了,但是jz2440開發板沒有統一的啟動文件,需要自己編寫,那么,基礎的arm匯編就得有所熟悉,在之后的學習中,遇到一個指令就學習一個。

(匯編)指令是CPU機器指令的助記符,經過編譯后會得到一串1、0組成的機器碼,可以由CPU讀取執行。 (匯編)偽指令本質上不是指令(只是和指令一起寫在代碼中),它是編譯器環境提供的,目的是用來指導編譯過程,經過編譯后偽指令最終不會生成機器碼。

ARM官方的ARM匯編風格:指令一般用大寫、Windows中IDE開發環境(如ADS、MDK等)常用。如: LDR R0, [R1] GNU風格的ARM匯編:指令一般用小寫字母、linux中常用。如:ldr r0, [r1]

ARM采用RISC架構,CPU本身不能直接讀取內存,而需要先將內存中內容加載入CPU中通用寄存器中才能被CPU處理。 ldr(load register)指令將內存內容加載入通用寄存器。 str(store register)指令將寄存器內容存入內存空間中。 ldr/str組合用來實現 ARM CPU和內存數據交換。

先看流水燈的一段啟動代碼:

1 @****************************************************************************** 2 @ File:crt0.S 3 @ 功能:通過它轉入C程序 4 @****************************************************************************** 5 6 .text 7 .global _start 8 _start: 9 ldr r0, =0x53000000 @ WATCHDOG寄存器地址 10 mov r1, #0x0 11 str r1, [r0] @ 寫入0,禁止WATCHDOG,否則CPU會不斷重啟 12 13 ldr sp, =1024*4 @ 設置堆棧,注意:不能大于4k, 因為現在可用的內存只有4K 14 @ nand flash中的代碼在復位后會移到內部ram中,此ram只有4K 15 bl main @ 調用C程序中的main函數 16 halt_loop: 17 b halt_loop

預備知識:摘自 http://blog.csdn.net/qq506124204/article/details/7952966

mov?? r1, #0x53000000?? //立即數尋址方式?
mov?? r2, #0x0?
str?? r2, [r1]????????
立即數尋址方式,立即數要求以“#”作前綴,對于十六進制的數,還要求在#后面加上0x或者&。STR是比較重要的指令了,跟它對應的是LDR。 ARM指令集是加載/存儲型的,也就是說它只處理在寄存器中的數據。那么對于系統存儲器的訪問就經常用到STR和LDR了。STR是把寄存器上的數據傳輸 到指定地址的存儲器上。它的格式我個人認為很特殊:
STR(條件) 源寄存器,<存儲器地址>
比如 STR R0, [R1] ,意思是R0-> [R1],它把源寄存器寫在前面,跟MOV、LDR都相反。
LDR應該是非常常見了。LDR就是把數據從存儲器傳輸到寄存器上。而且有個偽指令也是LDR,因此我有個百思不得其解的問題。看這段代碼:
mov r1, #GPIO_CTL_BASE?
add?? r1, r1, #oGPIO_F?
ldr?? r2,=0x55aa?? // 0x55aa是個立即數啊,前面加個=干什么??
對于當中的ldr 那句,我就不明白了,如果你把=去掉,是不能通過編譯的。我查了一些資料,個人感覺知道了原因:這個=應該表示LDR不是ARM指令,而是偽指令。作為偽指令的時候,LDR的格式如下:
LDR 寄存器, =數字常量/Label
它的作用是把一個32位的地址或者常量調入寄存器。嗬嗬,那大家可能會問,
“MOV r2,#0x55aa”也可以啊。應該是這樣的。不過,LDR是偽指令啊,也就是說編譯時編譯器會處理它的。怎么處理的呢?——規則如下:如果該數字常量 在MOV指令范圍內,匯編器會把這個指令作為MOV。如果不在MOV范圍中,匯編器把該常量放在程序后面,用LDR來讀取,PC和該常量的偏移量不能超過 4KB。

然后說一下跳轉指令。ARM有兩種跳轉方式。
(1) mov pc <跳轉地址〉
這種向程序計數器PC直接寫跳轉地址,能在4GB連續空間內任意跳轉。
(2)通過 B BL BLX BX 可以完成在當前指令向前或者向后32MB的地址空間的跳轉(為什么是32MB呢?寄存器是32位的,此時的值是24位有符號數,所以32MB)。
B是最簡單的跳轉指令。要注意的是,跳轉指令的實際值不是絕對地址,而是相對地址——是相對當前PC值的一個偏移量,它的值由匯編器計算得出。
BL非常常用。它在跳轉之前會在寄存器LR(R14)中保存PC的當前內容。

為什么要先關閉看門狗?因為板子上電,看門狗是硬件打開的,不關閉會一直復位。

再看Makefile文件:

1 CFLAGS := -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -ffreestanding 2 leds.bin : crt0.S leds.c 3 arm-linux-gcc $(CFLAGS) -c -o crt0.o crt0.S 4 arm-linux-gcc $(CFLAGS) -c -o leds.o leds.c 5 arm-linux-ld -Ttext 0x0000000 crt0.o leds.o -o leds_elf 6 # arm-linux-ld -Tleds.lds crt0.o leds.o -o leds_elf 7 arm-linux-objcopy -O binary -S leds_elf leds.bin 8 arm-linux-objdump -D -m arm leds_elf > leds.dis 9 clean: 10 rm -f leds.dis leds.bin leds_elf *.o

這里用到了arm的交叉編譯器,-ld,是鏈接指令,-Ttext是指明程序段,即程序存儲的地方,為什么是從0地址開始,這是因為在我使用的2440中,是以nand flash啟動的,nand啟動會復制nand flash中4K的內容到2440芯片的SRAM,這4K內容從地址0開始取址啟動,nor啟動就不需要復制內容到SARM,可以直接啟動。前面-c選項,表示只編譯不鏈接,而后面ld,表示把那些.o文件鏈接起來構成*elf文件,然后通過objcopy,把上面編譯鏈接之后的目標文件轉化成二進制文件即.bin文件。objcopy把一種目標文件中的內容復制到另一種類型的目標文件中.?-S?表示移出所有的標志及重定位信息 ;
-O?binary?xyb?xyb.bin?表示由xyb生成二進制文件xyb.bin。

objdump指令,-D代表反匯編所有的段,-m代表的是反匯編目標文件使用的構架,這里是arm構架,>重定向成*.dis文件。

關于Makefile中的幾個編譯選項:參考鏈接:http://blog.chinaunix.net/uid-20737871-id-1881211.html
-Wall 開啟所有警告

-Wstrict-prototypes?如果函數的聲明或定義沒有指出參數類型,編譯器就發出警告。

-O2 優化等級2

-fomit-frame-pointer選項是發布產品時經常會用到的優化選項,它可以優化匯編函數中用edp協助獲取堆棧中函數參數的部分,不使用edp,而是通過計算,全部使用esp來完成。參考鏈接:http://www.cnblogs.com/yamadie/p/3363567.html

-ffreestanding按獨立環境編譯,該環境可以沒有標準庫,且對main()函數沒有要求。最典型的例子就是操作系統內核。參考鏈接:http://blog.csdn.net/eroswang/article/details/1966640

?

?

終于介紹完了預備知識,這些東西有的需要理解記憶,有的只用了解熟悉即可。現在開始編寫程序。就流水燈的C語言程序來說,其實和單片機一樣,屬于簡單的。但是arm版之所以很多人買了之后就吃灰了,就是因為對只是體系的構架不熟悉,還有基本技能的缺失。這也是為什么很多人說,韋老師的課程不適合新手吧。

1 #define GPFCON (*(volatile unsigned long *)0x56000050) 2 #define GPFDAT (*(volatile unsigned long *)0x56000054) 3 4 #define GPF4_out (1<<(4*2)) 5 #define GPF5_out (1<<(5*2)) 6 #define GPF6_out (1<<(6*2)) 7 8 void wait(volatile unsigned long dly) 9 { 10 for(; dly > 0; dly--); 11 } 12 13 int main(void) 14 { 15 unsigned long i = 0; 16 17 GPFCON = GPF4_out|GPF5_out|GPF6_out; // 將LED1,2,4對應的GPF4/5/6三個引腳設為輸出 18 19 while(1){ 20 wait(30000); 21 GPFDAT = (~(i<<4)); // 根據i的值,點亮LED1,2,4 22 if(++i == 8) 23 i = 0; 24 } 25 26 return 0; 27 }

這是韋老師的參考代碼,硬件上是低電平LED亮。

IO口分別對應GPIO_F ?4,5,6。雖然老師的代碼很好地實現了流水燈,但我覺得這個代碼寫成一個函數更友好,可移植性也更高,要是我的LED等編程GPI0_F 0,3,7,要實現流水燈就要大改代碼了,所以自己做了更改,模仿st的庫函數寫法,但是由于才接觸2440,對它的寄存器還不熟悉,所以先不急于封裝,等學了韋老師資料之后再去封裝。

總結

以上是生活随笔為你收集整理的起航,第一个程序——还是LED灯的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 尤物视频在线观看视频 | 亚洲一级免费毛片 | 国产毛片久久久久久国产毛片 | 中文字幕乱码在线 | 一区二区三区精品免费视频 | 午夜影视av | 成人网站在线进入爽爽爽 | 欧美手机在线视频 | 精品无码人妻一区二区三 | 爱情岛论坛自拍 | 日韩一区二 | 朱竹清到爽高潮痉挛 | 亚洲一区二区三区观看 | 黄色综合网站 | 色婷婷777777仙踪林 | 欧美日一区二区 | 国产免费又爽又色又粗视频 | 高清一区二区三区四区五区 | www在线免费观看 | 91麻豆网 | 激情五月视频 | 成人va在线观看 | 在线你懂| 久久精品国产亚洲av麻豆图片 | 五月婷婷激情在线 | 久久综合一区二区 | 久久蜜臀精品av | 91在线免费视频观看 | 欧美图片自拍偷拍 | 手机av在线看 | 91精品黄色 | av字幕在线| 一本一道波多野结衣av黑人 | 91午夜在线观看 | 精品人伦一区二区三区蜜桃网站 | 人妻大战黑人白浆狂泄 | 中国a级大片 | 亚洲成av人片一区二区 | 欧美另类自拍 | 在线观看中文字幕一区 | 四虎影视www在线播放 | av在哪里看 | 久久久一本 | 国产精品一区二区三区不卡 | 亚洲综合av网 | 久久青娱乐 | 91正在播放 | 欧美福利在线 | 激情综合五月网 | 欧美美女色图 | a√在线观看 | 久久视频在线播放 | 国产欧美一区二区三区精品酒店 | 痴汉电车在线播放 | 国产乱码精品一区二区三 | 欧美成人一区二区视频 | 国产精品视频在线观看 | 自拍偷拍色 | www.爆操 | 欧美激情一区在线 | 国产乱人伦app精品久久 | 亚洲三级影院 | 成人av网站在线播放 | 免费成人看视频 | 国产精品99久久久久久人 | 精品国产丝袜一区二区三区乱码 | 日日夜夜一区二区 | 日韩欧美亚洲一区二区 | 黄色中文 | 国产一区二区三区成人 | 亚洲福利午夜 | 国产又粗又猛视频免费 | 亚洲av综合永久无码精品天堂 | 欧美乱插 | 亚洲永久精品视频 | 天堂av影院 | 性xxxx视频播放免费 | 亚洲免费在线观看视频 | 欧美日本在线播放 | 欧美a级大片 | 91国产免费看 | 精品无码久久久久久久 | av剧情在线 | 丝袜 中出 制服 人妻 美腿 | 韩国女同性做爰三级 | 日韩精品――色哟哟 | 蜜桃视频在线观看污 | 999资源站 | 六十路息与子猛烈交尾 | 国产久视频 | 欧美日韩国产一区二区三区 | 一本色道久久hezyo加勒比 | 国产av人人夜夜澡人人爽麻豆 | 伊人午夜 | 久久午夜无码鲁丝片 | 久久精品欧美日韩精品 | 农村妇女av | 黄色片视频播放 | 欧美色图亚洲色 |