01. 光敏传感器简介% A ?- X3 n. x( Q& L* Y
光敏传感器是最常见的传感器之一,它的种类繁多,主要有:光电管、光电倍增管、光敏电阻、光敏三极管、太阳能电池、红外线传感器、紫外线传感器、光纤式光电传感器、色彩传感器、CCD 和 CMOS 图像传感器等。光传感器是目前产量最多、应用最广的传感器之一,它在自动控制和非电量电测技术中占有非常重要的地位。
( G% |% S% j: u' s+ b0 I9 `5 P8 h. B2 s0 n$ l, C; E
光敏传感器是利用光敏元件将光信号转换为电信号的传感器,它的敏感波长在可见光波长附近,包括红外线波长和紫外线波长。光传感器不只局限于对光的探测,它还可以作为探测元件组成其他传感器,对许多非电量进行检测,只要将这些非电量转换为光信号的变化即可。
- z# S4 z( i% k& K9 m% M
0 @- E7 P: O/ d# q) `探索者 STM32F4 开发板板载了一个光敏二极管(光敏电阻),作为光敏传感器,它对光的变化非常敏感。光敏二极管也叫光电二极管。光敏二极管与半导体二极管在结构上是类似的,其管芯是一个具有光敏特征的 PN 结,具有单向导电性,因此工作时需加上反向电压。无光照时,有很小的饱和反向漏电流,即暗电流,此时光敏二极管截止。当受到光照时,饱和反向漏电流大大增加,形成光电流,它随入射光强度的变化而变化。当光线照射 PN 结时,可以使 PN 结中产生电子一空穴对,使少数载流子的密度增加。这些载流子在反向电压下漂移,使反向电流增加。因此可以利用光照强弱来改变电路中的电流。
" A. w/ B6 ~7 P2 \$ O
. `+ n% i/ o% t% a' f6 B- K9 R利用这个电流变化,我们串接一个电阻,就可以转换成电压的变化,从而通过 ADC 读取电压值,判断外部光线的强弱。
$ F8 z( n$ n5 ^) M2 ^6 ]; X1 p3 h" H* n% Z
02. 硬件模块
/ B& U' k, C( ^9 J* d! v用到的硬件资源有:. S! o4 }$ ]3 ?" e8 u# C
1) 指示灯 DS0
5 d( S$ @9 Z, k- r; K' y2) TFTLCD 模块: `! V, C$ `- b' Q& h4 p5 ?
3) ADC1 F+ ^! X3 I. Y4 A
4) 光敏传感器6 w; o. k0 m% _9 n8 t& x( W
" G+ D! t+ r$ ?. {, {0 `# ~
7 c& ]' v( u, V+ C& M" g2 X1 |
: ?/ n8 ]( q+ e. C% b; D( \
LS1 是光敏二极管(实物在开发板摄像头接口右侧),R58 为其提供反向电压,当环境光线变化时,LS1 两端的电压也会随之改变,从而通过 ADC3_IN5 通道,读取LIGHT_SENSOR(PF7)上面的电压,即可得到环境光线的强弱。光线越强,电压越低,光线越暗,电压越高。. T% j( _2 `( B5 x8 \, y8 f, z
% `+ A c8 k# o& ^
03. 程序设计) ~) x2 l/ W2 C
adc.h文件$ L* L/ y2 |& _7 N
: T% D" s1 t5 Y
- //-----------------------------------
6 Y( J9 K. ^' T: Q9 p - //ADC3通道初始化- s9 }% w; @3 k6 a- s. M8 S" Q' @
- void ADC3_Init(void);
! I, F# F; w3 _, Q - //获取ADC3某个通道的值
) ^0 `0 x7 K5 d" j ^7 h - u16 Get_Adc3(u8 ch);
! J$ M! F( q' a( a7 M! d& j - //获取某个通道给定次数采样的平均值# ~9 ?. Y# n4 [1 J# w
- u16 Get_Adc3_Average(u8 ch, u8 times);
复制代码 ; j0 F+ I* I o3 f
adc.c文件
2 `4 c: S' s8 e0 f1 q2 o/ `: W7 R, Y9 S
- //-------------------------ADC3------------------------
9 U2 G: T9 ?6 \( g. o' I+ _8 u - //ADC3通道初始化
M/ b; c2 n2 l. [2 }0 ` - void ADC3_Init(void)
3 M6 T' S5 Z' r7 n- ?9 b) j - {8 A' j% S4 ]3 s( @* }
- GPIO_InitTypeDef GPIO_InitStructure;( L4 Z4 Z5 W3 [" y, ]( O8 l
- ADC_CommonInitTypeDef ADC_CommonInitStructure;
$ N- P. G& ?, e" Q - ADC_InitTypeDef ADC_InitStructure; |; N" N4 j& ?9 `3 i
- + K' @2 i1 x( a: f7 O( M4 B
- //开启GPIO时钟 PA5
( x7 S+ _% X1 o# \ - RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE); 0 d1 ] X' k4 ^# z8 y
-
: D+ d0 y6 t! V5 b) w" A4 t - //开启ADC1时钟( I/ f" M& s. j" Q4 F
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);
9 O" \/ {/ ^' `* a) x" W - " C2 C1 J5 g: j* U' u5 z- I
- //GPIO初始化 初始化为模拟功能7 u& h" [) n' i
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; g& _& [3 V5 O% ~
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
9 A2 s/ m4 l1 m1 e4 O0 u7 I. g6 g9 m - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;- Y; @/ o1 v* ]! l
- GPIO_Init(GPIOF, &GPIO_InitStructure);' P4 O0 o) F3 x; z
- 5 `. O6 r- T8 g3 G/ g N
- RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC3,ENABLE); //ADC1复位4 t, |( m8 T: I$ r! z5 K6 X
- RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC3,DISABLE); //复位结束
$ ^1 l* p& d9 F9 O# ]5 |, a. P - ; D+ i J" {) n- f& K5 h
-
' k- Y# j- P/ k2 b. d% V ~6 W - //初始化ADC_CCR寄存器$ R: `6 H5 o: b7 h
; P! o7 ~# s4 A' S+ X; d/ z- ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;- y4 j9 e# R3 S/ V
- ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;& w/ s6 i8 B& b. u! U
- ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;5 X( V0 E3 E2 q5 |, A8 \
- ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;+ H. p3 k, r9 H- ?) \( U
- ADC_CommonInit(&ADC_CommonInitStructure);
- V& s! u; P6 q - , K( M9 F: i# d+ R
( V' c6 s( f7 \0 n" l6 l+ h, A- //初始化ADC1
! C9 ?' u: H ] - ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;4 r: y8 O$ y3 a2 t* j
- ADC_InitStructure.ADC_ScanConvMode = DISABLE;
9 ]5 n2 g" v" T8 t) O# C% p - ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;& W9 m3 K% z* J, @; i
- ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;: T" k+ d+ O" E1 U8 ]$ N" I B1 z
- ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
: T) `8 `, ]0 k. M3 A) s( \; V& L - ADC_InitStructure.ADC_NbrOfConversion = 1;- H: H: d' m& ^
% t* T3 ?$ H; G4 [9 x" I- ADC_Init(ADC3, &ADC_InitStructure);
$ h& j3 P3 G& }, j) [ ^7 P/ _! C - ' p1 G* m, x* W) r
4 B( ~0 J% o6 h, T- //设置ADC规则组通道 一个序列 采样时间
' K# N$ I7 C! t- @+ [+ Z, m; ^4 q, f - //ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 1, ADC_SampleTime_480Cycles);. K! G# b |5 |2 R1 }0 A
, A3 ^. O4 F: w! T
" D2 K s2 c4 b% L! h2 v- //使能ADC5 @1 n2 @$ T. f, ~
- ADC_Cmd(ADC3, ENABLE);
1 v6 v+ k3 U3 d" `& C1 s - # `% |6 ?& g6 B$ }7 m: W
- } T2 I# u# Z5 i% ], z" }
3 n' Y& c3 e; V+ {7 ]; c6 p3 s0 [- //获取ADC3某个通道的值8 N1 ^* p8 j# P) e
- u16 Get_Adc3(u8 ch)
: L/ `0 E) C; S2 w: M* u - {
% W/ g7 X0 g: m/ N+ {- W. e3 o - //设置ADC规则组通道 一个序列 采样时间 R6 W' A2 _0 F) S3 z! U' t
- ADC_RegularChannelConfig(ADC3, ch, 1, ADC_SampleTime_480Cycles);
, D- ^5 Q2 a, D, r -
8 N% L7 h* O" h- a: z6 u - //开启ADC3的软件转换启动功能
5 s u. B1 ]% U7 S - ADC_SoftwareStartConv(ADC3);: K i m# m- G* R
- ' k, H+ `$ u; Y2 ~
- //等待转换结束
1 D- F% X* J, y9 `: u7 m C - while(ADC_GetFlagStatus(ADC3, ADC_FLAG_EOC) == RESET)2 k" N& q* P2 o" c9 h5 s
- ;
$ Y% t* J& S6 W/ W& t0 p
2 l" `3 b3 c" n& u' i2 t- //读取ADC的值
" g2 o! c/ b9 r, } - return ADC_GetConversionValue(ADC3);
2 }7 V! o# R; v) S. G2 h
5 t; n: g8 \1 a0 s( ], R- J- E9 J- }
; V9 Y& M8 |7 l+ e - ! L! ^# ]( r+ {% ~4 \8 ]+ |5 [
- //获取某个通道给定次数采样的平均值' X& I7 z: N4 a$ l) B5 E
- u16 Get_Adc3_Average(u8 ch, u8 times)9 j5 q( ]; P- t/ X8 `' C x: n2 r
- {2 _8 Z" |0 X! b8 T+ R N, A
- u32 tmp = 0;- n; ]8 }" P2 \! @3 f
- u8 i = 0;
) }+ d7 L& N" N) c -
3 v' s c H( H" Z3 y" @ - for (i = 0; i < times; i++)) b _5 i( s6 e4 W
- {
6 @; t! Y# D' ^0 m0 m# `7 E - tmp += Get_Adc3(ch);4 `. {/ A5 u' W V) p
- delay_ms(5);
- \3 J: x o5 B3 ~' R* q+ g -
8 f: E8 ?" f. E; E# G5 I4 a - }
1 o; o: @) u1 j1 ? -
* n. Y6 r1 A$ w; k1 I; _ - //得到平均值0 h6 S. x/ Z' w( M
- tmp /= times;3 Y* s; C# P" @) {; {% u
-
e) a% X. d& C8 f' I - if (tmp > 4000)# ]9 ]+ M/ |$ ~, g1 J- _* R1 a
- {
' l( ?3 v) |/ L- {" b - tmp = 4000;
6 U5 Y. H' O% ]' T5 m/ A% s/ e- ^ - }
" j+ f6 v0 l4 }4 t; l -
5 K1 t9 Q4 q# h- \ -
& q( ~" [: M6 b: A$ w8 k$ X - return (u16)(100 - (tmp / 40));
0 L8 S# t; Q* B5 d - }
复制代码 % N% I+ ]9 U2 L7 a1 L- f+ s
main.c文件
2 N1 y6 {3 e6 H) J" _. ~5 U8 z9 {* R$ j. f) W8 k( P7 X& X
- #include "sys.h"
2 q/ R% o8 `6 n3 _# }' i - #include "delay.h"4 I& T2 e- Y, G9 s
- #include "usart.h"
/ K! Q& P% d. Y2 Z# x. ]! p; {8 P1 a( J - #include "led.h"
4 a# J/ y8 }+ {! T% v - #include "beep.h"" p" Z" t$ c" W" p+ o/ S
- #include "key.h"
. s, H# @' h2 w, e - #include "usmart.h"
) E. \! Q/ m! A# v- y - #include "lcd.h"' d6 P |& g9 U' }8 t
- #include "rtc.h", f$ z+ N" I+ |! {
- #include "rng.h"
, O0 q1 n( [9 S1 f/ ]: H+ C4 h - #include "key.h"- Q( z' ^, h1 s: \
- #include "wkup.h"
* I/ a& Y7 h( i& f - #include "adc.h"
9 {" R7 X- I3 b/ t; g- |
3 F1 n- S1 {3 S( c- int main(void)
q$ @+ R: n5 _# B& M4 ~4 D - { % y0 y3 F0 A/ h5 Q* l% Y4 P
- //u16 value = 0;
, [- L K: [. `/ h5 Y -
! u& Q; Z9 \! q+ |. ]4 M. i - u16 temp = 0;, _: ~) k$ _* L
5 ~5 c" C, B7 C1 [: l. b$ B- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
0 D. a( }/ Y( \6 F -
6 S' n) N. p6 b( u - delay_init(168);
' N2 f" |5 {3 o! A4 \) _ -
; Z9 }$ C5 S' B6 W - uart_init(115200);
E) I" w3 n, `# z; M, i7 ]4 O -
! S" y7 M( D$ [( |, ]/ J, V - //usmart_dev.init(84);7 p/ F2 }2 W7 k
- 6 q1 o3 C0 m6 U7 S
- 6 k2 [3 ~- G$ \" [- J1 a
- LED_Init();
. y i9 ?8 o4 y+ v9 ?% f: \ -
& s% P4 z& V& l! n, \ - + M9 q) n m, D1 f$ ?( ^9 q8 ]3 R
- LCD_Init();
+ Z& g8 L6 L' g% i" H
/ @. |( ^) [$ B2 @/ C7 G% @- ADC3_Init();
1 `9 o; s7 O/ ~1 q- I' P - 0 R( S4 ^" L2 W& c5 l- n
-
6 z& E5 ] ?( V( J$ A# C - POINT_COLOR = RED;
( k! l, U! L4 j- B$ Y X - T' n" A) C4 c( a% O
- LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");
1 z& E" Z* u5 T; [5 W; j5 l - LCD_ShowString(30,70,200,16,16,"LSENS TEST"); . s3 U* G6 I) v2 ^6 w- A
- LCD_ShowString(30,90,200,16,16,"ATOM@tom");# q/ C7 [- y$ z: D; N8 `
- LCD_ShowString(30,110,200,16,16,"2020/09/15"); * X8 ?! z z0 x0 Y' y H" l$ m
-
# r3 p9 Q6 Z* K1 Y4 K" o. n - //设置字体为蓝色
6 _- u8 r( e1 L7 M; J( _# Z - POINT_COLOR = BLUE;
9 ]( R$ j3 V/ f, \" I - LCD_ShowString(30,140,200,16,16,"LSENS VAL:");
6 F) ^) P5 z. e5 h% _1 E3 q -
' ~% n, [& v/ M4 B f- o - while(1)
- @3 q% W9 g* G9 c& b/ L m2 E" y - {2 f- T. J- T: O& U. y0 t4 X: \; ~
- //得到温度值
: U0 p3 Y U! E' c! p% B' e3 A% m - temp = Get_Adc3_Average(ADC_Channel_5, 10);
6 a, n3 d% o- U" t - ( i) c; k9 e- A( K4 f3 f
- - \- ?9 w1 J) |
- LCD_ShowxNum(30+10*8,130,temp,3,16,0);//显示ADC的值
! K' ^: A8 t0 o: v4 Z - ' t0 W$ M% V2 D9 p F$ Q
- printf("Light: %d\r\n", temp);- W0 o" B6 a: _
- ' U3 \( a5 d/ y1 k0 L
- LED1 = !LED1;
+ L& p- T4 k4 a: Y - * Z. Q/ S! K. }! ]
- delay_ms(250);
6 ]/ R8 N7 O2 J: |$ z - }
4 x: U" V- I' p, B1 o+ k8 r6 s9 e - }
复制代码
1 V6 r; `: r' a) ^1 s04. 结果验证7 u U9 O5 ^& P
伴随 DS0 的不停闪烁,提示程序在运行。此时,我们可以通过给 LS1 不同的光照强度,来观察 LSENS_VAL 值的变化,光照越强,该值越大,光照越弱,该值越小。
; |6 n7 J( c; u" h9 A' [7 ^, t) h& |& L& z6 i/ \
5 Q# Q& X( M7 W
|