NanoPi NEO Air使用一:介绍
NanoPi NEO Air使用二:固件烧录
NanoPi NEO Air使用三:OverlayFS、CPU温度和频率、wifi、蓝牙、npi-config
NanoPi NEO Air使用四:操作GPIO
NanoPi NEO Air使用五:安装Xfce和xrdp,实现远程访问
NanoPi NEO Air使用六:使用摄像头
NanoPi NEO Air使用七:获取并编译U-boot和Linux的源码
NanoPi NEO Air使用八:编写个简单的驱动和应用程序
NanoPi NEO Air使用九:使用Linux内核自带的LED驱动
NanoPi NEO Air使用十:自己编写驱动来控制LED
NanoPi NEO Air使用十一:编写SPI驱动点亮TFT屏幕,ST7789V

在Ubuntu用户文件夹下新建个测试目录,比如我的linux源码目录为:/home/ql/linux/H3/linux
本驱动和应用程序源码放置的目录为/home/ql/linux/H3/MyDriver/01_chrdevbase
然后在此目录下添加3个文件:

驱动源文件

chrdevbase.c

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
/***************************************************************
Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
文件名     : chrdevbase.c
作者      : 左忠凯
版本      : V1.0
描述      : chrdevbase驱动文件。
其他      : 无
论坛      : www.openedv.com
日志      : 初版V1.0 2019/1/30 左忠凯创建
***************************************************************/#define CHRDEVBASE_MAJOR    200             /* 主设备号 */
#define CHRDEVBASE_NAME     "chrdevbase"  /* 设备名     */static char readbuf[100];      /* 读缓冲区 */
static char writebuf[100];      /* 写缓冲区 */
static char kerneldata[] = {"kernel data!"};/** @description        : 打开设备* @param - inode     : 传递给驱动的inode* @param - filp   : 设备文件,file结构体有个叫做private_data的成员变量*                       一般在open的时候将private_data指向设备结构体。* @return             : 0 成功;其他 失败*/
static int chrdevbase_open(struct inode *inode, struct file *filp)
{//printk("chrdevbase open!\r\n");return 0;
}/** @description      : 从设备读取数据 * @param - filp  : 要打开的设备文件(文件描述符)* @param - buf    : 返回给用户空间的数据缓冲区* @param - cnt  : 要读取的数据长度* @param - offt  : 相对于文件首地址的偏移* @return             : 读取的字节数,如果为负值,表示读取失败*/
static ssize_t chrdevbase_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{int retvalue = 0;/* 向用户空间发送数据 */memcpy(readbuf, kerneldata, sizeof(kerneldata));retvalue = copy_to_user(buf, readbuf, cnt);if(retvalue == 0){printk("kernel senddata ok!\r\n");}else{printk("kernel senddata failed!\r\n");}//printk("chrdevbase read!\r\n");return 0;
}/** @description      : 向设备写数据 * @param - filp   : 设备文件,表示打开的文件描述符* @param - buf     : 要写给设备写入的数据* @param - cnt     : 要写入的数据长度* @param - offt  : 相对于文件首地址的偏移* @return             : 写入的字节数,如果为负值,表示写入失败*/
static ssize_t chrdevbase_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{int retvalue = 0;/* 接收用户空间传递给内核的数据并且打印出来 */retvalue = copy_from_user(writebuf, buf, cnt);if(retvalue == 0){printk("kernel recevdata:%s\r\n", writebuf);}else{printk("kernel recevdata failed!\r\n");}//printk("chrdevbase write!\r\n");return 0;
}/** @description      : 关闭/释放设备* @param - filp   : 要关闭的设备文件(文件描述符)* @return             : 0 成功;其他 失败*/
static int chrdevbase_release(struct inode *inode, struct file *filp)
{//printk("chrdevbase release!\r\n");return 0;
}/** 设备操作函数结构体*/
static struct file_operations chrdevbase_fops = {.owner = THIS_MODULE,    .open = chrdevbase_open,.read = chrdevbase_read,.write = chrdevbase_write,.release = chrdevbase_release,
};/** @description : 驱动入口函数 * @param      : 无* @return       : 0 成功;其他 失败*/
static int __init chrdevbase_init(void)
{int retvalue = 0;/* 注册字符设备驱动 */retvalue = register_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME, &chrdevbase_fops);if(retvalue < 0){printk("chrdevbase driver register failed\r\n");}printk("chrdevbase init!\r\n");return 0;
}/** @description  : 驱动出口函数* @param       : 无* @return       : 无*/
static void __exit chrdevbase_exit(void)
{/* 注销字符设备驱动 */unregister_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME);printk("chrdevbase exit!\r\n");
}/* * 将上面两个函数指定为驱动的入口和出口函数 */
module_init(chrdevbase_init);
module_exit(chrdevbase_exit);/* * LICENSE和作者信息*/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zuozhongkai");

应用源文件

chrdevbaseApp.c

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
/***************************************************************
Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
文件名     : chrdevbaseApp.c
作者      : 左忠凯
版本      : V1.0
描述      : chrdevbase驱测试APP。
其他      : 使用方法:./chrdevbase /dev/chrdevbase <1>|<2>argv[2] 1:读文件argv[2] 2:写文件
论坛      : www.openedv.com
日志      : 初版V1.0 2019/1/30 左忠凯创建
***************************************************************/static char usrdata[] = {"usr data!"};/** @description      : main主程序* @param - argc   : argv数组元素个数* @param - argv    : 具体参数* @return            : 0 成功;其他 失败*/
int main(int argc, char *argv[])
{int fd, retvalue;char *filename;char readbuf[100], writebuf[100];if(argc != 3){printf("Error Usage!\r\n");return -1;}filename = argv[1];/* 打开驱动文件 */fd  = open(filename, O_RDWR);if(fd < 0){printf("Can't open file %s\r\n", filename);return -1;}if(atoi(argv[2]) == 1){ /* 从驱动文件读取数据 */retvalue = read(fd, readbuf, 50);if(retvalue < 0){printf("read file %s failed!\r\n", filename);}else{/*  读取成功,打印出读取成功的数据 */printf("read data:%s\r\n",readbuf);}}if(atoi(argv[2]) == 2){/* 向设备驱动写数据 */memcpy(writebuf, usrdata, sizeof(usrdata));retvalue = write(fd, writebuf, 50);if(retvalue < 0){printf("write file %s failed!\r\n", filename);}}/* 关闭设备 */retvalue = close(fd);if(retvalue < 0){printf("Can't close file %s\r\n", filename);return -1;}return 0;
}

Makefile

KERNELDIR := /home/ql/linux/H3/linux
CURRENT_PATH := $(shell pwd)
obj-m := chrdevbase.obuild: kernel_moduleskernel_modules:make ARCH=arm CROSS_COMPILE=arm-linux- -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean:make ARCH=arm CROSS_COMPILE=arm-linux- -C $(KERNELDIR) M=$(CURRENT_PATH) clean

编译

上面3个文件添加好后:

编译驱动

进入驱动文件源码所在目录编译驱动:

cd /home/ql/linux/H3/MyDriver/01_chrdevbase
make


此时已编译出ko文件。

编译应用程序

再编译应用程序,执行

arm-linux-gcc chrdevbaseApp.c -o chrdevbaseApp

编译完成以后会生成一个叫做 chrdevbaseApp 的可执行程序,输入file chrdevbaseApp命令查看chrdevbaseAPP 这个程序的文件信息:

在开发板上测试运行

把编译好的chrdevbase.ko和chrdevbaseApp 通过SCP传到开发板上。

scp chrdevbase.ko root@192.168.0.103:/lib/modules/4.14.111/
scp chrdevbaseApp  root@192.168.0.103:/lib/modules/4.14.111/



使用如下命令更改控制台消息等级:

echo 5 >/proc/sys/kernel/printk
cat /proc/sys/kernel/printk

驱动模块加载

输入如下命令加载 chrdevbase.ko 驱动文件:

insmod chrdevbase.ko


可以看到有“chrdevbase init!”输出,这正是驱动入口函数的输出,说明驱动模块加载成功。

输入lsmod命令即可查看当前系统中存在的模块:

输入cat /proc/devices命令查看当前系统中有没有 chrdevbase 这个设备:

可以看出,当前系统存在 chrdevbase 这个设备,主设备号为 200,跟我们设置的主设备号一致。

应用程序测试

驱动加载成功需要在/dev 目录下创建一个与之对应的设备节点文件,应用程序就是通过操作这个设备节点文件来完成对具体设备的操作。输入如下命令创建/dev/chrdevbase 这个设备节点文件:
mknod /dev/chrdevbase c 200 0
其中“mknod”是创建节点命令,“/dev/chrdevbase”是要创建的节点文件,“c”表示这是个字符设备,“ 200”是设备的主设备号,“ 0”是设备的次设备号。创建完成以后就会存在/dev/chrdevbase 这个文件,可以使用ls /dev/chrdevbase -l命令查看。

Linux 下一切皆文件,因此可以像windows下一样对文件进行读写、打开、关闭操作。对文件的操作在应用程序中实现了,这里直接运行它即可。首先进行读操作,输入如下命令:
./chrdevbaseApp /dev/chrdevbase 1


接下来测试对 chrdevbase 设备的写操作,输入如下命令:
./chrdevbaseApp /dev/chrdevbase 2

卸载驱动模块

rmmod chrdevbase.ko

NanoPi NEO Air使用八:编写个简单的驱动和应用程序相关推荐

  1. NanoPi NEO Air使用十五:移植RTL8723BU驱动

    NanoPi NEO Air使用一:介绍 NanoPi NEO Air使用二:固件烧录 NanoPi NEO Air使用三:OverlayFS.CPU温度和频率.wifi.蓝牙.npi-config ...

  2. NanoPi NEO Air使用十五:使用V4L2驱动USB摄像头

    USB摄像头初识   Linux UVC driver(uvc) 该驱动适用于符合USB视频类(USB Video Class)规范的摄像头设备,它包括V4L2内核设备驱动和用户空间工具补丁.大多数大 ...

  3. NanoPi NEO Air使用十一:编写SPI驱动点亮TFT屏幕,ST7789V

    NanoPi NEO Air使用一:介绍 NanoPi NEO Air使用二:固件烧录 NanoPi NEO Air使用三:OverlayFS.CPU温度和频率.wifi.蓝牙.npi-config ...

  4. NanoPi NEO Air使用十:自己编写驱动来控制LED

    NanoPi NEO Air使用一:介绍 NanoPi NEO Air使用二:固件烧录 NanoPi NEO Air使用三:OverlayFS.CPU温度和频率.wifi.蓝牙.npi-config ...

  5. NanoPi NEO Air使用九:使用Linux内核自带的LED驱动

    NanoPi NEO Air使用一:介绍 NanoPi NEO Air使用二:固件烧录 NanoPi NEO Air使用三:OverlayFS.CPU温度和频率.wifi.蓝牙.npi-config ...

  6. NanoPi NEO Air使用七:获取并编译U-boot和Linux的源码

    NanoPi NEO Air使用一:介绍 NanoPi NEO Air使用二:固件烧录 NanoPi NEO Air使用三:OverlayFS.CPU温度和频率.wifi.蓝牙.npi-config ...

  7. NanoPi NEO Air使用六:使用摄像头

    NanoPi NEO Air使用一:介绍 NanoPi NEO Air使用二:固件烧录 NanoPi NEO Air使用三:OverlayFS.CPU温度和频率.wifi.蓝牙.npi-config ...

  8. NanoPi NEO Air使用五:安装Xfce和xrdp,实现远程访问

    NanoPi NEO Air使用一:介绍 NanoPi NEO Air使用二:固件烧录 NanoPi NEO Air使用三:OverlayFS.CPU温度和频率.wifi.蓝牙.npi-config ...

  9. NanoPi NEO Air使用四:操作GPIO

    NanoPi NEO Air使用一:介绍 NanoPi NEO Air使用二:固件烧录 NanoPi NEO Air使用三:OverlayFS.CPU温度和频率.wifi.蓝牙.npi-config ...

最新文章

  1. 盛大文学推出“一人一书”计划,发布电子书战略
  2. 一些随笔,我有故事,你有酒吗
  3. php中输出js语句
  4. JDK、J2EE、J2SE、J2ME的区别
  5. c#-检查USB硬件变化
  6. sscanf函数中类型不匹配警告引发的BUG和思考
  7. Oracle中删除用户和表空间的常见问题(比如:ORA-01940无法删除当前已连接用户的解决方案)
  8. 单变量离散傅里叶变换DFT原理及实现
  9. 【渝粤教育】 国家开放大学2020年春季 1068小企业管理 参考试题
  10. 机器学习算法之 K-means、层次聚类,谱聚类
  11. IntelliJ IDEA 2020 创建xml文件
  12. 如何对 Jenkins 共享库进行单元测试
  13. java实现回溯算法,java基础面试笔试题
  14. mysql的gobye_Mysql學習(一)添加一個新的用戶並用golang操作Mysql
  15. 抽象类与接口的区别与联系
  16. tperformancegraph_列车运行实绩图,train performance graph,音标,读音,翻译,英文例句,英语词典...
  17. PHP修改防火墙ip,利用防火墙进行同网段下的ip地址欺骗
  18. HTML label标签用法介绍
  19. OCV (on-chip-variation)
  20. Python爬虫新手入门教学(十):爬取彼岸4K超清壁纸

热门文章

  1. oculus rift 开发入门
  2. 数学大神攻克猜字游戏Wordle,求解算法成绩逼近理论极限,连信息论都用上了...
  3. 特斯拉2021全年交付近百万辆,同比暴涨87%,马斯克:了不起!
  4. 电脑插个“U盘”就能给基因测序,实时查看结果,售价1000美元
  5. 平板就是生产力?东京大学研究者“辟谣”了,用纸笔记录,更有利于记忆
  6. DeepMind丢掉了归一化,让图像识别训练速度提升了8.7倍 | 已开源
  7. 你们AI圈儿,已经引起了罗马教皇的警惕
  8. 谁是中国CS高引第一人徐泽水?蝉联六年,36000次引用
  9. 用deepfake拍电影可以安排了:迪士尼发布首个百万像素高分辨率换脸算法
  10. 谷歌新App观妙中国发布:AR传承文化艺术,小米vivo应用宝可体验