姓名:李萌怡? 學(xué)號:19020100103? 學(xué)院:電子工程學(xué)院
轉(zhuǎn)自:https://blog.csdn.net/weixin_44839882/article/details/108468131
【嵌牛導(dǎo)讀】:嵌入式系統(tǒng)分為硬件層氧急、驅(qū)動層、操作系統(tǒng)層和應(yīng)用層。要深入學(xué)習(xí)嵌入式系統(tǒng)班巩,應(yīng)用層開發(fā)是非常重要的部分亮钦。
【嵌牛鼻子】:應(yīng)用層? 文件結(jié)構(gòu)
【嵌牛提問】:Linux的文件結(jié)構(gòu)分為哪幾部分赫蛇?
【嵌牛正文】
1 應(yīng)用層與驅(qū)動層
要想學(xué)習(xí)嵌入式Linux應(yīng)用層的開發(fā)酷麦,首先要區(qū)分好應(yīng)用層和驅(qū)動層之間的關(guān)系甚负。我們在本科階段學(xué)習(xí)51等較簡單的單片機(jī)時霎挟,都是把應(yīng)用層和驅(qū)動層混在一個文件里寫的窝剖。比如拿下面的I2C程序為例:
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define nop _nop_()
sbit sda = P2^1;//sda接在P2.1 ?
sbit scl = P2^0;//sda接在P2.0
void delay1()//用于每個語句間的延時
{
;//空語句
;
;
}
void delay(unsigned int i )//用于LED亮燈延時
{
while(i--);
}
/*scl在高電平期間,sda由高電平變成低電平時酥夭,I2C啟動*/
void start_24c02() ? //用于24C02的啟動
{
scl = 1;
delay1(); ?
sda = 1;
delay1();
sda = 0;
delay1();
}
/*scl在高電平期間赐纱,sda由低電平變成高電平時,I2C停止*/
void stop_24c02() //用于24c02啟動
{
sda = 0;
delay1();
scl = 1;
delay1();
sda = 1;
delay1();
}
/*scl在高電平期間熬北,sda變成低電平表示應(yīng)答*/
void ack_24c02() //24C02的應(yīng)答
{
uchar i = 0;
scl = 1;
delay1();
while((sda ==1)&&(i<200)) //(i<200)表示:如果期間不給應(yīng)答信號疙描,則程序會一直停在這里,為了避免長時間的等待應(yīng)答讶隐,在此處增加了一個延時
{
i++;
}
scl = 0;
delay1();
}
/*I2C總線初始化起胰,將I2C總線全部設(shè)置為高電平,來釋放總線*/
void init_24c02()//I2C總線的初始化
{
sda = 1;
delay1();? ?
scl = 0;
delay1();
}
/*讀取一個字節(jié)*/
uchar read_onebyte_24c02()
{
uchar i,date;
scl=0;
delay1();
sda=1;
delay1();
for(i = 0;i<8;i++) ? ? ? ? ? ?
{
scl = 1; ?
delay1();
date=(date<<1)|sda; ? ?
scl = 0;
delay1();
}
delay1();
return date;
}
/*寫一個字節(jié)*/
void write_onebyte_24c02(uchar date)
{
uchar i,temp;
temp = date;
for(i=0;i<8;i++)
{
temp = temp<<1;
scl = 0;
delay1();
sda =CY;? //temp 左移一位巫延,將移出的最高位字節(jié)放到PSW的CY中
delay1();
scl = 1;
delay1();
}
scl = 0;
delay1();
sda = 1;
delay1();
}
/*對從機(jī)的某一地址的某一位置寫入一個字節(jié)
1效五、找到要操作地址的從機(jī),同時進(jìn)行寫操作0xA0
2烈评、要寫入的位置add
3火俄、要寫入的數(shù)據(jù)dat
*/
void write_add_dat_24c02(uchar add,uchar dat)
{
start_24c02();
write_onebyte_24c02(0xA0); //進(jìn)行寫操作0XA0,24C02 的高四位地址為1010;后三位地址A2讲冠、A1瓜客、A0全部接地,所以為000,竿开;由于為寫操作谱仪,所以最后一位也為0
ack_24c02();
write_onebyte_24c02(add);
ack_24c02();
write_onebyte_24c02(dat);
ack_24c02();
stop_24c02();
}
/*讀取某地址的一個字節(jié)
1、找到要操作地址的從機(jī)否彩,同時進(jìn)行寫操作0xA0
2疯攒、要寫入的地址add
3、對選中地址的從機(jī)進(jìn)行讀操作 0xA1
4列荔、調(diào)用讀取一個字節(jié)函數(shù)read_onebyte_24c02()敬尺,進(jìn)行數(shù)據(jù)讀取
*/
uchar read_add_dat_24c02(uchar add)
{
uchar dat;
start_24c02();
write_onebyte_24c02(0xa0);
ack_24c02();
write_onebyte_24c02(add);
ack_24c02();
start_24c02();
write_onebyte_24c02(0xa1); //進(jìn)行讀操作0XA0,24C02 的高四位地址為1010枚尼;后三位地址A2、A1砂吞、A0全部接地署恍,所以為000,;由于為讀操作蜻直,所以最后一位為1
ack_24c02();
dat = read_onebyte_24c02();
ack_24c02();
stop_24c02();
return (dat);
}
void main()
{
init_24c02(); //初始化I2C
while(1)
{
write_add_dat_24c02(3,0x0f); //對地址3進(jìn)行寫入數(shù)據(jù)
delay(200);
write_add_dat_24c02(4,0xf0); //對地址4進(jìn)行寫入數(shù)據(jù)
delay(200);
P3 = read_add_dat_24c02(3); //讀取地址3的數(shù)據(jù)
delay(55000); //保持燈亮
P3 = read_add_dat_24c02(4); //讀取地址4的數(shù)據(jù)
delay(55000); //保持燈亮
}
}
該程序所要實現(xiàn)的功能是將數(shù)據(jù)0x0f和0xf0分別寫入地址3和地址4盯质。這個目標(biāo)可以分為兩部分執(zhí)行:第一部分是計算出要存儲的數(shù)據(jù)(由于該程序要存儲的數(shù)據(jù)已經(jīng)給出來了,就不用算了概而,但在實際工程中呼巷,這些數(shù)據(jù)一般是要自己獲取的),第二部分是按照I2C協(xié)議的時序?qū)⑦@些數(shù)據(jù)發(fā)送給硬件赎瑰。于是王悍,上面提到的第一部分被稱為應(yīng)用層開發(fā),第二部分被稱為驅(qū)動層開發(fā)乡范。
我們觀察以上示例代碼配名,發(fā)現(xiàn)作者還是很規(guī)矩地把驅(qū)動層程序編程了函數(shù)的形式(例如write_add_dat_24c02()),但應(yīng)用層和驅(qū)動層的程序終究還是存儲在同一個c文件中晋辆。而在Linux系統(tǒng)中渠脉,驅(qū)動層和應(yīng)用層分的很清楚,它們分別保存在兩個不同的文件中瓶佳。并且應(yīng)用層的程序運行在用戶空間中芋膘,驅(qū)動層的程序則是被編進(jìn)了Linux內(nèi)核里。在實際調(diào)用程序的過程中霸饲,由應(yīng)用層程序執(zhí)行數(shù)據(jù)計算等任務(wù)为朋,任務(wù)執(zhí)行完后通過一個接口將算好的數(shù)據(jù)發(fā)送給驅(qū)動層程序,最后由驅(qū)動層程序進(jìn)行硬件實現(xiàn)厚脉。這樣的分層有一個好處习寸,就是對于調(diào)用同一個硬件的應(yīng)用程序,他的驅(qū)動層可以不用修改傻工,只修改應(yīng)用層程序就可以了霞溪。
由于Linux操作系統(tǒng)現(xiàn)在發(fā)展的已經(jīng)比較完善了,很多硬件設(shè)備都能在網(wǎng)上找到寫好的驅(qū)動中捆,因此在進(jìn)行嵌入式Linux開發(fā)的過程中鸯匹,一般更多地進(jìn)行應(yīng)用層的開發(fā),只是當(dāng)找不到合適的驅(qū)動時泄伪,才會在現(xiàn)有驅(qū)動程序的基礎(chǔ)上進(jìn)行適當(dāng)改寫殴蓬,以使其適應(yīng)我們的硬件。
2 Linux的文件結(jié)構(gòu)
Linux下一切皆文件蟋滴。在Linux系統(tǒng)中染厅,不僅像文本文檔等傳統(tǒng)文件是文件痘绎,各種設(shè)備也可以被映射成一個文件。通過對設(shè)備文件進(jìn)行操作就可以實現(xiàn)對設(shè)備的操作肖粮。因此简逮,了解Linux的文件結(jié)構(gòu)非常重要。
2.1 目錄
目錄是用來保存其他文件節(jié)點(inode)號和名字的文件尿赚,目錄文件中的每項數(shù)據(jù)都指向一個文件的節(jié)點,刪除一個文件就相當(dāng)于刪除了目錄文件中對應(yīng)的節(jié)點項蕉堰。
那么問題來了凌净,什么是文件的節(jié)點(inode)呢?文件節(jié)點其實就是保存了文件的屬性的一個東西屋讶,這些屬性包括文件的創(chuàng)建/修改日期冰寻、訪問權(quán)限、文件位置皿渗、文件長度等等斩芭。Linux在尋找某文件或?qū)Γ硞€文件進(jìn)行操作時乐疆,不是去尋找文件的名字划乖,而是去尋找文件對應(yīng)的節(jié)點。
Linux系統(tǒng)中最常用的目錄之一就是家目錄挤土。Linux系統(tǒng)會為每個用戶創(chuàng)建一個家目錄琴庵。比如你的用戶名叫neil,那你的家目錄就是/home/neil/仰美。很多Linux系統(tǒng)迷殿,比如Ubuntu,都允許用~ 符號代替用戶的家目錄咖杂。然而庆寺,標(biāo)準(zhǔn)庫函數(shù)不能識別文件參數(shù)中的~ 符號,因此在程序中不要使用波浪線符號代替家目錄诉字。
所有目錄的最頂層是根目錄懦尝。在它下面包含了存放系統(tǒng)程序的/bin目錄、存放系統(tǒng)配置文件的/etc目錄奏窑、存放系統(tǒng)函數(shù)庫的/lib目錄和存放代表物理設(shè)備的設(shè)備文件的/dev目錄等等导披。
2.2 文件和設(shè)備
在Linux中,設(shè)備可以被映射成一個文件埃唯。例如撩匕,我們可以使用以下命令將CD-ROM驅(qū)動掛載為一個文件:
mount -t iso9660 /dev/hdc /mnt/cdrom
cd /mnt/cdrom
這時我們進(jìn)入到/mnt/cdrom下就可以查看CD-ROM中包含的目錄,只不過其中的目錄都是只讀的墨叛。
Linux中有3個比較重要的設(shè)備文件:/dev/console止毕、/dev/tty和/dev/null模蜡。
/dev/console
這個設(shè)備代表系統(tǒng)控制臺。錯誤信息和診斷信息通常會被發(fā)到這個設(shè)備扁凛。
/dev/tty
如果一個進(jìn)程有控制終端的話忍疾,文件/dev/tty就會作為控制終端的別名。但對于系統(tǒng)自動運行的進(jìn)程和腳本谨朝,它們就沒有控制終端卤妒,不需要訪問設(shè)備/dev/tty。
/dev/null
這個設(shè)備是“空”設(shè)備字币,所有寫向這個設(shè)備的輸出都會被丟棄则披,而讀這個設(shè)備會返回一個文件尾標(biāo)志。通常用于作復(fù)制空文件的源文件洗出,或?qū)⒉恍枰妮敵鲋囟ㄏ虻酱宋募?/p>
設(shè)備可以分為字符設(shè)備和塊設(shè)備士复,兩者的區(qū)別在于訪問設(shè)備時是否需要一次讀寫一整塊。字符設(shè)備通常是普通的設(shè)備翩活,塊設(shè)備通常是硬盤阱洪、SD卡等存儲設(shè)備。
————————————————
版權(quán)聲明:本文為CSDN博主「畢浩然」的原創(chuàng)文章菠镇,遵循CC 4.0 BY-SA版權(quán)協(xié)議冗荸,轉(zhuǎn)載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/weixin_44839882/article/details/108468131