int a = 100; * (&a) = 100; 0xc001c000 // 常量 (int*)0xc001c000 // 地址 * ((int*)0xc001c000) = 0x100; // 寫入數(shù)據(jù),按int-4字節(jié)寫入0x100volatile 的作用,以及哪種場(chǎng)合需要使用該關(guān)鍵字?(課后查資料)>>表示'一個(gè)變量也許會(huì)被后臺(tái)程序意想不到的修改'。變量如果加了volatile修飾,則會(huì)從內(nèi)存重新裝載內(nèi)容,而不是直接從寄存器拷貝內(nèi)容。volatile可以保證對(duì)特殊地址的穩(wěn)定訪問(wèn)。>>寄存器地址要加volatile修飾,主要是因?yàn)榧拇嫫骼锩娴?#20540;是隨時(shí)變化的。 我們讀取數(shù)據(jù)的時(shí)候,CPU直接到內(nèi)存里面取值,而不是到cache里面。 1) 并行設(shè)備的硬件寄存器; 2) 中斷服務(wù)子程序中會(huì)訪問(wèn)到的非自動(dòng)變量; 3) 多線程應(yīng)用中被及格任務(wù)共享的變量;例如:
volatile int i = 10; int a = i; // 其他代碼,并未告訴編譯器,對(duì)i進(jìn)行過(guò)操作 int b = i;"volatile 指出i是隨時(shí)可能發(fā)生變化的,每次使用它的時(shí)候必須從i的地址中讀取,因而編譯器生成的匯編代碼會(huì)重新從i的地址讀取數(shù)據(jù)放在b中。而優(yōu)化做法是,由于編譯器發(fā)現(xiàn)兩次從i讀數(shù)據(jù)的代碼之間的代碼沒(méi)有對(duì)i進(jìn)行過(guò)操作,它會(huì)自動(dòng)把上次讀的數(shù)據(jù)放在b中。而不是重新從i里面讀,這樣以來(lái),如果i是一個(gè)寄存器變量或者表示一個(gè)端口數(shù)據(jù)就容易出錯(cuò),所以說(shuō) volatile 可以保證特殊地質(zhì)的穩(wěn)定訪問(wèn)。"// 訪問(wèn)特殊功能寄存器的時(shí)候需要加 volatile 關(guān)鍵字,正確的寫法: a = * ((volatile unsigned int*)0xc001c000); // 下面此條做法,不但將bit12清0,也導(dǎo)致其他的bit被清0了,錯(cuò)誤!! * ((volatile unsigned int*)0xc001c000) = 0x00;3.2 位運(yùn)算 假設(shè)需要將 0xc001c020 寄存器的[25:24]bit位設(shè)置為 01 ,* ((volatile unsigned int*)0xc001c020) &= ~(0x03000000); // 第一步 // 32bit : xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx // 0x03000000 0000 0011 0000 0000 0000 0000 0000 0000 // ~(0x03000000) 1111 1100 1111 1111 1111 1111 1111 1111 // &= ~(0x03000000) xxxx xx00 xxxx xxxx xxxx xxxx xxxx xxxx * ((volatile unsigned int*)0xc001c020) |= 0x01000000; // 第二步 // 32bit : xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx // 01 ([25:24]bit) // 0x0______01_0____0____0____0____0____0 "實(shí)際做法:" * ((volatile unsigned int*)0xc001c020) &= ~(3<<24); // 第一步 * ((volatile unsigned int*)0xc001c020) |= (1<<24); // 第二步<tips>$:'file a.out// file 命令可以用來(lái)分析文件的一些屬性。x86-64 是x86的64位平臺(tái)運(yùn)行。4. 編碼 vi led.c/** 代碼演示 **/#define GPIOC_OUT *((volatile unsigned int*)0xc001c000)#define GPIOC_OUTENB *((volatile unsigned int*)0xc001c004)#define GPIOC_ALTFN0 *((volatile unsigned int*)0xc001c020)void delay (unsigned int); void led_test (void) { // 配置對(duì)應(yīng)管腳為GPIO功能 GPIOC_ALTFN0 &= ~ (3 << 24); // clear bit 24,25 GPIOC_ALTFN0 |= (1 << 24); // set bit 24 // 選擇為輸出功能 GPIOC_OUTENB |= (1 << 12); // OUTPUT while (1) { // 亮 - 輸出低電平 GPIOC_OUT &= ~ (1 << 12); // clear bit 12 delay (0x1000000); // 滅 - 輸出高電平 GPIOC_OUT |= (1 << 12); // set bit 12 delay (0x1000000); }}// delay函數(shù)的實(shí)現(xiàn)不能放前面,只能先聲明后實(shí)現(xiàn)void delay (unsigned int n) { unsigned int i = 0; for (i = n; i != 0; i--); // CPU執(zhí)行空操作來(lái)耗時(shí)}5. arm編譯器
5.1 安裝arm交叉編譯器>>位置:/home/tarena/workdir/arm-linux-gcc/ 'arm-cortex_a9-eabi-4.7-eglibc-2.18.tar.gz 權(quán)限不夠時(shí)解決方法: 1> $:' sudo ... 2> $:' sudo chmod +w /opt/ -R 3> $:' sudo chmod 777 /opt/ -R // 將交叉編譯器tar包文件拷貝到/opt/下,在此文件夾下解壓縮 $:'cd ~/opt/ $:'sudo cp ~/workdir/arm..<table>/arm... .tar.gz . $:'sudo tar xvf *.gz>>位置:/opt/arm-cortex_a9-eabi-4.7-eglibc-2.18/bin/ 'arm-cortex_a9-linux-gnueabi-gcc $:'vi ~/.bashrc>>添加:<shift + g> // 添加到文件尾 'PATH=$PATH:/opt/arm-cortex_a9-eabi-4.7-eglibc-2.18/bin $:'source ~/.bashrc5.2 編譯程序希望編譯出來(lái)的程序不使用共享庫(kù) (因?yàn)槭锹惆澹?nbsp; 1)編譯 $:'arm-cortex_a9-linux-gnueabi-gcc -c -nostdlib led.c -o led.o 2)連接 $:'arm-cortex_a9-linux-gnueabi-ld -nostdlib -nostartfiles -Ttext=0x48000000 -eled_test led.o -o led // -no stdlib 不連接標(biāo)準(zhǔn)庫(kù)文件 // -no startfiles 不連接系統(tǒng)標(biāo)準(zhǔn)啟動(dòng)文件 // -Ttext 指定代碼段的起始地址 // -e 指定入口點(diǎn)函數(shù),默認(rèn)找_start 3)去掉附加信息,生成二進(jìn)制文件 $:'arm-cortex_a9-linux-gnueabi-objcopy -O binary led led.bin $:' file led.bin<tips>$:'arm-cortex_a9-linux-gnueabi-readelf -d a.out// 顯示可執(zhí)行文件a.out文件中所需的共享庫(kù).so信息$:'arm-cortex_a9-linux-gnueabi-objdump -S led// 反匯編的命令,查看文件的具體的函數(shù)及信息6. 下載運(yùn)行: X6818# 命令行 $:' cp led.bin /tftpboot/ X6818#:'tftp 48000000 led.bin // uboot下數(shù)字都識(shí)別為十六進(jìn)制 X6818#:' go led.bin<tips>執(zhí)行tftp 48000000 led.bin 時(shí) Ubuntu-server報(bào) T..T..T...時(shí)需重啟服務(wù)器:$:'sudo /etc/init.d/tftpd-hpa restart補(bǔ)充:編程錯(cuò)誤>>語(yǔ)法錯(cuò)誤: '只關(guān)注只解決第一個(gè)錯(cuò)誤。邏輯錯(cuò)誤: ' printf / gdb 1. 是不是硬件問(wèn)題? env/led.bin放進(jìn)去,燈亮硬件沒(méi)問(wèn)題(或者換到別人電腦上試一試) 2. 如果是軟件問(wèn)題,怎么查? 修改led.c的邏輯 讓對(duì)應(yīng)管腳一直輸出高電平 拿萬(wàn)用表量一下對(duì)應(yīng)的管腳上是否是高電平。env/BCompare-3.3.4.14431.zip // 工具,對(duì)比文件夾和文件里面不同之處<tips>vi中的命令模式下:e ../xxx.c // 在vi中直接打開別的文件練習(xí): 1. LED1和LED2交替閃爍。(理清楚今天的整個(gè)流程,看手冊(cè),理流程) 2. beep蜂鳴器的控制管腳相關(guān)數(shù)據(jù)準(zhǔn)備:'led1 - GPIOC12 - W15 - Function1 GPIOCALTFN0 - 0xc001c020 - bit[25:24] - 01=Function1 (I/O功能) GPIOCOUTENB - 0xc001c004 - bit[12] - 1=Output Mode (輸出功能) GPIOCOUT - 0xc001c000 - bit[12] - 1=High Level (0/1 低高電平)'led2 - GPIOC7 - AE21 - Function1 GPIOCALTFN0 - 0xc001c020 - bit[15:14] - 01 GPIOCOUTENB - 0xc001c004 - bit[7] - 1 GPIOCOUT - 0xc001c000 - bit[7] - 1'led3 - GPIOC11 - W14 - Function1 GPIOCALTFN0 - 0xc001c020 - bit[23:22] - 01 GPIOCOUTENB - 0xc001c004 - bit[11] - 1 GPIOCOUT - 0xc001c000 - bit[11] - 1'led4 - GPIOB26 - MCU_SPI_WP AC25 - Function1 (暫略)/** 代碼演示 **/#define GPIOC_ALTFN0 *((volatile unsigned int*)0xc001c020)#define GPIOC_OUTENB *((volatile unsigned int*)0xc001c004)#define GPIOC_OUT *((volatile unsigned int*)0xc001c000)void delay (unsigned int);void led_run (void) { // 配置GPIOC管腳 // led1 25:24 GPIOC_ALTFN0 &= ~ (3 << 24); GPIOC_ALTFN0 |= (1 << 24); // led2 15:14 GPIOC_ALTFN0 &= ~ (3 << 14); GPIOC_ALTFN0 |= (1 << 14); // led3 23:22 GPIOC_ALTFN0 &= ~ (3 << 22); GPIOC_ALTFN0 |= (1 << 22); // 設(shè)置輸出功能 GPIOC_OUTENB |= (1 << 12); GPIOC_OUTENB |= (1 << 11); GPIOC_OUTENB |= (1 << 7); for (;;) { GPIOC_OUT &= ~ (1 << 12); // led1 delay (0x800000); GPIOC_OUT &= ~ (1 << 11); // led2 delay (0x800000); GPIOC_OUT &= ~ (1 << 7); // led3 delay (0x800000); GPIOC_OUT |= (1 << 12); delay (0x800000); GPIOC_OUT |= (1 << 11); delay (0x800000); GPIOC_OUT |= (1 << 7); delay (0x800000); } }void delay (unsigned int n) { unsigned int i; for (i = n; i; --i);}2. beep蜂鳴器的控制' beep蜂鳴器 - PWM2[GPIOC14] - AD12 - Function2 GPIOCALTFN0 - 0xc001c020 - bit[29:28] - 10=Function2 (I/O功能) GPIOCOUTENB - 0xc001c004 - bit[14] - 1=Output Mode (輸出功能) GPIOCOUT - 0xc001c000 - bit[14] - 1=High Level (0/1 低高電平)
/** 代碼演示 **/#define GPIOC_ALTFN0 *((volatile unsigned int*)0xc001c020)#define GPIOC_OUTENB *((volatile unsigned int*)0xc001c004)#define GPIOC_OUT *((volatile unsigned int*)0xc001c000)void delay (unsigned int);void beep_run (void) { // 配置GPIO管腳 GPIOC_ALTFN0 &= ~(3 << 28); GPIOC_ALTFN0 |= (2 << 28); // 設(shè)置輸出功能 GPIOC_OUTENB |= (1 << 14); for (;;) { GPIOC_OUT &= ~(1 << 14); // 低電平 - 鳴叫 delay (0x2000000); GPIOC_OUT |= (1 << 14); // 高電平 - 不叫 (無(wú)延時(shí)和停止蜂鳴效果) delay (0x2000000); } }void delay (unsigned int n) { unsigned int i; for (i = n; i; --i);}
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注