当前位置:网站首页>基于STM32的简易示波器项目(含代码)——HAL库
基于STM32的简易示波器项目(含代码)——HAL库
2022-08-08 10:19:00 【混分巨兽龙某某】
前言:本文基于STM32的简易示波器项目,示波器作为嵌入式开发中必不可少的器件,其使用方式和工作原理是必须被掌握的。巧妙利用STM32可以实现媲美度非常高的示波器,本文中的简易示波器主要是为了简单实现了示波器的功能,主要利用了ADC+DMA去快速读取并显示波形。(文末有项目代码开源)
实验硬件:STM32F103C8T6;0.96寸OLED
硬件实物图:
效果图:
引脚连接:
OLED模块:
VCC --> 3.3V
GND --> GND
SCL --> PB6
SDA --> PB7
方波模块(PWM):
PA0 --> PA3
一、示波器简介
示波器是一种用途十分广泛的电子测量仪器。它能把肉眼看不见的电信号变换成看得见的图像,便于人们研究各种电现象的变化过程。在被测信号的作用下,电子束就好像一支笔的笔尖,可以在屏面上描绘出被测信号的瞬时值的变化曲线。利用示波器能观察各种不同信号幅度随时间变化的波形曲线,还可以用它测试各种不同的电量,如电压、电流、频率、相位差、调幅度等等。
按照信号的不同分类
模拟示波器采用的是模拟电路(示波管,其基础是电子枪)电子枪向屏幕发射电子,发射的电子经聚焦形成电子束,并打到屏幕上。屏幕的内表面涂有荧光物质,这样电子束打中的点就会发出光来。
数字示波器则是数据采集,A/D转换,软件编程等一系列的技术制造出来的高性能示波器。数字示波器的工作方式是通过模拟转换器(ADC)把被测电压转换为数字信息。数字示波器捕获的是波形的一系列样值,并对样值进行存储,存储限度是判断累计的样值是否能描绘出波形为止,随后,数字示波器重构波形。数字示波器可以分为数字存储示波器(DSO),数字荧光示波器(DPO)和采样示波器。
本文中实现的简易示波器可以归结为数字示波器,是利用STM32的ADC+DMA去去快速读取数据,并且在OLED上显示出对应波形。本项目采用的是STM32F103C8T6,其性能非常一般。如果使用较高性能的STM32单片机,可以复现出功能非常完善的示波器。
硬件实物:
二、功能模块
2.1、ADC模块
模拟数字转换器即A/D转换器,或简称ADC,通常是指一个将模拟信号转变为数字信号的电子元件。STM32 的 ADC 是 12 位逐次逼近型的模拟数字转换器。它有 18 个通道,可测量 16 个外部和 2 个内部信号源。各通道的 A/D 转换可以单次、连续、扫描或间断模式执行。ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中。 模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。
STM32F103 系列最少都拥有 2 个 ADC,我们的C8T6刚好是2个ADC,STM32 的 ADC 最大的转换速率为 1Mhz,也就是转换时间为 1us。(搭配DMA模块,可以进行超快的数据读取与传输)
STM32 将 ADC 的转换分为 2 个通道组:规则通道组和注入通道组。规则通道相当于你正常运行的程序,而注入通道呢,就相当于中断。在你程序正常执行的时候,中断是可以打断你的执行的。同这个类似,注入通道的转换可以打断规则通道的转换, 在注入通道被转换完成之后,规则通道才得以继续转换。
简述:STM32的ADC就是将阈值内的电压映射至4096(12位的ADC),然后通过映射值再转换成电压数值。这里笔者准备使用ADC+DMA去快速读取和传输数据,尽可能于OLED屏幕上去显示出波形。
2.2、DMA模块
DMA,全称为:Direct Memory Access,即直接存储器访问,DMA 传输将数据从一个地址空间复制到另外一个地址空间。DMA 传输对于高效能嵌入式系统算法和网络是很重要的。DMA 传输方式无需 CPU 直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为 RAM 与 I/O 设备开辟一条直接传送数据的通路,能使 CPU 的效率大为提高。
STM32 最多有 2 个 DMA 控制器(DMA2 仅存在大容量产品中),DMA1 有 7 个通道。DMA2 有 5个通道。每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁起来协调各个 DMA 请求的优先权。
STM32 的 DMA 有以下一些特性:
●每个通道都直接连接专用的硬件 DMA 请求,每个通道都同样支持软件触发。这些功能
通过软件来配置。
●在七个请求间的优先权可以通过软件编程设置(共有四级:很高、高、中等和低),假如
在相等优先权时由硬件决定(请求 0 优先于请求 1,依此类推) 。●独立的源和目标数据区的传输宽度(字节、半字、全字),模拟打包和拆包的过程。源和目标地址必须按数据传输宽度对齐。
●支持循环的缓冲器管理
●每个通道都有3个事件标志(DMA 半传输,DMA 传输完成和 DMA 传输出错),这3个事件标志逻辑或成为一个单独的中断请求。
●存储器和存储器间的传输
●外设和存储器,存储器和外设的传输
●闪存、SRAM、外设的 SRAM、APB1 APB2 和 AHB 外设均可作为访问的源和目标。
●可编程的数据传输数目:最大为 65536
2.3、方波模块
示波器主要的作用之一就是显示波形,其实,利用STM32单片机可以输出方波,正弦波,余弦波,三角波,锯齿波等等特殊波形。(使用DAC模块)由于笔者本次使用的是STM32F103C8T6的MCU,不存在DAC模块,所以这里笔者给大家使用定时器的PWM调节去输出一个方波,并在OLED屏幕上进行显示。
PWM波形:
2.4、OLED模块
关于OLED的使用与原理不熟悉的笔者欢迎去笔者另一篇文章学习。【强烈推荐】基于stm32的OLED各种显示实现(含动态图)_混分巨兽龙某某的博客-CSDN博客_oled显示stm32https://blog.csdn.net/black_sneak/article/details/125418537?spm=1001.2014.3001.5501
三、CubexMX配置
1、RCC配置外部高速晶振(精度更高)——HSE;
2、SYS配置:Debug设置成Serial Wire(否则可能导致芯片自锁);
3.1、ADC1配置:选取ADC1的通道0(IN0)
3.2、ADC1+DMA配置:配置其DMA的选项
4、TIM2配置:配置通道4为PWM调节(作为输出方波)
5、I2C2配置:作为OLED的通讯方式;
6、时钟树配置:
7、工程配置
四、代码
4.1 OLED显示的基础代码
OLED.C代码:
代码可以直接使用本人另一篇文章的代码。
4.2 示波器显示效果API函数
简单描述就是将数据点进行连线操作。
void Before_State_Update(uint8_t y)//根据y的值,求出前一个数据的有关参数
{
Bef[0]=7-y/8;
Bef[1]=7-y%8;
Bef[2]=1<<Bef[1];
}
void Current_State_Update(uint8_t y)//根据Y值,求出当前数据的有关参数
{
Cur[0]=7-y/8;//数据写在第几页
Cur[1]=7-y%8;//0x01要移动的位数
Cur[2]=1<<Cur[1];//要写什么数据
}
void OLED_SetPos2(unsigned char x, unsigned char y) //设置起始点坐标
{
WriteCmd(0xb0+x);
WriteCmd((y&0x0f)|0x00);//LOW
WriteCmd(((y&0xf0)>>4)|0x10);//HIGHT
}
void OLED_DrawWave(uint8_t x,uint8_t y)
{
int8_t page_sub;
uint8_t page_buff,i,j;
Current_State_Update(y);//根据Y值,求出当前数据的有关参数
page_sub=Bef[0]-Cur[0];//当前值与前一个值的页数相比较
//确定当前列,每一页应该写什么数据
if(page_sub>0)
{
page_buff=Bef[0];
OLED_SetPos2(page_buff,x);
WriteDat(Bef[2]-0x01);
page_buff--;
for(i=0;i<page_sub-1;i++)
{
OLED_SetPos2(page_buff,x);
WriteDat(0xff);
page_buff--;
}
OLED_SetPos2(page_buff,x);
WriteDat(0xff<<Cur[1]);
}
else if(page_sub==0)
{
if(Cur[1]==Bef[1])
{
OLED_SetPos2(Cur[0],x);
WriteDat(Cur[2]);
}
else if(Cur[1]>Bef[1])
{
OLED_SetPos2(Cur[0],x);
WriteDat((Cur[2]-Bef[2])|Cur[2]);
}
else if(Cur[1]<Bef[1])
{
OLED_SetPos2(Cur[0],x);
WriteDat(Bef[2]-Cur[2]);
}
}
else if(page_sub<0)
{
page_buff=Cur[0];
OLED_SetPos2(page_buff,x);
WriteDat((Cur[2]<<1)-0x01);
page_buff--;
for(i=0;i<0-page_sub-1;i++)
{
OLED_SetPos2(page_buff,x);
WriteDat(0xff);
page_buff--;
}
OLED_SetPos2(page_buff,x);
WriteDat(0xff<<(Bef[1]+1));
}
Before_State_Update(y);
//把下一列,每一页的数据清除掉
for(i=0;i<8;i++)
{
OLED_SetPos2(i, x+1) ;
for(j=0;j<1;j++)
WriteDat(0x00);
}
}
4.3 PWM调制的方波
利用PWM去产生方波,这里50%宽的方波。
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_4); //开启PwM调节(TIM2CHANNEL_4)
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_4,500); //PWM方波的占空比50%
4.4 main函数部分
主要是去将ADC1读取的数据点进行连线操作,利用DMA传输可以更快的在OLED上去显示,提高整体速度。(包含数据的缩放因子)
#define accur 0.015295 //18*3.3/4096 (3.3/4096就是ADc采样精度,1:是为了让波形转化一下能够显示在适当位子)
uint16_t ConvData;
HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&ConvData,1); //ADC+DMA的读取
//while函数中
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
for(x=0;x<128;x=(x+1)%128)//若测高频,改为x=(x+8)号128,注意由于没进行信号发生器验证可能出现bug
{
HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&ConvData,1);
float count=accur*ConvData;
OLED_DrawWave(x,count);
}
}
五、实验效果
简易示波器
六、总结
本项目为简易的示波器实现(乞丐版),后续如果有空,笔者可能会在性能较优的STM32板子上做一个功能非常完善的示波器项目,感兴趣的读者朋友可以关注一下。本项目中因为OLED尺寸有限,没有去读取电压等数据(可以使用ADC的HAL库函数去读取,问题不大),但是整体代码框架是比较简明清楚的,欢迎读者朋友在此基础上补全功能,或是提出不足!
代码开源
链接:https://pan.baidu.com/s/1BNcL7BqHYhGzV_OQsH4wqQ 提取码:rciu
边栏推荐
- A concise tutorial on expanding (increasing capacity) of VMWare Esxi virtual system data storage
- String equals hashcode
- 【AGC】开放式测试示例
- 以技术御风险,护航云原生 | 同创永益 X 博云举办产品联合发布会
- 面试突击72:输入URL之后会执行什么流程?
- 快速定位线上慢 SQL 问题,掌握这几个性能排查工具可助你一臂之力
- 带你深入理解3.4.2的版本更新,对用户带来了什么?
- 新款“廉价”SUV曝光,安全、舒适一个不落
- 高并发下秒杀商品,你必须知道的9个细节
- 键值数据库是将什么作为标识符的呢?
猜你喜欢
随机推荐
嵌入式C编程中错误异常该如何统一处理?
SVN基本操作--文字解析版
电视机画质问题--PQ问题
MySQL源码解析之执行计划
2万字50张图玩转Flink面试体系
典型的图数据库有哪些呀?
Code implementation of various kinds of attention
VMWare Esxi 虚拟系统数据存储扩容(增加容量)的简明教程
In ASP.NET Core 2.0, solve the configuration problem of large file upload
有哪些典型的列存储数据库呢?
Leetcode 105. 从前序与中序遍历序列构造二叉树
新款“廉价”SUV曝光,安全、舒适一个不落
Machine learning model too slow?Look at Intel (R) extension to accelerate
vs2019+boost库(boost_1_67_0)安装
Bytes and Characters and Common Encodings
文档数据库中的文档可以有相同的数据结构嘛?
图像分割 总结
A small test of basic grammar, Go lang1.18 introductory refining tutorial, from Bai Ding to Hongru, basic grammar of go lang and the use of variables EP02
使用文档数据库的目的是什么呢?
LeetCode每日一题--有序队列(整理最小表示法)