微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > FPGA,CPLD和ASIC > 用verilog实现IIC。

用verilog实现IIC。

时间:10-02 整理:3721RD 点击:
我想用verilog实现一个控制AT24C08读写的IIC协议的状态机,现在出现了一个很奇怪的问题,我的状态机在功能仿真时可以实现读写,但下到芯片里却发现不成功。特此求教大家,望大家不吝赐教,如能解答问题,鄙人十分感激。关于代码的详细内如下
/*这是一个控制AT24C08读写的基于IIC协议的状态机,具体功能是,向AT24C08输入一个数,再把这个数读回来。
输入的数和读回的数分别用一位数码管显示。IIC的实现思路是将SCL时钟分成四段,操作SDA变换。*/
module i2c_controller_top(write,read,datain,clock,rst,scl,sda,seg,dig);
        input clock,rst;
        input[3:0]datain;//数据输入端
        input write,read;//控制读写的按键
       
        output reg [7:0] seg;//数码管段信号
        output reg[1:0]dig;//数码管位信号
        output reg scl;
        inout wire sda;
//--------------数码管显示部分---------------//       
        reg clk_dig;//数码管动态显示时钟
        reg[15:0]cnt1;//数码管显示用的分频系数
        reg[7:0]seg_code;//数码管显示译码器的输入码
        //reg st;
        reg [7:0]dout,dout_buf;//数据输出端及其缓冲器(输出从AT24C08读回的数据)
        wire[7:0]din;//主状态机的数据输入端
        always@(posedge clock or negedge rst)begin //产生数码管动态显示时钟       
                if(!rst) begin
                        cnt1<=0;
                        clk_dig<=0;
                end
                else if (cnt1==16'd50000)begin
                        cnt1<=0;
                        clk_dig<=~clk_dig;
                end
                else cnt1<=cnt1+16'd1;
        end
       
        always@(seg_code)begin//数码管显示译码器
                case(seg_code)
                        8'd0:seg=8'hc0;
                        8'd1:seg=8'hf9;
                        8'd2:seg=8'ha4;
                        8'd3:seg=8'hb0;
                        8'd4:seg=8'h99;
                        8'd5:seg=8'h92;
                        8'd6:seg=8'h82;
                        8'd7:seg=8'hf8;
                        8'd8:seg=8'h80;
                        8'd9:seg=8'h90;
                        8'd10:seg=8'h88;
                        8'd11:seg=8'h83;
                        8'd12:seg=8'hc6;
                        8'd13:seg=8'ha1;
                        8'd14:seg=8'h86;
                        8'd15:seg=8'h8e;
                        default:seg=0;
                endcase
        end
        always@(posedge clk_dig or negedge rst)begin//数码管显示
                if(!rst)
                        //st<=0;
                        dig<=2'b10;
                else begin
                        //st<=~st;
                        dig<=~dig;
                        case(dig)
                                2'd1:begin seg_code<=din;end
                                2'd2:begin seg_code<=dout;end
                        endcase
                end
        end
//--------------状态机部分------------//       
        reg sel;//sda三态输出选择端
        reg sda_buf;
        reg[7:0]send_dat;//数据发送缓冲器
        reg[6:0] cnt2;//产生i2c状态机时钟的分频计数器
        reg clk_iic;//状态机时钟
        reg[19:0] in_state;//内部状态
        reg[1:0] state;//主状态
        reg[2:0]dcnt;//数据位计数器
        reg[1:0]wcmd;//发送内容控制命令端,详见最下方always块
        reg rw;//读写标志
        parameter ba=8'b00000010,//字节地址
                                 saw=8'b10100000,//从机地址(写)
                  sar=8'b10100001;//从机地址(读)
       
        assign din={4'd0,datain};
        assign sda=sel?sda_buf:1'bz;//sda三态输出
/* 状态编码*/
        parameter idle=2'b00,//空闲状态
                                 send=2'b01,//发送状态
                                 recv=2'b10;//接受状态
        parameter write_a=20'b0000_0000_0000_0000_0001,//写状态
                                 write_b=20'b0000_0000_0000_0000_0010,
                                 write_c=20'b0000_0000_0000_0000_0100,
                                 write_d=20'b0000_0000_0000_0000_1000;
        parameter read_a=20'b0000_0000_0000_0001_0000,//读状态
                                 read_b=20'b0000_0000_0000_0010_0000,
                                 read_c=20'b0000_0000_0000_0100_0000,
                                 read_d=20'b0000_0000_0000_1000_0000;
        parameter sta_a=20'b0000_0000_0001_0000_0000,//开始
                                 sta_b=20'b0000_0000_0010_0000_0000,
                                 sta_c=20'b0000_0000_0100_0000_0000,
                                 sta_d=20'b0000_0000_1000_0000_0000,
                                 sto_a=20'b0000_0001_0000_0000_0000,//结束
                                 sto_b=20'b0000_0010_0000_0000_0000,
                                 sto_c=20'b0000_0100_0000_0000_0000,
                                 sto_d=20'b0000_1000_0000_0000_0000;
        parameter ack_a=20'b0001_0000_0000_0000_0000,//响应
                                 ack_b=20'b0010_0000_0000_0000_0000,
                                 ack_c=20'b0100_0000_0000_0000_0000,
                                 ack_d=20'b1000_0000_0000_0000_0000;
       
        always@(posedge clock or negedge rst)begin//产生IIC状态机时钟
                if(!rst)begin
                        cnt2<=0;
                        clk_iic<=0;
                end
                else if(cnt2==7'd24)begin
                        cnt2<=0;
                        clk_iic<=1;
                end
                else begin
                        cnt2<=cnt2+7'd1;
                        clk_iic<=0;
                end
        end
       
        always@(posedge clk_iic or negedge rst)begin       
                if(!rst) begin
                        sel<=1;
                        state<=idle;
                        wcmd<=0;
                        scl<=1;
                        sda_buf<=1;
                        dcnt<=7;
                        rw<=0;
                end
                else begin
                case(state)
                idle: begin
                                        if(!write) begin//如果write键被按下了,rw=0,进入发送状态
                                                state<=send;
                                                rw<=0;
                                        end
                                        else if(!read)begin
                                                rw<=1;
                                                state<=recv;
                                        end
                                        else state<=idle;
                                        //rw<=0;
                                        wcmd<=0;
                                        dcnt<=7;
                                        in_state<=sta_a;
                                end
                send: begin//发送状态机
                                case(in_state)
                                        sta_a:        begin
                                                                        sel<=1;
                                                                        scl<=1;
                                                                        sda_buf<=1;
                                                                        in_state<=sta_b;
                                                                end
                                        sta_b:        begin
                                                                        scl<=1;
                                                                        sda_buf<=0;
                                                                        in_state<=sta_c;
                                                                end
                                        sta_c:        begin
                                                                        scl<=1;
                                                                        sda_buf<=0;
                                                                        in_state<=sta_d;
                                                                end
                                        sta_d:        begin
                                                                        scl<=0;
                                                                        sda_buf<=0;
                                                                        in_state<=write_a;
                                                                        //if(wcmd==3'd2)
//                                                                                wcmd<=0;
//                                                                        else sim:/IIC_top/u2/wcmd sim:/IIC_top/u2/send_dat sim:/IIC_top/u2/saw sim:/IIC_top/u2/ba sim:/IIC_top/u2/din
//                                                                                wcmd<=wcmd+2'b1;
//                                                                        case(wcmd)
//                                                                                3'd0:send_dat<=saw;
//                                                                                3'd1:send_dat<=ba;
//                                                                                3'd2:begin send_dat<=din;end
//                                                                        endcase
                                                                end
                                        write_a: begin       
                                                                        sel<=1;
                                                                        scl<=0;
                                                                        sda_buf<=send_dat[dcnt];
//                                                                        if(wcmd==3'd2)
//                                                                                wcmd<=0;
//                                                                        else
                                                                                //wcmd<=wcmd+2'b1;
//                                                                        case(wcmd)
//                                                                                3'd0:send_dat<=saw;
//                                                                                3'd1:send_dat<=ba;
//                                                                                3'd2:begin send_dat<=din;end
//                                                                        endcase
                                                                        in_state<=write_b;
                                                                end
                                        write_b: begin
                                                                        scl<=1;
                                                                        sda_buf<=send_dat[dcnt];
                                                                        in_state<=write_c;
                                                                end
                                        write_c: begin
                                                                        scl<=1;
                                                                        sda_buf<=send_dat[dcnt];
                                                                        in_state<=write_d;
                                                                end
                                        write_d: begin
                                                                        scl<=0;
                                                                        sda_buf<=send_dat[dcnt];                                                               
                                                                        if(dcnt==0)begin//判断数据是否发送完,送完则进入响应状态,否则继续发送
                                                                                dcnt<=7;
                                                                                in_state<=ack_a;
                                                                        end
                                                                        else begin
                                                                                dcnt<=dcnt-3'b1;
                                                                                in_state<=write_a;
                                                                        end
                                                                end
                                        ack_a:        begin
                                                                        sel<=0;
                                                                        scl<=0;
                                                                         in_state<=ack_b;
                                                                end
                                        ack_b:        begin
                                                                        sel<=0;
                                                                        scl<=1;
                                                                        in_state<=ack_c;
                                                                end
                                        ack_c:        begin
                                                                        sel<=0;
                                                                        scl<=1;
                                                                        in_state<=ack_d;
                                                                end
                                        ack_d:        begin
                                                                        scl<=0;
                                                                        if(sda==0)begin//判断从机是否响应
                                                                          wcmd<=wcmd+2'b1;
                                                                                if(wcmd<2)
                                                                                        in_state<=write_a;
                                                                                else begin in_state<=sto_a; wcmd <=0;end
                                                                        end
                                                                        else in_state<=ack_d;
                                                                end
                                        sto_a:        begin
                                                                        sel<=1;
                                                                        scl<=0;
                                                                        sda_buf<=0;
                                                                        in_state<=sto_b;
                                                                end
                                        sto_b:        begin
                                                                        scl<=1;
                                                                        sda_buf<=0;
                                                                        in_state<=sto_c;
                                                                end
                                        sto_c:        begin       
                                                                        scl<=1;
                                                                        sda_buf<=0;
                                                                        in_state<=sto_d;
                                                                end
                                        sto_d:        begin
                                                                        scl<=1;
                                                                        sda_buf<=1;
                                                                        state<=idle;
                                                                        in_state<=sta_a;
                                                                end
                                endcase
                                end
                               
                recv:        begin//接收状态机
                                case(in_state)
                                        sta_a:        begin
                                                                        sel<=1;
                                                                        scl<=0;
                                                                        sda_buf<=1;
                                                                        in_state<=sta_b;
                                                                end
                                        sta_b:        begin
                                                                        scl<=1;
                                                                        sda_buf<=1;
                                                                        in_state<=sta_c;
                                                                end
                                        sta_c:        begin
                                                                        scl<=1;
                                                                        sda_buf<=0;
                                                                        in_state<=sta_d;
                                                                end
                                        sta_d:        begin
                                                                        scl<=0;
                                                                        sda_buf<=0;
                                                                        in_state<=write_a;
                                                                        if(wcmd==3)
                                                                                in_state<=read_a;
                                                                end
                                        write_a:        begin
                                                                        sel<=1;
                                                                        scl<=0;
                                                                        sda_buf<=send_dat[dcnt];
                                                                        in_state<=write_b;
                                                                end
                                        write_b:        begin
                                                                        scl<=1;
                                                                        sda_buf<=send_dat[dcnt];
                                                                        in_state<=write_c;
                                                                end
                                        write_c:        begin
                                                                        scl<=1;
                                                                        sda_buf<=send_dat[dcnt];
                                                                        in_state<=write_d;
                                                                end
                                        write_d:        begin
                                                                        scl<=0;
                                                                        sda_buf<=send_dat[dcnt];
                                                                        in_state<=ack_a;
                                                                        if(dcnt==0)begin
                                                                                in_state<=ack_a;
                                                                                dcnt<=7;
                                                                        end
                                                                        else begin
                                                                                in_state<=write_a;
                                                                                dcnt<=dcnt-3'd1;
                                                                        end
                                                                end
                                        ack_a:        begin
                                                                        sel<=0;
                                                                        scl<=0;
                                                                        sda_buf<=1;
                                                                        in_state<=ack_b;
                                                                end
                                        ack_b:        begin
                                                                        sel<=0;
                                                                        scl<=1;
                                                                        in_state<=ack_c;
                                                                end
                                        ack_c:        begin
                                                                        sel<=0;
                                                                        scl<=1;
                                                                        in_state<=ack_d;
                                                                end
                                        ack_d:        begin
                                                                        sel<=0;
                                                                        scl<=0;
                                                                        if(sda==0)begin
                                                                          wcmd<=wcmd+2'b1;
                                                                                if(wcmd==0)
                                                                                        in_state<=write_a;
                                                                                else if(wcmd==1)begin
          &nb

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top