led和蜂鸣器驱动广州龙芯中科1B开发板.docx
- 文档编号:1915882
- 上传时间:2023-05-02
- 格式:DOCX
- 页数:26
- 大小:336.97KB
led和蜂鸣器驱动广州龙芯中科1B开发板.docx
《led和蜂鸣器驱动广州龙芯中科1B开发板.docx》由会员分享,可在线阅读,更多相关《led和蜂鸣器驱动广州龙芯中科1B开发板.docx(26页珍藏版)》请在冰点文库上搜索。
led和蜂鸣器驱动广州龙芯中科1B开发板
1.前言3
2.硬件电路3
2.1.LED引脚3
2.2.LED原理分析4
2.3.蜂鸣器引脚5
2.4.蜂鸣器原理分析5
3.GPIO相关分析6
3.1.阅读CPU手册6
3.2.Linux内核源码分析6
4.点亮一个led9
4.1.源码9
4.2.运行结果13
5.手动指定那个led亮13
5.1.源码13
5.2.运行结果19
6.蜂鸣器驱动20
6.1.源码20
7.参考资料20
修订历史
版本号
更新日期
更新内容
V1.0
2013.9.13
创建
前言
由于龙芯资料较少,现在又有点时间,写了两句,仅供初学者入门时参考,还望高手多多指教。
硬件电路
LED引脚
先把电路图贴出来
我们选择LED9作为本次实验的对象。
LED9接到龙芯1B的引脚T12
再查龙芯1B处理器的用户手册v1.9如下图
即CAN0_RX为GPIO38.,同理可得
Led6接GPIO39;led7接GPIO40;led8接GPIO41。
如原理图所示
注意:
这里有GPIO0,GPIO1,。
。
。
。
GPIO38,GPIO39。
。
。
。
到底表示什么意思啊?
个人认为第一列的GPIO1,GPIO2,……为原理图中的编号,而第三列的GPIO38,GPIO39为CPU引脚编号,可以再CPU手册中找到。
如前面的led9所示。
这几个引脚可以在源码中定义为宏,详细请见后面代码,这里只贴出相关部分。
LED原理分析
LED又叫发光二极管,有正负两个极,只要在正负两极之间接上合适的正电压,LED就导通,并发光。
这里只需要让CPU的GPIO引脚输出低电平,对应的LED就被点亮。
比如GPIO38输出低电平,即可点亮LED9。
蜂鸣器引脚
LED7接在CAN1_RX上,CAN1_RX经过电阻后接蜂鸣器,如下图所示
所以LED7和蜂鸣器共用一个引脚——GPIO40。
蜂鸣器原理分析
蜂鸣器通过NPN三极管提供所需的大电流,当GPIO40输出低电平时,NPN三极管截止,蜂鸣器不响;当输出高电平时,NPN三极管导通,蜂鸣器响。
由于LED7和蜂鸣器共用同一个引脚,并且为了开机后蜂鸣器不响(想起来烦人,哈哈)。
所以引脚GPIO40必须输出低电平,恰好低电平使LED导通,所以LED7在开机后一直亮着。
GPIO相关分析
阅读CPU手册
首先看龙芯1B处理器的手册,其中对GPIO相关的寄存器有:
配置寄存器,输入使能寄存器,输入寄存器,配置输出寄存器,MUX寄存器。
根据经验,一般都是先配置GPIO为输入还是输出,然后读输入寄存器或者写输出寄存器实现输入输出功能。
V1.9版的手册中写得还不是很清楚,我们这里也只能猜了。
贴上手册中的截图
作为对比参考,我把其它CPU的截图也贴上
相比较而言,龙芯1B处理器手册写得太简单了,以至于没有说清楚。
Linux内核源码分析
现在我们来看一下linux内核中GPIO相关代码。
源码路径“linux内核根目录/arch/mips/loongson/ls1x/gpio.c”。
我们想实现的功能就是简单的在GPIO口输出高低电平。
源文件gpio.c中有个函数ls1b_gpio_direction_output(),从函数名字上看好像能实现这个功能。
具体分析一下。
/*
函数功能:
直接在某个GPIO输出高电平或者低电平
入参:
structgpio_chip*chip可以为空指针
unsignedgpioGPIO的序号
intlevel电平值。
1--高电平;0--低电平
*/
intls1b_gpio_direction_output(structgpio_chip*chip,
unsignedgpio,intlevel)
{
u32temp;
u32mask;
//入参检查:
判断是否超过最大的GPIO个数,即GPIO的合法性检查
if(gpio>=STLS1B_N_GPIO)
return-EINVAL;
//把高低电平值写到输出寄存器中
gpio_set_value(gpio,level);
//由于寄存器是32位的,一个寄存器最多可以控制32个GPIO
//就比如:
配置寄存器,就有配置寄存器0和配置寄存器1
//所以这里分开处理
if(gpio>=32){
//获取锁,执行原子操作
spin_lock(&gpio_lock);
mask=1<<(gpio-32);
//配置GPIO引脚为GPIO功能
temp=LOONGSON_GPIOCFG1;
temp|=mask;
LOONGSON_GPIOCFG1=temp;
//配置GPIO引脚为输出
temp=LOONGSON_GPIOIE1;
temp&=(~mask);
LOONGSON_GPIOIE1=temp;
//释放锁
spin_unlock(&gpio_lock);
}else{
spin_lock(&gpio_lock);
mask=1< temp=LOONGSON_GPIOCFG0; temp|=mask; LOONGSON_GPIOCFG0=temp; temp=LOONGSON_GPIOIE0; temp&=(~mask); LOONGSON_GPIOIE0=temp; spin_unlock(&gpio_lock); } return0; } /* 函数功能: 把高低电平值写到输出寄存器中 入参: unsignedgpioGPIO编号 intstate高低电平。 1--高电平;0--低电平 */ voidgpio_set_value(unsignedgpio,intstate) { u32val; u32mask; //判断GPIO是否有效、合法 if(gpio>=STLS1B_N_GPIO){ __gpio_set_value(gpio,state); return; } //对不同GPIO操作不同的寄存器 if(gpio>=32){ mask=1<<(gpio-32); //获取锁 spin_lock(&gpio_lock); //把高低电平值写到输出寄存器中 val=LOONGSON_GPIOOUT1; if(state) val|=mask; else val&=(~mask); LOONGSON_GPIOOUT1=val; //释放锁 spin_unlock(&gpio_lock); }else{ mask=1< spin_lock(&gpio_lock); val=LOONGSON_GPIOOUT0; if(state) val|=mask; else val&=~mask; LOONGSON_GPIOOUT0=val; spin_unlock(&gpio_lock); } } 经过以上分析,要让GPIO输出高低电平,首先写输出寄存器,然后把引脚配置为GPIO,最后设置为输出。 点亮一个led 源码 源码包含一个驱动源程序、一个应用源程序和一个Makefile。 [root@localhostled]#catMakefile #ifKERNELRELEASEisdefined,we'vebeeninvokedfromthe #kernelbuildsystemandcanuseitslanguage. ifneq($(KERNELRELEASE),) obj-m: =ls1b_led_driver.o #otherwisewewerecalleddirectlyfromthecommand #line;invokethekernelbuildsystem. else KERNELDIR=/home/dev/develop/1b-linux-3.0-d8b47bb PWD: =$(shellpwd) default: $(MAKE)-C$(KERNELDIR)M=$(PWD)modules cp./ls1b_led_driver.ko/nfsramdisk/LS1Brootfs/test mipsel-linux-gccls1b_led_app.c-ols1b_led_app cpls1b_led_app/nfsramdisk/LS1Brootfs/test clean: rm*.o*.mod.c*.order*.symvers*.ko endif 这个Makefile是参考《linuxdevicedriver》修改的。 也是比较通用的,只需要修改一个linux内核路径和驱动模块文件名就可以了。 这里把应用程序的编译也放在了一起。 这样执行make时,驱动和应用一起编译。 [root@localhostled]#catls1b_led_driver.c #include #include #include #include #include #include #include #include #include #include #include #include #defineLS1B_LED_1_ON(0) #defineLS1B_LED_1_OFF (1) intls1b_led_major=0; intls1b_led_minor=0; structcdevls1b_led_devs; intls1b_led_open(structinode*inode,structfile*filp) { printk(KERN_DEBUG"%s: open\n",__FUNCTION__); return0; } intls1b_led_release(structinode*inode,structfile*file) { printk(KERN_DEBUG"%s: close\n",__FUNCTION__); return0; } ssize_tls1b_led_set(structfile*filp,constchar__user*buff,size_tcount,loff_t*offp) { ls1b_gpio_direction_output(NULL,38,0); printk(KERN_DEBUG"%s: led9on\n",__FUNCTION__); return0; } structfile_operationsls1b_led_ops={ .owner=THIS_MODULE, .open=ls1b_led_open, .release=ls1b_led_release, .write=ls1b_led_set, }; MODULE_AUTHOR("caogoscaogos@"); MODULE_LICENSE("DualBSD/GPL"); intls1b_led_init(void) { intresult; dev_tdevno; structcdev*dev=&ls1b_led_devs; structfile_operations*fops=&ls1b_led_ops; result=alloc_chrdev_region(&devno,0,1,"ls1b_led"); if(0>result) { printk(KERN_WARNING"ls1b_led: unabletogetamjor\n"); returnresult; } ls1b_led_major=MAJOR(devno); printk(KERN_DEBUG"ls1b_led: major=%d\n",ls1b_led_major); cdev_init(dev,fops); dev->ops=fops; result=cdev_add(dev,devno,1); if(result) { printk(KERN_NOTICE"Error%daddingls1b_led",result); returnresult; } printk(KERN_DEBUG"ls1b_leddeviceinstalled.withmajor%d\n",ls1b_led_major); return0; } voidls1b_led_exit(void) { cdev_del(&ls1b_led_devs); unregister_chrdev_region(MKDEV(ls1b_led_major,0),1); printk("ls1b_leddeviceuninstalled\n"); } module_init(ls1b_led_init); module_exit(ls1b_led_exit); 这个驱动程序必《linuxdevicedriver》中的HelloWorldModule要稍微复杂点。 不过已经是非常简单的字符设备驱动了。 这个驱动程序的核心就是函数ls1b_led_set()。 其中的ls1b_gpio_direction_output(NULL,38,0);的功能是让GPIO38输出低电平。 然后把函数ls1b_led_set()作为该驱动structfile_operationsls1b_led_ops的写函数,即应用程序中调用write()函数,就会对应调用驱动的函数ls1b_led_set()。 注意: 函数ls1b_led_set()没有对入参进行分别处理,只要应用程序调用write()函数,不管write什么内容,都执行GPIO38输出低电平的操作。 [root@localhostled]#catls1b_led_app.c #include #include #include #include #include #include #include intmain(void) { intdev_fd; charbuff[2]={0}; dev_fd=open("/dev/led",O_RDWR|O_NONBLOCK); if(-1==dev_fd) { printf("Cann'topenfile/dev/led\n"); return-1; } write(dev_fd,buff,1); close(dev_fd); return0; } 这个应用程序简单来说就是打开设备文件,并执行写操作。 即调用驱动中的函数ls1b_led_set()点亮LED。 友情提示: 内核顶层配置中[*]Enableloadablemodulesupport--->一定要选上。 运行结果 /test#ls ls1b_led_appls1b_led_driver.ko /test#echo8>/proc/sys/kernel/printk /test#insmodls1b_led_driver.ko ls1b_led: major=253 ls1b_leddeviceinstalled.withmajor253 /test#mknod/dev/ledc2530 /test#./ls1b_led_app ls1b_led_open: open ls1b_led_set: led9on ls1b_led_release: close /test# 当然开发板上的LED9肯定被点亮。 经过前面分析可知,打印信息“ls1b_led_set: led9on”为驱动程序打印出来的。 命令“echo8>/proc/sys/kernel/printk”是将内核打印级别调到最低。 为了能把所有驱动中的printk打印信息打印出来。 命令“mknod/dev/ledc2530”新建设备节点。 否则,应用中open()会失败。 253为主设备号,根据前面的打印“ls1b_leddeviceinstalled.withmajor253”获得的。 手动指定那个led亮 源码 在前面led驱动的基础上改进了一下,现在可以手动输入led序号,然后制定序号的led被点亮。 驱动程序源码ls1b_led_driver.c #include #include #include #include #include #include #include #include #include #include #include #include //led正极接3.3v,负极接cpu引脚 //cpu输出低电平,led导通,亮 #defineLS1B_LED_ON(0) //cpu输出高电平,led截止,灭 #defineLS1B_LED_OFF (1) //led引脚 #defineLS1B_PIN_LED_9(38)//gpio38 #defineLS1B_PIN_LED_6(39)//gpio39 #defineLS1B_PIN_LED_7(40)//gpio40 #defineLS1B_PIN_LED_8(41)//gpio41 //led主次设备号,动态申请 intls1b_led_major=0; intls1b_led_minor=0; structcdevls1b_led_devs; intls1b_led_open(structinode*inode,structfile*filp) { printk(KERN_DEBUG"%s: open\n",__FUNCTION__); return0; } intls1b_led_release(structinode*inode,structfile*file) { printk(KERN_DEBUG"%s: close\n",__FUNCTION__); return0; } /*********************************************************** 功能: 将led序号转换为对应的引脚 入参: unsignedintled_indexled序号 出参: 无 返回值: unsignedintled_gpioled引脚 ***********************************************************/ unsignedintls1b_led_index_to_pin(unsignedintled_index) { switch(led_index) { case9: returnLS1B_PIN_LED_9; case6: returnLS1B_PIN_LED_6; case7: returnLS1B_PIN_LED_7; case8: returnLS1B_PIN_LED_8; default: return0; } } /*********************************************************** 功能: 熄灭指定led 入参: unsignedintled_indexled序号 出参: 无 返回值: 无 ***********************************************************/ voidls1b_led_off(unsignedintled_index) { ls1b_gpio_direction_output(NULL,ls1b_led_index_to_pin(led_index),LS1B_LED_OFF); } /*********************************************************** 功能: 点亮指定led 入参: unsignedintled_indexled序号 出参: 无 返回值: 无 ***********************************************************/ voidls1b_led_on(unsignedintled_index) { ls1b_gpio_direction_output(NULL,ls1b_led_index_to_pin(led_index),LS1B_LED_ON); } /*********************************************************** 功能: 关闭所有led 入参: 无 出参: 无 返回值: 无
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- led 蜂鸣器 驱动 广州 龙芯中科 开发