目录

1、手动创建设备文件

2、应用程序如何将数据传递给驱动

3、控制LED灯:

4、应用层控制灯

5、自动创建设备节点


1、手动创建设备文件

cat  /proc/devices 查看主设备号

sudo  mknod hello(路径:任意的)   c/b(C代表字符设备 b代表块设备)主设备号  次设备号

生成hello:应用层可以打开的文件

设置驱动层程序:hello.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/fs.h>  //添加头文件
#define CNAME "hello"
int major=0;
ssize_t mycdev_read (struct file *file, char __user *user, size_t size, loff_t * loff)
{ printk("this is read\n"); return 0;
}
ssize_t mycdev_write (struct file *file, const char __user *user, size_t size, loff_t *loff)
{   printk("this is write\n");  return 0;
}
int mycdev_open (struct inode *inode, struct file *file)
{   printk("this is open\n");
return 0;
}
int mycdev_release (struct inode *inode, struct file *file)
{   printk("this is close\n");   return 0;
}
const struct file_operations fops={   .open=mycdev_open,   .read=mycdev_read,   .write=mycdev_write,   .release=mycdev_release,
};
static int __init hello_init(void)//入口
{ major=register_chrdev(major,CNAME,&fops); if(major<0)  {   printk("register chrdev error"); } return 0;
}
static void __exit hello_exit(void)//出口
{  unregister_chrdev(major,CNAME);
}
module_init(hello_init);//告诉内核驱动的入口module_exit(hello_exit);//告诉内核驱动的出口MODULE_LICENSE("GPL");

 设置应用层程序:test.c

2、应用程序如何将数据传递给驱动

(读写的方向是站在用户的角度来说的)

#include <linux/uaccess.h>

int copy_from_user(void *to, const void __user *from, int n)

功能:从用户空间拷贝数据到内核空间

参数:

@to  :内核中内存的首地址

@from:用户空间的首地址

@n   :拷贝数据的长度(字节)

返回值:成功返回0,失败返回未拷贝的字节的个数

int copy_to_user(void __user *to, const void *from, int n)

功能:从内核空间拷贝数据到用户空间

参数:

@to  :用户空间内存的首地址

@from:内核空间的首地址  __user需要加作用是告诉编译器这是用户空间地址

@n   :拷贝数据的长度(字节)

返回值:成功返回0,失败返回未拷贝的字节的个数

驱动层:hello.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/uaccess.h>   //添加头文件
#include <linux/fs.h>
#define CNAME "hello"
int major=0;
char kbuf[128]={0}; //存储数据
int dev=0;
ssize_t mycdev_read (struct file *file, char __user *user, size_t size, loff_t * loff)
{//printk("this is read\n");if(size>sizeof(kbuf)){size=sizeof(kbuf);}dev=copy_to_user(user,kbuf,size);  //从内核空间到用户空间if(dev){printk("copy to user err");return dev;}return 0;
}
ssize_t mycdev_write (struct file *file, const char __user *user, size_t size, loff_t *loff)
{  //printk("this is write\n");  if(size>sizeof(kbuf)){size=sizeof(kbuf);}dev=copy_from_user(kbuf,user,size);   //从用户空间到内核空间return 0;
}
int mycdev_open (struct inode *inode, struct file *file)
{  printk("this is open\n");
return 0;
}
int mycdev_release (struct inode *inode, struct file *file)
{  printk("this is close\n");  return 0;
}
const struct file_operations fops={  .open=mycdev_open,  .read=mycdev_read,  .write=mycdev_write,  .release=mycdev_release,
};
static int __init hello_init(void)//入口
{major=register_chrdev(major,CNAME,&fops);if(major<0)  {  printk("register chrdev error");}
return 0;
}
static void __exit hello_exit(void)//出口
{  unregister_chrdev(major,CNAME);
}
module_init(hello_init);//告诉内核驱动的入口
module_exit(hello_exit);//告诉内核驱动的出口
MODULE_LICENSE("GPL");

应用程序:test.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
char buf[128]="hello world!";
int main(int argc, const char *argv[])
{int fd;fd=open("./hello",O_RDWR);if(fd==-1)
{perror("open error");return -1;
}write(fd,buf,sizeof(buf));memset(buf,0,sizeof(buf));read(fd,buf,sizeof(buf));printf("buf is :%s\n",buf);close(fd);return 0;
}

$make

$sudo insmod hello.ko

$gcc test.c

$./a.out

$dmesg

3、控制LED灯:

驱动如何操作寄存器

rgb_led灯的寄存器是物理地址,在linux内核启动之后,在使用地址的时候操作的全是虚拟地址,需要将物理地址转化为虚拟地址。在驱动代码中操作的虚拟地址就相当于操作实际的物理地址。

物理地址<------>虚拟地址

void * ioremap(phys_addr_t offset, unsigned long size)

功能:将物理地址映射成虚拟地址

参数:@offset :要映射的物理地址

@size   :大小(字节)

返回值:成功返回虚拟地址,失败返回NULL;

void iounmap(void  *addr)

功能:取消映射

参数: @addr :虚拟地址

返回值:无

RGB_led

red  :gpioa28

GPIOXOUT   :控制高低电平的   0xC001A000

GPIOxOUTENB:输入输出模式    0xC001A004

GPIOxALTFN1:function寄存器  0xC001A024

green:gpioe13    0xC001e000

blue :gpiob12     0xC001b000

 R:GPIOA

G: GPIOE

 B: GPIOB

宏定义基地址 ,设置虚拟地址

 将物理地址映射成虚拟地址

指针类型加1是加的类型大小

 添加头文件:#include <linux/io.h>

取消映射:

将hello.ko拷贝到开发板内核文件夹中指针类型加1是加的类型大小

#include <linux/init.h>
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/io.h>     //添加头文件
int major=0;
#define CNAME "hello"
char kbuf[128]={0};
int dev=0;
#define RED_BASE  0XC001A000
#define BLUE_BASE  0XC001B000
#define GREEN_BASE 0XC001E000
unsigned int *red_base=NULL;
unsigned int *blue_base=NULL;
unsigned int *green_base=NULL;
ssize_t mycdev_read (struct file *file, char __user *user, size_t size, loff_t * loff)
{//printk("this is read");if(size>128){    size=128;}
    dev=copy_to_user(user,kbuf,size);if(dev){printk("copy to user errer");return dev;}return 0;
}
ssize_t mycdev_write (struct file *file, const char __user *user, size_t size, loff_t *loff)
{//printk("this is write");if(size>128){    size=128;}
    dev=copy_from_user(kbuf,user,size);return 0;
}
int mycdev_open (struct inode *inode, struct file *file)
{printk("this is open");return 0;
}
int mycdev_release (struct inode *inode, struct file *file)
{printk("this is close");return 0;
}
const struct file_operations fops={.open=mycdev_open,.read=mycdev_read,.write=mycdev_write,.release=mycdev_release,
};
static int __init hello_init(void)//入口
{  major=register_chrdev(major,CNAME,&fops);if(major<0){printk("register chrdev error");}
  red_base=ioremap(RED_BASE,36);if(red_base==NULL){printk("red ioremap error\n");return -ENOMEM;}
  blue_base=ioremap(BLUE_BASE,36);if(blue_base==NULL){printk("blue ioremap error\n");return -ENOMEM;}
    green_base=ioremap(GREEN_BASE,36);if(green_base==NULL){printk("green ioremap error\n");return -ENOMEM;}*red_base &=~(1<<28);*(red_base+1) |=1<<28;  //指针类型加1是加的类型大小  int占4字节*(red_base+9) &=~(3<<24);return 0;
}
static void __exit hello_exit(void)//出口
{iounmap(green_base);iounmap(blue_base);iounmap(red_base);unregister_chrdev(major,CNAME);
}
module_init(hello_init);//告诉内核驱动的入口
module_exit(hello_exit);//告诉内核驱动的出口
MODULE_LICENSE("GPL");

Makefile:

开发板上电测试:

4、应用层控制灯

1、 驱动层

判断语句 、宏定义开关

#define RED_ON *red_base |= 1<<28
#define RED_OF *red_base &= ~(1<<28)
ssize_t mycdev_write (struct file *file, const char __user *user, size_t size, loff_t *loff)
{//printk("this is write");if(size>128){    size=128;}
    dev=copy_from_user(kbuf,user,size);if(kbuf[0]==1){        RED_ON;}else{        RED_OF;}return 0;
}

2、应用层

需要将test.c 在开发板中进行编译,还需要拷贝编译生成的a.out,所以直接在Makefile中添加两行代码:


while(1){write(fd,buf,sizeof(buf));sleep(1);
        buf[0]=buf[0]?0:1;}

驱动开发--创建设备文件--控制LED灯相关推荐

  1. STM32MP157驱动开发——Linux自带的LED灯驱动

    STM32MP157驱动开发--Linux自带的LED灯驱动 0.前言 一.Linux 内核自带 LED 驱动使能 二.驱动简介 1.LED灯驱动框架分析 2.module_platform_driv ...

  2. 手把手教你智能硬件开发(三) 控制LED灯

    第3节 控制LED灯 现在我们开始尝试用代码控制一个真正的直观的硬件设备. 第一个例子:让Arduino开发板上的一个LED小灯周期性的打开.关闭. 第二个例子:让LED灯亮度逐渐的变亮变暗. 3.1 ...

  3. 驱动开发指南 第八章 汇编LED灯实验

    <I.MX6U 嵌入式 x Linux 驱动开发指南 V1.6 6>第八章 汇编LED灯实验 正点原子[第二期]手把手教你学Linux之ARM(MX6U)裸机篇 视频 选集 时间 P6 第 ...

  4. ADSP-21489的开发详解:VDSP+自己编程写代码开发(4-按键控制 LED 灯)(含源代码)

    硬件准备 ADSP-21489EVB:ADI 21489处理器的开发板 AD-HP530ICE:ADI DSP专用仿真器 USBi:ADI SigmaDSP和SHARC DSP的图形化编程调试器 软件 ...

  5. 基于Arduino IDE平台开发ESP8266天猫精灵控制LED灯

    Arduino教程传送门

  6. I.MX6ULL ARM驱动开发---platfrom设备驱动

    引言   对IO进行最简单的读写操作,设备驱动都非常的简单.像I2C.SPI.LCD 等这些复杂外设的驱动就不能这么去写了,Linux 系统要考虑到驱动的可重用性,因此提出了驱动的分离与分层这样的软件 ...

  7. linux字符设备led驱动源码,字符设备驱动控制LED灯

    开发板:龙芯1B PC:Ubuntu 13.10 本程序为字符设备驱动,提供控制led灯功能,如要实现控制需要自己写应用程序,打开驱动文件就可控制led灯,led灯通过gpio控制 #include ...

  8. Linux设备树led,linux设备树下LED灯控制

    linux设备树下LED灯控制 linux设备树下LED灯控制 原理图: 所以在设备树下子节点下插入gpioled节点: gpioled { #address-cells = <1>; # ...

  9. 第45讲 控制LED灯设备

    学习资料来自于: 野火[第一期]Linux系列教学视频之"零基础入门"篇,手把手教学,从0开始,基于野火i.MX6ULL Pro/MINI开发板 第45讲 控制LED灯设备_哔哩哔 ...

最新文章

  1. Python小程序:你看?这千年难遇的雪景—简直“美到犯规” 【满屏雪花飞舞 】
  2. 关于MATLAB处理大数据坐标文件2017529
  3. oracle批处理脚本学习总结
  4. Jenkins环境搭建(2)-搭建jmeter+ant+jenkins自动化测试环境
  5. 《操作系统》OS学习(十):进程控制
  6. mysql mgr 三节点_详解MySQL 5.7 MGR单主确定主节点方法
  7. tidb 架构 ~Tidb学习系列(5)
  8. 理论题 —— Windows 7基础知识
  9. [转载] Python format()格式:中文对齐问题
  10. 计算机的拓扑 树状结构图,树型网络拓扑结构
  11. (转)200亿美元比特币找不到主人,这个邪恶职业一夜爆火
  12. 在深度学习时代如何用 HowNet 搞事情 | 讲座笔记
  13. 基于Levy飞行策略的改进樽海鞘群算法( LECUSSA) Matlab代码
  14. 傅里叶变换时域和频域之间的对应关系
  15. Oracle 11gR2 RSF(Recurive Subquery factoring)
  16. 失业登记对养老保险是否有影响
  17. Java基础 DAY13
  18. 聊聊苹果审核——App Store Review Guidelines
  19. Python基础知识学习(六)——包与模块:指令、包加载步骤、搜索范围
  20. 会计培训计算机,《会计计算机培训》PPT课件.ppt

热门文章

  1. 8.MATLAB变量——字符串操作
  2. maven打包本地jar到项目中
  3. IT综合运维系统-身份对接记录
  4. Xstart连接Windows和远程Linux图形化界面
  5. TEE OS中断篇(三):中断的向量表
  6. 爱立信助力Robi Axiata进行网络升级
  7. feign原理和使用
  8. 实用拜占庭容错算法 (PBFT)
  9. 江西百岁和尚还俗娶妻办砖厂
  10. ue4手机ui_UE4入门之路(UI篇):UI性能优化