赞
踩
程序中使用到串口通信,mcu串口不够用了,使用fpga扩展出一路串口供使用,特此记录。
1、串口波特率自定义
2、串口同时支持发送及接收
3、串口接收到的数据传输至mcu解析,mcu将要发送的数据送至fpga发出
4、未使用到校验位,仅预留(未作)
串口通信过程中状态明确,选择三段式状态机进行实现
状态包含:IDLE(空闲)START(起始)DATA(数据移位)CHECK(校验)STOP(停止)
模块分为3部分,接收部分,发送部分,顶层模块
- /*
- 将rx引脚上的串口数据送至data_o[7:0]寄存器,data_en高有效
- */
- module uart_rx
- #(parameter BPS_WID = 9,
- parameter BPS_CNT = 434) //115200
- (
- input sys_clk,
- input rst_n,
-
- input rx,
- output reg[7:0]data_o,
- output data_en
- );
-
- localparam IDLE = 5'b00000,
- START= 5'b00001,
- DATA = 5'b00010,
- CHECK= 5'b00100,
- STOP = 5'b01000,
- WAIT = 5'b10000; //校验错误时进入
- /*******************************************************
- RX_module
- *******************************************************/
- wire rx_str_n,rx_bit;
- reg [2:0]rx_r;
- reg [BPS_WID-1:0] baud_cnt;
-
- assign rx_bit = rx_r[1];
- // assign clk_bps = baud_cnt < BPS_CNT/2;
- //消除亚稳态,产生起始下降沿
- assign rx_str_n = (!rx_r[1])&(rx_r[2]);
-
- always @(posedge sys_clk) begin
- rx_r <= {rx_r[1:0],rx};
- end
- //--1
- (*noprune*)reg [4:0]cur_st,nxt_st;
- reg [7:0]rx_data;
-
- always @(posedge sys_clk or negedge rst_n) begin
- if(!rst_n) cur_st <= IDLE;
- else cur_st <= nxt_st;
- end
- //--2
- reg [3:0]bit_cnt;
- always @(*) begin
- case(cur_st)
- IDLE :begin
- if(rx_str_n) nxt_st = START;
- else nxt_st = IDLE;
- end
- START :begin
- if(baud_cnt == BPS_CNT/2) nxt_st = DATA;
- else nxt_st = START;
- end
- DATA :begin
- if(bit_cnt < 'd9) nxt_st = DATA;
- else nxt_st = CHECK;
- end
- CHECK :begin
- if(baud_cnt == BPS_CNT/2) nxt_st = STOP;
- else nxt_st = CHECK;
- end
- STOP :
- if(baud_cnt == BPS_CNT/2) nxt_st = IDLE;
- else nxt_st = STOP;
- WAIT : nxt_st <= IDLE;
- default : nxt_st <= IDLE;
- endcase
- end
- //--3
- always @(posedge sys_clk) begin
- if((nxt_st == START)||(nxt_st == DATA)||
- (nxt_st == CHECK)||(nxt_st == STOP))begin
- if(baud_cnt < BPS_CNT - 'd1)
- baud_cnt <= baud_cnt + 'd1;
- else
- baud_cnt <= 'd0;
- end
- end
-
- always @(posedge sys_clk or negedge rst_n) begin
- if(!rst_n)begin
- rx_data <= 'd0;
- bit_cnt <= 'd1;
- end
- else if((baud_cnt == BPS_CNT/2)&&(nxt_st == DATA)&&(bit_cnt < 'd9))begin
- rx_data[bit_cnt - 'd1] <= rx_bit;
- bit_cnt <= bit_cnt + 'd1;
- end
- else if(nxt_st == STOP)begin
- data_o <= rx_data;
- end
- else if(nxt_st == START)begin
- rx_data <= 'd0;
- bit_cnt <= 'd1;
- end
- end
- //--数据有效信号
- wire back_end;
- reg [1:0]en_dely;
- assign back_end = (cur_st==STOP);
- assign data_en = en_dely[1]&(!en_dely[0]);
- always @(posedge sys_clk) begin
- en_dely <= {en_dely[0],back_end};
- end
- endmodule
- /*
- 将data_i[7:0]寄存器的数据以串口格式发送到tx引脚上,
- data_en高时,data_i[7:0]数据有效
- busy: 1:模块忙 0:无操作
- */
- module uart_tx
- #(parameter BPS_WID = 9,
- parameter BPS_CNT = 434) //115200
- (
- input sys_clk ,
- input rst_n ,
-
- input [7:0]data_i ,
- input data_en ,
-
- output reg tx ,
- output reg busy //1:busy 0:no busy
- );
-
- localparam IDLE = 5'b00000,
- START= 5'b00001,
- DATA = 5'b00010,
- CHECK= 5'b00100,
- STOP = 5'b01000;
- /*******************************************************
- TX_module
- *******************************************************/
- reg [BPS_WID-1:0] baud_cnt;
- reg [7:0]tx_data;
- reg str_p,par_data = 1'b1;
- //预存数据
- always @(posedge sys_clk) begin
- if(data_en &(!busy))begin
- tx_data <= data_i;
- str_p <= 'd1;
- end
- else
- str_p <= 'd0;
- end
- //--1
- (*noprune*)reg [4:0]cur_st,nxt_st;
-
- always @(posedge sys_clk or negedge rst_n) begin
- if(!rst_n) cur_st <= IDLE;
- else cur_st <= nxt_st;
- end
- //--2
- reg [3:0]bit_cnt;
- always @(*) begin
- case(cur_st)
- IDLE :begin
- if(str_p) nxt_st = START;
- else nxt_st = IDLE;
- end
- START :begin
- if(baud_cnt < BPS_CNT - 'd1) nxt_st = START;
- else nxt_st = DATA;
- end
- DATA :begin
- if(bit_cnt < 'd9) nxt_st = DATA;
- else nxt_st = CHECK;
- end
- CHECK :begin
- if(baud_cnt < BPS_CNT - 'd1) nxt_st = CHECK;
- else nxt_st = STOP;
- end
- STOP :begin
- if(baud_cnt < BPS_CNT - 'd1) nxt_st = STOP;
- else nxt_st = IDLE;
- end
- default : nxt_st <= IDLE;
- endcase
- end
- //--3
- always @(posedge sys_clk) begin
- if((nxt_st == START)||(nxt_st == DATA)||
- (nxt_st == CHECK)||(nxt_st == STOP))begin
- if(baud_cnt < BPS_CNT - 'd1)
- baud_cnt <= baud_cnt + 'd1;
- else
- baud_cnt <= 'd0;
- end
- else
- baud_cnt <= 'd0;
- end
-
- always @(posedge sys_clk) begin
- case(nxt_st)
- IDLE : tx <= 1'b1;
- START : tx <= 1'b0;
- DATA : if(bit_cnt > 'd0) tx <= tx_data[bit_cnt - 'd1];
- CHECK : tx <= par_data;
- STOP : tx <= 1'b1;
- default : tx <= 1'b1;
- endcase
- end
- always @(posedge sys_clk) begin
- if(cur_st == IDLE) busy <= 'd0;
- else busy <= 'd1;
- end
- always @(posedge sys_clk or negedge rst_n) begin
- if(!rst_n)begin
- bit_cnt <= 'd0;
- end
- else if((baud_cnt == BPS_CNT-'d1)&&(nxt_st == DATA)&&(bit_cnt < 'd9))begin
- bit_cnt <= bit_cnt + 'd1;
- end
- else if(nxt_st == START)begin
- bit_cnt <= 'd0;
- end
- end
- endmodule
功能描述:fpga将串口接收模块收到的数据“+1”后,送至串口发送模块,发送至电脑串口助手
例如:串口助手发送0x11,接收到0x12 (0x11+0x01)
- module uart_mt(
- input sys_clk,
- input rst_n,
-
- // input [7:0]tx_data,
- // output [7:0]rx_data,
-
- input rx,
- output tx,
- output tx_busy
- );
- localparam BAUD_WID = 11;
- localparam BAUD_CNT = 1302; //38400
- //----------------
- wire [7:0]rx_d;
- wire rx_e;
- //----------------
- wire tx_e;
- reg [3:0]dely_cnt;
- reg [7:0]rx_data,tx_data;
- reg tx_str;
-
- always @(posedge sys_clk) begin
- if(rx_e) begin
- rx_data <= rx_d;
- tx_str <= 1'd1;
- dely_cnt <= 'd0;
- end
- else if((tx_str)&&(dely_cnt < 'd5))
- dely_cnt <= dely_cnt + 'd1;
- else if(dely_cnt == 'd5)
- tx_str <= 'd0;
- end
- always @(posedge sys_clk) begin
- tx_data <= rx_data + 'd1;
- end
- assign tx_e = (dely_cnt == 'd4);
-
- uart_tx #(
- .BPS_WID (BAUD_WID ),
- .BPS_CNT (BAUD_CNT )
- )u1_uart_tx(
- .sys_clk (sys_clk ),
- .rst_n (rst_n ),
- .data_i (tx_data ),
- .data_en (tx_e ),
- .tx (tx ),
- .busy () //1:busy 0:no busy
- );
-
- uart_rx #(
- .BPS_WID (BAUD_WID ),
- .BPS_CNT (BAUD_CNT )
- )u1_uart_rx(
- .sys_clk (sys_clk ),
- .rst_n (rst_n ),
- .rx (rx ),
- .data_o (rx_d ),
- .data_en (rx_e )
- );
-
- endmodule
signaltap II实物调试波形
串口助手界面
波特率:38400
波特率:115200
如若需要实现连续接收,则可搭配ram或fifo,对数据进行保存。
如需实现连续发送,则将数据写入ram中,持续监测busy信号,再no busy时将数据读出,送入发送模块即可。
至此,串口收发均验证完成,数据收发正常,此次功能简单,未进行仿真验证,但有signtap波形图可以看出功能符合预期,后续有时间再增加modelsim仿真波形图
欢迎大家互相交流
测试数据为:0x69
符合预期
测试数据为:0xdb
波形数据为0b 1101 1011,即(0xdb),符合预期
注:之前的代码发送模块发送数据时第一位数据发送前2个clk对TX数据线操作有误,实物调试无法观测到,已修正。
#生活很苦 自己加糖# 习惯不贪心,太好的东西总是留不住
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。