在开发板上,有三个LED灯.如何通过应用程序点亮这三个灯如何编写驱动程序

操作硬件的时候,我们需要准备开发板的原理图和开发手册,,根据这两个文档来进行配置

在source insight 编写代码

1 第一个led驱动程序

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>static struct class *firstled_drv_class;
static struct class_device  *firstled_drv_class_dev;volatile unsigned long *gpfcon = NULL;//指向控制寄存器的地址的指针
volatile unsigned long *gpfdat = NULL;//指向数据寄存器的地址的指针static int firstled_drv_open(struct inode *inode, struct file *file)
{//printk("firstled_drv_open\n");/* 配置GPF4,5,6为输出 */*gpfcon &= ~((0x3<<(4*2)) | (0x3<<(5*2)) | (0x3<<(6*2)));//将 4 5 6 位清零*gpfcon |= ((0x1<<(4*2)) | (0x1<<(5*2)) | (0x1<<(6*2)));// 将 4 5 6 设为1 输出引脚return 0;
}static ssize_t firstled_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{int val;//printk("firstled_drv_write\n");copy_from_user(&val, buf, count); //    copy_to_user();if (val == 1){// 点灯*gpfdat &= ~((1<<4) | (1<<5) | (1<<6));}else{// 灭灯*gpfdat |= (1<<4) | (1<<5) | (1<<6);}return 0;
}/*定义一个file_operations结构体
怎么用  告诉内核?*/
static struct file_operations firstled_drvfops = {.owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */.open   =   firstled_drv_open,     .write    =  firstled_drv_write,
};int major;
//驱动的入口  写出来是一般的函数  需要修饰
static int firstled_drv_init(void)
{//注册告诉内核  主设备号  名字(随便写)  结构体//app找到这个驱动  不是根据名字  是根据  设备类型 主设备号//主设备号 随便写个123  写 0会自动分配major = register_chrdev(0, "firstled_drv", &firstled_drv_fops); // 注册, 告诉内核firstled_drv_class = class_create(THIS_MODULE, "firstled_drv");firstled_drv_class_dev = class_device_create(firstled_drv_class, NULL, MKDEV(major, 0), NULL, "xyz"); /* /dev/xyz */gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);gpfdat = gpfcon + 1;return 0;
}static void firstled_drv_exit(void)
{//123unregister_chrdev(major, "firstled_drv"); // 卸载class_device_unregister(firstled_drv_class_dev);class_destroy(firstled_drv_class);iounmap(gpfcon);
}//通过修饰  成为入口函数 内核会找到这个函数
//对与驱动  是c
module_init(firstled_drv_init);
//通过修饰  成为出口函数  内核来调用
//用宏来定义一个指针
module_exit(firstled_drv_exit);MODULE_LICENSE("GPL");

2 编写makefile文件

KERN_DIR = /work/system/linux-2.6.22.6all:make -C $(KERN_DIR) M=`pwd` modules clean:make -C $(KERN_DIR) M=`pwd` modules cleanrm -rf modules.orderobj-m    += firstled_drv.o

将代码上传到linux服务器,编译 放到网络文件系统上,进入开发板,挂接驱动,

insmod firstled_drv.ko
# cat /proc/devices
Character devices:1 mem2 pty3 ttyp4 /dev/vc/04 tty4 ttyS5 /dev/tty5 /dev/console5 /dev/ptmx6 lp7 vcs10 misc13 input14 sound29 fb90 mtd99 ppdev
116 alsa
128 ptm
136 pts
180 usb
189 usb_device
204 s3c2410_serial
252 firstled_drv
253 usb_endpoint
254 rtcBlock devices:1 ramdisk7 loop8 sd31 mtdblock65 sd66 sd67 sd68 sd69 sd70 sd71 sd
128 sd
129 sd
130 sd
131 sd
132 sd
133 sd
134 sd
135 sd
179 mmc

创建设备目录节点

# mknod  /dev/xyz c 252 0

3 编写测试程序

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>/* firstleddrvtest on* firstleddrvtest off*/
int main(int argc, char **argv)
{int fd;int val = 1;fd = open("/dev/xyz", O_RDWR);if (fd < 0){printf("can't open!\n");}if (argc != 2){printf("Usage :\n");printf("%s <on|off>\n", argv[0]);return 0;}if (strcmp(argv[1], "on") == 0){val  = 1;}else{val = 0;}write(fd, &val, 4);return 0;
}

上传到服务器,编译,放到网络文件系统

 arm-linux-gcc ledtest firstleddevtest.c cp firstleddevtest /work/nfs_root/first_fs

在开发板上运行程序

# cd /mnt/
# ./firstled_drv_test
first_drv_open
Usage :
./firstled_drv_test <on|off>
# ./firstled_drv_test off
first_drv_open
first_drv_write
# ./firstled_drv_test on
first_drv_open
first_drv_write
# ./firstled_drv_test off
first_drv_open
first_drv_write
# 

看到开发板灯亮灯灭

4 继续编写LED驱动代码

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>#define DEVICE_NAME     "leds"  /* 加载模式后,执行”cat /proc/devices”命令看到的设备名称 */
#define LED_MAJOR       231     /* 主设备号 */static struct class *leds_class;
static struct class_device  *leds_class_devs[4];/* bit0<=>D10, 0:亮, 1:灭 *  bit1<=>D11, 0:亮, 1:灭 *  bit2<=>D12, 0:亮, 1:灭 */
static char leds_status = 0x0;
static DECLARE_MUTEX(leds_lock); // 定义赋值//static int minor;
static unsigned long gpio_va;#define GPIO_OFT(x) ((x) - 0x56000000)
#define GPFCON  (*(volatile unsigned long *)(gpio_va + GPIO_OFT(0x56000050)))
#define GPFDAT  (*(volatile unsigned long *)(gpio_va + GPIO_OFT(0x56000054)))/* 应用程序对设备文件/dev/leds执行open(...)时,* 就会调用s3c24xx_leds_open函数*/
static int s3c24xx_leds_open(struct inode *inode, struct file *file)
{int minor = MINOR(inode->i_rdev); //MINOR(inode->i_cdev);switch(minor){case 0: /* /dev/leds */{// 配置3引脚为输出//s3c2410_gpio_cfgpin(S3C2410_GPF4, S3C2410_GPF4_OUTP);GPFCON &= ~(0x3<<(4*2));GPFCON |= (1<<(4*2));//s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP);GPFCON &= ~(0x3<<(5*2));GPFCON |= (1<<(5*2));//s3c2410_gpio_cfgpin(S3C2410_GPF6, S3C2410_GPF6_OUTP);GPFCON &= ~(0x3<<(6*2));GPFCON |= (1<<(6*2));// 都输出0//s3c2410_gpio_setpin(S3C2410_GPF4, 0);GPFDAT &= ~(1<<4);//s3c2410_gpio_setpin(S3C2410_GPF5, 0);GPFDAT &= ~(1<<5);//s3c2410_gpio_setpin(S3C2410_GPF6, 0);GPFDAT &= ~(1<<6);down(&leds_lock);leds_status = 0x0;up(&leds_lock);break;}case 1: /* /dev/led1 */{s3c2410_gpio_cfgpin(S3C2410_GPF4, S3C2410_GPF4_OUTP);s3c2410_gpio_setpin(S3C2410_GPF4, 0);down(&leds_lock);leds_status &= ~(1<<0);up(&leds_lock);break;}case 2: /* /dev/led2 */{s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP);s3c2410_gpio_setpin(S3C2410_GPF5, 0);leds_status &= ~(1<<1);break;}case 3: /* /dev/led3 */{s3c2410_gpio_cfgpin(S3C2410_GPF6, S3C2410_GPF6_OUTP);s3c2410_gpio_setpin(S3C2410_GPF6, 0);down(&leds_lock);leds_status &= ~(1<<2);up(&leds_lock);break;}}return 0;
}static int s3c24xx_leds_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
{int minor = MINOR(filp->f_dentry->d_inode->i_rdev);char val;switch (minor){case 0: /* /dev/leds */{copy_to_user(buff, (const void *)&leds_status, 1);                    break;}case 1: /* /dev/led1 */{down(&leds_lock);val = leds_status & 0x1;up(&leds_lock);copy_to_user(buff, (const void *)&val, 1);break;}case 2: /* /dev/led2 */{down(&leds_lock);val = (leds_status>>1) & 0x1;up(&leds_lock);copy_to_user(buff, (const void *)&val, 1);break;}case 3: /* /dev/led3 */{down(&leds_lock);val = (leds_status>>2) & 0x1;up(&leds_lock);copy_to_user(buff, (const void *)&val, 1);break;}}return 1;
}static ssize_t s3c24xx_leds_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{//int minor = MINOR(inode->i_rdev); //MINOR(inode->i_cdev);int minor = MINOR(file->f_dentry->d_inode->i_rdev);char val;copy_from_user(&val, buf, 1);switch (minor){case 0: /* /dev/leds */{            s3c2410_gpio_setpin(S3C2410_GPF4, (val & 0x1));s3c2410_gpio_setpin(S3C2410_GPF5, (val & 0x1));s3c2410_gpio_setpin(S3C2410_GPF6, (val & 0x1));down(&leds_lock);leds_status = val;up(&leds_lock);break;}case 1: /* /dev/led1 */{s3c2410_gpio_setpin(S3C2410_GPF4, val);if (val == 0){down(&leds_lock);leds_status &= ~(1<<0);up(&leds_lock);}else{down(&leds_lock);leds_status |= (1<<0);                up(&leds_lock);}break;}case 2: /* /dev/led2 */{s3c2410_gpio_setpin(S3C2410_GPF5, val);if (val == 0){down(&leds_lock);leds_status &= ~(1<<1);up(&leds_lock);}else{down(&leds_lock);leds_status |= (1<<1);                up(&leds_lock);}break;}case 3: /* /dev/led3 */{s3c2410_gpio_setpin(S3C2410_GPF6, val);if (val == 0){down(&leds_lock);leds_status &= ~(1<<2);up(&leds_lock);}else{down(&leds_lock);leds_status |= (1<<2);                up(&leds_lock);}break;}}return 1;
}/* 这个结构是字符设备驱动程序的核心* 当应用程序操作设备文件时所调用的open、read、write等函数,* 最终会调用这个结构中指定的对应函数*/
static struct file_operations s3c24xx_leds_fops = {.owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */.open   =   s3c24xx_leds_open,     .read    =  s3c24xx_leds_read,     .write   =  s3c24xx_leds_write,
};/** 执行insmod命令时就会调用这个函数 */
static int __init s3c24xx_leds_init(void)
//static int __init init_module(void){int ret;int minor = 0;gpio_va = ioremap(0x56000000, 0x100000);if (!gpio_va) {return -EIO;}/* 注册字符设备* 参数为主设备号、设备名字、file_operations结构;* 这样,主设备号就和具体的file_operations结构联系起来了,* 操作主设备为LED_MAJOR的设备文件时,就会调用s3c24xx_leds_fops中的相关成员函数* LED_MAJOR可以设为0,表示由内核自动分配主设备号*/ret = register_chrdev(LED_MAJOR, DEVICE_NAME, &s3c24xx_leds_fops);if (ret < 0) {printk(DEVICE_NAME " can't register major number\n");return ret;}leds_class = class_create(THIS_MODULE, "leds");if (IS_ERR(leds_class))return PTR_ERR(leds_class);leds_class_devs[0] = class_device_create(leds_class, NULL, MKDEV(LED_MAJOR, 0), NULL, "leds"); /* /dev/leds */for (minor = 1; minor < 4; minor++)  /* /dev/led1,2,3 */{leds_class_devs[minor] = class_device_create(leds_class, NULL, MKDEV(LED_MAJOR, minor), NULL, "led%d", minor);if (unlikely(IS_ERR(leds_class_devs[minor])))return PTR_ERR(leds_class_devs[minor]);}printk(DEVICE_NAME " initialized\n");return 0;
}/** 执行rmmod命令时就会调用这个函数 */
static void __exit s3c24xx_leds_exit(void)
{int minor;/* 卸载驱动程序 */unregister_chrdev(LED_MAJOR, DEVICE_NAME);for (minor = 0; minor < 4; minor++){class_device_unregister(leds_class_devs[minor]);}class_destroy(leds_class);iounmap(gpio_va);
}/* 这两行指定驱动程序的初始化函数和卸载函数 */
module_init(s3c24xx_leds_init);
module_exit(s3c24xx_leds_exit);/* 描述驱动程序的一些信息,不是必须的 */
MODULE_LICENSE("GPL");

编写makefile代码

KERN_DIR = /work/system/linux-2.6.22.6all:make -C $(KERN_DIR) M=`pwd` modules clean:make -C $(KERN_DIR) M=`pwd` modules cleanrm -rf modules.orderobj-m    += myleds.o

测试程序

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>/**  ledtest <dev> <on|off>*/void print_usage(char *file)
{printf("Usage:\n");printf("%s <dev> <on|off>\n",file);printf("eg. \n");printf("%s /dev/leds on\n", file);printf("%s /dev/leds off\n", file);printf("%s /dev/led1 on\n", file);printf("%s /dev/led1 off\n", file);
}int main(int argc, char **argv)
{int fd;char* filename;char val;if (argc != 3){print_usage(argv[0]);return 0;}filename = argv[1];fd = open(filename, O_RDWR);if (fd < 0){printf("error, can't open %s\n", filename);return 0;}if (!strcmp("on", argv[2])){// 亮灯val = 0;write(fd, &val, 1);}else if (!strcmp("off", argv[2])){// 灭灯val = 1;write(fd, &val, 1);}else{print_usage(argv[0]);return 0;}return 0;
}

运行程序

# mknod  /dev/leds c 231 0
# mknod  /dev/led1 c 231 1
# mknod  /dev/led2 c 231 2
# mknod  /dev/led3 c 231 3
# ./ledtest 0
Usage:
./ledtest <dev> <on|off>
eg.
./ledtest /dev/leds on
./ledtest /dev/leds off
./ledtest /dev/led1 on
./ledtest /dev/led1 off
# ./ledtest 1
Usage:
./ledtest <dev> <on|off>
eg.
./ledtest /dev/leds on
./ledtest /dev/leds off
./ledtest /dev/led1 on
./ledtest /dev/led1 off
# ./ledtest of
Usage:
./ledtest <dev> <on|off>
eg.
./ledtest /dev/leds on
./ledtest /dev/leds off
./ledtest /dev/led1 on
./ledtest /dev/led1 off
# ./ledtest ooff
Usage:
./ledtest <dev> <on|off>
eg.
./ledtest /dev/leds on
./ledtest /dev/leds off
./ledtest /dev/led1 on
./ledtest /dev/led1 off
# ./ledtest off
Usage:
./ledtest <dev> <on|off>
eg.
./ledtest /dev/leds on
./ledtest /dev/leds off
./ledtest /dev/led1 on
./ledtest /dev/led1 off
# ./ledtest on
Usage:
./ledtest <dev> <on|off>
eg.
./ledtest /dev/leds on
./ledtest /dev/leds off
./ledtest /dev/led1 on
./ledtest /dev/led1 off
# ./ledtest /dev/led1 off
# ./ledtest /dev/led1 on
# ./ledtest /dev/led2 off
# ./ledtest /dev/led2 on
# ./ledtest /dev/leds on
# ./ledtest /dev/leds off
# ./ledtest /dev/led3 off
# ./ledtest /dev/led3 on
# ./ledtest /dev/leds on

嵌入式驱动编写-点亮LED驱动程序相关推荐

  1. 嵌入式实验-汇编点亮LED 灯

    嵌入式实验-汇编点亮LED 灯 一.实验目的 通过本次实验,使学生能够操作 S5PV210实验平台,搭建并使用交叉编译环境,具备初步的嵌入式裸机平台应用开发能力. 二.实验原理 由原理图可知,点亮 2 ...

  2. linux字符驱动之点亮LED

    上一节中,我们讲解了如何自动创建设备节点,这一节我们在上一节的基础上,实现点亮LED. 上一节文章链接:https://blog.csdn.net/qq_37659294/article/detail ...

  3. 嵌入式驱动编写-LCD驱动程序

    如何来写LCD的驱动程序,首先 看芯片开发手册和原理图 根据原理图,找到s3c2440的GPIO控制管脚,gpb   gpc  gpd  gpg管脚控制 需要设置寄存器 以及设置LCD控制寄存器 查看 ...

  4. 嵌入式开发板02---点亮LED升级版

    LED汇编的复杂编写 首先,每次地址的输入都需要自己输入,非常容易输入错误,所以使用宏定义: #define GPJ0CON 0xE0200040 同时在编写的汇编程序进行make时会有警告,找不到_ ...

  5. 嵌入式开发板01---点亮LED

    开发板设置 将启动方式选择为从USB启动,通过串口和USB与电脑相连.在电脑上安装USB的驱动.利用dnw软件将程序下载进开发板.具体的流程请看朱有鹏老师的讲解视频. 下面总结一下整个编写流程: 假定 ...

  6. hello 驱动编写-最简单的驱动程序

    在前面学习了树莓派字符设备驱动代码编写和编译,但一直不是特别明白,现在学习100ask_imx6ull_mini的驱动框架时更加清楚了一些,所以重新记录下来.整个编写和编译流程与树莓派区别不大,思路相 ...

  7. 蓝桥杯嵌入式第一篇 点亮LED灯开启成功之路

    文章目录 前言 一.准备工作 1.拿到开发板第一步看原理图 2.下载STM32cubeMX 二.开始点灯 1.查看LED原理图 2.cubeMX配置 3.代码实现 总结 前言 从这篇文章开始将为大家带 ...

  8. i.MX6ULL驱动开发 | 24 - 基于platform平台驱动模型点亮LED

    一.编写基本设备驱动模块 编写驱动模块源码: #include <linux/module.h> #include <linux/init.h>static int __ini ...

  9. linux驱动编写--2--应用程序控制led闪烁

    本系列教程的上一篇:  linux驱动编写--1--点亮led 目标:编写一个驱动程序,实现上一篇没写的 "接口".并编写一个测试程序,透过驱动来控制led闪烁. 硬件:micro ...

最新文章

  1. 【LibreOJ】#541. 「LibreOJ NOIP Round #1」七曜圣贤
  2. Merkle Tree(梅克尔树)算法解析
  3. linux安装mysql、卸载mysql、设置mysql
  4. Ubuntu设置环境变量并立即生效
  5. adc0832对光电二极管进行数据采集_一种基于光电二极管的麦克风跟踪检测电路的制作方法...
  6. 【Pytorch神经网络实战案例】01 CIFAR-10数据集:Pytorch使用GPU训练CNN模版-方法①
  7. 多年以前提高asp.net分页查询效率的一个实例
  8. 计算机磁盘管理使用不,win10系统提示“操作无法完成,因为磁盘管理控制台不是最新状态”的处理方法...
  9. 音频的相MATLAB,音频处理后频率响应和相位响应问题
  10. Elasticsearch在后台启动
  11. 高级GIS-1.提取纯净像元
  12. python办公自动化——批量合并工作簿案例
  13. Java——通过Java代码从ftp服务器下载文件
  14. 计算机二级考试报名如何上传照片?
  15. 苏州大学在职研究生计算机专业,苏州大学在职研究生入学须知
  16. 智能运营助你轻松玩转消息推送
  17. 浅谈滴滴需求响应式公交背后的技术
  18. 【老本行的碎碎念】- - 关于新闻传播的整体认识和下一步规划 - - 开始继续充电趴!~ :D
  19. 成都服务器销售熊掌号,百度熊掌号主页可以做产品词排名吗
  20. js 弹出QQ对话框

热门文章

  1. 常州大学新生赛 F-大佬的生日礼包
  2. Datetimepicker.js用法
  3. 【Android技巧】通过am完成发送开机广播等操作
  4. 康耐视VisionPro工业标定
  5. ISE综合工具XST综合约束相关
  6. 【苹果虚拟机真机】群控软件安装操作补码主动扫描或手动过滤
  7. 体会IBM的思维——参加2011年IBM大济南区高峰论坛体会摘要
  8. java计算机毕业设计bs架构实习管理系统源码+mysql数据库+系统+lw文档+部署
  9. 1.1 Introduction中 Consumers官网剖析(博主推荐)
  10. 哈工大计算金融本科新专业 | 全国首发