Board logo

标题: FPGA时序逻辑的一种写法 [打印本页]

作者: rise_ming    时间: 2012-7-4 00:19     标题: FPGA时序逻辑的一种写法

我读书时候学过VHDL,那时候一门课学了好几种语言,还有一种是ABEL,另外一种连名字都忘了。当时ABEL学得最熟悉,因为最早开课,VHDL看起来太繁琐没学会多少。刚毕业那时候用过CPLD,但是那时是用画原理图的办法来开发的,处理复杂的时序逻辑比较困难。毕业四年后进了研究所,当时的有同事懂一点点Verilog,感觉语句跟C很像,我对这个也有了一点点兴趣,但是没去练,当时搞ARM跟学linux操作去了。去年我在淘宝买了一块特权同学的SF-EP1V2 FPGA学习板,想自己学习一下Verilog HDL语言,后来慢慢有时间才做了一些练习。
下面这个module是参考一个I2C的Verilog HDL写的,这个处理时序的方法跟自己以前写的真不一样。自己写的虽然功能也出来了,但是一大堆异步逻辑,总觉得不太妥当。这个时序逻辑的思想是用一个计数器来控制时序信号的输出,输出的状态由几个变量来控制。

module test595 (
       CLOCK,
       ds_shcp,//serial clock input
       ds_stcp,// parallel clock input
      ds_data,//parallel data
       HC595_DATA,//DATA:[segment code, location code]
       GO,      //GO transfer
       RESET
       //TEST
       //SD_COUNTER,
       //SDO
);
       input  CLOCK;
       input  [15:0]HC595_DATA;  
       input  GO;
       input  RESET;      
      output ds_data;      
       output ds_shcp;
       output ds_stcp;      

//TEST
       //output [4:0] SD_COUNTER;
       //output SDO;


reg SDO;
reg SCLK;
reg STO;
reg END;
reg [15:0]SD;
reg [4:0]SD_COUNTER;

wire ds_shcp=SCLK | ( ((SD_COUNTER >= 3) & (SD_COUNTER <=18))? ~CLOCK :0 );
wire ds_data=SDO?1'b1:0 ;
wire ds_stcp=STO | ((SD_COUNTER==19)?1'b1:1'b0);


//SHIFT COUNTER
always @(negedge RESET or posedge CLOCK ) begin
if (!RESET) SD_COUNTER=5'b11111;
else begin
if (GO==0)
       SD_COUNTER=0;
       else
       if (SD_COUNTER < 5'b11111) SD_COUNTER=SD_COUNTER+1;  
end
end
//----

always @(negedge RESET or  posedge CLOCK ) begin
if (!RESET) begin SCLK=1;SDO=1;STO=1; end
else
case (SD_COUNTER)
       5'd0  : begin  SDO=1; SCLK=1;end
       //start
       5'd1  : begin SD=HC595_DATA;SDO=0;end
       5'd2  : SCLK=0;
       //SLAVE ADDR
       5'd3  : SDO=SD[15];
       5'd4  : SDO=SD[14];
       5'd5  : SDO=SD[13];
       5'd6  : SDO=SD[12];
       5'd7  : SDO=SD[11];
       5'd8  : SDO=SD[10];
       5'd9  : SDO=SD[9];
       5'd10 : SDO=SD[8];      
       6'd11 : SDO=SD[7];

       //SUB ADDR
       5'd12  : SDO=SD[6];
       5'd13  : SDO=SD[5];
       5'd14  : SDO=SD[4];
       5'd15  : SDO=SD[3];
       5'd16  : SDO=SD[2];
       5'd17  : SDO=SD[1];
       5'd18  : SDO=SD[0];
       5'd19  : begin SCLK=1'b1; STO=1'b0; end
       5'd20  : STO=1'b0;
       5'd20  : STO=1'b1;

       default:begin SCLK=1;SDO=1;STO=1; end

endcase
end
endmodule

下面是调用了该module的一个下载到开发板的模块,实现一个计数器并显示。可能语句又比较烂了,希望今后水平提高了能有所改进。
module seg7(clk1,rst_n,ds_shcp,ds_stcp,ds_data//,
            //test
            //code,GO,dis_code

);

input clk1;//25MHz
input rst_n;
output ds_shcp,ds_stcp,ds_data;
//output code;
//output GO;
//output dis_code;
wire dsdata;
assign ds_data=dsdata;
reg [15:0]code;//code to be display
reg GO;

reg [7:0]divd;
always @(posedge clk1 or negedge rst_n)
  if(!rst_n) divd<=0;
  else divd<=divd+1;

assign clk=divd[7];
//开发板用了25MHz的晶振,计数太快了,不得不分频一下,搞了个异步时钟
//count
reg [7:0]cnt;
always @(posedge clk or negedge rst_n)
  if(!rst_n) cnt<=0;
  else cnt<=cnt+1;  

reg [7:0]cntcode;  
always @(posedge clk or negedge rst_n)
  begin
  if(!rst_n) begin cntcode<=0;code<=0; end
  else if(cnt==8'hff)
    begin
      cntcode<=cntcode+1;  
      if(cntcode==8'hff) code<=code+1;
    end  
  end

//decode
parameter
        data0=8'b00111111,//8'b11111100,//0
              data1=8'b00000110,//8'b01100000,//1
              data2=8'b01011011,//8'b11011010,//2
              data3=8'b01001111,//8'b11110010,//3
              data4=8'b01100110,//8'b01100110,//4
              data5=8'b01101101,//8'b10110110,//5
              data6=8'b01111101,//8'b10111110,//6
              data7=8'b00000111,//8'b11100000,//7
              data8=8'b01111111,//8'b11111110,//8
              data9=8'b01101111,//8'b11110110,//9
              dataa=8'b01110111,//8'b11101110,//a
              datab=8'b01111100,//8'b00111110,//b
              datac=8'b00111001,//8'b10011100,//c
              datad=8'b01011110,//8'b01111010,//d
              datae=8'b01111001,//8'b10011110,//e
              dataf=8'b01110001;//8'b10001110;//f

reg[15:0] dis_code;
reg [11:0]decode;
always @(posedge clk or negedge rst_n)
  if(!rst_n) GO=1;
  else if(cnt>=8'h20 && cnt<=8'h24) begin decode={code[3:0],8'hf7};GO=0; end
  else if(cnt>=8'h60 && cnt<=8'h64) begin decode={code[7:4],8'hfb};GO=0; end
  else if(cnt>=8'ha0 && cnt<=8'ha4) begin decode={code[11:8],8'hfd};GO=0; end
  else if(cnt>=8'he0 && cnt<=8'he4) begin decode={code[15:12],8'hfe};GO=0; end
  else GO=1;

always @(posedge clk or negedge rst_n)
  if(!rst_n) dis_code<=0;
  else
      case(decode[11:8])
          4'h0:dis_code={data0,decode[7:0]};
          4'h1:dis_code={data1,decode[7:0]};
          4'h2:dis_code={data2,decode[7:0]};
          4'h3:dis_code={data3,decode[7:0]};
          4'h4:dis_code={data4,decode[7:0]};
          4'h5:dis_code={data5,decode[7:0]};
          4'h6:dis_code={data6,decode[7:0]};
          4'h7:dis_code={data7,decode[7:0]};
          4'h8:dis_code={data8,decode[7:0]};
          4'h9:dis_code={data9,decode[7:0]};
          4'ha:dis_code={dataa,decode[7:0]};
          4'hb:dis_code={datab,decode[7:0]};
          4'hc:dis_code={datac,decode[7:0]};
          4'hd:dis_code={datad,decode[7:0]};
          4'he:dis_code={datae,decode[7:0]};
          4'hf:dis_code={dataf,decode[7:0]};
  endcase

test595 HC595(
       .CLOCK(cnt[0]),
       .ds_shcp(ds_shcp),//serial clock input
       .ds_stcp(ds_stcp),// paralet clock input
      .ds_data(dsdata),//I2C DATA
       .HC595_DATA(dis_code),//DATA:[SLAVE_ADDR,SUB_ADDR,DATA]
       .GO(GO),      //GO transfor
       .RESET(rst_n)
       //TEST
       //SD_COUNTER,
       //SDO
);
endmodule




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0