光感模块是一种用于检测光照强度的传感器。它可以感知周围环境的光照水平,并将其转换为电信号输出。光感模块的工作原理基于光电效应,主要有以下几种类型:
光敏电阻(LDR):光敏电阻是一种基于光电效应的传感器,其电阻值会根据光照强度的变化而变化。当光照强度增加时,光敏电阻的电阻值会减小,反之亦然。通过测量光敏电阻的电阻值,可以得到光照强度的信息。
光电二极管(Photodiode):光电二极管是一种能够将光能转化为电能的二极管。当光照射到光电二极管上时,光子会激发电子,使其在PN结中产生电流。通过测量光电二极管上的电流,可以得到光照强度的信息。
光电三极管(Phototransistor):光电三极管是一种具有放大功能的光电二极管。它可以将光能转化为电能,并放大输出的电流。光电三极管通常具有更高的灵敏度和响应速度,适用于需要较高灵敏度的应用。
光电容传感器(Photocapacitor):光电容传感器是一种基于光电效应的电容传感器。当光照射到光电容传感器上时,光子会激发电子,使其在电容器中产生电荷积累。通过测量电容器上的电荷积累水平,可以得到光照强度的信息。
这些光感模块可以通过模拟电压输出或数字接口输出(例如I2C或SPI)来提供光照强度的信息。它们广泛应用于自动照明系统、环境监测、光线调节和光敏控制等领域。
调试光感模块(三个角分别接供电VCC、地GND、ADC),光线越亮, 屏越亮;光线越暗, 屏越暗(亮度不低于50%)
。
源码路径:kernel/drivers/input/keyboard/adc0_driver.c
/*
* Input driver for resistor ladder connected on ADC
*
* Copyright (c) 2016 Alexandre Belloni
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/*-------------------*/
struct iio_channel *adc_channel;
static ssize_t adc_value_read(struct device *dev, struct device_attribute *attr,char *buf)
{
//return sprintf(buf, "%d\n",sunxi_keyboard_read_data());
int read_value = 0;
if(adc_channel !=NULL)
iio_read_channel_processed(adc_channel, &read_value);
return sprintf(buf, "%d\n",read_value);
}
static DEVICE_ATTR(adc_value, S_IRUGO|S_IWUSR|S_IWGRP,adc_value_read, NULL);
static struct attribute *adc_value_attributes[] = {
&dev_attr_adc_value.attr,
NULL
};
static struct attribute_group adc_value_attribute_group = {
.attrs = adc_value_attributes
};
/*-------------------------------------------*/
static int adc0_driver_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct kobject *dev_kobj;
int err =-1;
printk("adc_value:adc_keys_probe 1\n");
adc_channel = devm_iio_channel_get(dev, "adc0_chan");
if (IS_ERR(adc_channel))
return PTR_ERR(adc_channel);
printk("adc_value:adc_keys_probe 2\n");
/*fy add kobj to create sysfs of adc_value>*/
dev_kobj = kobject_create_and_add("adc_value",NULL);
if(dev_kobj != NULL)
err = sysfs_create_group(dev_kobj,&adc_value_attribute_group);
if (err < 0)
{
printk("adc_value: sysfs_create_group err\n");
}
/*fy: end >*/
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id adc0_driver_of_match[] = {
{ .compatible = "adc0_driver", },
{ }
};
MODULE_DEVICE_TABLE(of, adc0_driver_of_match);
#endif
static struct platform_driver __refdata adc0_driver = {
.driver = {
.name = "adc0_driver",
.of_match_table = of_match_ptr(adc0_driver_of_match),
},
.probe = adc0_driver_probe,
};
module_platform_driver(adc0_driver);
MODULE_AUTHOR("Alexandre Belloni " );
MODULE_DESCRIPTION("Input driver for resistor ladder connected on ADC");
MODULE_LICENSE("GPL v2");
iio_read_channel_processed` 函数的实现是在 IIO 子系统中完成的。它的主要作用是读取指定 IIO 通道的原始值,并将其转换为工程单位后的值。下面是该函数的伪代码:
int iio_read_channel_processed(struct iio_channel *chan, int *val)
{
int ret;
long long raw_val;
double scale, offset;
// 读取 IIO 通道的原始值
ret = iio_read_channel_raw(chan, &raw_val);
if (ret < 0)
return ret;
// 获取 IIO 设备的比例因子和偏移量
scale = iio_channel_get_scale(chan);
offset = iio_channel_get_offset(chan);
// 将原始值转换为工程单位后的值
*val = (int)round((raw_val * scale) + offset);
return 0;
}
在这个函数中,首先调用 iio_read_channel_raw函数读取 IIO 通道的原始值,并将其保存在 raw_val变量中。然后,通过调用 iio_channel_get_scale和 iio_channel_get_offset函数获取 IIO 设备的比例因子和偏移量。比例因子和偏移量是用于将原始值转换为工程单位后的值的参数。最后,将原始值乘以比例因子,加上偏移量,并使用 round函数四舍五入为整数,得到处理后的值,并将其保存在 val 变量中。
需要注意的是,iio_read_channel_processed 函数只能读取处理后的值,而无法读取原始值。如果需要读取原始值,可以使用 iio_read_channel_raw 函数。
1> 获取AD通道
struct iio_channel *chan; //定义 IIO 通道结构体
chan = iio_channel_get(&pdev->dev,xxx); //获取 IIO 通道结构体
注: iio_channel_get 通过 probe 函数传进来的参数 pdev 获取 IIO通道结构体,probe 函数如下:
2> 读取AD采集到的原始数据
int val,ret;
ret = iio_read_channel_raw(chan, &val);
调用 iio_read_channel_raw 函数读取 AD 采集的原始数据并存入 val 中。
3> 计算采集到的电压
使用标准电压将 AD 转换的值转换为用户所需要的电压值。其计算公式如下:
Vref / (2^n-1) = Vresult / raw
例如,标准电压为 1.8V,AD 采集位数为 10 位,AD 采集到的原始数据为 568,则: Vresult = (1800mv * 568) / 1023
源码路径:kernel/drivers/input/keyboard/Makefile
diff --git a/kernel/drivers/input/keyboard/Makefile b/kernel/drivers/input/keyboard/Makefile
index 182e929..0ada96c 100644
--- a/kernel/drivers/input/keyboard/Makefile
+++ b/kernel/drivers/input/keyboard/Makefile
@@ -67,3 +67,4 @@ obj-$(CONFIG_KEYBOARD_TM2_TOUCHKEY) += tm2-touchkey.o
obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o
obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o
+obj-y += adc0_driver.o
源码路径:kernel/arch/arm64/boot/dts/rockchip/rk3568.dtsi
diff --git a/kernel/arch/arm64/boot/dts/rockchip/rk3568.dtsi b/kernel/arch/arm64/boot/dts/rockchip/rk3568.dtsi
index 0cf8a59..3384fe1 100644
--- a/kernel/arch/arm64/boot/dts/rockchip/rk3568.dtsi
+++ b/kernel/arch/arm64/boot/dts/rockchip/rk3568.dtsi
@@ -291,6 +291,13 @@
};
};
+ adc:adc0_driver {
+ compatible = "adc0_driver";
+ io-channels = <&saradc 4>;
+ io-channel-names = "adc0_chan";
+ //keyup-threshold-microvolt = <1800000>;
+ };
firmware {
firmware_android: android {
compatible = "android,firmware";
驱动部分添加完成后编译烧录, 在进入系统后,会出现一个 /sys/adc_value/adc_value
节点,表示创建成功。cat /sys/adc_value/adc_value可看到节点状态。
源码路径:frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java
diff --git a/frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java b/frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java
index 1f41038..3298c78 100644
--- a/frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java
+++ b/frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java
@@ -39,13 +39,40 @@ import java.io.PrintWriter;
import javax.inject.Inject;
-public class SystemUIService extends Service {
+import android.app.smdt.SmdtManagerNew;
+import android.app.smdt.SmdtManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.io.BufferedReader;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.OutputStream;
+import android.content.Context;
+public class SystemUIService extends Service {
+ private static final String TAG="SystemUIService";
private final Handler mMainHandler;
private final DumpHandler mDumpHandler;
private final BroadcastDispatcher mBroadcastDispatcher;
private final LogBufferFreezer mLogBufferFreezer;
private final BatteryStateNotifier mBatteryStateNotifier;
+ private SmdtManager mSmdt=null;
+ private SmdtManagerNew smdtManagerNew;
+ private Context mContext;
@Inject
public SystemUIService(
@@ -72,6 +99,13 @@ public class SystemUIService extends Service {
// Finish initializing dump logic
mLogBufferFreezer.attach(mBroadcastDispatcher);
+ mContext=this;
+ if(mSmdt==null){
+ mSmdt = new SmdtManager(mContext);
+ smdtManagerNew = SmdtManagerNew.getInstance(mContext);
+ }
+ mHandler.sendEmptyMessageDelayed(1001,100);
+
// If configured, set up a battery notification
if (getResources().getBoolean(R.bool.config_showNotificationForUnknownBatteryState)) {
mBatteryStateNotifier.startListening();
@@ -103,6 +137,87 @@ public class SystemUIService extends Service {
UserHandle.SYSTEM);
}
+private Handler mHandler=new Handler(){
+ @Override
+ public void dispatchMessage(Message msg) {
+ switch (msg.what){
+ case 1001://wifi
+ Log.d(TAG, "dispatchMessage: fy==========value="+cccccss());//("cat /sys/adc_value/adc_value"));
+ readLightSenseValue();
+ mHandler.removeMessages(1001);
+ mHandler.sendEmptyMessageDelayed(1001,500);
+ break;
+ case 1002://
+
+ break;
+ default:
+ break;
+ }
+ }
+};
+private int cccccss(){//get light sensor value
+ String a="0";
+ try {
+ BufferedReader bufWriter = null;
+ bufWriter = new BufferedReader(new FileReader("/sys/adc_value/adc_value"));
+ a=bufWriter.readLine();
+ bufWriter.close();
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ Log.e("aaa","can't write the point" );
+ }
+ return Integer.parseInt(a);
+}
+
+//光线越亮, 屏越亮;光线越暗, 屏越暗(亮度不低于50%)
+private int oldvalue = 1800;
+private int time = 0;
+private int readLightSenseValue(){
+ int result=0;
+ int value=cccccss();
+ Log.d(TAG, "dispatchMessage: fy==========value="+value);
+ if(Math.abs(value - oldvalue) < 10)
+ return result;
+ time ++;
+ if(time < 2)
+ return result;
+ time = 0;
+
+ Log.d(TAG, "readLightSenseValue: adc value="+value + " oldvalue="+oldvalue);
+ oldvalue = value;
+ float fv = ((float)value - 1646) / 150;
+ Log.d(TAG, "readLightSenseValue: fv="+fv);
+ value=(int)(fv*255);
+ if(value < 10)
+ value = 10;
+
+ //value = (int)(((255.0 - 125.0) / 10.0 ) * value + 125 );
+ if(value > 255)
+ value = 255;
+ Log.d(TAG, "smdt set lvds Brightness " + value);
+ setLcdBrightness(value);
+ mSmdt.setBrightness(getContentResolver(), value);
+ return result;
+}
+
+/* //光线越暗 屏越亮,光线越亮 屏越暗(亮度不低于50%)
+private int oldvalue = 1800;
+private int time = 0;
+private int readLightSenseValue(){
+ int result=0;
+ int value=cccccss();
+ if(Math.abs(value - oldvalue) < 40)
+ return result;
+ time ++;
+ if(time < 3)
+ return result;
+ time = 0;
+ Log.d(TAG, "readLightSenseValue: adc value="+value + " oldvalue="+oldvalue);
+ oldvalue = value;
+ value = (value - 900) / 40;
+ Log.d(TAG, "readLightSenseValue: value="+value);
+ if(value > 10)
+ value = 10;
+ setLcdBrightness(value);
+ value = (int)(((255.0 - 125.0) / 10.0 ) * value + 125 );
+ if(value > 255)
+ value = 255;
+ Log.d(TAG, "smdt set lvds Brightness " + value);
+ mSmdt.setBrightness(getContentResolver(), value);
+ return result;
+}
+*/
+private void setLcdBrightness(int bri){
+ smdtManagerNew.disp_setLcdBackLight(0, bri, 0, false);
+
@Override
public IBinder onBind(Intent intent) {
return null;