视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
Verilog程序8、I2C通信协议
2025-09-25 03:15:51 责编:小OO
文档


接口定义

状态机:

状态机涉及的变量有:

        reg [3:0] cstate;

        reg sda_r;

        reg sda_link;

        reg [3:0] num;

        reg [7:0] db_r;

        reg [7:0] read_data;

没有仿真、没有下载测试。解决方法:可以从杨老师那里自己焊一个板子来试验。

`timescale 1ns / 1ps

//////////////////////////////////////////////////////////////////////////////////

// Company:

// Engineer:

//

// Create Date:    09:36:37 11/15/2010

// Design Name:

// Module Name:    i2c

// Project Name:

// Target Devices:

// Tool versions:

// Description:

//

// Dependencies:

//

// Revision:

// Revision 0.01 - File Created

// Additional Comments:

//

//////////////////////////////////////////////////////////////////////////////////

module i2c(clk,rst_n,bu1,bu2,scl,sda,out_data);

        input clk,rst_n,bu1,bu2;                //bu1:按下执行写入.bu2:按下执行读取.

        output scl;

        output [7:0] out_data;

        inout sda;

        

        //按键部分

        reg [19:0] cnt_20ms;            //20ms的定时器

        reg bu1_r,bu2_r;

        

        always @(posedge clk or negedge rst_n)

        if(!rst_n)

                cnt_20ms <= 1'b0;

        else

                cnt_20ms <= cnt_20ms + 1'd1;

        

        

        always @(posedge clk or negedge rst_n)

                if(!rst_n)

                begin

                        bu1_r <= 1'b0;

                        bu1_r <= 1'b0;

                end

                else if(cnt_20ms == 20'hf_ffff)

                begin

                        bu1_r <= bu1;

                        bu2_r <= bu2;

                end     

        

        //分频中的计数

        reg [8:0] cnt_delay;

        reg [2:0] cnt;

        

        always @(posedge clk or negedge rst_n)

                if(!rst_n)

                        cnt_delay <= 1'd0;

                else if(cnt_delay == 9'd499)

                        cnt_delay <= 1'd0;

                else

                        cnt_delay <= cnt_delay+1;

                        

        //获取捕捉的点

        always @(posedge clk or negedge rst_n)

                if(!rst_n)

                        cnt <= 3'd5;

                else

                begin

                        case(cnt_delay)

                                9'd125: cnt <= 3'd1;            //高电片的中间时刻

                                9'd249: cnt <= 3'd2;            //下降沿

                                9'd375: cnt <= 3'd3;            //低电平的中间时刻

                                9'd499: cnt <= 3'd0;            //上升沿

                                default: cnt <= 3'd5;

                        endcase

                end

        `define scl_pos (cnt == 3'd0)

        `define scl_high (cnt == 3'd1)

        `define scl_neg (cnt == 3'd2)

        `define scl_low (cnt == 3'd3)

        

        //EEPRom时钟的产生

        reg scl_r;

        

        always @(posedge clk or negedge rst_n)

                if(!rst_n)

                        scl_r <= 3'd0;

                else if(`scl_pos)

                        scl_r <= 3'd1;

                else if(`scl_neg)

                        scl_r <= 3'd0;

        assign scl = scl_r;             

        

        //写入iic的地址和数据

        `define DEVICE_READ 8'b1010_0001

        `define DEVICE_WRITE 8'b1010_0000

        `define WRITE_DATA 8'b1101_0001

        `define BYTE_ADDR 8'b0000_0011

        

        reg [7:0] db_r;         //数据寄存器,存放要发送的地址或数据

        reg [7:0] read_data;

        

        //写入、?慈?iic的状态机

        parameter IDLE   = 4'd0;

        parameter START1 = 4'd1;

        parameter ADD1   = 4'd2;

        parameter ACK1   = 4'd3;

        parameter ADD2   = 4'd4;

        parameter ACK2   = 4'd5;

        parameter START2 = 4'd6;

        parameter ADD3   = 4'd7;

        parameter ACK3   = 4'd8;

        parameter DATA   = 4'd9;

        parameter ACK4   = 4'd10;

        parameter STOP1  = 4'd11;

        parameter STOP2  = 4'd12;

        

        reg [3:0] cstate;

        reg sda_r;

        reg sda_link;

        reg [3:0] num;          //用来计量地址或数据的位数

        

        always @(posedge clk or negedge rst_n)

                if(!rst_n)

                begin

                        cstate <= IDLE;

                        sda_r <= 1'b1;

                        sda_link <= 1'b0;

                        num <= 4'd0;

                        read_data <= 8'd0;

                end

                else

                begin

                        case(cstate)

                                IDLE:

                                begin

                                        sda_link <= 1'b1;

                                        sda_r <= 1'b1;

                                        if(bu1 || bu2)

                                        begin

                                                db_r <= `DEVICE_WRITE;

                                                cstate <= START1;

                                        end

                                        else

                                                cstate <= IDLE;

                                end

                                START1:

                                begin

                                        if(`scl_high)

                                        begin

                                                sda_link <= 1'b1;

                                                sda_r <= 0;             //产生下降沿,产生起始信号

                                                cstate <= ADD1;

                                                num <= 1'b0;

                                        end

                                        else

                                                cstate <= START1;

                                end

                                ADD1:

                                begin

                                        if(`scl_low)

                                                if(num == 4'd8)

                                                begin

                                                        num <= 4'd0;

                                                        sda_r <= 1'b1;

                                                        sda_link <= 1'b0;

                                                        cstate <= ACK1;

                                                end

                                                else

                                                begin

                                                        cstate <= ADD1;

                                                        num <= num + 1'b1;

                                                        case(num)

                                                                4'd0: sda_r <= db_r[7];

                                                                4'd1: sda_r <= db_r[6];

                                                                4'd2: sda_r <= db_r[5];

                                                                4'd3: sda_r <= db_r[4];

                                                                4'd4: sda_r <= db_r[3];

                                                                4'd5: sda_r <= db_r[2];

                                                                4'd6: sda_r <= db_r[1];

                                                                4'd7: sda_r <= db_r[0];

                                                                default: ;

                                                        endcase

                                                end

                                        else

                                                cstate <= ADD1;

                                end

                                ACK1:

                                begin

                                        if(`scl_neg)

                                        begin

                                                cstate <= ADD2;

                                                db_r <= `BYTE_ADDR;

                                        end

                                        else

                                                cstate <= ACK1;

                                end

                                ADD2:

                                begin

                                        if(`scl_low)

                                                if(num == 4'd8)

                                                begin

                                                        num <= 4'd0;

                                                        sda_r <= 1'b1;

                                                        sda_link <= 1'b0;

                                                        cstate <= ACK2;

                                                end

                                                else

                                                begin

                                                        cstate <= ADD2;

                                                        num <= num + 1'b1;

                                                        case(num)

                                                                4'd0: sda_r <= db_r[7];

                                                                4'd1: sda_r <= db_r[6];

                                                                4'd2: sda_r <= db_r[5];

                                                                4'd3: sda_r <= db_r[4];

                                                                4'd4: sda_r <= db_r[3];

                                                                4'd5: sda_r <= db_r[2];

                                                                4'd6: sda_r <= db_r[1];

                                                                4'd7: sda_r <= db_r[0];

                                                                default: ;

                                                        endcase

                                                end

                                        else

                                                cstate <= ADD2;

                                end

                                ACK2:

                                begin

                                        if(`scl_neg)

                                        begin

                                                if(bu1_r)

                                                begin

                                                        cstate <= DATA;

                                                        db_r <= `WRITE_DATA;

                                                end

                                                else if(bu2_r)

                                                begin

                                                        cstate <= START2;

                                                        db_r <= `DEVICE_READ;

                                                end

                                        end

                                        else

                                                cstate <= ACK2;

                                end

                                START2:

                                begin

                                        if(`scl_high)

                                        begin

                                                sda_r <= 1'b0;

                                                cstate <= ADD3;

                                        end

                                        else

                                        begin

                                                sda_link <= 1'b1;

                                                sda_r <= 1'b1;

                                                cstate <= START2;

                                        end

                                end

                                ADD3:

                                begin

                                        if(`scl_low)

                                                if(num == 4'd8)

                                                begin

                                                        num <= 4'd0;

                                                        sda_r <= 1'b1;

                                                        sda_link <= 1'b0;

                                                        cstate <= ACK3;

                                                end

                                                else

                                                begin

                                                        cstate <= ADD2;

                                                        num <= num + 1'b1;

                                                        case(num)

                                                                4'd0: sda_r <= db_r[7];

                                                                4'd1: sda_r <= db_r[6];

                                                                4'd2: sda_r <= db_r[5];

                                                                4'd3: sda_r <= db_r[4];

                                                                4'd4: sda_r <= db_r[3];

                                                                4'd5: sda_r <= db_r[2];

                                                                4'd6: sda_r <= db_r[1];

                                                                4'd7: sda_r <= db_r[0];

                                                                default: ;

                                                        endcase

                                                end

                                        else

                                                cstate <= ADD2;

                                end

                                ACK3:

                                begin

                                        if(`scl_neg)

                                        begin

                                                cstate <= DATA;

                                                sda_link <= 1'b0;

                                        end

                                        else

                                                cstate <= ACK2;

                                end

                                DATA:

                                begin

                                        if(bu2_r)

                                        begin

                                                if(num <=7)

                                                begin

                                                        cstate <= DATA;

                                                        if(`scl_high)

                                                        begin

                                                                num <= num + 1'b1;

                                                                case(num)

                                                                        4'd0: sda_r <= db_r[7];

                                                                        4'd1: sda_r <= db_r[6];

                                                                        4'd2: sda_r <= db_r[5];

                                                                        4'd3: sda_r <= db_r[4];

                                                                        4'd4: sda_r <= db_r[3];

                                                                        4'd5: sda_r <= db_r[2];

                                                                        4'd6: sda_r <= db_r[1];

                                                                        4'd7: sda_r <= db_r[0];

                                                                        default: ;

                                                                endcase

                                                        end

                                                end

                                                else if(`scl_low && num == 4'd8)

                                                begin

                                                        num <= 4'd0;

                                                        cstate <= ACK4;

                                                end

                                        else

                                                cstate <= DATA;

                                        end

                                else if(bu1_r)

                                begin

                                        sda_link <= 1'b1;

                                        if(num <=7)

                                                begin

                                                        cstate <= DATA;

                                                        if(`scl_high)

                                                        begin

                                                        sda_link <= 1'b1;

                                                                num <= num + 1'b1;

                                                                case(num)

                                                                        4'd0: sda_r <= db_r[7];

                                                                        4'd1: sda_r <= db_r[6];

                                                                        4'd2: sda_r <= db_r[5];

                                                                        4'd3: sda_r <= db_r[4];

                                                                        4'd4: sda_r <= db_r[3];

                                                                        4'd5: sda_r <= db_r[2];

                                                                        4'd6: sda_r <= db_r[1];

                                                                        4'd7: sda_r <= db_r[0];

                                                                        default: ;

                                                                endcase

                                                        end

                                                end

                                                else if(`scl_low && num == 4'd8)

                                                begin

                                                        num <= 4'd0;

                                                        cstate <= ACK4;

                                                end

                                        else

                                                cstate <= DATA;

                                        end

                                end

                                //end

                                ACK4:

                                begin

                                        if(`scl_neg)

                                                cstate <= STOP1;

                                        else

                                                cstate <= ACK4;

                                end

                                STOP1:

                                begin

                                        if(`scl_low)

                                        begin

                                                sda_link <= 1'b1;

                                                sda_r <= 1'b0;

                                                cstate <= STOP1;

                                        end

                                        else if(`scl_high)

                                        begin

                                                sda_r <= 1'b1;

                                                cstate <= STOP2;

                                        end

                                end

                                STOP2:

                                        if(`scl_low)

                                                sda_r <= 1'b1;

                                        else if(cnt_20ms == 20'hfffff)

                                                cstate <= IDLE;

                                        else

                                                cstate <= STOP2;

                                default: cstate <= IDLE;

                        endcase

                end

        assign sda = sda_link? sda_r:1'bz;

        assign out_data = read_data;

endmodule下载本文

显示全文
专题