verilong 串口通信程序及原理
作者:互联网
通过回环测试,可以先用串口把数据链路验证。接收程序
module uart_rx #( parameter UART_BPS = 'd9600, //串口波特率 parameter CLK_FREQ = 'd50_000_000 //时钟频率 ) ( input wire sys_clk , //系统时钟50MHz input wire sys_rst_n , //全局复位 input wire rx , //串口接收数据 output reg [7:0] po_data , //串转并后的8bit数据 output reg po_flag //串转并后的数据有效标志信号 ); //********************************************************************// //****************** Parameter and Internal Signal *******************// //********************************************************************// //localparam define localparam BAUD_CNT_MAX = CLK_FREQ/UART_BPS ; //reg define reg rx_reg1 ; reg rx_reg2 ; reg rx_reg3 ; reg start_nedge ; reg work_en ; reg [12:0] baud_cnt ; reg bit_flag ; reg [3:0] bit_cnt ; reg [7:0] rx_data ; reg rx_flag ; //********************************************************************// //***************************** Main Code ****************************// //********************************************************************// //插入两级寄存器进行数据同步,用来消除亚稳态 //rx_reg1:第一级寄存器,寄存器空闲状态复位为1 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) rx_reg1 <= 1'b1; else rx_reg1 <= rx; //rx_reg2:第二级寄存器,寄存器空闲状态复位为1 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) rx_reg2 <= 1'b1; else rx_reg2 <= rx_reg1; //rx_reg3:第三级寄存器和第二级寄存器共同构成下降沿检测 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) rx_reg3 <= 1'b1; else rx_reg3 <= rx_reg2; //start_nedge:检测到下降沿时start_nedge产生一个时钟的高电平 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) start_nedge <= 1'b0; else if((~rx_reg2) && (rx_reg3)) start_nedge <= 1'b1; else start_nedge <= 1'b0; //work_en:接收数据工作使能信号 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) work_en <= 1'b0; else if(start_nedge == 1'b1) work_en <= 1'b1; else if((bit_cnt == 4'd8) && (bit_flag == 1'b1)) work_en <= 1'b0; //baud_cnt:波特率计数器计数,从0计数到BAUD_CNT_MAX - 1 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) baud_cnt <= 13'b0; else if((baud_cnt == BAUD_CNT_MAX - 1) || (work_en == 1'b0)) baud_cnt <= 13'b0; else if(work_en == 1'b1) baud_cnt <= baud_cnt + 1'b1; //bit_flag:当baud_cnt计数器计数到中间数时采样的数据最稳定, //此时拉高一个标志信号表示数据可以被取走 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) bit_flag <= 1'b0; else if(baud_cnt == BAUD_CNT_MAX/2 - 1) bit_flag <= 1'b1; else bit_flag <= 1'b0; //bit_cnt:有效数据个数计数器,当8个有效数据(不含起始位和停止位) //都接收完成后计数器清零 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) bit_cnt <= 4'b0; else if((bit_cnt == 4'd8) && (bit_flag == 1'b1)) bit_cnt <= 4'b0; else if(bit_flag ==1'b1) bit_cnt <= bit_cnt + 1'b1; //rx_data:输入数据进行移位 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) rx_data <= 8'b0; else if((bit_cnt >= 4'd1)&&(bit_cnt <= 4'd8)&&(bit_flag == 1'b1)) rx_data <= {rx_reg3, rx_data[7:1]}; //rx_flag:输入数据移位完成时rx_flag拉高一个时钟的高电平 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) rx_flag <= 1'b0; else if((bit_cnt == 4'd8) && (bit_flag == 1'b1)) rx_flag <= 1'b1; else rx_flag <= 1'b0; //po_data:输出完整的8位有效数据 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) po_data <= 8'b0; else if(rx_flag == 1'b1) po_data <= rx_data; //po_flag:输出数据有效标志(比rx_flag延后一个时钟周期,为了和po_data同步) always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) po_flag <= 1'b0; else po_flag <= rx_flag; endmodule
标签:rx,通信,reg1,sys,串口,bit,reg,verilong 来源: https://www.cnblogs.com/Fifthspace/p/14121245.html