[其他ST产品] STM32使用光敏传感器计算光照度Lux

[复制链接]
6490|17
 楼主| 漫天星yl 发表于 2023-1-15 23:40 | 显示全部楼层 |阅读模式

最近项目中用到了光敏电阻。搜索资料,发现很多人都使用光敏电阻,只是用了AD读取了电压值,或者算出了电阻值,就发送给上位机或者服务器,美其名曰获取了光照度。

c462ec4b8fc0ce2f5373037f2fbf51dd.png

搜索一番,也没找到用光敏电阻计算Lux的方法,于是自己做了一些研究,分享一下。


评论

———————————————— 版权声明:本文为CSDN博主「yummy说电子」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/geek_monkey/article/details/116280622  发表于 2023-1-15 23:41
 楼主| 漫天星yl 发表于 2023-1-15 23:40 | 显示全部楼层
计算光敏电阻值
相信STM32的ADC读者应该会用,教程也一抓一大把,在此不表。接下来先计算电阻值。我的光敏电阻电路图如下:
7662063c41e7470907.png
其中PA6接单片机AD采集引脚,它最大只能输入3.6V电压,而光敏电阻的供电为5V,所以设计了R1与R2两个分压电阻,确保PA6的电压不超过3.6V。
 楼主| 漫天星yl 发表于 2023-1-15 23:45 | 显示全部楼层
设光敏电阻的阻值为xΩ,PA6的电压为y,可得以下公式:                     

y/1500=5/(x+2500)

STM32的ADC精度为12位,则最大值为4096。采集到的AD值与电压成线性对应关系,系统中最高的电压值为3.3V的电源电压,它与4096对应。假设PA6感受到的电压y对应的AD值为z,则:

y/z=3.3/4096

联立两式,消去y,得到关于x的表达式:

x=10240000/(1.1×z)-2500

使用ADC得到z以后,就可以根据上式算出光敏电阻的值了。
 楼主| 漫天星yl 发表于 2023-1-15 23:46 | 显示全部楼层
我的代码使用了DMA获取多通道AD值,并且取100个数据求算数平均值滤波,然后打印电阻值的代码如下
  1. //main.c  main()
  2.   while (1)
  3.   {
  4.     if(DMA_Flag)
  5.     {
  6.       for(int i=0;i<ADC_CHANNEL_CNT;i++)
  7.         printf("CH%d value = %d \n",i+2,ADC1_AVG_Buf[i] );
  8.       uint32_t PhotoResistor = (uint32_t)(10240000/(1.1*ADC1_AVG_Buf[4]) - 2500);
  9.       //串口打印采样结果
  10.       printf("The AD value is %d,the PhotoResistor is %d .\r\n",ADC1_AVG_Buf[4],PhotoResistor);
  11.       printf("The DMA count is %d .\r\n",DMA_CNT);
  12.       DMA_Flag = 0;
  13.     }
  14.   }
 楼主| 漫天星yl 发表于 2023-1-15 23:48 | 显示全部楼层
现象是能够打印出光敏电阻值。
6765163c420545ddfb.png
 楼主| 漫天星yl 发表于 2023-1-15 23:49 | 显示全部楼层
从电阻值到光照度
之前已经算出来了光敏电阻的电阻值,并且能够分出光照强度的等级,但是仍然无法计算出光照强度。光照强度是指单位面积上所接受可见光的能量,简称照度,单位勒克斯(Lux或lx)。常见环境的光照强度值如表
 楼主| 漫天星yl 发表于 2023-1-15 23:50 | 显示全部楼层
 楼主| 漫天星yl 发表于 2023-1-15 23:51 | 显示全部楼层
精确测量光照强度是比较困难的一件事情,使用简陋的光敏电阻测量光照强度则精度更难以保障。本节的重点是解决问题的思路,如何用较简单的方法获取相对准确的光照度。配套电路板中使用的光敏电阻型号为GL5528,它的主要参数如表
9496863c420d76bf67.png
 楼主| 漫天星yl 发表于 2023-1-15 23:51 | 显示全部楼层
其中的γ值表示10Lux电阻值与100Lux电阻值的比值的对数。

γ=lg⁡(R10/R100)

将γ=0.6带入,可得R10/R100≈4。即R10=4×R100,对于R10与R1关系仍然成立:R1=4×R10。手册中给出了一个对数坐标系的图,光照强度与Lux的对应关系并非一条直线,而是一个范围。为了简便计算,取范围中稍微靠下的一条直线,直线中包含(1,40),(10,10),(100,2.5)这三个点。
 楼主| 漫天星yl 发表于 2023-1-15 23:52 | 显示全部楼层
6458863c421237ae46.png
手册中给出的1到100范围太小了,常用光照度可到达1000Lux,因此要通过现有的关系推算出光照度与电阻值的关系式。虽然看上去光照度与电阻值的对应关系是一条直线,但是要注意坐标系是对数坐标系,不能套用一元一次方程。
 楼主| 漫天星yl 发表于 2023-1-15 23:53 | 显示全部楼层
在MATLAB中拟合,拟合过程如图7-19所示。可得关系式为:

f(x)=(4e+0.4)×x^(-0.6021)

拟合过程如图。

6360763c42151a0d2e.png
 楼主| 漫天星yl 发表于 2023-1-15 23:54 | 显示全部楼层
编写代码算出光照度
在单片机内,用带指数的关系式计算,计算速度会很慢。可以使用查表法,无需计算,只遍历数组得到结果。根据拟合得到的函数,可以推导出Lux从1到1000,各自对应的电阻值,共1000对。观察数据,可以发现在Lux比较大的时候,对应的电阻值过于接近。此处仅要求粗略计算,无需这么多数据。将电阻值的个位数舍去,并删除重复电阻值,可得到281对数据。
7572863c4217adcde6.png
 楼主| 漫天星yl 发表于 2023-1-15 23:54 | 显示全部楼层
定义新的结构体数据如下。
  1.   //ADC.h
  2. typedef struct
  3. {
  4.   unsigned short ohm;   //光敏电阻值
  5.   unsigned short lux;   //流明
  6. }PhotoRes_TypeDef;
  7. //ADC.c
  8. //GL5528光敏电阻的阻值与流明对应的关系
  9. const  PhotoRes_TypeDef GL5528[281]=
  10. {
  11. {40000, 1},{26350, 2},{20640, 3},{17360, 4},{15170, 5},
  12. {13590, 6},{12390, 7},{11430, 8},{10650, 9},{9990, 10},
  13. {9440, 11},{8950, 12},{8530, 13},{8160, 14},{7830, 15},
  14. ......
  15. {720, 773},{710, 791},{700, 809},{690, 829},{680, 849},
  16. {670, 869},{660, 891},{650, 914},{640, 937},{630, 961},
  17. {620, 987},
  18. };

 楼主| 漫天星yl 发表于 2023-1-15 23:55 | 显示全部楼层
当得到电阻值以后,遍历数据,算出光照度,代码如下。
  1. //ADC.c
  2. /**
  3.   * [url=home.php?mod=space&uid=247401]@brief[/url] 通过电阻值算出光照度
  4.   * @param 光敏电阻值
  5.   * @retval None
  6.   */   
  7. unsigned short GetLux(uint32_t PhotoResistor)
  8. {
  9.   unsigned short lux = 0;
  10.   //查表法,根据电阻值得出光照度
  11.   for(int i = 0 ; i < 281 ; i++)
  12.   {
  13.     if (PhotoResistor > GL5528[i].ohm)
  14.     {
  15.       lux = GL5528[i].lux;
  16.       break;
  17.     }
  18.   }
  19.   return lux;
  20. }
 楼主| 漫天星yl 发表于 2023-1-15 23:55 | 显示全部楼层
主函数中,打印光照度:
  1. //main.c main() while(1)
  2.     if(DMA_Flag)
  3.     {
  4.       unsigned short lux = 0;
  5.       for(int i=0;i<ADC_CHANNEL_CNT;i++)
  6.         printf("CH%d value = %d \n",i+2,ADC1_AVG_Buf[i] );
  7.       uint32_t PhotoResistor = (uint32_t)(10240000/(1.1*ADC1_AVG_Buf[4]) - 2500);
  8.       //从电阻值计算光照度
  9.       lux = GetLux(PhotoResistor);
  10.       //串口打印采样结果
  11.       printf("The AD value is %d,the PhotoResistor is %d .\r\n",ADC1_AVG_Buf[4],PhotoResistor);
  12.       printf("The Lux is %d .\r\n",lux);
  13.       printf("The DMA count is %d .\r\n",DMA_CNT);
  14.       DMA_Flag = 0;
  15.     }

 楼主| 漫天星yl 发表于 2023-1-15 23:56 | 显示全部楼层
下载程序,观察现象,应该看到如图7-19所示的现象,说明算出了Lux的值。
8149163c4220be09b9.png
 楼主| 漫天星yl 发表于 2023-1-15 23:56 | 显示全部楼层
当然,这个计算结果也不会很精确,毕竟光照度与电阻的关系也不是一一对应的。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

34

主题

350

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部