FPGA模块——IIC协议(读写PCF8591)
FPGA模块——IIC协议(读取PCF8591)
- PCF8591/AT8591芯片
- 对iic协议的使用
PCF8591/AT8591芯片
低功耗8位CMOS数据采集设备,4路模拟输入,1路模拟输出,分时多路复用,读取数据用串型iic总线接口,最大100khz。
控制字节(iic中写寄存器地址位8b)
这个芯片中是有自己要求的,但是也符合iic协议的时序。
stop之前最后一步:
写的8位数据就是DAC转换得到的电压值,
读的数据就是ADC转换得到的8位数据
对iic协议的使用
iic协议就看这个之前写的:链接: IIC协议模块
module pcf8591(
//clock and reset
input clk , // 时钟信号
input rst_n , // 复位信号
//i2c interface
output reg i2c_rh_wl , // I2C读写控制信号
output reg i2c_exec , // I2C触发执行信号
output reg [15:0] i2c_addr , // I2C器件内地址
output reg [ 7:0] i2c_data_w , // I2C要写的数据
input [ 7:0] i2c_data_r , // I2C读出的数据
input i2c_done , // I2C一次操作完成
//user interface
output reg [19:0] num // 数码管要显示的数据
);
//parameter
parameter CONTORL_BYTE = 8'b0100_0001; // PCF8591的控制字
parameter V_REF = 12'd3300 ; // 3.3V放大1000倍,避免用小数
//reg define
reg [7:0] da_data ; // DA数据
reg [7:0] ad_data ; // AD数据
reg [3:0] flow_cnt ; // 状态流控制
reg [18:0] wait_cnt ; // 计数等待
//wire define
wire [19:0] num_t ; // 临时寄存的数据
//*****************************************************
//** main code
//*****************************************************
assign num_t = V_REF * ad_data ;
//DA输出数据
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) begin
da_data <= 8'd0;
end
else if(i2c_rh_wl == 1'b0 & i2c_done == 1'b1)begin
if(da_data == 8'd255)
da_data<= 8'd0;
else
da_data<= da_data + 1'b1;
end
end
//AD输入数据处理
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) begin
num <= 20'd0;
end
else
num <= num_t >> 4'd8;
end
//AD、DA控制及采样
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) begin
i2c_exec <= 1'b0;
i2c_rh_wl<= 1'b0;
i2c_addr <= 8'd0;
i2c_data_w <= 8'd0;
flow_cnt <= 4'd0;
wait_cnt <= 17'd0;
end
else begin
i2c_exec <= 1'b0;
case(flow_cnt)
'd0: begin
if(wait_cnt == 17'd100) begin
wait_cnt<= 17'd0;
flow_cnt<= flow_cnt + 1'b1;
end
else
wait_cnt<= wait_cnt + 1'b1;
end
//DA转换输出
'd1: begin
i2c_exec <= 1'b1;
i2c_addr <= CONTORL_BYTE;
i2c_rh_wl <= 1'b0;
i2c_data_w<= da_data;
flow_cnt <= flow_cnt + 1'b1;
end
'd2: begin
if(i2c_done == 1'b1) begin
flow_cnt<= flow_cnt + 1'b1;
end
end
'd3: begin
//每1秒变化0.1V,需33秒变化完,共256【0~255】次变化,故每次变化计数为:
//(33/256)*10^6 = 128906
if(wait_cnt == 17'd128906) begin
wait_cnt<= 17'd0;
flow_cnt<= flow_cnt + 1'b1;
end
else
wait_cnt<= wait_cnt + 1'b1;
end
//AD转换输入
'd4: begin
i2c_exec <= 1'b1;
i2c_addr <= CONTORL_BYTE;
i2c_rh_wl <= 1'b1;
flow_cnt <= flow_cnt + 1'b1;
end
'd5: begin
if(i2c_done == 1'b1) begin
ad_data <= i2c_data_r;
flow_cnt<= 4'd0;
end
end
default: flow_cnt <= 4'd0;
endcase
end
end
endmodule