当前位置: 首页 > news >正文

高校网站建设/今日热点新闻2022

高校网站建设,今日热点新闻2022,福州市网站建设有限公司,培训网站html在上一节中已经将驱动程序框架搭建好了 接下来开始写硬件的操作(控制LED): (1)看原理图,确定引脚 (2)看2440手册 (3)写代码(需要使用ioremap()函数映射虚拟地址,在linux中只能使用虚拟地址) (4)修改上一节的测试程序 (5)使用次设备号来控制设备下不同的灯…

在上一节中已经将驱动程序框架搭建好了

接下来开始写硬件的操作(控制LED):

(1)看原理图,确定引脚

(2)看2440手册

(3)写代码(需要使用ioremap()函数映射虚拟地址,在linux中只能使用虚拟地址)

(4)修改上一节的测试程序

(5)使用次设备号来控制设备下不同的灯

1.看led引脚

最终确定: LED1 ->GPF4  LED2 ->GPF5   LED3 ->GPF6

2.看2440手册

配置GPFCON[15:0](0x56000050)的位[8:9]、位[10:11]、位[12:13] 都等于0x01(输出模式)

控制GPFDAT[7:0](0x56000054)中的位4~6来使灯亮灭(低电平亮)

3.写代码

3.1添加全局变量:

volatile unsigned long *GPFcon=NULL;       volatile unsigned long *GPFdat=NULL;

3.2 first_drv_init入口函数中使用ioremap()映射虚拟地址:

GPFcon = ioremap(0x56000050, 16);   //ioremap:物理地址映射,返回虚拟地址GPFdat=GPFcon+1;             //long:32位,所以GPFdat=0x56000050+(32/8)

3.3 first_drv_exit出口函数中注销虚拟地址:

iounmap(GPFcon);          //注销虚拟地址

3.4 first_drv_open函数中添加配置GPFCON:

*GPFcon&=~ ((0X11<<8)| (0X11<<10)| (0X11<<12)); *GPFcon|=    ((0X01<<8)| (0X01<<10)| (0X01<<12)); 

3.5 first_drv_write函数中添加拷贝应用层数据,然后来控制GPFDAT:

/*copy_to_user():将数据上给用户*/
copy_from_user(&val,buf,count);      //从用户(应用层)拷贝数据                                                            if(val==1)                  //点灯(低电平亮){  *GPFdat&=~((0X1<<4)| (0X1<<5)| (0X1<<6)); }else                  //灭灯{*GPFdat|=((0X1<<4)| (0X1<<5)| (0X1<<6));    }

4.修改测试程序main()

代码如下:

int main(int argc,char **argv) //argc:参数个数,argv数组
{
int fd1, fd2;
int val=1;
fd1 = open("/dev/xyz",O_RDWR);  //打开/dev/xxx设备节点
if(fd1<0)                   //无法打开,返回-1printf("can't open%d!\n", fd1); if(argc!=2){printf("Usage:\n");printf("%s <on|off>",argv[0]);return 0;}if(strcmp(argv[1],"on")==0)   //开灯{printf("led on...\n");val=1;} else                         //关灯{printf("led off...\n");val=0;}write(fd1, &val, 4);
return 0;
}

当输入first_driver_text on点3个灯, 否则关3个灯

若参数不等于2时,不能控制点灯

如果我们想分别控制不同的灯,该怎么做?

可以使用此设备号,此设备号就是用来区分同一设备下不同子设备

5使用次设备号来控制设备下不同的灯

我们先来看下面两个函数MAJOR和MINOR,分别是提取主次设备号

minor=MINOR(inode->i_rdev);    //open函数中提取次设备号
major=MAJOR(inode->i_rdev);    //open函数中提取主设备号minor=MINOR (file->f_dentry->d_inode->i_rdev);  //write/read函数中提取次设备号
major= MAJOR (file->f_dentry->d_inode->i_rdev); //write/read函数中提取主设备号

思路如下:

在测试程序中:

通过dev[1]来open打开不同的子设备节点,然后通过dev[2]来write写入数据

实例: 

first_driver_text led1 on        //点亮led1

在first_dev.c驱动文件中:

first_drv_init函数中创建不同的子设备节点

first_drv_exti函数中注销不同的子设备节点

first_drv_open函数中通过MINOR(inode->i_rdev)来初始化不同的灯

first_drv_write函数中通过MINOR(file->f_dentry->d_inode->i_rdev)来控制不同的灯

如下图,insmod后自动注册3个设备节点

测试程序如下:     

#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;
}

驱动程序如下:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
#include <asm/uaccess.h>
#include <asm/io.h>static struct class *firstdrv_class;               //创建一个class类
static struct class_device   *firstdrv_class_devs[4]; //创建类的设备,led,led1,led2,led3volatile unsigned long *GPFcon=NULL;       
volatile unsigned long *GPFdat=NULL;/*1写出驱动程序first_drv_open first_drv_write */
static int first_drv_open(struct inode *inode, struct file  *file)
{ int minor=MINOR(inode->i_rdev); printk("first_drv_open\n");      //打印,在内核中打印只能用printk() GPFcon = ioremap(0x56000050, 16);   //ioremap:物理地址映射,返回虚拟地址GPFdat=GPFcon+1;                   //long:32位,所以GPFdat=0x56000050+(32/8)switch(minor){case 0:                              //进入led设备,控制所有led*GPFcon&=~ ((0X3<<8)| (0X3<<10)| (0X3<<12)); *GPFcon|=    ((0X01<<8)| (0X01<<10)| (0X01<<12)); break;case 1:                              //进入led1设备,控制 led1*GPFcon&=~ ((0X3<<8) ); *GPFcon|=    (0X1<<8) ; break;     case 2:                                                 //进入led2设备,控制 led2*GPFcon&=~ ((0X3<<10) ); *GPFcon|=  (0X1<<10) ; break;case 3:                              //进入led3设备,控制 led3*GPFcon&=~ ((0X3<<12) ); *GPFcon|=    ((0X1<<12) ); break;}return 0;}/*参数filp为目标文件结构体指针,buffer为要写入文件的信息缓冲区,count为要写入信息的长度,ppos为当前的偏移位置,这个值通常是用来判断写文件是否越界*/
static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{int val;int minor=MINOR(file->f_dentry->d_inode->i_rdev);copy_from_user(&val,buf,count);      //通过用户(应用层)拷贝数据                                                           switch(minor){case 0:                                               //进入led设备,控制所有ledprintk("led0,%d\n",val);if(val)       //开灯{*GPFdat&=~ ((0X1<<4)| (0X1<<5)| (0X1<<6)); *GPFdat|=      ((0X0<<4)| (0X0<<5)| (0X0<<6));   }else     //关灯{*GPFdat&=~ ((0X1<<4)| (0X1<<5)| (0X1<<6)); *GPFdat|=      ((0X1<<4)| (0X1<<5)| (0X1<<6));   }break;case 1:                                               //进入led1设备,控制 led1printk("led1,%d\n",val);if(val)      //开灯{*GPFdat&=~ (0X1<<4); *GPFdat|=      (0X0<<4);  }else         //关灯{  *GPFdat&=~  (0X1<<4); *GPFdat|=      (0X1<<4);  }break;case 2:                                         //进入led2设备,控制 led2printk("led2,%d\n",val);if(val)      //开灯{*GPFdat&=~ (0X1<<5); *GPFdat|=      (0X0<<5);  }else         //关灯{*GPFdat&=~  (0X1<<5); *GPFdat|=      (0X1<<5);  }break;case 3:                                               //进入led3设备,控制 led3printk("led3,%d\n",val);                  if(val)      //开灯{*GPFdat&=~ (0X1<<6); *GPFdat|=      ( 0X0<<6); }else         //关灯{*GPFdat&=~ (0X1<<6); *GPFdat|=      (0X1<<6);  }                break;       }return 0;
}/*2定义file_operations结构体来封装驱动函数first_drv_open first_drv_write */static struct file_operations first_drv_fops = {.owner  =   THIS_MODULE,     //被使用时阻止模块被卸载.open   =   first_drv_open,     .write   =   first_drv_write,   };int major;              //定义一个全局变量,用来保存主设备号
int first_drv_init(void)
{int i;                       /*3 register_chrdev注册字符设备*//*如果设置major为0,表示由内核动态分配主设备号,函数的返回值是主设备号*/major=register_chrdev (0, "first_drv", &first_drv_fops);  firstdrv_class= class_create(THIS_MODULE,"firstdrv");  
//创建类,它会在sys目录下创建firstdrv这个类  firstdrv_class_devs[0]=class_device_create(firstdrv_class,NULL,MKDEV(major,0),NULL,"led");
//创建类设备,它会在firstdrv_class类下创建led设备,然后mdev通过这个自动创建/dev/xyz这个设备节点for(i=1;i<4;i++)   //创建led1 led2 led3 设备节点,控制led1 led2 led3{firstdrv_class_devs[i]=class_device_create(firstdrv_class,NULL,MKDEV(major,i),NULL,"led%d",i);}return 0;
}/*6 写first_drv_exit出口函数*/
void first_drv_exit(void)
{int i;unregister_chrdev (major, "first_drv");  //卸载驱动,只需要主设备号和设备名就行class_destroy(firstdrv_class);                      //注销类,与class_create对应for(i=0;i<4;i++)                              //注销类设备led,led1,led2,led3class_device_unregister(firstdrv_class_devs[i]);      iounmap(GPFcon);          //注销虚拟地址
}/*5 module_init修饰入口函数*/
module_init(first_drv_init);/*7 module_exit修饰出口函数*/
module_exit(first_drv_exit); MODULE_LICENSE("GPL v2");  //声明许可证

 下章学习: 

4.查询方式来写按键驱动程序(详解)

http://www.lbrq.cn/news/1450639.html

相关文章:

  • 买的服务器做两个网站/免费发布推广平台
  • 建立个人免费网站/win7优化软件
  • 织梦网站主页文章列表调用/怎么找精准客户资源
  • 做网站具体收费/360应用商店
  • 无锡网站建设推广服务/seo公司哪家好用
  • 建网站需成本多少钱/竞价推广托管多少钱
  • 学网站开发首先学哪些基础/收录批量查询
  • win7电脑做网站/查指数
  • 杭州建网站/seo优化师
  • 设计相关网站/站长之家新网址
  • 个人网站申请空间/西安高端模板建站
  • 上海个体户注册代办/吉林seo外包
  • 百度做网站续费费用/会员制营销方案
  • 闲鱼网站建设费用/成都网站快速排名优化
  • 简易做海报网站/免费测试seo
  • 做淘宝网站代理/郑州seo优化
  • 网站建设经验典型/微信营销平台哪个好
  • 网站注册系统/爱站网站排行榜
  • 做库房推广哪个网站好/百度数据开放平台
  • 房地产做网站的意义/网站排名优化课程
  • 建筑网格布/网站推广的优化
  • 怎么做二级网站域名/腾讯搜索引擎入口
  • wordpress 重复内容/北京百度seo排名
  • 徐汇科技网站建设/seo优化教程自学网
  • 香港人做evus在哪个网站/网络营销推广计划
  • 建设购物网站/线下推广宣传方式有哪些
  • 张家港普通网站建设/域名服务器ip查询网站
  • wordpress 写文章页面/seo建站
  • 老域名怎么做新网站/现在百度推广有用吗
  • 如何制作单页网站/站外推广方式
  • 类内部方法调用,自注入避免AOP失效
  • 前端1.0
  • JS-第二十一天-尺寸位置
  • 【PHP】对比两张图片的相似度
  • 豆包1.6+PromptPilot实战:构建智能品牌评价情感分类系统的技术探索
  • 设计模式-创建型-工厂模式