当前位置:   article > 正文

基于FPGA的串口发送_fpga串口发送数据

fpga串口发送数据

基于FPGA的串口发送(E/FPGACode/uart_tx_new)

一、串口

  • 串口简称UART
  • 设计的目的是用来发送数据的,因此需要有一个数据输入端口,用来发送这8bit数据。类似于实验中的Ctrl,用来指定亮灭模式
  • 支持不同的波特率,所以需要有一个波特率设置端口。类似于计数器实验中的Time
  • 如下图所示,本质是把这8位的并行数据通过一根信号线在不同的时刻分别以高低电平一位一位得传出去。并行输入,串行输出

在这里插入图片描述

  • 1位的低电平标志串行传输的开始待8位数据传输完成之后,再以1位的高电平标志传输的结束
    在这里插入图片描述
  • 数据什么时候发?答:发送开始信号-Send_en
  • 一串数据什么时候发送结束?答:发送完成标志信号-Tx_Done

二、串口简易图

uart_tx=起始位+data[7:0]+结束位

在这里插入图片描述

三、 问题


module uart_byte_tx(
	input [7:0] data,
	input Send_en,
	input Clk,
	input Reset_n,
	input [2:0] Baud_set,//假设只支持8种波特率
	output reg uart_tx,
	output reg Tx_Done
    );
	
	reg [17:0] div_cnt;
	
	//计算不同波特率时计数的次数
	//Baud_set=0,则波特率=9600,
	//Baud_set=1,则波特率=19200,
	//Baud_set=2,则波特率=38400,
	//Baud_set=3,则波特率=57600,
	//Baud_set=4,则波特率=115200
	reg [17:0] bps_DR;
	always@(*)begin
		case(Baud_set)
			0:bps_DR=1000000000/9600/20;
			1:bps_DR=1000000000/19200/20;
			2:bps_DR=1000000000/38400/20;
			3:bps_DR=1000000000/57600/20;
			4:bps_DR=1000000000/115200/20;
			default:bps_DR=1000000000/9600/20;
		endcase	
	end
	
	
	//计数基本时间单元
	always@(posedge Clk or negedge Reset_n)begin
		if(!Reset_n)begin
			div_cnt<=0;
		end else if(Send_en)begin
			if(div_cnt == bps_DR-1) begin
				div_cnt<=0;
			end else begin
				div_cnt<=div_cnt+1'b1;
			end
		end else
			div_cnt<=0;
	end
	
	reg [3:0] bps_cnt;
	
	//发送10个段:开始+8数据+结束,一共需要11个clk确定
	always@(posedge Clk or negedge Reset_n)begin
		if(!Reset_n)begin
			bps_cnt<=0;
		end else if(Send_en)begin
			if(div_cnt == bps_DR-1) begin
				if(bps_cnt==11)
					bps_cnt<=0;
				else
					bps_cnt<=bps_cnt+1'b1;
			end 
		end else
			bps_cnt<=0;
	end
	
	always@(posedge Clk or negedge Reset_n)begin
		if(!Reset_n)begin
			Tx_Done<=1'b0;
			uart_tx<=1'b1;
		end else begin
			case(bps_cnt)
				0:begin uart_tx<=1'b0;Tx_Done<=0;end
				1:uart_tx<=data[0];
				2:uart_tx<=data[1];
				3:uart_tx<=data[2];
				4:uart_tx<=data[3];
				5:uart_tx<=data[4];
				6:uart_tx<=data[5];
				7:uart_tx<=data[6];
				8:uart_tx<=data[7];
				9:uart_tx<=1'b1;
				10:begin uart_tx=1'b1;Tx_Done<=1;end
				default:uart_tx=1'b1;
			endcase
		end
	end
	
endmodule

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87

在这里插入图片描述

1、当Send_en从0变成1时,代表开始传递数据。uart_tx初始为1,所以当send_en上升沿时,uart_tx应该同时变成0,代表传输START(低电平)位。
但是由图片可知,uart_tx大概早了将近1位的时间就将其拉为低电平。

  • 分析:由代码可知,当bps_cnt=0时,将uart_tx=0;
  • 解决方法:将case(bps_cnt)改成从1-11.

在这里插入图片描述
改完之后的波形图如上图所示,当bps_cnt=1时,才将uart_tx=0,传输开始位。

在这里插入图片描述
2、两个蓝色的marker标志在这个空闲时间中,是让uart_tx一直保持为1。但是这个有必要吗?如何进行更改?

  • 分析:这两个marker是因为当Send_en为1时,才开始计时,当div_cnt == bps_DR-1,即div_cnt计满一次,bps_cnt才+1.所以就相当于多计了一个bps_cnt.
			if(div_cnt == bps_DR-1) begin
				if(bps_cnt==11)
					bps_cnt<=0;
				else
					bps_cnt<=bps_cnt+1'b1;
			end 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 修改:当div_cnt=1时,就进行+1.
		if(div_cnt == 1) begin
				if(bps_cnt==11)
					bps_cnt<=0;
				else
					bps_cnt<=bps_cnt+1'b1;
			end 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

四、 串口发送数据任务

使用前面设计的串口发送模块,设计一个数据发送器,每10ms以115200的波特率发送一个数据,每次发送的数据比前一个数据大一(计数器)

问题一

//每隔10ms发送一个数据
    always @(posedge Clk or negedge Reset_n) begin
        if (!Reset_n) begin
            counter<=0;
        end
        else if (counter == 500000-1) begin
            counter<=0;
        end else
            counter<=counter+1;
    end

    always @(posedge Clk or negedge Reset_n) begin
        if (!Reset_n) begin
            Send_en<=0;
        end
        else if (counter==1) begin
            Send_en<=1;
        end else if(Tx_Done) begin
            Send_en<=0;
        end
    end

    always @(posedge Tx_Done or negedge Reset_n) begin
        if (!Reset_n) begin
            data<=0;
        end else begin
            data <= data+1'b1;
        end
    end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

在这里插入图片描述
波形图:1、Tx_Done一直为1,导致poedeg Tx_Done检测不到,所以data无法进行自加
2、继续分析,Tx_Done什么时候0->1,1->0
看E://uart_byte_tx,当bps_cnt=1时,Tx_Done=1,当bps_cnt=11时,Tx_Done=1。
当Tx_Done=1时,Send_En就会变成0.此时bps_cnt就不会再+1.由此成了一个死循环.
修改:可以从波形图看到,bps_cnt是从0->a,然后就一直持续为0.刚好我们前面有一个为0的状态位没有用到。此时就将bps_cnt=0时,

问题二:串口波形图的时序要求,Tx_Done从3个节拍改为1个节拍,所以不能使用posedge Tx_Done

在这里插入图片描述

分析:为什么是3个周期?
当bps_cnt=11时,Tx_Done=1.此时,Send_En从1->0.但在下一个节拍才能变为0(非阻塞赋值)。再到下一个节拍才能知晓已经为0,此时bps_cnt才从11变成0.当bps_cnt=0时,再过一个节拍Tx_Done=0.
修改:

always@(posedge Clk or negedge Reset_n)begin
		if(!Reset_n)begin
			Tx_Done<=1'b0;
			uart_tx<=1'b1;
		end else begin
			case(bps_cnt)
				0:Tx_Done<=0;
				1:uart_tx<=1'b0;
				2:uart_tx<=data[0];
				3:uart_tx<=data[1];
				4:uart_tx<=data[2];
				5:uart_tx<=data[3];
				6:uart_tx<=data[4];
				7:uart_tx<=data[5];
				8:uart_tx<=data[6];
				9:uart_tx<=data[7];
				10:uart_tx<=1'b1;
				11:uart_tx=1'b1;
				default:uart_tx=1'b1;
			endcase
		end
	end

	always @(posedge Clk or negedge Reset_n)begin
		if(!Reset_n)
			Tx_Done<=0;
		else if((bps_cnt==10)&&(bps_clk==1))
			Tx_Done<=1;
		else
			Tx_Done<=0;
	end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

五、板级编译

最后上板子调试,发现一直接收的是00,后看了一篇博客发现是在不同的always块中对同一个信号进行赋值。这是不允许的!!!!!
这是那篇博客/提问链接:https://ask.csdn.net/questions/7737125

六、 运行成功

串口之数据传输

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/516591
推荐阅读
相关标签
  

闽ICP备14008679号