24AA128的verilog编程

       查阅了不少资料,终于找到一篇读起来很舒服的说明及程序源码,具体链接不给了,很容易搜到。原文是针对24c08的程序,开始也没仔细看资料,直接复制粘贴,烧录,发现不行。查了代码,我这水平也是不够看的,粗略的理解下应当没啥大问题。从网上找到了24AA128资料,发现他的读写和24C08区别还是有的,主要是地址,一个是双地址,一个是单地址。想当然的在程序上直接改了,发现不太好用。但思路是没错的。走了不少弯路,终于,上道了。程序可以读出来了。不会仿真,请见谅。只放个能用代码吧。第一来到csdn的宝地,不太熟悉门道,见谅。

  领导说我不是爱干净的人,但是代码有时看着别扭,改来改去的,突然觉得自己还是有点洁癖的。不过只是心病,不严重。

`timescale 1ns / 1ps
module iiccom(
            clk,rst_n,
            sw1_r,sw2_r,sw3_r,sw4_r,
            scl,sda,
            ackflag,
            outdata
        );
 
input clk;              // 50MHz
input rst_n;            //复位信号,低有效
input sw1_r,sw2_r,sw3_r,sw4_r;  //按键,(1按下执行写入操作,2按下执行读操作,3按下执行连写操作,4按下执行连读操作)
output scl;             // 24AA128的时钟端口
output [2:0]ackflag;    //后面显示接收到数据的标准
inout sda;              // 24AA128的数据端口
output [7:0] outdata;   //数码管显示的数据
 
//--------------------------------------------
//按键检测
//reg sw1_r,sw2_r,sw3_r,sw4_r;    //键值锁存寄存器,每20ms检测一次键值
reg[19:0] cnt_20ms; //20ms计数寄存器
 
always @ (posedge clk or negedge rst_n)
  if(!rst_n) cnt_20ms <= 20'd0;
  else if(cnt_20ms == 20'hfffff) cnt_20ms <= 20'h0;
  else cnt_20ms <= cnt_20ms+1'b1;  //不断计数

//--分频部分--//
reg[2:0] cnt;   // cnt=0:scl上升沿,cnt=1:scl高电平中间,cnt=2:scl下降沿,cnt=3:scl低电平中间
reg[8:0] cnt_delay; //500循环计数,产生iic所需要的时钟
reg scl_r;      //时钟脉冲寄存器
 
always @ (posedge clk or negedge rst_n)
begin
  if(!rst_n) cnt_delay <= 9'd0;
  else if(cnt_delay == 9'd499) cnt_delay <= 9'd0;  //计数到10us为scl的周期,即100KHz
  else cnt_delay <= cnt_delay+1'b1;    //时钟计数
end
 
always @ (posedge clk or negedge rst_n)
begin
  if(!rst_n) cnt <= 3'd5;
    else begin
      case (cnt_delay)
        9'd124: cnt <= 3'd1; //cnt=1:scl高电平中间,用于数据采样
        9'd255: cnt <= 3'd2; //cnt=2:scl下降沿后面点
        9'd374: cnt <= 3'd3; //cnt=3:scl低电平中间,用于数据变化
        9'd495: cnt <= 3'd0; //cnt=0:scl上升沿前面点
        default: cnt <= 3'd5;
      endcase
    end
end
 
`define SCL_POS     (cnt==3'd0)     //cnt=0:scl上升沿前面点
`define SCL_HIG     (cnt==3'd1)     //cnt=1:scl高电平中间,用于数据采样
`define SCL_NEG     (cnt==3'd2)     //cnt=2:scl下降沿后面点
`define SCL_LOW     (cnt==3'd3)     //cnt=3:scl低电平中间,用于数据变化
 
always @ (posedge clk or negedge rst_n)
  if(!rst_n) scl_r <= 1'b0;
  else if(cnt_delay==9'd499) scl_r <= 1'b1;    //scl信号上升沿
  else if(cnt_delay==9'd249) scl_r <= 1'b0;    //scl信号下降沿
 
assign scl = scl_r; //产生iic所需要的时钟
//--------------需要写入24AA128的地址和数据-------------------------------
`define DEVICE_READ     8'b1010_0001    //被寻址器件地址(读操作)
`define DEVICE_WRITE    8'b1010_0000    //被寻址器件地址(写操作)
`define WRITE_DATA0     8'b1001_0010    
`define WRITE_DATA1     8'b0010_0001    //写入EEPROM的数据
`define WRITE_DATA2     8'b0100_0011
`define WRITE_DATA3     8'b0110_0101
`define WRITE_DATA4     8'b1001_0111
`define BYTE_ADDR       8'b0010_0100    //写入/读出EEPROM的地址寄存器
`define BYTE_ADDR1      8'b0101_0101    //写入/读出EEPROM的地址寄存器
reg[7:0] db_r;      //在IIC上传送的数据寄存器
reg[7:0] read_data; //读出EEPROM的数据寄存器
reg[7:0] outdata_r; //输出数据贮存器
parameter   PAGEDATA_NUM = 3'd4;        //页写数据个数
//-----------读、写时序----------------------------------
parameter   IDLE    = 17'd1;//初始态
parameter   START1  = 17'd2;//起始信号
parameter   ADD1    = 17'd3;//写入器件地址
parameter   ACK1    = 17'd4;//应答

parameter   ADD11    = 17'd5;//写入器件地址
parameter   ACK11    = 17'd6;//应答

parameter   ADD2    = 17'd7;//写入字节地址
parameter   ACK2    = 17'd8;//应答

parameter   ADD21    = 17'd9;//写入字节地址
parameter   ACK21    = 17'd10;//应答

parameter   START2  = 17'd11;//读操作开始前的起始信号
parameter   ADD3    = 17'd12;//写入器件地址
parameter   ACK3    = 17'd13;//应答
parameter   ACKR    = 17'b1_0000_0000_0000_0000;//fpga给应答
parameter   DATA    = 17'd14;//字节读写
parameter   PAGER   = 17'd15;//页读
parameter   PAGEW   = 17'd16;//页写
parameter   ACK4    = 17'd17;//应答
parameter   HIGH    = 17'd18;//高电平
parameter   STOP1   = 17'd19;//停止位
parameter   STOP2   = 17'd20;//延时同步
 
 
reg[16:0] cstate;   //状态寄存器
reg sda_r;      //输出数据寄存器
reg sda_link;   //输出数据sda信号inout方向控制位       
reg[3:0] num;   //读写的字节计数
reg[2:0] ackflag;//连读时的数据标志
reg[2:0] pagecnt;//连读连写时的数据计数器
reg[7:0] pagedata_r;//连读储存器
 
always @ (posedge clk or negedge rst_n) begin
  if(!rst_n) begin
    pagedata_r <= 8'd0;
    end
  else begin
    case(pagecnt)
      3'd0:   pagedata_r <= `WRITE_DATA1;
      3'd1:   pagedata_r <= `WRITE_DATA2;
      3'd2:   pagedata_r <= `WRITE_DATA3;
      3'd3:   pagedata_r <= `WRITE_DATA4;
      default:;
    endcase
  end
end
//---------------------------------------状态机---------------------------------------------//
always@(posedge clk or negedge rst_n) begin
  if(!rst_n) begin
    cstate <= IDLE;
    sda_r <= 1'b1;
    sda_link <= 1'b0;
    num <= 4'd0;
    ackflag <= 3'd0;
    pagecnt <= 3'd0;
    read_data <= 8'b0000_0000;
    outdata_r <= 8'b0000_0000;
  end
  else     
    case (cstate)
      IDLE:   begin
        sda_link <= 1'b1;//数据线sda为input
        sda_r <= 1'b1;
        read_data <= 8'b0000_0000;
        //ackflag <= 3'd0;
        if(!sw1_r || !sw2_r || !sw3_r || !sw4_r) begin    //SW1,SW2,SW3,SW4键有一个被按下          
            db_r <= `DEVICE_WRITE;                       //送器件地址(写操作)
            cstate <= START1;        
            end
        else cstate <= IDLE; //没有任何键被按下
      end
      START1: begin
        if(`SCL_HIG) begin      //scl为高电平期间
            sda_link <= 1'b1;    //数据线sda为output
            sda_r <= 1'b0;       //拉低数据线sda,产生起始位信号
            cstate <= ADD1;
            ackflag <= 1'b0;
            num <= 4'd0;     //num计数清零
            end
        else cstate <= START1; //等待scl高电平中间位置到来
      end
      ADD1:   begin
        if(`SCL_LOW) begin
          if(num == 4'd8) begin   
            num <= 4'd0;         //num计数清零
            sda_r <= 1'b1;
            sda_link <= 1'b0;        //sda置为高阻态(input)
            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
    end
    else cstate <= ADD1;
    end
      ACK1:   begin
        if(`SCL_NEG) begin  
          cstate <= ADD11;  //从机响应信号
          db_r <= `BYTE_ADDR;  // 1地址      
        end
        else cstate <= ACK1;     //等待从机响应
      end
                    
      ADD11:   begin
        if(`SCL_LOW) begin
          if(num == 4'd8) begin   
            num <= 4'd0;         //num计数清零
            sda_r <= 1'b1;
            sda_link <= 1'b0;        //sda置为高阻态(input)
            cstate <= ACK11;
        end
          else begin
            cstate <= ADD11;
            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 cstate <= ADD11;
      end
      ACK11:   begin
        if(`SCL_NEG) begin  
          cstate <= ADD2;  //从机响应信号
          db_r <= `BYTE_ADDR1;  // 1地址      
        end
        else cstate <= ACK11;     //等待从机响应
      end
/                    
      ADD2:   begin
        if(`SCL_LOW) begin
          if(num==4'd8) begin
             num <= 4'd0;         //num计数清零
             sda_r <= 1'b1;
             sda_link <= 1'b0;        //sda置为高阻态(input)
             cstate <= ACK2;
           end
         else begin
           sda_link <= 1'b1;        //sda作为output
           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
          cstate <= ADD2;                  
          end
        end
        else cstate <= ADD2;             
      end
      ACK2:   begin
        if(`SCL_NEG) begin      //从机响应信号
           if(!sw1_r) begin
             cstate <= DATA;  //写操作
             db_r <= `WRITE_DATA0;    //写入的数据1                            
           end
              else if(!sw2_r || !sw4_r) begin //读或着是连读
             db_r <= `DEVICE_READ;//送器件地址(读操作),特定地址读需要执行该步骤以下操作
             cstate <= START2;        //读操作
           end
           else if(!sw3_r) begin       //连写
             //db_r <=  pagedata_r;
             //ackflag <= ackflag + 1'd1;
             cstate <= PAGEW;
            end
            else cstate <= ACK2; //等待从机响应
        end
      end
      START2: begin   //读操作起始位
        if(`SCL_LOW) begin
          sda_link <= 1'b1;    //sda作为output
          sda_r <= 1'b1;       //拉高数据线sda
          cstate <= START2;
          end
        else if(`SCL_HIG) begin //scl为高电平中间
          sda_r <= 1'b0;       //拉低数据线sda,产生起始位信号
          cstate <= ADD3;
          end  
        else cstate <= START2;
      end
      ADD3:   begin   //送读操作地址
        if(`SCL_LOW) begin
          if(num==4'd8) begin
            num <= 4'd0;         //num计数清零
            sda_r <= 1'b1;
            sda_link <= 1'b0;        //sda置为高阻态(input)
            cstate <= ACK3;
          end
          else 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             
            cstate <= ADD3;                  
          end
        end
        else cstate <= ADD3;             
      end
      ACK3:   
        begin
        if(`SCL_NEG && !sw2_r)
          begin
          cstate <= DATA;  //从机响应信号
          sda_link <= 1'b0;
        end
        else if(`SCL_NEG && !sw4_r)
          begin
          cstate <= PAGER; //从机响应信号
          ackflag <= ackflag +1'd1;
          sda_link <= 1'b0;
        end
        else cstate <= ACK3;         //等待从机响应
      end
      ACKR:   
        begin
        sda_r <= 0;      //主控制器应答
        if(`SCL_NEG && !sw4_r)
          begin
          cstate <= PAGER;
          ackflag <= ackflag +1'd1;
          sda_link <= 1'b0;
        end
        else cstate <= ACKR;     
      end
      DATA:   
        begin
        if(!sw2_r) begin     //读操作
          if(num<=4'd7) begin
            cstate <= DATA;
            if(`SCL_HIG) begin  
              num <= num+1'b1;
              case (num)
                4'd0: read_data[7] <= sda;
                4'd1: read_data[6] <= sda;  
                4'd2: read_data[5] <= sda;
                4'd3: read_data[4] <= sda;
                4'd4: read_data[3] <= sda;
                4'd5: read_data[2] <= sda;
                4'd6: read_data[1] <= sda;
                4'd7: read_data[0] <= sda;
                default: ;
              endcase                                 
            end
          end
          else if((`SCL_LOW) && (num==4'd8))
             begin
            num <= 4'd0;         //num计数清零
            //cstate <= ACK4;
            sda_link <= 1'b1;        //无应答
            outdata_r <= read_data;
            ackflag <= 3'd1;     //1个数
            cstate <= HIGH;
           end
         else cstate <= DATA;
       end
       else if(!sw1_r) begin   //写操作
         sda_link <= 1'b1;    
         if(num<=4'd7) begin
           cstate <= DATA;
           if(`SCL_LOW) begin
             sda_link <= 1'b1;        //数据线sda作为output
             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;
             sda_r <= 1'b1;
             sda_link <= 1'b0;        //sda置为高阻态
             cstate <= ACK4;
          end
          else cstate <= DATA;
        end
      end
      PAGEW:begin
        sda_link <= 1'b1;    //sda为输出
       //if(pagecnt < PAGEDATA_NUM)begin
           if(num<=4'd7) begin
             cstate <= PAGEW;
             if(`SCL_LOW) begin
               sda_link <= 1'b1;        //数据线sda作为output
               num <= num+1'b1;
               case (num)
                 4'd0: sda_r <= pagedata_r[7];
                 4'd1: sda_r <= pagedata_r[6];
                 4'd2: sda_r <= pagedata_r[5];
                 4'd3: sda_r <= pagedata_r[4];
                 4'd4: sda_r <= pagedata_r[3];
                 4'd5: sda_r <= pagedata_r[2];
                 4'd6: sda_r <= pagedata_r[1];
                 4'd7: sda_r <= pagedata_r[0];
                 default: ;
               endcase
               end
             end
           else if((`SCL_LOW) && (num==4'd8)&&(pagecnt < PAGEDATA_NUM-1'b1)) begin
             num <= 4'd0;
             pagecnt <= pagecnt +1'd1;
             sda_r <= 1'b1;
             sda_link <= 1'b0;        //sda置为高阻态
             cstate <= ACK2;
           end
           else if((`SCL_LOW) && (num==4'd8) && (pagecnt == PAGEDATA_NUM -1'b1)) begin
             num <= 4'd0;
             //pagecnt <= pagecnt +1'd1;
             pagecnt <= 1'd0;
             sda_r <= 1'b1;
             sda_link <= 1'b0;
             cstate <= ACK4;
           end
           else cstate <= PAGEW;
        end
                  //end
      PAGER:begin
        //if(pagecnt < PAGEDATA_NUM)begin
        if(num<=4'd7) begin
          cstate <= PAGER;
          if(`SCL_LOW) begin
             num <= num+1'b1;
             case (num)
               4'd0: read_data[7] <= sda;
               4'd1: read_data[6] <= sda;  
               4'd2: read_data[5] <= sda;
               4'd3: read_data[4] <= sda;
               4'd4: read_data[3] <= sda;
               4'd5: read_data[2] <= sda;
               4'd6: read_data[1] <= sda;
               4'd7: read_data[0] <= sda;
               default: ;
             endcase
           end                                         
         end
           else if((`SCL_LOW) && (num==4'd8)&& (pagecnt < PAGEDATA_NUM-1'b1)) begin
             num <= 4'd0;
             pagecnt <= pagecnt +1'd1;
             outdata_r <= read_data;
             //ackflag <= ackflag +1'd1;
             sda_r <= 1'b1;
             sda_link <= 1'b1;        //主控制器应答
             cstate <= ACKR;
            end
            else if((`SCL_LOW) && (num==4'd8) && (pagecnt == PAGEDATA_NUM -1'b1)) begin
              num <= 4'd0;
               //pagecnt <= pagecnt +1'd1;
              outdata_r <= read_data;
              ackflag <= ackflag +1'b1;
              pagecnt <= 1'd0;
              sda_r <= 1'b1;
              sda_link <= 1'b1;
              cstate <= HIGH;
            end
            else cstate <= PAGER;
          end
                        //end
      ACK4: begin                                     //写操作最后个应答
        if(`SCL_NEG) begin
          cstate <= STOP1;                     
        end
        else cstate <= ACK4;
      end
      HIGH: begin
        if(`SCL_NEG)begin
          sda_r <= 1'd1;
          //ackflag <= ackflag +1'd1;
          cstate <= STOP1;
        end
        else cstate <= HIGH;
      end
      STOP1:  begin
        if(`SCL_LOW) begin
          sda_link <= 1'b1;
          sda_r <= 1'b0;
          cstate <= STOP1;
        end
        else if(`SCL_HIG) begin
          sda_r <= 1'b1;   //scl为高时,sda产生上升沿(结束信号)
          cstate <= STOP2;
        end
          else cstate <= STOP1;
      end
      STOP2:  begin
        if(`SCL_LOW) sda_r <= 1'b1;
        else if(cnt_20ms==20'hffff0) cstate <= IDLE;//同步采样
        else cstate <= STOP2;
      end
      default: cstate <= IDLE;
    endcase
end
 
assign sda = sda_link ? sda_r:1'bz;
assign outdata = outdata_r;
//---------------------------------------------------------
endmodule

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值