【单片机开发】STM32简易示波器开发
文章目录
- (一)前言
- (二)硬件介绍
- (1)MCU
- (2)TFT显示屏
- (3)按键接口
- (三)驱动编程
- (1)ADC驱动
- (2)LCD驱动
- (3)一路测试PWM
- (四)FFT原理
- (四)操作逻辑
- (五)操作效果
- 0.1KHz
- 0.2KHz
- 0.4KHZ
- 0.8KHz
- 1.6KHz
- 3.2K
- 6.4KHz
- 双通道
- (六)下载地址
(一)前言
还记得之前因为个人需要,又不太想花钱买示波器,实现了一个简易的示波器。
这个示波器非常明显存在以下几个非常尴尬的问题:
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 999extern 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=12MHzADC_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_A1ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_1Cycles5); //AI_VS_B1ADC_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);//50HZTIM4->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(nlog2n)
一下是我用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;}elsepi[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;//²»Äܳ¬¹ý500Kif(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。
(六)下载地址
下载地址
【单片机开发】STM32简易示波器开发相关推荐
- STM32简易示波器开发总结
考研失利不用准备复试了,有了空闲时间做了个示波器,带宽80Khz,输入幅度0-3.3V,带有触发功能,接近实时的波形显示和FFT计算,不过存储深度太小了只有1024个点.最近要准备工作的面试了之后有时 ...
- STM32简易示波器
第一次写博客,也是想分享一下自己的心得体会.本人大三,因为准备比赛的缘故,需要做一个示波器,因为不是想做一个成品,所以只是实现了基本功能,后续的话也不会再用这个,更多的是体会过程.此文章主要是给像我这 ...
- USB开发—STM32 USB Audio 开发板介绍(Feedback)
USB开发-STM32 USB Audio 开发板介绍(Feedback) 一.背景 我个人从事音频行业有好几年的时间.后面慢慢的做起了声卡,也就是USB Audio.自己也走了不少的弯路.之前一起是 ...
- stm32简易示波器(标准库)
简介 此项案例是基于正点原子精英板制作的一个简易示波器,可以读取信号的频率和幅值,并可以通过按键改变采样频率和控制屏幕的更新暂停. (输入最大3.3V,由ADC参考电压决定) 将PA6与PA4相连,可 ...
- matlab示波器如何反白,stc12单片机写的简易示波器代码,求大神答疑
#include #include #include sbit RS=P0^0; //并行的指令/数据选择信号, H数据, L命令 sbit RW=P0^1; //并行读写选择信号, H读, L写 s ...
- 单片机毕业设计 stm32迷你示波器设计与实现 - 嵌入式 物联网
文章目录 0 前言 1 简介 2 主要器件 3 实现效果 4 设计原理 4.1 硬件部分 4.2 软件部分 5 部分核心代码 5 最后 0 前言
- 使用EmBitz开发STM32项目开发环境配置
一.EmBitz软件获取与安装 1.EmBitz软件的获取 EmBitz原名Em::Blocks,是基于Code::Blocks开发的,面向嵌入式的C/C++集成开发环境.支持J-Link和ST ...
- 基于stm32mini开发板的简易函数发生器和简易示波器
基于stm32 mini开发板的简易函数发生器和简易示波器 前言:用正点原子的mini开发板,设计制作简易示波器和简易函数发生器,需要运用的知识是 ADC+DAC+DMA+通用定时器+外部中断. 一. ...
- Vscode开发STM32单片机程序
STM32单片机非常强大,大多数教程都是使用 keil 编译器,keil 是收费的而 gcc 是开源免费的.这里介绍一些使用 gcc + vscode 开发单片机程序的经验.(这里不解释 gcc 是什 ...
最新文章
- Bootstrap下拉菜单组件
- python8_python8
- Python读入CIFAR-10数据库
- PHP用空格分割文本为数组的方法
- Redis 面试题补充与汇总
- (计算机组成原理)第三章存储系统-第六节1:高速缓冲存储器Cache及其相关基本概念、程序访问的局部性原理和命中率
- Spring 源码分析(四) ——MVC(六)M 与 C 的实现
- 静态类型和动态类型的语言有什么区别?
- 关于algorithm的sort函数
- 读[SBO高层大变动]一文有感
- 【原创】VBA学习笔记(4)VBA函数 和 worksheetfunction工作表函数
- 深入理解地球的经度和纬度换算
- 九大背包问题专题--背包问题求方案数
- 微信小程序云开发 实时地图显示
- 【天光学术】物流工程论文:连锁超市缺货和爆仓库存问题改善分析(节选)
- angular学习笔记(十四)-$watch(3)
- win7修复计算机界面,用好Windows7自修复 系统崩溃无需重做
- Flink一站式平台 StreamX 1.2.2 正式发布, 迄今最稳定可用版本
- Python numpy.atleast_3d函数方法的使用
- linux的电脑 配哪款显卡,27款AMD、NVIDIA显卡大战Linux