01. 光敏传感器简介
2 {# U! m( s9 K, r- N- B3 ]. k光敏传感器是最常见的传感器之一,它的种类繁多,主要有:光电管、光电倍增管、光敏电阻、光敏三极管、太阳能电池、红外线传感器、紫外线传感器、光纤式光电传感器、色彩传感器、CCD 和 CMOS 图像传感器等。光传感器是目前产量最多、应用最广的传感器之一,它在自动控制和非电量电测技术中占有非常重要的地位。
. ^) g9 W# P$ I$ F ~
& G. A3 P( V: N0 L7 F光敏传感器是利用光敏元件将光信号转换为电信号的传感器,它的敏感波长在可见光波长附近,包括红外线波长和紫外线波长。光传感器不只局限于对光的探测,它还可以作为探测元件组成其他传感器,对许多非电量进行检测,只要将这些非电量转换为光信号的变化即可。
. b- E7 l1 S# @1 P/ j7 ]" k! p; Z; {1 ^/ N5 r/ i; T
探索者 STM32F4 开发板板载了一个光敏二极管(光敏电阻),作为光敏传感器,它对光的变化非常敏感。光敏二极管也叫光电二极管。光敏二极管与半导体二极管在结构上是类似的,其管芯是一个具有光敏特征的 PN 结,具有单向导电性,因此工作时需加上反向电压。无光照时,有很小的饱和反向漏电流,即暗电流,此时光敏二极管截止。当受到光照时,饱和反向漏电流大大增加,形成光电流,它随入射光强度的变化而变化。当光线照射 PN 结时,可以使 PN 结中产生电子一空穴对,使少数载流子的密度增加。这些载流子在反向电压下漂移,使反向电流增加。因此可以利用光照强弱来改变电路中的电流。) _% v& V( s. m: ?7 s
5 H/ R, }5 T4 U5 }& ?
利用这个电流变化,我们串接一个电阻,就可以转换成电压的变化,从而通过 ADC 读取电压值,判断外部光线的强弱。
; n2 ^ H2 ?& c5 T$ ~# A
8 K: S; u s8 S/ z6 u8 a02. 硬件模块
8 P% w" W" S3 u# p- y m0 x* U用到的硬件资源有:
! K. p: ~# |* [9 D- d* _1) 指示灯 DS0
8 n3 G2 E) Y ^/ {3 a1 b2) TFTLCD 模块/ u+ E1 w; Z6 M# ]
3) ADC
7 a/ C) Z* D/ [, G. @4) 光敏传感器0 }3 {$ q t+ U8 h- M1 r+ Z% D* c
7 G* T, {( ^* j0 k
$ b$ ?% l5 {& e% s' _' m, f9 R
$ N7 N3 N4 j! \, { F) C4 m) h p3 WLS1 是光敏二极管(实物在开发板摄像头接口右侧),R58 为其提供反向电压,当环境光线变化时,LS1 两端的电压也会随之改变,从而通过 ADC3_IN5 通道,读取LIGHT_SENSOR(PF7)上面的电压,即可得到环境光线的强弱。光线越强,电压越低,光线越暗,电压越高。! L' G+ U! s7 Z7 J; V
/ T3 c! M+ p6 _
03. 程序设计) D3 j1 y4 ^3 D; W
adc.h文件
9 p0 u" \+ b" Y! d- l3 N5 U- //-----------------------------------1 T% X2 m; }* \2 ?
- //ADC3通道初始化
- J& C- c5 T% d4 a: S - void ADC3_Init(void);
% L) }6 [% {8 f - //获取ADC3某个通道的值
2 P* ~* H0 C5 G: Z - u16 Get_Adc3(u8 ch);- |8 f9 B A& x A4 j
- //获取某个通道给定次数采样的平均值1 q6 z g8 R5 G& ^6 `
- u16 Get_Adc3_Average(u8 ch, u8 times);
复制代码
$ g% N H! [% B' Y) v( Ladc.c文件& ~/ Z% A2 S; z' L& E. j! F$ s
& z5 c' n/ D2 B5 m( b! T
- //-------------------------ADC3------------------------
3 R, V, c7 f6 \' R( V H - //ADC3通道初始化
6 P; W1 B) x/ e% S! s* q: J$ u3 a9 [ - void ADC3_Init(void)
0 q4 Y/ Z6 {; [+ `' X - {& K! f! h- {. F, L" X- U, i
- GPIO_InitTypeDef GPIO_InitStructure;' q: z5 r, T4 v& m* y
- ADC_CommonInitTypeDef ADC_CommonInitStructure;
* {; B I! x: E6 E9 L - ADC_InitTypeDef ADC_InitStructure;$ a9 Q h1 @' U$ z2 K
-
( w& T, e5 {4 a' N: m - //开启GPIO时钟 PA5
( Q; m( ?8 I% J6 N# l3 w - RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
3 j' t1 {# {, a3 Q* P# d - 2 y3 c* P" P( u" u. ^# d+ W, b4 O% M
- //开启ADC1时钟$ h) N" e0 ]: j" ?% T
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE); 0 A, B. }: i( H
-
9 f- W$ u) R: K+ {2 P - //GPIO初始化 初始化为模拟功能0 d3 k- L5 _& |' C
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
+ Q6 b: y$ f: K. H9 z2 u - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
6 ], i+ N) `( M! _ - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; I0 Q8 o& w5 z6 c* o* Y
- GPIO_Init(GPIOF, &GPIO_InitStructure);' @& \7 H$ z9 u/ `1 x3 o& A
-
' _0 z8 |8 I. z+ { ^% Y - RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC3,ENABLE); //ADC1复位
( z0 W& o2 C& J$ L2 P5 S% Q - RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC3,DISABLE); //复位结束
' y+ f: l: a. Y, [1 O+ _( P! x - ; h/ c; A! c2 s- k. o+ u
-
9 z0 n3 R5 b$ t - //初始化ADC_CCR寄存器8 u8 Z2 {. K% _$ b* x" y+ S; Q4 ^
: L# r s7 o( j, P: o; }- ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;1 z+ a) _" D( g" ^% ^
- ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
) K% A+ S% N, p7 i4 ?( T# Q - ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
( w+ b% o" H& x - ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;
6 q; I# J; r4 q) x+ X3 m - ADC_CommonInit(&ADC_CommonInitStructure);
& C! _' ~, f# I5 r) X0 h; |: x8 m% T -
5 w6 T5 M5 I8 |, w5 O8 {* X7 F - 2 @9 r3 l5 H& p1 q0 k+ s1 @2 F5 n1 T( h
- //初始化ADC1- |5 Z: T' V. D. T
- ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;7 [. g7 G$ C. e ?
- ADC_InitStructure.ADC_ScanConvMode = DISABLE;6 v2 B4 [+ Q* a, e% }
- ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
" L% J2 v+ Y7 h0 [6 {, R. B3 r - ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
! k9 M4 I, d3 \5 w# F5 C$ p! P - ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
; g9 C! N: F! P" Y; O8 Z - ADC_InitStructure.ADC_NbrOfConversion = 1;9 ]0 i5 J: X5 ]9 C+ |4 E
- , Y c+ N* e& K
- ADC_Init(ADC3, &ADC_InitStructure);% ]) j1 W9 o* T9 h5 W
- 7 t* C* q) f' n4 l& u3 ^) M+ D
- |; S) n+ c! O( b. Q9 f( \- //设置ADC规则组通道 一个序列 采样时间
- V- Q/ q0 I: ?+ B - //ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 1, ADC_SampleTime_480Cycles);
5 _( j5 h# [( e) Y& M - . P! T0 {) j# r3 R; \' s$ v
! i; d& r* y9 B; U" r$ c* _4 u- //使能ADC
2 S- H6 g- N/ { - ADC_Cmd(ADC3, ENABLE);! k# [8 s; n I0 ^
-
' \/ E/ c g w2 B9 [& `" D - }
& ~, C; o3 Q" M& a/ W, f
- u1 z! \, `' X+ ?. l- //获取ADC3某个通道的值8 }+ b: W' C: p* T+ j5 c
- u16 Get_Adc3(u8 ch)# e. d8 n, [5 i* R5 \( ?
- {
! U. I3 R& ~5 a7 M+ j - //设置ADC规则组通道 一个序列 采样时间
# X" I/ J! q% ~( i - ADC_RegularChannelConfig(ADC3, ch, 1, ADC_SampleTime_480Cycles);
% e# ~# Q. x* z" r -
6 ?- X5 h5 j1 F4 B& s) [0 r - //开启ADC3的软件转换启动功能
. s0 g9 Y8 J' }' F( L* P - ADC_SoftwareStartConv(ADC3);
: J3 Q; }2 J: m -
: T }% V* @/ ~0 C - //等待转换结束
* k- n$ A1 X5 I0 k1 w6 G - while(ADC_GetFlagStatus(ADC3, ADC_FLAG_EOC) == RESET)
, C3 A0 x J# @1 `7 } - ;2 ^5 x0 U" P( k1 |
, R* n0 ]2 l/ @% N- L9 K- //读取ADC的值# V1 y$ q) O- ~: b
- return ADC_GetConversionValue(ADC3);& H5 L6 X$ X! g0 w' U7 t$ p
- " U# L, K) \* Q9 m. k
- }( @, i @% g- L
- 4 U+ w% }/ r1 y* J- S9 {! V
- //获取某个通道给定次数采样的平均值
1 V2 ]0 n% U) N+ Y - u16 Get_Adc3_Average(u8 ch, u8 times)
3 G2 f! K) M* Q1 ~3 K8 z - {
8 Q ]) C5 Z( Y8 L5 | - u32 tmp = 0;
3 h8 u4 m, S8 N. g& i# W - u8 i = 0;( X. K" `! ~; h+ c% l; s0 H9 G/ M
-
" l/ w# {1 }! Y; ], ]9 _; ], r9 z - for (i = 0; i < times; i++)" x1 e; A" ? _# c- X* q* p J
- {4 ~1 [7 c8 n' g" d( s5 e
- tmp += Get_Adc3(ch);
! q) E, a7 ^( h* l$ j1 `& E# h - delay_ms(5);
3 W' }5 `; r/ U4 J7 ~ -
% [0 T$ D2 p! K2 S r; y8 H - }6 \ l( x4 m4 E
- b7 y& j6 w! ~- W" U% Y8 P# x
- //得到平均值2 Y% q0 Z0 }3 w' e N1 a& s0 L9 W" i
- tmp /= times;
+ `9 r, A2 C3 C: o - . }( ?' A4 m1 Q6 k- p* b, R
- if (tmp > 4000) G4 B, l% ], {3 j) \% N1 h+ u
- {
( U$ M, k, v# z1 w7 ` - tmp = 4000;
0 A: f. ^7 @0 V n3 k - }
2 g t6 C5 B* `9 U# h# ^ -
* y. B" q4 b2 C -
% D+ h0 U% g8 k/ J9 K$ Z6 l - return (u16)(100 - (tmp / 40));" j+ H6 C$ J, r( Z$ g3 E) w
- }
复制代码 % V2 F$ g; o" U S* l
main.c文件* G% g0 k1 x! u. e/ A
$ _% W; ~: g* N# J) F b9 w% K1 J- #include "sys.h"1 A% ^/ |* g* V$ M+ b; Q2 \) X- n# b
- #include "delay.h", q, B5 u7 ^; i$ H
- #include "usart.h"
6 z+ C3 Y: S1 e0 G - #include "led.h"
7 r/ i5 |' k6 L$ r3 B2 t3 j - #include "beep.h"
. b' ?; W, ?7 D# \8 j6 o; w - #include "key.h"
9 F/ e% F$ E+ A% L: | - #include "usmart.h"8 p/ x! i% D# l% U
- #include "lcd.h"3 A) h& S& w* N2 t3 M8 I+ u9 v; o# D) \5 s
- #include "rtc.h"# E% ]5 y3 [4 u$ }' M2 [
- #include "rng.h" t+ E( G+ |0 E4 M" G
- #include "key.h"
9 u7 V: G% n0 ~* ~; a - #include "wkup.h"8 v; _3 f) {0 m2 |) X6 I
- #include "adc.h": T0 F% {* D6 x* G
" i/ q b# X. N! t" v- int main(void) m$ C5 e5 O) P0 P
- { 9 s) T; r/ W3 f5 R5 Y7 \, X
- //u16 value = 0;
+ x& g" t; [2 h$ q2 P5 f6 U/ M% c -
2 O0 W9 l8 B' M9 v; U - u16 temp = 0;
. c3 I4 Q$ _7 W; V8 m - / L; P$ [$ _4 ?( m" Z0 B
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2' S) o; t$ \" i
- 1 q8 T# d- M. ?7 o2 ~+ X8 v
- delay_init(168);
0 H# t: G/ D: f4 y" x( p6 | -
) z2 l m. x/ D: s' w - uart_init(115200);1 x3 S$ k5 V" j
- % }8 Y/ a ?' k5 y5 Y- Q& |7 e3 K
- //usmart_dev.init(84);
) m4 c5 b& [$ D" |& @ - - S9 y2 {$ P0 J: d: T$ A$ `1 R
-
6 {! v- [6 R, k+ P: v) u( b! m - LED_Init();- r! ?; p9 ^/ C: z+ a5 x
-
" Y3 j$ \0 ~- `5 } -
e$ T! @9 A6 `3 v - LCD_Init();, @2 l) o, G# g# ~6 g H4 _
- " t: U& Z1 r7 c9 Q+ n
- ADC3_Init();
4 ~( y4 ?7 j# m) w. ] - - {- E7 s8 Q" V8 f: }1 X5 ?( M2 m
-
# M4 H( T# u" ?! u - POINT_COLOR = RED;7 x1 X. \6 S# s! H7 H' x
- * A7 K- j( ^/ S
- LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");
! Z9 j7 B4 g% S2 T - LCD_ShowString(30,70,200,16,16,"LSENS TEST");
# l$ x$ e1 e% B& C0 e: ?0 d - LCD_ShowString(30,90,200,16,16,"ATOM@tom");% L8 r c' I1 Y, n$ U) S- ~
- LCD_ShowString(30,110,200,16,16,"2020/09/15");
- {2 B7 Z) V$ D$ _ - % `, Z6 ]+ m- s% r* C/ ?/ p
- //设置字体为蓝色; H- z1 M7 y3 N5 G
- POINT_COLOR = BLUE; * L/ Z5 M! x/ d9 _: V
- LCD_ShowString(30,140,200,16,16,"LSENS VAL:"); * ]# x! _0 a @, E% J. f- c* i" y
- " s) A# o) b+ k8 J' f5 D8 _
- while(1)& e5 Y) C: |4 t
- {
4 t! J4 m9 u( A6 ^& }& f! ] - //得到温度值
" z" o' u! S+ G0 p - temp = Get_Adc3_Average(ADC_Channel_5, 10);, H- G% O) Y+ `8 A
-
' @ Q/ ?( _0 v/ v - " `/ v& T2 Q& U' t' }( T. y
- LCD_ShowxNum(30+10*8,130,temp,3,16,0);//显示ADC的值! W, |) f2 {/ f5 ?! l/ W7 L
- + k2 ~8 ?4 n, @9 {: B/ \3 S4 i1 ~
- printf("Light: %d\r\n", temp);
$ G! V4 b( ^/ M& X8 ]. Z: L. ^ -
# l: V0 o* l( m, ~, c - LED1 = !LED1;9 ]' d8 V! D+ z! Y- I) C8 z/ D- u
- 5 h# h* r3 \. a5 G: I, O' V' @+ m
- delay_ms(250);
) Z( r+ Y( C i; Y - }( v: t8 t4 b( e7 G
- }, \2 P4 h' T2 X2 C, M- `
复制代码
, o* r1 q6 X( v3 |( M* {04. 结果验证
: M) I2 j- m$ D伴随 DS0 的不停闪烁,提示程序在运行。此时,我们可以通过给 LS1 不同的光照强度,来观察 LSENS_VAL 值的变化,光照越强,该值越大,光照越弱,该值越小。
. {2 G, {6 e; W7 V) r E% N' W! t: J
5 E' c8 v2 u7 M' n3 y3 D
|