跳到主要内容

13.4 实验原理

13.4.1 ADXL345模块介绍

SHT-30是一款超低功耗三轴加速度计,分辨率13位,测量范围-16g~16g。采用3mm x 5mm贴片LGA封装,数字I2C总线接口,管脚功能描述如下:

alt text
管脚功能描述

13.4.2 SHT-30模块连接

STEP BaseBoard V4.0底板上的加速度传感器ADXL345模块电路图如下(上拉电阻未显示):

alt text
ADXL345模块电路

上图为加速度传感器ADXL345模块电路,与FPGA硬件接口有I2C总线(SCL、SDA)。

13.4.3 ADXL345模块驱动设计

智能接近系统设计实验中我们已经讲述学习过I2C总线驱动的设计,本实验可以在原来的基础上调整,首先来了解ADXL345时序中的参数要点。

alt text
ADXL345 I2C时序图
alt text
ADXL345 I2C时序参数

通过ADXL345时序参数了解,SHT-30支持I2C通信最大400KHz模式。

  • 分频得到400KHz的时钟,程序实现同智能接近系统设计实验。

I2C时序基本单元(启动、停止、发送、接收、发应答、读应答)协议里统一的,所以所以基本单元状态的设计也是不需要调整的。

  • 启动时序状态设计程序实现同智能接近系统设计实验。
  • 发送单元和读应答单元合并,时序状态设计程序实现同智能接近系统设计实验。
  • 接收单元和写应答单元合并,时序状态设计程序实现同智能接近系统设计实验。
  • 停止时序状态设计程序实现同智能接近系统设计实验。

ADXL345驱动的流程,手册上看到SHT-30芯片有很多指令,指令列表可查看数据手册。

寄存器复位:

ADXL345驱动首先进行配置,也就是往寄存器写数据,这里一般我们要先配置数据格式控制寄存器DATA_FORMAT(0x31),数据速率及功率模式配置寄存器BW_RATE(0x2C),省电特性控制字POWER_CTL(0x2D)。这些寄存器配置完成后ADXL345进入工作模式。

程序实现如下:

MODE1:begin //单次写操作
 if(cnt_mode1 >= 4'd5) cnt_mode1 <= 1'b0;    //对START中的子状态执行控制cnt_start
 else cnt_mode1 <= cnt_mode1 + 1'b1;
 state_back <= MODE1;
 case(cnt_mode1)
   4'd0:   begin state <= START; end   //I2C通信时序中的START
   4'd1:   begin data_wr <= dev_addr<<1; state <= WRITE; end   //设备地址
   4'd2:   begin data_wr <= reg_addr; state <= WRITE; end  //寄存器地址
   4'd3:   begin data_wr <= reg_data; state <= WRITE; end  //写入数据
   4'd4:   begin state <= STOP; end    //I2C通信时序中的STOP
   4'd5:   begin state <= MAIN; end    //返回MAIN
   default: state <= IDLE; //如果程序失控,进入IDLE自复位状态
 endcase
end
alt text

数据读取:

读数据部分,程序实现如下:

MODE2:begin //两次读操作
 if(cnt_mode2 >= 4'd10) cnt_mode2 <= 1'b0;   //对START中的子状态执行控制cnt_start
 else cnt_mode2 <= cnt_mode2 + 1'b1;
 state_back <= MODE2;
 case(cnt_mode2)
   4'd0:   begin state <= START; end   //I2C通信时序中的START
   4'd1:   begin data_wr <= dev_addr<<1; state <= WRITE; end   //设备地址
   4'd2:   begin data_wr <= reg_addr; state <= WRITE; end  //寄存器地址
   4'd3:   begin state <= START; end   //I2C通信时序中的START
   4'd4:   begin data_wr <= (dev_addr<<1)|8'h01; state <= WRITE; end   //设备地址
   4'd5:   begin ack <= ACK; state <= READ; end    //读寄存器数据
   4'd6:   begin dat_l <= data_r; end
   4'd7:   begin ack <= NACK; state <= READ; end   //读寄存器数据
   4'd8:   begin dat_h <= data_r; end
   4'd9:   begin state <= STOP; end    //I2C通信时序中的STOP
   4'd10:  begin state <= MAIN; end    //返回MAIN
   default: state <= IDLE; //如果程序失控,进入IDLE自复位状态
endcase
end

最后我们编程控制状态机按照驱动例程代码中流程运行,程序实现如下:

MAIN:begin
 if(cnt_main >= 4'd10) cnt_main <= 4'd3;     //写完控制指令后循环读数据
 else cnt_main <= cnt_main + 1'b1;  
 case(cnt_main)
   4'd0:   begin dev_addr <= 7'h53; reg_addr <= 8'h31; reg_data <= 8'h09; state <= MODE1; end  //写入配置
   4'd1:   begin dev_addr <= 7'h53; reg_addr <= 8'h2c; reg_data <= 8'h0a; state <= MODE1; end  //写入配置
   4'd2:   begin dev_addr <= 7'h53; reg_addr <= 8'h2d; reg_data <= 8'h08; state <= MODE1; end  //写入配置
   4'd3:   begin state <= DELAY; num_delay <= 24'd1_440_000;data_valid <= 1'b0; end    //120ms延时
   4'd4:   begin dev_addr <= 7'h53; reg_addr <= 8'h32;  state <= MODE2; end    //读取配置
   4'd5:   begin  x_dat<= {dat_h,dat_l}; end   //读取数据
   4'd6:   begin dev_addr <= 7'h53; reg_addr <= 8'h34;  state <= MODE2; end    //读取配置
   4'd7:   begin y_dat <= {dat_h,dat_l}; end   //读取数据
   4'd8:   begin dev_addr <= 7'h53; reg_addr <= 8'h36;  state <= MODE2; end    //读取配置
   4'd9:   begin z_dat <= {dat_h,dat_l}; end   //读取数据
   4'd10:  begin data_valid <= 1'b1; end   //读取数据
   default: state <= IDLE; //如果程序失控,进入IDLE自复位状态
 endcase
end

13.4.4 系统总体实现

ADXL345驱动模块得到的是X、Y、Z三个方向的,有效位数13位,我们把其中一路显示在数码管上,首先要对数据进行BCD转码。

BCD转码在前面电压器实验中介绍过,这里直接例化,程序实现如下:

//进行BCD转码处理
//小数点在BCD码基础上左移2位,完成除以100的操作
//T_data_bcd[19:16]百位,[15:12]十位,[11:8]个位,[7:0]两个小数位
wire [19:0] data_bcd;
bin_to_bcd u1
(
.rst_n              (rst_n      ),  //系统复位,低有效
.bin_code           (data_bin   ),  //需要进行BCD转码的二进制数据
.bcd_code           (data_bcd   )   //转码后的BCD码型数据输出
);

//要显示的数据,保留1位小数

assign data_out = (data_in[12])? {4'ha,data_bcd[15:0]}:data_bcd[19:0];

//数据显示使能,高位消零
assign dat_en[4] = |data_out[19:16]; //自或
//assign dat_en[2] = (data_in[12])?(|data_out[11:8]):(|data_out[15:8]);
assign dat_en[7:5] = 3'b000;
assign dat_en[3:0] = 4'b1111;
//小数点显示使能
assign dot_en[7:0] = 8'b0000_0000;

综合后的设计框图如下:

alt text