概述
这次来分享一次突发奇想的经历。文章主要是要实现将ADC模块获取的光敏电阻数值转换成标准单位勒克斯的光照强度,虽然说由于实验方法和实验环境,最终结果并不是很准确,但也算是一次创意小实验。
最终的代码可以来这里下载:
Android端
MCU端
本文目录
- 一、前言(无关技术的废话,可以跳过)
- 二、具体实现思路
- 三、实验设备和环境
- 1.软件
- 2.硬件
- 3.其它
- 四、Android端开发
- 1.搭建界面
- 2.搭建SQLite数据库
- 2.1创建类
- 2.2创建数据库Helper
- 2.3创建Adapter
- 3.在MainAcivity使用传感器服务获取数据
- 五、MCU端开发
- 1.使用STM32CubeMX配置引脚
- 2.在Keil中设置串口发送和ADC电压数值的读取
- 2.1设置串口发送的函数
- 2.2设置ADC的读取函数
- 3.在主循环中读取电压和发送数据
- 六、实际测试
- 1.测试前准备
- 2.正式测试
- 七、数据拟合处理
- 1.数据汇总
- 2.拟合处理
一、前言(无关技术的废话,可以跳过)
最近在项目搞STM32和光敏电阻传感器,辛辛苦苦地找了厂家客服和很多资料,发现都没有光敏电阻阻值或者电压转换成光照强度的公式。
百度了一下,发现我还是太高估了光敏电阻的精确度了,大多数光敏电阻传感器只是提供一个大概的明暗程度的判断,有一些三线的光敏电阻传感器只是提供一个DO口,输出就是1位二进制表示的明和暗。四线的光敏电阻传感器就有提供一个AO口,输出的是12位二进制表示的电压,相比来说就准确了许多,但是不同厂家甚至是同一个厂家的不同光敏电阻,对于光照强度的转换相去甚远,所以基本上找不到一条符合所有光敏电阻的转换公式。如果要更加精准的光照强度,更多的是使用光敏二极管或者是数字照度仪等。
但是,我不甘心呀,项目需要的是光照强度,而到手的光敏电阻传感器我也不想就这么地废了。所以我就想:能不能自己给光敏电阻传感器测试一下,计算出属于它的公式。实际上,我只要有一个能够测光照强度的东西就可以实现。突然想到,手机不就有这个玩意吗?虽然手机的也不够精准,但还是值得一试的,于是,我就有一个大胆的思路:
- 开发一个可以获取手机光线传感器数据并且存入数据库的APP;
- 将手机和我的光敏电阻传感器同步同向测试,获取两者的数据;
- 将手机获取的以勒克斯(lx)作为单位的数据,和光敏电阻的数据进行拟合,获得两者之间的转换公式。
二、具体实现思路
三、实验设备和环境
1.软件
- Keil uVision5
- Android Studio 3.6.3
- 串口调试助手
- SQLite Expert Personal
- Excel 2016
2.硬件
- 光敏电阻传感器(4线)
- STM32F103C8T6
- ST-Link
- CH340(USB转TTL)
- 手机(使用Android系统的)
3.其它
- 绝缘胶带
- 手机支架(方便测试而已,没有的话可以不用)
- 光源(比如:手电筒、台灯之类,本文用的是另一个手机的手电筒)
四、Android端开发
1.搭建界面
首先在Android Studio中创建一个空白工程,因为本实验比较简单,所以只需要一个MainActivity就可以了。在activity_main.xml中添加简单的文字说明、两个按钮(开始和删除数据)以及ListView(用于展示数据)。
除此之外还要完成一个listview_item.xml的界面,这个就是用在ListView的每个item中的界面,在Adapter中适配。
2.搭建SQLite数据库
2.1创建类
这里虽然我们要存储的数据很简单,只有光照强度这一个浮点数值,但是为了方便操作数据库,还是要创建一个类,同时为了和MCU端收集的数据进行匹配,也添加了一个自增的变量id。
package com.peanuo.lighttest;
public class Light {
private int id;
private double lux;
public double getLux() {
return lux;
}
public int getId() {
return id;
}
public void setLux(double lux) {
this.lux = lux;
}
public void setId(int id) {
this.id = id;
}
}
2.2创建数据库Helper
这里继承了SQLiteOpenHelper类来完成我们自定义的数据库的创建。在构造方法中创建数据库,在重写的onCreate方法中使用SQL语句创建数据表。然后是增加两个方法insertData和deleteData来方便操作数据库。最后的query方法是查询数据表的中全部,也就是用来给ListView展示数据的。
package com.peanuo.lighttest.database;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import com.peanuo.lighttest.Light;
import java.util.ArrayList;
import java.util.List;
public class LightHelper extends SQLiteOpenHelper {
private SQLiteDatabase sqLiteDatabase;
public LightHelper(Context context) {
super(context,"lightDB",null, 1);
sqLiteDatabase = this.getWritableDatabase();
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE light(id INTEGER PRIMARY KEY AUTOINCREMENT, light REAL)");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { }
public boolean insertData(double light) {
ContentValues values = new ContentValues();
values.put("light",light);
return sqLiteDatabase.insert("light", null, values)>0;
}
public boolean deleteData(Context context){
return context.deleteDatabase("lightDB");
}
public List<Light> query(){
List<Light> list = new ArrayList<Light>();
Cursor cursor = sqLiteDatabase.query("light", null, null, null, null, null, "id desc");
if (cursor != null){
while (cursor.moveToNext()){
Light info = new Light();
int id = cursor.getInt(cursor.getColumnIndex("id"));
double lux = cursor.getDouble(cursor.getColumnIndex("light"));
info.setId(id);
info.setLux(lux);
list.add(info);
}
cursor.close();
}
return list;
}
}
2.3创建Adapter
创建这个适配器就是用来给契合ListView和数据库的。这里要继承BaseAdapter类,然后实现getCount、getItem、getItemId、getView这些方法,最后的ViewHoled类是使用了优化加载list的方法。
package com.peanuo.lighttest.database;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import com.peanuo.lighttest.Light;
import com.peanuo.lighttest.R;
import java.util.List;
public class LightAdapter extends BaseAdapter {
private LayoutInflater layoutInflater;
private List<Light> list;
public LightAdapter(Context context, List<Light> list){
this.layoutInflater = LayoutInflater.from(context);
this.list = list;
}
@Override
public int getCount() {
return list==null ? 0 :list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if(convertView == null){
convertView = layoutInflater.inflate(R.layout.listview_item, null);
holder = new ViewHolder();
holder.id = convertView.findViewById(R.id.item_id);
holder.light = convertView.findViewById(R.id.item_light);
convertView.setTag(holder);
}else {
holder = (ViewHolder) convertView.getTag();
}
Light info = (Light) getItem(position);
holder.id.setText(String.valueOf(info.getId()));
holder.light.setText(String.valueOf(info.getLux()));
return convertView;
}
class ViewHolder{
TextView id,light;
}
}
3.在MainAcivity使用传感器服务获取数据
MainAcivity中要先创建SensorManager和Sensor,分别是所有传感器服务的变量以及具体传感器的变量。TYPE_LIGHT就是指向光线传感器的。在activity处于onResume时,要注册传感器服务,在处于onPause时要注销。
sensorManager = (SensorManager)this.getSystemService(SENSOR_SERVICE);
assert sensorManager != null;
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
@Override
protected void onResume() {
super.onResume();
sensorManager.registerListener(sensorEventListener, sensor, SensorManager.SENSOR_DELAY_NORMAL);
}
@Override
protected void onPause() {
super.onPause();
sensorManager.unregisterListener(sensorEventListener);
}
创建自定义的线程来实现测试,同时在其中使用runOnUiThread来更新界面数据。(由于我对Android的线程还不太了解,所以此处这样处理并不是最佳的)
//开始测试的线程
private class TestThread extends Thread{
@Override
public void run() {
super.run();
while (isTesting){
try {
Thread.sleep(4000);
if (lightHelper.insertData(light)) {
Log.i("Light","光照强度:"+light);
}
} catch (InterruptedException e) {
e.printStackTrace();
Log.i("Thread","测试线程已停止");
//break;
}
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
showData();
}
});
}
}
}
五、MCU端开发
1.使用STM32CubeMX配置引脚
首先根据自己的MCU型号创建工程,然后在SYS中根据自己使用的调试器选择Debug。我这里是使用ST-Link,所以选择Serial Wire。
接着,就是配置ADC和USAR了。根据自己的板子随便选,我这里选择的是ADC1 IN8和USART1。这两个外设的配置都保持默认的参数就行了。
最后在生成代码之前,要去Project设置好名称、文件位置和对应的IDE。然后点击靠近右上角的GENERATE CODE就行了。
注意一下,可以点击Code Generator里面在下面图示的位置打一个钩,这样生成的代码文件就会分类放好,如果没有打勾的话,就会全部放在main文件中。
2.在Keil中设置串口发送和ADC电压数值的读取
找到STM32CubeMX生成的代码文件,打开Keil工程文件。
首先,我们要将芯片的启动文件添加进去工程。(不知道此处是我的Keil配置问题还是STM32Cube本身的问题,生成的代码总是得自己亲手添加启动文件进去工程)
注意,在使用STM32CubeMX生成的代码,在Keil中编辑的时候自己添加的代码要在BEGIN注释和END注释之间,否则用STM32CubeMX重新生成代码之后,不在两个注释之间的代码会被清除。
2.1设置串口发送的函数
要现在usart.h头文件中声明函数void u1_printf(char* fmt, …);
然后在usart.c文件中添加串口发送的函数。这里使用的是类似于printf的方法。
void u1_printf(char* fmt,...)
{
uint8_t i,j;
va_list ap;
va_start(ap,fmt);
vsprintf((char*)USART1_TX_BUF,fmt,ap);
va_end(ap);
i=strlen((const char*)USART1_TX_BUF); //此次发送数据的长度
for(j=0;j<i;j++) //循环发送数据
{
while((USART1->SR&0X40)==0); //循环发送,直到发送完毕
USART1->DR=USART1_TX_BUF[j];
}
}
2.2设置ADC的读取函数
同样,首先要在头文件中声明函数uint16_t read_adc(void);
然后到c文件中添加函数。
注意此函数读取的数字不是标准单位的电压伏特值,而是ADC读取得使用12位二进制表示的电压,还未按照比例换算成电压伏特值。由于我的目标是转换成光照强度,所以先按比例转换成电压没有必要,所以就直接使用ADC读取的数值了。
uint16_t read_adc(void)
{
uint16_t temp;
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 50);
if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
{
temp = HAL_ADC_GetValue(&hadc1);
}
return temp;
}
3.在主循环中读取电压和发送数据
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_Delay(3000);
id++;
light = read_adc();
u1_printf("id: %d light: %drn", id, light);
}
/* USER CODE END 3 */
六、实际测试
1.测试前准备
- 找一个比较暗的地方做实验。
- 将实验手机开启开发者模式,然后允许USB安装,使用USB连接到电脑,通过Android Studio调试的方法将app安装到手机上。
- 在Keil将开发好的工程编译下载到开发板上
- 把光敏电阻传感器的引脚接到开发板对应的GPIO口引脚。
- 将CH340连接到电脑以及串口对应的开发板的引脚。
- 用绝缘胶带将光敏电阻传感器贴在手机靠近光线传感器的部分,并且朝向要和手机正面一样,每个手机的位置都不太一样,不过基本都是在屏幕上部听筒的附近。
- 打开串口助手和端口,准备接收串口数据。
- 打开手机APP,这里最好的话手机可以一直开着开发者模式,保持充电,而且开启“充电时保持不休眠”的功能。
2.正式测试
- 做好上述的准备工作之后,就可以着手开始了。
- 要先启动单片机,之后MCU端会有3秒的等待时间(LED灯会闪烁),时间到了就点击手机APP的开始按钮。这样才能保证两端是同时开始的。
- 然后就使用外部的光源逐渐地改变亮度。尽量让亮度的范围广一点,才能让拟合计算出来的数据更加准确。
七、数据拟合处理
1.数据汇总
- 将串口助手收集到的数据复制到excel中,在excel中使用分列的方式将id和light数据提取出来放在工作表Sheet1中
- Android端的数据库可以通过Android Studio提取出来,将手机连接到电脑,打开Android Studio的Device File Explorer,查看连接至电脑的设备,可以直接获取我们的数据库文件,路径是:data/data/自己应用的包名/databases,然后就可以看到我们的数据库文件了,点击save as保存,此处要自己添加一个后缀名.db。
- 在SQLite Expert Personal打开我们保存的数据库,然后复制数据到excel的Sheet2。
- 在excel的Sheet3中将两个数据的id进行匹配,最后整理成两列数据,如下图所示。
2.拟合处理
- 选中两列数据,然后插入散点图。
- 选择散点图,添加趋势线,然后在趋势线选项中点击显示R平方值。
- 选择“指数”、“多项式”、“乘幂”等不同的趋势线,对比R平方值,选择最接近1的一个,就大功告成了,可以看到实验拟合的结果了。
最后
以上就是美满舞蹈为你收集整理的使用拟合方法实现光敏电阻传感器数值与光照强度的近似转换一、前言(无关技术的废话,可以跳过)二、具体实现思路三、实验设备和环境四、Android端开发五、MCU端开发六、实际测试七、数据拟合处理的全部内容,希望文章能够帮你解决使用拟合方法实现光敏电阻传感器数值与光照强度的近似转换一、前言(无关技术的废话,可以跳过)二、具体实现思路三、实验设备和环境四、Android端开发五、MCU端开发六、实际测试七、数据拟合处理所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复