正点原子 发表于 2021-10-12 15:19:28

《新起点V2之FPGA开发指南》第三十三章 环境光传感器实验

本帖最后由 正点原子 于 2021-10-30 10:41 编辑

1)实验平台:正点原子新起点V2FPGA开发板
2)章节摘自【正点原子】《新起点之FPGA开发指南 V2.1》
3)购买链接:https://detail.tmall.com/item.htm?id=609758951113
4)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-328002-1-1.html
5)正点原子官方B站:https://space.bilibili.com/394620890
6)正点原子FPGA技术交流QQ群:712557122








第三十三章 环境光传感器实验
       AP3216C是一个能够测量环境光强度和距离的整合型光感测距传感器。因其功耗低、控制简单、封装小而广泛应用于智能手机、电容式触摸屏、数码相机等领域。例如应用于智能手机上面检测环境光强度,用来实现自动背光控制,以及接近开关控制(听筒靠近耳朵,手机自动灭屏功能)。本章我们将使用FPGA开发板上的AP3216C器件实现环境光照强度和距离的测量。
       本章包括以下几个部分:
       1.1简介
       1.2实验任务
       1.3硬件设计
       1.4程序设计
       1.5下载验证

1.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进行应答。
1.2实验任务
       本节实验任务是使用新起点FPGA开发板上的AP3216C器件测量环境光强度和物体距离,并在数码管上显示环境光强度,用4个led灯的亮灭来指示物体距离的远近。
1.3硬件设计
      新起点开发板上AP3216C接口部分的原理图如图 33.3.1所示。

图 33.3.1 AP3216C接口原理图
      AP3216C作为I2C接口的从器件与EEPROM等模块统一挂接在新起点开发板上的IIC总线上。LEDA是器件内部红外发光二极管(IR_LED)的阳极,LEDC为阴极,一般连接到LED的驱动输出脚LDR。
      本实验中,各端口信号的管脚分配如下表所示:


表 33.3.1 AP3216C环境光—距离传感器实验管脚分配
对应的TCL约束语句如下:
<font size="4">set_location_assignment PIN_M2 -to sys_clk</font>
<font size="4">set_location_assignment PIN_M1 -to sys_rst_n</font>
<font size="4">set_location_assignment PIN_C8 -to ap_sda</font>
<font size="4">set_location_assignment PIN_D8 -to ap_scl</font>
<font size="4">set_location_assignment PIN_D11 -to led</font>
<font size="4">set_location_assignment PIN_C11 -to led</font>
<font size="4">set_location_assignment PIN_E10 -to led</font>
<font size="4">set_location_assignment PIN_F9 -to led</font>
<font size="4">set_location_assignment PIN_N16 -to sel</font>
<font size="4">set_location_assignment PIN_N15 -to sel</font>
<font size="4">set_location_assignment PIN_P16 -to sel</font>
<font size="4">set_location_assignment PIN_P15 -to sel</font>
<font size="4">set_location_assignment PIN_R16 -to sel</font>
<font size="4">set_location_assignment PIN_T15 -to sel</font>
<font size="4">set_location_assignment PIN_M11 -to seg_led</font>
<font size="4">set_location_assignment PIN_N12 -to seg_led</font>
<font size="4">set_location_assignment PIN_C9 -to seg_led</font>
<font size="4">set_location_assignment PIN_N13 -to seg_led</font>
<font size="4">set_location_assignment PIN_M10 -to seg_led</font>
<font size="4">set_location_assignment PIN_N11 -to seg_led</font>
<font size="4">set_location_assignment PIN_P11 -to seg_led</font>
<font size="4">set_location_assignment PIN_D9 -to seg_led</font>
1.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):数码管显示模块显示采集到的环境光强度值。
       顶层模块的代码如下:
<font size="4">1   module ap3216c_top(</font>
<font size="4">2       //global clock</font>
<font size="4">3       input                sys_clk    ,      // 系统时钟</font>
<font size="4">4       input                sys_rst_n,      // 系统复位</font>
<font size="4">5   </font>
<font size="4">6       //ap3216c interface</font>
<font size="4">7       output               ap_scl   ,      // i2c时钟线</font>
<font size="4">8       inout                ap_sda   ,      // i2c数据线</font>
<font size="4">9   </font>
<font size="4">10      //user interface</font>
<font size="4">11      output      led      ,      // led灯接口</font>
<font size="4">12      output      sel      ,      // 数码管位选</font>
<font size="4">13      output      seg_led             // 数码管段选</font>
<font size="4">14);</font>
<font size="4">15</font>
<font size="4">16//parameter define</font>
<font size="4">17parameter      SLAVE_ADDR =7'h1e      ;// 器件地址</font>
<font size="4">18parameter      BIT_CTRL   =1'b0         ;// 字地址位控制参数(16b/8b)</font>
<font size="4">19parameter      CLK_FREQ   = 26'd50_000_000;// i2c_dri模块的驱动时钟频率(CLK_FREQ)</font>
<font size="4">20parameter      I2C_FREQ   = 18'd250_000   ;// I2C的SCL时钟频率</font>
<font size="4">21</font>
<font size="4">22//wire define</font>
<font size="4">23wire         clk       ;                   // I2C操作时钟</font>
<font size="4">24wire         i2c_exec;                   // i2c触发控制</font>
<font size="4">25wire   i2c_addr;                   // i2c操作地址</font>
<font size="4">26wire   [ 7:0]i2c_data_w;                   // i2c写入的数据</font>
<font size="4">27wire         i2c_done;                   // i2c操作结束标志</font>
<font size="4">28wire         i2c_rh_wl ;                   // i2c读写控制</font>
<font size="4">29wire   [ 7:0]i2c_data_r;                   // i2c读出的数据</font>
<font size="4">30wire   als_data;                   // ALS的数据</font>
<font size="4">31wire   [ 9:0]ps_data   ;                   // PS的数据</font>
<font size="4">32</font>
<font size="4">33//*****************************************************</font>
<font size="4">34//**                  main code</font>
<font size="4">35//*****************************************************</font>
<font size="4">36</font>
<font size="4">37//例化i2c_dri,调用IIC协议</font>
<font size="4">38i2c_dri #(</font>
<font size="4">39      .SLAVE_ADDR(SLAVE_ADDR),               // slave address从机地址,放此处方便参数传递</font>
<font size="4">40      .CLK_FREQ    (CLK_FREQ),               // i2c_dri模块的驱动时钟频率(CLK_FREQ)</font>
<font size="4">41      .I2C_FREQ    (I2C_FREQ)                // I2C的SCL时钟频率</font>
<font size="4">42) u_i2c_dri(</font>
<font size="4">43      //global clock</font>
<font size="4">44      .clk         (sys_clk   ),               // i2c_dri模块的驱动时钟(CLK_FREQ)</font>
<font size="4">45      .rst_n       (sys_rst_n ),               // 复位信号</font>
<font size="4">46      //i2c interface</font>
<font size="4">47      .i2c_exec    (i2c_exec),               // I2C触发执行信号</font>
<font size="4">48      .bit_ctrl    (BIT_CTRL),               // 器件地址位控制(16b/8b)</font>
<font size="4">49      .i2c_rh_wl   (i2c_rh_wl ),               // I2C读写控制信号</font>
<font size="4">50      .i2c_addr    (i2c_addr),               // I2C器件内地址</font>
<font size="4">51      .i2c_data_w(i2c_data_w),               // I2C要写的数据</font>
<font size="4">52      .i2c_data_r(i2c_data_r),               // I2C读出的数据</font>
<font size="4">53      .i2c_done    (i2c_done),               // I 2C一次操作完成</font>
<font size="4">54      .i2c_ack   (),                         // I2C应答标志 0:应答 1:未应答</font>
<font size="4">55      .scl         (ap_scl    ),               // I2C的SCL时钟信号</font>
<font size="4">56      .sda         (ap_sda    ),               // I2C的SDA信号</font>
<font size="4">57      //user interface</font>
<font size="4">58      .dri_clk   (clk       )                // I2C操作时钟</font>
<font size="4">59);</font>
<font size="4">60</font>
<font size="4">61//例化AP3216C测量模块</font>
<font size="4">62ap3216c u_ap3216c(</font>
<font size="4">63      //system clock</font>
<font size="4">64      .clk         (clk       ),               // 时钟信号</font>
<font size="4">65      .rst_n       (sys_rst_n ),               // 复位信号</font>
<font size="4">66      //i2c interface</font>
<font size="4">67      .i2c_rh_wl   (i2c_rh_wl ),               // I2C读写控制信号</font>
<font size="4">68      .i2c_exec    (i2c_exec),               // I2C触发执行信号</font>
<font size="4">69      .i2c_addr    (i2c_addr),               // I2C器件内地址</font>
<font size="4">70      .i2c_data_w(i2c_data_w),               // I2C要写的数据</font>
<font size="4">71      .i2c_data_r(i2c_data_r),               // I2C读出的数据</font>
<font size="4">72      .i2c_done    (i2c_done),               // I2C一次操作完成</font>
<font size="4">73      //user interface</font>
<font size="4">74      .als_data    (als_data),               // ALS的数据</font>
<font size="4">75      .ps_data   (ps_data   )                // PS的数据</font>
<font size="4">76);</font>
<font size="4">77</font>
<font size="4">78//例化动态数码管显示模块</font>
<font size="4">79seg_led u_seg_led(</font>
<font size="4">80      //module clock</font>
<font size="4">81      .clk         (sys_clk),            // 时钟信号</font>
<font size="4">82      .rst_n         (sys_rst_n),            // 复位信号</font>
<font size="4">83      //seg_led interface</font>
<font size="4">84      .seg_sel       (sel      ),            // 位选</font>
<font size="4">85      .seg_led       (seg_led),            // 段选</font>
<font size="4">86      //user interface</font>
<font size="4">87      .data          (als_data ),            // 显示的数值</font>
<font size="4">88      .point         (6'd0   ),            // 小数点具体显示的位置,从高到低,高电平有效</font>
<font size="4">89      .en            (1'd1   ),            // 数码管使能信号</font>
<font size="4">90      .sign          (1'b0   )               // 符号位(高电平显示“-”号)</font>
<font size="4">91);</font>
<font size="4">92</font>
<font size="4">93//例化LED模块</font>
<font size="4">94led_disp u_led_disp(</font>
<font size="4">95//system clock</font>
<font size="4">96.clk          (clk      ),                // 时钟信号</font>
<font size="4">97.rst_n      (sys_rst_n),                // 复位信号</font>
<font size="4">98//led interface</font>
<font size="4">99.led          (led      ),                // led灯接口</font>
<font size="4">100 //user interface</font>
<font size="4">101 .data         (ps_data)               // PS的数据</font>
<font size="4">102 );</font>
<font size="4">103 </font>
<font size="4">104 endmodule</font>
      顶层模块中主要完成对其余模块的例化,其中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数据采集模块的代码如下所示:
<font size="4">1   module ap3216c(</font>
<font size="4">2       //system clock</font>
<font size="4">3       input               clk      ,    // 时钟信号</font>
<font size="4">4       input               rst_n      ,    // 复位信号</font>
<font size="4">5   </font>
<font size="4">6       //i2c interface</font>
<font size="4">7       output   reg          i2c_rh_wl,    // I2C读写控制信号</font>
<font size="4">8       output   reg          i2c_exec   ,    // I2C触发执行信号</font>
<font size="4">9       output   regi2c_addr   ,    // I2C器件内地址</font>
<font size="4">10      output   reg[ 7:0]i2c_data_w ,    // I2C要写的数据</font>
<font size="4">11      input         [ 7:0]i2c_data_r ,    // I2C读出的数据</font>
<font size="4">12      input               i2c_done   ,    // I2C一次操作完成</font>
<font size="4">13</font>
<font size="4">14      //user interface</font>
<font size="4">15      output   regals_data   ,    // ALS的数据</font>
<font size="4">16      output   reg[ 9:0]ps_data         // PS的数据</font>
<font size="4">17);</font>
<font size="4">18</font>
<font size="4">19//parameter define</font>
<font size="4">20parameter      TIME_PS   = 14'd12_500;// PS转换时间为12.5ms(clk = 1MHz)</font>
<font size="4">21parameter      TIME_ALS= 17'd100_000 ;// ALS转换时间为100ms(clk = 1MHz)</font>
<font size="4">22parameter      TIME_REST =8'd2       ;// 停止后重新开始的时间间隔控制</font>
<font size="4">23</font>
<font size="4">24//reg define</font>
<font size="4">25reg   [ 3:0]   flow_cnt   ;               // 状态流控制</font>
<font size="4">26reg      wait_cnt   ;               // 计数等待</font>
<font size="4">27reg      als_data_t ;               // ALS的临时数据</font>
<font size="4">28reg            als_done   ;               // 环境光照强度值采集完成信号</font>
<font size="4">29reg   [ 9:0]   ps_data_t;               // PS的临时数据</font>
<font size="4">30reg            ir_of      ;               // 溢出标志(判断ps_data是否有效)</font>
<font size="4">31reg            obj      ;               // 物体状态标志(0远离1靠近)</font>
<font size="4">32</font>
<font size="4">33//*****************************************************</font>
<font size="4">34//**                  main code</font>
<font size="4">35//*****************************************************</font>
<font size="4">36</font>
<font size="4">37//配置AP3216C并读取数据</font>
<font size="4">38always @(posedge clk or negedge rst_n) begin</font>
<font size="4">39      if(!rst_n) begin</font>
<font size="4">40          i2c_exec   <=1'b0;</font>
<font size="4">41          i2c_addr   <=8'd0;</font>
<font size="4">42          i2c_rh_wl<=1'b0;</font>
<font size="4">43          i2c_data_w <=8'h0;</font>
<font size="4">44          flow_cnt   <=4'd0;</font>
<font size="4">45          wait_cnt   <= 18'd0;</font>
<font size="4">46          ps_data    <= 10'd0;</font>
<font size="4">47          ps_data_t<= 10'd0;</font>
<font size="4">48          ir_of      <=1'b0;</font>
<font size="4">49          obj      <=1'b0;</font>
<font size="4">50          als_done   <=1'b0;</font>
<font size="4">51          als_data_t <= 16'd0;</font>
<font size="4">52      end</font>
<font size="4">53      else begin</font>
<font size="4">54          i2c_exec <= 1'b0;</font>
<font size="4">55          case(flow_cnt)</font>
<font size="4">56            //初始化AP3216C</font>
<font size="4">57            4'd0: begin</font>
<font size="4">58                  if(wait_cnt == 18'd100) begin</font>
<font size="4">59                      wait_cnt <= 18'd0;</font>
<font size="4">60                      flow_cnt <= flow_cnt + 1'b1;</font>
<font size="4">61                  end</font>
<font size="4">62                  else</font>
<font size="4">63                      wait_cnt <= wait_cnt +1'b1;</font>
<font size="4">64            end</font>
<font size="4">65            //配置AP3216C的功能模式</font>
<font size="4">66            4'd1: begin</font>
<font size="4">67                  i2c_exec   <= 1'b1 ;</font>
<font size="4">68                  i2c_rh_wl<= 1'b0 ;</font>
<font size="4">69                  i2c_addr   <= 8'h00;               // 配置系统寄存器</font>
<font size="4">70                  i2c_data_w <= 8'h03;               // 激活ALS+PS+IR 功能</font>
<font size="4">71                  flow_cnt   <= flow_cnt + 1'b1;</font>
<font size="4">72            end</font>
<font size="4">73            //配置完成</font>
<font size="4">74            4'd2: begin</font>
<font size="4">75                  if(i2c_done)</font>
<font size="4">76                      flow_cnt <= flow_cnt + 1'b1;</font>
<font size="4">77            end</font>
<font size="4">78            //等待PS转换完成(12.5ms)</font>
<font size="4">79            4'd3: begin</font>
<font size="4">80                  if(wait_cnt== TIME_PS) begin</font>
<font size="4">81                      wait_cnt <= 18'd0;</font>
<font size="4">82                      flow_cnt <= flow_cnt + 1'd1;</font>
<font size="4">83                  end</font>
<font size="4">84                  else</font>
<font size="4">85                      wait_cnt <= wait_cnt + 1'b1;</font>
<font size="4">86            end</font>
<font size="4">87            //预读PS Data Register(0x0E)</font>
<font size="4">88            4'd4: begin</font>
<font size="4">89                  i2c_exec <= 1'b1;</font>
<font size="4">90                  i2c_rh_wl<= 1'b1;</font>
<font size="4">91                  i2c_addr <= 8'h0E;</font>
<font size="4">92                  flow_cnt <= flow_cnt + 1'b1;</font>
<font size="4">93            end</font>
<font size="4">94            //读PS Data Register(0x0E)</font>
<font size="4">95            4'd5: begin</font>
<font size="4">96                  if(i2c_done) begin</font>
<font size="4">97                      flow_cnt   <= flow_cnt + 1'b1;</font>
<font size="4">98                      ps_data_t <= i2c_data_r;</font>
<font size="4">99                      ir_of      <= i2c_data_r;</font>
<font size="4">100                     obj          <= i2c_data_r;</font>
<font size="4">101               end</font>
<font size="4">102             end</font>
<font size="4">103             //等待一段时间以进行下一次读写</font>
<font size="4">104             4'd6: begin</font>
<font size="4">105               if(wait_cnt == TIME_REST) begin//TIME_REST</font>
<font size="4">106                     wait_cnt <= 18'd0;</font>
<font size="4">107                     flow_cnt <= flow_cnt + 1'b1;</font>
<font size="4">108               end</font>
<font size="4">109               else</font>
<font size="4">110                     wait_cnt <= wait_cnt +1'b1;</font>
<font size="4">111             end</font>
<font size="4">112             //预读PS Data Register(0x0F)</font>
<font size="4">113             4'd7: begin</font>
<font size="4">114               i2c_exec <= 1'b1;</font>
<font size="4">115               i2c_rh_wl<= 1'b1;</font>
<font size="4">116               i2c_addr <= 8'h0F;</font>
<font size="4">117               flow_cnt <= flow_cnt + 1'b1;</font>
<font size="4">118             end</font>
<font size="4">119             //读PS Data Register(0x0F)</font>
<font size="4">120             4'd8: begin</font>
<font size="4">121               if(i2c_done) begin</font>
<font size="4">122                     flow_cnt   <= flow_cnt + 1'b1;</font>
<font size="4">123                     ps_data_t <= i2c_data_r;</font>
<font size="4">124                     ir_of      <= i2c_data_r;</font>
<font size="4">125                     obj          <= i2c_data_r;</font>
<font size="4">126               end</font>
<font size="4">127             end</font>
<font size="4">128             //等待ALS转换完成(100ms)</font>
<font size="4">129             4'd9: begin</font>
<font size="4">130               if(wait_cnt==TIME_ALS) begin</font>
<font size="4">131                     wait_cnt <= 18'd0;</font>
<font size="4">132                     flow_cnt <= flow_cnt + 1'd1;</font>
<font size="4">133                     ps_data<= ps_data_t;</font>
<font size="4">134               end</font>
<font size="4">135               else</font>
<font size="4">136                     wait_cnt <= wait_cnt + 1'b1;</font>
<font size="4">137             end</font>
<font size="4">138             //预读ALS Data Register(0x0C)</font>
<font size="4">139             4'd10: begin</font>
<font size="4">140               i2c_exec <= 1'b1;</font>
<font size="4">141               i2c_rh_wl<= 1'b1;</font>
<font size="4">142               i2c_addr <= 8'h0C;</font>
<font size="4">143               flow_cnt <= flow_cnt + 1'b1;</font>
<font size="4">144             end</font>
<font size="4">145             //读ALS Data Register(0x0C)</font>
<font size="4">146             4'd11: begin</font>
<font size="4">147               if(i2c_done) begin</font>
<font size="4">148                     als_done      <= 1'b0;</font>
<font size="4">149                     als_data_t <= i2c_data_r;</font>
<font size="4">150                     flow_cnt      <= flow_cnt + 1'b1;</font>
<font size="4">151               end</font>
<font size="4">152             end</font>
<font size="4">153             //等待一段时间以进行下一次读写</font>
<font size="4">154             4'd12: begin</font>
<font size="4">155               if(wait_cnt == TIME_REST) begin</font>
<font size="4">156                     wait_cnt <= 18'd0;</font>
<font size="4">157                     flow_cnt <= flow_cnt + 1'b1;</font>
<font size="4">158               end</font>
<font size="4">159               else</font>
<font size="4">160                     wait_cnt <= wait_cnt +1'b1;</font>
<font size="4">161             end</font>
<font size="4">162             //预读ALS Data Register(0x0D)</font>
<font size="4">163             4'd13: begin</font>
<font size="4">164               i2c_exec <= 1'b1;</font>
<font size="4">165               i2c_rh_wl<= 1'b1;</font>
<font size="4">166               i2c_addr <= 8'h0D;</font>
<font size="4">167               flow_cnt <= flow_cnt + 1'b1;</font>
<font size="4">168             end</font>
<font size="4">169             //读ALS Data Register(0x0D)</font>
<font size="4">170             4'd14: begin</font>
<font size="4">171               if(i2c_done) begin</font>
<font size="4">172                     als_done         <= 1'b1;</font>
<font size="4">173                     als_data_t <= i2c_data_r;</font>
<font size="4">174                     flow_cnt         <= 4'd3;             //跳转到状态3重新读取数据</font>
<font size="4">175               end</font>
<font size="4">176             end</font>
<font size="4">177         endcase</font>
<font size="4">178   end</font>
<font size="4">179 end</font>
<font size="4">180 </font>
<font size="4">181 //当采集的环境光转换成光照强度(单位:lux)</font>
<font size="4">182 always @(posedge clk or negedge rst_n) begin</font>
<font size="4">183   if(!rst_n)</font>
<font size="4">184         als_data <= 16'd0;</font>
<font size="4">185   else if(als_done)</font>
<font size="4">186         als_data = als_data_t * 6'd35 / 7'd100;</font>
<font size="4">187 end</font>
<font size="4">188 </font>
<font size="4">189 endmodule</font>
       程序中第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显示模块的代码如下:
<font size="4">1module led_disp(</font>
<font size="4">2      //system clock</font>
<font size="4">3      input                        clk,   // 时钟信号</font>
<font size="4">4      input                        rst_n,   // 复位信号</font>
<font size="4">5</font>
<font size="4">6      //led interface</font>
<font size="4">7      output   reg             led,   // led灯接口</font>
<font size="4">8</font>
<font size="4">9      //user interface</font>
<font size="4">10   input                   data       // 数据</font>
<font size="4">11 );</font>
<font size="4">12 </font>
<font size="4">13 //*****************************************************</font>
<font size="4">14 //**                  main code</font>
<font size="4">15 //*****************************************************</font>
<font size="4">16 </font>
<font size="4">17 //led灯亮灭个数显示数据大小</font>
<font size="4">18 always @(posedge clk or negedge rst_n) begin</font>
<font size="4">19   if(!rst_n) begin</font>
<font size="4">20         led <=4'd0;</font>
<font size="4">21   end</font>
<font size="4">22   else if(data < 10'd16)</font>
<font size="4">23         led <= 4'b0001;</font>
<font size="4">24   else if(data < 10'd32)</font>
<font size="4">25         led <= 4'b0011;</font>
<font size="4">26   else if(data < 10'd512)</font>
<font size="4">27         led <= 4'b0111;</font>
<font size="4">28   else</font>
<font size="4">29         led <= 4'b1111;</font>
<font size="4">30 end</font>
<font size="4">31 </font>
<font size="4">32 endmodule</font>
       led显示模块通过点亮led的个数表示物体距离的远近。程序中的第18行开始的always语句判断读取的PS数据以控制4个led灯的亮灭,PS数据越小,说明物体距离传感器越远,LED灯点亮的个数越少。
1.5下载验证
       首先将下载器一端连电脑,另一端与开发板上对应端口连接,最后连接电源线并打开电源开关。接下来我们下载程序,验证AP3216C的传感器功能。下载完成后观察到开发板上数码管显示的值随着环境光照强度的增强而变大;物体的位置靠近AP3216C时,led灯亮的个数增加,远离时减少,如图 33.5.1所示,说明环境光传感器实验程序下载验证成功。

图 33.5.1 AP3216C实验结果显示

页: [1]
查看完整版本: 《新起点V2之FPGA开发指南》第三十三章 环境光传感器实验