1. 程式人生 > >3 led程式編寫和交叉編譯器

3 led程式編寫和交叉編譯器

3 led程式編寫和交叉編譯器

1、明確:下位機執行的軟體型別

嵌入式軟體分兩類:裸板程式和基於作業系統程式

裸板程式的特點:

單檔案:可執行程式只有一個

單任務: 執行的程式就一個

執行環境不是基於作業系統(例如:linux/winodows/ios等)

不允許使用標準C庫的內容(例如:printf)

切記:裸板程式的程式設計框架

void abc(void)

 {

xyz_init();

/*

led_init(); //初始化LED

uart_init(); //初始化UART串列埠

lcd_init();//初始化LCD顯示屏

net_init(); //初始化網絡卡

usb_init(); //初始化USB

emmc_init();//初始化EMMC

nand_init(); //初始化nadflash

norflash_init();//初始化norflash

...

*/

while(1)

{

//根據使用者需求來操作訪問硬體

/*

led_on(); //開燈

delay(); //延時一段時間

led_off(); //關燈

                  delay(); //延時一段時間

*/

}

}

 

說明:

1.裸板程式的入口函式名不一定叫main,隨便叫,例如abc

2.裸板程式上來首先做各種硬體初始化工作,例如xyz_init初始化函式

"硬體初始化":硬體外設正式使用操作之前,將它的工作狀態指定一個合適的狀態下

例如LED燈:首先應該把LED1對應的處理器的引腳的功能配置為GPIO功能

還要配置為輸出模式,只有這兩個做好了,才能輸出0和輸出1,不能上來就輸出1或者0

                                                                            

基於作業系統程式特點:

多檔案

多工

可以使用標準C庫的內容(例如:printf)

應用程式程式設計框架

int main(int argc, char *argv[])

{

/*根據使用者需求完成業務*/

return 0;

}

                                                                     

結論:目前此LED程式採用裸板程式來實現      

led.h
#ifndef __LED_H
#define __LED_H

/*暫存器的定義*/
#define GPIOCOUT    (*(volatile unsigned long *)0xC001C000)
#define GPIOCOUTENB    (*(volatile unsigned long *)0xC001C004)
#define GPIOCALTFN0    (*(volatile unsigned long *)0xC001C020)

/*宣告LED操作函式*/
extern void led_init(void);
extern void led_on(void);
extern void led_off(void);

#endif
led.c
#include "led.h"

//宣告延時函式
extern void delay(int n);

/*裸板程式的入口函式*/
void led_test(void)
{
    /*1.初始化LED*/
    led_init();

    //2.根據使用者需求重複開關燈
    while(1) {
        led_on(); //開
        delay(0x1000000); //延時
        led_off(); //關
        delay(0x1000000); //延時
    }
}

//初始化函式定義
void led_init(void)
{
    //1.配置LED1對應的CPU引腳功能為GPIO
    GPIOCALTFN0 &= ~(3 << 24);
    GPIOCALTFN0 |= (1 << 24);

    //2.配置為輸出功能
    GPIOCOUTENB |= (1 << 12);
}

//開燈函式定義
void led_on(void)
{
    GPIOCOUT &= ~(1 << 12);
}

//關燈函式定義
void led_off(void)
{
    GPIOCOUT |= (1 << 12);
}

//延時函式
void delay(int n)
{
    int i = n;
    for(; i != 0; i--);
}











    

                                  

2、上位機開始編輯編譯LED的裸板程式

上位機的操作步驟如下:

    1)上位機新增部署交叉編譯器

"交叉編譯器":本身執行在上位機,而它編譯出來的二進位制檔案執行在下位機

獲取交叉編譯器:resource.rar/編譯器/arm-cortex_a9-eabi-4.7-eglibc-2.18.tar.gz

sudo chown baby/opt -R

sudo chgrp baby /opt -R

cp arm-cortex_a9-eabi-4.7-eglibc-2.18.tar.gz /opt/

cd /opt/

tar -xvf arm-cortex_a9-eabi-4.7-eglibc-2.18.tar.gz

ls

arm-cortex_a9-eabi-4.7-eglibc-2.18 //交叉編譯器目錄

mv arm-cortex_a9-eabi-4.7-eglibc-2.18 toolchains

sudo vim /etc/environment //開啟此檔案,新增交叉編譯器的路徑

PATH="/opt/toolchains/bin:..." //在PATH中新增交叉編譯器的路徑

儲存退出

重啟上位機linux系統

驗證交叉編譯器,上位機執行:

arm-cortex_a9-linux-gnueabi-gcc -v //檢視交叉編譯器是否正常執行和檢視版本

                 

2)編輯,交叉編譯LED裸板程式    

mkdir /opt/arm/03/1.0 -p

cd /opt/arm/day03/1.0

vim led.h

vim led.c

arm-cortex_a9-linux-gnueabi-gcc -nostdlib -c -o led.o led.c

說明:

-nostdlib:由於此程式led.c為裸板程式,不允許使用標準C庫的內容

新增-nostdlib告訴編譯器不會使用標準C庫的內容

-c:只編譯不連結

            

arm-cortex_a9-linux-gnueabi-ld -nostartfiles -nostdlib -Ttext=0x48000000-o led.elf led.o

說明:

arm...ld:連結器

-nostartfiles:連結時無需連結啟動檔案

-nostdlib:不允許使用標準C庫的內容

-Ttext:程式碼段

-Tdata:資料段

-Ttext=0x48000000:指定程式碼段的起始地址為0x480000000(下位機記憶體的地址)

led.elf:生成ELF格式的二進位制檔案,但是ELF格式的二進位制檔案只能執行在作業系統下

            

arm-cortex_a9-linux-gnueabi-objcopy -O binary led.elf led.bin

說明:

arm...objcopy:將ELF格式的二進位制檔案生成對應的純正的二進位制檔案

例如:

led.elf:整個橘子

led.bin:果肉

objcopy:去皮工具

led.bin:純正的二進位制檔案可以執行在裸板上

                                                                         

cp led.bin /tftpboot  //拷貝tftp服務的下載目錄

     

下位機測試:

重啟下位機,進入uboot的命令列模式,執行:

tftp 0x48000000 led.bin

go 0x48000000 //觀察燈的閃爍

     

vim操作技巧:

左右分屏:vs 檔名

上下分屏:sp 檔名

螢幕切換:ctrl +ww

一個終端中建立子終端:ctrl+shift+t

終端切換:alt+終端的編號

建議:一個終端編輯儲存程式碼(不用退出),另一個終端編譯程式碼

     

案例:反彙編裸板程式碼

上位機實施步驟:

cd /opt/arm/03/1.0

arm-cortex_a9-linux-gnueabi-objdump -D led.elf > led.dis

說明:

arm-cortex_a9-linux-gnueabi-objdump:反彙編命令,將elf可執行檔案生成對應的彙編檔案

led.elf:反彙編的二進位制檔案

led.dis:反彙編以後的彙編檔案

     

vim led.dis //開啟反彙編檔案

目前只需看一條資訊即可:

48000000 <led_test>: //led_test函式對應的地址為0x48000000

每次go0x48000000:讓CPU跑到0x48000000執行,本質就是讓CPU執行led_test函式

//繼續驗證反彙編

cd /opt/arm/03/1.0

vim led.c //將delay函式的定義放在led_test函式定義的前面

儲存退出

arm-cortex_a9-linux-gnueabi-gcc -nostdlib -c -o led.o led.c

arm-cortex_a9-linux-gnueabi-ld -nostartfiles -nostdlib-Ttext=0x48000000 -o led.elf led.o

arm-cortex_a9-linux-gnueabi-objdump -D led.elf > led.dis

 

vim led.dis

獲得以下資訊

48000000 <delay>: //0x48000000這個地址對應的函式為delay函式

也就是將來go0x48000000,是讓CPU執行delay函式

結論:連結(ld)的時候從檔案的開頭開始連結!

切記:將來最好用objdump反彙編確保入口函式的地址是否是0x48000000