基于STM32的简易示波器设计

news2024/11/27 14:49:52

疫情期间闲来无事,正好学习STM32F407,因此设计、制作了简易示波器,以助学习。长话短说方案如下:

(1)单片机,选择STM32F407VET6,采用SWD方式仿真及程序烧写。五路独立按键和两个LED指示灯。使用ADC1/通道5/PA5。细见附件原理图。

(2)程控放大电路,使用继电器和运放组成,实现不同放大倍数。如下:

(3)显示面板采用3.2寸TFT液晶屏。使用FSMC接口,9341驱动。

(4)串口通信,用于与上位机通信,实现虚拟示波器功能。

2、PCB设计

见下图:

3软件设计

软件大体分为四部分:

(1)软件主体框架,主要包括单片机基本软件部分、LED、按键等功能实现

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
    delay_init(168);      //初始化延时函数
    LED_Init();                   //初始化LED
    i=LCD_Init();           //初始化LCD FSMC接口
    /*<24C02初始化>*/
    AT24CXX_Init(); 
    delay_ms(1);
    i=5;
    while(i--)
    {
        n8tmp=AT24CXX_Check();
        if(n8tmp==0) 
        {
            break;
        }
        delay_ms(1);
    }
    Adc_Init();         //初始化ADC

    /*<定时器初始化>*/
    TIM5_Int_Init(4-1,21-1);// 0.001ms
    UART2_Init(115200);//   
    // DMA1_Config(DMA1_Stream4,DMA_Channel_4,(u32)&UART4->DR,(u32)BUF4,SENTDATA_LEN2);//串口4DMA发送初始化
    DMA1_Config(DMA1_Stream6,DMA_Channel_4,(u32)&USART2->DR,(u32)BUF2,SENTDATA_LEN2);//串口2DMA发送初始化

(2)程控电路,通过按键控制继电器实现放大倍数变化

        处理部分

if(KEY1==0||KEY2==0||KEY3==0||KEY4==0||KEY5==0)
        {
            BEEP=1;
            delay_ms(10);
            if(KeyDown==0)
            {
            Key_Got=1;
            if(KEY1==0) 
            {KEY_NUM=1;
            stimeradd();
            KeyDown=1;
            }
            else if(KEY2==0) 
            {KEY_NUM=2;
            KeyDown=1;
            stimersub();
            }
            else if(KEY3==0) 
            {KEY_NUM=3;
            OKpchage(1);
            KeyDown=1;
            }
            else if(KEY4==0) {
                KEY_NUM=4;
                OKpchage(0);
                KeyDown=1;
            }
            else if(KEY5==0) 
            {KEY_NUM=5;
                spmark=!spmark;
                KeyDown=1;
            }
            else KEY_NUM=0;
            }

        }
        else
        {
            KeyDown=0;
        }

程控函数:

float Kbc=1;//1.538F;
void OKpchage(u8 ca)
{
    static u8 nKv=7;
    if(ca)
    {
        // 增加每格电压
        if(nKv<7)nKv++;
    }
    else
    {
        if(nKv>0)nKv--;
        // 减小每格电压
    }
    if(nKv>7)nKv=7;
    // 放大倍数控制
    if(nKv<3)
    {
        if(nKv==0)
        {
            Kpsh=500*Kbc;
        }
        else if(nKv==1)
        {
            Kpsh=250*Kbc;
        }
        else if(nKv==2)
        {
            Kpsh=50*Kbc;
        }
        rK2=1;
        rK3=0; 
    }
    else if(nKv<4)
    {
        Kpsh=25*Kbc;
        rK2=1;
        rK3=1; 
    }
    else if(nKv<6)
    {
        if(nKv==4)
        {
            Kpsh=12.5F*Kbc;
        }
        else if(nKv==5)
        {
            Kpsh=5*Kbc;
        }
        rK2=0;
        rK3=0; 
    }
    else
    {
        if(nKv==6)
        {
            Kpsh=2.5F*Kbc;
        }
        else if(nKv==7)
        {
            Kpsh=1.25F*Kbc;
        }
        rK2=0;
        rK3=1; 
    }
    nSVinx=nKv;
}

(3)采样控制,控制ADC采样时间,实现不同频率采样

u16 nARR[7]=       {10000   ,5000   ,1000   ,500    ,100    ,10     ,8};
u16 nPSC[7]=       {840     ,840    ,84     ,84     ,84     ,84     ,21};
void stimeradd()
{
    if(ideTimr<7) ideTimr++;
    if(ideTimr<7)
    TIM5_Int_Init(nARR[ideTimr]-1,nPSC[ideTimr]-1);// 0.001ms
    else
    {
        ideTimr=6;
        micTTT=1;
    }
}
void stimersub()
{
    if(ideTimr>0) ideTimr--;
    if(ideTimr<7)
    {
        micTTT=0;
       TIM5_Int_Init(nARR[ideTimr]-1,nPSC[ideTimr]-1);
    }
    
}

(4)LCD驱动、绘图与文字显示软件

void SCU_Refresh()
{
    static u8 ntmp1=0;
    static int tempstart = 0;
    static int tempend = 0;
    static int wavenum = 4;
    static int jumpwave = 5;
    static int nT = 2;
    
    char * P_Char=&gstrltemp[0];
    int i,j,k,l;
    
    u16 x,y;
    switch (SCUtype)
    {
   
    case MainScu2://Home 示波器界面
        {
            //底图
            gDrawRectangle(WHITE,5,5,300,200,1);
            // 仿真曲线
            for(x=0;x<300;x++)
            {
                line1[x]=(u8)(50*sin(0.1*x+ntmp1)+100);
            }
            ntmp1+=2;
            // 测量曲线
            // AdcBuf
            fMax=-80;
            fMin=80;
            for(x=0;x<300;x++)
            {
                ftmp2[x]=(AdcBuf[x]-2048)*Ka2V*Kbcbf[nSVinx]*Kopf[nSVinx]*2;
                if(fMax<ftmp2[x])fMax=ftmp2[x];
                if(fMin>ftmp2[x])fMin=ftmp2[x];
                ftmp=ftmp2[x]*Kpsh;
                if(ftmp>=98.00F)ftmp=98.0F;
                else if(ftmp<=-98.00F)ftmp=-98.0F;
                
                line1[x]=(u8)(ftmp+100+5);//0.04885197850512945774303859306302
                 if(micTTT)  line1_f[x]= line1[x];
            }
            if(micTTT)
            {
                // memcpy(line1_,line1,300);    
                for(x=0;x<60;x++)
                {
                    line1[x*5]=line1_f[x];
                    line1[x*5+1]=line1_f[x]+(u8)((line1_f[x+1]-line1_f[x])*0.2F);
                    line1[x*5+2]=line1_f[x]+(u8)((line1_f[x+1]-line1_f[x])*0.4F);
                    line1[x*5+3]=line1_f[x]+(u8)((line1_f[x+1]-line1_f[x])*0.6F);
                    line1[x*5+4]=line1_f[x]+(u8)((line1_f[x+1]-line1_f[x])*0.7F);
                }
            }
            fVpp=(fMax-fMin);//Kopf[nSVinx]*
            fAveV=(fMax+fMin)*0.5F;
            // 频率计算
            for(i=0;i<300;i++)
            {
                ftmp2[i]=ftmp2[i]-fAveV;
            }
            j=0;
            tempend =tempstart=0;
            for(i=0;i<299;i++)
            {
                if((ftmp2[i]<=0)&&(ftmp2[i+1]>=0)||(ftmp2[i]>=0)&&(ftmp2[i+1]<=0))
                {
                    if (j == 0) tempstart = i;
                    else if (j == 1)
                    {
                        k = i - tempstart;
                        if (k > 150) break;
                        wavenum = 150 / k;
                        if (wavenum % 2 == 1) wavenum += 1;
                        if (k < 10)
                        {
                            tempend = 0;
                            break;
                        }
                        if (k < 20) jumpwave = k / 4;
                    }
                    j = j + 1;
                    if (j > wavenum)
                    {
                        tempend = i;
                        break;
                    }
                    i = i + jumpwave;
                }
            }
            if (tempend - tempstart > 0)
            {
                CYcyc=cycyc[ideTimr];
                cycle = ((tempend - tempstart) * CYcyc) * 2 / wavenum;//um  一共wavenum/2 个周期
                freq = 1 / cycle;
               
            }
            else
            {
                cycle = -1;
                freq = -1;
            }
            if(lineMod)
            {
                for(i=1;i<299;i++)
                {
                     Gui_DrawLine(i+5,line1o[i],i+6,line1o[i+1]+3,BLACK);
                }
                memcpy(line1o,line1,300);   
                //绘制曲线 
                for(i=1;i<299;i++)
                {
                    Gui_DrawLine(i+5,line1o[i],i+6,line1o[i+1]+3,GREEN);
                }                
            }
            else
            {
                for(i=1;i<299;i++)
                {
                    LCD_Fast_DrawPoint(i+5,line1o[i]+6,BLACK);
                    // y=
                    // gDrawLine
                }
                memcpy(line1o,line1,300);   
                //绘制曲线 
                for(i=1;i<299;i++)
                {
                    LCD_Fast_DrawPoint(i+5,line1[i]+6,GREEN);
                    // y=
                    // gDrawLine
                }
            }
            gDrawLeVeLine(DGRAY,155,5,155,205,1);
            gDrawLeVeLine(DGRAY,5,103,305,103,1);
            for(i=0;i<4;i++)
            {
                for(j=0;j<6;j++)
                {
                    if(i<2)
                    {
                        x=155-(i+1)*50; 
                        if(j<3)
                        {
                            y=105-(j+1)*25; 
                        }
                        else
                        {
                            y=105+(j-2)*25; 
                        }
                    }
                    else
                    {
                        x=155+(i-1)*50; 
                        if(j<3)
                        {
                            y=105-(j+1)*25; 
                        }
                        else
                        {
                            y=105+(j-2)*25; 
                        }
                    }
                    LCD_Fast_DrawPoint(x,y,LGRAY);
                }
            }
            if(micTTT)
            gDrawString(BLUE,0,0,210,40,16,16," 20us");
            else
            gDrawString(BLUE,0,0,210,40,16,16,strts[ideTimr]);
            // strV u8 nSVinx=0;
            gDrawString(MAGENTA,0,45,210,40,16,16,strV[nSVinx]);
            gDrawString(LGRAY,0,95,210,24,12,12,"Vpp:");
            sprintf(P_Char,"% 6.2fV",fVpp);
            gDrawString(BLUE,0,120,210,56,16,16,P_Char);
            if(freq<0.0001F)
            {
                gDrawString(MAGENTA,0,180,210,64,16,16," ---.-Hz");
                gDrawString(BLUE,0,245,210,64,16,16," ---.-ms");
            }
            else if(freq<1000)
            {
                sprintf(P_Char,"% 6.2fHz",freq);
                gDrawString(MAGENTA,0,180,210,64,16,16,P_Char);
                sprintf(P_Char,"% 6.1fms",1000/freq);
                gDrawString(BLUE,0,245,210,72,16,16,P_Char);
            }
            else
            {
                freq=freq*0.001F;
                sprintf(P_Char,"% 6.2fKHz",freq);
                gDrawString(MAGENTA,0,180,210,64,16,16,P_Char);
                 sprintf(P_Char,"% 6.0fus",1000/freq);
                gDrawString(BLUE,0,245,210,72,16,16,P_Char);
            }
        }
        break;
   
    default:
        SCUtype=MainScu;
        break;
    }
}

4、电压测量及组合表

AD输入电压范围 ±1.65V

检测电压范围   ±66V

硬件放大倍数       0.5                0.25           0.05            0.025

继电器控制组合     rk2=1,rk3=0;       rk2=1,rk3=1;   rk2=0,rk3=0;    rk2=0,rk3=1;

硬件放大倍数档位   0.5                0.25           0.05            0.025

显示范围          200mv 400mv  2V     4V        8V    20V       40V   80V

测量范围          ±3.3                ±6.6          ±33             ±66

每格电压          50mv  100mv  500mv  1V       2V    5V        10V   20V

表显1V电压点数     500   250    50     25       12.5   5         2.5   1.25

显示倍数Kps:     

  0.5V   1V   2V     10V    40V  //每小格电压 每小格25个像素点 上下各4格

附录:

     1、原理图与PCB:

https://download.csdn.net/download/w267309080/88292915?spm=1001.2014.3001.5501

    2、程序源代码

(待更新)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/968769.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[国产MCU]-W801开发实例-用户报文协议(UDP)数据接收和发送

用户报文协议(UDP)数据接收和发送 文章目录 用户报文协议(UDP)数据接收和发送1、UDP简单介绍2、W801的UDP创建逻辑2.1 UDP使用步骤2.2 代码实现1、UDP简单介绍 用户数据报协议 (UDP) 是一种跨互联网使用的通信协议,用于对时间敏感的传输,例如视频播放或 DNS查找。它通过在数…

OTFS-ISAC通信最新进展

测试场景 Tx DD域帧结构导频区域 Rx DD域帧导频区域 原始星座图 信道估计及数据检测 经过MP算法后的星座图 误码率曲线

串行协议——USB驱动[基础]

多年前的学习记录&#xff0c;整理整理。 一、USB协议基础 二、Linux内核USB驱动源码分析 USB中不同类型设备使用的 设备描述符(设备类\设备子类\设备协议) 配置不同,典型的以下几种:1)HID设备: Human Input Device人工输入设备, 如鼠标\键盘\游戏手柄等.2)CDC设备: Communi…

GB28181学习(二)——注册与注销

概念 使用REGISTER方法进行注册和注销&#xff1b;注册和注销应进行认证&#xff0c;认证方式应支持数字摘要认证方式&#xff0c;高安全级别的宜支持数字证书认证&#xff1b;注册成后&#xff0c;SIP代理在注册过期时间到来之前&#xff0c;应向注册服务器进行刷新注册&…

core dump管理在linux中的前世今生

目录 一、什么是core dump&#xff1f; 二、coredump是怎么来的&#xff1f; 三、怎么限制coredump文件的产生&#xff1f; ulimit 半永久限制 永久限制 四、从源码分析如何对coredump文件的名字和路径管理 命名 管理 一些问题的答案 1、为什么新的ubuntu不能产生c…

ApplicationRunner、InitializingBean、@PostConstruct 执行顺序

概述 开发中可能会有这样的场景&#xff0c;需要在容器启动的时候执行一些内容。比如读取配置文件&#xff0c;数据库连接之类的。SpringBoot给我们提供了两个接口来帮助我们实现这种需求。两个启动加载接口分别是&#xff1a;CommandLineRunner和ApplicationRunner。Spring 提…

【高阶数据结构】红黑树 {概念及性质;红黑树节点的定义;红黑树插入操作详细解释;红黑树的验证}

红黑树 一、红黑树的概念 红黑树&#xff08;Red Black Tree&#xff09; 是一种自平衡二叉查找树&#xff0c;在每个结点上增加一个存储位表示结点的颜色&#xff0c;可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制&#xff0c;红黑树确保没有…

【多线程案例】生产者消费者模型(堵塞队列)

文章目录 1. 什么是堵塞队列&#xff1f;2. 堵塞队列的方法3. 生产者消费者模型4. 自己实现堵塞队列 1. 什么是堵塞队列&#xff1f; 堵塞队列也是队列&#xff0c;故遵循先进先出的原则。但堵塞队列是一种线程安全的数据结构&#xff0c;可以避免线程安全问题&#xff0c;当队…

数学建模--时间序列预测模型的七种经典算法的Python实现

目录 1.开篇版权提示 2.时间序列介绍 3.项目数据处理 4.项目数据划分可视化 5.时间预测序列经典算法1&#xff1a;朴素法 6.时间预测序列经典算法2&#xff1a; 简单平均法 7.时间预测序列经典算法3&#xff1a;移动平均法 8.时间预测序列经典算法4&#xff1a;简单指…

pytest自动化测试两种执行环境切换的解决方案

目录 一、痛点分析 方法一&#xff1a;Hook方法pytest_addoption注册命令行参数 1、Hook方法注解 2、使用方法 方法二&#xff1a;使用插件pytest-base-url进行命令行传参 一、痛点分析 在实际企业的项目中&#xff0c;自动化测试的代码往往需要在不同的环境中进行切换&am…

windows-nessus安装

1、下载 路径&#xff1a;Download Tenable Nessus | Tenable 2、获取active code 路径&#xff1a;Tenable Nessus Essentials Vulnerability Scanner | Tenable 3、安装 challenge code:上图马赛克位置 active code:获取active code第二张图片的马赛克位置 4、激活 5、安装…

Docker从认识到实践再到底层原理(三)|Docker在Centos7环境下的安装和配置

前言 那么这里博主先安利一些干货满满的专栏了&#xff01; 首先是博主的高质量博客的汇总&#xff0c;这个专栏里面的博客&#xff0c;都是博主最最用心写的一部分&#xff0c;干货满满&#xff0c;希望对大家有帮助。 高质量博客汇总 然后就是博主最近最花时间的一个专栏…

企业架构LNMP学习笔记10

1、Nginx版本&#xff0c;在实际的业务场景中&#xff0c;需要使用软件新版本的功能、特性。就需要对原有软件进行升级或重装系统。 Nginx的版本需要升级迭代。那么如何进行升级呢&#xff1f;线上服务器如何升级&#xff0c;我们选择稳定版本。 从nginx的1.14版本升级到ngin…

【数据库】MySQL基础知识全解

系列综述&#xff1a; &#x1f49e;目的&#xff1a;本系列是个人整理为了秋招面试的&#xff0c;整理期间苛求每个知识点&#xff0c;平衡理解简易度与深入程度。 &#x1f970;来源&#xff1a;材料主要源于拓跋阿秀、小林coding等大佬博客进行的&#xff0c;每个知识点的修…

计算机的存储规则(ASCII,GBK,Unicode)

不爱生姜不吃醋⭐️⭐️⭐️ 声明&#xff1a; &#x1f33b;本文写的是关于计算机的存储规则 ❗️ &#x1f33b;看完之后觉得不错的话麻烦动动小手点个赞赞吧&#x1f44d; &#x1f33b;如果本文有什么错误的话欢迎在评论区中指正哦&#x1f497; &#x1f33b;与其明天开始…

count(1)与count(*)的区别、ROUND函数

部分问题 1. count(1)与count(*)的区别2. ROUND函数3. SQL19 分组过滤练习题4. Mysql bigdecimal 与 float的区别5. 隐式内连接与显示内连接 &#xff08;INNER可省略&#xff09; 1. count(1)与count(*)的区别 COUNT(*)和COUNT(1)有什么区别&#xff1f; count(*)包括了所有…

【网络】路由配置实践1

网络实践-路由篇 本文使用vmware虚拟机进行路由表配置实践&#xff0c;通过配置路由表连接两个不同的网络&#xff0c;不涉及路由协议&#xff0c;全手动配置&#xff0c;旨在理解路由表的概念 网络规划&#xff1a; 准备三台centos7虚拟机&#xff0c;其中一台作为路由设备ro…

【个人博客系统网站】注册与登录 · 加盐加密验密算法 · 上传头像

【JavaEE】进阶 个人博客系统&#xff08;3&#xff09; 文章目录 【JavaEE】进阶 个人博客系统&#xff08;3&#xff09;1. 加盐加密验密算法原理1.1 md5加密1.2 md5验密1.3 md5缺漏1.4 加盐加密1.5 后端的盐值拼接约定1.6 代码实现1.6.1 加密1.6.2 验密1.6.3 测试 2. 博客…

探究IP路由的工作原理与路由表查找规则

文章目录 一、定义二、IP连通的前提三、路由表1. 作用2. 路由表字段内容3. 路由表查表规则4. 路由信息的来源5. 路由表写表规则6. 路由优先级 四、常用命令 首先可以看下思维导图&#xff0c;以便更好的理解接下来的内容。 一、定义 路由器是网络中负责将数据报文在不同IP网段…

css 左右宽固定,中间自适应——双飞翼布局

最近面试的时候遇到一个提问说&#xff0c;如何做到一个左右宽度固定&#xff0c;中间自适应的布局&#xff0c;我的答案不重要&#xff0c;重要的是不是面试官想听到的答案&#xff0c;这样问大概率他想听到的答案一定是双飞翼布局&#xff0c;所以今天就手敲一个双飞翼布局让…