第七章 LED将为我闪烁:控制发光二极管

发布者:平和心态最新更新时间:2024-09-30 来源: cnblogs关键字:LED  闪烁 手机看文章 扫描二维码
随时随地手机看文章

该Linux驱动用来控制开发板上的4个LED灯,即通过向Linux驱动发送数据可以控制LED灯的开关。LED驱动提供两种交互方式:命令和读写设备文件。

测试LED驱动之前需用USB线连接开发板,然后打开开发板。成功启动后,执行build.sh脚本文件编译和安装LED驱动。build.sh脚本文件会自动将s3c6410_leds.ko文件上传到开发板并安装。LED驱动只能在开发板上安装,build.sh执行了build_s3c6410.sh脚本文件进行编译和安装。LED驱动会建立一个/dev/s3c6410_leds设备文件,该Linux驱动可控制4个LED,通过向设备文件发送长度为1到4的字符串可以控制这4个LED的开关。1表示开,0表示关。字符串长度不足4个,相当于后面补0。执行命令

“# adb shell 'echo '1'> /dev/s3c6410_leds' #打开第一个LED,其他的都关闭

# adb shell 'echo '1010'> /dev/s3c6410_leds' #第一个和第三个LED打开,第二个和第四个关闭

# adb shell 'echo '1111'> /dev/s3c6410_leds' #打开所有的LED”可控制开发板上的LED。可使用命令“# sh ~/drivers/s3c6410_leds/test_leds.sh”执行test_leds.sh脚本文件测试LED。执行脚本文件后,开发板上的4个LED会根据0到15的二进制形式控制LED,第一个为最低位。脚本文件使用的是标准的Bash Shell,如果在Ubuntu下无法成功执行,是因为其将dash作为默认的脚本解析器。可使用命令“# dpkg-reconfigure dash”将默认脚本解析器改成Bash,出现设置界面时,选择“否”,再回车即可。

创建LED驱动的设备文件,步骤如下;1.描述设备文件需要使用一个cdev结构体,该结构体在/include/linux/cdev.h文件中定义。其中的大多数成员变量只需调用cdev_init()就可被初始化,该函数在/fs/char_dev.c文件中。若要在一个Linux驱动中建立多个设备文件,cdev.count变量的值就是要建立的设备文件数。这些设备文件对应的cdev结构体就通过cdev.list.prev和cdev.list.next指针变量连接,从而形成一个双向链表。cdev.owner变量未在cdev.init函数中初始化,使用语句“leds_cdev.owner=THIS_MODULE;”来初始化2.Linux设备文件的设备号分为主设备号和次设备号。用一个int类型表示,其中前12位表示主设备号,后20位表示次设备号。设备号有两种指定方法:直接在代码中指定和动态分配。第一种方法虽比较直观,但如果主设备号和次设备号已存在,建立设备文件就会失败。以防万一,可使用alloc_chrdev_region()自动分配一个未使用的主设备号。习惯上将次设备号设为0。函数原型为int alloc_chrdev_region(dev_t*dev,unsigned baseminor,unsigned count,const char *name),其中dev表示设备号指针,函数会随机分配一个未使用的主设备号,根据baseminor参数值分配次设备号。count表示分配的次设备号范围。name表示设备文件名称。多个Linux设备文件可拥有同一个主设备号,但两个设备的主设备号和次设备号不能都一样。在使用函数自动分配设备号时,baseminor和count参数不要设太大,否则次设备号会溢出,且主设备号会进位,从而变成下一个主设备号。若要直接指定设备号,需使用register_chrdev_region()注册字符设备区域,该函数在/fs/char_dev.c文件中实现,原型为:int register_chrdev_region(dev_t from,unsigned count,const char *name),from表示设备号,count表示次设备号范围,name表示设备文件名称。一般采用分别指定主设备号和次设备号的方式指定设备号,需要MKDEV宏将主设备号和次设备号组合成设备号-“int dev_number=MKDEV(major,minor);”。也可分别使用MAJOR和MINOR宏从设备号中获取主设备号和次设备号,代码为:“int major=MAJOR(dev_number); int minor=MAJOR(dev_number);”3.cdev_add()用于将字符设备添加到probes数组中。函数在/fs/char_dev.c文件中实现,原型为

“int cdev_add(struct cdev *p,dev_t dev,unsigned count){

p->dev=dev;

p->count=count;

return kobj_map(cdev_map,dev,count,NULL,exact_match,exact_lock,p);

}”,调用该函数需指定设备文件指针p、设备号dev和设备文件数量count。在该函数还调用了一个重要的函数kobj_map,此函数负责将设备文件的相关信息添加到保存已建立的设备文件的probes数组中。kobj_map()和probes数组都在/drivers/base/map.c文件中4.struct class包含一些与设备文件有关的变量及一些回调函数指针变量,使用class_create宏创建struct class,代码为

“struct class *leds_class=NULL;

leds_class=class_create(THIS_MODULE,'dev_name');”,dev_name是设备文件名称。class_create宏实际上使用了_class_create()创建struct class。该函数在/drivers/base/class.c文件中实现5.device_create()用于创建设备文件,该函数在/include/linux/device.h文件中定义,在/drivers/base/core.c文件中实现。可使用代码“device_create(leds_class,NULL,dev_number,NULL,DEVICE_NAME);”调用device_create()创建设备文件,其中leds_class表示struct class,dev_number表示设备号,DEVICE_NAME表示设备文件的名称。编写leds_create_device()时应了解:①DEVICE_COUNT表示建立设备文件的个数②alloc_chrdev_region()的第二个参数表示分配的起始次设备号。如果第三个参数的值大于1,函数会依次分配次设备号③采用自动分配设备号的方式创建设备文件,建议使用MAJOR和MINOR宏获取主设备号和次设备号,并分别保存在major和minor变量中,以备之后使用到④LED驱动的设备号保存在dev_number变量中,要将leds_cdev.dev变量的值赋给dev_number变量。leds_init()是LED驱动的初始化函数,在函数中直接调用leds_create_device()即可。若将S3C6410_LEDS_MAJOR设为0,系统会自动分配一个未使用的主设备号,次设备号仍是10.在每次装载LED驱动时主设备号可能会不一样,但次设备号总是10。

卸载LED驱动的设备文件:卸载操作会稍简单一些,需依次调用device_destroy、class_destroy和unregister_chrdev_region()。leds_destroy_device()用于卸载LED驱动的设备文件,leds_exit()是LED驱动的卸载函数,它通过调用leds_destroy_device()来完成卸载LED驱动设备文件的工作。

设置寄存器与初始化LED驱动:ARM处理器有多个寄存器,通过设置不同寄存器的值。可以设置LED引脚的状态、打开或禁止上拉电路以及控制LED的亮和灭。我们必须知道的有:①LED有两个引脚:GPB0和GPB1,其中一个引脚连接到了ARM处理器的GPI0端口,另一个引脚经过一个限流电阻连接到电源VCC3上。当GPI0端口为低电平时,LED两端产生电压差,LED有电流通过发光;反之当GPI0端口为高电平时,LED中没有电流通过,灯熄灭。高低电平之间切换非常快,LED亮灭之间有一定的延迟②控制LED需要通过3个寄存器完成,GPMCON端口配置寄存器、GPMDAT端口数据寄存器和GPMPUD端口上拉电路寄存器③每一个寄存器可以使用4个字节,即一个int类型数据占用的空间④使用GPMCON寄存器的低16位将LED的两个端口GPB0、GPB1的属性设为Output。每4位设置一个LED,共4个LED。output的值是0001,若使用十六进制表示,寄存器的低16位的值是0x1111⑤使用GPMDAT寄存器的低4位控制4个LED的亮、灭。每一位控制一个LED,最低位控制离电池最近的LED。0表示亮、1表示灭⑥使用GPMPUD寄存器的低8位分别打开4个LED的上拉电路。每两位控制一个LED的上拉电路。10为打开上拉电路。使用十六进制的话,GPMPUD寄存器的低8位是0xAA,才能同时打开4个LED的上拉电路。以上3个寄存器在内存中都有一个虚拟地址。向这些地址写入数据后,ARM处理器会使用一套算法将虚拟地址映射成物理地址,并根据物理地址将数据写入相应的硬件端口。ARM处理器中的GPMCOM、GPMDAT和GPMPUD的虚拟地址在Linux内核中都使用了宏定义。为了跟踪这些宏,需再加两个include路径:/root/kernel/linux_kernel_2.6.36/arch/arm/mach-s3c64xx/include和/root/kernel/linux_kernel_2.6.36/arch/arm/plat-samsung/include。这三个寄存器的虚拟地址对应的宏分别为S3C64XX_GPMCON、S3C64XX_GPMPUD、S3C64XX_GPMDAT。这三个宏涉及了4个头文件共9个宏。可推出S3C64XX_GPM_BASE的值是0xF04500820,GPMCON、GPMDAT和GPMPUD寄存器的虚拟地址分别为0xF04500820、0xF04500824和0xF04500828,这三个虚拟地址是固定的,可向这三个地址写数据。更好的是使用S3C64XX_GPMCON、S3C64XX_GPMPUD、S3C64XX_GPMDAT来操作这3个地址。一般需在LED驱动装载时初始化上述3个寄存器。只要在leds_init()中调用leds_init_gpm()就可完成寄存器的初始化。

控制LED:LED驱动可使用两种方式控制LED:通过字符串控制LED和通过I/O命令控制LED。要使用以上两种方式控制LED,驱动必须接收相应的数据。若通过字符串控制LED,需使用file_operations.write(),可接收向设备文件写入的数据。若通过I/O命令控制,需使用file_operations.ioctl(),可接收向字符设备发送的命令和参数。s3c6410_leds_write()用于接收向LED驱动的设备文件写入控制LED的数据,在实现其功能编写代码时需了解:①4个LED的亮灭用一个长度为4的mem数组。1表示点亮LED,0表示熄灭LED。与GPMDAT寄存器的低4位表示的含义正好相反②若写入的字符串长度小于等于4,直接写入这些字符串。若长度大于4,则只写入前4个字符串。s3c6410_leds_write()要按传入该函数的字符串长度返回,否则系统会调用多次该函数写入字符串③事先mem数组已被清零,若要写入的字符串长度小于4,则相当于后面的字符都是④向GPMDAT寄存器写入数据之前最好先读取GPMDAT寄存器的当前值,并通过位与、或等操作保留与本次操作无关的值⑤ioread32、iowrite32用于读写虚拟地址中的32位数据。使用命令

“# adb shell 'echo 1101 > /dev/s3c6410_leds'

# adb shell 'echo 1 > /dev/s3c6410_leds'”可通过字符串控制LED的亮、灭。I/O命令无法使用命令行方式进行测试。

LED驱动的模块参数:若想在装载LED驱动时指定默认状态值,就要使用模块参数。为Linux驱动指定一个模块参数需使用module_param(name,type,perm)宏。name表示参数名,type表示参数类型,perm表示读/写权限。module_param支持的参数类型包括byte、short、ushort、int、uint、long、charp、bool和invbool。使用module_param宏指定模块参数时,会在/sys/module目录下生成和驱动设备文件同名的目录。若在装载Linux驱动时未指定某个参数,则参数文件的内容是该参数在Linux驱动源代码中指定的默认值。通过module_param宏可指定参数文件的访问权限。S_IRUGO表示所有的用户都可访问该参数文件中的内容,但不能修改。S_IRUGO|S_IWUSR表示允许所有用户读,以及创建文件的用户写。Linux内核还提供了更多的定义访问权限的宏。S_IRWXUGO表示所有用户可对文件读、写和执行。IWUGO表示所有用户对文件只有写权限。需要修改LED驱动的代码,为LED驱动添加一个模块参数,该参数存储了4个LED的初始状态,参数类型为int。参数值的范围是0到15.参数值控制LED的规则与GPMDAT寄存器低4位控制LED的规则相同。为LED驱动添加模块参数首先要定义一个保存模块参数值的变量,然后使用module_param宏指定模块参数的相关信息。最后修改leds_init()代码,将leds_init_gpm()的参数值改成~leds_state。使用命令“# adb shell insmod /data/local/s3c6410_leds.ko leds_state=3”可测试LED驱动的模块参数。执行完命令后,会在/sys/module/s3c6410_leds/parameters目录下生成一个leds_state文件,使用命令

“# adb shell cat /sys/module/s3c6410_leds/parameters/leds_state”可看到文件内容为3。使用命令“# adb shell 'echo 5 > /sys/module/s3c6410_leds/parameters/leds_state'”可将文件内容改为5。修改leds_state文件内容后,在LED驱动代码中的leds_state变量值会变成5。Linux驱动在装载时会将指定的参数值写入参数文件,若未指定参数值,Linux驱动会将参数的默认值写入参数文件。在Linux驱动工作的过程中,参数值会与参数文件中的内容同步。使用module_param_array(name,type,nump,perm)宏可为Linux驱动指定数组形式的模块参数。nump表示存储数组长度的变量的指针,perm表示参数文件的访问权限。通过命令“# adb shell insmod /data/local/s3c6410_leds.ko 'leds_state=11 param=str1,str2,str3'”可指定params参数值。如果params参数指定的值的个数少于数组长度,后面的数组元素使用默认值。如果大于数组长度,LED驱动装载失败,并在日志中输出信息。使用模块参数要注意:①通过module_param_array宏的第3个参数指定数组长度时要使用指针类型的数据②如果Linux驱动含有多个模块参数,需将这些参数用单引号或双引号括起来③指定数组类型的参数值时,逗号前不能有空格。


关键字:LED  闪烁 引用地址:第七章 LED将为我闪烁:控制发光二极管

上一篇:Android深度探索(卷1)HAL与驱动开发第七章总结
下一篇:uboot移植

推荐阅读最新更新时间:2024-11-10 10:32

有效解决LED路灯光衰问题的三个建议
  LED路灯光衰的关键问题在于温度,偏偏LED路灯通常又败在这个环节。LED路灯由于发光功率大于家用灯具,因此厂商在散热基板鳍片、散热模块的设计上费尽苦心,组装完毕需在灯具散热模块外面,加烤漆保护以防气候侵蚀。不料这个外部保护的喷漆却把散热模块的热度又封了回去,造成散热不良导致LED磊晶光衰。   LED磊晶发光热能属于小范围的集中热能,在高功率路灯的应用时,电力输入功率也大,LED的接口温度相当的高,在路灯长时间持续工作下,散热 模块如不能有效散热,就会影响LED使用寿命及发光表现,像目前的LED路灯严重光衰就是这些因素所造成。LED路灯是在户外使用,有环境气候的干扰因 素,所以多半的厂商是将LED路灯散热器外壳以阳极处理保护
[电源管理]
LED驱动电源为什么需要高效率?
高效率是LED驱动系统整体节能要求,是低温升、长寿命、高可靠的基础与保证。   (1)高效率、低损耗、低温升   如一台输出100W的LED驱动电源,当效率达95%时,其损耗是5.2W,当效率只有85%时,其损耗达17.6W,后者是前者的3.4倍,实验表明在同等条件下前者比后者温度低10~15℃。   (2) 降低LED灯的工作温度及延缓光衰   LED芯片温度的升高将导致发光器件性能的变化与电光转换效率的衰减,严重时甚至失效,有实验测试表明:LED自身温度每上升5℃,光通量就下降3%。   (3)高效率、低温升、长寿命   如果选用105℃,寿命为10000小时的高温电解电容,根据通行的电解电容寿命估算公式“每降低10度,寿命增
[电源管理]
带你走近LED驱动电源
  LED驱动 电源 把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子 变压器 的输出)等。而LED驱动电源的输出则大多数为可随LED正向压降值变化而改变电压的恒定电流源。LED电源核心元件包括开关控制器、电感器、开关元器件(MOSfet)、反馈电阻、输入滤波器件、输出滤波器件等等。根据不同场合要求、还要有输入过压保护电路、输入欠压保护电路,LED开路保护、过流保护等电路。   LED驱动电源的特点   (1)高可靠   性特别像LED路灯的驱动电源,装在高空,维修不方便,维修的花费也大。   (2)高效率   LE
[电源管理]
LED显示屏五大关键指标,决定显示屏的品质
LED显示屏由一列发光二极管排列组合而成,因此LED的质量直接影响显示屏的整体品质。决定LED品质的指标有五个:亮度与视角、均匀性与清晰度、像素失控率、寿命、能耗与能效。影响LED显示屏寿命的因素有内因和外因,内因有外围部件性能。下面就随电源管理小编一起来了解一下相关内容吧。 LED显示屏由一列发光二极管排列组合而成,因此LED的质量直接影响显示屏的整体品质。决定LED品质的指标有五个:亮度与视角、均匀性与清晰度、像素失控率、寿命、能耗与能效。影响LED显示屏寿命的因素有内因和外因,内因有外围部件性能、LED发光器件的性能、产品抗疲劳性能;内因有LED显示屏的工作环境等等。散热就是影响LED显示屏质量和使用寿命的关键因素。 L
[电源管理]
LED显示屏维修的检测方法及步骤
   一、LED显示屏维修的检测方法   1、短路检测法,将万用表调到短路检测挡(一般具有报警功能,如导通则发出鸣叫声),检测是否有短路的现象出现,发现短路后应马上解决,短路现象也是最常见的LED显示屏模块故障。有的通过观察IC引脚和排针引脚就能发现。短路检测应在电路断电的情况下操作,避免损坏万用表。这个方法是最常用到的方法,简单、高效。90%的故障都可以通过这个方法检测判断。   2、电阻检测法,将万用表调到电阻档,检测一块正常的电路板的某点的到地电阻值,再检测另一块相同的电路板的同一个点测试与正常的电阻值是否有不同,若不同则就确定了问题的范围。   3、电压检测法,将万用表调到电压档,检测怀疑有问题的电路的某个点的到地电压,
[电源管理]
<font color='red'>LED</font>显示屏维修的检测方法及步骤
封装新技术导入加速,LED背光市场格局或重构
 LED最早被导入到手机按键背光,2008年逐渐进入产业化,2009年进入中大尺寸显示背光领域,应用于笔记本电脑和液晶电视。随之而来的是产业格局的改变,曾经一度是欧美和中国台湾地区厂商天下的LED背光,如今被中国大陆厂商分食,电视厂商也纷纷移情别恋。   2012年,对于大陆LED背光器件厂来说,显然是丰收的一年。代表厂商瑞丰光电全年实现营收5亿元,同比增长71.63%;净利润为0.47亿元,同比增长41.48%。其中,背光器件营收同比增长超过100%。另一家以中小尺寸背光业务为主的聚飞光电,2012年实现营业收入4.95亿元,同比增长42.75%;净利润0.92亿元,同比增长14.15%。以大尺寸背光为主的东山精密2012
[模拟电子]
封装新技术导入加速,<font color='red'>LED</font>背光市场格局或重构
S3C2440 字符设备驱动程序之LED驱动程序_操作LED(四)
第12课第2.3节 字符设备驱动程序之LED驱动程序_操作LED(四) 写一个点LED的驱动: 一、框架 二、完善、硬件的操作: a.看原理图、确定引脚; b.看2440手册; c.写代码: 单片机:操作物理地址 驱动:用ioremap函数来映射虚拟地址 ★★★ void *ioremap(unsigned long phys_addr, unsigned long size) phys_addr:要映射的物理地址 size:要映射的长度,单位是字节 ioremap是以页为单位进行映射,你的长度写为4,16,32等等,都会映射到4096字节的空间。 ★★★ 下面的代码中:
[单片机]
S3C2440 字符设备驱动程序之<font color='red'>LED</font>驱动程序_操作<font color='red'>LED</font>(四)
TCL集团展出全球首款全平板超薄LED电视
    4月10日,首届中国电子信息博览会在深圳召开,TCL集团推出了一个全新高端子品牌Viveza旗下的首款产品V101,这也是全球首款全平板超薄LED电视。     V101仅有12.5毫米的超薄高端电视,由于采用了空间效率最高的业界第三代一体化集成技术(BMS),V101将散热系统、信号系统、电源系统、声学系统完美容纳在12.5mm厚的整机力学空间内,创造了全球LED电视的极致超薄记录。     据了解,V101是TCL多媒体于今年3月26日正式发布的“V计划”的新品,“V计划”是TCL多媒体2013年一项重大战略举措。TCL多媒体NPI设计中心总经理杨福军表示,Viveza灵感来自西班牙语,意为“生活”,是由TCL
[家用电子]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved