下面用imx6ull的qt'点灯说明,这里要使用c++,c混合编程
一、完成ui界面位置
构造一个这样的简单界面即可,主要是实现open和close的槽函数即可。我这里分别把两个按钮改名为为openbt closebt了
二、实现逻辑功能
2.1完成led类创建
在主文件夹led中addnew,选择c++的类,记得把base class改成qobject,取个类的名字,其余保持默认即可。
完成创建后你会得到一个led.h和led.cpp
下面我们在led.h中的public加入我们led要用到的一些元素,我加入了fd(后面用于保存文件句柄),led灯的值,打开和关闭led的函数,
重点:c语言里面的头文件移植到c++中我们需要用extern “C”{ ……}将其括起来,然后为了标准我们通常将c语言里面的函数如open write 等调用之前加入::如::open()
下面我们去完成这两个函数即可,
在led的构造函数中我让其open,我们这里就是打开写入1,关闭写入0而已。
2.2在widget中调用led类
我们在widget的头文件的public中声明一个led类
然后再去其cpp文件new一下,这时候会触发其构造函数即open对应设备节点,然后再去两个按钮的槽函数分别调用打开灯和关灯函数即可
这里注意widget的头文件中要include "led.h"否则调用会出错
2.3实现对应驱动函数
我们上面led的构造函数打开的设备节点是/dev/flyled,但是压根没这个设备节点啊,所以你要自己写驱动程序来驱动这个led
这里我们首先需要进行设备树添加
然后我们去实现对应的函数,记住我们要成功的对应compatible即可:
这里简略回忆一下驱动函数:
1.入口函数,注册平台驱动程序,出口函数卸载平台驱动程序
2.平台驱动程序:driver中的of_match_table来用于匹配设备树的compatible,probe用于匹配后进入,remove用于卸载probe的事情
3.probe中:注册字符驱动设备,注册类,注册设备节点,注册file_operation结构体,在该结构体内再实现相应功能
4.file_operation中open可以不写,owner是THIS_MODULE,然后实现写函数即可
5.写函数使用copy_from_user进行数据交互
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/gpio/consumer.h>
#include <media/i2c/adp1653.h>
#include <media/v4l2-device.h>
#include <linux/platform_device.h>
static int major = 0 ;
static struct gpio_desc *led_gpiod;
static struct class *ledclass;
static ssize_t led_write(struct file *file, const char __user *buf, size_t size, loff_t *loff)
{
char value;
copy_from_user(&value, buf, 1);
if(value)
gpiod_set_value(led_gpiod,0);
else
gpiod_set_value(led_gpiod,1);
return 0;
}
static const struct file_operations ledfops = {
.owner = THIS_MODULE,
.write = led_write,
};
//获得资源
static int led_dri_probe (struct platform_device *device)
{
major = register_chrdev(0,"fly_led", &ledfops);
ledclass = class_create(THIS_MODULE, "led_class");
device_create(ledclass,NULL, MKDEV(major,0), NULL,"flyled");
printk("%s,%s,%d\r\n",__FILE__,__FUNCTION__,__LINE__);
led_gpiod = gpiod_get(&device->dev,NULL,GPIOD_OUT_HIGH);
return 0;
}
static int led_dri_remove(struct platform_device *device)
{
gpiod_put(led_gpiod);
device_destroy(ledclass,MKDEV(major,0));
class_destroy(ledclass);
unregister_chrdev(major,"fly_led");
return 0;
}
static const struct of_device_id led_dri_ofmatch[] = {
{ .compatible = "fly,led", },
{ },
};
static struct platform_driver led_dri =
{
.probe = led_dri_probe,
.remove = led_dri_remove,
.driver = {
.name = "fly_led_dri",
.of_match_table = led_dri_ofmatch,
},
};
static int led_dri_init(void)
{
platform_driver_register(&led_dri);
return 0;
}
static void led_dri_exit(void)
{
platform_driver_unregister(&led_dri);
}
module_init(led_dri_init);
module_exit(led_dri_exit);
MODULE_LICENSE("GPL");
2.4测试函数
以防万一,我自己有编写了一个测试函数
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main(int argc,char **argv)
{
int fd ;
fd = open("/dev/flyled",O_RDWR);
if(strcmp(argv[1],"open")==0)
{
char buf = 1;
write(fd,&buf, 1);
printf("led open\r\n");
}
else if(strcmp(argv[1],"close")==0)
{
char buf = 0;
write(fd,&buf, 1);
printf("led close\r\n");
}
return 0;
}
三、结束
最后需要先安装驱动程序,然后再下载qt程序否则会没用open到设备节点
本次学习了如何使用qt操作硬件,其实也很简单就是把c代码移植到c++里面,主要记住面向对象的编程思想构造出led类,以及extern ”C“{ }引用头文件,以及c语言中的代码需要加::,如::open。