S3C2440 ADC采样光敏电阻传感器驱动

通过光敏电阻传感器获取外界光线的变化,并通过ADC采样,上报,获取阻值。电路接口图如下。
在这里插入图片描述在这里插入图片描述

驱动实现

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/of.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <plat/gpio-cfg.h>
#include <mach/regs-gpio.h>
#include <linux/input.h>
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/sched.h>

#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>

//#define DEB_PRINTk printk
#define DEB_PRINTk(...)

#define LM393_MAJOR       253     /* 主设备号 */

struct s3c_adc_regs {				
	unsigned long adccon;
	unsigned long adctsc;
	unsigned long adcdly;
	unsigned long adcdat0;
	unsigned long adcdat1;
	unsigned long adcupdn;
};

struct s3c_adc_dev {  
    wait_queue_head_t wait;  
    int data;  
    int flag;  
};  

static volatile struct s3c_adc_regs *s3c_adc_regs;
static  struct s3c_adc_dev s3c_adc_dev;

static struct class *lm393_class;
static struct clk *clock;

//ADC中断服务
static irqreturn_t adc_irq(int irq, void *dev_id)  
{
	s3c_adc_dev.data = (s3c_adc_regs->adcdat0 & 0x3ff);  //获取转换数据
	s3c_adc_dev.flag = 1;  
	wake_up_interruptible(&s3c_adc_dev.wait);      //唤醒等待事件   
	return IRQ_HANDLED;  
}  

static int lm393_drv_open (struct inode *inode, struct file *file)
{
	s3c_adc_regs->adccon = (1<<14) | (49<<6) | (0x01<<3);	
	s3c_adc_regs->adcdly = 0xff;
	s3c_adc_dev.data = 0;  
	s3c_adc_dev.flag = 0;  
	init_waitqueue_head(&s3c_adc_dev.wait);		//初始化等待事件
	return 0;
}

static ssize_t lm393_drv_read (struct file *file, char __user *buf, size_t count, loff_t * ppos)
{
	int err;
	
	/* [15] : ECFLG,  1 = End of A/D conversion
	 * [14] : PRSCEN, 1 = A/D converter prescaler enable
	 * [13:6]: PRSCVL, adc clk = PCLK / (PRSCVL + 1)
	 * [5:3] : SEL_MUX, 000 = AIN 0
	 * [2]   : STDBM
	 * [0]   : 1 = A/D conversion starts and this bit is cleared after the startup.
	 */
	s3c_adc_regs->adccon  |= (0x01) | (0x01<<14) | (0x01<<3) | (49<<6);
	wait_event_interruptible(s3c_adc_dev.wait, s3c_adc_dev.flag);   //等待ADC转换完成
	s3c_adc_dev.flag = 0;   
	
	err = copy_to_user(buf,(char*)&s3c_adc_dev.data,sizeof(s3c_adc_dev.data));		
	return err? -EFAULT:sizeof(s3c_adc_dev.data);
}

/*字符设备的相关操作实现*/
static struct file_operations lm393_drv_fops = {
	.owner	=	THIS_MODULE,    
	.open	=	lm393_drv_open,     
	.read	=	lm393_drv_read,
};

static int __init lm393_drv_init(void)
{
	int retval = 0;
	retval = register_chrdev(0, "lm393_drv", &lm393_drv_fops);
	if (retval < 0)
	{
		DEB_PRINTk(" can't register major number\n");
		return retval;
	}
	lm393_class = class_create(THIS_MODULE, "lm393_drv");
	device_create(lm393_class, NULL, MKDEV(LM393_MAJOR, 0), NULL, "lm393");	// /dev/lm393
	s3c_adc_regs = ioremap(0x58000000, sizeof(struct s3c_adc_regs));		//地址映射
	clock = clk_get(NULL, "adc");		//获取ADC 时钟并启动操作
	if (!clock) 
	{
		DEB_PRINTk(KERN_ERR "failed to get adc clock source\n");		
		return -ENOENT;	
	}	
	clk_enable(clock);
	retval = request_irq(IRQ_ADC, adc_irq, IRQF_SAMPLE_RANDOM, "adc", NULL);		//申请ADC中断服务
	if (retval) {
		DEB_PRINTk("Error requesting IRQ_ADC\n");
		return -1;
	}
	DEB_PRINTk("Register success!\n");
	return 0;	
}

static void __exit lm393_drv_exit(void)
{
	iounmap(s3c_adc_regs);
	unregister_chrdev(LM393_MAJOR, "lm393_drv"); // 卸载
	device_destroy(lm393_class, MKDEV(LM393_MAJOR, 0));
	class_destroy(lm393_class);
	DEB_PRINTk("Unregister success!\n");
}

module_init(lm393_drv_init);
module_exit(lm393_drv_exit);

MODULE_LICENSE("GPL v2");

验证测试

## 测试程序
		#include <sys/types.h>
		#include <sys/stat.h>
		#include <fcntl.h>
		#include <stdio.h>
		
		#define DEB_PRINTF printf
		//#define DEB_PRINTF(...)
		
		int main(int argc, char **argv)
		{
			int i, ret,  fd, adc_data;
			char result[4];
		
			DEB_PRINTF("will open fd... \n");
			if((fd = open("/dev/lm393",O_RDONLY)) < 0 )
			{
				DEB_PRINTF("open device lm393 fail.\n");
				return -1;
			}
			else
			{
				DEB_PRINTF("Open Device lm393 Successful!!\n");
			}
			ret = read(fd, result, sizeof(result));
			if(ret != sizeof(result))
			{
				DEB_PRINTF("read wrong\n");
				DEB_PRINTF("ret = %d\n", ret);
				return -1;
			}
			else 
			{
				DEB_PRINTF("read success !\n");
			}
			for (i = 0; i < ret; i++)
			{
		           adc_data = result[0] + (int)(result[1]<<8);  
		           DEB_PRINTF("adc value = %d (%.2f V) \n",adc_data, adc_data/1024.0*3.3);  
			}
			close(fd);
			return 0;
		}

测试结果如图
在这里插入图片描述

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值