1.下载树莓派os镜像:https://www.raspberrypi.org/downloads/raspbian/
2.使用命令:uname -a 查看树莓派内核:Linux raspberrypi 4.19.118-v7+ #1311 SMP Mon Apr 27 14:21:24 BST 2020 armv7l GNU/Linux
3.一般使用是树莓派镜像中不含有内核源码,因此要下载树莓派内核源码:在目录/usr/src 下执行命令:sudo apt-get install raspberrypi-kernel-headers
******* 将会下载到与uname -a 查看树莓派内核版本号一致的内核源码。如果不一致,可能无法用于内核驱动的使用。
4.编写驱动helloworld.c
#include
#include
#include
#include
#include
#include
#include
#define HELLOWORLD_MAJOR 200 //主设备号
#define HELLOWORLD_NAME "helloworld" //名字
static char readbuf[30]; /*读缓冲 */
static char writebuf[30]; /* 写缓冲 */
static char kerneldata[] = {"Hello World!"};
static int helloworld_open(struct inode *inode, struct file *filp)
{
printk("helloworld_open\r\n");
return 0;
}
static int helloworld_release(struct inode *inode, struct file *filp)
{
printk("helloworld_release\r\n");
return 0;
}
static ssize_t helloworld_read(struct file *filp, __user char *buf, size_t count,
loff_t *ppos)
{
int ret = 0;
printk("helloworld_read\r\n");
memcpy(readbuf, kerneldata, sizeof(kerneldata));
ret = copy_to_user(buf, readbuf, count);
return 0;
}
static ssize_t helloworld_write(struct file *filp, const char __user *buf,
size_t count, loff_t *ppos)
{
int ret = 0;
printk("helloworld_write\r\n");
ret = copy_from_user(writebuf, buf, count);
if(ret == 0) {
printk("kernel recevdata:%s\r\n", writebuf);
}
return 0;
}
/*
* 字符设备 操作集合
*/
static struct file_operations helloworld_fops={
.owner = THIS_MODULE,
.open = helloworld_open,
.release = helloworld_release,
.read = helloworld_read,
.write = helloworld_write,
};
static int __init helloworld_init(void)
{
int ret = 0;
printk("hello world init\r\n");
/* 注册字符设备 */
ret = register_chrdev(HELLOWORLD_MAJOR, HELLOWORLD_NAME, &helloworld_fops);
if(ret < 0) {
printk("helloworld init failed!\r\n");
}
return 0;
}
static void __exit helloworld_exit(void)
{
printk("helloworld_exit\r\n");
/* 注销字符设备 */
unregister_chrdev(HELLOWORLD_MAJOR, HELLOWORLD_NAME);
}
/*
模块入口与出口
*/
module_init(helloworld_init); /* 入口 */
module_exit(helloworld_exit); /* 出口 */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("changhaijun");
5.编写Makefile
ifneq ($(KERNELRELEASE),)
obj-m := helloworld.o
else
KDIR := /usr/src/linux-headers-4.19.118-v7+/ #树莓派内核源码目录
PWD := $(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules
clean:
rm *.o *.ko *.mod.c modules.order Module.symvers
.PHONY:clean
endif
6.将helloworld.c 和 Makefile 放在同一个目录下执行:make 生成.ko文件
7.加载驱动与卸载驱动
(1)动态加载驱动执行:inmod helloworld.ko 查看驱动是否加载上执行命令:cat /proc/devices
(2)卸载驱动执行命令:rmmod helloworld.ko 查看驱动是否卸载执行命令:cat /proc/devices
8.手动创建设备节点执行命令:mknod /dev/helloworld c 200 0 (c 表示字符设备) 查看是否创建:ls /dev
9.编写应用程序helloworldApp.c
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char *argv[])
{
int ret = 0;
int fd = 0;
char *filename;
char readbuf[30], writebuf[30];
static char usrdata[] = {"user data!"};
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){ /* 璇?*/
/* read */
ret = read(fd, readbuf, 13);
if (ret < 0) {
printf("read file %s failed!\r\n", filename);
}
else {
printf("APP read data:%s\r\n", readbuf);
}
}
/* write */
if(atoi(argv[2]) == 2) { /* 鍐?*/
memcpy(writebuf, usrdata, sizeof(usrdata));
ret = write(fd, writebuf, 11);
if (ret < 0) {
printf("write file %s failed!\r\n", filename);
}else {
printf("APP writedata:%s\r\n", writebuf);
}
}
/* close */
ret = close(fd);
if(ret < 0) {
printf("close file %s falied!\r\n", filename);
}
return 0 ;
}
10.交叉编译工具编译应用程序helloworldApp.c
gcc -Wall -o helloworldApp helloworldApp.c
生成 helloworldApp
11.执行应用程序:./helloworldApp /dev/helloworld 1 输出:APP read data:Hello World!
执行应用程序:./helloworldApp /dev/helloworld 2 输出:APP writedata:user data!