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