搭载好了一个空的字符设备驱动程序,接下来就是填充对硬件的控制程序,查看自己板子的LED驱动程序例子,用的misc,混杂设备,现在不用那么深入(慢慢积累),提出其中对硬件控制的程序
#define LED_GPIO MXS_PIN_TO_GPIO(PINID_LCD_D23) //硬件引脚
gpio_request //这个函数是对GPIO口做初始化的函数,就像单片机引脚初始化一样
gpio_direction_output //这个函数是对GPIO输出高低电平做改变的函数
然后是添加进自己的字符设备驱动程序里,只做了write操作
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/types.h>
- #include <linux/sched.h>
- #include <linux/init.h>
- #include <linux/fs.h>
- #include <linux/ioctl.h>
- #include <linux/delay.h>
- #include <linux/bcd.h>
- #include <linux/capability.h>
- #include <linux/rtc.h>
- #include <linux/cdev.h>
- #include <linux/miscdevice.h>
- #include <linux/gpio.h>
-
- #include <../arch/arm/mach-mx28/mx28_pins.h>
-
- #define DEVICE_NAME "led" /* 加载模式后,执行”cat /proc/devices”命令看到的设备名称 */
-
- #define LED_GPIO MXS_PIN_TO_GPIO(PINID_LCD_D23) //硬件引脚
-
- static struct class *led_class;
- static struct class_device *led_class_devs;
-
- static int led_open(struct inode *inode, struct file *file)
- {
- printk("led open ok\n");
- gpio_request(LED_GPIO, "led");
- return 0;
- }
-
- static int led_release(struct inode *inode, struct file *filp)
- {
- gpio_free(LED_GPIO);
- return 0;
- }
-
- ssize_t led_write(struct file *filp, const char __user *buf, size_t count,
- loff_t *f_pos)
- {
- char data[2];
-
- copy_from_user(data, buf, count);
- gpio_direction_output(LED_GPIO, data[0]);
-
- printk("write data:%d \n",data[0]);
- return count;
-
- }
-
-
-
- static struct file_operations led_fops = {
- .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
- .open = led_open,
- .write = led_write,
- .release = led_release,
- };
-
- int major;
- static int __init led_init(void)
- {
-
- major = register_chrdev(0, DEVICE_NAME, &led_fops); //主设备号为0 就自动分配
-
- if (major < 0) {
- printk(" can't register major number\n");
- return major;
- }
- printk("register sucess /dev/led OK!\n");
- led_class = class_create(THIS_MODULE, DEVICE_NAME);
- if (IS_ERR(led_class))
- return PTR_ERR(led_class);
-
- led_class_devs = device_create(led_class, NULL, MKDEV(major, 0), NULL, "led");
- if (unlikely(IS_ERR(led_class_devs)))
- return PTR_ERR(led_class_devs);
-
- printk(DEVICE_NAME " initialized\n");
- return 0;
- }
-
- static void __exit led_exit(void)
- {
- unregister_chrdev(major, DEVICE_NAME);
-
- device_unregister(led_class_devs);
-
- class_destroy(led_class);
-
- printk(" led rmmod OK!\n");
- }
-
- module_init(led_init);
- module_exit(led_exit);
-
- MODULE_LICENSE("GPL");
内核写好了,是不是该写测试文件了,看着LCD屏还是触摸的,不来点交互怎么能行呢?
那就用QT来测试吧:
对内核写进 1 就是点亮灯
对内核写进 0 就是熄灭灯
我选择用QCommandLinkButton,个人感觉这个控件比QPushbutton要好看一些,就选择它了,按下一个点亮灯,按下另一个熄灭灯
具体程序如下:
- #include "mainwindow.h"
-
- MainWindow::MainWindow(QWidget *parent)
- : QMainWindow(parent)
- {
- fd = open("/dev/led", O_RDWR);
- ON = new QCommandLinkButton("open LED","",this);
- OFF = new QCommandLinkButton("close LED","",this);
-
- ON->setGeometry(10,10,100,30);
- OFF->setGeometry(10,40,100,30);
- connect(ON,SIGNAL(clicked()),this,SLOT(open_led()));
- connect(OFF,SIGNAL(clicked()),this,SLOT(close_led()));
- }
-
- MainWindow::~MainWindow()
- {
-
- }
-
- void MainWindow::open_led()
- {
- val = 0;
- write(fd, &val, 1);
- }
-
- void MainWindow::close_led()
- {
- val = 1;
- write(fd, &val, 1);
- }
然后是.h文件要包含对应的头文件
- #ifndef MAINWINDOW_H
- #define MAINWINDOW_H
-
- #include <QtGui/QMainWindow>
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <termios.h>
- #include <errno.h>
- #include <limits.h>
- #include <asm/ioctls.h>
- #include <time.h>
- #include <pthread.h>
-
- #include <QCommandLinkButton>
- class MainWindow : public QMainWindow
- {
- Q_OBJECT
-
- public:
- MainWindow(QWidget *parent = 0);
- ~MainWindow();
- QCommandLinkButton *ON;
- QCommandLinkButton *OFF;
- private:
- int fd;
- char val;
- private slots:
- void open_led();
- void close_led();
- };
-
- #endif // MAINWINDOW_H
经过编译 进入nfs目录 加载内核驱动文件,运行QT
点击"open LED",会发现左边的灯变亮
点击“close LED” 会发现左边的灯会熄灭
同时,终端也会打印出数据
本帖最后由 ywlzh 于 2016-7-23 23:54 编辑