国产日韩欧美一区二区三区三州_亚洲少妇熟女av_久久久久亚洲av国产精品_波多野结衣网站一区二区_亚洲欧美色片在线91_国产亚洲精品精品国产优播av_日本一区二区三区波多野结衣 _久久国产av不卡

?

基于Qt的多線程嵌入式系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)

2017-03-25 16:48向明尚張志華潘麗艷
科技與創(chuàng)新 2017年4期
關(guān)鍵詞:驅(qū)動(dòng)程序嵌入式系統(tǒng)

向明尚++張志華++潘麗艷

摘 要:以飛凌6410開發(fā)板上的外部設(shè)備為例,介紹了GPIO工作原理,講解了Linux字符驅(qū)動(dòng)程序的工作原理和設(shè)計(jì)步驟,介紹了Linux內(nèi)核模塊設(shè)計(jì)、編譯、加載和卸載等的實(shí)現(xiàn)方法,闡述了嵌入式系統(tǒng)圖形用戶界面Qt的應(yīng)用和多線程工作機(jī)制,給出了軟硬件的設(shè)計(jì)方法,以完成多線程嵌入式控制系統(tǒng)的設(shè)計(jì)。

關(guān)鍵詞:字符設(shè)備;驅(qū)動(dòng)程序;多線程;嵌入式系統(tǒng)

中圖分類號(hào):TP368.1 文獻(xiàn)標(biāo)識(shí)碼:A DOI:10.15913/j.cnki.kjycx.2017.04.011

嵌入式系統(tǒng)被廣泛應(yīng)用于航天、航空、鐵路、公路、汽車和家居生活等各個(gè)領(lǐng)域。系統(tǒng)中有大量的外部設(shè)備,比如用于測(cè)量溫度、壓力、流量和速度等的傳感器,以及馬達(dá)、電機(jī)等執(zhí)行機(jī)構(gòu)。這些外部設(shè)備往往需要協(xié)同、并行工作,即所謂的多任務(wù)、實(shí)時(shí)系統(tǒng),對(duì)系統(tǒng)的設(shè)計(jì)有較高的要求。設(shè)計(jì)系統(tǒng)時(shí),既要考慮每一個(gè)外部硬件設(shè)備能夠可靠工作,又要考慮多個(gè)設(shè)備之間的資源共享,所以,軟件、硬件系統(tǒng)的設(shè)計(jì)要考慮到多任務(wù)、實(shí)時(shí)性的要求。Linux操作系統(tǒng)因其多任務(wù)、實(shí)時(shí)性的特點(diǎn),被廣泛應(yīng)用于嵌入式系統(tǒng)的設(shè)計(jì)中。Qt作為一種基于C++跨平臺(tái)GUI系統(tǒng),能夠?yàn)橛脩籼峁?gòu)造圖形界面的強(qiáng)大功能,提供豐富的多線程支持,并被應(yīng)用于嵌入式系統(tǒng)的GUI設(shè)計(jì)中。本文基于Linux+Qt,實(shí)現(xiàn)了多任務(wù)、多線程嵌入式控制系統(tǒng)。

1 字符設(shè)備驅(qū)動(dòng)程序工作原理

對(duì)于嵌入式系統(tǒng)中的外部設(shè)備,有一大類在Linux系統(tǒng)中被定義為字符設(shè)備,它需要專用的設(shè)備驅(qū)動(dòng)程序驅(qū)動(dòng)才能正常工作。Linux設(shè)備驅(qū)動(dòng)程序是為了特定的硬件提供給用戶程序的一組標(biāo)準(zhǔn)化接口,它隱藏了設(shè)備工作的細(xì)節(jié)。它是用來控制和管理硬件設(shè)備、完成數(shù)據(jù)傳送的專用軟件,是用戶的應(yīng)用程序與外部設(shè)備信息交換的橋梁。設(shè)備驅(qū)動(dòng)程序作為操作系統(tǒng)的一部分運(yùn)行在操作系統(tǒng)內(nèi)核中,用戶的應(yīng)用程序通過系統(tǒng)調(diào)用與內(nèi)核打交道,內(nèi)核根據(jù)系統(tǒng)通調(diào)用號(hào)來調(diào)用相應(yīng)的驅(qū)動(dòng)程序所對(duì)應(yīng)的接口函數(shù),實(shí)現(xiàn)對(duì)外部設(shè)備的管理。Linux中字符設(shè)備驅(qū)動(dòng)程序以內(nèi)核模塊的形式編寫,驅(qū)動(dòng)程序的加載方式之一就是采用內(nèi)核模塊方式動(dòng)態(tài)加載,具有靈活、高效的特點(diǎn)。

Linux的字符設(shè)備是能夠像字節(jié)流一樣被訪問的設(shè)備,由字符設(shè)備驅(qū)動(dòng)程序來實(shí)現(xiàn)這種特性。字符設(shè)備驅(qū)動(dòng)程序的設(shè)計(jì),就是實(shí)現(xiàn)設(shè)備的讀寫、控制接口,即實(shí)現(xiàn)Linux的核心結(jié)構(gòu)體file_operation。該結(jié)構(gòu)體是Linux虛擬文件系統(tǒng)的文件接口,其中定義了用于設(shè)備操作的各種接口函數(shù)。在設(shè)計(jì)設(shè)備驅(qū)動(dòng)程序時(shí),只需要實(shí)現(xiàn)結(jié)構(gòu)體中的有關(guān)函數(shù)即可,比如設(shè)備的打開、讀、寫、控制、關(guān)閉所對(duì)應(yīng)的open、read、wtite、ioctl、release等函數(shù),即可像操作普通文件一樣來管理設(shè)備。Linux系統(tǒng)為每一個(gè)設(shè)備分配一個(gè)主設(shè)備號(hào)和次設(shè)備號(hào),驅(qū)動(dòng)程序以主設(shè)備號(hào)、次設(shè)備號(hào)唯一標(biāo)示一個(gè)具體的外設(shè),比如開發(fā)板上的LED、按鍵、蜂鳴器、溫度傳感器和AD轉(zhuǎn)換器,等等。

2 Qt多線程工作機(jī)制

嵌入式系統(tǒng)大多是多任務(wù)、實(shí)時(shí)系統(tǒng),多個(gè)外部設(shè)備同時(shí)并行工作,實(shí)時(shí)性要求比較嚴(yán)格。因?yàn)閷?duì)用戶系統(tǒng)的設(shè)計(jì)要求比較高,所以,引入了多線程技術(shù)。

在Qt系統(tǒng)中,與線程有關(guān)的類是與平臺(tái)無關(guān)的QThread類,提供線程的創(chuàng)建、運(yùn)行、管理等多種方法。線程通QThread類run函數(shù)重載執(zhí)行。應(yīng)用程序要想執(zhí)行自己的線程,需要繼承QThread類,實(shí)現(xiàn)run函數(shù)即可。GUI運(yùn)行主線程,從窗口獲取事件,并分發(fā)給相應(yīng)的組件處理,即實(shí)現(xiàn)主線程、子線程多個(gè)線程之間并發(fā)執(zhí)行,保證系統(tǒng)對(duì)多個(gè)外部設(shè)備的及時(shí)響應(yīng)。為了實(shí)現(xiàn)多個(gè)線程之間的通信,Qt提供了一整套工作機(jī)制。

Qt系統(tǒng)中引入“可重入”“線程安全”的概念來說明函數(shù)與線程之間的關(guān)系?!翱芍厝搿崩^承于C++,它指的是一個(gè)類的函數(shù)在該類的不同實(shí)例上可以被多個(gè)線程調(diào)用,則該類是“可重入”的;“線程安全”指的是不同的線程作用于同一個(gè)實(shí)例上可以正常工作。

Qt提供的信號(hào)和槽機(jī)制支持跨線程連接,方便了GUI主線程與子線程之間的通信,其連接方式有3種:①直接連接。當(dāng)信號(hào)發(fā)出時(shí),對(duì)應(yīng)的槽函數(shù)立即調(diào)用執(zhí)行。槽函數(shù)在發(fā)出信號(hào)的線程中執(zhí)行,而不一定在接收對(duì)象所屬的線程中執(zhí)行。②排隊(duì)連接。信號(hào)發(fā)出后,要等到接收對(duì)象所屬線程的時(shí)間循環(huán)取得控制權(quán)時(shí)再調(diào)用對(duì)應(yīng)的槽函數(shù),并在信號(hào)接收對(duì)象所屬的同一個(gè)線程中執(zhí)行。③自動(dòng)連接。這是Qt默認(rèn)的連接方式。信號(hào)的發(fā)出與接收信號(hào)的對(duì)象在同一個(gè)線程,則工作在直接連接方式,否則工作在排隊(duì)方式。

對(duì)于Qt線程與事件循環(huán)機(jī)制,每個(gè)Qt的線程都有自己的事件循環(huán)。GUI主線程是唯一可以創(chuàng)建Qapplication對(duì)象并調(diào)用exec函數(shù)啟動(dòng)事件循環(huán)的,而其他子線程則通過調(diào)用QTread類的exec函數(shù)啟動(dòng)自己的事件循環(huán)。

3 系統(tǒng)設(shè)計(jì)

系統(tǒng)以飛凌6410開發(fā)板為例,利用其上的外部設(shè)備,比如LED、按鍵、蜂鳴器、溫度傳感器和GPIO等字符設(shè)備來設(shè)計(jì)實(shí)現(xiàn)多線程系統(tǒng)。

3.1 GPIO端口工作原理

GPIO通用輸入/輸出端口。每個(gè)GPIO端口有多個(gè)對(duì)應(yīng)的寄存器,比如配制寄存器、數(shù)據(jù)寄存器等。它們可以通過軟件修改配制寄存器的值,將端口的功能分別配置成輸入、輸出等多種工作方式,而數(shù)據(jù)寄存器則用于保存端口數(shù)據(jù)。當(dāng)端口配置成輸入功能時(shí),可以讀取數(shù)據(jù)寄存器得到1個(gè)二進(jìn)制數(shù)值,它的每一位1,0分別代表1個(gè)引腳電平的高、低;當(dāng)端口配置成輸出功能時(shí),可以寫入1個(gè)二進(jìn)制數(shù)值到數(shù)據(jù)寄存器,它的每一位1,0分別控制1個(gè)引腳輸出高、低電平。

3.2 驅(qū)動(dòng)程序設(shè)計(jì)

以開發(fā)板上的LED為例,介紹字符設(shè)備驅(qū)動(dòng)程序的設(shè)計(jì)過程。6410開發(fā)板上有4個(gè)共陽(yáng)極接法的LED指示燈,分別接到GPM0-GPM3上。當(dāng)GPM0-GPM3的4個(gè)引腳有低電平輸出時(shí),對(duì)應(yīng)的LED點(diǎn)亮,否則熄滅。

LED驅(qū)動(dòng)程序的設(shè)計(jì)就是實(shí)現(xiàn)Linux的核心結(jié)構(gòu)體file_operation結(jié)構(gòu)體的接口函數(shù)的過程,即實(shí)現(xiàn)下列幾個(gè)函數(shù):

struct file_operation LED_fops={

.owner = THIS_LED, //模塊塊所有者

.open = led_open, //設(shè)備打開函數(shù)

.ioctl = led_ioctl, //設(shè)備操作函數(shù)

.release = led_release} //設(shè)備關(guān)閉函數(shù)

led_ioctl函數(shù)用來控制端口的操作,包括功能配置、輸出高低電平控制LED的亮滅燈等。

驅(qū)動(dòng)程序設(shè)計(jì)采用內(nèi)核模塊方式,可以實(shí)現(xiàn)動(dòng)態(tài)加載,運(yùn)行靈活,便于調(diào)試。其在驅(qū)動(dòng)程中添加模塊代碼如下:

模塊初始化函數(shù):

static int led_init(void)

{ int ret;

ret=register_chrdev(led_MAJOR,“l(fā)ed”,& LED_fops)

//注冊(cè)字符設(shè)備,其中參數(shù)分別為:主設(shè)備號(hào)、設(shè)備名稱、設(shè)備操作函數(shù)入口其中設(shè)備名稱提供給用戶,以文件的形式打開并操控設(shè)備

if (ret < 0) { printk(“Unable to register!”); return ret; }

return 0;

}

模塊退出函數(shù):

static void led_exit(void)

{unregister_chrdev(led_MAJOR,“l(fā)ed”);

Printk(“Unregister !”);}

添加初始化、卸載接口:

module_init(led_init)//模塊初始化接口

module_exit(led_exit)//模塊卸載接口

3.3 模塊編譯

可加載的模塊化驅(qū)動(dòng)程序?qū)懞煤?,需要編譯成內(nèi)核模塊才能加載到內(nèi)核執(zhí)行,并編寫相應(yīng)的makefile文件,即:

obj-m := led_module.o

CROSS_COMPILE=arm-linux-

KERNELDIR?=/home/linux-3.0.1

PWD := $(shell pwd)

default:

$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

clean:

$(MAKE) -C $(KERNELDIR) M=$(PWD) clean

有了makefile文件后,可以用命令編譯生成模塊:

make -C /linux-3.0.1/ M=/home/drivers6410 modules

3.4 模塊加載

模塊生成后,根據(jù)需要使用下列命令在內(nèi)核中加載、卸載模塊,即:

insmod led_module.ko 加載模塊到內(nèi)核

rmmod led_module.ko 卸載模塊

4 系統(tǒng)實(shí)現(xiàn)

4.1 系統(tǒng)測(cè)試程序設(shè)計(jì)

為了保證驅(qū)動(dòng)程設(shè)計(jì)的正確性,需要編寫用戶程序來測(cè)試LED驅(qū)動(dòng)程序和用戶程序的正確性、可靠性。經(jīng)過測(cè)試可以正確運(yùn)行,測(cè)試代碼如下:

int led_fd,i = 0,j;

led_fd = open("/dev/led",0); //以輸出的形式打開設(shè)備,控制LED的亮滅

if(led_fd < 0 )

{printf("Error opening gpcio!\n"); exit(0); }

while(1)

{

for(i = 0;i < 4; i++)

{ ioctl(led_fd, 1, i); //輸出高電平,熄滅LED }

for(i = 0;i < 4; i++)

{ ioctl(led_fd, 0, i); //端口低電平,點(diǎn)亮LED }

}

close(led_fd);

4.2 多線程用戶程序設(shè)計(jì)

由于該系統(tǒng)中控制多個(gè)外部設(shè)備,為了保證設(shè)備能夠及時(shí)得到系統(tǒng)的響應(yīng),在程序設(shè)計(jì)時(shí)引入了多線程操作,確保外部設(shè)備的工作不受影響,從而實(shí)現(xiàn)多線程實(shí)時(shí)系統(tǒng)。程序部分代碼如下:

GUI主線程部分代碼如下:

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

{

QApplication app1(argc, argv);//定義Qt應(yīng)用程序?qū)ο螅錁?gòu)造函數(shù)接收與主函數(shù)相同的參數(shù),是Qt圖形界面程序的入口。

MainWindow mainWindow;//定義主窗體、設(shè)置其屬性

mainWindow.setOrientation(MainWindow::ScreenOrientationAuto);

mainWindow.showExpanded();

QCoreApplication app(argc, argv);

Led led; //以下創(chuàng)建多個(gè)線程對(duì)象的實(shí)例,控制LED、ADC的設(shè)備的操作

Adc adc;

Buzzer buzzer;

Keyscan keyscan;

Ds18b20 ds18b20;

led.start();//以下啟動(dòng)多個(gè)線程,實(shí)現(xiàn)多個(gè)設(shè)備的操作

adc.start();

buzzer.start();

keyscan.start();

ds18b20.start();

led.wait(); //線程等待,調(diào)用它的線程暫停執(zhí)行,直到被喚醒或等待時(shí)間到。

buzzer.wait();

adc.wait();

keyscan.wait();

ds18b20.wait();

return app1.exec();} //調(diào)用了QCoreApplication的exec函數(shù),創(chuàng)建消息循環(huán)

LED 控制子線程部分代碼:

class Led : public QThread //創(chuàng)建一個(gè)子線程,實(shí)例化QThread類

{ public: void run(); };

void Led::run() //重寫run函數(shù)

{ int led_fd,i = 0,j;

led _fd = ::open("/dev/led",0);//打開設(shè)備寫數(shù)據(jù)

if(led _fd < 0 ){printf("Error opening gpcio?。躰"); exit(0); }

while(1)

{ for(i = 0;i < 4; i++)

{ioctl(led _fd, 1, i); sleep(1); //延時(shí)作用 }

文章編號(hào):2095-6835(2017)04-0013-02

for(i = 0;i < 4; i++)

{ioctl(led _fd, 0, i); sleep(1); }

}

::close(led _fd);

}

5 結(jié)束語(yǔ)

該系統(tǒng)利用Linux內(nèi)核模塊技術(shù)開發(fā)了多個(gè)字符設(shè)備驅(qū)動(dòng)程序,同時(shí),利用Qt作為圖形界面開發(fā)了多線程、多任務(wù)嵌入式系統(tǒng),實(shí)現(xiàn)了外部設(shè)備的并發(fā)操作。經(jīng)測(cè)試,系統(tǒng)運(yùn)行穩(wěn)定、

可靠。

參考文獻(xiàn)

[1]黃宇東,胡躍明,陳安.基于Qt的多線程技術(shù)應(yīng)用于研究[J].軟件導(dǎo)刊,2009,8(10):40-42.

[2]王粉花.基于Linux字符設(shè)備驅(qū)動(dòng)程序的設(shè)計(jì)與實(shí)現(xiàn)[J].計(jì)算機(jī)工程,2006,32(23):278-280.

[3]張威,黃沖.嵌入式Linux設(shè)備驅(qū)動(dòng)程序的設(shè)計(jì)方法研究[J].江西師范大學(xué)學(xué)報(bào),2007,31(4):391-393.

〔編輯:白潔〕

猜你喜歡
驅(qū)動(dòng)程序嵌入式系統(tǒng)
避免Windows系統(tǒng)更新反復(fù)安裝顯示驅(qū)動(dòng)
方便直觀改善Windows驅(qū)動(dòng)程序管理
設(shè)備升級(jí)問題回退驅(qū)動(dòng)解決
阻止Windows Update更新驅(qū)動(dòng)程序
辦公自動(dòng)化系統(tǒng)的設(shè)計(jì)
基于物聯(lián)網(wǎng)項(xiàng)目驅(qū)動(dòng)的嵌入式系統(tǒng)教學(xué)改革的研究與實(shí)踐
嵌入式系統(tǒng)課程“中斷、異常與事件”教學(xué)實(shí)踐及啟示
面向?qū)嵺`創(chuàng)新人才培養(yǎng)的嵌入式系統(tǒng)教學(xué)研究
妙用鼠標(biāo)驅(qū)動(dòng)
驅(qū)動(dòng)程序更新與推薦