module exam #(
parameter [6:0] ADXL_ADDR = 7'h53 // SDO=0->0x53, SDO=1->0x1D
)(
input wire clk_12m,
input wire rst_n,
output reg scl,
inout wire sda,
// 数码管1(共阴极,段选高有效)
output reg seg_a1,
output reg seg_b1,
output reg seg_c1,
output reg seg_d1,
output reg seg_e1,
output reg seg_f1,
output reg seg_g1,
output reg seg_dp1,
output reg seg_dig1 // 组选通,低有效
);
// ============================================================
// 数码管:固定显示 "1",DP 表示 i2c_ok
// ============================================================
reg i2c_ok;
always @(*) begin
seg_dig1 = 1'b0; // 使能数码管1(低有效)
// "1":b、c 亮(共阴极:1=亮)
seg_a1 = 1'b0;
seg_b1 = 1'b1;
seg_c1 = 1'b1;
seg_d1 = 1'b0;
seg_e1 = 1'b0;
seg_f1 = 1'b0;
seg_g1 = 1'b0;
seg_dp1 = i2c_ok; // 成功点亮小数点
end
// ============================================================
// I2C half tick: 12MHz -> 100kHz (half period = 60 cycles)
// ============================================================
reg [6:0] div_cnt; // 0..59
reg tick;
always @(posedge clk_12m or negedge rst_n) begin
if (!rst_n) begin
div_cnt <= 7'd0;
tick <= 1'b0;
end else if (div_cnt == 7'd59) begin
div_cnt <= 7'd0;
tick <= 1'b1;
end else begin
div_cnt <= div_cnt + 7'd1;
tick <= 1'b0;
end
end
// ============================================================
// SDA open-drain
// ============================================================
reg sda_oe, sda_out;
assign sda = sda_oe ? sda_out : 1'bz;
wire sda_in = sda;
// ============================================================
// I2C state machine: read DEVID(0x00)
// ============================================================
localparam ST_IDLE = 4'd0;
localparam ST_START = 4'd1;
localparam ST_SEND = 4'd2;
localparam ST_ACK = 4'd3;
localparam ST_RESTART = 4'd4;
localparam ST_READ = 4'd5;
localparam ST_READNACK = 4'd6;
localparam ST_STOP = 4'd7;
localparam ST_CHECK = 4'd8;
reg [3:0] st;
reg [7:0] tx;
reg [7:0] rx;
reg [2:0] bitn; // 7..0
reg phase; // 0:SCL low, 1:SCL high
reg nack_seen;
reg [1:0] seq; // 0:ADDRW, 1:REG, 2:ADDRR
wire [7:0] ADDR_W = {ADXL_ADDR, 1'b0};
wire [7:0] ADDR_R = {ADXL_ADDR, 1'b1};
always @(posedge clk_12m or negedge rst_n) begin
if (!rst_n) begin
scl <= 1'b1;
sda_oe <= 1'b0;
sda_out <= 1'b1;
st <= ST_IDLE;
tx <= 8'h00;
rx <= 8'h00;
bitn <= 3'd7;
phase <= 1'b0;
nack_seen <= 1'b0;
seq <= 2'd0;
i2c_ok <= 1'b0;
end else if (tick) begin
case (st)
ST_IDLE: begin
scl <= 1'b1;
sda_oe <= 1'b0; // release SDA
sda_out <= 1'b1;
phase <= 1'b0;
bitn <= 3'd7;
rx <= 8'h00;
nack_seen <= 1'b0;
seq <= 2'd0;
st <= ST_START;
end
ST_START: begin
// START: SDA 1->0 while SCL=1
scl <= 1'b1;
sda_oe <= 1'b1;
sda_out <= 1'b0;
tx <= ADDR_W;
bitn <= 3'd7;
phase <= 1'b0;
st <= ST_SEND;
end
ST_SEND: begin
if (!phase) begin
// SCL low: set data bit
scl <= 1'b0;
sda_oe <= 1'b1;
sda_out <= tx[bitn];
phase <= 1'b1;
end else begin
// SCL high: slave samples
scl <= 1'b1;
phase <= 1'b0;
if (bitn == 3'd0)
st <= ST_ACK;
else
bitn <= bitn - 3'd1;
end
end
ST_ACK: begin
if (!phase) begin
// SCL low: release SDA
scl <= 1'b0;
sda_oe <= 1'b0;
sda_out <= 1'b1;
phase <= 1'b1;
end else begin
// SCL high: sample ACK (0=ACK, 1=NACK)
scl <= 1'b1;
if (sda_in) nack_seen <= 1'b1;
phase <= 1'b0;
if (seq == 2'd0) begin
// after ADDR_W
tx <= 8'h00; // DEVID reg
bitn <= 3'd7;
seq <= 2'd1;
st <= ST_SEND;
end else if (seq == 2'd1) begin
// after reg
st <= ST_RESTART;
end else begin
// after ADDR_R
bitn <= 3'd7;
rx <= 8'h00;
st <= ST_READ;
end
end
end
ST_RESTART: begin
// repeated START in 2 ticks
if (!phase) begin
scl <= 1'b1;
sda_oe <= 1'b0; // release SDA -> high
sda_out <= 1'b1;
phase <= 1'b1;
end else begin
scl <= 1'b1;
sda_oe <= 1'b1;
sda_out <= 1'b0; // pull low -> repeated START
phase <= 1'b0;
tx <= ADDR_R;
bitn <= 3'd7;
seq <= 2'd2;
st <= ST_SEND;
end
end
ST_READ: begin
if (!phase) begin
// SCL low: release SDA
scl <= 1'b0;
sda_oe <= 1'b0;
sda_out <= 1'b1;
phase <= 1'b1;
end else begin
// SCL high: sample data
scl <= 1'b1;
rx[bitn] <= sda_in;
phase <= 1'b0;
if (bitn == 3'd0)
st <= ST_READNACK;
else
bitn <= bitn - 3'd1;
end
end
ST_READNACK: begin
// master NACK: drive SDA=1 on 9th clock
if (!phase) begin
scl <= 1'b0;
sda_oe <= 1'b1;
sda_out <= 1'b1; // NACK
phase <= 1'b1;
end else begin
scl <= 1'b1;
phase <= 1'b0;
st <= ST_STOP;
end
end
ST_STOP: begin
// STOP: SDA 0->1 while SCL=1
if (!phase) begin
scl <= 1'b0;
sda_oe <= 1'b1;
sda_out <= 1'b0;
phase <= 1'b1;
end else begin
scl <= 1'b1;
sda_oe <= 1'b0; // release SDA -> rises due to pull-up
sda_out <= 1'b1;
phase <= 1'b0;
st <= ST_CHECK;
end
end
/*ST_CHECK: begin
i2c_ok <= (!nack_seen) && (rx == 8'hE5);
st <= ST_IDLE;
end*/
ST_CHECK: begin
// 暂时只测试 ACK,不管读回来的数据对错
i2c_ok <= !nack_seen; // 只要收到ACK就亮小数点
st <= ST_IDLE;
end
default: st <= ST_IDLE;
endcase
end
end
endmodule
以上为代码部分,用板子上的数码管是否显示小数点判断信号是否有传输,但是一直都没能看到小数点显示

图片里是板子外接了一个传感器,管脚分配和接线应该都没问题,硬件应该也都是好的
希望能帮忙找找问题,帮忙解答谢谢