700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 【正点原子FPGA连载】第三十三章环境光传感器实验 -摘自【正点原子】新起点之FPGA开

【正点原子FPGA连载】第三十三章环境光传感器实验 -摘自【正点原子】新起点之FPGA开

时间:2022-12-27 23:48:02

相关推荐

【正点原子FPGA连载】第三十三章环境光传感器实验 -摘自【正点原子】新起点之FPGA开

1)实验平台:正点原子新起点V2开发板

2)平台购买地址:/item.htm?id=609758951113

2)全套实验源码+手册+视频下载地址:/thread-300792-1-1.html

3)对正点原子FPGA感兴趣的同学可以加群讨论:994244016

4)关注正点原子公众号,获取最新资料更新

第三十三章环境光传感器实验

AP3216C是一个能够测量环境光强度和距离的整合型光感测距传感器。因其功耗低、控制简单、封装小而广泛应用于智能手机、电容式触摸屏、数码相机等领域。例如应用于智能手机上面检测环境光强度,用来实现自动背光控制,以及接近开关控制(听筒靠近耳朵,手机自动灭屏功能)。本章我们将使用FPGA开发板上的AP3216C器件实现环境光照强度和距离的测量。

本章包括以下几个部分:

3232.1简介

32.2实验任务

32.3硬件设计

32.4程序设计

32.5下载验证

33.1简介

AP3216C是敦南科技推出的一款整合型传感器,它内部集成了:数字环境光传感器(Ambilent Light Sensor,ALS)、距离传感器(Proximity Sensor,PS)和一个红外LED(Infrared Radiation LED,IR LED)。其中,距离传感器具有10位的分辨率,环境光传感器具有16位的分辨率。AP3216C能够支持多种工作模式,我们使用的是ALS+PS+IR模式,在该模式下AP3216C连续采集环境光照强度和距离值。

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

图 33.1.1 AP3216C功能框图

当有物体接近时,图 33.1.1中的红外发光二极管(IR_LED)发出的红外线碰撞到物体后反射到红外光电二极管(PS)上,光电二极管将光信号转换成电流信号,并通过模数转换器(ADC)将其转换成数字信号并存储在寄存器中。

物体离的越近,反射到PS上的红外光强度越高,模数转换后得到的数据就越大,从而实现感应物体距离远近的功能。与此类似,可见光光电二极管(ALS)感应环境光强度,并将其转化成数字信号,从而实现环境光强度的检测。

AP3216C内部有一些寄存器,这些寄存器可以控制AP3216C的工作模式、中断方式以及采集数据等。这里我们仅介绍本章中需要用到的一些寄存器,其他寄存器的描述和说明,请大家参考AP3216C的数据手册。

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

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

上表中,地址0X00对应的是一个系统模式控制寄存器,我们在初始化的时候将它配置为011,开启ALS+PS+IR检测功能。剩下的6个寄存器为数据寄存器,分别寄存AP3216C采集到的红外光强度、环境光强度、以及距离值。

AP3216C采用I2C总线协议与控制器(FPGA)进行通信,因此我们通过I2C协议实现对AP3216C相关寄存器的配置和采集数据的读取。

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

图 33.1.2 AP3216C 写寄存器时序

图 33.1.2中,先发送AP3216C的器件地址(0X1E)和读写控制位,最低位W=0表示写数据;随后发送8位寄存器地址,最后发送写入寄存器中的配置指令。其中:S,表示IIC起始信号;W,表示读/写标志位(W=0 表示写,W=1 表示读);A,表示应答信号;P,表示IIC停止信号。有关I2C总线协议更详细的介绍请大家参考“EEPROM读写实验”。

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

图 33.1.3 AP3216C 读寄存器时序

图 33.1.3中,同样是先发送7位器件地址+写操作标志,然后再发送寄存器地址;随后,重新发送起始信号(Sr),再次发送7位地址+读操作标志,最后读取寄存器值。其中:Sr,表示重新发送IIC起始信号;N,表示不对AP3216C进行应答。

33.2实验任务

本节实验任务是使用新起点FPGA开发板上的AP3216C器件测量环境光强度和物体距离,并在数码管上显示环境光强度,用4个led灯的亮灭来指示物体距离的远近。

33.3硬件设计

新起点开发板上AP3216C接口部分的原理图如图 33.3.1所示。

图 33.3.1 AP3216C接口原理图

AP3216C作为I2C接口的从器件与EEPROM等模块统一挂接在新起点开发板上的IIC总线上。LEDA是器件内部红外发光二极管(IR_LED)的阳极,LEDC为阴极,一般连接到LED的驱动输出脚LDR。

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

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

对应的TCL约束语句如下:

set_location_assignment PIN_M2 -to sys_clk

set_location_assignment PIN_M1 -to sys_rst_n

set_location_assignment PIN_C8 -to ap_sda

set_location_assignment PIN_D8 -to ap_scl

set_location_assignment PIN_D11 -to led[0]

set_location_assignment PIN_C11 -to led[1]

set_location_assignment PIN_E10 -to led[2]

set_location_assignment PIN_F9 -to led[3]

set_location_assignment PIN_N16 -to sel[0]

set_location_assignment PIN_N15 -to sel[1]

set_location_assignment PIN_P16 -to sel[2]

set_location_assignment PIN_P15 -to sel[3]

set_location_assignment PIN_R16 -to sel[4]

set_location_assignment PIN_T15 -to sel[5]

set_location_assignment PIN_M11 -to seg_led[0]

set_location_assignment PIN_N12 -to seg_led[1]

set_location_assignment PIN_C9 -to seg_led[2]

set_location_assignment PIN_N13 -to seg_led[3]

set_location_assignment PIN_M10 -to seg_led[4]

set_location_assignment PIN_N11 -to seg_led[5]

set_location_assignment PIN_P11 -to seg_led[6]

set_location_assignment PIN_D9 -to seg_led[7]

33.4程序设计

根据实验任务,我们可以大致规划出系统的控制流程:FPGA首先通过I2C总线读取AP3216C采集的环境光及距离数据,然后将读到的距离值用于控制4个led灯的亮灭,以指示物体的远近;并将环境光光照强度用数码管显示出来。由此画出系统的功能框图如下所示:

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

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

由系统框图可知,FPGA部分包括五个模块,顶层模块(ap3216c_top)、IIC驱动模块(i2c_dri)、AP3216C数据采集模块(ap3216c)、LED显示模块(led_disp)以及数码管显示模块(seg_led)。各模块功能如下:

图 33.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 clock3 inputsys_clk , // 系统时钟4 inputsys_rst_n , // 系统复位5 6 //ap3216c interface 7 outputap_scl, // i2c时钟线8 inoutap_sda, // i2c数据线9 10//user interface11output [3:0] led , // led灯接口12output [5:0] sel , // 数码管位选13output [7:0] seg_led // 数码管段选14 );15 16 //parameter define17 parameterSLAVE_ADDR = 7'h1e ; // 器件地址18 parameterBIT_CTRL = 1'b0 ; // 字地址位控制参数(16b/8b)19 parameterCLK_FREQ = 26'd50_000_000; // i2c_dri模块的驱动时钟频率(CLK_FREQ)20 parameterI2C_FREQ = 18'd250_000 ; // I2C的SCL时钟频率21 22 //wire define23 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 code35 //*****************************************************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 clock44.clk (sys_clk ),// i2c_dri模块的驱动时钟(CLK_FREQ)45.rst_n (sys_rst_n ),// 复位信号46//i2c interface47.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.i2c_ack(),// I2C应答标志 0:应答 1:未应答55.scl (ap_scl ),// I2C的SCL时钟信号56.sda (ap_sda ),// I2C的SDA信号57//user interface58.dri_clk(clk )// I2C操作时钟59 );60 61 //例化AP3216C测量模块62 ap3216c u_ap3216c(63//system clock64.clk (clk ),// 时钟信号65.rst_n (sys_rst_n ),// 复位信号66//i2c interface67.i2c_rh_wl (i2c_rh_wl ),// I2C读写控制信号68.i2c_exec (i2c_exec ),// I2C触发执行信号69.i2c_addr (i2c_addr ),// I2C器件内地址70.i2c_data_w (i2c_data_w),// I2C要写的数据71.i2c_data_r (i2c_data_r),// I2C读出的数据72.i2c_done (i2c_done ),// I2C一次操作完成73//user interface74.als_data (als_data ),// ALS的数据75.ps_data(ps_data )// PS的数据76 );77 78 //例化动态数码管显示模块79 seg_led u_seg_led(80//module clock81.clk (sys_clk ), // 时钟信号82.rst_n (sys_rst_n), // 复位信号83//seg_led interface84.seg_sel (sel), // 位选85.seg_led (seg_led ), // 段选86//user interface87.data(als_data ), // 显示的数值88.point (6'd0), // 小数点具体显示的位置,从高到低,高电平有效89.en (1'd1), // 数码管使能信号90.sign(1'b0)// 符号位(高电平显示“-”号)91 );92 93 //例化LED模块94 led_disp u_led_disp(95 //system clock96 .clk(clk),// 时钟信号97 .rst_n (sys_rst_n),// 复位信号98 //led interface99 .led(led),// led灯接口100 //user interface101 .data (ps_data ) // PS的数据102 );103 104 endmodule

顶层模块中主要完成对其余模块的例化,其中I2C驱动模块(i2c_dri)程序与“EEPROM读写实验”章节中的IIC驱动模块(i2c_dri)程序完全相同。有关IIC驱动模块的详细介绍请大家参考“EEPROM读写实验”。

为了可以同时采集到环境光照强度值和距离值,我们需要配置系统寄存器(地址0x00)为011,使AP3216C工作在PS和ALS模式下,此时AP3216C交替采集距离值PS和环境光照强度ALS。

图 33.4.3 采集时序图

由图 33.4.3可以看到,I2C配置完系统寄存器后采集距离值PS需要的时间为12.5ms,采集环境光照强度ALS需要的时间为100ms。

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

1 module ap3216c(2 //system clock3 input clk , // 时钟信号4 input rst_n, // 复位信号5 6 //i2c interface7 output regi2c_rh_wl , // I2C读写控制信号8 output regi2c_exec , // I2C触发执行信号9 output reg [15:0] i2c_addr , // I2C器件内地址10output reg [ 7:0] i2c_data_w , // I2C要写的数据11input [ 7:0] i2c_data_r , // I2C读出的数据12input i2c_done , // I2C一次操作完成13 14//user interface15output reg [15:0] als_data , // ALS的数据16output reg [ 9:0] ps_data // PS的数据17 );18 19 //parameter define20 parameterTIME_PS = 14'd12_500 ; // PS转换时间为12.5ms(clk = 1MHz)21 parameterTIME_ALS = 17'd100_000 ; // ALS转换时间为100ms(clk = 1MHz)22 parameterTIME_REST = 8'd2 ; // 停止后重新开始的时间间隔控制23 24 //reg define25 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 code35 //*****************************************************36 37 //配置AP3216C并读取数据38 always @(posedge clk or negedge rst_n) begin39if(!rst_n) begin40i2c_exec <= 1'b0;41i2c_addr <= 8'd0;42i2c_rh_wl <= 1'b0;43i2c_data_w <= 8'h0;44flow_cnt <= 4'd0;45wait_cnt <= 18'd0;46ps_data <= 10'd0;47ps_data_t <= 10'd0;48ir_of<= 1'b0;49obj <= 1'b0;50als_done <= 1'b0;51als_data_t <= 16'd0;52end53else begin54i2c_exec <= 1'b0;55case(flow_cnt)56 //初始化AP3216C57 4'd0: begin58 if(wait_cnt == 18'd100) begin59 wait_cnt <= 18'd0;60 flow_cnt <= flow_cnt + 1'b1;61 end62 else63 wait_cnt <= wait_cnt +1'b1;64 end65 //配置AP3216C的功能模式66 4'd1: begin67 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 end73 //配置完成74 4'd2: begin75 if(i2c_done)76 flow_cnt <= flow_cnt + 1'b1;77 end78 //等待PS转换完成(12.5ms)79 4'd3: begin80 if(wait_cnt == TIME_PS) begin81 wait_cnt <= 18'd0;82 flow_cnt <= flow_cnt + 1'd1;83 end84 else85 wait_cnt <= wait_cnt + 1'b1;86 end87 //预读PS Data Register(0x0E)88 4'd4: begin89 i2c_exec <= 1'b1;90 i2c_rh_wl<= 1'b1;91 i2c_addr <= 8'h0E;92 flow_cnt <= flow_cnt + 1'b1;93 end94 //读PS Data Register(0x0E)95 4'd5: begin96 if(i2c_done) begin97 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 end102 end103 //等待一段时间以进行下一次读写104 4'd6: begin105 if(wait_cnt == TIME_REST) begin//TIME_REST106 wait_cnt <= 18'd0;107 flow_cnt <= flow_cnt + 1'b1;108 end109 else110 wait_cnt <= wait_cnt +1'b1;111 end112 //预读PS Data Register(0x0F)113 4'd7: begin114 i2c_exec <= 1'b1;115 i2c_rh_wl<= 1'b1;116 i2c_addr <= 8'h0F;117 flow_cnt <= flow_cnt + 1'b1;118 end119 //读PS Data Register(0x0F)120 4'd8: begin121 if(i2c_done) begin122 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 end127 end128 //等待ALS转换完成(100ms)129 4'd9: begin130 if(wait_cnt == TIME_ALS) begin131 wait_cnt <= 18'd0;132 flow_cnt <= flow_cnt + 1'd1;133 ps_data <= ps_data_t;134 end135 else136 wait_cnt <= wait_cnt + 1'b1;137 end138 //预读ALS Data Register(0x0C)139 4'd10: begin140 i2c_exec <= 1'b1;141 i2c_rh_wl<= 1'b1;142 i2c_addr <= 8'h0C;143 flow_cnt <= flow_cnt + 1'b1;144 end145 //读ALS Data Register(0x0C)146 4'd11: begin147 if(i2c_done) begin148 als_done <= 1'b0;149 als_data_t[7:0] <= i2c_data_r;150 flow_cnt <= flow_cnt + 1'b1;151 end152 end153 //等待一段时间以进行下一次读写154 4'd12: begin155 if(wait_cnt == TIME_REST) begin156 wait_cnt <= 18'd0;157 flow_cnt <= flow_cnt + 1'b1;158 end159 else160 wait_cnt <= wait_cnt +1'b1;161 end162 //预读ALS Data Register(0x0D)163 4'd13: begin164 i2c_exec <= 1'b1;165 i2c_rh_wl<= 1'b1;166 i2c_addr <= 8'h0D;167 flow_cnt <= flow_cnt + 1'b1;168 end169 //读ALS Data Register(0x0D)170 4'd14: begin171 if(i2c_done) begin172 als_done <= 1'b1;173 als_data_t[15:8] <= i2c_data_r;174 flow_cnt <= 4'd3; //跳转到状态3重新读取数据175 end176 end177 endcase178end179 end180 181 //当采集的环境光转换成光照强度(单位:lux)182 always @(posedge clk or negedge rst_n) begin183if(!rst_n)184 als_data <= 16'd0;185else if(als_done)186 als_data = als_data_t * 6'd35 / 7'd100;187 end188 189 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传感器应用进行拓展。

图 33.4.4为采集过程中SignalTap抓取的波形图。从图中可以看到I2C写的数值为03h,也即配置AP3216C工作在ALS+PS+IR模式。当前读到的环境光强度als_data为2164lux,距离值ps_data为029h。

图 33.4.4 SignalTap波形图

led显示模块的代码如下:

1 module led_disp(2//system clock3inputclk ,// 时钟信号4inputrst_n,// 复位信号5 6//led interface7output reg [3:0]led ,// led灯接口8 9//user interface10input[9:0] data // 数据11 );12 13 //*****************************************************14 //**main code15 //*****************************************************16 17 //led灯亮灭个数显示数据大小18 always @(posedge clk or negedge rst_n) begin19if(!rst_n) begin20 led <= 4'd0;21end22else if(data < 10'd16)23 led <= 4'b0001;24else if(data < 10'd32)25 led <= 4'b0011;26else if(data < 10'd512)27 led <= 4'b0111;28else29 led <= 4'b1111;30 end31 32 endmodule

led显示模块通过点亮led的个数表示物体距离的远近。程序中的第18行开始的always语句判断读取的PS数据以控制4个led灯的亮灭,PS数据越小,说明物体距离传感器越远,LED灯点亮的个数越少。

33.5下载验证

首先将下载器一端连电脑,另一端与开发板上对应端口连接,最后连接电源线并打开电源开关。接下来我们下载程序,验证AP3216C的传感器功能。下载完成后观察到开发板上数码管显示的值随着环境光照强度的增强而变大;物体的位置靠近AP3216C时,led灯亮的个数增加,远离时减少,如图 33.5.1所示,说明环境光传感器实验程序下载验证成功。

图 33.5.1 AP3216C实验结果显示

【正点原子FPGA连载】第三十三章环境光传感器实验 -摘自【正点原子】新起点之FPGA开发指南_V2.1

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。