自制简易示波器

其实是在整理手上的元器件的时候,想用一个示波器,但是我没有,因此就想到自己简单做一个,能满足自己的简单需求即可。

经过测试 10Khz 及以下的波形都可以正常显示,可以先去文章末尾看效果。更高的频率还没试过。缺点就是:只能测量正电压,0-3.3。一般测量开发板调试电机时输出的PWM波是够用了。

====>>> 文章汇总(有代码汇总) <<<====

1. 硬件准备

  1. 正点原子STM32F103 Mini开发板,主控 STM32F103RCT6.
  2. 配套的 2.8英寸 LCD屏幕。

其他开发板也行,只要能驱动这个屏幕就行。
普中的开发板的话,我主页也有同样 LCD屏的驱动教程,完全可以直接替代移植。

2. 软件规划

示波器监测部分

  1. 定时器定时触发ADC;
  2. ADC监测电压变化;
  3. DMA传输数据ADC数据。

显示部分:

  1. LCD屏进行显示;

3. 硬件配置

3.1. 创建工程

选择 STM32F103RCT6主控;

配置调试接口
在这里插入图片描述
配置外部时钟
在这里插入图片描述
配置时钟树
在这里插入图片描述
工程设置
在这里插入图片描述

3.2. LCD配置

懒的话,可以直接把 软件模拟8080接口驱动LCD的工程拿过来(主页置顶文章有)。跳过前面和本节的步骤。

因为LCD占用的引脚比较多,而且在开发板上都是定死的,而ADC之类的,都有的选则,所以先配置这个。

这里使用的是 正点原子STM32F103 Mini开发板,采用软件模拟8080通信协议进行驱动。

LCD的配置已经说过了,这里就不再重复了。看往期文章的 软件模拟8080并口驱动LCD屏部分。

====>>> LCD 配置在这里 <<<====

配置完成之后的脚印分布如图。

在这里插入图片描述
然后添加 LCD 驱动文件。先测试LCD是否可以正常驱动。同理,看上面说的那篇文章。

在这里插入图片描述

懒的话,可以直接把 软件模拟8080接口驱动LCD的工程拿过来(主页置顶文章有)。跳过前面和本节的步骤。

在确保 LCD 可以运行的情况下,然后开始配置剩下的部分。

3.3. 定时器配置

因为需要保证 ADC每次采用的时间间隔相同,不能再while(1)中进行循环采样。

在《STM32中文参考手册》中可以看到如下内容。
在这里插入图片描述
也就是说,可以利用一个定时器触发ADC采样。

因此,进行如下配置。
在这里插入图片描述

定时器都是挂在APB1和APB2上,时钟频率都一样,都是72MHZ。
这里 分频系数为 36-1,分频完之后的频率是72Mhz / 36 = 2Mhz,计数值为100,也就是每秒产生20000次中断。

也就是每秒触发ADC采用20000次。换句话说,ADC的采样频率是 20000HZ。

3.4. ADC配置

任选一个ADC通道即可。

  1. 设置数据对齐方式,一般都直接选右对齐即可。
  2. 扫描、循环都不用设置。
  3. 设置为定时器3外部事件触发。
  4. 设置采用周期。
  5. 配置DMA,从外设到内存。
    在这里插入图片描述

DMA是需要循环转移数据的。

在这里插入图片描述
配置完ADC之后,ADC的时钟也需要再改一下,配置ADC之前,这个地方是灰色的。现在就可以改了,配置完不超过14Mhz就可以了。
在这里插入图片描述

3.5. 按键配置

调整示波器的显示,正经的示波器上是个旋钮,这里用按键代替,一个开发板齐活。

开发板上有三个按钮。WK_UP、KEY0、KEY1. 原理图如下, 把这三个按钮都配置为中断。

  • WK_UP:上升沿中断、下拉;
  • KEY0:下降沿中断、上拉;
  • KEY1:下降沿中断、上拉;

在这里插入图片描述

需要注意的就是 按键中断 和 DMA中断的优先级(跟DMA相关的中断优先级总是要调试很久。。。不明白,心累,改天补补课研究研究)。

在这里插入图片描述

3.6. 指示灯配置

最后再配置个指示灯,用于给个提示,正在获取数据 刷新波形之前让 LED 亮,波形刷新之后让他灭,等待下次获取的时候再亮。。。

开发板上原理图有两个,这里随便用一个,选 LED0 吧。
在这里插入图片描述

设置为推挽输出,其他的不重要。

到这里所有的配置就没了,重新生成工程即可。

要注意,因为重新生成了代码,前面LCD的源文件和头文件如果没了,需要重新添加源文件和头文件路径。

4. 软件代码

4.1. GUI 代码

先规划一下 LCD 显示界面,把LCD的驱动代码包装一下,方便绘制。

先看一下最终效果。网格效果应该不会再改了,还有一些静态的不需要刷新的文字,放在了函数void setBackGroundText(void);里面,到最后根据布局再回来更改。

在这里插入图片描述

icode文件夹中再创建一个GUI文件夹,在GUI文件夹中创建gui.cgui.h文件。并将源文件和头文件在keil中添加到工程。

gui.h

#ifndef __GUI_H
#define __GUI_H

/*
	author:Haozi
	
	Author URI:https://blog.csdn.net/weixin_46253745
	
	Describe:对 LCD 的驱动文件进行了包装,方便绘制GUI
*/

#include "stdint.h"		// uint16_t 定义

void drawLineWithColor(uint16_t startX, uint16_t startY, uint16_t endX, uint16_t endY, uint16_t color);
void drawStringWithColor(uint16_t startX, uint16_t startY, uint16_t width, uint8_t *p, uint16_t color);
void setBackGroundColor(void);
void drawNetwork(void);
void setBackGroundText(void);

#endif

gui.c

#include "gui.h"
#include "stdint.h"		// uint16_t 定义
#include "lcd.h"

/*
	author:Haozi
	
	Author URI:https://blog.csdn.net/weixin_46253745
	
	Describe:对 LCD 的驱动文件进行了包装,方便绘制GUI
*/


/* ===================================================== */
// 描述:画线函数
// 参数:
//		起始和结束的x y坐标。
//		color:线的颜色
// 返回值:
/* ===================================================== */
void drawLineWithColor(uint16_t startX, uint16_t startY, uint16_t endX, uint16_t endY, uint16_t color)
{
	POINT_COLOR = color;
	LCD_DrawLine(startX, startY, endX, endY);
}


/* ===================================================== */
// 描述:显示字符串函数
// 参数:
//		startX、startY:起始的x y坐标。
//		width:			区域宽度。
//		p:				字符串地址。
//		color:			线的颜色
// 返回值:
/* ===================================================== */
void drawStringWithColor(uint16_t startX, uint16_t startY, uint16_t width, uint8_t *p, uint16_t color)
{
    POINT_COLOR = color;
	// 字符区域大小 和 字体大小 直接定死了
    LCD_ShowString(startX, startY, width, 16, 16, p);
}

/* ===================================================== */
// 描述:设置LCD背景。设置显示方向为横向;背景颜色为黑色。
// 参数:
// 返回值:
/* ===================================================== */
void setBackGroundColor(void)
{
	LCD_Display_Dir(1);		// 设置LCD显示方向为横向
	
	LCD_Clear(BLACK);		// 清空LCD,用黑色覆盖
	BACK_COLOR = BLACK;		// 背景颜色
	POINT_COLOR = YELLOW;	// 线的颜色
}

/* ===================================================== */
// 描述:显示字符串函数
// 参数:
//		startX、startY:起始的x y坐标。
//		width:			区域宽度。
//		p:				字符串地址。
//		color:			线的颜色
// 返回值:
/* ===================================================== */
void drawNetwork(void)
{
    uint16_t y = 0;
    uint16_t x = 0;
	
    for(x = 20; x < lcddev.width; x += 20)
    {
        for(y = 20; y < (lcddev.height - 20); y += 5)
        {
            LCD_Fast_DrawPoint(x, y, 0XAAAA);
        }
    }

    for(y = 20; y < (lcddev.height - 20); y += 20)
    {
        for(x = 0 ; x < lcddev.width ; x += 5)
        {
            LCD_Fast_DrawPoint(x, y, 0xAAAA);
        }
    }

	POINT_COLOR = 0X534c;
    drawLineWithColor(0, lcddev.height / 2, lcddev.width, lcddev.height / 2, POINT_COLOR);
    drawLineWithColor(lcddev.width / 2, 20, lcddev.width / 2, (lcddev.height - 20), POINT_COLOR);
    LCD_DrawRectangle(0, 20, lcddev.width, (lcddev.height - 20)); // 矩形
}

/* ===================================================== */
// 描述:设置背景上静态的文字
// 参数:
// 返回值:
/* ===================================================== */
void setBackGroundText(void)
{
	// 待定,最后根据布局再看吧。
}

然后在主函数中调用即可看到前面的效果。

// main函数上面
#include "lcd.h"
#include "gui.h"

	// main函数中
	
	// 1. 初始化LCD
	LCD_Init();

	// 2. 初始化 LCD 背景设置
	setBackGroundColor();	// 设置背景颜色
	drawNetwork();			// 绘制背景网络
	setBackGroundText();	// 设置背景静态文字

4.2. 电压采集及绘制

这节是重点

这里设计ADC的采集方法并显示在上面的网格中。

先说思路,方便理解代码:
在这里插入图片描述
可以看到,按照这个思路,其实ADC并不是在一直连续的显示电压的变化,而是每隔一段时间截取一段,显示之后,再次截取,避免LCD的刷新速度影响。

icode文件夹中再创建一个OSC文件夹,在OSC文件夹中创建osc.cosc.h文件。并将源文件和头文件在keil中添加到工程。

这里的代码有点长,放几个关键的说一下,全部代码主页置顶文章有

初始化代码相对简单。

/* ===================================================== */
// 描述:示波器初始化
// 参数:
// 返回值:
/* ===================================================== */
void OSC_Init(void)
{
	// 初始化 示波器 背景设置
	setBackGroundColor();	// 设置背景颜色
	setBackGroundText();	// 设置背景静态文字
	
	// 1. adc校准
    HAL_ADCEx_Calibration_Start(&hadc1);
	// 2. 开启DMA传输
    HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&originalAdc, numOfCollect);
	// 3. 关掉传输一半中断
    __HAL_DMA_DISABLE_IT((&hadc1)->DMA_Handle, DMA_IT_HT);
	// 4. 设置ADC采样频率。并开始计时采样
    setAdcFrequency(numF);
    HAL_TIM_Base_Start(&htim3);
}

DMA中断代码,这段其实时关键,中间的代码有点多,又分成了几个函数。

/* ===================================================== */
// 描述:DMA传输回调函数,用于绘制获取的ADC波形并输出提示信息。
// 参数:
// 返回值:
// 注意:在绘制期间,会关闭定时器,停止触发ADC。
// 		可以看出,这里的逻辑是,
//		1. 打开定时器计时,定时器开始计数,可以触发中断;
//		2. 定时器触发中断,ADC获取连续的一段电压值;(在这里频率是可以设置的)
//		3. 关闭定时器计数,ADC停止转换;
//		4. 绘制刚刚获取的ADC波形,绘制完成之后,再次打开定时器。
// 		
//		简单来说,其实电压值并不是在连续转换。而是转换一段 停一会 再次转换一段。
/* ===================================================== */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
	// 失能定时器3
    HAL_TIM_Base_MspDeInit(&htim3);

    if(oscState == 1)
    {
        // HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);
        drawStringWithColor(240, 1, 120, "Running ", YELLOW);
		/*
			显示所有需要的内容
			1. 绘制背景网格
			2. 计算被测波形的频率;
			3. 将波形显示在屏幕上;
			4. 更新波形信息
		*/
		
		// 执行过程中 让LED亮
		HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
		
		drawNetwork();
		updateWaveFrequency();
		OSC_ShowWave();
		OSC_ShowInfo();
		
		// 刷新完成之后 灭掉LED
		HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
    }
    else
    {
        drawStringWithColor(240, 1, 120, "Stopping", RED);
    }
	
	// 使能定时器3
    HAL_TIM_Base_MspInit(&htim3);
}

中间四个函数的逻辑,就是上面流程图的逻辑,这里就不放了,可以直接去下载工程。全部代码主页置顶文章有

4.3. 主函数

在主函数中其实非常简单,初始化即可,剩下的都在 回调函数和中断中完成。

#include "lcd,h"
#include "osc,h"

// 1. 初始化LCD
LCD_Init();
// 2. 初始化示波器(核心代码)
OSC_Init();
// 3. 设置运行标志位
oscState = 1;

4.4. 测试工程(可有可无)

另找一个开发板,用定时器生成PWM波,进行测试。

我这里用另一个开发板的三个定时器,分别生成 100hz、1Khz、10Khz的PWM波。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在主函数中,打开定时器,随便设置个占空比,然后监测一下试试。

	HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
	HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
	HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
	HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);
	HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1);
	HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_2);
	
	__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, 4000);
	__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, 8000);
	
	__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 300);
	__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 500);

	__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, 20);
	__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_2, 60);

5. 使用说明及测试

把两个开发板的 GND 连起来。
把输出信号的开发板引脚,连到示波器开发板的PA1引脚。

按键功能:

  1. 长按 WK_UP 键,暂停刷新 / 重新启动;
  2. 短按 WK_UP 键,切换模式,被选中的模式会有一个方格,选中中间的偏移的话,中间的两根线会变成白色;
  3. KEY0、KEY1,在不同模式下,增加或减少。

下面信息含义:

  1. max:这个屏幕中最大的电压值;
  2. min:这个屏幕中最大的电压值;
  3. dif:这个屏幕中最大与最小电压的差;
  4. Hz:被测信号的频率。

上面信息的含义:

  1. 1V / 2V / 4V 显示的电压范围;
  2. 5ms:表示一个小方格(红色点组成的方格)对应的实际时常;
  3. [—|—]符号:波形左右偏移量。
  4. Running / Stoping:示波器状态。

LED 闪烁:亮表示正在测量及显示;灭表示已经在LCD上刷新了。

视频效果:https://www.bilibili.com/video/BV1AP411M75M/

1000HZ测试效果
在这里插入图片描述
10000HZ测试效果
在这里插入图片描述
正弦波测试效果
在这里插入图片描述
三角波测试效果
在这里插入图片描述

代码在主页置顶文章,或者点个关注点个赞,私聊我直接给你发也行。


2023年2月22日记。
刚刚调试电机PWM波,手贱想看看量12V电压会有什么情况,就碰了一下,只一瞬间。。。芯片烧了。。。
-100。
请勿尝试高电压!!!

  • 79
    点赞
  • 252
    收藏
    觉得还不错? 一键收藏
  • 33
    评论
关于是德科技: 是德科技(NYSE:KEYS)-原安捷伦电子测量事业部,是全球电子测量技术和市场的领导者,致力于推动无线通信、模块化和软件解决方案的持续创新,专注于为客户提供卓越的测量体验。是德科技提供的电子测量仪器、系统、软件及服务广泛应用于电子设备的设计、研发、制造、安装、部署和运营。 前言: 最近一直在玩STM32和LCD屏,从字符到TFT,从1.8到3.5寸,挨个都摸了个摸,公司产品出来了,可一直想用这些东东来作点什么。示波器上班用公司的,虽说也是便携的,但也不好带回家去用呵,看看市场上动辙千元以上,唉,还是自己动手来DIY方便自己,也造福网友。 性能目标: 电源使用二节2500mA锂电,正常工作5小时以上。 数字示波器参数: 主控: STM32F103ZET6 液晶屏: 3.2"TFT320×240 65K彩色LCD显示屏 STM32 FSMC总线驱动 AD: ADS831 IDT7205 最高实时取样率60Msps 8Bits, 取样缓冲器深度:5K 垂直灵敏度:5V,1V,500mV,200mV,100mV,50mV,20mV,10mV; 基准电压使用STM32 DA输出,实现按键调节波形基准。并有位置指示 水平时基范围:2S, 1S,500mS,200mS,100mS,50mS,20mS,10mS,5mS,2mS,1mS,500uS,200uS,100uS,50uS,20uS,10uS,5uS,2uS,1uS,500nS, 水平位置可调并有指示 输入阻抗:≥1MΩ 最高输入电压:50Vpp 耦合方式:AC/DC 实现自动、常规、单次触发方式 ,上升或下降边沿触发 实现计算测量输入信号的频率、周期、占空比、交流峰-峰值、平均值 触发电平高低位置可调,并电压指示 触发时基位置可调,并带指示 实现RUN/STOP功能 使用16个按键,真正作到单键操作以免去组合按键麻烦。 如截图: 功能预留: 波形发生器:使用STM32另一路DA+NE5532实现正弦,三角波,方波输出。 SD卡波形存储输出。 系统串口,可连接电脑输出数据,也可实现远程ISP升级:通过从网上下载升级包文件,方便地升级示波器软件。 注意: 具体看原理图,实现机理:在系统复位后,SYSCLK的第4个上升沿,BOOT管脚的值将被锁存。在开机时使用按键将BOOT0位拉低即可实现STM公司原ISP程序升级,而不再用提前预装IAP程序造成使用麻烦 数字示波器实物展示: 原文出处:https://www.amobbs.com/thread-3706638-1-1.html
自制USB示波器电路图需要以下元件和步骤: 元件: 1. USB接口:作为示波器与计算机之间传输数据的接口。 2. 微控制器:用于控制示波器的运行和数据传输。 3. 示波器模块:包括模拟电路和信号采集电路,用于测量和监测电压信号。 4. 模数转换器(ADC):将模拟信号转换为数字信号。 5. 存储器:用于存储采集到的数据。 6. 显示屏:显示测量结果。 步骤: 1. 连接USB接口和微控制器:将USB接口连接到微控制器的相应引脚。 2. 连接示波器模块:将示波器模块连接到微控制器的模拟输入引脚。 3. 连接ADC和微控制器:将ADC连接到微控制器的模拟输入引脚,并将ADC的数字输出引脚连接到微控制器的数字输入引脚。 4. 连接存储器和微控制器:将存储器连接到微控制器的相应引脚,用于存储采集到的数据。 5. 连接显示屏和微控制器:将显示屏连接到微控制器的相应引脚,用于显示测量结果。 6. 编写控制程序:使用相应的编程语言编写微控制器的控制程序,包括数据采集、存储和传输的逻辑。 7. 调试和测试:连接示波器电路图到计算机上,并进行相关功能和性能的调试和测试。 通过以上步骤,可以自制USB示波器电路图,实现对电压信号的测量和监测,并将数据传输到计算机进行进一步的处理和显示。这样的自制USB示波器电路图使用简便,成本较低,适用于一些简单的电子实验和工程应用。
评论 33
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值