赞
踩
本代码参考了野火的相关教程,实现了发送和接收回环,同时可以通过串口数据控制LED灯的亮灭,在电脑发送数据时要选择HEX发送模式,发送16进制的数据进行控制。
UART协议中,在空闲时为高电平。在常用的一位停止位和无校验位的设置中,起始位为低电平,紧接着是8位的数据位,最后是一位高电平的停止位。
接收模块的主要设计是将起始位下降沿的检测作为接收系统的开始信号,通过起始信号和bit位的计数信号相结合就可以得到一个贯穿整体运行过程的使能信号,通过对使能信号的判断就可以实现对系统的控制。
另一个关键问题是电平采集的时间,应该 在一个bit的中间位置进行采集,这样可以有效避免采集电平不稳定的问题。
接收模块的代码如下:
module uart_receive ( input clk, input rst_n, input uart_rx, output reg receive_done, output reg [7:0] uart_data ); parameter SYSTERM_CLK = 50_000_000; //系统时钟频率 parameter UART_BPS = 115200; //串口波特率 localparam BPS_COUNT_MAX = SYSTERM_CLK/UART_BPS; //为得到指定波特率 //需要对系统时钟计数BPS_COUNT次 reg [7:0] reg_data;//接受数据缓存 reg [3:0] bit_count;//接收数据时用于计数接收到了多少位 reg [12:0] bps_count;//用于按照时钟计算一个字节的时间 reg start_bit;//检测到起始位的下降沿之后触发一个时钟的高电平 reg reg1 ; reg reg2 ; reg reg3 ; reg bit_flag ;//在一个电平的中间位置产生高电平标志 reg work_en ;//在本标志位高电平时,接受工作开始,在低电平时工作结束 reg rx_flag ;//在数据缓存器存满了之后产生一个高电平 //插入两级寄存器进行数据同步,用来消除亚稳态 always @(posedge clk or negedge rst_n) begin if (!rst_n) begin reg1 <= 1'b1;//因为UART的空闲状态是高电平,所以复位时电平要设置为高电平 end else begin reg1 <= uart_rx; end end //插入两级寄存器进行数据同步,用来消除亚稳态 always @(posedge clk or negedge rst_n) begin if (!rst_n) begin reg2 <= 1'b1;//因为UART的空闲状态是高电平,所以复位时电平要设置为高电平 end else begin reg2 <=reg1; end end //插入两级寄存器进行数据同步,用来消除亚稳态 always @(posedge clk or negedge rst_n) begin if (!rst_n) begin reg3 <= 1'b1;//因为UART的空闲状态是高电平,所以复位时电平要设置为高电平 end else begin reg3 <=reg2; end end //start_bit用来检测起始位的下降沿 always @(posedge clk or negedge rst_n) begin if (!rst_n) begin start_bit <= 1'b0; end else if ((reg3)&&(!reg2)) begin start_bit <= 1'b1; end else start_bit <= 1'b0; end //work_en,在本标志位高电平时,接受工作开始,在低电平时工作结束 always @(posedge clk or negedge rst_n) begin if (!rst_n) begin work_en <= 1'b0; end else if (start_bit) begin work_en <= 1'b1; end else if ((bit_count == 4'd8) && (bit_flag == 1'b1)) begin work_en <= 1'b0; end else work_en <= work_en; end //bps_count用来计数计算波特率 always @(posedge clk or negedge rst_n) begin if (!rst_n) begin bps_count <= 13'b0; end else if ((bps_count == BPS_COUNT_MAX -1) || (work_en == 0)) begin bps_count <= 13'b0;//只有在工作使能的状态下才会计数 end else if (work_en == 1) begin bps_count <= bps_count + 1'b1; end else bps_count <= bps_count; end //bit_flag,在一个字节的中点输出一个时钟的高电平 always @(posedge clk or negedge rst_n) begin if (!rst_n) begin bit_flag <= 1'b0; end else if (bps_count == BPS_COUNT_MAX/2-1) begin bit_flag <= 1'b1; end else bit_flag <= 1'b0; end //bit_count,用于计数当前接收到了第几bit always @(posedge clk or negedge rst_n) begin if (!rst_n) begin bit_count <= 4'b0; end else if ((bit_count == 4'd8) && (bit_flag == 1'b1)) begin bit_count <= 4'b0; end else if (bit_flag == 1'b1) begin bit_count <= bit_count + 1'b1; end else bit_count <= bit_count; end //reg_data表示接收数据的缓存 always @(posedge clk or negedge rst_n) begin if (!rst_n) begin reg_data <= 8'b0; end else if ((bit_flag == 1) && (work_en == 1) && (bit_count <= 4'd8) && (bit_count >= 4'd1)) begin reg_data <= {reg3,reg_data[7:1]}; end else reg_data <= reg_data; end //rx_flag在接收缓存满了之后输出一个时钟的高电平 always @(posedge clk or negedge rst_n) begin if (!rst_n) begin rx_flag <= 1'b0; end else if ((bit_count == 4'd8) && (bit_flag == 1'b1)) begin rx_flag <= 1'b1; end else rx_flag <= 1'b0; end //uart_data将数据缓存器中的数据导出 always @(posedge clk or negedge rst_n) begin if (!rst_n) begin uart_data <= 8'b0; end else if (rx_flag == 1'b1) begin uart_data <= reg_data; end else uart_data <= uart_data; end //receive_done导出接收完成的信号 always @(posedge clk or negedge rst_n) begin if (!rst_n) begin receive_done <= 1'b0; end else if (rx_flag == 1'b1) begin receive_done <= 1'b1; end else receive_done <= 1'b0; end endmodule //uart_receive
UART的发送模块的实现过程比接收过程稍简单,因为发送模块无需考虑采集电平的位置,只需要在接收到发送使能之后,通过计算每一个bit的时间,按照顺序将数据发送出去即可。
代码如下:
module uart_send ( input wire clk, input wire rst_n, input wire [7:0] uart_in_data, input wire uart_in_flag, output reg uart_tx ); parameter SYSTERM_CLK = 50_000_000; //系统时钟频率 parameter UART_BPS = 115200; //串口波特率 localparam BPS_COUNT_MAX = SYSTERM_CLK/UART_BPS; //为得到指定波特率 //需要对系统时钟计数BPS_COUNT次 reg [12:0] bps_count;//用于按照时钟计算一个字节的时间 reg [3:0] bit_count;//接收数据时用于计数接收到了多少位 reg bit_flag ;//在一个电平的中间位置产生高电平标志 reg work_en ;//在本标志位高电平时,接受工作开始,在低电平时工作结束 //bps_count波特率计数器 always @(posedge clk or negedge rst_n) begin if (!rst_n) begin bps_count <= 13'b0; end else if ((bps_count ==BPS_COUNT_MAX - 1'b1) || (work_en == 1'b0)) begin bps_count <= 13'b0; end else if (work_en == 1'b1) begin bps_count <= bps_count + 1'b1; end else bps_count <= bps_count; end //work_en发送工作使能 always @(posedge clk or negedge rst_n) begin if (!rst_n) begin work_en <= 1'b0; end else if ((bit_count == 4'd9) && (bit_flag == 1'b1)) begin work_en <= 1'b0; end else if (uart_in_flag == 1'b1) begin work_en <= 1'b1; end else work_en <= work_en; end //bit_flag每一个bit的信号 always @(posedge clk or negedge rst_n) begin if (!rst_n) begin bit_flag <= 1'b0; end else if (bps_count == 13'b1) begin bit_flag <= 1'b1; end else bit_flag <= 1'b0; end //bit_count字节计数 always @(posedge clk or negedge rst_n) begin if (!rst_n) begin bit_count <= 4'b0; end else if ((bit_flag == 1'b1) && (work_en == 1'b1)) begin bit_count <= bit_count + 1'b1; end else if ((bit_count == 4'd9) && (bit_flag == 1'b1)) begin bit_count <= 4'b0; end else bit_count <= bit_count; end //uart_tx always @(posedge clk or negedge rst_n) begin if (!rst_n) begin uart_tx <= 1'b1;//串口传输,空闲时为高电平 end else if (bit_flag == 1'b1) begin case (bit_count) 0: uart_tx <= 1'b0 ; 1: uart_tx <= uart_in_data[0]; 2: uart_tx <= uart_in_data[1]; 3: uart_tx <= uart_in_data[2]; 4: uart_tx <= uart_in_data[3]; 5: uart_tx <= uart_in_data[4]; 6: uart_tx <= uart_in_data[5]; 7: uart_tx <= uart_in_data[6]; 8: uart_tx <= uart_in_data[7]; 9: uart_tx <= 1'b1 ; default uart_tx <= 1'b1 ; endcase end end endmodule //uart_send
顶层只需将发送和接收模块例化即可,同时加入了LED管脚,可以在发送和接收回环的过程中实现对4个LED灯的控制。
代码如下:
module uart_top ( input wire clk, input wire rst_n, input wire uart_rx, output wire uart_tx, output wire [3:0] led ); parameter SYSTERM_CLK = 26'd50_000_000; //系统时钟频率 parameter UART_BPS = 17'd115200; //串口波特率 wire flag; wire [7:0] data; assign led = data[3:0]; uart_receive #( .SYSTERM_CLK (SYSTERM_CLK ), .UART_BPS (UART_BPS ) ) u_uart_receive( .clk (clk ), .rst_n (rst_n ), .uart_rx (uart_rx ), .receive_done (flag ), .uart_data (data ) ); uart_send #( .SYSTERM_CLK (SYSTERM_CLK ), .UART_BPS (UART_BPS ) ) u_uart_send( .clk (clk ), .rst_n (rst_n ), .uart_in_data (data ), .uart_in_flag (flag ), .uart_tx (uart_tx ) ); endmodule //uart_top
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。