设为首页 加入收藏

TOP

用状态机实现串口多字节数据接收(一)
2023-07-23 13:25:57 】 浏览:423
Tags:

这次设计一个可以接收多字节(通过修改例化时的位宽实现)的串口接收模块。
 
当接收到9个字节的数据,但是我们只需要8个字节的数据时候,我们需要的是前八位的数据还是后八位的数据我们无法确定。
image
 
所以我们需要设定一种传输协议,这种协议我们可以自定义规则。我们就设定前缀为8'h55+8'hA5,后缀为8'hF0的一串数据即为我们需要的数据。
image

1、状态机的设定

 
image
 

2、需要的模块

(1) 8位串口接收模块

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: Lclone
// 
// Create Date: 2022/12/16 15:37:44
// Design Name: uart_byte_rx
// Module Name: uart_byte_rx
// Project Name: uart_byte_rx
// Target Devices: 
// Tool Versions: 
// Description: 8位串口接收模块
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module uart_byte_rx
  # (
        parameter   RX_BAUD  = 9600,             //波特率
        parameter   CLK_FQC  = 50_000_000,       //模块时钟频率
        parameter   BAUD_CNT = CLK_FQC/RX_BAUD)  //模块每波特需要计数的次数(设置此端口方便仿真用)
    (
        input               Clk,                 //时钟频率接口
        input               Rst_n,               //复位接口
        input               Uart_rx,             //串口接收接口
        output  reg  [7:0]  Data,                //接收到的数据接口
        output  reg         Rx_done              //接收完成信号
    );
    
    reg            uart_rx_r;                    //延一拍
    reg            uart_rx_rr;                   //延两拍
    reg            uart_rx_rrr;                  //延三拍
    reg            receiv_begin;                 //接收开始信号
    reg            receiv_flag;                  //接收状态信号
    reg   [ 3:0]   state;                        //状态机寄存器
    reg   [15:0]   baud_cnt;                     //波及计数器
    reg   [ 3:0]   sampel_cnt;                   //采样计数器
    reg            sampel_en;                    //采样使能
    reg            sampel_ref;                   //样本寄存器
    reg   [ 3:0]   acc;                          //累加寄存器
    reg   [ 3:0]   bit_cnt;                      //数据位寄存器
    
    always @(posedge Clk) begin   //延两拍为下降沿捕获
        uart_rx_r <= Uart_rx;
        uart_rx_rr <= uart_rx_r;
        uart_rx_rrr <= uart_rx_rr;
    end
    
    always @(posedge Clk or negedge Rst_n) begin	//接收信号发生
        if(Rst_n == 0)
            receiv_begin <= 0;
        else if(state == 0 & uart_rx_rrr & ~uart_rx_rr)
            receiv_begin <= 1'b1;
        else
            receiv_begin <= 0;
    end
    
    always @(posedge Clk or negedge Rst_n) begin	//状态机
        if(Rst_n == 0) begin
            state <= 0;
            sampel_ref <= 8'b0;
            acc <= 8'b0;
            Data <= 8'b0;
        end
        else case(state)
            0:     //空闲状态
                if(receiv_begin == 1)
                    state <= 3'd1;
                else
                    state <= 0;
            
            1: begin    //抽样状态
                    if(sampel_en == 1) begin
                           sampel_ref <= Uart_rx;
                           state <= 3'd2;
                    end

                    else
                        state <= 3'b1;
               end   
                    
            2: begin    //数据判断状态

                    acc <= acc + sampel_ref;
                   
                    if(sampel_cnt == 7) begin
                        if(acc >= 4)
                            begin Data[7] <= 1'b1; state <= 3'd3;acc <= 8'b0; end
                        else
                            begin Data[7] <= 0; state <= 3'd3;acc <= 8'b0; end
                    end
                    
                    else
                        state <= 3'd1;
               end

            3: begin	//数据移位状态
                    if(bit_cnt < 8) begin
                        Data <= Data >> 1;
                        state <= 3'd1; 
                    end
                    
                    else 
                        state <= 0;
            end
            
            default:;
       endcase
    end
    
    always @(posedge Clk or negedge Rst_n) begin    //接收进行标志
        if(Rst_n == 0)
            receiv_flag <= 0;
        else if(receiv_begin == 1)
            receiv_flag <= 1'b1;
        else if(bit_cnt == 9 & baud_cnt == BAUD_CNT/9*8) //这里设置为记到BAUD_CNT/9*8是为了让Rx_done信号提前一点产生,避免因为Rx_done出现过晚,导致错过下一个起始位的下降沿。后面和其相同的条件判断,也是因为相同原因设置的。
            receiv_flag <= 1'b0;
    end
    
    always @(posedge Clk or negedge Rst_n) begin    //波特计数
        if(Rst_n == 0)     
            baud_cnt <= 0;
        else if(receiv_flag == 1) begin
            if(baud_cnt == BAUD_CNT - 1)
                baud_cnt <= 0;
            else
                baud_cnt <= baud_cnt + 1'b1;
            end
        else
            baud_cnt <= 0;      
    end
    
    always @(posedge Clk or negedge Rst_n) begin    //采样计数
        if(Rst_n == 0) begin
            sampel_cnt <= 0;
            sampel_en <= 0;
        end
        else if(receiv_flag == 1) begin
            case(baud_cnt)
                BAUD_CNT/9*1-1 : begin sampel_cnt <= 0; sampel_en <=1; end
                BAUD_CNT/9*2-1 : begin sampel_cnt <= 1; sampel_en <=1; end
                BAUD_CNT/9*3-1 : begin sampel_cnt <= 2; sampel
首页 上一页 1 2 3 4 5 下一页 尾页 1/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇串口接收模块——verilog实现 下一篇verilog常见语法记录(一)

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目