BH1750环境光强度传感器FPGA驱动
1. BH1750介绍
BH1750是一种用于两线式串行总线接口的数字型光强度传感器集成电路。这种集成电路可以根据收集的光线强度数据来调整液晶或者键盘背景灯的亮度。利用它的高分辨率可以探测较大范围的光强度变化。(1x-65535lx)
特点:
1.支持IIC接口。
2.接近视觉灵敏度的光谱灵敏度特性(峰值灵敏度波长典型值:560nm).
3.输出对应亮度的数字值。
4.对应广泛的输入光范围(相当于1-65535lx)。
5.通过降低功率功能,实现低电流化。

| 引脚名称 | 介绍 |
|---|---|
| GND | 电源地 |
| VCC | 供电电源 |
| SCL | IIC时钟线 |
| SDA | IIC数据线,双向IO口 |
| ADDR | IIC地址线,接GND时地址为:0100011;接VCC时地址为:1011100 |
2. BH1750的IIC通信

上面所示是BH1750用IIC通信协议实现测量的步骤。如果忽略第二步的等待时间,这是一个标准的IIC读取过程,因此为了方便,可以在标准的IIC通信协议上做修改,再第二次写入器件地址前做一个延时等待判断。当延时时间为200ms时,开始执行第三步的操作。同时需要注意,BH1750的输出数据为16bit,IIC读取时要改为16位读取。
3. 整体模块

key_filter模块是按键输入的消抖模块,当按下按键是,FPGA开始用IIC通信协议向BH1750通信,经过延时等待后得到数据。将数据利用UART串口模块发送到上位机计算使用。
4. 代码
按键消抖
module key_filter(Clk,Rst_n,key_in,key_flag,key_state);
input Clk;
input Rst_n;
input key_in;
output reg key_flag;
output reg key_state;
localparam
IDEL = 4'b0001,
FILTER0 = 4'b0010,
DOWN = 4'b0100,
FILTER1 = 4'b1000;
reg [3:0]state;
reg [19:0]cnt;
reg en_cnt; //使能计数寄存器
//对外部输入的异步信号进行同步处理
reg key_in_sa,key_in_sb;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
key_in_sa <= 1'b0;
key_in_sb <= 1'b0;
end
else begin
key_in_sa <= key_in;
key_in_sb <= key_in_sa;
end
reg key_tmpa,key_tmpb;
wire pedge,nedge;
reg cnt_full;//计数满标志信号
//使用D触发器存储两个相邻时钟上升沿时外部输入信号(已经同步到系统时钟域中)的电平状态
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
key_tmpa <= 1'b0;
key_tmpb <= 1'b0;
end
else begin
key_tmpa <= key_in_sb;
key_tmpb <= key_tmpa;
end
//产生跳变沿信号
assign nedge = !key_tmpa & key_tmpb;
assign pedge = key_tmpa & (!key_tmpb);
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
en_cnt <= 1'b0;
state <= IDEL;
key_flag <= 1'b0;
key_state <= 1'b1;
end
else begin
case(state)
IDEL :
begin
key_flag <= 1'b0;
if(nedge)begin
state <= FILTER0;
en_cnt <= 1'b1;
end
else
state <= IDEL;
end
FILTER0:
if(cnt_full)begin
key_flag <= 1'b1;
key_state <= 1'b0;
en_cnt <= 1'b0;
state <= DOWN;
end
else if(pedge)begin
state <= IDEL;
en_cnt <= 1'b0;
end
else
state <= FILTER0;
DOWN:
begin
key_flag <= 1'b0;
if(pedge)begin
state <= FILTER1;
en_cnt <= 1'b1;
end
else
state <= DOWN;
end
FILTER1:
if(cnt_full)begin
key_flag <= 1'b1;
key_state <= 1'b1;
state <= IDEL;
end
else if(nedge)begin
en_cnt <= 1'b0;
state <= DOWN;
end
else
state <= FILTER1;
default:
begin
state <= IDEL;
en_cnt <= 1'b0;
key_flag <= 1'b0;
key_state <= 1'b1;
end
endcase
end
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
cnt <= 20'd0;
else if(en_cnt)
cnt <= cnt + 1'b1;
else
cnt <= 20'd0;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
cnt_full <= 1'b0;
else if(cnt == 4_999)
cnt_full <= 1'b1;
else
cnt_full <= 1'b0;
endmodule
IIC驱动
module i2c_dri
#(// slave address(器件地址)
parameter SLAVE_ADDR = 7'b0100011 ,
parameter CLK_FREQ = 26'd50_000_000, // i2c_dri模块的驱动时钟频率(CLK_FREQ)
parameter I2C_FREQ = 18'd250_000 // I2C的SCL时钟频率
)(
//global clock
input clk , // i2c_dri模块的驱动时钟(CLK_FREQ)
input rst_n , // 复位信号
//i2c interface
input i2c_exec , // I2C触发执行信号
input bit_ctrl , // 字地址位控制(16b/8b)
input i2c_rh_wl , // I2C读写控制信号
input [ 7:0] i2c_addr , // I2C器件内地址
input [ 7:0] i2c_data_w , // I2C要写的数据
output reg [ 15:0] i2c_data_r , // I2C读出的数据
output reg i2c_done , // I2C一次操作完成
output reg scl , // I2C的SCL时钟信号
inout sda , // I2C的SDA信号
//user interface
output reg dri_clk // 驱动I2C操作的驱动时钟
);
//localparam define
localparam st_idle = 8'b0000_0001; // 空闲状态
localparam st_sladdr = 8'b0000_0010; // 发送器件地址(slave address)
localparam st_addr16 = 8'b0000_0100; // 发送16位字地址
localparam st_addr8 = 8'b0000_1000; // 发送8位字地址
localparam st_data_wr = 8'b0001_0000; // 写数据(8 bit)
localparam st_addr_rd = 8'b0010_0000; // 发送器件地址读
localparam st_data_rd = 8'b0100_0000; // 读数据(8 bit)
localparam st_stop = 8'b1000_0000; // 结束I2C操作
//reg define
reg sda_dir ; // I2C数据(SDA)方向控制
reg sda_out ; // SDA输出信号
reg st_done ; // 状态结束
reg wr_flag ; // 写标志
reg [ 6:0] cnt ; // 计数
reg [ 7:0] cur_state ; // 状态机当前状态
reg [ 7:0] next_state ; // 状态机下一状态
reg [15:0] addr_t ; // 地址
reg [15:0] data_r ; // 读取的数据
reg [ 7:0] data_wr_t ; // I2C需写的数据的临时寄存
reg [ 9:0] clk_cnt ; // 分频时钟计数
reg [15:0] delay_cnt ; // 延时200ms时钟计数
reg delay_done ; // 延时结束
//wire define
wire sda_in ; // SDA输入信号
wire [8:0] clk_divide ; // 模块驱动时钟的分频系数
//SDA控制
assign sda = sda_dir ? sda_out : 1'bz; // SDA数据输出或高阻
assign sda_in = sda ; // SDA数据输入
assign clk_divide = (CLK_FREQ/I2C_FREQ) >> 3; // 模块驱动时钟的分频系数
//生成I2C的SCL的四倍频率的驱动时钟用于驱动i2c的操作
always @

本文介绍了一种BH1750环境光强度传感器的FPGA驱动设计方法,包括按键消抖模块、IIC驱动模块及串口模块的设计,并通过实验验证了系统的正确性。
最低0.47元/天 解锁文章
2116





