• <tr id="yyy80"></tr>
  • <sup id="yyy80"></sup>
  • <tfoot id="yyy80"><noscript id="yyy80"></noscript></tfoot>
  • 99热精品在线国产_美女午夜性视频免费_国产精品国产高清国产av_av欧美777_自拍偷自拍亚洲精品老妇_亚洲熟女精品中文字幕_www日本黄色视频网_国产精品野战在线观看 ?

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

    2017-03-25 16:48:15向明尚張志華潘麗艷
    科技與創(chuàng)新 2017年4期
    關(guān)鍵詞:多線程嵌入式系統(tǒng)驅(qū)動(dò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è)備,比如用于測量溫度、壓力、流量和速度等的傳感器,以及馬達(dá)、電機(jī)等執(zhí)行機(jī)構(gòu)。這些外部設(shè)備往往需要協(xié)同、并行工作,即所謂的多任務(wù)、實(shí)時(shí)系統(tǒng),對系統(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)程序工作原理

    對于嵌入式系統(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)程序所對應(yīng)的接口函數(shù),實(shí)現(xiàn)對外部設(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)閉所對應(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)閷τ脩粝到y(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)對多個(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í),對應(yīng)的槽函數(shù)立即調(diào)用執(zhí)行。槽函數(shù)在發(fā)出信號(hào)的線程中執(zhí)行,而不一定在接收對象所屬的線程中執(zhí)行。②排隊(duì)連接。信號(hào)發(fā)出后,要等到接收對象所屬線程的時(shí)間循環(huán)取得控制權(quán)時(shí)再調(diào)用對應(yīng)的槽函數(shù),并在信號(hào)接收對象所屬的同一個(gè)線程中執(zhí)行。③自動(dòng)連接。這是Qt默認(rèn)的連接方式。信號(hào)的發(fā)出與接收信號(hào)的對象在同一個(gè)線程,則工作在直接連接方式,否則工作在排隊(duì)方式。

    對于Qt線程與事件循環(huán)機(jī)制,每個(gè)Qt的線程都有自己的事件循環(huán)。GUI主線程是唯一可以創(chuàng)建Qapplication對象并調(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è)對應(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è)共陽極接法的LED指示燈,分別接到GPM0-GPM3上。當(dāng)GPM0-GPM3的4個(gè)引腳有低電平輸出時(shí),對應(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)

    //注冊字符設(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)測試程序設(shè)計(jì)

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

    int led_fd,i = 0,j;

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

    if(led_fd < 0 )

    {printf("Error opening gpcio?。躰"); 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è)線程對象的實(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é)束語

    該系統(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)測試,系統(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.

    〔編輯:白潔〕

    猜你喜歡
    多線程嵌入式系統(tǒng)驅(qū)動(dòng)程序
    Java并發(fā)工具包對并發(fā)編程的優(yōu)化
    基于物聯(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é)研究
    在DiskOnChip上構(gòu)建VxWorks系統(tǒng)開發(fā)環(huán)境
    基于多線程文件傳輸關(guān)鍵技術(shù)研究與實(shí)現(xiàn)
    網(wǎng)頁爬蟲技術(shù)的關(guān)鍵技術(shù)研究探索
    一種基于多線程的高速磁盤鏡像算法
    驅(qū)動(dòng)程序更新與推薦
    驅(qū)動(dòng)程序更新與推薦
    林芝县| 肃宁县| 巴马| 绩溪县| 留坝县| 柳州市| 刚察县| 泸水县| 日照市| 奉新县| 上思县| 安吉县| 洞口县| 商河县| 自贡市| 鄱阳县| 桐梓县| 濮阳市| 库车县| 弋阳县| 沁阳市| 福清市| 和林格尔县| 布尔津县| 龙里县| 峨山| 高密市| 邵武市| 内江市| 威宁| 商都县| 乐清市| 云浮市| 安庆市| 禹城市| 叙永县| 长子县| 社会| 若羌县| 瑞安市| 信丰县|