第一課:裝置樹的引入與體驗(基於linux4.19核心版本)
本套視訊面向如下三類學員:
- 有Linux驅動開發基礎的人, 可以挑感興趣的章節觀看;
- 沒有Linux驅動開發基礎但是願意學習的人,請按順序全部觀看,我會以比較簡單的LED驅動為例講解;
- 完全沒有Linux驅動知識,又不想深入學習的人, 比如應用開發人員,不得已要改改驅動, 等全部錄完後,我會更新本文件,那時再列出您需要觀看的章節。
第01節_字元裝置的三種寫法
怎麼寫驅動?
①看原理圖:
a.確定引腳;
b.看晶片手冊,確定如何操作引腳;
②寫驅動程式;
起封裝作用;
③寫測試程式;
如下原理圖,VCC經過一個限流電阻到達LED的一端,再通向晶片的引腳上。
當晶片引腳輸出低電平時,電流從高電平流向低電平,LED燈點亮;
當晶片引腳輸出高電平時,沒有電勢差,沒有電流流過,LED燈不亮;
從原理圖可以看出,控制了晶片引腳,就等於控制了燈。
在Linux裡,操作硬體都是統一的介面,比如操作LED燈,需要先open,如果要讀取LED狀態就呼叫read,如果要操作LED就呼叫write函式,也可以通過ioctl去實現。
在驅動裡,針對前面應用的每個呼叫函式,都寫一個對應的函式,實現對硬體的操作。
可以看出驅動程式起封裝作用,它讓應用程式訪問硬體變得簡單,遮蔽了硬體更加複雜的操作。
如何寫驅動程式?
①分配一個file_operations結構體;
②設定:
a. .open=led_open;把led引腳設定為輸出引腳
b. .read=led_read;根據APP傳入的值設定引腳狀態
③註冊(告訴核心),register_chrdev(主裝置號,file_operations,name)
④入口函式
⑤出口函式
在驅動中如何指定LED引腳?
有如下三種方法:
①傳統方法:在程式碼led_drv.c中寫死;
②匯流排裝置驅動模型:
a. 在led_drv.c裡分配、註冊、入口、出口等
b. 在led_dev.c裡指定引腳
③使用裝置樹指定引腳
a. 在led_drv.c裡分配、註冊、入口、出口等
b. 在jz2440.dts裡指定引腳
可以看到,’’‘無論何種方法,驅動寫法的核心不變,差別在於如何指定硬體資源’’’。
對比下三種方法的優缺點。
假設這樣一個情況,某公司用同一個晶片做了兩款產品,其中一款是TV(電視盒子),使用Pin1作為LED的指示燈控制引腳,其中一款是Cam(監控攝像頭),使用Pin2作為LED的指示燈控制引腳。
TV裝置 | Cam裝置 | 優缺點 | |
---|---|---|---|
1.傳統方法 | led_drv.c ①分配一個file_operations結構體; ②設定: a .open=led_open;設定Pin1為輸出引腳 b .read=led_read;根據APP傳入的值設定引腳狀態 ③註冊(告訴核心) ④入口函式 ⑤出口函式 | led_drv.c ①分配一個file_operations結構體; ②設定: a. .open=led_open;設定Pin2為輸出引腳 b. .read=led_read;根據APP傳入的值設定引腳狀態 ③註冊(告訴核心) ④入口函式 ⑤出口函式 | 優點:簡單 缺點:不易擴充套件,需要重新編譯 |
2.匯流排裝置驅動模型 | led_drv.c ①分配/設定/註冊 platform_driver; ② .probe: a 分配一個file_operations結構體; b .open=led_open;設定平臺裝置總指定的引腳為輸出引腳 .read=led_read;根據APP傳入的值設定引腳狀態 c註冊 ③ .driver{ .name } led_dev.c ①分配/設定/註冊 platform_device; ② .resource:指定引腳;,name為Pin1 | led_dev.c ①分配/設定/註冊 platform_driver; ② .resource:指定引腳;,name為Pin2 | 優點:易擴充套件 缺點:稍複雜,冗餘程式碼太多,需要重新編譯 |
3.裝置樹 | led_drv.c ①分配/設定/註冊 platform_driver; ② .probe: a 分配一個file_operations結構體; b .open=led_open;設定平臺裝置總指定的引腳為輸出引腳 .read=led_read;根據APP傳入的值設定引腳狀態 c註冊 ③ .driver{ .name } .dts指定資源 核心根據dts生成的dtb檔案分配/設定/註冊platform_device | .dts指定資源 核心根據dts生成的dtb檔案分配/設定/註冊platform_device | 優點:易擴充套件 缺點:稍複雜,冗餘程式碼太多,需要重新編譯 |
第02節_字元裝置驅動的傳統寫法
在上一節視訊裡我們介紹了三種編寫驅動的方法,也對比了它們的優缺點,後面我們將使用比較快速的方法寫出驅動程式,因為寫驅動程式不是我們這套視訊的重點,所以儘快的把驅動程式寫出來,給大家展示一下。
這節視訊我們使用傳統的方法編寫字元驅動程式,以最簡單的點燈驅動程式為示例。
先回顧下寫字元裝置驅動的五個步驟:
1.2.3.分配/設定/註冊file_operations
4.入口
5.出口
所謂分配file_operations,我們可以定義一個file_operations結構體,就不需要分配了。
static struct file_operations myled_oprs = {
.owner = THIS_MODULE, //表示這個模組本身
.open = led_open,
.write = led_write,
.release = led_release,
};
定義好了file_operations結構體,再去入口函式註冊結構體。
static int myled_init(void)
{
major = register_chrdev(0, "myled", &myled_oprs);
return 0;
}
第一個引數:主裝置號寫0,讓系統為我們分配;
第二個引數:設定名字,沒有特殊要求;
第三個引數:file_operations結構體;
對應的出口操作進行相反向操作:
static void myled_exit(void)
{
unregister_chrdev(major, "myled");
}
然後用巨集module_init對入口、出口函式進行修飾,表示它們和普通函式不一樣:
module_init(myled_init);
module_exit(myled_exit);
module_init(myled_init)
實際就是int init_module(void) attribute((alias(“myled_init”)))
,表示myled_init
的別名是init_module
,以後就可以使用init_module
來引用myled_init
。
此外,還要加上GPL協議:
MODULE_LICENSE("GPL");
寫到這裡,驅動程式的框架已經搭建起來了,接下來實現具體的硬體操作函式:led_open()和led_write()。
在led_open()裡把對應的引腳配置為輸出引腳,在led_write()根據應用程式傳入的資料點燈,讓其輸出高電平或低電平。
為了讓程式更具有擴充套件性,把GPIO的暫存器放在一個數組裡:
static unsigned int gpio_base[] = {
0x56000000, /* GPACON */
0x56000010, /* GPBCON */
0x56000020, /* GPCCON */
0x56000030, /* GPDCON */
0x56000040, /* GPECON */
0x56000050, /* GPFCON */
0x56000060, /* GPGCON */
0x56000070, /* GPHCON */
0, /* GPICON */
0x560000D0, /* GPJCON */
};
定義好了引腳的組,還得確定使用該組的哪個引腳,使用巨集來確定哪個引腳:
#define S3C2440_GPA(n) (0<<16 | n)
#define S3C2440_GPB(n) (1<<16 | n)
#define S3C2440_GPC(n) (2<<16 | n)
#define S3C2440_GPD(n) (3<<16 | n)
#define S3C2440_GPE(n) (4<<16 | n)
#define S3C2440_GPF(n) (5<<16 | n)
#define S3C2440_GPG(n) (6<<16 | n)
#define S3C2440_GPH(n) (7<<16 | n)
#define S3C2440_GPI(n) (8<<16 | n)
#define S3C2440_GPJ(n) (9<<16 | n)
後面就可以向對應巨集傳入對應位,得到對應組的對應引腳。
檢視原理圖,知道我們要使用的引腳是GPF5,因此定義 led_pin = s3c2440_GPF(5)。
static int led_open (struct inode *node, struct file *filp)
{
/* 把LED引腳配置為輸出引腳 */
/* GPF5 - 0x56000050 */
int bank = led_pin >> 16;
int base = gpio_base[bank];
int pin = led_pin & 0xffff;
gpio_con = ioremap(base, 8);
if (gpio_con) {
printk("ioremap(0x%x) = 0x%x\n", base, gpio_con);
}
else {
return -EINVAL;
}
gpio_dat = gpio_con + 1;
*gpio_con &= ~(3<<(pin * 2));
*gpio_con |= (1<<(pin * 2));
return 0;
}
在Linux中,不能直接操作基地址,需要使用ioremap()對映。
對於基地址,定義全域性指標來表示,gpio_con表示控制暫存器,gpio_dat表示資料暫存器。
這裡將GPF5的第二個引腳先清空,再設定為1,表示輸出引腳。
接下來是寫函式:
static ssize_t led_write (struct file *filp, const char __user *buf, size_t size, loff_t *off)
{
/* 根據APP傳入的值來設定LED引腳 */
unsigned char val;
int pin = led_pin & 0xffff;
copy_from_user(&val, buf, 1);
if (val)
{
/* 點燈 */
*gpio_dat &= ~(1<<pin);
}
else
{
/* 滅燈 */
*gpio_dat |= (1<<pin);
}
return 1; /* 已寫入1個數據 */
}
注意這裡的__user巨集起強調作用,告訴你buf來自應用空間,在核心裡不能直接使用。
使用copy_from_user()將使用者空間的資料拷貝到核心空間。
再根據傳入的值,設定gpio_dat的值,來點亮或者熄滅pin所對應的燈。
至此,這個驅動程式已經具備操作硬體的功能,但我們還要增加一些內容,比如我們先註冊驅動後,自動建立節點資訊。
在入口函式裡,使用class_create()建立class,並且使用device_create()建立裝置。
static int myled_init(void)
{
major = register_chrdev(0, "myled", &myled_oprs);
led_class = class_create(THIS_MODULE, "myled");
device_create(led_class, NULL, MKDEV(major, 0), NULL, "led"); /* /dev/led */
return 0;
}
出口函式需要進行相反操作:
static void myled_exit(void)
{
unregister_chrdev(major, "myled");
device_destroy(led_class, MKDEV(major, 0));
class_destroy(led_class);
}
還有在release函式裡,釋放前面的iormap()的資源
static int led_release (struct inode *node, struct file *filp)
{
printk("iounmap(0x%x)\n", gpio_con);
iounmap(gpio_con);
return 0;
}
最後把以前的測試程式拷貝過來,簡單修改一下,見網盤led_driver/001_led_drv_traditional/ledtest.c
。
可以看出,這種傳統寫驅動程式的方法把硬體資源寫在了程式碼裡,換個LED,換個引腳,就得去修改 led_pin = s3c2440_GPF(5)
,然後重新編譯,載入。
第03節_字元裝置驅動的編譯測試
這節課來講解一下測試和編譯的過程。
驅動程式的編譯依賴於核心,在驅動程式裡的一堆標頭檔案,是來自於核心的,因此我們需要先編譯核心。
接下來我們要編譯驅動程式,編譯測試程式,並在單板上測試一樣。
首先從網盤下載:
doc_and_sources_for_device_tree/source_and_images/source_and_images
下的核心原始碼和補丁;
doc_and_sources_for_device_tree/source_and_images/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi.tar.xz
編譯核心和驅動的交叉編譯工具鏈;
doc_and_sources_for_device_tree/source_and_images/arm-linux-gcc-4.3.2.tar.bz2
編譯測試程式的交叉編譯工具鏈;
doc_and_sources_for_device_tree/source_and_images/readme.txt
介紹了一些編譯器、工具的使用、uboot等筆記,需要時可以看一看;
1.編譯核心
將核心原始碼、補丁、編譯核心的交叉工具鏈上傳到Ubuntu,然後解壓、打補丁。
再解壓工具鏈,設定工具鏈環境,最後編譯。
編譯中遇到錯誤提示,嘗試百度搜索,一般都能找到解決方法。
2.編譯驅動
待核心編譯完後,修改Makefile,編譯驅動。
3.編譯應用程式
解壓編譯應用程式的交叉編譯工具鏈,修改環境變數,編譯應用程式。
4.載入驅動和執行測試程式
使用nfs掛載該目錄,載入驅動,執行測試程式。
第04節_匯流排裝置驅動模型
匯流排驅動模型是為了解決什麼問題呢?
- 使用之前的驅動模型,編寫一個led驅動程式,如果需要修改gpio引腳,則需要修改驅動原始碼,重新編譯驅動檔案,假如驅動放在核心中,則需要重新編譯核心
bus匯流排是虛擬的概念,並非硬體,dev註冊設定某個結構體,這個裝置也就是平臺裝置
struct platform_device {
const char *name;
int id;
bool id_auto;
struct device dev;
u32 num_resources;
/*resource 裡面確定使用那些資源*/
struct resource *resource;
const struct platform_device_id *id_entry;
char *driver_override; /* Driver name to force a match */
/* MFD cell pointer */
struct mfd_cell *mfd_cell;
/* arch specific additions */
struct pdev_archdata archdata;
};
drv那面定義platform_driver 去註冊
struct platform_driver {
int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*resume)(struct platform_device *);
struct device_driver driver;
const struct platform_device_id *id_table;
bool prevent_deferred_probe;
};
裝置和驅動如何進行通訊呢
*通過bus進行匹配 platform_match函式確定(dev,drv)若匹配則呼叫drv中的probe函式
struct bus_type platform_bus_type = {
.name = "platform",
.dev_groups = platform_dev_groups,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};
這種模型只是一種程式設計技巧一種機制
並不是驅動程式的核心
platform_match是如何判斷dev drv是匹配的?
判斷方法是比較dev 和drv 各自的name來進行匹配
- 平臺裝置platform_device這面有name
- platform_driver這面有 driver (裡面含有name) 還有id_table(包含 name driver_data)
- id_table裡面的內容表示所支援一個或多個的裝置名
static int platform_match(struct device *dev, struct device_driver *drv)
{
/*省略部分無用程式碼*/
/* Then try to match against the id table */
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;
/* fall-back to driver name match */
return (strcmp(pdev->name, drv->name) == 0);
}
也就是優先比較 id_table中名字,如果沒有則對比driver中名字
- 根據二期視訊led程式碼進行修改
/* 分配/設定/註冊一個platform_device */
/*設定資源*/
static struct resource led_resource[] = {
[0] = {
/*指明瞭使用那個引腳*/
.start = S3C2440_GPF(5),
/*end並不重要,可以隨意指定*/
.end = S3C2440_GPF(5),
.flags = IORESOURCE_MEM,
},
};
static void led_release(struct device * dev)
{
}
static struct platform_device led_dev = {
.name = "myled",
.id = -1,
.num_resources = ARRAY_SIZE(led_resource),
.resource = led_resource,
.dev = {
.release = led_release,
},
};
/*入口函式去註冊平臺裝置*/
static int led_dev_init(void)
{
platform_device_register(&led_dev);
return 0;
}
/*出口函式去釋放這個平臺裝置*/
static void led_dev_exit(void)
{
platform_device_unregister(&led_dev);
}
module_init(led_dev_init);
module_exit(led_dev_exit);
- led_drv驅動檔案
static int led_probe(struct platform_device *pdev)
{
struct resource *res;
/* 根據platform_device的資源進行ioremap */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
led_pin = res->start;
major = register_chrdev(0, "myled", &myled_oprs);
led_class = class_create(THIS_MODULE, "myled");
device_create(led_class, NULL, MKDEV(major, 0), NULL, "led"); /* /dev/led */
return 0;
}
struct platform_driver led_drv = {
.probe = led_probe,
.remove = led_remove,
.driver = {
.name = "myled",
}
};
static int myled_init(void)
{
platform_driver_register(&led_drv);
return 0;
}
static void myled_exit(void)
{
platform_driver_unregister(&led_drv);
}
Makefile檔案
KERN_DIR = /work/system/linux-4.19-rc3
all:
make -C $(KERN_DIR) M=`pwd` modules
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order
obj-m += led_drv.o
obj-m += led_dev.o
執行測試程式
如果我需要更換一個led
則只需要修改 led_dev led_resource結構體中的引腳即可
static struct resource led_resource[] = {
[0] = {
.start = S3C2440_GPF(6),
.end = S3C2440_GPF(6),
.flags = IORESOURCE_MEM,
},
};
裝置和驅動的匹配是如何完成的?
- dev這面有裝置連結串列
- drv這面也有驅動的結構體連結串列
- 通過match函式進行對比,如果相同,則呼叫drv中的probe函式
第05節_使用裝置樹時對應的驅動程式設計
-
本節介紹怎麼使用裝置樹怎麼編寫對應的驅動程式
-
只是平臺裝置的構建區別,以前構造平臺裝置是在.c檔案中,使用裝置樹構造裝置節點原本不存在,需要在dts檔案中構造節點,節點中含有資源
-
dts被編譯成dtb檔案傳給核心,核心會處理解析dtb檔案得到device_node結構體,之後變成platform_device結構體,裡面含有資源(資源來自dts檔案)
-
我們定義的led裝置節點
led {
compatible = "jz2440_led";
reg = <S3C2410_GPF(5) 1>;
};
- 以後就使用compatible找到核心支援這個裝置節點的平臺driver
reg = <S3C2410_GPF(5) 1>;
就是暫存器地址的對映
修改好後編譯 裝置樹檔案 make dtb
拷貝到tftp資料夾,開發板啟動
- 進入
/sys/devices/platform
目錄檢視是否有5005.led平臺裝置資料夾
- 檢視 reg 的地址,這裡面是以大位元組須來描述這些值的
這個屬性有8個位元組,對應兩個數值
- 第一個值S3C2410_GPF(5)是我們的起始地址,對應 #define S3C2410_GPF(_nr) ((5<<16) + (_nr))
- 第二個值1 本意是指暫存器的大小
如何去寫平臺驅動?
通過bus匯流排去匹配裝置驅動
在 platform_match函式中,通過
/* Attempt an OF style match first */
if (of_driver_match_device(dev, drv))
return 1;
進入 of_device.h中
/**
* of_driver_match_device - Tell if a driver's of_match_table matches a device.
* @drv: the device_driver structure to test
* @dev: the device structure to match against
*/
static inline int of_driver_match_device(struct device *dev,
const struct device_driver *drv)
{
return of_match_device(drv->of_match_table, dev) != NULL;
}
of_match_table結構體
include\linux\mod_devicetable.h
/*
* Struct used for matching a device
*/
struct of_device_id {
char name[32];
char type[32];
char compatible[128];
const void *data;
};
- compatible 也就是從dts得到的platform_device裡有compatible 屬性,兩者進行對比,一樣就表示匹配
- 寫led驅動,修改led_drv.c
- 新增
static const struct of_device_id of_match_leds[] = {
{ .compatible = "jz2440_led", .data = NULL },
{ /* sentinel */ }
};
*修改
struct platform_driver led_drv = {
.probe = led_probe,
.remove = led_remove,
.driver = {
.name = "myled",
.of_match_table = of_match_leds, /* 能支援哪些來自於dts的platform_device */
}
};
*修改Makefile並編譯
- 如果修改燈怎麼辦?
-
- 直接修改裝置樹中的led裝置節點
led {
compatible = "jz2440_led";
reg = <S3C2410_GPF(6) 1>;
};
上傳編譯,直接使用新的dtb檔案
我們使用另外一種方法指定引腳
led {
compatible = "jz2440_led";
pin = <S3C2410_GPF(5)>;
};
修改led_drv中的probe函式
在of.h中找到獲取of屬性的函式 of_property_read_s32
static int led_probe(struct platform_device *pdev)
{
struct resource *res;
/* 根據platform_device的資源進行ioremap */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res) {
led_pin = res->start;
}
else {
/* 獲得pin屬性 */
of_property_read_s32(pdev->dev.of_node, "pin", &led_pin);
}
if (!led_pin)
{
printk("can not get pin for led\n");
return -EINVAL;
}
major = register_chrdev(0, "myled", &myled_oprs);
led_class = class_create(THIS_MODULE, "myled");
device_create(led_class, NULL, MKDEV(major, 0), NULL, "led"); /* /dev/led */
return 0;
}
- 從新編譯裝置樹 和led驅動檔案
在platform_device結構體中的struct device dev;中對於dts生成的platform_device這裡含有of_node
of_node中含有屬性,這取決於裝置樹,比如compatible屬性
讓後註冊/配置/file_operation
第06節_只想使用裝置樹不想深入研究怎麼辦
寄希望於寫驅動程式的人,提供了文件/示例/程式寫得好適配性強
根據之前寫的裝置樹
led {
compatible = “jz2440_led”;
reg = <S3C2410_GPF(6) 1>;
};
led {
compatible = “jz2440_led”;
pin = <S3C2410_GPF(5)>;
};
可以通過reg指定引腳也可以通過pin指定引腳,我們在裝置樹中如何指定引腳完全取決於驅動程式
既可以獲取pin屬性值也可以獲取reg屬性值
/* 根據platform_device的資源進行ioremap */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res) {
led_pin = res->start;
}
else {
/* 獲得pin屬性 */
of_property_read_s32(pdev->dev.of_node, "pin", &led_pin);
}
if (!led_pin)
{
printk(
相關推薦
第一課:裝置樹的引入與體驗(基於linux4.19核心版本)
本套視訊面向如下三類學員:
有Linux驅動開發基礎的人, 可以挑感興趣的章節觀看;
沒有Linux驅動開發基礎但是願意學習的人,請按順序全部觀看,我會以比較簡單的LED驅動為例講解;
完全沒有Linux驅動知識,又不想深入學習的人, 比如應用開發人員,不得
第一課:linux裝置樹的引入與體驗(基於linux4.19核心版本)
轉載請註明原文地址:http://wiki.100ask.org/Linux_devicetree
本套視訊面向如下三類學員:
有Linux驅動開發基礎的人, 可以挑感興趣的章節觀看;
沒有Linux驅動開發基礎但是願意學習的人,請按順序全部觀看,我會
裝置樹編譯與反彙編
轉載地址:https://blog.csdn.net/fight_onlyfor_you/article/details/74059029
1.編譯最新的核心
第一步 tar -xvf .........解壓核心
第二步 mak
第006課 開發板熟悉與體驗
第001節_開發板介面介紹與串列埠連線
在前面的視訊裡,我們涉及四個介面,兩個開關。
四個介面:電源介面、USB串列埠、USB下載口、JTAG下載口;
兩個開關:電源開關、啟動選擇開關;
分別對應下圖中的1、8、6、7、1、11;
我們買開發板
字元裝置驅動第十一課----裝置樹
介面
1.出處:
include/linux/of.h
2.資料結構:
struct device_node {
const char *name;
const char *type;
phandle phandle;
安卓第一課:android studio 的環境搭建與真機運行以及遇到的問題
自己的 安卓 structure 最好 not found 創建過程 cor 虛擬 col AS的下載:
https://developer.android.com/studio/index.html
AS的安裝:
android studio, sdk, virtual
第一課:安卓模擬器的介紹與應用
pos 模擬器 直接 blog 系統 安卓教程 安卓模擬器 class 腳本 1: 安卓教程 第一:安卓模擬器 。 第二:真機安卓系統。 2: 安卓腳本 第一: 就是外部EXE程序來控制模擬器。 第二: 就是直接用A
爬蟲第一課:正則表示式符號與方法
第一課:正則表示式符號與方法
1.
. :匹配任意字元,換行符除外:
>>> import re
>>> a='xy123'
>>> b=re.findall('x',a)
>>> b
['x']
>
基於Android7.1 8953 高通平臺下零死角玩轉裝置樹DTS
【基於Android7.1 8953 高通平臺下零死角玩轉裝置樹DTS】
更新內容:
【創科之龍_安卓開發】第01課_為什麼引用linux裝置樹和對比優勢
【創科之龍_安卓開發】第02課_如何在Linux-3.x核心
執行緒第一課——程序與執行緒
這節課開始我們進入java的執行緒部分。
首先了解幾個概念: 程式、程序、執行緒。
程式: 就是我們寫的程式碼,是靜態的。
程序: 程式執行的過程,或者說是cpu排程各個程式的過程
執行緒: 一程序為達到併發操
基於python的 樹型資料結構,二叉樹使用與AVL樹使用
樹由n個節點組成的集合,可以遞迴定義資料結構,如果n=0就是空樹 如果n>那麼有樹
概念
根節點、葉子節點
樹的深度(高度)
樹的度
孩子節點、父節點
子樹
二叉樹-遍歷
# 樹型圖示意
E
程式設計師之路:c++:第一課:格式與cout
程式設計師之路
先舉個例子:
#include <iostream>
//匯入iostream庫
using namespace std;
//宣告名稱空間
int main()
2018智慧樹慕課 智慧樹大學生創業概論與實踐單元測試期末答案
2017秋季 選修課智慧樹大學生創業概論與實踐答案單元測試答案 1 【單選題】(5分) 創業是一門關乎實踐的課程,因此不需要學習。A A. 錯誤 B. 正確 2 【多選題】(5分) 創業過程中遇到困難和挫折的時候應該:CD A. 主動放棄 B. 執迷不悟 C. 不斷反思 D. 咬牙堅持 3
Python第一課:Pythonan安裝、PyCharm專業版的安裝與破解
之所以寫部落格,主要目的是自己學習過程中的一些筆記,方便複習用,此外,也可以與同行的朋友一起交流。接觸了挺久的Python,這是第一次寫部落格,哈哈!
首先是Python的安裝,可以直接安裝Python,強烈建議安裝python3。官方網址如下(https://ww
x4412 基於裝置樹的 hello_world驅動
首先在exynos4412-x4412.dts檔案中新增HelloWorld節點,如下:
HelloWorld {
compatible = "x4412, hello_world";
status = "okay";
};
然後新建一
jquery與php互動的ajax應用第一課:檢測使用者註冊時使用者名稱是否存在
當用戶註冊需要知道這個使用者名稱是否被人使用所以需要在使用者登陸前判斷
為了使使用者得到更好的體驗,我們使用了jquery的ajax效果,來使用者名稱是否存在。
首先需要一個新增年級的頁面,暫時叫grade.htm
這個檔案需要引入兩個檔案jquery.js(jquery
第六課:在LCD驅動中使用裝置樹
按照計劃,本課會講解修改uboot和核心讓JZ2440支援裝置樹。
但前面修改uboot已經講解完了,修改核心也沒必要單獨講,可以直接看核心補丁,修改的方法也並不複雜。
核心補丁路徑:
doc_and_sources_for_device_tree/sourc
基於裝置樹下gpio的簡單操作
目標: 學習裝置樹中GPIO資源的使用,實現按鍵中斷簡單驅動程式。原理圖: tiny4412 底板上有4顆按鍵,分別為連線在 GPX3_2、GPX3_3、GPX3_4、GPX3_5 ,引腳狀態常高。裝置樹: interrupt_demo: interrupt_demo
基於裝置樹的GPIO驅動(通過系統節點控制)
#include <linux/types.h>
#include <linux/pm.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/init.h>
#inclu
第三課:linux核心對裝置樹的處理
這一課是裝置樹中最重要的一課。
前面我們從核心文件瞭解到,對於裝置樹,它裡面描述的資訊可以分為這三部分:
Linux uses DT data for three major purposes:
platform identification,
runtim