英特尔FPGA实训 day11

学习任务:今天实现了串口控制led的亮灭切换,以及发送一个特定字符的功能。

问题的产生及解决:

        在书写led切换亮灭条件的时候,最开始只写了 rx_data == 49 ,导致led没能按照预期发送特定字符亮起,再发送特定字符,熄灭。 这是因为,当 没有新值传入的情况下,rx_data会一直保持最后传入的那个值,也即:如果最后一个是49,则会一直保持49,也就是说,这个if条件会持续成立,内部的语句led <= ~led 会不断执行。导致每有一个时钟电平到来,led就会翻转一次。

为了解决这个问题,也即 想要,只有一瞬间满足该条件,然后执行内部语句。则很自然想到,,后面就再添加一个条件,也即 数据接收完成的标志。 当接收完成,且接收的值为49 才会进行内部语句。这样就实现了 发送一次翻转 一次led。

下面是相关代码:

led_control 

module led_control(
    input rst_n,
    input clk,
    input [7:0] rx_data,
    input dout_vld,

    output reg tx_req_flag,
    output reg  led
);

always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        led <= 0;
        tx_req_flag <= 0;
    end //下面这排不能少条件,若只写条件1,则会让每个时钟电平到来的时候都会翻转led。
    else if(rx_data == 49 && dout_vld==1)begin //接收到的是ascii码对应值
        led <= ~led;  
        tx_req_flag <= 1; 
    end 
    else begin 
        led <= led; 
        tx_req_flag <= 0;
    end 
end

endmodule

数据接收模块

`include "param.v"
module uart_rx(
    input clk,
    input rst_n,
    input rx_din,

    output [7:0] rx_dout,
    output reg dout_vld
);//开始的标志是,数据接收端下降沿产生,结束标志是,数据包传完,即cnt_bit == 9

reg [12:0] cnt_bps;//波特率计数寄存器
wire add_cnt_bps;//波特率计数开始
wire end_cnt_bps;//波特率计数结束


reg [3:0] cnt_bit;//比特计数寄存器
wire add_cnt_bit;//比特计数开始
wire end_cnt_bit;//比特计数结束

reg rx_flag;
reg rx_din_r0;
reg rx_din_r1;
reg [9:0] rx_data;

wire nedge;

always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        rx_din_r0 <= 1'b1;
        rx_din_r1 <= 1'b1;
    end
    else begin 
        rx_din_r0 <= rx_din;
        rx_din_r1 <= rx_din_r0;
    end 
end

assign nedge = ~rx_din_r0 && rx_din_r1;//下降沿产生,是开始接收的标志。 因为在发送端,第一位是0,所以这里正好从1->0,即下降沿产生 

//波特率计数器 (接收一个Bit需要的时间)
always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt_bps <= 0;
    end 
    else if(add_cnt_bps)begin 
            if(end_cnt_bps)begin 
                cnt_bps <= 0;
            end
            else begin 
                cnt_bps <= cnt_bps + 1;
            end 
    end
   else  begin
       cnt_bps <= cnt_bps;
    end
end 

assign add_cnt_bps = rx_flag;
assign end_cnt_bps = add_cnt_bps && cnt_bps == (`SYS_FRQ / `BAUD_MAX) - 1'd1;

//计数发送了多少位数据
always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt_bit <= 0;
    end 
    else if(add_cnt_bit)begin 
            if(end_cnt_bit)begin 
                cnt_bit <= 0;
            end
            else begin 
                cnt_bit <= cnt_bit + 1;
            end 
    end
   else  begin
       cnt_bit <= cnt_bit;
    end
end 

assign add_cnt_bit = end_cnt_bps;
assign end_cnt_bit = add_cnt_bit && cnt_bit == 4'd9;
//判断是否开始接收数据(下降沿产生,则开始,几位数据位遍历完,则结束)
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        rx_flag <= 1'b0;
    end 
    else if(nedge)begin//数据开始输入 
        rx_flag <= 1'b1;
    end
    else if(end_cnt_bit)begin
        rx_flag <= 1'b0;
    end
    else begin 
        rx_flag <= rx_flag;
    end 
end

always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        rx_data <= 10'b0;
    end //下面这个判断条件很巧妙
    //(考虑到了 0.1数据位之间临界处并不是理想的垂直跳变,所以就慢半拍(电平完全稳定了)读取数据值,
    else if(rx_flag && cnt_bps == (`SYS_FRQ / `BAUD_MAX)>>1)begin 
        rx_data[cnt_bit] <= rx_din_r0;//注意cnt_bit要cnt_bps==(`SYS_FRQ / `BAUD_MAX)才会+1,所以第一次赋值的rx_data[0]会被覆盖一次
    end 
    else begin 
        rx_data <= rx_data;
    end 
end

assign rx_dout = rx_data[8:1];

always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        dout_vld <= 1'b0;
    end 
    else if(end_cnt_bit)begin 
        dout_vld <= 1'b1;
    end 
    else begin 
        dout_vld <= 1'b0;
    end 
end

endmodule

数据发送模块

`include "param.v"
module uart_tx(
    input clk,
    input rst_n,
    input tx_req,
    input [7:0] tx_din,//输入的并行数据(真正需要发送的数据串)(数据不够这么多位,自动补零?)

    output reg tx_dout,//输出的串行数据
    output dout_vld     //发送完成的标志
);//开始的标志是 tx_req为1,结束的标志是 数据发送完,tx_flag随即置0

reg [12:0] cnt_bps;//波特率计数寄存器 
wire add_cnt_bps;   //波特率计数开始标志 
wire end_cnt_bps;   //波特率计数结束 


reg [3:0] cnt_bit;//比特计数寄存器
wire   add_cnt_bit;//比特计数开始标志
wire   end_cnt_bit;//比特计数结束
reg tx_flag;
reg [9:0] tx_data;//需要发送的数据  (实际发送的数据串,即:包括包头包尾)

//波特率计数器(发送1bit需要的时间)
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        cnt_bps <= 0;
    end 
    else if(add_cnt_bps)begin 
        if (end_cnt_bps) begin
            cnt_bps <= 0;
        end
        else begin
            cnt_bps <= cnt_bps +1;
        end
    end 
    else begin 
        cnt_bps <= cnt_bps ;
    end 
end
assign add_cnt_bps = tx_flag;
assign end_cnt_bps = add_cnt_bps && cnt_bps == (`SYS_FRQ/`BAUD_MAX)-1'd1 ;


//计数已经发送了多少位数据(确定当前应该发送第几位了)
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        cnt_bit <= 0;
    end 
    else if(add_cnt_bit)begin 
        if (end_cnt_bit) begin
            cnt_bit <= 0;
        end  
        else begin 
            cnt_bit <= cnt_bit + 1;
        end 
    end 
    else begin
        cnt_bit <= cnt_bit;
    end
    
end
assign add_cnt_bit = end_cnt_bps;
assign end_cnt_bit = add_cnt_bit && cnt_bit == 4'd9;//达到条件后,结束发送

//发送开始,结束的判断
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        tx_flag <= 0;
    end 
    else if(tx_req)begin //收到发送请求,则 将发送位(即tx_flag)置1
        tx_flag <= 1'b1;
    end 
    else if (end_cnt_bit) begin
        tx_flag <= 1'b0; 
    end 
    else begin 
        tx_flag <= tx_flag;  
    end 
end 

//拼接(打包)需要发送的数据
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        tx_data <= 10'b0; 
    end 
    else if(tx_req)begin 
        tx_data <= {1'b1,tx_din,1'b0};//注意:传送的时候 tx_data[0]=0  而不是1。  这里最后一位是1,是因为 要让接收端的默认信号变回高电平,便于下次低电平到来的时候,下降沿的产生
    end 
    else begin 
        tx_data <= tx_data;
    end 
end
//开始发送数据
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        tx_dout <= 1'b1;
    end 
    //发送端为什么不考虑0.1衔接不理想的问题?
    //,因为发送端是发送,而不是读取,读取要判断该电平表示1还是0,而发送端不用读取、所以不用考虑0.1电平理想的问题
    else if(tx_flag && cnt_bps == 1)begin 
        tx_dout <= tx_data[cnt_bit];
    end 
    else begin 
        tx_dout <= tx_dout;
    end 
end
assign dout_vld = ~tx_flag;

endmodule

顶层文件:

module uart_led(
    input clk,
    input rst_n,
    input rx,

    output tx_dout,
    output led
);
wire [7:0] rx_reg;
wire dout_vld;
wire tx_req_flag;
reg [7:0] message = "t";



uart_rx u_uart_rx(
.clk(clk),
.rst_n(rst_n),
.rx_din(rx),

.rx_dout(rx_reg),//rx_reg在没有新值产生的情况下,一直保持该时刻的值
.dout_vld(dout_vld)
);

led_control u_led_control(
.clk(clk),
.rst_n(rst_n),
.rx_data(rx_reg),
.dout_vld(dout_vld),

.tx_req_flag(tx_req_flag),
.led(led)
);

uart_tx u_uart_tx(
.clk(clk),
.rst_n(rst_n),
.tx_req(tx_req_flag),

.tx_din(message),
.tx_dout(tx_dout)

);

endmodule 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值