Wednesday, March 3, 2010

verilog串口代码

学单片机时是从串口开始的,学FPGA仍旧从串口开始,谁让它是最简单的呢?
串口发送模块对外接口为: (下面给出的仅为1启动位,8个数据位,1个停止位,无奇偶校验)
            发送管脚     : txd_pin
            正在发送标志 : finish_F
            送数据接口   : bus
            波特率时钟   : clock
            复位信号     :  reset
            启动发送信号 :  load_bus_reg
module uart_emitter(txd_pin,finish_F,bus,clock,reset,load_bus_reg);
input load_bus_reg;                        
input clock;
input reset;
input [7:0] bus;//并行总线
output txd_pin;
output finish_F;//0:正在发送,1:移位寄存器空
reg finish_F;
reg txd_pin;

reg[7:0] bus_reg;//并行输入缓冲
reg[3:0] state;
//并-串状态机Gray码编码
parameter  idle=4'b0000;
parameter  bit0=4'b0001;
parameter  bit1=4'b0011;
parameter  bit2=4'b0010;
parameter  bit3=4'b0110;
parameter  bit4=4'b0111;
parameter  bit5=4'b0101;
parameter  bit6=4'b0100; 
parameter  bit7=4'b1100;
parameter  bit8=4'b1101;
parameter  bit9=4'b1111;
parameter  ver=4'b1110;
//////////////////////////////////////////
always@(posedge clock or negedge reset)
if(!reset) 
    begin 
    state<=idle;
    txd_pin<=1'b1;
    finish_F<=1;
    end    
else 
    case(state)
        idle : 
        begin
            if(load_bus_reg) 
                begin 
                bus_reg<=bus;
                state<=bit0;
                end
            else 
                begin 
                state<=idle;
                finish_F<=1;
                end      
       end
       bit0 : begin txd_pin<=1'b0;state<=bit1; finish_F<=0; end//bit0
       bit1 : begin txd_pin<=bus_reg[0];state<=bit2;end//bit1
       bit2 : begin txd_pin<=bus_reg[1];state<=bit3;end//bit2
       bit3 : begin txd_pin<=bus_reg[2];state<=bit4;end//bit3
       bit4 : begin txd_pin<=bus_reg[3];state<=bit5;end//bit4
       bit5 : begin txd_pin<=bus_reg[4];state<=bit6;end//bit5
       bit6 : begin txd_pin<=bus_reg[5];state<=bit7;end//bit6
       bit7 : begin txd_pin<=bus_reg[6];state<=bit8;end//bit7
       bit8 : begin txd_pin<=bus_reg[7];state<=bit9;end//bit8
       bit9 : begin txd_pin<=1'b1; state<=over;     end//bit9
       over : begin finish_F<=1'b1;state<=idle;     end
       default : begin state<=idle;                 end
    endcase
endmodule
 
提串口发送,就不能不提时钟分频,因为上边的模块用的就是实际波特率,
而我们电路板上不可能刚好接成串口的频率时钟,所以就需要用现有的时钟分频得到串口时钟,
下边给出的是为40M的源时钟时,串口对应的分频设置:
//===========================================================
// 40MHz = 40,000,000 Hz  
// 40MHz ~~~ 8*115200*11*4
`define Baudrate_preDiv        11

`define Baudrate_115200_b      2
`define Baudrate_115200_v      3     // 3.9457 ~~~~ 4
  
`define Baudrate_57600_b       3
`define Baudrate_57600_v       7     // 7.89    ~~~~ 8
  
`define Baudrate_38400_b       4
`define Baudrate_38400_v       11     // 11.837  ~~~ 12

`define Baudrate_19200_b       5
`define Baudrate_19200_v       23     // 23.674  ~~~ 24

`define Baudrate_9600_b        6
`define Baudrate_9600_v        46    // 47.348 ~~~ 47

//========================  
`define BAUD_RATE_USE_b   2 //115200------已测试OK
`define BAUD_RATE_USE_v   3 
//===========================================================
// baudrate 115200
module uart_clk(sys_clock,reset,uart_rx_clk,uart_tx_clk);
input sys_clock;
input reset;
output uart_rx_clk;  // 串口接收的采样时钟
output uart_tx_clk;  // 串口发送的时钟

wire sys_clock_by_11;

divide_by_11    divide_11(sys_clock,reset,sys_clock_by_11);
divide_by_xx    divide_xx(sys_clock_by_11,reset,uart_rx_clk,uart_tx_clk);

endmodule
/////////////////////
module divide_by_11(sys_clock,reset,sys_clock_by_11);
input sys_clock;
input reset;
output sys_clock_by_11;
wire sys_clock_by_11;
reg [3:0] temp;

assign  sys_clock_by_11=temp[3];

always@(posedge sys_clock or negedge reset)
    if(!reset) 
        temp<=0;
    else
       
        begin
        if(temp==(`Baudrate_preDiv-1)) temp<=0;
        else temp<=temp+1;
        end
    
endmodule 
//////////////////////////
module divide_by_xx(sys_clock_11,reset,clock,sample_clk);
input reset;
input sys_clock_11;
output clock;
output sample_clk;

wire clock;
wire sample_clk;

reg[(`BAUD_RATE_USE_b-1):0] temp;
reg[2:0] temp0;

assign sample_clk=temp0[2];
assign clock = temp[(`BAUD_RATE_USE_b-1)];

always@(posedge sys_clock_11 or negedge reset)
    if(!reset) 
        temp<=0;
    else begin 
        if (temp==`BAUD_RATE_USE_v) temp<=0;
        else temp<=temp+1;
    end
    
always@( posedge clock or negedge reset)
    if(!reset) 
        temp0<=0;
    else begin
        if(temp0==7) temp0<=0;
        else temp0<=temp0+1;
    end
    
endmodule

最外层的调用接用,
uart_clk UartClock(.sys_clock(clk),
                   .reset(rst),
                   .uart_rx_clk(uart_rxclk),
                   .uart_tx_clk(uart_txclk));
                   
uart_emitter UartTx(.txd_pin(txdPin),
                    .finish_F(txFlgPin),
                    .bus(tx_reg),
                    .clock(uart_txclk),
                    .reset(rst),
                    .load_bus_reg(tx_dat_rdy));                   
设置UCF文件分配好管脚就可以用来发送数据了,但要注意目前我可是没有给数据源噢,
不过也可以写个模块模拟产生一个源噢,然后就可以源源不断地发送数据到PC端了,呵呵,
stimulus_uart_tx gentxq(.clk(buzzerClk),//产生源数据的时钟  我用的是0.0625s
                        .txStart(txFlgPin),//发送状态标志,避免一个字符发N次,
                        .reset(rst), 
                        .databus(tx_reg),  //产生要发送的数据;
                        .data_rdy(tx_dat_rdy),//启动发送,只维持一个发送时钟周期
                        .txFlgpin(txRdyPin));  //这个是我留的一个测试点,LED
把全部代码编译生成BIT文件后写入,就看见复位一次就发送出"123.....z"的串,
这个激励是由模拟的激励模块产生的噢,

No comments: