六、字符设备控制

在 linux 驱动中字符驱动是必须掌握的,本章主要介绍字符设备应用的程序,无论是学习了后面的知识自己写的字符驱动,还是已有的字符驱动,都需要能够写一些简单的应用程序。

一、字符类led灯

1、led原理图如下:

                                    

2、程序设计

在前面介绍过,如果要给文件进行写操作,那么使用的是 write 函数。对于 led 小灯的操作,使用写函数,理论上也是可以的。但是对于 IO 口(这里的 IO 口指的是硬件上的 IO 口,不是指 IO 文件)的操作,Linux 专门设计了一个高效的函数 ioctl。这个函数在头文件#include<unistd.h>中。

  • int ioctl( int fd, int request, int cmd); 

        --参数 fd,函数 open 返回的句柄。

        --参数 request 和参数cmd,由内核驱动决定具体操作,例如 request 可以代表那个 IO 口,cmd 代表对 IO 进行什么样的操作,也可以反过来。具体的含义由驱动工程师在驱动中 switch决定。 

        --返回值:返回 0 成功;返回-1,出错。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define LED_NUM 2 // LED个数(io为0则是靠近蜂鸣器的小灯,为1则靠近独立按键的小灯)
#define LED_CMD 2 // 控制命令个数(cmd为0,则灭,为1,则亮;)

int main(int argc,char *argv[])
{
	int fd,led_num,led_c;
	char *leds = "/dev/leds";//leds驱动路径

	led_num = LED_NUM;
	led_c = LED_CMD;
	
	printf("argv1 is cmd;argv2 is io \n"); 
	//对传入的参数进行判断,超出范围直接退出
	if (atoi(argv[1]) >= led_c) {
		printf("argv1 is 0 or 1)");
		exit(1);
	}
	if (atoi(argv[2]) >= led_num) {
		printf("argv2 is 0 or 1)");
		exit(1);
	}
	//使用ioctl函数将参数传入内核
	if((fd = open(leds, O_RDWR|O_NOCTTY|O_NDELAY))<0)
		printf("open %s failed\n",leds);   
	else{
			ioctl(fd,atoi(argv[1]),atoi(argv[2]));
			printf("ioctl %s success\n",leds);
		}
	close(fd);
	
	return(1);
}

3、运行效果:

   

 

 

二、字符类Buzzer蜂鸣器

1、Buzzer原理图如下: 

                                           

 

2、程序设计

  Buzzer程序实际上和上面LED灯是一样的,具体如下:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define BUZZER_CMD 2 // 响(高) / 不响(低)
int main(int argc,char *argv[]){
	char *buzzer_ctl = "/dev/buzzer_ctl";// 蜂鸣器驱动文件
	int fd,ret,buzzer_c;
	
	buzzer_c = BUZZER_CMD;
	
	if(atoi(argv[1]) >= buzzer_c ){
		printf("argv[1] is 0 or 1\n");
		exit(1);
	}
	
	if((fd = open(buzzer_ctl,O_RDWR|O_NOCTTY|O_NDELAY))<0){ // 先要打开该文件
		printf("open %s failed\n",buzzer_ctl);
		exit(1);
	}
	
	ret = ioctl(fd,atoi(argv[1]),atoi(argv[2])); // argv[2]实际上没用,是通过argv[1]来控制
	close(fd);
	
	return 0;
}

3、运行效果:

      

三、字符类ADC模数转换 

1、ADC原理图如下: 

                                                              

如上图所示。XadcAIN0 网络可以读取到当前输入电压,滑动变阻器 R 移动的时候,1 和 2 之间的电阻R12 改变,滑动变阻器最大电阻为 R13,然后电压 Vadc=R12*VDD1V8_EXT/R13上面公式中 Vadc 可以通过 4412 读取出来,VDD1V8 和 R13 已知,那么就很容易求出 R12的电阻。如下图所示,在 4412datasheet 中 ADC 章节中有真实的电阻和电压曲线图。 

                                              

这里将数值做一个简单的换算:

           1.8V 对应的是 10K 欧姆,对应的寄存器数值为 0xfff;
             0 V 对应的是     0 欧姆,对应的寄存器数值为 0x00。
这样做一个简单公式,将读取的数值 r 转化为电阻值 R。
          R = r*10000/0xfff,即 R = r*10000/4095。
这个小公式在后面的代码中将会使用到。 

2、程序设计

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <stdint.h>
#include <termios.h>
//#include <android/log.h>
//#include <sys/ioctl.h>

int main(void){
	int fd;
	char *adc = "/dev/adc";
	char buffer[512];
	int len=0, r=0;
	
	memset(buffer,0,sizeof(buffer));
		printf("adc ready!\n");
	
	if((fd = open(adc, O_RDWR|O_NOCTTY|O_NDELAY))<0) // 先要打开该文件
		printf("open adc err!\n");
	else{
		printf("open adc success!\n");
		
		len=read(fd,buffer,10);	// 通过read函数读取驱动内获得的AD值
		
		if(len == 0)
			printf("return null\n");
		else{
			r = atoi(buffer);
			r = (int)(r*10000/4095);	//Datas  transition to Res
			printf("res value is %d\n",r);
		}			
	}
}

3、运行效果:

                                             

最后,我将整理的实验源码打包上传,有需要的可以下载:

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hello Jason

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值