基于FPGA+单片机的简易数字示波器_fpga 虚拟示波器
一、序言
在传统电子实验中,示波器是一件不可或缺的工具,它帮助我们“看见”电信号的变化过程,洞察系统的时序、逻辑甚至故障。
FPGA(现场可编程门阵列)作为一种高度并行、实时响应迅速的硬件平台,正好为构建一个“自制”的简易数字示波器提供了理想的基础。通过采集、存储和显示输入波形,我们不仅能实现基础波形观察功能,还能深入理解数据采集、触发逻辑、时序控制、以及数字信号处理等核心概念。
在这篇博客中,我将用FPGA和单片机协同实现简易数字示波器,总体功能框图如下:
- FPGA端:测试信号的产生(后续可去掉)、信号触发的判断及采集
- MCU端:读取波形数据,做可视化处理
二、FPGA端
具体模块如下:
- DUT:包含信号源、触发模块、时基模块
- ram_wr:一块512*8bit的RAM
- spi_CTL:SPI通信控制器
1.测试信号源
测试信号源原理于DDS相同,即需要一个时钟驱动信号、预设的频率字以及一个写有波形数据的ROM,由于这里直接产生了波形的数字数据,因此不用加DAC或ADC
2.为什么要加触发模块?
时域触发技术是示波器的重要的概念 ,例如,假设存在一个用电压表示的具有无穷时间长度的正弦信号,并且我们有某种技术手段可以把时域上的一段电压信号显示在一个电子屏幕上。 如果我们需要在屏幕上显示该正弦信号时间长度为1秒的一段时域波形,那么
- 屏幕上显示信号的刷新方式是什么?
- 手动单次刷新:人工操作一次,则绘制一次信号波形
- 自动连续刷新:无需操作,连续绘制信号波形
- 当采用自动的连续刷新方式时,在屏幕上两次绘制的信号波形, 其相位关系是什么?
- 相位关系相同,则两次绘制的正弦波形形状一致,观察到稳定的波形
- 相位关系不同,则两次绘制的正弦波形形状不同,观察到抖动的波形
要实现前后两次采集的相位关系一致,关键在于触发机制的设置。通过设置固定的触发电平,可以确保信号在每次采集中都从同一幅度起始,始终在相同的位置开始捕获。这种方式有效保证了每次采样波形在相位上的一致性,从而便于对比和分析。
在实际工作中,示波器的常用触发方式是带有方向性的电平触发方式,比如:
- 正向通过触发电平:即信号电平值从低到高的通过触发电平,产生触发。
- 负向通过触发电平:即信号电平从高到低的通过触发电平,产生触发。
- 双向通过触发电平:即信号只要在触发电平附近来回变化则产生触发。
- 自由触发:无触发电平。
在设计示波器时,触发电路有模拟触发和数字触发两种方式,即
- 所谓模拟触发,是指使用模拟比较器电路来完成信号电平和触发电平的比较
- 所谓数字触发,是指使用数字电路来比较经过ADC采样的信号波形样值和触发电平样值
在本设计中,我们采用FPGA实现数字正向触发,以本实验的正弦信号为例,信号被量化到[0-255]的区间内,因此我们设置触发区间[127-8,127+8],当信号正向通过该区间时,输出触发电平
通过Modelsim仿真可以看出符合功能
3.时基模块
时间基准的用途是,在主控器(MCU)的控制下,把满足触发条件的波形数据写入到双口RAM中, 模块的工作过程如下:
- 主控器启动本模块工作
- 当输入信号满足触发条件时, 启动写入电路
- 把从触发点开始的每个有效数据,依次顺序写入到存储数据的双口RAM中
- 当数据RAM写满后,通知主控器读取数据
- 等待主控器再次启动
该功能形成一状态机
时基模块的工作状态变迁逻辑描述如下:
- 模块复位后进入空闲待命状态,IDLE
- 当模块处于IDLE状态或是RAM FULL状态时,来自主控器的启动信号有效时,模块进入触发等待的状态
- 当接收到第一个有效触发数据后,进入数据存储状态,依次保存所有的有效数据,生成写使能和写地址信号,直到数据RAM装满
- 数据RAM装满后,进入RAM写满状态,生成RAM写满状态信号,等待主控器再次启动
从ModelSim仿真图中可以看出,只有启动信号I_START发出后,才会进行触发等待,开始写RAM;否则无视触发信号
4.SPI控制器
FPGA端实现信号采集并存储后,需要将数据送给MCU端,这就需要一个控制器实现SPI通信,主控端写入要读取的地址,读出对应的数据。可以参考我前面发的spi通信打通fpga和单片机(一)_单片机spi传输32位数据-CSDN博客,本实验的spi控制器更加简单,不需要进行地址解码片选及总线复用。
三、主控(MCU)端
主控端的设计相较于FPGA的硬件设计就简单得多,仅需配置6个IO口,围绕这6个端口进行操作:
- O_CS:spi片选,拉低通信
- O_SCLK:通信时钟
- O_SDOUT:往FPGA里写需要读取数据的地址
- O_START:输出启动信号
- I_SDIN:读取FPGA返回的数据
- I_FULL:FPGA中RAM存满的标志,此时可进行数据读取
系统运行流程为:
void scope_test(){start_scope();//发送启动信号while(!get_full()){};//等待RAM写满spi_rd_addr_9b_data_8_rom_512();//读取数据 scope_display();//刷新显示}int main(void){//初始化 HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART1_UART_Init(); gpio_led_tick_loop(1); printf(\"Hello Stm32 \\r\\n\");while (1)//控制循环 {scope_test(); }}
四、测试
首先,测试spi通信是否成功:先不上显示屏,把单片机收到的信息用串口发出来
收到了稳定的数据,将串口数据导出,绘制波形图:
与我们的触发电平设置相同,因此本设计的核心部分已经验证完毕,可以正常工作,接下来的工作就较为简单了,配置一块显示屏就可以
这里配置了一块4.3存的TFTLCD,做一个初步的可视化波形
可以看到,切换信号类型(正弦/锯齿)、信号频率时,对应有改变,说明已经调通
接下来我们将FPGA内置信号源去掉,换成真实信号源外加ADC,做一个真正的示波器
如图所示,左单片机+显示屏,右FPGA+挂在的一块带ADC的扩展板,再往后是连接的信号源,图片装不下了,目前可以实现波形的显示,波形状态随输入信号的频率、幅值发生改变。
最后附上测试视频~
自制简易数字示波器