大家好,欢迎来到IT知识分享网。
文章目录
一.校验位原理
- 校验分为无校验位,奇校验位和偶校验位
1.奇校验
- 数据位中1的个数为奇数,则校验位为0,否则校验位为1
2.偶校验
- 数据为中1的个数为偶数,则校验位为0,否则校验位为1
二.设计思路
- 根据传输的数据计算出一个校验位和我们传输的校验位做对比。使能信号需要保证在传输的校验位和计算的校验位相等时才有效
- 根据无校验位,奇校验位,偶校验位三种情况,需要改变状态转移图
- uart_tx
- uart_rx
三.代码
1.uart_tx
/功能介绍* Date : 2023年8月16日17:07:11 Author : Alegg xy. Version : 2.0 Description: FPGA向上位机发送数据【8bit变1bit(波形)】 */ //---------<模块及端口声名>------------------------------------------------------ module uart_tx( input clk , input rst_n , input [7:0] tx_data , input tx_data_vld, output ready , output reg tx ); //---------<参数定义>--------------------------------------------------------- parameter MAX_BPS = ; parameter CLOCK = 50_000_000; parameter MAX_1bit = CLOCK/MAX_BPS;//1bit要计434次 parameter CHECK_BIT = "None";//None无校验,Odd奇校验,Even偶校验 //状态机参数定义 localparam IDLE = 'b00001,//空闲状态 START = 'b00010,//起始位 DATA = 'b00100,//数据位 CHECK = 'b01000,//校验位 STOP = 'b10000;//停止位 //---------<内部信号定义>----------------------------------------------------- reg [4:0] cstate ;//现态 reg [4:0] nstate ;//次态 wire IDLE_START; wire START_DATA; wire DATA_CHECK; wire CHECK_STOP; wire STOP_IDLE; reg [8:0] cnt_baud ;//波特计数器,波特率 wire add_cnt_baud ; wire end_cnt_baud ; reg [2:0] cnt_bit ;//bit计数器,起始位1bit,数据位8bit,结束位1bit wire add_cnt_bit ; wire end_cnt_bit ; reg [3:0] bit_max;//bit最大值,复用需要考察每个状态的bit值 reg [7:0] tx_data_r; wire check_val; //计434次 always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_baud <= 'd0; end else if(add_cnt_baud)begin if(end_cnt_baud)begin cnt_baud <= 'd0; end else begin cnt_baud <= cnt_baud + 1'd1; end end end assign add_cnt_baud = cstate != IDLE; assign end_cnt_baud = add_cnt_baud && cnt_baud == MAX_1bit - 1'd1; //bit计数器 always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_bit <= 'd0; end else if(add_cnt_bit)begin if(end_cnt_bit)begin cnt_bit <= 'd0; end else begin cnt_bit <= cnt_bit + 1'd1; end end end assign add_cnt_bit = end_cnt_baud; assign end_cnt_bit = add_cnt_bit && cnt_bit == bit_max -1'd1; //计数器复用 always @(*)begin case (cstate) IDLE :bit_max = 'd0; START:bit_max = 'd1;//起始位1bit DATA :bit_max = 'd8;//数据位7bit CHECK:bit_max = 'd1;//校验位1bit STOP :bit_max = 'd1;//结束位1bit default: bit_max = 'd0; endcase end assign IDLE_START = (cstate == IDLE) && tx_data_vld;//考察到开始传输信号 assign START_DATA = (cstate == START) && end_cnt_bit;//计1bit数据 assign DATA_STOP = (cstate == DATA) && end_cnt_bit && CHECK_BIT == "None"; assign DATA_CHECK = (cstate == DATA) && end_cnt_bit;//计8bit数据 assign CHECK_STOP = (cstate ==CHECK) && end_cnt_bit;//计1bit数据 assign STOP_IDLE = (cstate == STOP) && end_cnt_bit;//计1bit数据 //第一段:时序逻辑描述状态转移 always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cstate <= IDLE; end else begin cstate <= nstate; end end //第二段:组合逻辑描述状态转移规律和状态转移条件 always @(*) begin case(cstate) IDLE :begin if (IDLE_START) begin nstate = START; end else begin nstate = cstate; end end START :begin if (START_DATA) begin nstate = DATA; end else begin nstate = cstate; end end DATA :begin if (DATA_CHECK) begin nstate = CHECK; end else if (DATA_STOP) begin nstate = STOP; end else begin nstate = cstate; end end CHECK :begin if (CHECK_STOP) begin nstate = STOP; end else begin nstate = cstate; end end STOP :begin if (STOP_IDLE) begin nstate = IDLE; end else begin nstate = cstate; end end default : nstate = cstate; endcase end //寄存一拍 always @(posedge clk or negedge rst_n) begin if (!rst_n) begin tx_data_r <= 'd0; end else if (tx_data_vld) begin tx_data_r <= tx_data; end else begin tx_data_r <= tx_data_r; end end assign check_val = (CHECK_BIT == "Odd") ? ~^tx_data_r : ^tx_data_r; //第三段:描述输出,时序逻辑或组合逻辑皆可 always @(*)begin case (cstate) IDLE : tx = 1'b1; START: tx = 1'b0;//起始位为0 DATA : tx = tx_data_r[cnt_bit]; CHECK: tx = check_val; STOP : tx = 1'b1;//结束位为1 default: tx = 1'b1; endcase end assign ready = cstate == IDLE;//当状态为IDLE时,表示tx端可以接收数据 endmodule
2.uart_rx
/功能介绍* Date : 2023年8月16日18:25:03 Author : Alegg xy. Version : 1.0 Description: FPGA收上位机发来的数据【1bit(波形)变8bit】 */ //---------<模块及端口声名>------------------------------------------------------ module uart_rx( input clk , input rst_n , input rx , output rx_data_vld, output [7:0] rx_data ); //---------<参数定义>--------------------------------------------------------- parameter MAX_BPS = ; parameter CLOCK = 50_000_000; parameter MAX_1bit = CLOCK/MAX_BPS;//1bit要计434次 parameter CHECK_BIT = "None";//None无校验,Odd奇校验,Even偶校验 //状态机参数定义 localparam IDLE = 'b0001,//空闲状态 START = 'b0010,//起始位 DATA = 'b0100,//数据位 CHECK = 'b1000; //---------<内部信号定义>----------------------------------------------------- reg [3:0] cstate ;//现态 reg [3:0] nstate ;//次态 wire IDLE_START; wire START_DATA; wire DATA_IDLE; wire DATA_CHECK; wire CHECK_IDLE; reg [8:0] cnt_baud ;//波特计数器,波特率 wire add_cnt_baud ; wire end_cnt_baud ; reg [2:0] cnt_bit ;//bit计数器,起始位1bit,数据位8bit,结束位1bit wire add_cnt_bit ; wire end_cnt_bit ; reg [3:0] bit_max;//bit最大值,复用需要考察每个状态的bit值 reg [7:0] rx_temp; reg rx_check; wire check_val; reg rx_r1; reg rx_r2; wire rx_nege; //打两拍 always @(posedge clk or negedge rst_n) begin if (!rst_n) begin rx_r1 <= 1; rx_r2 <= 1; end else begin rx_r1 <= rx; rx_r2 <= rx_r1; end end assign rx_nege = ~rx_r1 && rx_r2; //计434次 always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_baud <= 'd0; end else if(add_cnt_baud)begin if(end_cnt_baud)begin cnt_baud <= 'd0; end else begin cnt_baud <= cnt_baud + 1'd1; end end end assign add_cnt_baud = cstate != IDLE; assign end_cnt_baud = add_cnt_baud && cnt_baud == MAX_1bit - 1'd1; //bit计数器 always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_bit <= 'd0; end else if(add_cnt_bit)begin if(end_cnt_bit)begin cnt_bit <= 'd0; end else begin cnt_bit <= cnt_bit + 1'd1; end end end assign add_cnt_bit = end_cnt_baud; assign end_cnt_bit = add_cnt_bit && cnt_bit == bit_max -1'd1; //计数器复用 always @(*)begin case (cstate) IDLE :bit_max = 'd0; START:bit_max = 'd1;//起始位1bit DATA :bit_max = 'd8;//数据位8bit CHECK:bit_max = 'd1; default: bit_max = 'd0; endcase end assign IDLE_START = (cstate == IDLE) && rx_nege;//识别到起始位0 assign START_DATA = (cstate == START) && end_cnt_bit;//计1bit数据 assign DATA_IDLE = (cstate == DATA) && end_cnt_bit && CHECK_BIT == "None";//计8bit数据 assign DATA_CHECK = (cstate == DATA) && end_cnt_bit; assign CHECK_IDLE = (cstate == CHECK) && end_cnt_bit; //第一段:时序逻辑描述状态转移 always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cstate <= IDLE; end else begin cstate <= nstate; end end //第二段:组合逻辑描述状态转移规律和状态转移条件 always @(*) begin case(cstate) IDLE :begin if (IDLE_START) begin nstate = START; end else begin nstate = cstate; end end START :begin if (START_DATA) begin nstate = DATA; end else begin nstate = cstate; end end DATA :begin if (DATA_IDLE) begin nstate = IDLE; end else if (DATA_CHECK) begin nstate = CHECK; end else begin nstate = cstate; end end CHECK:begin if (CHECK_IDLE) begin nstate = IDLE; end else begin nstate = cstate; end end default : nstate = IDLE; endcase end //接受校验位 always @(posedge clk or negedge rst_n) begin if (!rst_n) begin rx_check <= 0; end else if (cstate == CHECK && cnt_baud == MAX_1bit >>1) begin rx_check <= rx_r1; end end //计算校验位 assign check_val = (CHECK_BIT == "Odd") ? ~^rx_temp : ^rx_temp; //第三段:描述输出,时序逻辑或组合逻辑皆可 always @(posedge clk or negedge rst_n) begin if (!rst_n) begin rx_temp <= 0; end else if (cstate == DATA && cnt_baud == MAX_1bit >> 1) begin//电平中间值采样,边沿采样容易出错 rx_temp[cnt_bit] <= rx_r1; end else begin rx_temp <= rx_temp; end end assign rx_data = rx_temp; assign rx_data_vld = (CHECK_BIT == "None") ? DATA_IDLE :(CHECK_IDLE && (check_val == rx_check)) ? 1 : 0; endmodule
- 其中可以通过top重定义MAX_BPS和CHECK_BIT来修改波特率和校验位
四.仿真
- 仿真有多种情况
1.无校验位
1.1无校验位总仿真
1.2无校验位rx
1.3无校验位tx
2.奇校验位
2.1奇校验位正确总仿真
2.2奇校验位正确rx
2.3奇校验位正确tx
2.4奇校验位错误总仿真
2.5奇校验位错误rx
2.6奇校验位错误tx
3.偶校验位
2.1偶校验位正确总仿真
2.2偶校验位正确rx
2.3偶校验位正确tx
2.4偶校验位错误总仿真
2.5偶校验位错误rx
2.6偶校验位错误tx
五.效果
5.1如何在串口助手中设置校验位
- 选择左下角的更多串口设置后弹窗中调整校验位(None:无校验位、Odd:奇校验位、Even:偶校验位)
5.2奇校验
- 这里代码中设置奇校验,串口设置无校验位时会有一些问题,大家如果发现了我的错误在哪可以私信或者评论我一下,谢谢大家了
5.3偶校验
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/121171.html



















