清霜一梦

Verilog实现IIC通讯第二版

0
阅读(1379)

HMC5883三轴磁力传感器IIC通讯模块的VerilogHDL的实现

上一版并没有实现我想要的功能

 

0.0.1版   正在修订中   2013/9/2

//date :2013/7/7
   //designer :pengxiaoen
   //synthesizer:QuartusII 12.1
   //function : IIC实现HMC5883的通讯  50M /(400k × 4)= 32
   
   
 `define WriteAddress  8'h3c
 `define ReadAddress   8'h3d
   
`define RegAAddress   8'h00  //配置寄存器A
`define RegBAddress   8'h01  //配置寄存器B
`define ModelAddress  8'h02  //模式寄存器
`define X_MSBAddress  8'h03  //X MSB寄存器
`define X_LSBAddress  8'h04
`define Z_MSBAddress  8'h05
`define Z_LSBAddress  8'h06
`define Y_MSBAddress  8'h07
`define Y_LSBAddress  8'h08
`define STATEAddress  8'h09  //状态寄存器
`define IdentifyAAddress  8'h10  //识别寄存器A 
`define IdentifyBAddress  8'h10
`define IdentifyCAddress  8'h10
  
`define INITIAL  0
`define DELAY    1
`define MEASURE  2
  
`define START  3
`define Re     4
`define Se     5
`define STOP   6
  
  //`default_nettype none
  
  module HMC5883_2 (
                      clock,reset,
                            sda,scl,
                            out_seg,
                           
                            sel_seg,
                                     IIC_result
                            );
                            
  input clock,reset;
  inout sda,scl;
  output reg [7:0]out_seg;
  output reg IIC_result;
  
  output reg [5:0]sel_seg;
  
  reg [7:0] SEND_buffer;
  reg [7:0] Re_buffer ;
  reg sda_reg;
  reg scl_reg;
  reg ack_reg; 
  reg sda_enable;
  reg scl_enable;
  
  reg IC_state;
  reg n_IC_state;
  reg [2:0]state;           //当前状态寄存器
  reg state_finish_flag ;   //
  
  reg [5:0] scl_4;
  reg [3:0] step_counter;
  reg [3:0] clk_temp ;
  
//==============================================================================================  
//-------------时钟控制模块------------------start---------------
  always @ (posedge clock or negedge reset)
  if (!reset)
      begin 
           clk_temp <= 4'd0;
            scl_4 <= 6'd0;
       end 
  else if (clk_temp==4'd15)
           begin
               clk_temp <= 4'd0;
               if (state_finish_flag) scl_4 <= 6'd0;
               else if (scl_4 == 6'b111_111)   //这里是一个保护机制,可以设置一个flag
                      scl_4 <= 6'b111_111;
                    else  scl_4 <= scl_4 + 1;
          end 
       else clk_temp <= clk_temp + 1;
//----------时钟控制模块----------end-----------

//--------一个检测的pin---------start-----------
always @(posedge clock or negedge reset)
if(!reset)
   IIC_result <= 1'd0;
else if(scl_4 == 6'b111_111)
       IIC_result <= 1'd1;
        else ; 
//-----------一个检测的pin-------end----------        
        
//-------延时模块----5us------start--------
 reg [7:0] delay_counter;
 reg delay_enable;
 always @(posedge clock )
  if(!delay_enable) 
      begin 
           delay_counter <= 8'd0;
           state_finish_flag <= 1'd0;
      end 
  else  if(delay_counter == 8'd250)
           begin 
               state_finish_flag <= 1'd1;
               delay_counter <= 8'd0;
           end 
        else  begin 
                    delay_counter <= delay_counter + 1;
                        state_finish_flag <= 1'd0;
                  end 
 //--------------延时模块-------end---------------
 
 //----------状态机控制模块---------start-------
 always @ (posedge clock or negedge reset)
 if(!reset) 
   IC_state <= `INITIAL;
  else IC_state <= n_IC_state;             
  
 //------------------------------------------ 
  always @ (posedge state_finish_flag or negedge reset)
  if (!reset)
      begin 
           SEND_buffer  <= 8'd0;
           n_IC_state   <= 1'd0;
       end 
   else if(IC_state == `INITIAL)
      case (step_counter)
             0: begin  state <= `START;end 
             1: begin  state <= `Se;  SEND_buffer <= `WriteAddress;   end 
             2: begin  state <= `Se;  SEND_buffer <= `ModelAddress;   end
             3: begin  state <= `Se;  SEND_buffer <= `RegAAddress;   end     
             4: begin  state <= `STOP;   end
                 
                 5: begin  n_IC_state <= `MEASURE;   end
             default state <= `START;
       endcase 
  else if (IC_state == `MEASURE)
      case (step_counter)
              0: begin  state <= `START; end 
              1: begin  state <= `Se;   SEND_buffer <= `WriteAddress; end 
              2: begin  state <= `Se;   SEND_buffer <= `X_MSBAddress; end
              3: begin  state <= `START; end     
              4: begin  state <= `Se;   SEND_buffer <= `ReadAddress;end            
              5: begin  state <= `Re;   end
              6: begin  state <= `Re;   end
              7: begin  state <= `Re;   end
              8: begin  state <= `Re;   end
              9: begin  state <= `Re;   end
             10: begin  state <= `Re;   end
             11: begin  state <= `STOP; end
                 
                 12:begin  n_IC_state <= `INITIAL;  end
             default state <= `START;
       endcase       
       else ;
 //----------状态机控制模块----------end--- ---

//----------执行步骤计数--------start------------ 
always @ (posedge clock  or negedge reset)
if (!reset) begin 
    step_counter <= 4'd0;  end 
else  if((IC_state == `INITIAL)&& (state_finish_flag))   begin 
             if(step_counter == 4'd5)  step_counter <= 4'd0;  
                else step_counter <= step_counter + 1; end 
       else if((IC_state == `MEASURE) && (state_finish_flag))   begin  
                 if(step_counter == 4'd12 ) step_counter <= 4'd0;
                  else step_counter <= step_counter + 1;     end 
                 else ; 
//----------执行步骤计数--------end------------ 
                
 //-----------外部数据线 控制模块----start------
 always @ (posedge clock or negedge reset)
if(!reset)
  begin
       Re_buffer <= 8'd0;
         sda_enable <= 1'd0; 
         scl_enable <= 1'd0;
         delay_enable <= 1'd0;
  end 
 else case (state)
     `START : case (scl_4)
                 0: begin sda_enable <= 1'd1; scl_enable <= 1'd1; delay_enable <= 1'd0;
                                  sda_reg <= 1'd1;  scl_reg <= 1'd0;  end                      
                 1: begin sda_reg <= 1'd1;  scl_reg <= 1'd0;  end
                 2: begin sda_reg <= 1'd1;  scl_reg <= 1'd1;  end
                 3: begin sda_reg <= 1'd0;  scl_reg <= 1'd1;  end 
                      4: delay_enable <= 1'd1;
                  default  begin sda_reg <= 1'dz;  scl_reg <= 1'dz;  end     
              endcase  
     `STOP  : case (scl_4)
                 0: begin sda_enable <= 1'd1; scl_enable <= 1'd1; delay_enable <= 1'd0;
                               sda_reg <= 1'd0;  scl_reg <= 1'd0; end
                 1: begin sda_reg <= 1'd0;  scl_reg <= 1'd0; end     
                 2: begin sda_reg <= 1'd0;  scl_reg <= 1'd1; end 
                 3: begin sda_reg <= 1'd1;  scl_reg <= 1'd1; end
                      4: delay_enable <= 1'd1;
                  default  begin sda_reg <= 1'dz;  scl_reg <= 1'dz; end
               endcase                  
      `Se    : case (scl_4)
                 0: begin sda_enable <= 1'd1; scl_enable <= 1'd1; delay_enable <= 1'd0;
                               sda_reg <= 1'd0;            scl_reg <= 1'd0;  end
                 1: begin sda_reg <= SEND_buffer[7];  scl_reg <= 1'd0;  end
                 2: begin sda_reg <= SEND_buffer[7];  scl_reg <= 1'd1;  end
                 3: begin sda_reg <= SEND_buffer[7];  scl_reg <= 1'd1;  end
                 4: begin                             scl_reg <= 1'd0;  end
                 5: begin sda_reg <= SEND_buffer[6];  scl_reg <= 1'd0;  end
                 6: begin sda_reg <= SEND_buffer[6];  scl_reg <= 1'd1;  end
                 7: begin sda_reg <= SEND_buffer[6];  scl_reg <= 1'd1;  end
                 8: begin                             scl_reg <= 1'd0;  end
                 9: begin sda_reg <= SEND_buffer[5];  scl_reg <= 1'd0;  end
                10: begin sda_reg <= SEND_buffer[5];  scl_reg <= 1'd1;  end
                11: begin sda_reg <= SEND_buffer[5];  scl_reg <= 1'd1;  end
                12: begin                             scl_reg <= 1'd0;  end
                13: begin sda_reg <= SEND_buffer[4];  scl_reg <= 1'd0;  end
                14: begin sda_reg <= SEND_buffer[4];  scl_reg <= 1'd1;  end
                15: begin sda_reg <= SEND_buffer[4];  scl_reg <= 1'd1;  end
                16: begin                             scl_reg <= 1'd0;  end
                17: begin sda_reg <= SEND_buffer[3];  scl_reg <= 1'd0;  end
                18: begin sda_reg <= SEND_buffer[3];  scl_reg <= 1'd1;  end
                19: begin sda_reg <= SEND_buffer[3];  scl_reg <= 1'd1;  end
                20: begin                             scl_reg <= 1'd0;  end
                21: begin sda_reg <= SEND_buffer[2];  scl_reg <= 1'd0;  end
                22: begin sda_reg <= SEND_buffer[2];  scl_reg <= 1'd1;  end
                23: begin sda_reg <= SEND_buffer[2];  scl_reg <= 1'd1;  end
                24: begin                             scl_reg <= 1'd0;  end
                25: begin sda_reg <= SEND_buffer[1];  scl_reg <= 1'd0;  end
                26: begin sda_reg <= SEND_buffer[1];  scl_reg <= 1'd1;  end
                27: begin sda_reg <= SEND_buffer[1];  scl_reg <= 1'd1;  end
                28: begin                             scl_reg <= 1'd0;  end
                29: begin sda_reg <= SEND_buffer[0];  scl_reg <= 1'd0;  end
                30: begin sda_reg <= SEND_buffer[0];  scl_reg <= 1'd1;  end
                31: begin sda_reg <= SEND_buffer[0];  scl_reg <= 1'd1;  end
                //此时序之后必须释放掉sda控制权  等待响应
                32: begin  sda_enable <= 1'd0; scl_enable <= 1'd0; delay_enable <= 1'd1;
                                ack_reg <= 1'd0;           scl_reg <= 1'd0;  end //这里出现了一个警告,因为ack_reg没有利用到
                33: begin  ack_reg <= sda;            scl_reg <= 1'd0;  end
                     34: begin  ack_reg <= sda;            scl_reg <= 1'd1;  end
                35: begin  ack_reg <= sda;            scl_reg <= 1'd1;  end
               //此时IC有可能在一个时钟下来不及响应,从而导致主机没有接收到响应信号
                default  begin                        scl_reg <= 1'dz;      end                  
             endcase  
                  
      `Re  : case (scl_4)
                     0: begin  sda_enable <= 1'd0; scl_enable <= 1'd1; delay_enable <= 1'd0;
                                                       scl_reg <= 1'd0;  end
                     1: begin                        scl_reg <= 1'd0;  end
                     2: begin                        scl_reg <= 1'd1;  end 
                     3: begin Re_buffer[7] <= sda;   scl_reg <= 1'd1;  end
                     4: begin                        scl_reg <= 1'd0;  end
                     5: begin                        scl_reg <= 1'd0;  end
                     6: begin                        scl_reg <= 1'd1;  end
                     7: begin Re_buffer[6] <= sda;   scl_reg <= 1'd1;  end
                     8: begin                        scl_reg <= 1'd0;  end
                     9: begin                        scl_reg <= 1'd0;  end
                    10: begin                        scl_reg <= 1'd1;  end
                    11: begin Re_buffer[5] <= sda;   scl_reg <= 1'd1;  end
                    12: begin                        scl_reg <= 1'd0;  end
                    13: begin                        scl_reg <= 1'd0;  end
                    14: begin                        scl_reg <= 1'd1;  end
                    15: begin Re_buffer[4] <= sda;   scl_reg <= 1'd1;  end
                    16: begin                        scl_reg <= 1'd0;  end
                    17: begin                        scl_reg <= 1'd0;  end
                    18: begin                        scl_reg <= 1'd1;  end
                    19: begin Re_buffer[3] <= sda;   scl_reg <= 1'd1;  end
                    20: begin                        scl_reg <= 1'd0;  end
                    21: begin                        scl_reg <= 1'd0;  end
                    22: begin                        scl_reg <= 1'd1;  end
                    23: begin Re_buffer[2] <= sda;   scl_reg <= 1'd1;  end
                    24: begin                        scl_reg <= 1'd0;  end
                    25: begin                        scl_reg <= 1'd0;  end
                    26: begin                        scl_reg <= 1'd1;  end
                    27: begin Re_buffer[1] <= sda;   scl_reg <= 1'd1;  end
                    28: begin                        scl_reg <= 1'd0;  end
                    29: begin                        scl_reg <= 1'd0;  end
                    30: begin                        scl_reg <= 1'd1;  end
                    31: begin Re_buffer[0] <= sda;   scl_reg <= 1'd1;  end
               //此时序之后主机夺回sda控制权,延时开始
                    32: begin sda_enable <= 1'd1; delay_enable <= 1'd1;
                               sda_reg <= 0; scl_reg <= 1'd0;  end
                    33: begin  sda_reg <= 0; scl_reg <= 1'd0;  end
                    34: begin  sda_reg <= 0; scl_reg <= 1'd1;  end
                    35: begin  sda_reg <= 0; scl_reg <= 1'd1;  end
                    default  begin sda_reg <= 1'dz;    scl_reg <= 1'dz;end
               endcase
      endcase
 //-------外部数据线 控制模块----------end---------------
 
 assign sda = sda_enable ? sda_reg : 1'dz ;
 assign scl = scl_enable ? scl_reg : 1'dz ;
//==================================================================================== 
 
 
 //--------------数码管显示部分=======只显示了一部分,有待优化============================
 always @ ( posedge clock or negedge reset)
 if (!reset)
   begin 
     sel_seg <= 6'b111110;
   end 
 else if(state_finish_flag)
        begin
          sel_seg <= {sel_seg[4:0],sel_seg[5]};
        end
 //------------------------------------------------
 always @(posedge clock or negedge reset)
 if (!reset) out_seg <= 8'd0;
 else 
   begin
     case (Re_buffer[3:0])  //刚开始这里没有[3:0] 居然没有报错,连个警告都没有,这是为什么呢
         4'b0000  :  out_seg<=8'b1100_0000;//0000_0011
         4'b0001  :  out_seg<=8'b1111_1001;//1001_1111 
         4'b0010  :  out_seg<=8'b1010_0100;//0010_0101 
         4'b0011  :  out_seg<=8'b1011_0000;//0000_1101 
         4'b0100  :  out_seg<=8'b1001_1001;//1001_1001 
         4'b0101  :  out_seg<=8'b1001_0010;//0100_1001 
         4'b0110  :  out_seg<=8'b1000_0010;//0100_0001 
         4'b0111  :  out_seg<=8'b1111_1000;//0001_1111 
         4'b1000  :  out_seg<=8'b1000_0000;//0000_0001 
         4'b1001  :  out_seg<=8'b1001_1000;//0001_1001 
         4'b1010  :  out_seg<=8'b1000_1000;//0001_0001 
         4'b1011  :  out_seg<=8'b1000_0011;//1100_0001 
         4'b1100  :  out_seg<=8'b1100_0110;//0110_0011 
         4'b1101  :  out_seg<=8'b1010_0001;//1000_0101 
         4'b1110  :  out_seg<=8'b1000_0110;//0110_0001 
         4'b1111  :  out_seg<=8'b1000_1110;//0111_0001 
      endcase 
   end 
//-------------------------------================================= 

 endmodule