基于NIOS-II的示波器:PART3 初步功能实现

本文记录了在NIOS II上实现示波器的第三部分。
本文主要包括:硬件部分的BRAM记录波形,计算频率的模块,以及软件部分这两个模块的驱动。

本文所有的硬件以及工程参考来自魏坤示波仪,重新实现驱动并重构工程。

version 0.3 初步功能实现

关于示波器的两种Trigger Mode的

以下内容参考博客StrongPiLab

设置好的Trigger condition才会使得波形固定在屏幕上,不会左右乱飘。

触发就是,当波形穿过Trigger level的时候,就会产生触发信号,且该点为触发点。

如下图所示:

这里写图片描述

触发模式有以下几种

  • Auto Trigger

    若ADC输入的数据没有满足Trigger condition,则示波器不会发出Trigger信号。

    Auto Trigger就是在没有满足Trigger condition的时候,就内部自动发出Trigger信号画波形。

    这里写图片描述

    第一个直流波形因为毫无震幅变化,所以Trigger永远无法满足,因此Auto trigger会自行发出Trigger讯号画波形,红色的框框就是每次画出的波形内容。这也就是为何一个没有讯号输入的示波器,你还是能够看到0V(ground)能不断更新画面的原因。

    第二个含有脉冲的方波因为有部分波型满足上缘触发,因此前两格画面是Trigger条件满足下而画出来的,后面三格画面则是Auto trigger自己画出来的,以使用者观点来说,他会看到一个脉冲波突然出现,之后随即消失。

  • Normal Trigger

    Auto trigger平常很好用,但在Debug的时候可能就不见得这么好用。因为Debug时所面对的波形通常是在不确定时间出现的不正常波形,因此若採用Auto trigger的话,很容易错失观察波形的机会,这时Normal trigger就派上用场了。

    这里写图片描述

    Normal trigger只在波形符合trigger条件时, 才会更新屏幕上的波形,否则屏幕就继续维持著上次的波形。也就是屏幕上永远都会有一个上次触发过的波形固定在那里。

这里设计的MEM_CONTROL利用TRIG_AN在自动触发以及Normal Trigger中选择。

利用三个计数器来实现Timeout的功能。

  • 若选择Auto触发模式,在COUNTER3计数结束之后便自动开始触发
  • 若选择Noramal模式,则只有在满足了Triger Condition的情况下才触发
  • 触发开始后counter2开始计数,增长一个存储深度后便停止增长,并停止向内存中写入
            if(COUNTER1>=MEM_LEN) 
                TRIG_EN<=1;
            else
                COUNTER1<=COUNTER1+1;
            //Auto模式COUNTER3用来记录Timeout
            if(TRIG_EN && COUNTER3<MEM_LEN && TRIG_AN == 0)
                COUNTER3<=COUNTER3+1;
            //触发结束或者自动触发TOif(TRIG_DONE||COUNTER3>=MEM_LEN)
            begin
                if(COUNTER2>=MEM_LEN) 
                    MEM_DONE<=1;
                else 
                    COUNTER2<=COUNTER2+1;
            end

触发成功模块如下,其中TRIG_PULSE为触发脉冲

    //有数据超过了Trigger condition 触发成功
    always @(posedge TRIG_PULSE or negedge RESET)
    begin
        if(!RESET)
            TRIG_DONE<=0;
        else
            TRIG_DONE<=TRIG_EN;
    end

触发成功的同时记录触发地址

    //这里记录触发的起始地址
    always @(posedge TRIG_DONE or negedge RESET)
    begin
        if(!RESET)
            TRIG_ADDR<=0;
        else
            TRIG_ADDR<=RAM_ADDR;
    end
MEM_CONTROL

这个模块为整个硬件部分最为重要的一部分,主要承当了以下作用

  • 读取ADC传入的信息并将其存入MEM中。

  • 根据选择的触发法相输出脉冲给后续FREQ_COUNTER_MODULE 计算频率。

  • 确定存储深度MEM_LEN 后,先采集一个深度的数据,然后根据是否有触发脉冲确定是否有有效数据。
module MEM_control_H(CLK,RESET,RD,ADC_DATA_CH1,ADC_DATA_CH2, 
                MEM_DATA_CH1,MEM_DATA_CH2,MEM_ADDR,MEM_DONE,
                TRIG_ADDR,TRIG_DATA,TRIG_DONE,
                TRIG_PULSE_CH1,TRIG_PULSE_CH2,
                TRIG_EDGE_SEL,TRIG_SEL,
                MEM_LEN,TRIG_AN);

    //输入输出端口声明
    input CLK;
    input RD;
    input [12:0] MEM_LEN;
    input RESET;
    input TRIG_EDGE_SEL;
    input TRIG_SEL;
    input [7:0] TRIG_DATA;
    input [7:0] ADC_DATA_CH1;
    input [7:0] ADC_DATA_CH2;
    input [12:0] MEM_ADDR;
    input TRIG_AN;                          //TRIG_AUTO/NORMAL选择
    output reg [12:0]TRIG_ADDR;             //用来表示触发内存地址
    output reg [7:0] MEM_DATA_CH1;          //MEM_DONE为1时 利用RD读取MEM_ADDR的CH1的数据
    output reg [7:0] MEM_DATA_CH2;          //MEM_DONE为1时 利用RD读取MEM_ADDR的CH2的数据
    output reg MEM_DONE;                    //用来表示内存存储已经完成,可以利用RD进行读取
    output reg TRIG_DONE;                   //用来表示已经被触发
    output reg TRIG_PULSE_CH1;              //CH1的触发波形 用来计算CH1的周期
    output reg TRIG_PULSE_CH2;              //CH2的触发波形 用来计算CH2的周期
    //临时变量
    reg [12:0] RAM_ADDR;
    reg [7:0] MEM_CH1[8192]; //B_RAM
    reg [7:0] MEM_CH2[8192];
    reg TRIG_EN;
    reg [12:0] COUNTER1;
    reg [12:0] COUNTER2;
    reg [12:0] COUNTER3;
    reg TRIG_PULSE;

    always @(posedge CLK or negedge RESET)
    begin
        if(!RESET)
        //RESET 重置
        begin
            TRIG_EN<=0;
            COUNTER1<=0;
            COUNTER2<=0;
            COUNTER3<=0;
            MEM_DONE<=0;
            RAM_ADDR<=0;
        end
        else if(MEM_DONE==0)
        begin
            //将ADC的输入写入内存
            MEM_CH1[RAM_ADDR]<=ADC_DATA_CH1;
            MEM_CH2[RAM_ADDR]<=ADC_DATA_CH2;
            RAM_ADDR=RAM_ADDR+1;
            //若COUNTER大于存储深度 则开始触发用于计算周期
            if(COUNTER1>=MEM_LEN) 
                TRIG_EN<=1;
            else
                COUNTER1<=COUNTER1+1;
            if(TRIG_EN && COUNTER3<MEM_LEN && TRIG_AN == 0)
                COUNTER3<=COUNTER3+1;
            if(TRIG_DONE||COUNTER3>=MEM_LEN)
            begin
                if(COUNTER2>=MEM_LEN) 
                    MEM_DONE<=1;
                else 
                    COUNTER2<=COUNTER2+1;
            end
        end
    end

    //RD的上升沿读取MEM_ADDR指向的地址
    always @(posedge RD)
    begin
        if(MEM_DONE)
        begin
            MEM_DATA_CH1<=MEM_CH1[MEM_ADDR];
            MEM_DATA_CH2<=MEM_CH2[MEM_ADDR];
        end
    end

    //CH1实现边缘触发    
    //若TRIG_EDGE_SEL = 1 则为上升触发
    //若TRIG_EDGE_SEL = 0 则为下降触发
    //实现触发的思路均为当从不同的方向超过触发线
    //则将TRIG_PULSE_CH1置为1,表示有一个CH1脉冲
    //后还利用TRIG_PULSE判断一个周期的时间 计算频率
    always @(posedge CLK)
    begin
        if(TRIG_EDGE_SEL)
        begin
            if(ADC_DATA_CH1>TRIG_DATA)
                TRIG_PULSE_CH1<=1;
            else 
                TRIG_PULSE_CH1<=0;
        end
        else
        begin
            if(ADC_DATA_CH1<TRIG_DATA)
                TRIG_PULSE_CH1<=1;
            else 
                TRIG_PULSE_CH1<=0;
        end
    end

    //CH2实现边缘触发    
    //若TRIG_EDGE_SEL = 1 则为上升触发
    //若TRIG_EDGE_SEL = 0 则为下降触发
    //实现触发的思路均为当从不同的方向超过触发线
    
  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值