FPGA串口接收Demo
创始人
2024-02-07 23:48:04
0

串口接收Demo

简单介绍

在发送数据时将并行数据转换成串行数据来传输,在接收数据时将接收到的串行数据转换成并行数据

在这里插入图片描述

  • 空闲状态时,为高电平
  • 起始位为一个单位长度低电平,停止位为一个长度高电平
分析
帧格式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aMQEeA18-1669128642072)(https://gitee.com/wangchaosun/picgo/raw/master/image-20221122222307710.png)]

  • 8位数据位
  • 1位停止位
  • 无校验位
基本思路

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LDKeGrYm-1669128642074)(https://gitee.com/wangchaosun/picgo/raw/master/image-20221122223525080.png)]

采集每一位中间时刻的数据作为这一位的数据 ( 也可以每一位多采几个时刻的数据,取众数 )

框图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6yEkqLBs-1669128642075)(https://gitee.com/wangchaosun/picgo/raw/master/image-20221122222417869.png)]

状态机

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tBpPzN04-1669128642076)(https://gitee.com/wangchaosun/picgo/raw/master/image-20221122222530106.png)]

Verilog
`timescale 1ns / 1ps
//
// Engineer: wkk
// Create Date: 2022/11/22 16:35:19
// Module Name: uart_rx
// Description: uart rx function
//
module uart_rx(input               sys_clk,input               sys_rst_n,input               uart_rx,output              uart_rx_valid,output  [7:0]       uart_rx_data
);parameter  SYS_CLK         = 100_000_000;
// 115200
parameter  BAUD_COUNT      =  868;
parameter  BAUD_HALF_COUNT =  434;
parameter  TIME_COUNT_LEN  =  12;localparam IDLE_STATE       = 4'd0;
localparam START_STATE      = 4'd1;
localparam RECV_STATE       = 4'd2;
localparam RECV_D0_STATE    = 4'd3;
localparam RECV_D1_STATE    = 4'd4; 
localparam RECV_D2_STATE    = 4'd5; 
localparam RECV_D3_STATE    = 4'd6; 
localparam RECV_D4_STATE    = 4'd7; 
localparam RECV_D5_STATE    = 4'd8; 
localparam RECV_D6_STATE    = 4'd9; 
localparam RECV_D7_STATE    = 4'd10; 
localparam END_STATE        = 4'd11; reg [3:0]   curr_state;
reg [3:0]   next_state;reg         uart_rx_d0;
reg         uart_rx_d1;
wire        uart_rx_en;// 开始计时
reg         time_en;
// 计时模式 0: 计数一个波特率周期 1: 计数半个波特率周期  
reg         half_en;
reg         count_en;
reg         [TIME_COUNT_LEN-1:0] time_count;reg  [7:0]  rx_data;
reg  [3:0]  rx_data_index;// 计时模块
always @(posedge sys_clk or negedge sys_rst_n) beginif(!sys_rst_n || !time_en) begin time_count <= 0;count_en <= 0;end else if(half_en)if(time_count == BAUD_HALF_COUNT -1 )begintime_count <=0;count_en <= 1;endelse begintime_count <= time_count + 1'b1;count_en <= 0;end else if(time_count == BAUD_COUNT -1 )begincount_en <= 1;time_count <= 0;endelse begintime_count <= time_count + 1'b1;count_en <= 0;end
end// 产生下一状态
always @(*) begincase( curr_state )IDLE_STATE: beginif( uart_rx_en )next_state = START_STATE;else next_state = IDLE_STATE;endSTART_STATE:if( count_en)next_state = RECV_STATE;elsenext_state = START_STATE;RECV_STATE:if( count_en )next_state = RECV_D0_STATE;elsenext_state = RECV_STATE;RECV_D0_STATE:if( count_en )next_state = RECV_D1_STATE;elsenext_state = RECV_D0_STATE;RECV_D1_STATE:if( count_en )next_state = RECV_D2_STATE;elsenext_state = RECV_D1_STATE;RECV_D2_STATE:if( count_en )next_state = RECV_D3_STATE;elsenext_state = RECV_D2_STATE;RECV_D3_STATE:if( count_en )next_state = RECV_D4_STATE;elsenext_state = RECV_D3_STATE;RECV_D4_STATE:if( count_en )next_state = RECV_D5_STATE;elsenext_state = RECV_D4_STATE;RECV_D5_STATE:if( count_en )next_state = RECV_D6_STATE;elsenext_state = RECV_D5_STATE;RECV_D6_STATE:if( count_en )next_state = RECV_D7_STATE;elsenext_state = RECV_D6_STATE;RECV_D7_STATE:if( count_en )next_state = END_STATE;elsenext_state = RECV_D7_STATE;END_STATE:next_state = IDLE_STATE;default: ;endcase
endassign uart_rx_data = rx_data;
assign uart_rx_valid = (curr_state == END_STATE)?1'b1:1'b0;// 状态输出
always @(posedge sys_clk or negedge sys_rst_n) beginif(!sys_rst_n) beginrx_data <= 7'b0;time_en <= 1'b0;half_en <= 1'b0;rx_data_index <= 3'b0;end elsecase(curr_state)IDLE_STATE: begintime_en <= 1'b0;half_en <= 1'b0;rx_data_index <= 3'b0;endSTART_STATE: begintime_en <= 1'b1;half_en <= 1'b1;endRECV_STATE:begintime_en <= 1'b1;half_en <= 1'b0;end     RECV_D0_STATE:if(rx_data_index == 3'd0)beginrx_data[0] <= uart_rx;rx_data_index <= rx_data_index + 1'b1;end elserx_data[0] <= rx_data[0];      RECV_D1_STATE:if(rx_data_index == 3'd1)beginrx_data[1] <= uart_rx;rx_data_index <= rx_data_index + 1'b1;end elserx_data[1] <= rx_data[1];RECV_D2_STATE:if(rx_data_index == 3'd2)beginrx_data[2] <= uart_rx;rx_data_index <= rx_data_index + 1'b1;end elserx_data[2] <= rx_data[2];RECV_D3_STATE:if(rx_data_index == 3'd3)beginrx_data[3] <= uart_rx;rx_data_index <= rx_data_index + 1'b1;end elserx_data[3] <= rx_data[3];RECV_D4_STATE:if(rx_data_index == 3'd4)beginrx_data[4] <= uart_rx;rx_data_index <= rx_data_index + 1'b1;end elserx_data[4] <= rx_data[4];RECV_D5_STATE:if(rx_data_index == 3'd5)beginrx_data[5] <= uart_rx;rx_data_index <= rx_data_index + 1'b1;end elserx_data[5] <= rx_data[5];RECV_D6_STATE:if(rx_data_index == 3'd6)beginrx_data[6] <= uart_rx;rx_data_index <= rx_data_index + 1'b1;end elserx_data[6] <= rx_data[6];RECV_D7_STATE:if(rx_data_index == 3'd7)beginrx_data[7] <= uart_rx;rx_data_index <= rx_data_index + 1'b1;end elserx_data[7] <= rx_data[7];END_STATE:begintime_en <= 1'b0;half_en <= 1'b0;rx_data_index <= 3'b0;enddefault: ;endcase
end// catch rising edge 
assign uart_rx_en = (uart_rx_d0 & !uart_rx_d1) ? 1'b1:1'b0;always @(posedge sys_clk or negedge sys_rst_n) beginif(!sys_rst_n) beginuart_rx_d0 <= 1'b0;uart_rx_d1 <= 1'b0;end else beginuart_rx_d1 <= uart_rx;uart_rx_d0 <= uart_rx_d1;end 
end// update curr_state
always @(posedge sys_clk or negedge sys_rst_n) beginif(!sys_rst_n) curr_state <= IDLE_STATE;elsecurr_state <= next_state;
endendmodule
testbench
`timescale 1ns / 1ns
//
// Engineer: wkk
// Module Name: uart_rx_tb
//module uart_rx_tb;
reg         sys_clk;
reg         sys_rst_n;
reg         uart_rx;
wire        uart_rx_valid;
wire [7:0]  uart_rx_data;parameter BAUD_COUNT      = 20;
parameter BAUD_HALF_COUNT = 10;
parameter TIME_COUNT_LEN  = 5;
uart_rx #(.BAUD_COUNT     (BAUD_COUNT),.BAUD_HALF_COUNT(BAUD_HALF_COUNT),.TIME_COUNT_LEN (TIME_COUNT_LEN)
)u_uart_rx(.sys_clk        (sys_clk),.sys_rst_n      (sys_rst_n),.uart_rx        (uart_rx),.uart_rx_valid  (uart_rx_valid),.uart_rx_data   (uart_rx_data)
);initial begin sys_clk = 0;sys_rst_n = 0;uart_rx = 1;endalways #5 sys_clk = !sys_clk;initial begin#10 sys_rst_n = 1;#30 uart_rx = 0;  // 起始位#200 uart_rx = 0; #200 uart_rx = 1;#200 uart_rx = 1;#200 uart_rx = 1;#200 uart_rx = 0;#200 uart_rx = 1;#200 uart_rx = 1;#200 uart_rx = 0;#200 uart_rx = 1; // 停止位#450$stop;endendmodule

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PUpUJd90-1669128642076)(https://gitee.com/wangchaosun/picgo/raw/master/uart_rx_sim.png)]

总结
三段式状态机

使用三个always 模块

  1. 第一个always模块采用同步时序描述状态转移
  2. 第二个always模块采用组合逻辑判断状态转移条件,描述状态转移规律
  3. 第三个always模块描述状态输出(可以使用组合电路输出,也可以使用时序电路输出)
对应代码结构

第一段

always @(posedge sys_clk or negedge sys_rst_n) beginif(!sys_rst_n) curr_state <= IDLE_STATE;elsecurr_state <= next_state;
end

第二段

always @(*) begincase( curr_state )// ....endcase
end

第三段

always @(posedge sys_clk or negedge sys_rst_n) beginif(!sys_rst_n) begin//...end else begin//...end
end
第二段不使用同步时序逻辑的原因

always 的执行是并行的

倘若使用同步时序逻辑,则:

  • 第一段的内容: curr_state <-- next_state

    将下一状态变为当前状态,状态更新

  • 第二段的内容:需要根据curr_state的值结合其他条件,得出下一状态

  • 第一段改变curr_state的值,第二段需要使用curr_state的值,并且两者是并行执行的,会形成冲突,可能使得第二段使用的curr_state是未更新前的,导致状态转移的错误。

相关内容

热门资讯

珍爱生命的名人名言 珍爱生命的名人名言(精选55句)  关于生命的名人名言有哪些?生命,值得我们尊重,你知道哪些关于生命...
关于知音的名言名句  导语:关于知音或者是友谊的古诗词, 名人名言,这里全都有,关于知音的名言名句。  君子之交淡若水,...
清正廉洁格言 清正廉洁格言最短的人生格言1、执政以廉为本,为官以勤为先。2、做人一身正气,为官一尘不染。3、名位利...
罗素名言 罗素名言69句  1、伟大的事业是根源于坚韧不断的工作,以全付精神去从事,不避艰苦。——罗素  2、...
朋友的名人名言 有关朋友的名人名言汇总  在学习、工作、生活中,大家都不可避免地会接触并使用名言吧,名言可以用来鞭策...
乔布斯名言经典摘抄 乔布斯名言经典摘抄  乔布斯出生于美国加利福尼亚州旧金山,美国发明家、企业家、美国苹果公司联合创办人...
夺眶而出的名言名句 关于夺眶而出的名言名句  这里是郁郁葱葱的山神之森,一定,要有一段时间无法再盼望夏天了,心如刀绞,泪...
信仰名言 精选关于信仰名言  关于信仰名言  1、没有信仰的人如同盲人(弥顿)  2、有信仰未必能成大事,而没...
告诉自己珍惜时间的名言名句 志士惜年,贤人惜日,圣人惜时,告诉自己珍惜时间的名言名句。圣人都珍惜时间,我们凡人更要珍惜时间。下面...
工匠精神的名人名言 关于工匠精神的名人名言  1、最佳的创新定义是“不限大小,不限部门”。 最有效的创新都简单得惊人,其...
青春奋斗的名言警句 关于青春奋斗的名言警句1、青春是美妙的,挥霍青春就是犯罪,关于青春奋斗的名言警句。——萧伯纳  2、...
理想的阶梯 理想的阶梯理想的阶梯[教学目标]1.通过学习本文,使学生懂得“奋斗,是实现理想的阶梯”这一道理,并能...
激励的名言警句 激励的名言警句50句  大家都听过哪些激励的话呢?还记得吗?下面,小编为大家分享激励的名言警句,希望...
清明节家风家训的名言 清明节家风家训的名言  家风不仅是民风社风的组成要素,也是中华民族传统价值观的重要组成部分,各位,我...
英文爱情电影名言 英文爱情电影名言1) i love you not because of who you are, ...
霸气青春励志名言英语短句 霸气青春励志名言英语短句  青春是美好的时光,也是很重要的时光,下面unjs小编整理了霸气青春励志名...
文化的名言 关于文化的名言  文化是一种社会现象,是人们长期创造形成的产物,同时又是一种历史现象,是社会历史的积...
每日英语励志名言 每日一句英语励志名言  1、 No one can walk backward into the f...
感谢老师的成语和名言 感谢老师的成语和名言  春风化雨  有教无类  平易近人  古道热肠  十年树木,百年树人  作育英...
孝老敬亲的名人名言 关于孝老敬亲的名人名言  泱泱中华,礼义之邦,道德传统,源远流长。敬老孝老,是我们的传统美德,是我们...