stm32f429开发指南寄存器_【正点原子FPGA连载】第二十九章 环境光传感器实验-摘自【正点原子】开拓者 FPGA 开发指南...

本篇博客详细介绍了如何使用正点原子开拓者FPGA开发板进行AP3216C环境光和距离传感器实验。实验中,通过I2C协议与AP3216C通信,读取并显示环境光强度和物体距离。实验涉及硬件设计、程序设计,包括I2C驱动、数据采集模块和LED显示模块的实现。通过数码管显示光照强度,LED灯指示距离远近。
摘要由CSDN通过智能技术生成

1)实验平台:正点原子开拓者FPGA 开发板

2)摘自《开拓者FPGA开发指南》关注官方微信号公众号,获取更多资料:正点原子

3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-13912-1-1.html

3f6f051e9a7a9ca9a5da785f96d9e9fb.png

第二十九章 环境光传感器实验

AP3216C是一个能够测量环境光强度和距离的整合型光感测距传感器。因其功耗低、控制

简单、封装小而广泛应用于智能手机、电容式触摸屏、数码相机等领域。例如应用于智能手机

上面检测环境光强度,用来实现自动背光控制,以及接近开关控制(听筒靠近耳朵,手机自动

灭屏功能)。本章我们将使用FPGA开发板上的AP3216C器件实现环境光照强度和距离的测量。

本章包括以下几个部分:

29.1 AP3216C简介

29.2 实验任务

29.3 硬件设计

29.4 程序设计

29.5 下载验证

AP3216C简介

AP3216C是敦南科技推出的一款整合型传感器,它内部集成了:数字环境光传感器

(Ambilent Light Sensor,ALS)、距离传感器(Proximity Sensor,PS)和一个红外LED

(Infrared Radiation LED,IR LED)。其中,距离传感器具有10位的分辨率,环境光传感器

具有16位的分辨率。AP3216C能够支持多种工作模式,我们使用的是ALS+PS+IR模式,在该模式

下AP3216C连续采集环境光照强度和距离值。

AP3216C 内部功能模块的框图如图 29.1.1所示:

9a69903cef5c47c540694ab718e64f01.png

图 29.1.1 AP3216C功能框图

当有物体接近时,图 29.1.1中的红外发光二极管(IR_LED)发出的红外线碰撞到物体后反

射到红外光电二极管(PS)上,光电二极管将光信号转换成电流信号,并通过模数转换器(ADC)

将其转换成数字信号并存储在寄存器中。

物体离的越近,反射到PS上的红外光强度越高,模数转换后得到的数据就越大,从而实现

感应物体距离远近的功能。与此类似,可见光光电二极管(ALS)感应环境光强度,并将其转

化成数字信号,从而实现环境光强度的检测。

AP3216C内部有一些寄存器,这些寄存器可以控制AP3216C的工作模式、中断方式以及采集

数据等。这里我们仅介绍本章中需要用到的一些寄存器,其他寄存器的描述和说明,请大家参

考AP3216C的数据手册。

本章用到的AP3216C寄存器如表 29.1.1所示:

414770b6f6386d5a0d96b9e02a42dc20.png

表 29.1.1 AP3216C 相关寄存器及其说明

上表中,地址0X00对应的是一个系统模式控制寄存器,我们在初始化的时候将它配置为011,

开启ALS+PS+IR检测功能。剩下的6个寄存器为数据寄存器,分别寄存AP3216C采集到的红外光

强度、环境光强度、以及距离值。

AP3216C采用I2C总线协议与控制器(FPGA)进行通信,因此我们通过I2C协议实现对AP3216C

相关寄存器的配置和采集数据的读取。

AP3216C写寄存器的时序图如图 29.1.2所示:

8164e3b29e1188b06e218cfdb38adec4.png

图 29.1.2 AP3216C 写寄存器时序

图 29.1.2中,先发送AP3216C的器件地址(0X1E)和读写控制位,最低位W=0表示写数据;

随后发送8位寄存器地址,最后发送写入寄存器中的配置指令。其中:S,表示IIC起始信号;

W,表示读/写标志位(W=0 表示写,W=1 表示读);A,表示应答信号;P,表示IIC停止信号。

有关I2C总线协议更详细的介绍请大家参考“EEPROM读写实验”。

AP3216C的读寄存器时序如图 29.1.3所示:

e8c854ee40c9898baccaaa90619d1f50.png

图 29.1.3 AP3216C 读寄存器时序

图 29.1.3中,同样是先发送7位器件地址+写操作标志,然后再发送寄存器地址;随后,

重新发送起始信号(Sr),再次发送7位地址+读操作标志,最后读取寄存器值。其中:Sr,表

示重新发送IIC起始信号;N,表示不对AP3216C进行应答。

实验任务

本节实验任务是使用开拓者FPGA开发板上的AP3216C器件测量环境光强度和物体距离,并

在数码管上显示环境光强度,用4个led灯的亮灭来指示物体距离的远近。

硬件设计

开拓者开发板上AP3216C接口部分的原理图如图 29.3.1所示。

a2ea4af49e16293e5d9ebf401796fb9f.png

图 29.3.1 AP3216C接口原理图

AP3216C作为I2C接口的从器件与EEPROM等模块统一挂接在开拓者开发板上的IIC总线上。

LEDA是器件内部红外发光二极管(IR_LED)的阳极,LEDC为阴极,一般连接到LED的驱动输出脚

LDR。

本实验中,各端口信号的管脚分配如下表所示:

表 29.3.1 AP3216C环境光—距离传感器实验管脚分配

1cc8ec6aa9713822e254a984c68b1156.png

1b31ad6fc90e044bfc176d2adeba3f26.png

程序设计

根据实验任务,我们可以大致规划出系统的控制流程:FPGA首先通过I2C总线读取AP3216C

采集的环境光及距离数据,然后将读到的距离值用于控制4个led灯的亮灭,以指示物体的远近;

并将环境光光照强度用数码管显示出来。由此画出系统的功能框图如下所示:

616d51c443388eef3dff8fd983d7fc03.png

图 29.4.1 AP3216C环境光—距离测量实验系统框图

程序中各模块端口及信号连接如图 29.4.2所示:

由系统框图可知,FPGA部分包括五个模块,顶层模块(ap3216c_top)、IIC驱动模块

(i2c_dri)、AP3216C数据采集模块(ap3216c)、LED显示模块(led_disp)以及数码管显示

模块(seg_led)。各模块功能如下:

b714782677e68dc704b6029116894e3d.png

图 29.4.2 顶层模块原理图

顶层模块(ap3216c_top):顶层模块例化了IIC驱动模块(i2c_dri)、AP3216C数据采集

模块(ap3216c)、LED显示模块(led_disp)以及数码管显示模块(seg_led),完成各模块之

间的数据交互。AP3216C数据采集模块通过IIC驱动模块与AP3216C器件进行通信,并将采集到

的环境光强度送入数码管显示模块显示,采集到的距离值送入LED显示模块显示。

IIC驱动模块(i2c_dri):由于AP3216C采用I2C协议与FPGA进行通信,所以需用IIC驱动

模块实现FPGA与AP3216C信号的交互。

AP3216C数据采集模块(ap3216c)通过调用IIC驱动模块(i2c_dri)来实现对AP3216C采

集数据的读取。将读到的环境光照强度数值als_data传递给数码管模块(seg_led)显示,将

读到的距离值ps_data传递给led显示模块(led_disp),用于控制4个led灯的亮灭以指示物体

的远近。

LED显示模块(led_disp):根据距离值的远近点亮LED灯的个数,距离越近,LED亮的个

数越多,距离越远,LED亮的个数越少。

数码管显示模块(seg_led):数码管显示模块显示采集到的环境光强度值。

顶层模块的代码如下:

1 module ap3216c_top(

2 //global clock

3 input sys_clk , // 系统时钟

4 input sys_rst_n , // 系统复位

5

6 //ap3216c interface

7 output ap_scl , // i2c时钟线

8 inout ap_sda , // i2c数据线

9

10 //user interface

11 output [3:0] led , // led灯接口

12 output [5:0] sel , // 数码管位选

13 output [7:0] seg_led // 数码管段选

14 );

15

16 //parameter define

17 parameter SLAVE_ADDR = 7'h1e ; // 器件地址

18 parameter BIT_CTRL = 1'b0 ; // 字地址位控制参数(16b/8b)

19 parameter CLK_FREQ = 26'd50_000_000; // i2c_dri模块的驱动时钟频率(CLK_FREQ)

20 parameter I2C_FREQ = 18'd250_000 ; // I2C的SCL时钟频率

21

22 //wire define

23 wire clk ; // I2C操作时钟

24 wire i2c_exec ; // i2c触发控制

25 wire [15:0] i2c_addr ; // i2c操作地址

26 wire [ 7:0] i2c_data_w; // i2c写入的数据

27 wire i2c_done ; // i2c操作结束标志

28 wire i2c_rh_wl ; // i2c读写控制

29 wire [ 7:0] i2c_data_r; // i2c读出的数据

30 wire [15:0] als_data ; // ALS的数据

31 wire [ 9:0] ps_data ; // PS的数据

32

33 //*****************************************************

34 //** main code

35 //*****************************************************

36

37 //例化i2c_dri,调用IIC协议

38 i2c_dri #(

39 .SLAVE_ADDR (SLAVE_ADDR), // slave address从机地址,放此处方便参数传递

40 .CLK_FREQ (CLK_FREQ ), // i2c_dri模块的驱动时钟频率(CLK_FREQ)

41 .I2C_FREQ (I2C_FREQ ) // I2C的SCL时钟频率

42 ) u_i2c_dri(

43 //global clock

44 .clk (sys_clk ), // i2c_dri模块的驱动时钟(CLK_FREQ)

45 .rst_n (sys_rst_n ), // 复位信号

46 //i2c interface

47 .i2c_exec (i2c_exec ), // I2C触发执行信号

48 .bit_ctrl (BIT_CTRL ), // 器件地址位控制(16b/8b)

49 .i2c_rh_wl (i2c_rh_wl ), // I2C读写控制信号

50 .i2c_addr (i2c_addr ), // I2C器件内地址

51 .i2c_data_w (i2c_data_w), // I2C要写的数据

52 .i2c_data_r (i2c_data_r), // I2C读出的数据

53 .i2c_done (i2c_done ), // I 2C一次操作完成

54 .scl (ap_scl ), // I2C的SCL时钟信号

55 .sda (ap_sda ), // I2C的SDA信号

56 //user interface

57 .dri_clk (clk ) // I2C操作时钟

58 );

59

60 //例化AP3216C测量模块

61 ap3216c u_ap3216c(

62 //system clock

63 .clk (clk ), // 时钟信号

64 .rst_n (sys_rst_n ), // 复位信号

65 //i2c interface

66 .i2c_rh_wl (i2c_rh_wl ), // I2C读写控制信号

67 .i2c_exec (i2c_exec ), // I2C触发执行信号

68 .i2c_addr (i2c_addr ), // I2C器件内地址

69 .i2c_data_w (i2c_data_w), // I2C要写的数据

70 .i2c_data_r (i2c_data_r), // I2C读出的数据

71 .i2c_done (i2c_done ), // I2C一次操作完成

72 //user interface

73 .als_data (als_data ), // ALS的数据

74 .ps_data (ps_data ) // PS的数据

75 );

76

77 //例化动态数码管显示模块

78 seg_led u_seg_led(

79 //module clock

80 .clk (sys_clk ), // 时钟信号

81 .rst_n (sys_rst_n), // 复位信号

82 //seg_led interface

83 .sel (sel ), // 位选

84 .seg_led (seg_led ), // 段选

85 //user interface

86 .data (als_data ), // 显示的数值

87 .point (6'd0 ), // 小数点具体显示的位置,从高到低,高电平有效

88 .en (1'd1 ), // 数码管使能信号

89 .sign (1'b0 ) // 符号位(高电平显示“-”号)

90 );

91

92 //例化LED模块

93 led_disp u_led_disp(

94 //system clock

95 .clk (clk ), // 时钟信号

96 .rst_n (sys_rst_n), // 复位信号

97 //led interface

98 .led (led ), // led灯接口

99 //user interface

100 .data (ps_data ) // PS的数据

101 );

102

103 endmodule

顶层模块中主要完成对其余模块的例化,其中I2C驱动模块(i2c_dri)程序与“EEPROM读

写实验”章节中的IIC驱动模块(i2c_dri)程序完全相同。有关IIC驱动模块的详细介绍请大

家参考“EEPROM读写实验”。

为了可以同时采集到环境光照强度值和距离值,我们需要配置系统寄存器(地址0x00)为

011,使AP3216C工作在PS和ALS模式下,此时AP3216C交替采集距离值PS和环境光照强度ALS。

2d5400b2134afc765e610862105dd972.png

图 29.4.3 采集时序图

由图 29.4.3可以看到,I2C配置完系统寄存器后采集距离值PS需要的时间为12.5ms,采集

环境光照强度ALS需要的时间为100ms。

AP3216C数据采集模块的代码如下所示:

1 module ap3216c(

2 //system clock

3 input clk , // 时钟信号

4 input rst_n , // 复位信号

5

6 //i2c interface

7 output reg i2c_rh_wl , // I2C读写控制信号

8 output reg i2c_exec , // I2C触发执行信号

9 output reg [15:0] i2c_addr , // I2C器件内地址

10 output reg [ 7:0] i2c_data_w , // I2C要写的数据

11 input [ 7:0] i2c_data_r , // I2C读出的数据

12 input i2c_done , // I2C一次操作完成

13

14 //user interface

15 output reg [15:0] als_data , // ALS的数据

16 output reg [ 9:0] ps_data // PS的数据

17 );

18

19 //parameter define

20 parameter TIME_PS = 14'd12_500 ; // PS转换时间为12.5ms(clk = 1MHz)

21 parameter TIME_ALS = 17'd100_000 ; // ALS转换时间为100ms(clk = 1MHz)

22 parameter TIME_REST = 8'd2 ; // 停止后重新开始的时间间隔控制

23

24 //reg define

25 reg [ 3:0] flow_cnt ; // 状态流控制

26 reg [18:0] wait_cnt ; // 计数等待

27 reg [15:0] als_data_t ; // ALS的临时数据

28 reg als_done ; // 环境光照强度值采集完成信号

29 reg [ 9:0] ps_data_t ; // PS的临时数据

30 reg ir_of ; // 溢出标志(判断ps_data是否有效)

31 reg obj ; // 物体状态标志(0远离1靠近)

32

33 //*****************************************************

34 //** main code

35 //*****************************************************

36

37 //配置AP3216C并读取数据

38 always @(posedge clk or negedge rst_n) begin

39 if(!rst_n) begin

40 i2c_exec <= 1'b0;

41 i2c_addr <= 8'd0;

42 i2c_rh_wl <= 1'b0;

43 i2c_data_w <= 8'h0;

44 flow_cnt <= 4'd0;

45 wait_cnt <= 18'd0;

46 ps_data <= 10'd0;

47 ps_data_t <= 10'd0;

48 ir_of <= 1'b0;

49 obj <= 1'b0;

50 als_done <= 1'b0;

51 als_data_t <= 16'd0;

52 end

53 else begin

54 i2c_exec <= 1'b0;

55 case(flow_cnt)

56 //初始化AP3216C

57 4'd0: begin

58 if(wait_cnt == 18'd100) begin

59 wait_cnt <= 18'd0;

60 flow_cnt <= flow_cnt + 1'b1;

61 end

62 else

63 wait_cnt <= wait_cnt +1'b1;

64 end

65 //配置AP3216C的功能模式

66 4'd1: begin

67 i2c_exec <= 1'b1 ;

68 i2c_rh_wl <= 1'b0 ;

69 i2c_addr <= 8'h00; // 配置系统寄存器

70 i2c_data_w <= 8'h03; // 激活ALS+PS+IR 功能

71 flow_cnt <= flow_cnt + 1'b1;

72 end

73 //配置完成

74 4'd2: begin

75 if(i2c_done)

76 flow_cnt <= flow_cnt + 1'b1;

77 end

78 //等待PS转换完成(12.5ms)

79 4'd3: begin

80 if(wait_cnt == TIME_PS) begin

81 wait_cnt <= 18'd0;

82 flow_cnt <= flow_cnt + 1'd1;

83 end

84 else

85 wait_cnt <= wait_cnt + 1'b1;

86 end

87 //预读PS Data Register(0x0E)

88 4'd4: begin

89 i2c_exec <= 1'b1;

90 i2c_rh_wl<= 1'b1;

91 i2c_addr <= 8'h0E;

92 flow_cnt <= flow_cnt + 1'b1;

93 end

94 //读PS Data Register(0x0E)

95 4'd5: begin

96 if(i2c_done) begin

97 flow_cnt <= flow_cnt + 1'b1;

98 ps_data_t[3:0] <= i2c_data_r[3:0];

99 ir_of <= i2c_data_r[6] ;

100 obj <= i2c_data_r[7] ;

101 end

102 end

103 //等待一段时间以进行下一次读写

104 4'd6: begin

105 if(wait_cnt == TIME_REST) begin//TIME_REST

106 wait_cnt <= 18'd0;

107 flow_cnt <= flow_cnt + 1'b1;

108 end

109 else

110 wait_cnt <= wait_cnt +1'b1;

111 end

112 //预读PS Data Register(0x0F)

113 4'd7: begin

114 i2c_exec <= 1'b1;

115 i2c_rh_wl<= 1'b1;

116 i2c_addr <= 8'h0F;

117 flow_cnt <= flow_cnt + 1'b1;

118 end

119 //读PS Data Register(0x0F)

120 4'd8: begin

121 if(i2c_done) begin

122 flow_cnt <= flow_cnt + 1'b1;

123 ps_data_t[9:4] <= i2c_data_r[5:0];

124 ir_of <= i2c_data_r[6] ;

125 obj <= i2c_data_r[7] ;

126 end

127 end

128 //等待ALS转换完成(100ms)

129 4'd9: begin

130 if(wait_cnt == TIME_ALS) begin

131 wait_cnt <= 18'd0;

132 flow_cnt <= flow_cnt + 1'd1;

133 ps_data <= ps_data_t;

134 end

135 else

136 wait_cnt <= wait_cnt + 1'b1;

137 end

138 //预读ALS Data Register(0x0C)

139 4'd10: begin

140 i2c_exec <= 1'b1;

141 i2c_rh_wl<= 1'b1;

142 i2c_addr <= 8'h0C;

143 flow_cnt <= flow_cnt + 1'b1;

144 end

145 //读ALS Data Register(0x0C)

146 4'd11: begin

147 if(i2c_done) begin

148 als_done <= 1'b0;

149 als_data_t[7:0] <= i2c_data_r;

150 flow_cnt <= flow_cnt + 1'b1;

151 end

152 end

153 //等待一段时间以进行下一次读写

154 4'd12: begin

155 if(wait_cnt == TIME_REST) begin

156 wait_cnt <= 18'd0;

157 flow_cnt <= flow_cnt + 1'b1;

158 end

159 else

160 wait_cnt <= wait_cnt +1'b1;

161 end

162 //预读ALS Data Register(0x0D)

163 4'd13: begin

164 i2c_exec <= 1'b1;

165 i2c_rh_wl<= 1'b1;

166 i2c_addr <= 8'h0D;

167 flow_cnt <= flow_cnt + 1'b1;

168 end

169 //读ALS Data Register(0x0D)

170 4'd14: begin

171 if(i2c_done) begin

172 als_done <= 1'b1;

173 als_data_t[15:8] <= i2c_data_r;

174 flow_cnt <= 4'd3; //跳转到状态3重新读取数据

175 end

176 end

177 endcase

178 end

179 end

180

181 //当采集的环境光转换成光照强度(单位:lux)

182 always @ (*) begin

183 if(als_done)

184 als_data <= als_data_t * 35 / 100;

185 end

186

187 endmodule

程序中第98行我们只取了读到的数据的低4位,第123取了读到的数据的低6位。这是因为

PS数据的低4位放在地址为0x0e处的寄存器的低4位,PS数据的高6位放在地址0x0f处的寄存器

的低6位。

程序中第182行开始的always语句是对采集到的als_data转化为环境光照强度值。由

AP3216C器件datasheet可知环境光照强度值Ambient Light (lux) 为:

Ambient Light (lux)= 16 bit ALS ADC data * Resolution

这里的16 bit ALS ADC data即程序中的als_data_t,Resolution 为0.35 lux/count(由

AP3216C的datasheet可知),所以环境光照强度值Ambient Light (lux)= als_data_t * 0.35。

由于0.35为小数,而Verilog HDL不能直接表示小数,所以我们需要进行转化。而0.35=35/100,

所以我们可以将读取到的als_data_t值乘以35然后再除以100得到环境光照强度值als_data。

并把最终得到的环境光照强度值als_data传递给数码管显示,数码管显示模块可参考动态数码

管显示实验。

另外需要注意的是,在程序的第30和第31行我们定义了两个寄存器变量ir_of和obj。ir_of

是溢出标志用来判断ps_data是否有效,obj是物体状态标志:0表示物体远离传感器,1表示物

体靠近传感器。用户可根据这两个数据来对AP3216C传感器应用进行拓展。

图 29.4.4为采集过程中SignalTap抓取的波形图。从图中可以看到I2C写的数值为03h,也

即配置AP3216C工作在ALS+PS+IR模式。当前读到的环境光强度als_data为2164lux,距离值

ps_data为029h。

897cce654ca38c8c1e82e5a22ffd2b33.png

图 29.4.4 SignalTap波形图

led显示模块的代码如下:

1 module led_disp(

2 //system clock

3 input clk , // 时钟信号

4 input rst_n, // 复位信号

5

6 //led interface

7 output reg [3:0] led , // led灯接口

8

9 //user interface

10 input [9:0] data // 数据

11 );

12

13 //*****************************************************

14 //** main code

15 //*****************************************************

16

17 //led灯亮灭个数显示数据大小

18 always @(posedge clk or negedge rst_n) begin

19 if(!rst_n) begin

20 led <= 4'd0;

21 end

22 else if(data < 10'd16)

23 led <= 4'b0001;

24 else if(data < 10'd32)

25 led <= 4'b0011;

26 else if(data < 10'd512)

27 led <= 4'b0111;

28 else

29 led <= 4'b1111;

30 end

31

32 endmodule

led显示模块通过点亮led的个数表示物体距离的远近。程序中的第18行开始的always语

句判断读取的PS数据以控制4个led灯的亮灭,PS数据越小,说明物体距离传感器越远,LED灯

点亮的个数越少。

下载验证

首先我们打开环境光传感器实验工程,在工程所在的路径下打开ap3216c_top/par文件夹,

在里面找到“ap3216c_top.qpf”并双击打开。注意工程所在的路径名只能由字母、数字以及

下划线组成,不能出现中文、空格以及特殊字符等。工程打开后如图 29.5.1所示。

4b78d6ba2c94bd70c9fe94acf061f877.png

图 29.5.1 环境光传感器实验工程

然后将下载器一端连电脑,另一端与开发板上对应端口连接,最后连接电源线并打开电源

开关。

接下来我们下载程序,验证AP3216C的传感器功能。

工程打开后通过点击工具栏中的“Programmer”图标打开下载界面,通过“Add File”按

钮选择ap3216c_top/par/output_files目录下的“ap3216c_top.sof”文件。开发板电源打开

后,在程序下载界面点击“Hardware Setup”,在弹出的对话框中选择当前的硬件连接为“USB-

Blaster[USB-0]”。然后点击“Start”将工程编译完成后得到的sof文件下载到开发板中,如

图 29.5.2所示。

d92e7dad92895a55a9d489df0b3a0981.png

图 29.5.2 程序下载界面

下载完成后观察到开发板上数码管显示的值随着环境光照强度的增强而变大;物体的位置

靠近AP3216C时,led灯亮的个数增加,远离时减少,如图 29.5.3所示,说明环境光传感器实

验程序下载验证成功。

edaf4e0594215a8876e77d8d8dd409ca.png

图 29.5.3 AP3216C实验结果显示

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值