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 @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
dri_clk <= 1'b1;
clk_cnt <= 10'd0;
end
else if(clk_cnt == clk_divide - 1'd1) begin
clk_cnt <= 10'd0;
dri_clk <= ~dri_clk;
end
else
clk_cnt <= clk_cnt + 1'b1;
end
//延時200ms等待BH1750采樣轉換結束
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
delay_cnt <= 16'd0;
end
else if((cur_state ==st_addr_rd) && (delay_cnt < 16'd50_000))
delay_cnt <= delay_cnt + 1'b1;
else
delay_cnt <= 16'd0;
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
delay_done <= 1'b0;
end
else if(delay_cnt == 16'd49_999)
delay_done <= ~delay_done;
end
//(三段式狀態機)同步時序描述狀態轉移
always @(posedge dri_clk or negedge rst_n) begin
if(!rst_n)
cur_state <= st_idle;
else
cur_state <= next_state;
end
//組合邏輯判斷狀態轉移條件
always @( * ) begin
case(cur_state)
st_idle: begin // 空閑狀態
if(i2c_exec) begin
next_state = st_sladdr;
end
else
next_state = st_idle;
end
st_sladdr: begin
if(st_done) begin
if(bit_ctrl) // 判斷是16位還是8位字地址
next_state = st_addr16;
else
next_state = st_addr8 ;
end
else
next_state = st_sladdr;
end
st_addr16: begin // 寫16位字地址
if(st_done) begin
next_state = st_addr8;
end
else begin
next_state = st_addr16;
end
end
st_addr8: begin // 8位字地址
if(st_done) begin
if(wr_flag==1'b0) // 讀寫判斷
next_state = st_data_wr;
else
next_state = st_addr_rd;
end
else begin
next_state = st_addr8;
end
end
st_data_wr: begin // 寫資料(8 bit)
if(st_done)
next_state = st_stop;
else
next_state = st_data_wr;
end
st_addr_rd: begin // 寫地址以進行讀資料
if(st_done) begin
next_state = st_data_rd;
end
else begin
next_state = st_addr_rd;
end
end
st_data_rd: begin // 讀取資料(8 bit)
if(st_done)
next_state = st_stop;
else
next_state = st_data_rd;
end
st_stop: begin // 結束I2C操作
if(st_done)
next_state = st_idle;
else
next_state = st_stop ;
end
default: next_state= st_idle;
endcase
end
//時序電路描述狀態輸出
always @(posedge dri_clk or negedge rst_n) begin
//復位初始化
if(!rst_n) begin
scl <= 1'b1;
sda_out <= 1'b1;
sda_dir <= 1'b1;
i2c_done <= 1'b0;
cnt <= 1'b0;
st_done <= 1'b0;
data_r <= 1'b0;
i2c_data_r <= 1'b0;
wr_flag <= 1'b0;
addr_t <= 1'b0;
data_wr_t <= 1'b0;
end
else begin
st_done <= 1'b0 ;
cnt <= cnt +1'b1 ;
case(cur_state)
st_idle: begin // 空閑狀態
scl <= 1'b1;
sda_out <= 1'b1;
sda_dir <= 1'b1;
i2c_done<= 1'b0;
cnt <= 7'b0;
if(i2c_exec) begin
wr_flag <= i2c_rh_wl ;
addr_t <= i2c_addr ;
data_wr_t <= i2c_data_w;
end
end
st_sladdr: begin // 寫地址(器件地址和字地址)
case(cnt)
7'd1 : sda_out <= 1'b0; // 開始I2C
7'd3 : scl <= 1'b0;
7'd4 : sda_out <= SLAVE_ADDR[6]; // 傳送器件地址
7'd5 : scl <= 1'b1;
7'd7 : scl <= 1'b0;
7'd8 : sda_out <= SLAVE_ADDR[5];
7'd9 : scl <= 1'b1;
7'd11: scl <= 1'b0;
7'd12: sda_out <= SLAVE_ADDR[4];
7'd13: scl <= 1'b1;
7'd15: scl <= 1'b0;
7'd16: sda_out <= SLAVE_ADDR[3];
7'd17: scl <= 1'b1;
7'd19: scl <= 1'b0;
7'd20: sda_out <= SLAVE_ADDR[2];
7'd21: scl <= 1'b1;
7'd23: scl <= 1'b0;
7'd24: sda_out <= SLAVE_ADDR[1];
7'd25: scl <= 1'b1;
7'd27: scl <= 1'b0;
7'd28: sda_out <= SLAVE_ADDR[0];
7'd29: scl <= 1'b1;
7'd31: scl <= 1'b0;
7'd32: sda_out <= 1'b0; // 0:寫
7'd33: scl <= 1'b1;
7'd35: scl <= 1'b0;
7'd36: begin
sda_dir <= 1'b0; // 從機應答
sda_out <= 1'b1;
end
7'd37: scl <= 1'b1;
7'd38: st_done <= 1'b1;
7'd39: begin
scl <= 1'b0;
cnt <= 1'b0;
end
default : ;
endcase
end
st_addr16: begin
case(cnt)
7'd0 : begin
sda_dir <= 1'b1 ;
sda_out <= addr_t[15]; // 傳送字地址
end
7'd1 : scl <= 1'b1;
7'd3 : scl <= 1'b0;
7'd4 : sda_out <= addr_t[14];
7'd5 : scl <= 1'b1;
7'd7 : scl <= 1'b0;
7'd8 : sda_out <= addr_t[13];
7'd9 : scl <= 1'b1;
7'd11: scl <= 1'b0;
7'd12: sda_out <= addr_t[12];
7'd13: scl <= 1'b1;
7'd15: scl <= 1'b0;
7'd16: sda_out <= addr_t[11];
7'd17: scl <= 1'b1;
7'd19: scl <= 1'b0;
7'd20: sda_out <= addr_t[10];
7'd21: scl <= 1'b1;
7'd23: scl <= 1'b0;
7'd24: sda_out <= addr_t[9];
7'd25: scl <= 1'b1;
7'd27: scl <= 1'b0;
7'd28: sda_out <= addr_t[8];
7'd29: scl <= 1'b1;
7'd31: scl <= 1'b0;
7'd32: begin
sda_dir <= 1'b0; // 從機應答
sda_out <= 1'b1;
end
7'd33: scl <= 1'b1;
7'd34: st_done <= 1'b1;
7'd35: begin
scl <= 1'b0;
cnt <= 1'b0;
end
default : ;
endcase
end
st_addr8: begin
case(cnt)
7'd0: begin
sda_dir <= 1'b1 ;
sda_out <= addr_t[7]; // 字地址
end
7'd1 : scl <= 1'b1;
7'd3 : scl <= 1'b0;
7'd4 : sda_out <= addr_t[6];
7'd5 : scl <= 1'b1;
7'd7 : scl <= 1'b0;
7'd8 : sda_out <= addr_t[5];
7'd9 : scl <= 1'b1;
7'd11: scl <= 1'b0;
7'd12: sda_out <= addr_t[4];
7'd13: scl <= 1'b1;
7'd15: scl <= 1'b0;
7'd16: sda_out <= addr_t[3];
7'd17: scl <= 1'b1;
7'd19: scl <= 1'b0;
7'd20: sda_out <= addr_t[2];
7'd21: scl <= 1'b1;
7'd23: scl <= 1'b0;
7'd24: sda_out <= addr_t[1];
7'd25: scl <= 1'b1;
7'd27: scl <= 1'b0;
7'd28: sda_out <= addr_t[0];
7'd29: scl <= 1'b1;
7'd31: scl <= 1'b0;
7'd32: begin
sda_dir <= 1'b0; // 從機應答
sda_out <= 1'b1;
end
7'd33: scl <= 1'b1;
7'd34: st_done <= 1'b1;
7'd35: begin
scl <= 1'b0;
cnt <= 1'b0;
end
default : ;
endcase
end
st_data_wr: begin // 寫資料(8 bit)
case(cnt)
7'd0: begin
sda_out <= data_wr_t[7]; // I2C寫8位資料
sda_dir <= 1'b1;
end
7'd1 : scl <= 1'b1;
7'd3 : scl <= 1'b0;
7'd4 : sda_out <= data_wr_t[6];
7'd5 : scl <= 1'b1;
7'd7 : scl <= 1'b0;
7'd8 : sda_out <= data_wr_t[5];
7'd9 : scl <= 1'b1;
7'd11: scl <= 1'b0;
7'd12: sda_out <= data_wr_t[4];
7'd13: scl <= 1'b1;
7'd15: scl <= 1'b0;
7'd16: sda_out <= data_wr_t[3];
7'd17: scl <= 1'b1;
7'd19: scl <= 1'b0;
7'd20: sda_out <= data_wr_t[2];
7'd21: scl <= 1'b1;
7'd23: scl <= 1'b0;
7'd24: sda_out <= data_wr_t[1];
7'd25: scl <= 1'b1;
7'd27: scl <= 1'b0;
7'd28: sda_out <= data_wr_t[0];
7'd29: scl <= 1'b1;
7'd31: scl <= 1'b0;
7'd32: begin
sda_dir <= 1'b0; // 從機應答
sda_out <= 1'b1;
end
7'd33: scl <= 1'b1;
7'd34: st_done <= 1'b1;
7'd35: begin
scl <= 1'b0;
cnt <= 1'b0;
end
default : ;
endcase
end
st_addr_rd: begin // 寫地址以進行讀資料
if(delay_done) begin
case(cnt)
7'd0 : begin
sda_dir <= 1'b1;
sda_out <= 1'b1;
end
7'd1 : scl <= 1'b1;
7'd2 : sda_out <= 1'b0; // 重新開始
7'd3 : scl <= 1'b0;
7'd4 : sda_out <= SLAVE_ADDR[6]; // 傳送器件地址
7'd5 : scl <= 1'b1;
7'd7 : scl <= 1'b0;
7'd8 : sda_out <= SLAVE_ADDR[5];
7'd9 : scl <= 1'b1;
7'd11: scl <= 1'b0;
7'd12: sda_out <= SLAVE_ADDR[4];
7'd13: scl <= 1'b1;
7'd15: scl <= 1'b0;
7'd16: sda_out <= SLAVE_ADDR[3];
7'd17: scl <= 1'b1;
7'd19: scl <= 1'b0;
7'd20: sda_out <= SLAVE_ADDR[2];
7'd21: scl <= 1'b1;
7'd23: scl <= 1'b0;
7'd24: sda_out <= SLAVE_ADDR[1];
7'd25: scl <= 1'b1;
7'd27: scl <= 1'b0;
7'd28: sda_out <= SLAVE_ADDR[0];
7'd29: scl <= 1'b1;
7'd31: scl <= 1'b0;
7'd32: sda_out <= 1'b1; // 1:讀
7'd33: scl <= 1'b1;
7'd35: scl <= 1'b0;
7'd36: begin
sda_dir <= 1'b0; // 從機應答
sda_out <= 1'b1;
end
7'd37: scl <= 1'b1;
7'd38: st_done <= 1'b1;
7'd39: begin
scl <= 1'b0;
cnt <= 1'b0;
end
default : ;
endcase
end
end
st_data_rd: begin // 讀取資料(16 bit)
case(cnt)
7'd0: sda_dir <= 1'b0;
7'd1: begin
data_r[15] <= sda_in;
scl <= 1'b1;
end
7'd3: scl <= 1'b0;
7'd5: begin
data_r[14] <= sda_in ;
scl <= 1'b1 ;
end
7'd7: scl <= 1'b0;
7'd9: begin
data_r[13] <= sda_in;
scl <= 1'b1 ;
end
7'd11: scl <= 1'b0;
7'd13: begin
data_r[12] <= sda_in;
scl <= 1'b1 ;
end
7'd15: scl <= 1'b0;
7'd17: begin
data_r[11] <= sda_in;
scl <= 1'b1 ;
end
7'd19: scl <= 1'b0;
7'd21: begin
data_r[10] <= sda_in;
scl <= 1'b1 ;
end
7'd23: scl <= 1'b0;
7'd25: begin
data_r[9] <= sda_in;
scl <= 1'b1 ;
end
7'd27: scl <= 1'b0;
7'd29: begin
data_r[8] <= sda_in;
scl <= 1'b1 ;
end
7'd31: begin
data_r[7] <= sda_in;
scl <= 1'b1;
end
7'd33: scl <= 1'b0;
7'd35: begin
data_r[6] <= sda_in ;
scl <= 1'b1 ;
end
7'd37: scl <= 1'b0;
7'd39: begin
data_r[5] <= sda_in;
scl <= 1'b1 ;
end
7'd41: scl <= 1'b0;
7'd43: begin
data_r[4] <= sda_in;
scl <= 1'b1 ;
end
7'd45: scl <= 1'b0;
7'd47: begin
data_r[3] <= sda_in;
scl <= 1'b1 ;
end
7'd49: scl <= 1'b0;
7'd51: begin
data_r[2] <= sda_in;
scl <= 1'b1 ;
end
7'd53: scl <= 1'b0;
7'd55: begin
data_r[1] <= sda_in;
scl <= 1'b1 ;
end
7'd57: scl <= 1'b0;
7'd59: begin
data_r[0] <= sda_in;
scl <= 1'b1 ;
end
7'd61: scl <= 1'b0;
7'd62: begin
sda_dir <= 1'b1; // 非應答
sda_out <= 1'b1;
end
7'd63: scl <= 1'b1;
7'd64: st_done <= 1'b1;
7'd65: begin
scl <= 1'b0;
cnt <= 1'b0;
i2c_data_r <= data_r;
end
default : ;
endcase
end
st_stop: begin // 結束I2C操作
case(cnt)
7'd0: begin
sda_dir <= 1'b1; // 結束I2C
sda_out <= 1'b0;
end
7'd1 : scl <= 1'b1;
7'd3 : sda_out <= 1'b1;
7'd15: st_done <= 1'b1;
7'd16: begin
cnt <= 1'b0;
i2c_done <= 1'b1; // 向上層模塊傳遞I2C結束信號
end
default : ;
endcase
end
endcase
end
end
endmodule
串口模塊
module uart_byte_tx(
Clk,
Rst,
data_byte,
send_en,
baud_set,
Rs232_Tx,
Tx_Done,
uart_state
);
input Clk;
input Rst;
input [15:0]data_byte;
input send_en;
input [2:0]baud_set;
output reg Rs232_Tx;
output reg Tx_Done;
output reg uart_state;
reg [15:0]div_cnt;//分頻計數器
reg bps_clk;//波特率時鐘
reg [15:0]bps_DR;//分頻計數最大值
reg [4:0]bps_cnt;//波特率時鐘計數器
reg [15:0]r_data_byte;
localparam start_bit = 1'b0;
localparam stop_bit = 1'b1;
always@(posedge Clk or negedge Rst)
if(!Rst)
uart_state <= 1'b0;
else if(send_en )
uart_state <= 1'b1;
else if(Tx_Done)
uart_state <= 1'b0;
else
uart_state <= uart_state;
always@(posedge Clk or negedge Rst)
if(!Rst)
r_data_byte <= 8'd0;
else if(send_en)
r_data_byte <= data_byte;
else
r_data_byte <= r_data_byte;
always@(posedge Clk or negedge Rst)
if(!Rst)
bps_DR <= 16'd5207;
else begin
case(baud_set)
0:bps_DR <= 16'd5207;
1:bps_DR <= 16'D2603;
2:bps_DR <= 16'd1301;
3:bps_DR <= 16'd867;
4:bps_DR <= 16'd433;
default:bps_DR <= 16'd5207;
endcase
end
//counter
always@(posedge Clk or negedge Rst)
if(!Rst)
div_cnt <= 16'd0;
else if(uart_state)begin
if(div_cnt == bps_DR)
div_cnt <= 16'd0;
else
div_cnt <=div_cnt + 1'b1;
end
else
div_cnt <= 16'd0;
//bps_clk
always@(posedge Clk or negedge Rst)
if(!Rst)
bps_clk <= 1'b0;
else if(div_cnt == 1'b1)
bps_clk <=1'b1;
else
bps_clk <= 1'b0;
always@(posedge Clk or negedge Rst)
if(!Rst)
bps_cnt <= 5'd0;
else if(Tx_Done)
bps_cnt <= 5'd0;
else if(bps_clk)
bps_cnt <= bps_cnt + 1'b1;
else
bps_cnt <= bps_cnt;
always@(posedge Clk or negedge Rst)
if(!Rst)
Tx_Done <= 1'b0;
else if(bps_cnt == 5'd21)
Tx_Done <= 1'b1;
else
Tx_Done <= 1'b0;
always@(posedge Clk or negedge Rst)
if(!Rst)
Rs232_Tx <= 1'b1;
else begin
case(bps_cnt)
0:Rs232_Tx <= 1'b1;
1:Rs232_Tx <= start_bit;
2:Rs232_Tx <= r_data_byte[8];
3:Rs232_Tx <= r_data_byte[9];
4:Rs232_Tx <= r_data_byte[10];
5:Rs232_Tx <= r_data_byte[11];
6:Rs232_Tx <= r_data_byte[12];
7:Rs232_Tx <= r_data_byte[13];
8:Rs232_Tx <= r_data_byte[14];
9:Rs232_Tx <= r_data_byte[15];
10:Rs232_Tx <= stop_bit;
11:Rs232_Tx <= 1'b1;
12:Rs232_Tx <= start_bit;
13:Rs232_Tx <= r_data_byte[0];
14:Rs232_Tx <= r_data_byte[1];
15:Rs232_Tx <= r_data_byte[2];
16:Rs232_Tx <= r_data_byte[3];
17:Rs232_Tx <= r_data_byte[4];
18:Rs232_Tx <= r_data_byte[5];
19:Rs232_Tx <= r_data_byte[6];
20:Rs232_Tx <= r_data_byte[7];
21:Rs232_Tx <= stop_bit;
default:Rs232_Tx <= 1'b1;
endcase
end
endmodule
頂層模塊
module BH1750_CTRL(
input clk,
input rst_n,
input key3,
output rx232_tx,
output scl,
inout sda
);
wire key_flag ;
wire key_state ;
wire start_en ; //按鍵啟動信號
wire en ; //定時1秒啟動
wire i2c_exec ; //I2C觸發執行信號
wire i2c_done ; //I2C暫存器配置完成信號
wire i2c_dri_clk ; //I2C操作時鐘
wire [15:0] i2c_data_r ; //I2C讀出資料
parameter SLAVE_ADDR = 7'h23 ; //BH1750的器件地址7'h3c
parameter BIT_CTRL = 1'b0 ; //位元組地址為8位 0:8位 1:16位
parameter CLK_FREQ = 26'd50_000_000; //時鐘頻率 50MHz
parameter I2C_FREQ = 18'd250_000 ; //I2C的SCL時鐘頻率,250KHz
assign start_en = key_flag && !key_state ;
i2c_dri
#(
.SLAVE_ADDR (SLAVE_ADDR), //引數傳遞
.CLK_FREQ (CLK_FREQ ),
.I2C_FREQ (I2C_FREQ )
)
u_i2c_dri(
.clk (clk ),
.rst_n (rst_n ),
.i2c_exec (start_en ),
.bit_ctrl (BIT_CTRL ),
.i2c_rh_wl (1'b1), //固定為讀操作
.i2c_addr (8'h10),
.i2c_data_w (0),
.i2c_data_r (i2c_data_r),
.i2c_done (i2c_done ),
.scl (scl ),
.sda (sda ),
.dri_clk (i2c_dri_clk) //I2C操作時鐘
);
uart_byte_tx u_uart_byte_tx(
.Clk (clk),
.Rst (rst_n),
.data_byte (i2c_data_r),
.send_en (i2c_done),
.baud_set (3'd0),
.Rs232_Tx (rx232_tx),
.Tx_Done (),
.uart_state()
);
key_filter u_key_filter(
.Clk (i2c_dri_clk),
.Rst_n (rst_n),
.key_in (key3),
.key_flag (key_flag),
.key_state(key_state)
);
endmodule
注意:按鍵消抖模塊的驅動時鐘使用IIC驅動模塊的輸出時鐘1MHz,如果使用50MHz的輸入時鐘,則按鍵啟動信號的高電平持續周期時間太短,可能不會被IIC模塊啟動信號捕捉到,從而導致按鍵按下,但IIC通信并未開始,
5. 驗證
將程式下載至開發板,將芯片模塊引腳連接好,打開串口除錯助手,波特率選擇9600,無檢驗位,資料位8位,1位停止位,按下按鍵,得到16位環境光強度資料,用光照射芯片,再按下按鍵,可以看到資料變大,多次測驗無誤,證明驗證成功,PS:得到的161位資料還需要轉換成十進制資料進行計算才可以得到光強資料,單位lx,請自行查閱手冊得到計算公式和引數,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/239577.html
標籤:其他
下一篇:施耐德開放自動化平臺初體驗(3)
