在这篇文章中串口(UART)的FPGA实现(含源码工程),实现了基于FPGA的串口发送驱动。利用发送驱动可以实现 起始位1bit+数据位8bit+停止位1bit 共10bit的单字节传输。
但是在实际应用过程中又经常需要一次性发送多个字节的数据。比如,一次发送一个位宽为【39:0】的数据。诚然,可以直接更改此文中的串口发送驱动,使其变成 起始位1bit+数据位40bit+停止位1bit 共42bit的多字节传输。这种方法理论上是可行的,因为UART协议并没有规定你一次要发送、接收多个少bit的数据,既然能发送8个bit,那同样能发送40个bit。
但是很不幸,实际上基本行不通,因为通用的绝大部分上位机都不支持一次解析40bit的数据位(如果你自己写上位机就当我没说)。
所以只能想点其他办法,比如:写个逻辑,多次调用8bit即单字节的串口发送驱动,40bit的数据就调用5次,也就是切割成5个 起始位1bit+数据位8bit+停止位1bit共10bit的单字节 分别发送过去就可以了。
请参考:串口(UART)的FPGA实现(含源码工程),在此文详细介绍了串口的发送驱动。
以下代码可以实现 1bit+数据位8bit+停止位1bit 共10bit的单字节传输,无奇偶校验。
-
- // *******************************************************************************************************
- // ** 作者 : 孤独的单刀
- // ** 邮箱 : zachary_wu93@163.com
- // ** 博客 : https://blog.csdn.net/wuzhikaidetb
- // ** 日期 : 2022/07/31
- // ** 功能 : 1、基于FPGA的串口发送驱动模块;
- // 2、可设置波特率BPS、主时钟CLK_FRE;
- // 3、起始位1bit,数据位8bit,停止位1bit,无奇偶校验;
- // 4、每发送1个字节后拉高uart_tx_done一个周期,可用于后续发送多字节模块。
- // *******************************************************************************************************
-
- module uart_tx
- #(
- parameter integer BPS = 9_600 , //发送波特率
- parameter integer CLK_FRE = 50_000_000 //主时钟频率
- )
- (
- //系统接口
- input sys_clk , //系统时钟
- input sys_rst_n , //系统复位,低电平有效
- //用户接口
- input [7:0] uart_tx_data , //需要通过UART发送的数据,在uart_tx_en为高电平时有效
- input uart_tx_en , //发送有效,当其为高电平时,代表此时需要发送的数据有效
- //UART发送
- output reg uart_tx_done , //成功发送1BYTE数据后拉高一个周期
- output reg uart_txd //UART发送数据线tx
- );
-
- //param define
- localparam integer BPS_CNT = CLK_FRE / BPS; //根据波特率计算传输每个bit需要计数多个系统时钟
- localparam integer BITS_NUM = 10 ; //发送格式确定需要发送的bit数,10bit = 1起始位 + 8数据位 + 1停止位
-
- //reg define
- reg tx_state ; //发送标志信号,拉高代表发送过程正在进行
- reg [7:0] uart_tx_data_reg ; //寄存要发送的数据
- reg [31:0] clk_cnt ; //计数器,用于计数发送一个bit数据所需要的时钟数
- reg [3:0] bit_cnt ; //bit计数器,标志当前发送了多少个bit
-
-
- //当发送使能信号到达时,寄存待发送的数据以免后续变化、丢失
- always @(posedge sys_clk or negedge sys_rst_n)begin
- if(!sys_rst_n)
- uart_tx_data_reg <=8'd0;
- else if(uart_tx_en) //要发送有效的数据
- uart_tx_data_reg <= uart_tx_data; //寄存需要发送的数据
- else
- uart_tx_data_reg <= uart_tx_data_reg;
- end
-
- //当发送使能信号到达时,进入发送过程
- always @(posedge sys_clk or negedge sys_rst_n)begin
- if(!sys_rst_n)
- tx_state <=1'b0;
- else if(uart_tx_en)
- tx_state <= 1'b1; //发送信号有效则进入发送过程
- //发送完了最后一个数据则退出发送过程
- else if((bit_cnt == BITS_NUM - 1'b1) && (clk_cnt == BPS_CNT - 1'b1))
- tx_state <= 1'b0;
- else
- tx_state <= tx_state;
- end
-
- //发送数据完毕后拉高发送完毕信号一个周期,指示一个字节发送完毕
- always @(posedge sys_clk or negedge sys_rst_n)begin
- if(!sys_rst_n)
- uart_tx_done <=1'b0;
- //发送数据完毕后拉高发送完毕信号一个周期
- else if((bit_cnt == BITS_NUM - 1'b1) && (clk_cnt == BPS_CNT - 1'b1))
- uart_tx_done <=1'b1;
- else
- uart_tx_done <=1'b0;
- end
-
- //进入发送过程后,启动时钟计数器与发送个数bit计数器
- always @(posedge sys_clk or negedge sys_rst_n)begin
- if(!sys_rst_n)begin
- clk_cnt <= 32'd0;
- bit_cnt <= 4'd0;
- end
- else if(tx_state) begin //在发送状态
- if(clk_cnt < BPS_CNT - 1'd1)begin //一个bit数据没有发送完
- clk_cnt <= clk_cnt + 1'b1; //时钟计数器+1
- bit_cnt <= bit_cnt; //bit计数器不变
- end
- else begin //一个bit数据发送完了
- clk_cnt <= 32'd0; //清空时钟计数器,重新开始计时
- bit_cnt <= bit_cnt+1'b1; //bit计数器+1,表示发送完了一个bit的数据
- end
- end
- else begin //不在发送状态
- clk_cnt <= 32'd0; //清零
- bit_cnt <= 4'd0; //清零
- end
- end
-
- //根据发送数据计数器来给uart发送端口赋值
- always @(posedge sys_clk or negedge sys_rst_n)begin
- if(!sys_rst_n)
- uart_txd <= 1'b1; //默认为高状态,空闲状态
- else if(tx_state) //处于发送状态
- case(bit_cnt) //数据发送从低位到高位
- 4'd0: uart_txd <= 1'b0; //起始位,拉低
- 4'd1: uart_txd <= uart_tx_data_reg[0]; //发送最低位数据
- 4'd2: uart_txd <= uart_tx_data_reg[1]; //
- 4'd3: uart_txd <= uart_tx_data_reg[2]; //
- 4'd4: uart_txd <= uart_tx_data_reg[3]; //
- 4'd5: uart_txd <= uart_tx_data_reg[4]; //
- 4'd6: uart_txd <= uart_tx_data_reg[5]; //
- 4'd7: uart_txd <= uart_tx_data_reg[6]; //
- 4'd8: uart_txd <= uart_tx_data_reg[7]; //发送最高位数据
- 4'd9: uart_txd <= 1'b1; //终止位,拉高
- default:uart_txd <= 1'b1;
- endcase
- else //不处于发送状态
- uart_txd <= 1'b1; //默认为高状态,空闲状态
- end
-
- endmodule
串口发送驱动模块的对外端口如下:

其中uart_tx_done信号是关键。当一个字节的数据被按约定的串口协议发送出去后,该信号就会拉高一个时钟周期,表示一次传输结束。
可以在发送完一个字节后,将该信号作为发送下一个字节的使能信号,直到所有的字节都被发送完毕。
但是有一个需要注意的问题:第一个字节的发送使能是无法参考信号 uart_tx_done,那么第一个信号何时发送?同样的,在任意字节发送模块设计一个对外信号:uart_bytes_en,只有当该信号有效时才发起一次传输,同时该信号还可以作为第一个字节的发送使能信号,如下:

总结一下,多字节的发送逻辑:
完整代码如下:
-
- // *******************************************************************************************************************
- // ** 作者 : 孤独的单刀
- // ** 邮箱 : zachary_wu93@163.com
- // ** 博客 : https://blog.csdn.net/wuzhikaidetb
- // ** 日期 : 2022/07/31
- // ** 功能 : 1、基于FPGA的串口多字节发送模块;
- // 2、可设置一次发送的字节数、波特率BPS、主时钟CLK_FRE;
- // 3、UART协议设置为起始位1bit,数据位8bit,停止位1bit,无奇偶校验(不可在端口更改,只能更改发送驱动源码);
- // 4、每发送1次多字节后拉高指示信号一个周期,指示一次多字节发送结束;
- // 5、数据发送顺序,先发送低字节、再发送高字节。如:发送16’h12_34,先发送单字节8'h34,再发送单字节8'h12。
- // *******************************************************************************************************************
-
- module uart_bytes_tx
- #(
- parameter integer BYTES = 4 , //发送字节数,单字节8bit
- parameter integer BPS = 9_600 , //发送波特率
- parameter integer CLK_FRE = 50_000_000 //输入时钟频率
- )
- (
- //系统接口
- input sys_clk , //系统时钟
- input sys_rst_n , //系统复位,低电平有效
- //用户接口
- input [(BYTES * 8 - 1):0] uart_bytes_data , //需要通过UART发送的多字节数据,在uart_bytes_en为高电平时有效
- input uart_bytes_en , //发送有效,当其为高电平时,代表此时需要发送的数据有效
- //UART发送
- output uart_bytes_done , //成功发送完所有字节数据后拉高1个时钟周期
- output uart_txd //UART发送数据线tx
- );
-
- //reg define
- reg [(BYTES*8-1):0] uart_bytes_data_reg; //寄存接收到的多字节数据
- reg work_en; //高电平表示处于发送状态,低电平表示空闲状态
- reg [9:0] byte_cnt; //发送的字节个数计数(因为懒直接用10bit计数,最大可以表示1024BYTE,大概率不会溢出)
- reg [7:0] uart_sing_data; //拆解的要发送的单个字节数据
- reg uart_sing_en; //要发送的单个字节数据发送使能
- reg uart_bytes_done_reg; //所有字节发送完毕打拍
- reg uart_sing_done_reg; //单个字节数据发送完毕打拍
-
- //wire define
- wire uart_sing_done; //单个字节发送完成标志信号
-
- //对端口赋值
- assign uart_bytes_done = uart_bytes_done_reg;
-
-
- //当发送使能信号到达时,寄存待发送的多字节数据以免后续变化、丢失
- always @(posedge sys_clk or negedge sys_rst_n)begin
- if(!sys_rst_n)
- uart_bytes_data_reg <= 0;
- else if(uart_bytes_en && ~work_en) //要发送有效的数据,且并未处于发送状态
- uart_bytes_data_reg <= uart_bytes_data; //寄存需要发送的数据
- else if(uart_sing_done)
- uart_bytes_data_reg <= uart_bytes_data_reg >> 8; //发送完一个数据后,把多字节数据右移8bit
- else
- uart_bytes_data_reg <= uart_bytes_data_reg;
- end
-
- //当发送使能信号到达时,进入工作状态
- always @(posedge sys_clk or negedge sys_rst_n)begin
- if(!sys_rst_n)
- work_en <= 1'b0;
- else if(uart_bytes_en && ~work_en) //要发送有效的数据且未处于工作状态
- work_en <= 1'b1; //进入发送状态
- else if(uart_sing_done && byte_cnt == BYTES - 1) //发送完了最后一个字节的数据
- work_en <= 1'b0; //发送完毕,退出工作状态
- else
- work_en <= work_en;
- end
-
- //在工作状态对发送的数据个数进行计数
- always @(posedge sys_clk or negedge sys_rst_n)begin
- if(!sys_rst_n)
- byte_cnt <= 0;
- else if(work_en)begin //处于发送状态则需要对发送的字节个数计数
- if(uart_sing_done && byte_cnt == BYTES - 1) //计数到了最大值则清零
- byte_cnt <= 0;
- else if(uart_sing_done) //发送完一个单字节则计数器+1
- byte_cnt <= byte_cnt + 1'b1;
- else
- byte_cnt <= byte_cnt;
- end
- else //不处于发送状态则清零
- byte_cnt <= 0;
- end
-
- //打拍凑时序·~·
- always @(posedge sys_clk or negedge sys_rst_n)begin
- if(!sys_rst_n)
- uart_sing_done_reg <= 0;
- else
- uart_sing_done_reg <= uart_sing_done;
- end
-
- //发送单个字节的数据
- always @(posedge sys_clk or negedge sys_rst_n)begin
- if(!sys_rst_n)
- uart_sing_data <= 8'd0;
- else if(uart_bytes_en && ~work_en) //进入工作状态后马上发送第一个数据
- uart_sing_data <= uart_bytes_data[7:0]; //发送最低字节
- else if(uart_sing_done_reg) //发送完一个字节则发送另一个字节
- uart_sing_data <= uart_bytes_data_reg[7:0]; //先右移8bit,然后取低8bit
- else
- uart_sing_data <= uart_sing_data; //保持稳定
- end
-
- //发送单个字节的数据使能
- always @(posedge sys_clk or negedge sys_rst_n)begin
- if(!sys_rst_n)
- uart_sing_en <= 1'b0;
- else if(uart_bytes_en && ~work_en) //进入工作状态后马上发送第一个数据
- uart_sing_en <= 1'b1;
- else if(uart_sing_done_reg && work_en) //发送完一个字节则发送另一个字节
- uart_sing_en <= 1'b1;
- else
- uart_sing_en <= 1'b0; //其他时候则为0
- end
-
- //所有数据发送完毕
- always @(posedge sys_clk or negedge sys_rst_n)begin
- if(!sys_rst_n)
- uart_bytes_done_reg <= 1'b0;
- else if(uart_sing_done && byte_cnt == BYTES - 1)
- uart_bytes_done_reg <= 1'b1;
- else
- uart_bytes_done_reg <= 1'b0;
- end
-
-
- //例化发送驱动模块
- uart_tx #(
- .BPS (BPS ),
- .CLK_FRE (CLK_FRE )
- )
- uart_tx_inst(
- .sys_clk (sys_clk ),
- .sys_rst_n (sys_rst_n ),
-
- .uart_tx_data (uart_sing_data ),
- .uart_tx_en (uart_sing_en ),
- .uart_tx_done (uart_sing_done ),
- .uart_txd (uart_txd )
- );
-
- endmodule
使用该模块发送数据3次,观测发送结果是否符合UART协议要求。分别使用单字节(8位)、双字节(16位)、5字节(40位)进行测试。
TB如下:
- `timescale 1ns/1ns //定义时间刻度
-
-
- module tb_uart_bytes_tx();
-
- localparam integer BYTES = 1 ; //一次发送的字节个数
-
- localparam integer BPS = 230400 ; //波特率
- localparam integer CLK_FRE = 50_000_000 ; //系统频率50M
-
- reg sys_clk ; //系统时钟
- reg sys_rst_n ; //系统复位,低电平有效
- reg [(BYTES * 8 - 1):0] uart_bytes_data ; //需要通过UART发送的多字节数据,在uart_bytes_en为高电平时有效
- reg uart_bytes_en ; //发送有效,当其为高电平时,代表此时需要发送的数据有效
- wire uart_bytes_done ; //成功发送完所有BYTE数据后拉高1个时钟周期
- wire uart_txd ; //UART发送数据线
-
- initial begin
- sys_clk <=1'b0;
- sys_rst_n <=1'b0;
- uart_bytes_en <=1'b0;
- uart_bytes_data <= 0;
- #80 //系统开始工作
- sys_rst_n <=1'b1;
- //*******************************************************************************
- //第1次发送随机数据
- #90 //发送1次随机的多字节数据
- uart_bytes_en <=1'b1;
- uart_bytes_data <= {$random}; //生成随机数据
- #20
- uart_bytes_en <=1'b0;
- wait(uart_bytes_done); //等待其发送完
- //*******************************************************************************
- //*******************************************************************************
- //第2次发送随机数据
- #20
- uart_bytes_en <=1'b1;
- uart_bytes_data <= {$random}; //发送1次随机的多字节数据
- #20
- uart_bytes_en <=1'b0;
- wait(uart_bytes_done); //等待其发送完
- //*******************************************************************************
- //第3次发送随机数据
- #20
- uart_bytes_en <=1'b1;
- uart_bytes_data <= {$random}; //发送1次随机的多字节数据
- #20
- uart_bytes_en <=1'b0;
- wait(uart_bytes_done); //等待其发送完
- //*******************************************************************************
- #1000 $finish(); //结束仿真
- end
-
- always #10 sys_clk=~sys_clk; //设置主时钟,20ns,50M
-
- //例化多字节发送模块
- uart_bytes_tx #(
- .BYTES (BYTES ),
- .BPS (BPS ),
- .CLK_FRE (CLK_FRE )
- )
- uart_bytes_tx_inst(
- .sys_clk (sys_clk ),
- .sys_rst_n (sys_rst_n ),
-
- .uart_bytes_data (uart_bytes_data ),
- .uart_bytes_en (uart_bytes_en ),
-
- .uart_bytes_done (uart_bytes_done ),
- .uart_txd (uart_txd )
- );
- endmodule
仿真结果如下:

TB基本不用修改,仅仅把BYTES这个参数改成2就行。仿真结果如下:

TB基本不用修改,仅仅把BYTES这个参数改成5就行。仿真结果如下:

您照着上面的逻辑看看就行,我就不啰嗦了。
下板实测的话,需要写个顶层模块来例化这个任意字节的串口发送模块。在顶层模块,设置成每1s拉高一次发送信号,同时将要发送的数据+1。
顶层模块如下:
-
- // *******************************************************************************************************************
- // ** 作者 : 孤独的单刀
- // ** 邮箱 : zachary_wu93@163.com
- // ** 博客 : https://blog.csdn.net/wuzhikaidetb
- // ** 日期 : 2022/07/31
- // ** 功能 : 1、对基于FPGA的串口多字节发送模块进行测试的模块;
- // 2、设置好一次发送的字节数、波特率、主时钟频率;
- // 3、UART协议设置为起始位1bit,数据位8bit,停止位1bit,无奇偶校验(不可在端口更改,只能更改发送驱动源码);
- // 4、数据发送顺序,先发送低字节、再发送高字节。如:发送16’h12_34,先发送单字节8'h34,再发送单字节8'h12。
- // *******************************************************************************************************************
-
-
- module uart_bytes_tx_test(
- //系统接口
- input sys_clk , //主时钟
- input sys_rst_n , //低电平有效的复位信号
- //UART发送线
- output uart_txd //UART发送线
- );
-
- localparam integer BYTES = 1 ; //发送的字节数,单字节8bit
- localparam integer BPS = 115200 ; //发送波特率
- localparam integer CLK_FRE = 50_000_000 ; //输入时钟频率
- localparam integer CNT_MAX = 50_000_000 ; //发送时间间隔,1秒
-
- reg [31:0] cnt_time;
- reg uart_bytes_en; //发送使能,当其为高电平时,代表此时需要发送数据
- reg [BYTES*8-1 :0] uart_bytes_data; //需要通过UART发送的数据,在uart_bytes_en为高电平时有效
-
- //1s计数模块,每隔1s发送一个数据和拉高发送使能信号一次,数据从初始值开始递增1
- always @(posedge sys_clk or negedge sys_rst_n)begin
- if(!sys_rst_n)begin
- cnt_time <= 'd0;
- uart_bytes_en <= 1'd0;
- uart_bytes_data <= 'h12; //初始数据
- end
- else if(cnt_time == (CNT_MAX - 1'b1))begin
- cnt_time <= 'd0;
- uart_bytes_en <= 1'd1; //拉高发送使能
- uart_bytes_data <= uart_bytes_data + 1'd1; //发送数据累加1
- end
- else begin
- cnt_time <= cnt_time + 1'd1;
- uart_bytes_en <= 1'd0;
- uart_bytes_data <= uart_bytes_data;
- end
- end
-
- //例化串口多字节发送模块
- uart_bytes_tx
- #(
- .BYTES (BYTES ),
- .BPS (BPS ),
- .CLK_FRE (CLK_FRE )
- )
- uart_bytes_tx_inst
- (
-
- .sys_clk (sys_clk ),
- .sys_rst_n (sys_rst_n ),
- .uart_bytes_data (uart_bytes_data ),
- .uart_bytes_en (uart_bytes_en ),
- .uart_bytes_done ( ),
- .uart_txd (uart_txd )
- );
-
- endmodule
初始值设定为8'h13,这样上位机每1s就可以接收一个数据,其值分别为8'h13、8'h14、8'h15、8'h16、8'h17·····,上位机接收到的数据如下:

测试结果与预期一致。
顶层模块如下:
-
- // *******************************************************************************************************************
- // ** 作者 : 孤独的单刀
- // ** 邮箱 : zachary_wu93@163.com
- // ** 博客 : https://blog.csdn.net/wuzhikaidetb
- // ** 日期 : 2022/07/31
- // ** 功能 : 1、对基于FPGA的串口多字节发送模块进行测试的模块;
- // 2、设置好一次发送的字节数、波特率、主时钟频率;
- // 3、UART协议设置为起始位1bit,数据位8bit,停止位1bit,无奇偶校验(不可在端口更改,只能更改发送驱动源码);
- // 4、数据发送顺序,先发送低字节、再发送高字节。如:发送16’h12_34,先发送单字节8'h34,再发送单字节8'h12。
- // *******************************************************************************************************************
-
-
- module uart_bytes_tx_test(
- //系统接口
- input sys_clk , //主时钟
- input sys_rst_n , //低电平有效的复位信号
- //UART发送线
- output uart_txd //UART发送线
- );
-
- localparam integer BYTES = 2 ; //发送的字节数,单字节8bit
- localparam integer BPS = 115200 ; //发送波特率
- localparam integer CLK_FRE = 50_000_000 ; //输入时钟频率
- localparam integer CNT_MAX = 50_000_000 ; //发送时间间隔,1秒
-
- reg [31:0] cnt_time;
- reg uart_bytes_en; //发送使能,当其为高电平时,代表此时需要发送数据
- reg [BYTES*8-1 :0] uart_bytes_data; //需要通过UART发送的数据,在uart_bytes_en为高电平时有效
-
- //1s计数模块,每隔1s发送一个数据和拉高发送使能信号一次,数据从初始值开始递增1
- always @(posedge sys_clk or negedge sys_rst_n)begin
- if(!sys_rst_n)begin
- cnt_time <= 'd0;
- uart_bytes_en <= 1'd0;
- uart_bytes_data <= 'h3412; //初始数据
- end
- else if(cnt_time == (CNT_MAX - 1'b1))begin
- cnt_time <= 'd0;
- uart_bytes_en <= 1'd1; //拉高发送使能
- uart_bytes_data <= uart_bytes_data + 1'd1; //发送数据累加1
- end
- else begin
- cnt_time <= cnt_time + 1'd1;
- uart_bytes_en <= 1'd0;
- uart_bytes_data <= uart_bytes_data;
- end
- end
-
- //例化串口多字节发送模块
- uart_bytes_tx
- #(
- .BYTES (BYTES ),
- .BPS (BPS ),
- .CLK_FRE (CLK_FRE )
- )
- uart_bytes_tx_inst
- (
-
- .sys_clk (sys_clk ),
- .sys_rst_n (sys_rst_n ),
- .uart_bytes_data (uart_bytes_data ),
- .uart_bytes_en (uart_bytes_en ),
- .uart_bytes_done ( ),
- .uart_txd (uart_txd )
- );
-
- endmodule
初始值设定为16'h3413,这样上位机每1s就可以接收一个数据,其值分别为8'h13、8'h34、8'h14、8'h34、8'h15、8'h34·····,上位机接收到的数据如下:

测试结果与预期一致。
顶层模块如下:
-
- // *******************************************************************************************************************
- // ** 作者 : 孤独的单刀
- // ** 邮箱 : zachary_wu93@163.com
- // ** 博客 : https://blog.csdn.net/wuzhikaidetb
- // ** 日期 : 2022/07/31
- // ** 功能 : 1、对基于FPGA的串口多字节发送模块进行测试的模块;
- // 2、设置好一次发送的字节数、波特率、主时钟频率;
- // 3、UART协议设置为起始位1bit,数据位8bit,停止位1bit,无奇偶校验(不可在端口更改,只能更改发送驱动源码);
- // 4、数据发送顺序,先发送低字节、再发送高字节。如:发送16’h12_34,先发送单字节8'h34,再发送单字节8'h12。
- // *******************************************************************************************************************
-
-
- module uart_bytes_tx_test(
- //系统接口
- input sys_clk , //主时钟
- input sys_rst_n , //低电平有效的复位信号
- //UART发送线
- output uart_txd //UART发送线
- );
-
- localparam integer BYTES = 5 ; //发送的字节数,单字节8bit
- localparam integer BPS = 115200 ; //发送波特率
- localparam integer CLK_FRE = 50_000_000 ; //输入时钟频率
- localparam integer CNT_MAX = 50_000_000 ; //发送时间间隔,1秒
-
- reg [31:0] cnt_time;
- reg uart_bytes_en; //发送使能,当其为高电平时,代表此时需要发送数据
- reg [BYTES*8-1 :0] uart_bytes_data; //需要通过UART发送的数据,在uart_bytes_en为高电平时有效
-
- //1s计数模块,每隔1s发送一个数据和拉高发送使能信号一次,数据从初始值开始递增1
- always @(posedge sys_clk or negedge sys_rst_n)begin
- if(!sys_rst_n)begin
- cnt_time <= 'd0;
- uart_bytes_en <= 1'd0;
- uart_bytes_data <= 40'h9a_78_56_34_12; //初始数据
- end
- else if(cnt_time == (CNT_MAX - 1'b1))begin
- cnt_time <= 'd0;
- uart_bytes_en <= 1'd1; //拉高发送使能
- uart_bytes_data <= uart_bytes_data + 1'd1; //发送数据累加1
- end
- else begin
- cnt_time <= cnt_time + 1'd1;
- uart_bytes_en <= 1'd0;
- uart_bytes_data <= uart_bytes_data;
- end
- end
-
- //例化串口多字节发送模块
- uart_bytes_tx
- #(
- .BYTES (BYTES ),
- .BPS (BPS ),
- .CLK_FRE (CLK_FRE )
- )
- uart_bytes_tx_inst
- (
-
- .sys_clk (sys_clk ),
- .sys_rst_n (sys_rst_n ),
- .uart_bytes_data (uart_bytes_data ),
- .uart_bytes_en (uart_bytes_en ),
- .uart_bytes_done ( ),
- .uart_txd (uart_txd )
- );
-
- endmodule
初始值设定为40'h9a78563413,这样上位机每1s就可以接收一个数据,其值分别为8'h13、8'h34、8'h56、8'h78、8'h9a、8'h14、8'h34、8'h56、8'h78、8'h9a、·····,上位机接收到的数据如下:

测试结果与预期一致。