1. 程式人生 > >Linux學習筆記之用QT介面操作板子LED

Linux學習筆記之用QT介面操作板子LED

Linux學習筆記之小目標一:用QT介面操作板子LED

一、目標:用QT繪製一個介面,點選開按鈕,板子LED點亮,點選關按鈕,LED熄滅
二、設計知識點:Linux底層IO驅動,核心程式設計,QT程式設計
三、程式碼部分

1、驅動程式碼 qt-led.c

/**************************************
版本記錄: chen :2017-11-11 V1.0
linux核心:2.6
硬體接法:
LED1 –> GPX1_0
LED2 –> GPK1_1
高電平點亮
驅動用法:
裝置名稱:qt-led
點亮一個燈:LED_ON
熄滅一個燈:LED_OFF
點亮所有燈:ALL_LED_ON
熄滅所有燈:ALL_LED_OFF
說明:
***************************************

/

//Linux通用的標頭檔案
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/device.h>
//針對板子的標頭檔案
#include <mach/gpio.h>
#include <mach/gpio-exynos4.h>
#include <plat/gpio-cfg.h>

#define DEVICE_NAME "qt-led" /* 裝置名稱 */        
static int LED_Major = 0;    /* 主裝置號 */

#define LED_ON  1
#define LED_OFF 0

#define FIRST_LED   0
#define SECOND_LED  1
#define ALL_LED     2

/* 開啟裝置函式,開啟的時候僅僅做了GPIO申請 */
static int qt_led_open(struct inode *inode,struct file *file) {
    int ret;
    //列印KERN_EMERG是為了區分列印資訊
    printk(KERN_EMERG"KERN_EMERG:qt_led_open_success!\r\n");
    //先釋放GPIO
    gpio_free(EXYNOS4_GPL2(0));
    //申請GPIO
    ret = gpio_request(EXYNOS4_GPL2(0),"LED1");
    if(ret < 0){
        printk(KERN_EMERG"KERN_EMERG:gpio_request EXYNOS4_GPX1_0 fail!\r\n");
        return -1;
    }
    //設定GPIO模式,為output
    s3c_gpio_cfgpin(EXYNOS4_GPL2(0),S3C_GPIO_OUTPUT);
    //給GPIO賦初值,相當於是LED預設關
    gpio_set_value(EXYNOS4_GPL2(0),0);

    //第二個LED GPIO,跟第一個操作一模一樣
    gpio_free(EXYNOS4_GPK1(1));
    ret = gpio_request(EXYNOS4_GPK1(1),"LED2");
    if(ret < 0){
        printk(KERN_EMERG"KERN_EMERG:gpio_request EXYNOS4_GPK1_1 fail!\r\n");
        return -1;
    }
    s3c_gpio_cfgpin(EXYNOS4_GPK1(1),S3C_GPIO_OUTPUT);
    gpio_set_value(EXYNOS4_GPK1(1),0);

    return 0;
}
/* 關閉裝置函式,關閉的時候沒做啥,釋放GPIO */
static int qt_led_release(struct inode *inode,struct file *file){
    gpio_free(EXYNOS4_GPL2(0));
    gpio_free(EXYNOS4_GPK1(1));
    printk(KERN_EMERG"KERN_EMERG:qt_led_release_success!\r\n");
    return 0;
}
/* GPIO控制函式 */
static long qt_led_ioctl(struct file *file,unsigned int cmd,unsigned long arg){
    printk(KERN_EMERG"KERN_EMERG:qt_led_ioctl!\r\n");

    //由於CMD組合比較複雜,達到目標我只用0.1就可以了,所以沒有組合
    //arg可以是很多值,所以用cmd表示開還是關,arg表示哪一路
    switch(arg){
        case FIRST_LED:{
            gpio_set_value(EXYNOS4_GPL2(0),cmd);
            printk(KERN_EMERG"KERN_EMERG:cmd is :%d,arg is :%ld\r\n",cmd,arg);
            return 0;
            break;
        }
        case SECOND_LED:{
            gpio_set_value(EXYNOS4_GPK1(1),cmd);
            printk(KERN_EMERG"KERN_EMERG:cmd is :%d,arg is :%ld\r\n",cmd,arg);
            return 0;
            break;          
        }
        case ALL_LED:{
            gpio_set_value(EXYNOS4_GPL2(0),cmd);
            gpio_set_value(EXYNOS4_GPK1(1),cmd);
            printk(KERN_EMERG"KERN_EMERG:cmd is :%d,arg is :%ld\r\n",cmd,arg);
            return 0;
            break;          
        }
        default:
            return -EINVAL;
            break;      
    }
}
//由於用的是字元裝置,不是平臺裝置,需要class結構體
static struct class *qt_led_class;
//file_operations結構體,無論字元裝置還是平臺裝置都需要
static struct file_operations qt_led_fs = {
    .owner = THIS_MODULE,
    .open  = qt_led_open,
    .release = qt_led_release,
    .unlocked_ioctl = qt_led_ioctl,
};


static int qt_led_init(void){
    printk(KERN_EMERG"Led_Drv_Module_Init!\r\n");
    //平臺裝置,要註冊主裝置號
    LED_Major = register_chrdev(0,DEVICE_NAME,&qt_led_fs);
    if(LED_Major < 0){
        printk(KERN_EMERG"Led_Drv_Module_Init_Major_error!\r\n");
        return LED_Major;
    }
    printk(KERN_EMERG"Led_Drv_Module_Init_Major_Success!\r\n");
    //建立class
    qt_led_class = class_create(THIS_MODULE,DEVICE_NAME);
    if(IS_ERR(qt_led_class)){
        printk(KERN_EMERG"Err: failed in qt_led_class.!\r\n");
        return -1;
    }
    //建立device
    device_create(qt_led_class,NULL,MKDEV(LED_Major,0),NULL,DEVICE_NAME);
    printk(DEVICE_NAME"initialized.!\r\n");
    return 0;
}

static void qt_led_exit(void){
    //解除安裝裝置,與註冊要相反的操作
    printk(KERN_EMERG"Led_Drv_Module_exit!\r\n");
    unregister_chrdev(LED_Major,DEVICE_NAME);
    device_destroy(qt_led_class,MKDEV(LED_Major,0));
    class_destroy(qt_led_class);
}

MODULE_AUTHOR("Chenxw");        
MODULE_DESCRIPTION("qt LED Driver");    
MODULE_LICENSE("Dual BSD/GPL");
module_init(qt_led_init);
module_exit(qt_led_exit);

2、驅動程式碼Makefile

#!/bin/bash
#通知編譯器我們要編譯模組的哪些原始碼
#這裡是編譯qt-led.c這個檔案編譯成中間檔案qt-led.o
obj-m += qt-led.o 

#原始碼目錄變數,這裡使用者需要根據實際情況選擇路徑
#作者是將Linux的原始碼拷貝到目錄/home/topeet/workstation下並解壓的
KDIR := /home/topeet/workstation/iTop4412_Kernel_3.0

#當前目錄變數
PWD ?= $(shell pwd)

#make命名預設尋找第一個目標
#make -C就是指呼叫執行的路徑
#$(KDIR)Linux原始碼目錄,作者這裡指的是/home/topeet/workstation/iTop4412_Kernel_3.0
#$(PWD)當前目錄變數
#modules要執行的操作
all:
    make -C $(KDIR) M=$(PWD) modules

#make clean執行的操作是刪除字尾為o的檔案
clean:
    rm -rf *.o *.ko *.mod.c *.symvers *.order

3、由於驅動C語言寫的,QT是C++寫的,需要寫一個給QT的C語言介面檔案,給C++提供操作驅動的介面函式

4、核心介面檔案led-c.c

#include "led-c.h"
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

//檔案控制代碼申明和初始化
int qt_led_fd = 0;
//qt呼叫的檔案開啟函式
int qt_led_open(const char *devname){
    //devname 是傳進來的檔案路徑,O_RDWR是可讀可寫
    qt_led_fd = open(devname,O_RDWR);
    if(qt_led_fd < 0){
        printf("Open device %s failed!\r\n",devname);
        return -1;
    }
    printf("Qt-led driver is ok,open success!\r\n");
    return 0;
}
//qt呼叫的檔案操作函式
int qt_led_ioctl(unsigned int cmd, unsigned long led_num){
    //cmd是控制開還是關,led_num就是arg,控制哪一個燈
    ioctl(qt_led_fd,cmd,led_num);
    return 0;
}

int qt_led_close(void){
    //如果有檔案開啟,就去關閉開啟的那個檔案
    if(qt_led_fd){
        close(qt_led_fd);
    }
    printf("Dev qt led closed!\r\n");
    return 0;
}

5、核心介面檔案的標頭檔案led-c.h

#ifndef LEDC_H
#define LEDC_H
//這是一段cpp的程式碼,加入extern "C"{和}處理其中的程式碼
//C++和C對產生的函式名字的處理是不一樣的,C++為了相容C
#ifdef __cplusplus
extern "C"{
    #endif
    extern int qt_led_open(const char *devname);
    int qt_led_ioctl(unsigned int cmd,unsigned long led_num);
    extern int qt_led_close();
    extern int qt_led_fd;
#ifdef __cplusplus
}
#endif
#endif // LEDC_H

6、窗體檔案mainwindow.cpp

//窗體設計可以自己一行程式碼一行程式碼敲
#include "mainwindow.h"
//窗體設計還可以用QT自帶的UI設計,區別在於自動生成程式碼,檔案前面自動新增ui標識
#include "ui_mainwindow.h"

//add by chen
#include "led-c.h"
//cmd取值
#define LED_ON  1
#define LED_OFF 0
//arg取值
#define FIRST_LED   0
#define SECOND_LED  1
#define ALL_LED     2
//裝置檔案位置,名字要跟驅動裡面保持一致
#define LED_DEVICE "/dev/qt-led"
//add by chen end

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

//add by chen
    //設定視窗名字,還可以設定圖片,這裡就不加了
    this->setWindowTitle("Chen qt led test!");
    //例項化一個按鈕
    button_led_on = new QPushButton(this);
    //設定按鈕位置,大小
    button_led_on->setGeometry(QRect(20,20,100,100));
    //設定按鈕顯示文字
    button_led_on->setText("led_on");
    //設定點選事件,訊號是released,槽是燈亮函式
    connect(button_led_on,SIGNAL(released()),this,SLOT(ctl_led_on()));
    /*下面程式碼跟上面一樣了*/
    button_led_off = new QPushButton(this);
    button_led_off->setGeometry(QRect(140,20,100,100));
    button_led_off->setText("led_off");
    connect(button_led_off,SIGNAL(released()),this,SLOT(ctl_led_off()));

    button_led_all_on = new QPushButton(this);
    button_led_all_on->setGeometry(QRect(20,140,100,100));
    button_led_all_on->setText("led_all_on");
    connect(button_led_all_on,SIGNAL(released()),this,SLOT(ctl_led_all_on()));

    button_led_all_off = new QPushButton(this);
    button_led_all_off->setGeometry(QRect(140,140,100,100));
    button_led_all_off->setText("led_all_off");
    connect(button_led_all_off,SIGNAL(released()),this,SLOT(ctl_led_all_off()));

    button_close_led_dev = new QPushButton(this);
    button_close_led_dev->setGeometry(QRect(260,140,100,100));
    button_close_led_dev->setText("close_dev");
    /*由於要除錯,在手動退出後文件未被關閉,增加一個按鈕主動關閉檔案*/
    connect(button_close_led_dev,SIGNAL(released()),this,SLOT(ctl_close_led_dev()));

    qt_led_open(LED_DEVICE);
    printf("C++ Open %s \r\n",LED_DEVICE);
//add by chen finished

}

//add by chen
//控制燈亮函式
void MainWindow::ctl_led_on(){
    qt_led_ioctl(LED_ON,FIRST_LED);
    printf("Qt ctl_led_on IO here!\r\n");
    printf("Qt cmd is:%d,arg is :%d\r\n",LED_ON,FIRST_LED);
}

void MainWindow::ctl_led_off(){
    qt_led_ioctl(LED_OFF,FIRST_LED);
    printf("Qt ctl_led_off IO here!\r\n");
    printf("Qt cmd is:%d,arg is :%d\r\n",LED_OFF,FIRST_LED);
}

void MainWindow::ctl_led_all_on(){
    qt_led_ioctl(LED_ON,ALL_LED);
    printf("Qt ctl_led_all_on IO here!\r\n");
    printf("Qt cmd is:%d,arg is :%d\r\n",LED_ON,ALL_LED);
}

void MainWindow::ctl_led_all_off(){
    qt_led_ioctl(LED_OFF,ALL_LED);
    printf("Qt ctl_led_all_off IO here!\r\n");
    printf("Qt cmd is:%d,arg is :%d\r\n",LED_OFF,ALL_LED);
}

void MainWindow::ctl_close_led_dev(){
    qt_led_close();
}

//add by chen finished

MainWindow::~MainWindow()
{
    delete ui;
    /*關閉窗體後要記得關閉檔案*/
    qt_led_close();//add by chen
}

7、窗體檔案標頭檔案mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
//add by chen 
#include <QPushButton>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
//add by chen end

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

//add by chen
//私有成員,宣告按鈕
private:
    QPushButton *button_led_on;
    QPushButton *button_led_off;
    QPushButton *button_led_all_on;
    QPushButton *button_led_all_off;
    QPushButton *button_close_led_dev;
//公有成員,宣告事件實現槽函式
public slots:
    void ctl_led_on();
    void ctl_led_off();
    void ctl_led_all_on();
    void ctl_led_all_off();
    void ctl_close_led_dev();
//add by chen end
};

#endif // MAINWINDOW_H

四、效果圖
Qt介面效果圖
Qt介面效果圖

五、實際效果

先載入模組 insmod qt-led.ko
再執行Qt程式 qt-led -qws &

我的板子是有觸控,可以接滑鼠。程式執行後兩個燈都是出於滅的狀態,點選led_on,第一個燈亮了,點選led_off第一個燈滅了。點選led_all_on,兩個燈都亮了,點選led_all_off,兩個燈都滅了。點選close_dev,然後再重複上面的操作,燈無變化,達到效果。

六、總結

買了書也兩個禮拜了,本人從13年畢業到現在一直從事於硬體工作,從方案選型到原理圖設計和PCB layout乃至量產等經驗倒是一大堆。一直想學習linux部分內容,自己倒騰了這麼久總算是完成第一個小目標。通過介面操作LED,Android部分還沒去看。不得不說,linux學起來還有點吃力,理解和要記憶的一大堆,自我感覺還沒入門,再接再厲。留下記錄部落格,以供自勉,如有同道之人願意一起交流,無比樂意。

相關推薦

Linux學習筆記QT介面操作板子LED

Linux學習筆記之小目標一:用QT介面操作板子LED 一、目標:用QT繪製一個介面,點選開按鈕,板子LED點亮,點選關按鈕,LED熄滅 二、設計知識點:Linux底層IO驅動,核心程式設計,QT程式設計 三、程式碼部分 1、驅動程式碼 qt-led.c

linux學習筆記系統管理操作

1.檢視網路IP和閘道器 檢視虛擬網路編輯器 在VMware裡 選擇 編輯->虛擬網路編輯器 修改ip地址 在虛擬編輯器裡面選擇NAT模式,然後配置子網ip, 如果不知道本機ip ,可以在window命令列中輸入ipconfig 檢視當前ip地址

Linux學習筆記4_基本文件操作命令復習2

linuxfind命令(5星級)find /data -type -f -name "test.txt" //找到某類型某名字文件find /data -type -f -name "test.txt" -exec rm

Linux學習筆記管道、重定向與正則表達式

linux管道與重定向 linux學習筆記 linux 正則表達式 管道:前一個命令的輸出,作為後一個命令的輸入命令1 | 命令2 | 命令3| 命令4 #tee 即在顯示器顯示,又在文件在保存文件例#echo “hello ,word” | tee /tmp/ hello.out例#wc -l

Linux學習筆記vim編輯技巧

vim linux學習筆記 linux vim編輯技巧 vim,一個純文本(純文本信息,ASCII text)編輯器,Vi(Visual Interface) IMproved,是一個模式化的編輯器。> vim有自帶的教程,也是linux的一個內置命令一、基本模式分類1 編輯模式(命令模式)

Linux學習筆記四————Linux常用命令 ( 待補充)

-h http “.” 現實 人性化 快捷 我們 包括 無法 一、Linux命令——文件、磁盤管理 1.文件管理 <1>查看文件信息:ls ls是英文單詞list的簡寫,其功能為列出目錄的內容,是用戶最常用的命令之一,它類似於DOS下的dir命令。 Linu

Linux學習筆記二————Linux系統的文件和目錄

管道 過程 命令 合成 給定 cal 如圖所示 項目 img 一、Windows和Linux文件系統區別 1、在 windows 平臺下,打開“計算機”,我們看到的是一個個的驅動器盤符: 每個驅動器都有自己的根目錄結構,這樣形成了多個樹並列的情形,如圖所示:

Linux學習筆記三————Linux命令概述

上下 eight ive 幫助 option pos misc tor tro 一、引言 很多人可能在電視或電影中看到過類似的場景,黑客面對一個黑色的屏幕,上面飄著密密麻麻的字符,梆梆一頓敲,就完成了竊取資料的任務。 Linux 剛出世時沒有什麽圖形界面,所有的操

Linux學習筆記九————ubuntu軟件安裝與卸載

升級 獲取 tor mage 技術 png bsp and rem 一、更新 源 1. 尋找國內鏡像源 所謂的鏡像源:可以理解為提供下載軟件的地方,比如Android手機上可以下載軟件的91手機助手;iOS手機上可以下載軟件的AppStore 2. 備份Ubuntu

Linux學習筆記十————Linux常用服務器構建ftp服務器

download pytho ftp服務 nsf png tp服務器 圖片 拷貝文件 span 一、ftp服務器介紹 FTP 是File Transfer Protocol(文件傳輸協議)的英文簡稱,而中文簡稱為“文傳協議”。 用於Internet上的控制文件的雙向傳輸。

六LWIP學習筆記戶數據報協議(UDP)

端口 數據結構 筆記 udp協議 pos body 校驗 傳輸 連接 一、背景知識 1、傳輸層協議 2、UDP協議 3、端口 4、UDP報文的交付 5、UDP報文格式 6、UDP偽首部與校驗和 二、UDP數據結構 1、報文首部結構 2、控制塊 三、控制塊操作函數 1、使用U

linux 學習筆記

幫助 bsp line 所有 默認 bin span mina eight 1 shell CLI(command line interface) GNIME Terminal Ctrl+Alt+T 快速打開Terminal F11 在全屏和普通模式下切換 默認shell

Linux 學習筆記四 查看文件

lin 學習 文件內容 筆記 文件 內容 上下 post blog 一 cat cat filename 查看文件內容 cat -n filename 查看文件內容,帶上行號 cat -b filename 查看文件內容 ,空行不帶行號 二 more more file

八LWIP學習筆記戶編程接口

log pos 數據 用戶數據 div 操作 套接字函數 函數 實現 一、定時事件 1、定時結構 2、定時鏈表 3、內核進程 4、處理定時事件 二、消息機制 1、消息結構 2、數據包消息 3、協議棧API實現 4、API消息 三、協議棧接口 1、用戶數據緩存netbuf 2

梓益C語言學習筆記常用鏈表操作函數

C語言 鏈表操作 梓益C語言學習筆記之常用鏈表操作函數一、創建鏈表void link_creat_head(STU **p_head,STU *p_new){ STU *p_mov=*p_head; if(*p_head==NULL) //當第一次加入鏈表為空時,head執行p_new { *

梓益C語言學習筆記常用字符串操作(sscanf & strtok)

C語言 字符串操作 梓益C語言學習筆記之常用字符串操作(sscanf & strtok)一、sscanf int sscanf(const char *buf,const char *format, …); \\從buf指定的內存區域中讀入信息 例: int a, b, c; ssc

Linux學習筆記搭建LNMP服務器環境

linux mysql php nginx contos LNMP(linux+nginx+mysql+php)服務器環境配置作為新手,肯定是需要linux+nginx+mysql+php這套環境來實驗一些東西的,但是網上的教程亂七八糟的,今天我就來分享一個不錯的快速集成環境安裝包吧系統要

LWIP學習筆記戶編程接口(NETCONN)(八)

socket api con 數據 實現 學習 數據緩存 用戶 soc 一、定時事件 1、定時結構 2、定時鏈表 3、內核進程 4、處理定時事件 二、消息機制 1、消息結構 2、數據包消息 3、協議棧API實現 4、API消息 三、協議棧接口 1、用戶數據緩存netbuf

Linux學習筆記5戶,組和權限

方式 無法 表示 組密碼 保存 pan upa 1.2 chmod u+s 1.用戶和組 1.1常用的幾個文件: /etc/passwd 用戶信息文件 /etc/shadow 用戶密碼文件 /etc/group 用

Linux學習筆記基礎命令與獲取幫助文檔

內容 大寫 用戶 協議 當前時間 switch 使用 主機 當前 一、linux的基本原則:1、 由目的單一的小程序組成,組合小程序,完成復雜任務;2、 一切皆文件;3、 盡量避免捕獲用戶接口;4、 配置文件保存為純文本格式二、shellGUI :Graphic U