最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

8.2第1個(gè)ARM裸板程序及引申(下)

2020-08-16 18:32 作者:韋東山  | 我要投稿

第006節(jié)_編程知識_字節(jié)序_位操作

字節(jié)序:

假設(shè)int a = 0x12345678;

前面說了16進(jìn)制每位是4個(gè)bit,在內(nèi)存中,是以8個(gè)bit作為1byte進(jìn)行存儲的,因此0x12345678中每兩位作為1byte,其中0x78是低位,0x12是高位。

在內(nèi)存中的存儲方式有兩種:

0x12345678的低位(0x78)存在低地址,即方式1,叫做小字節(jié)序(Little endian);

0x12345678的高位(0x12)存在低地址,即方式2,叫做大字節(jié)序(Big endian);

一般的arm芯片都是小字節(jié)序,對于2440可以設(shè)置某個(gè)寄存器,讓整個(gè)系統(tǒng)使用大字節(jié)序或小字節(jié)序,它默認(rèn)使用小字節(jié)序。


位操作:

1. 移位

左移:

int a = 0x123; ?int b = a<<2;--> b=0x48C

右移:

int a = 0x123; ?int b = a>>2;--> b=0x48

左移是乘4,右移是除4;


2. 取反 原來問0的位變1,原來為1的位變0;

int a = 0x123; int b = ~a;a=2


3. 位與

1 & 1 = 1

1 & 0 = 0?

0 & 1 = 0?

0 & 0 = 0

int a = 0x123; int b = 0x456; int c = a&b;--> c=0x2


4. 位或

1 | 1 = 1

1 | 0 = 1

0 | 1 = 1

0 | 0 = 0

int a = 0x123; int b = 0x456; int c = a|b;--> c=0x577


5. 置位 把a(bǔ)的bit7、8置位(變?yōu)?)

int a = 0x123; int b = a|(1<<7)|(1<<8);--> c=0x1a3


6. 清位 把a(bǔ)的bit7、8清位(變?yōu)?)

int a = 0x123; int b = (a& ~(1<<7))&(~(1<<8));--> c=0x23


置位和清位在后面寄存器的操作中,會經(jīng)常使用。



第007節(jié)_編寫C程序控制LED

C語言的指針操作:

①所有的變量在內(nèi)存中都有一塊區(qū)域;

②可以通過變量/指針操作內(nèi)存;

Chapter8 lesson7 001.png

TYPE *p = val1;

*p = val2;


把val2寫入地址val1的內(nèi)存中,寫入sizeof(TYPE)字節(jié);

TYPE *p = addr;?

*p = val;


把val寫入地址addrd的內(nèi)存,,寫入sizeof(TYPE)字節(jié);


a. 我們寫出了main函數(shù), 誰來調(diào)用它? b. main函數(shù)中變量保存在內(nèi)存中, 這個(gè)內(nèi)存地址是多少? 答: 我們還需要寫一個(gè)匯編代碼, 給main函數(shù)設(shè)置內(nèi)存, 調(diào)用main函數(shù)


led.c源碼:

start.S源碼:

Makefile源碼:

最后將上面三個(gè)文件放入U(xiǎn)buntu主機(jī)編譯,然后燒寫到開發(fā)板即可。



第008節(jié)_幾條匯編指令_bl_add_sub_ldm_stm

⑥ADD/SUB 加法/減法

舉例1:

add r0,r1,#4

效果為

r0=r1+4;


舉例2:

sub r0,r1,#4

效果為

r0=r1-4;


舉例3:

sub r0,r1,r2

效果為

r0=r1-r2;


⑦BL (Brarch and Link)帶返回值的跳轉(zhuǎn) 跳轉(zhuǎn)到指定指令,并將返回地址(下一條指令)保存在lr寄存器;


⑧LDM/STM 讀內(nèi)存,寫入多個(gè)寄存器/把多個(gè)寄存器的值寫入內(nèi)存

可搭配的后綴有 過后增加(Increment After)、預(yù)先增加(Increment Before)、過后減少(Decrement After)、預(yù)先減少(Decrement Before);

舉例1:

stmdb sp!, (fp,ip,lr,pc)

假設(shè)Sp=4096。 db意思是先減后存,按 高編號寄存器存在高地址 存。?

Chapter8 lesson8 001.png

舉例2:

ldmia sp, (fp,ip,pc)

Chapter8 lesson8 002.png


009節(jié)_解析C程序的內(nèi)部機(jī)制

003_led.c內(nèi)部機(jī)制分析:

start.S:

①設(shè)置棧;

②調(diào)用main,并把返回值地址保存到lr中;

led.c的main()內(nèi)容:

①定義2個(gè)局部變量;

②設(shè)置變量;

③return 0;

問題:

①為什么要設(shè)置棧?

因?yàn)閏函數(shù)要用。


②怎么使用棧?

a.保存局部變量;

b.保存lr等寄存器;


③調(diào)用者如何傳參數(shù)給被調(diào)用者?

④被調(diào)用者如何傳返回值給調(diào)用者?

⑤怎么從棧中恢復(fù)那些寄存器?


在arm中有個(gè)ATPCS規(guī)則,約定r0-r15寄存器的用途。

r0-r3:調(diào)用者和被調(diào)用者之間傳參數(shù);

r4-r11:函數(shù)可能被使用,所以在函數(shù)的入口保存它們,在函數(shù)的出口恢復(fù)它們;


下面分析個(gè)實(shí)例 start.S:

led.c:

將前面的程序反匯編得到led.dis如下:


分析上面的匯編代碼:

開發(fā)板上電后,將從0地址開始執(zhí)行,即開始執(zhí)行

mov sp, #4096:設(shè)置棧地址在4k RAM的最高處,sp=4096;

bl? ? c <main>:調(diào)到c地址處的main函數(shù),并保存下一行代碼地址到lr,即lr=8;

mov ip, sp:給ip賦值sp的值,ip=sp=4096

stmdb sp!, {fp, ip, lr, pc}:按高編號寄存器存在高地址,依次將pc、lr、ip、fp存入sp-4中;

sub fp, ip, #4:fp的值為ip-4=4096-4=4092;

sub sp, sp, #8:sp的值為sp-8=(4096-4x4)-8=4072;

mov r3, #1442840576:r3賦值0x5600 0000;?

add r3, r3, #80:r3的值加0x50,即r3=0x5600 0050;

str r3, [fp, #-16]:r3存入[fp-16]所在的地址,即地址4076處存放0x5600 0050;

mov r3, #1442840576:r3賦值0x5600 0000;?

add r3, r3, #84:r3的值加0x54,即r3=0x5600 0054;

str r3, [fp, #-20]:r3存入[fp-20]所在的地址,即地址4072處存放0x5600 0054;

ldr r2, [fp, #-16]:r2取[fp-16]地址處的值,即[4076]地址的值,r2=0x5600 0050;

mov r3, #256:r3賦值為0x100;

str r3, [r2]:將r3寫到r2內(nèi)容所對應(yīng)的地址,即0x5600 0050地址處的值為0x100;;對應(yīng)c語言*pGPFCON = 0x100;;

ldr r2, [fp, #-20]:r2取[fp-20]地址處的值,即[4072]地址的值,r2=0x5600 0054;

mov r3, #0:r3賦值為0x00;

str r3, [r2]:將r3寫到r2內(nèi)容所對應(yīng)的地址,即0x5600 0054地址處的值為0x00;對應(yīng)c語言*pGPFDAT = 0;

mov r3, #0:r3賦值為0x00;

mov r0, r3:r0=r3=0x00;

sub sp, fp, #12:sp=fp-12=4092-12=4080;

ldmia sp, {fp, sp, pc}:從棧中恢復(fù)寄存器,fp=4080地址處的值=原來的fp,sp=4084地址處的值=4096,pc=4088地址處的值=8,隨后調(diào)到0x08地址處繼續(xù)執(zhí)行。


過程中的內(nèi)存數(shù)據(jù)情況:

Chapter8 lesson9 001.jpg


前面那個(gè)例子,匯編調(diào)用main.c并沒有傳遞參數(shù),這里修改下c程序,讓其傳遞參數(shù)。

start.S:

led.c:

led.elf:

簡單分析下反匯編:

?mov sp, #4096:設(shè)置棧地址在4k RAM的最高處,sp=4096;


?mov r0, #4:r0=4,作為參數(shù);


?bl 58 <led_on>:調(diào)到58地址處的led_on函數(shù),并保存下一行代碼地址到lr,即lr=8;在led_on中會使用到r0;


?ldr r0, [pc, #12]:r0=[pc+12]處的值=[c+12=20]的值=0x186a0=1000000,作為參數(shù);


?bl 24 <delay>:調(diào)用24地址處的delay函數(shù),并保存下一行代碼地址到lr,即lr=24;在delay中會使用到r0;


?mov r0, #5:r0=5,作為參數(shù);


?bl 58 <led_on>:調(diào)到58地址處的led_on函數(shù),并保存下一行代碼地址到lr,即lr=58;在led_on中會使用到r0;



010節(jié)_完善LED程序_編寫按鍵程序

在上一節(jié)視頻里,我們編寫的程序代碼是先點(diǎn)亮led1,然后延時(shí)一會,再點(diǎn)亮led2,進(jìn)入死循環(huán)。

但在開發(fā)板上的實(shí)際效果是led1先亮,延時(shí)一會,led2再亮,然后一會之后,led1再次亮了。

這和我們的設(shè)計(jì)的代碼流程不吻合,這是因?yàn)?440里面有個(gè)看門狗定時(shí)器,開發(fā)板上電后,需要在一定時(shí)間內(nèi)“喂狗”(設(shè)置相應(yīng)的寄存器),否則就會重啟開發(fā)板。

之所以這樣設(shè)計(jì),是為了讓芯片出現(xiàn)死機(jī)時(shí),能夠自己復(fù)位,重新運(yùn)行。


這里我們寫個(gè)led燈循環(huán)的程序,步驟如下:

  1. 這里暫時(shí)用不到看門狗,先關(guān)閉看門狗,從參考手冊可知,向0x53000000寄存器寫0即可關(guān)閉看門狗;

  2. 設(shè)置內(nèi)存的棧,通過寫讀操作來判斷是Nand Flash還是Nor Flash;

  3. 設(shè)置GPFCON讓GPF4/5/6配置為輸出引腳;

  4. 循環(huán)點(diǎn)燈,依次設(shè)置GPFDAT寄存器;

完整代碼如下:

led.c

2440里面有很多寄存器,如果每次對不同的寄存器進(jìn)行查詢和操作會很麻煩,因此可以先提前定義成宏,做成一個(gè)頭文件,每次調(diào)用就行。

再舉一個(gè)按鍵控制LED的程序,,步驟如下:

  1. 這里暫時(shí)用不到看門狗,先關(guān)閉看門狗,從參考手冊可知,向0x53000000寄存器寫0即可關(guān)閉看門狗;

  2. 設(shè)置內(nèi)存的棧,通過寫讀操作來判斷是Nand Flash還是Nor Flash;

  3. 設(shè)置GPFCON讓GPF4/5/6配置為輸出引腳;

  4. 設(shè)置3個(gè)按鍵引腳為輸入引腳;

  5. 循環(huán)執(zhí)行,讀取按鍵引腳值,點(diǎn)亮對應(yīng)的led燈;


完整代碼如下:

視頻教程??

韋東山升級版全系列嵌入式免費(fèi)視頻_快速入門篇


8.2第1個(gè)ARM裸板程序及引申(下)的評論 (共 條)

分享到微博請遵守國家法律
大田县| 西林县| 丹棱县| 大关县| 蕉岭县| 鸡东县| 柳林县| 沂水县| 肥城市| 浦城县| 桐乡市| 甘谷县| 石阡县| 铁岭县| 赤水市| 安图县| 西平县| 涟水县| 南充市| 关岭| 全南县| 铁力市| 玉屏| 额敏县| 凉山| 临桂县| 太仓市| 河南省| 平和县| 唐河县| 郓城县| 天气| 怀安县| 新竹县| 临沧市| 沙洋县| 龙海市| 渝中区| 阜阳市| 凉城县| 印江|