【单片机开发】STM32简易示波器开发

本文介绍了自制简易示波器的设计与实现过程。针对原有版本存在的问题,如ADC数据处理方式、最高采样率限制等,提出了改进措施。采用DMA模式提高采样率,并通过DSP库计算信号频率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(一)前言

还记得之前因为个人需要,又不太想花钱买示波器,实现了一个简易的示波器。
在这里插入图片描述
这个示波器非常明显存在以下几个非常尴尬的问题:
1.对于ADC数据的处理方式还是基于查询模式
2.最高采样率无法控制,而且最高采样率可能都不会超过10K
3.供电方式有点尴尬,非常不方便
4.无法提供基本信息,包括峰峰值,以及信号频率

在这里插入图片描述

基于这些问题我想到了以下的改进方案
1.ADC采集基于定时器触发模式,可以实现采样频率的设置
2.ADC数据传输模式改成DMA模式,可以进一步提高采样率
3.改成小电池供电
4加入DSP库实现 256点的DSP运算,计算出信号频率

(二)硬件介绍

(1)MCU

因为需要实现DSP,需要大量的数据空间,所以我将之前的C8T6改成了RCT6,两者在封装以及部件上没有什么明显的区别,只是FLASH从64K升级成256K,RAM从20K变成了48K,这样就有了更多的操作空间。

在这里插入图片描述

(2)TFT显示屏

再网上买的核心板存在一个直插的OLED接口,也可以作为TFT接口。

在这里插入图片描述

(3)按键接口

在这里插入图片描述

(三)驱动编程

(1)ADC驱动

在这里插入图片描述

因为只有ADC1可以使用DMA所以我们将PA0,PA1映射到ADC1 CH0和ADC CH1

为了将ADC的采样率我们需要将ADC设置为TIM溢出触发,我们将TIM3作为触发。同时将PCLK2 6分频,可以得到12M的ADCCLK。

转换时间计算,我们设置转换周期ADC_SampleTime_1Cycles5
可以计算最短转换时间为(1.5+12.5)/12M=1.17us
0.85M采样率左右
当然实际肯定是达不到的。

ADC.h

#ifndef ADC_H
#define ADC_H

#include "sys.h"
#define ADC_CHANNEL_NUMS 		2
#define SAMPLS_NUM        	1024

#define TIM3_DEFAULT 9
#define TIM2_PERIOD  999

extern u16 ADC_SourceData[SAMPLS_NUM][ADC_CHANNEL_NUMS];

//ADCCLK=12M
void Adc_Init(void);
void ADC_SetFreq(u32 FREQ);
u32 ADC_GetFREQ(void);
#endif

ADC.c


#include "sys.h"
#include "usart.h"
#include "ADC.h"

u16 ADC_SourceData[SAMPLS_NUM][ADC_CHANNEL_NUMS] = {0};
u32 ADC_FREQ=100000;

void ADC_GPIO_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);		
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
}

void ADC_TIM2_GPIO_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
}

void ADC_TIM2_Configuration(void)
{ 
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure;
	ADC_TIM2_GPIO_Configuration();
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	TIM_DeInit(TIM2);
	TIM_TimeBaseStructure.TIM_Period = TIM2_PERIOD - 1;
	TIM_TimeBaseStructure.TIM_Prescaler = 71;		
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInit(TIM2, & TIM_TimeBaseStructure);
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;	
	TIM_OCInitStructure.TIM_Pulse = (TIM2_PERIOD - 1) / 2;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;		
	TIM_OC3Init(TIM2, & TIM_OCInitStructure);
}

void ADC_TIM3_Configuration(u16 TIM3_PERIOD)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; 
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	TIM_TimeBaseInitStructure.TIM_Period = TIM3_PERIOD - 1;
	TIM_TimeBaseInitStructure.TIM_Prescaler = 71;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;			
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;		
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
	TIM_SelectOutputTrigger(TIM3, TIM_TRGOSource_Update);			
	TIM_Cmd(TIM3,ENABLE);									
}

void ADC_DMA_NVIC_Configuration(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel	= DMA1_Channel1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority		 = 1;
	NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	DMA_ClearITPendingBit(DMA1_IT_TC1);
	DMA_ITConfig(DMA1_Channel1,DMA1_IT_TC1,ENABLE);
}

void ADC_DMA_Configuration(void)
{
	DMA_InitTypeDef  DMA_InitStructure;
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
	DMA_DeInit(DMA1_Channel1);
	DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&ADC1->DR;
	DMA_InitStructure.DMA_MemoryBaseAddr     = (u32)ADC_SourceData;
	DMA_InitStructure.DMA_DIR                = DMA_DIR_PeripheralSRC;
	DMA_InitStructure.DMA_BufferSize         = ADC_CHANNEL_NUMS*SAMPLS_NUM;
	DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
	DMA_InitStructure.DMA_MemoryDataSize     = DMA_MemoryDataSize_HalfWord;
	DMA_InitStructure.DMA_Mode               = DMA_Mode_Circular;
	DMA_InitStructure.DMA_Priority           = DMA_Priority_High;
	DMA_InitStructure.DMA_M2M                = DMA_M2M_Disable;
	DMA_Init(DMA1_Channel1, &DMA_InitStructure);
	DMA_Cmd(DMA1_Channel1, ENABLE);	
	ADC_DMA_NVIC_Configuration();
}
//ADCCLK=12M
//ADC_SampleTime_28Cycles5 ת»»ÖÜÆÚ28.5+12.5=41¸öÖÜÆÚ
//ADC_SampleTime_1Cycles5  ת»»ÖÜÆÚ1 .5+12.5=14¸öÖÜÆÚ
//×î¶Ìת»»Ê±¼ä£º 14/12=1.17us
//²ÉÑùÂÊ×î¸ß0.85M
void ADC_Init_Configuration(void)
{
	ADC_InitTypeDef  ADC_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);//AFCCLK:72/6=12MHz
	ADC_DeInit(ADC1);
	ADC_InitStructure.ADC_Mode               = ADC_Mode_Independent;
	ADC_InitStructure.ADC_ScanConvMode       = ENABLE;
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
	ADC_InitStructure.ADC_ExternalTrigConv   = ADC_ExternalTrigConv_T3_TRGO;
	ADC_InitStructure.ADC_DataAlign          = ADC_DataAlign_Right;
	ADC_InitStructure.ADC_NbrOfChannel       = ADC_CHANNEL_NUMS;
	ADC_Init(ADC1, &ADC_InitStructure);
	ADC_RegularChannelConfig(ADC1, ADC_Channel_0,  1, ADC_SampleTime_1Cycles5);	//AI_VS_A1
	ADC_RegularChannelConfig(ADC1, ADC_Channel_1,  2, ADC_SampleTime_1Cycles5);	//AI_VS_B1

	ADC_DMACmd(ADC1, ENABLE);
	ADC_Cmd(ADC1, ENABLE);
	
	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1));
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1));
	ADC_ExternalTrigConvCmd(ADC1, ENABLE);
}




void Adc_Init(void)
{
	ADC_GPIO_Configuration();
	ADC_TIM3_Configuration(TIM3_DEFAULT);
	ADC_DMA_Configuration();
	ADC_Init_Configuration();
}
u32 ADC_GetFREQ(void)
{
	return ADC_FREQ;
}
//TIM3¶¨Ê±Æ÷1M
//×î¸ß´¥·¢ PERIOD=0 				²ÉÑùÂÊ=1M
//				 PERIOD=1 				²ÉÑùÂÊ=0.5M
//				 PERIOD=3 				²ÉÑùÂÊ=0.25M		250K
//				 PERIOD=3 				²ÉÑùÂÊ=0.1M			100K
//				 PERIOD=999 		  ²ÉÑùÂÊ=1K
//				 PERIOD=60000    	²ÉÑùÂÊ=16
void ADC_SetFreq(u32 FREQ)
{
	u16 PERIOD=((float)1000000/FREQ)-1;
	TIM3->ARR=PERIOD;
	ADC_FREQ=FREQ;
}

void DMA1_Channel1_IRQHandler(void)
{
	if(DMA_GetITStatus(DMA1_IT_TC1) != RESET)
	{
		DMA_ClearITPendingBit(DMA1_IT_TC1);
	}
}


我设置将 ADC数据的目标地址设置为 ADC_SourceData。

(2)LCD驱动

(3)一路测试PWM

#include "SERVO.h"
#include "delay.h"
void TIM4_PWM_Init(u16 arr,u16 psc)
{
	RCC->APB1ENR|=1<<2;       
	GPIOB->CRH&=0XFFFFFF00;
	GPIOB->CRH|=0X000000BB;  
	GPIOB->ODR|=3<<8;
	TIM4->ARR=arr;
	TIM4->PSC=psc;
	TIM4->CCMR2|=6<<4; 
	TIM4->CCMR2|=1<<3; 
	TIM4->CCMR2|=6<<12;  
	TIM4->CCMR2|=1<<11;  
	TIM4->CCER|=1<<8;  
	TIM4->CCER|=1<<12;  
	TIM4->CR1=0x0080;  
	TIM4->CR1|=0x01;   
}

void Servo_Init(void)
{
	TIM4_PWM_Init(20000,71);//50HZ
	TIM4->CCR3 =10000;
	TIM4->CCR4 =15000;
}
void SERVO1(u8 degree)
{
	u16 k;
	k = 500 + degree * 11;
	TIM4->CCR3 = k;
}
void SERVO2(u8 degree)
{
	u16 k;
	k = 500 + degree * 11;
	TIM4->CCR4 = k;
}


(四)FFT原理

采集出信号频率以后我们需要在短时间内计算出信号的频率。

通过一组离散信号计算信号频率的方法通常叫做离散傅里叶变换。

我们首先来看一下DFT的原理:

学过信号的都知道,信号从时域来看是不断变换的,同时也可以从一个完全不同的角度来看信号。
DFT(FFT)的作用:可以将信号从时域变换到频域,而且时域和频域都是离散的,通俗的说,可以求出一个信号由哪些正弦波叠加而成,求出的结果就是这些正弦波的幅度和相位,我们音乐播放器上面显示的就是音乐fft之后不同频率正弦波的幅度,就像下面这张图片:
在这里插入图片描述

DFT公式:
在这里插入图片描述拆分以后可以得到

在这里插入图片描述

我们可以通过一组信号来测试:

DFT之后的数据是对称的,,在FFT的章节。比如做8点DFT,采样信号为x(n),DFT之后的数据为X(k),那么X(0)为直流信号,X(1), X(2), X(3), X(5), X(6), X(7),关于X(4)对称,即X(1)=X(7), X(2)=X(6),X(3)=X(5),如下图,是对1+sin(2PIt)进行DFT变换,具体的幅值先不关心,只要知道它是对称的就行了

在这里插入图片描述
我们可以看到得到的离散幅值序列,就是采样点数。这个时候点数的含义就从时间序列变成了频率序列。那么怎么从这个序列转换为我们需要的频率呢。

以上面的例子为例:

我们得到 0-7的离散序列可以对应到0-FS(采样频率)

具体公式为

我们在这个计算过程中可以看到采样频率一定要大于信号频率的两倍以上,否则幅值最高的频点就无法在你的采样范围内了。
我对DFT的理解其实就是将你的采样离散信号与采样信号进行卷积,这样以来,信号在频率中幅值最高的部分就会被突出出来。
FFT(Fast Fourier Transformation),中文名快速傅里叶变换,是离散傅氏变换的快速算法,它是根据离散傅氏变换的奇、偶、虚、实等特性,对离散傅立叶变换的算法进行改进获得的。
而在信奥中,一般用来加速多项式乘法。
朴素高精度乘法的时间为 O ( n 2 ) O(n^2) O(n2),但FFT能将时间复杂度降到 O ( n l o g 2 n ) O(nlog_2n) O(nlog2​n)

一下是我用C语言实现的简单FFT

/*
 * @Descripttion: 
 * @version: 
 * @Author: Yueyang
 * @email: 1700695611@qq.com
 * @Date: 2021-04-06 08:17:24
 * @LastEditors: Yueyang
 * @LastEditTime: 2021-04-06 11:02:16
 */
#include "stdio.h"
#include "math.h"
#include <time.h>
void kfft(double pr[],double pi[],int n,int k,double fr[],double fi[],int l,int il)
{ 
	int it,m,is,i,j,nv,l0;
    double p,q,s,vr,vi,poddr,poddi;
    for (it=0; it<=n-1; it++)
      { m=it; is=0;
        for (i=0; i<=k-1; i++)
          { j=m/2; is=2*is+(m-2*j); m=j;}
        fr[it]=pr[is]; fi[it]=pi[is];
      }
    pr[0]=1.0; pi[0]=0.0;
    p=6.283185306/(1.0*n);
    pr[1]=cos(p); pi[1]=-sin(p);
    if (l!=0) pi[1]=-pi[1];
    for (i=2; i<=n-1; i++)
      { p=pr[i-1]*pr[1]; q=pi[i-1]*pi[1];
        s=(pr[i-1]+pi[i-1])*(pr[1]+pi[1]);
        pr[i]=p-q; pi[i]=s-p-q;
      }
    for (it=0; it<=n-2; it=it+2)
      { vr=fr[it]; vi=fi[it];
        fr[it]=vr+fr[it+1]; fi[it]=vi+fi[it+1];
        fr[it+1]=vr-fr[it+1]; fi[it+1]=vi-fi[it+1];
      }
    m=n/2; nv=2;
    for (l0=k-2; l0>=0; l0--)
      { m=m/2; nv=2*nv;
        for (it=0; it<=(m-1)*nv; it=it+nv)
          for (j=0; j<=(nv/2)-1; j++)
            { p=pr[m*j]*fr[it+j+nv/2];
              q=pi[m*j]*fi[it+j+nv/2];
              s=pr[m*j]+pi[m*j];
              s=s*(fr[it+j+nv/2]+fi[it+j+nv/2]);
              poddr=p-q; poddi=s-p-q;
              fr[it+j+nv/2]=fr[it+j]-poddr;
              fi[it+j+nv/2]=fi[it+j]-poddi;
              fr[it+j]=fr[it+j]+poddr;
              fi[it+j]=fi[it+j]+poddi;
            }
      }
    if (l!=0)
      for (i=0; i<=n-1; i++)
        { fr[i]=fr[i]/(1.0*n);
          fi[i]=fi[i]/(1.0*n);
        }
    if (il!=0)
      for (i=0; i<=n-1; i++)
        { pr[i]=sqrt(fr[i]*fr[i]+fi[i]*fi[i]);
          if (fabs(fr[i])<0.000001*fabs(fi[i]))
            { if ((fi[i]*fr[i])>0) pi[i]=90.0;
              else pi[i]=-90.0;
            }
          else
            pi[i]=atan(fi[i]/fr[i])*360.0/6.283185306;
        }
    return;
}



#define PI 3.1415926535
#define FS 128
#define N (512)
#define M (int)log2(N)
 int main()
  { 
	  int i;
	  double t;
	  double pr[N],pi[N],fr[N],fi[N];
    clock_t start,end;
      //产生抽样序列
	  for (i=0; i<N; i++)
      { 
		 t=(double)i/FS;
		 pr[i]=sin(2*PI*33*t);
		 pi[i]=0.0;
	  }
    start=clock();
	  kfft(pr,pi,N,M,fr,fi,0,1);  //调用fft函数
    end=clock();
      for (i=0; i<N; i++)
      {
		  printf("%.6f %.6f\n",FS*(i+1)/(double)N,pr[i]); //输出数据
	    }
      printf("time:%d\n",(end-start));

      return 0;
  }

下面是输出序列
0.250000 0.000000
0.500000 0.000000
0.750000 0.000000
1.000000 0.000000

32.750000 0.000000
33.000000 0.000001
33.250000 256.000000
33.500000 0.000001
33.750000 0.000000

94.750000 0.000000
95.000000 0.000001
95.250000 256.000000
95.500000 0.000001
95.750000 0.000000

127.500000 0.000000
127.750000 0.000000
128.000000 0.000000

在频点33的位置幅值最高:

1* (FS)/N
那么怎样将256采样点转换为采样频率呢
我们可以通过以下函数转化频率:

float Get_Signal_Freq(int index)
{
	InitBuflnArray(index);
	DSP();
	return ((float)GetMaxData_Index()/256)*ADC_GetFREQ();
}

MyDSP.c

#include "MyDSP.h"
#include "math.h"
#include "ADC.h"

long 	FFT_256Pointln[N];
long 	FFT_256PointOut[N/2];
float IBufMagArray[N/2];
float Fs = 44800;	
float F = 44800/N;

void InitBuflnArray(int index)
{
	unsigned short i;
	float fx;
	Fs=ADC_GetFREQ();
	F = Fs/N;
	for(i = 0; i < N; i++)
	{
		fx = ADC_SourceData[i][index];
		FFT_256Pointln[i] = ((signed short)fx) << 16;	
	}
}

void GetPowerMag(void)
{
	signed short IX, IY;
	float X, Y, Mag;
	unsigned short i;
	for(i = 0; i < N/2;i++)
	{
		IX = (FFT_256PointOut[i] << 16) >> 16; 	
		IY = (FFT_256PointOut[i] >> 16);				
		X = N * ((float)IX) / 32768;
		Y = N * ((float)IY) / 32768;
		Mag = sqrt(X*X + Y*Y) / N;
		if(i == 0)
		{
			IBufMagArray[i] = (Mag * 32768);
		}
		else
		{
			IBufMagArray[i] = (Mag * 65536);
		}
	}
}


float GetMaxData(void)	
{
	int i = 0;
	float temp = 0;
	for(i = 1; i < N/2; i++)
	{
		if(temp < IBufMagArray[i])
		{
			temp = IBufMagArray[i];
		}
	}
	return temp;
}

int GetMaxData_Index(void)	
{
	int i = 0;
	float temp = 0;
	int tempindex=0;
	for(i = 1; i < N/2; i++)
	{
		if(temp < IBufMagArray[i])
		{
			temp = IBufMagArray[i];
			tempindex=i;
		}
	}
	return tempindex;
}


void DSP(void)	
{
	cr4_fft_256_stm32(FFT_256PointOut, FFT_256Pointln, N);
	GetPowerMag();
}

int Get_Adc_Max_Min(int index)
{
	int i = 0;
	int max = 0,min=0;
	if(index>1)index=0;
	for(i = 0; i < SAMPLS_NUM; i++)
	{
		if(max < ADC_SourceData[i][index])
			max = ADC_SourceData[i][index];
		if(min > ADC_SourceData[i][index])
			min = ADC_SourceData[i][index];
	}
	return max-min;
}

float Get_Signal_Freq(int index)
{
	InitBuflnArray(index);
	DSP();
	return ((float)GetMaxData_Index()/256)*ADC_GetFREQ();
}

(四)操作逻辑

main.c

#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "KEY.h"
#include "LCD_X.h"
#include "W25X16.h"
#include "malloc.h"
#include "SERVO.h"
#include "ADC.h"
#include "MyDSP.h"
u8 CHKEY=0; //0 CH0 1 CH1 2 

void DSO_Win()
{
	u8 data[3];
	int t=0;
	POINT_COLOR=GRAY;
	LCD_DrawFillRectangle(0,0,128,116);

	POINT_COLOR=BLUE;
	LCD_DrawFillRectangle(0,116,55,128);
	LCD_Show_Str(0,116,RED,BLUE,(u8*)"1HZ1V",12,1);

	POINT_COLOR=YELLOW;
	LCD_DrawFillRectangle(55,116,110,128);
	LCD_ShowString(55,116,12,(u8*)"1HZ1V",1);
	POINT_COLOR=GREEN;
	LCD_DrawFillRectangle(110,116,128,128);
	t=ADC_GetFREQ();
	sprintf((char*)data,"%3.1fK",(float)t/1000);
	LCD_ShowString(110,116,12,(u8*)data,1);
}

void CH1_Update(u32 freq,float vos)
{
	u8 data[10]={0};
	POINT_COLOR=BLUE;
	LCD_DrawFillRectangle(0,116,55,128);
	sprintf((char*)data,"%dHZ%1.1fV",freq,vos);
	LCD_Show_Str(0,116,RED,BLUE,(u8*)data,12,1);
}

void CH2_Update(int freq,float vos)
{
	u8 data[10]={0};
	POINT_COLOR=YELLOW;
	LCD_DrawFillRectangle(55,116,110,128);
	sprintf((char*)data,"%dHZ%1.1fV",freq,vos);
	LCD_Show_Str(55,116,RED,BLUE,(u8*)data,12,1);
}

void FREQ_Update(int freq)
{
	u8 data[3]={0};
	POINT_COLOR=GREEN;
	LCD_DrawFillRectangle(110,116,128,128);
	sprintf((char*)data,"%3.1f",(float)freq/1000);
	LCD_Show_Str(110,116,RED,BLUE,(u8*)data,12,1);
}
 int main(void)
 {	
	int i;
	u8 key;
	u32 freq1,freq2;
	float vos1,vos2;
	u32 freq;
	u8 line0[128];
	u8 line1[128];
	delay_init();	    	 
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 	 
	uart_init(115200); 
	LED_Init();		  	
	KEY_Init();
	LCD_Init();
	LCD_Clear(WHITE);
	SPI_Flash_Init();
	Adc_Init();
	ADC_SetFreq(100);
	Servo_Init();
	DSO_Win();

	while(1){
		 key=KEY_Scan(0);
		 if(key==KEY0_PRES){
				CHKEY++;
				if(CHKEY>=3)CHKEY=0;
		 }
		 if(key==KEY1_PRES){
				freq=ADC_GetFREQ();
			  freq*=2;//²»Äܳ¬¹ý500K
			  if(freq>=500000)freq=100;
			  ADC_SetFreq(freq);
				FREQ_Update(freq);
		 }
			POINT_COLOR=GRAY;
			LCD_DrawFillRectangle(0,0,128,116);
		if(CHKEY==0){
			for(i=1;i<128;i++){
				line0[i]=116-ADC_SourceData[i][0]/37;
				LCD_DrawLine_Color(128-(i-1),line0[i-1],128-i,line0[i],BLUE);
			}
		}
		else if(CHKEY==1){
			for(i=1;i<128;i++){
				line1[i]=116-ADC_SourceData[i][1]/37;
				LCD_DrawLine_Color(128-(i-1),line1[i-1],128-i,line1[i],YELLOW);
			}		
		}
		else
		{
			for(i=1;i<128;i++){
				line0[i]=116-ADC_SourceData[i][0]/37;
				LCD_DrawLine_Color(128-(i-1),line0[i-1],128-i,line0[i],BLUE);
			}
			for(i=1;i<128;i++){
				line1[i]=116-ADC_SourceData[i][1]/37;
				LCD_DrawLine_Color(128-(i-1),line1[i-1],128-i,line1[i],YELLOW);
			}	
		}
		freq1=Get_Signal_Freq(0);
		freq2=Get_Signal_Freq(1);
		vos1=3.3*(float)Get_Adc_Max_Min(0)/4096;
		vos2=3.3*(float)Get_Adc_Max_Min(1)/4096;
		CH1_Update(freq1,vos1);
		CH2_Update(freq2,vos2);
	}
}

可以通过KEY1更改采样率
KEY0更改通道

(五)操作效果

采样50HZ PWM

0.1KHz

在这里插入图片描述

0.2KHz

在这里插入图片描述

0.4KHZ

在这里插入图片描述

0.8KHz

在这里插入图片描述

1.6KHz

在这里插入图片描述

3.2K

在这里插入图片描述

6.4KHz

在这里插入图片描述

双通道

在这里插入图片描述
经过在保证对于信号频率的测量准确的前提下,最高采样频率为500K。

(六)下载地址

下载地址

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

与光同程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值