6.EP4CE10F17的基于串口的电压采集系统

前记:师夷长技以自强


一、需求

1.使用ADC以最高速度采集2000个数据,将这些数据存储在scfifo中

2.等待着2000个数据采集完成之后,从scfifo中读取数据出来使用串口持续发送直到2000个数据全部发完。

二、分析

.2.1系统框图

当系统模块多了后,最好画一个框图,以示数据在各模块中的流动关系。

2.2状态分析

2.2.1 状态的划分

1.空闲   IDEL

2.持续采样状态   

    (1)使能单次采样   Sample_T

    (2)等待单次采样完成    Wait_Conv_Done

3.串口持续发送数据状态

    (1)使能单次发送    Tx_T

    (2)等待单次发送完成    Wait_Tx_Done

2.2.2 关键信号选取

Key_flag    Key_state:空闲态到工作态的转换

Conv_done    Conv_times_cnt:采样状态到新的采样触发状态或者数据发送触发状态的跳转条件

Tx_Done    Tx_times_cnt     usedw:发送状态到新的发送触发状态或者空闲状态的跳转条件

2.3 注意问题

(1)端口信号延迟问题

我们都知道时序电路是有延迟的,因此从fifo中读数据到串口发送数据应该注意,发送读请求给fifo需要延迟一个时钟周期后数据才能输出,而fifo输出端口的数据又需要延迟一个时钟周期才能到达串口中的缓存。所以串口的发送使能信号应该在fifo的读请求信号后两个时钟周期。

(2)波特率设置

因为计时是从0开始的,所以对系统时钟分频后应记得减1.

(3)仿真问题

为了能在modelsim中仿真及早发现问题,可以利用系统函数$readmemh函数从指定的文件中输入数据,模拟ADC器件的DOUT端输出的数据,而每个采样值产生的时间应该是conv_start和conv_done之间。

为了能在modesim中看到串口发送模块发送的数据,可以设计一个Uart_Rx_Model模块用于接收Rs232_Tx发来的数据,数据的采集开始以Rs232_Tx的下降沿开始,然后在每一bit的中间采集数据。

为了控制仿真系统能够停止,可以捕捉fifo的empty信号,当出现上升沿时说明fifo中的数据已经读完,可以稍微延迟一段时间后就停止仿真。

为了精确控制ADC采样的每个数据和Uart_Rx_Model模块接收的每个数据,可利用系统函数$display输出到modelsim的仿真文本数据中。

3.代码设计

这里只给出状态机和仿真的代码设计,ADC,filtter和UART模块的代码可以参考之前的博客。

module FSM(
    input Clk,
    input Rst_n,
    input Conv_Done,
    input full,
    input [11:0]Redata,
    input [10:0]UsedW,
    input empty,
    input Tx_Done,
    input Key_flag,
    input Key_state,
    output reg Conv_Start,
    output reg [7:0]ADC_DIV_PARAM,
    output reg [2:0]Channel,
    output reg Sclr,
    output reg Wrreq,
    output reg Rdreq,
    output     [7:0]Data,
    output     Tx_Start,
    output reg [2:0]Baud_set
);

    localparam
        IDEL =           5'b00001,
        Sample_T =       5'b00010,
        Wait_Conv_Done = 5'b00100,
        Tx_T =           5'b01000,
        Wait_Tx_Done =   5'b10000;
        
    reg [4:0]state;
    reg [10:0]Conv_times_cnt;
    reg [10:0]Tx_times_cnt;
    reg [2:0]Tx_Start_r;
    
    always@(posedge Clk,negedge Rst_n)
    if(!Rst_n)
        Tx_Start_r <= 0;
    else
        Tx_Start_r <= {Tx_Start_r[1:0],Rdreq};
        
    assign Tx_Start = Tx_Start_r[2];
    assign Data = Redata[11:4];
    
    always@(posedge Clk,negedge Rst_n)
    if(!Rst_n)
        Conv_times_cnt <= 0;
    else if(Conv_Done)
        if(Conv_times_cnt == 11'd2000)
            Conv_times_cnt <= 0;
        else
            Conv_times_cnt <= Conv_times_cnt + 11'b1;
    else
        Conv_times_cnt <= Conv_times_cnt;

    always@(posedge Clk,negedge Rst_n)
    if(!Rst_n)
        Tx_times_cnt <= 0;
    else if(Tx_Done)
        if(Tx_times_cnt == 11'd2000)
            Tx_times_cnt <= 0;
        else
            Tx_times_cnt <= Tx_times_cnt + 11'b1;
    else
        Tx_times_cnt <= Tx_times_cnt;
        
    always@(posedge Clk,negedge Rst_n)
    if(!Rst_n)begin
        state <= IDEL;
        ADC_DIV_PARAM <= 8'd13;
        Channel <= 3'b0;
        Baud_set <= 3'd7;
        Rdreq <= 0;
    end
    else begin
        case(state)
            IDEL:
                begin
                    if(Key_flag&&!Key_state)
                    state <= Sample_T;
                end
            Sample_T:
                begin
                    Wrreq <= 0;
                    Conv_Start <= 1'b1;
                    state <= Wait_Conv_Done;
                end
            Wait_Conv_Done:
                begin
                    Conv_Start <= 1'b0;
                    if(Conv_Done)begin //write to fifo
                        Wrreq <= 1;
                        if(Conv_times_cnt == 11'd2000)
                            state <= Tx_T;
                        else
                            state <= Sample_T;
                    end
                    else
                        state <= Wait_Conv_Done;
                end
            Tx_T:
                begin
                    Wrreq <= 0;
                    Rdreq <= 1;
                    state <= Wait_Tx_Done;
                end
            Wait_Tx_Done:
                begin
                    Rdreq <= 0;
                    if(Tx_Done && Tx_times_cnt == 11'd2000)
                        state <= IDEL;
                    else if(Tx_Done)
                        state <= Tx_T;
                    else
                        state <= Wait_Tx_Done;
                end
        endcase
    end

endmodule 
 

仿真代码

module Sample_Voltage(
    input Clk,
    input Rst_n,
    input Key_in,
    input DOUT,
    output CS_N,
    output SCLK,
    output DIN,
    output Rs232_Tx
);
    wire Key_flag;
    wire Key_state;
    wire Conv_Start;
    wire Conv_Done;
    wire  [11:0] Vout; //ADC result
    wire [7:0]ADC_DIV_PARAM;
    wire [2:0]Channel;
    wire Wrreq;
    wire [11:0]Wrdata;
    wire Rdreq;
    wire [11:0]Redata;
    wire [11:0]UsedW;
    wire empty;
    wire full;
    wire Sclr;
    wire [7:0]Data2Uart;
    wire Tx_Start;
    wire [2:0]Baud_set;
    wire Tx_Done;
    
    key_filter key_filter(
        .Clk(Clk),
        .Rst_n(Rst_n),
        .Key_in(Key_in),
        .key_flag(Key_flag),
        .key_state(Key_state)    
    );

    ADC ADC(
        .Clk(Clk),
        .Rst_n(Rst_n),
        .DIV_PARAM(ADC_DIV_PARAM),
        .Channel(Channel),
        .Start(Conv_Start),
        .DOUT(DOUT),
        .Conv_Done(Conv_Done),
        .ADC_STATE(),  //0-idle,1-busy
        .Data(Vout),
        .SCLK(SCLK),
        .DIN(DIN),
        .CS_N(CS_N)
    );
    
    fifo fifo(
        .clock(Clk),
        .data(Vout),
        .rdreq(Rdreq),
        .sclr(Sclr),
        .wrreq(Wrreq),
        .empty(empty),
        .full(full),
        .q(Redata),
        .usedw(UsedW)
    );
    UART UART(
        .Clk(Clk),
        .Rst_n(Rst_n),
        .Send_En(Tx_Start),
        .data_byte(Data2Uart),
        .baud_set(Baud_set),
        .uart_state(),
        .Tx_done(Tx_Done),
        .Rs232_Tx(Rs232_Tx)
    );
    FSM FSM(
        .Clk(Clk),
        .Rst_n(Rst_n),
        .Conv_Done(Conv_Done),
        .full(full),
        .Redata(Redata),
        .UsedW(UsedW),
        .empty(empty),
        .Tx_Done(Tx_Done),
        .Key_flag(Key_flag),
        .Key_state(Key_state),
        .Conv_Start(Conv_Start),
        .ADC_DIV_PARAM(ADC_DIV_PARAM),
        .Channel(Channel),
        .Sclr(Sclr),
        .Wrreq(Wrreq),
        .Rdreq(Rdreq),
        .Data(Data2Uart),
        .Tx_Start(Tx_Start),
        .Baud_set(Baud_set)
    );
    
endmodule
 

 

`timescale 1ns/1ns
`define clk_period 20

module Uart_Rx_Model(Baud_Set,Uart_Rx);
    input [2:0]Baud_Set;
    input Uart_Rx;
    
    reg Clk;
    reg Rst_n;
    
    wire Mid_Flag_Receive; /*数据中点标志*/
    
    reg Receive_Baud_Start;/*接受波特率生成使能*/
    reg [7:0]Rx_Data;/*接受数据移位寄存器*/
    
    reg [7:0]Rx_Byte;/*最终接收结果*/
    
    initial Clk = 1;
    always #(`clk_period/2) Clk = ~Clk;
    
    /*例化波特率设置模块*/
    Baud_Select Baud_Select_Receive(
        .Clk(Clk),
        .Rst_n(Rst_n),
        .Baud_Set(Baud_Set),
        .Baud_Start(Receive_Baud_Start),
        .Mid_Flag(Mid_Flag_Receive)    
    );
    
    initial begin
        Rst_n = 0;
        Rx_Byte = 0;
        Rx_Data = 0;
        #100 Rst_n = 1;
    end
    
    /*接收一个字节的数据*/
    initial begin
        forever begin
            @(negedge Uart_Rx)
                begin
                    Receive_Baud_Start = 1;
                    @(posedge Mid_Flag_Receive);
                    @(posedge Mid_Flag_Receive)Rx_Data[0] = Uart_Rx;
                    @(posedge Mid_Flag_Receive)Rx_Data[1] = Uart_Rx;
                    @(posedge Mid_Flag_Receive)Rx_Data[2] = Uart_Rx;
                    @(posedge Mid_Flag_Receive)Rx_Data[3] = Uart_Rx;
                    @(posedge Mid_Flag_Receive)Rx_Data[4] = Uart_Rx;
                    @(posedge Mid_Flag_Receive)Rx_Data[5] = Uart_Rx;
                    @(posedge Mid_Flag_Receive)Rx_Data[6] = Uart_Rx;
                    @(posedge Mid_Flag_Receive)Rx_Data[7] = Uart_Rx;
                    @(posedge Mid_Flag_Receive)begin Receive_Baud_Start = 0;Rx_Byte = Rx_Data;end
                    $display("Master_receive Data = %0h",Rx_Byte);
                end
        end
    end
    
endmodule

/*此模块用于生成仿真模型接受数据所需波特率时钟信号*/
module Baud_Select(Clk,Rst_n,Baud_Set,Baud_Start,Mid_Flag);
    input Clk;
    input Rst_n;
    input [2:0]Baud_Set;
    input Baud_Start;
    output Mid_Flag;
    
    parameter system_clk = 1000_000_000/`clk_period;
    
    localparam bps9600 = system_clk/9600 - 1;
    localparam bps19200 = system_clk/19200 - 1;
    localparam bps38400 = system_clk/38400 - 1;
    localparam bps57600 = system_clk/57600 - 1;
    localparam bps115200 = system_clk/115200 - 1;
    localparam bps230400 = system_clk/230400 - 1;
    localparam bps460800 = system_clk/460800 - 1;
    localparam bps921600 = system_clk/921600 - 1;

    localparam bps9600_2 = system_clk/9600/2 - 1;
    localparam bps19200_2 = system_clk/19200/2 - 1;
    localparam bps38400_2 = system_clk/38400/2 - 1;
    localparam bps57600_2 = system_clk/57600/2 - 1;
    localparam bps115200_2 = system_clk/115200/2 - 1;
    localparam bps230400_2 = system_clk/230400/2 - 1;
    localparam bps460800_2 = system_clk/460800/2 - 1;
    localparam bps921600_2 = system_clk/921600/2 - 1;

    reg [31:0]BPS_PARA;
    reg [31:0]BPS_PARA_2;
    
    always@(posedge Clk or negedge Rst_n)
    if(!Rst_n)begin
        BPS_PARA <= bps9600;
        BPS_PARA_2 <= bps9600_2;
    end
    else begin
        case(Baud_Set)
            3'd0:begin BPS_PARA <= bps9600;BPS_PARA_2 <= bps9600_2;end
            3'd1:begin BPS_PARA <= bps19200;BPS_PARA_2 <= bps19200_2;end
            3'd2:begin BPS_PARA <= bps38400;BPS_PARA_2 <= bps38400_2;end
            3'd3:begin BPS_PARA <= bps57600;BPS_PARA_2 <= bps57600_2;end
            3'd4:begin BPS_PARA <= bps115200;BPS_PARA_2 <= bps115200_2;end
            3'd5:begin BPS_PARA <= bps230400;BPS_PARA_2 <= bps230400_2;end
            3'd6:begin BPS_PARA <= bps460800;BPS_PARA_2 <= bps460800_2;end
            3'd7:begin BPS_PARA <= bps921600;BPS_PARA_2 <= bps921600_2;end
        endcase
    end
    
    reg [31:0]cout;
    always@(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        cout<=32'd0;
    else if((cout==BPS_PARA)||!Baud_Start)
        cout<=32'b0;
    else
        cout<=cout+1'b1;
        
    reg Mid_Flag_1;
    always@(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        Mid_Flag_1 <= 1'b0;
    else if((cout==BPS_PARA_2))
        Mid_Flag_1 <= 1'b1;
    else
        Mid_Flag_1 <= 1'b0;
        
    assign Mid_Flag=Mid_Flag_1;
    
endmodule    

为了直观感受一下系统的运行结果,下面给出仿真波形图,这里软件出来点问题,波形叠加在了一起,不过不影响对波形的观察

有什么问题欢迎在下方留言~

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值