学单片机时是从串口开始的,学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:
Post a Comment