疫情期间闲来无事,正好学习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(fMaxftmp2[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、程序源代码
https://download.csdn.net/download/w267309080/88294446