• 
    

    
    

      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)程序更新與推薦
      寿光市| 休宁县| 三原县| 疏附县| 武强县| 来凤县| 措勤县| 东港市| 安义县| 澄迈县| 石嘴山市| 中阳县| 桦南县| 长宁区| 常熟市| 营口市| 巩留县| 康乐县| 普安县| 荣昌县| 博客| 吴旗县| 潮州市| 岑溪市| 马龙县| 潍坊市| 平谷区| 稻城县| 武汉市| 成武县| 江西省| 白玉县| 新和县| 自治县| 黄浦区| 阜南县| 沙田区| 灌云县| 江口县| 邯郸县| 瑞金市|