まず、基本的な部分の最初の質問をご覧ください まず、テスト後、私のエミッタ接地増幅回路の倍率は約 280 (ディスクリート部品は人によって異なります) であり、三極管の倍率が小さいほど良いことになります。 (1)を説明します。
基本的なハードウェア
入力抵抗
DDS が出力する正弦波の振幅は 1.1v なので、分圧後、抵抗を直列に接続し、計算式で求めます。回路図は次のとおりです。
上は分圧電圧の 10 分の 1、下は 1% です。まず、上記の機能について説明します。上は、DC を通過した後、フォロワに接続された DDS であることがわかります。タイトルで必要なため、フォローアップ後に抵抗を直列に接続します。最も重要なことは、入力抵抗が 1K ~ 50K であり、レンジ スパンが比較的大きいことです。入力抵抗が比較的大きい場合には大きな抵抗が直列に接続され、入力抵抗が比較的小さい場合には小さな抵抗が直列に接続されます。
実際の処理では、AD は波形のピーク値の判断が不正確であり (理由はわかりません。私の先輩も同じ状況です)、アルゴリズムを追加した後の効果は特に理想的ではないため、AD637 はここではAD637の紹介を行いますが、このチップの性能を忘れないように記録することもできます。
AD637 は、あらゆる複雑な波形の真の実効値を計算する 、完全な高精度モノリシック RMS/DCコンバータです。ディスクリート設計やモジュール設計に匹敵する精度、帯域幅、ダイナミック レンジを備えた集積回路 RMS -DC コンバータで前例のないパフォーマンスを提供します。AD637 は波高率補償方式を備えており、最大 10 の波高率で信号を 1% 未満の追加誤差で測定できます。広い帯域幅により、200 mV rms で最大 600 kHz、1 V rms 以上で最大 8 MHz の入力信号を測定できます。
中国語の資料がオンラインにありますので、ここでは繰り返しません。
回路図
±5V電源時、入力実効値電圧範囲:0~3V、±15V電源時、入力実効値電圧範囲:0~6V
したがって、検出値をADに直接接続すると、誤差は非常に小さく、非常に安定します。
出力抵抗は入力抵抗と非常に似ているため、詳細は説明しません。
得
倍率は入力増幅回路のUiと負荷のUoであり、DDSの出力や分圧では直接計算できません。
振幅周波数特性曲線
振幅周波数特性曲線(1)で述べたように、周波数を変化させてもDDSの振幅が大きく変化しないようにする必要があり、そうしないと入力を再収集する必要があり、時間がかかります。 . 問題には制限時間があり、延長した場合は減点されます。
(1)で述べたように、オシロスコープや周波数スイーパーを使用すると0.707倍に相当する周波数を測定できるので、DDSの出力周波数を書き込むのに便利です。
測定してみると手持ちの9850の振幅は100HZ-20Mで1.1Vなので入力端子が固定されているので入力を集める必要はありません。測定後の上下限周波数は260HZから十数MHZまであり、DDSを使って周波数を一度変更して拡大し、最終的にstm32lcdの画面に表示します。
注意しなければならないことは次のとおりです。
倍率が変化する端ではより多くの点を収集し、倍率が非常に固定されている中間点ではより少ない点を収集できるため、曲線は滑らかになり、一次関数ほど直線的ではなくなります。
2 つの抵抗による分圧器のノイズはまだ少し大きいので、オペアンプを使用した方が良いでしょう。
ハードウェアの基礎部分はここまでで、基本的なポイントは押さえやすく、難しいことはほとんどなく非常にスムーズです。
コード
#include "adc.h"
#include "lay.h"
#include "stdio.h"
#include "math.h"
#include "lcd.h"
#include "led.h"
#include "ad9850.h"
u8 Res_select=0;
u32 大きい_解像度=20000;
u32 little_Res=3000;
u32 ui1=55; //DDS_OUT はマルチメータで直接測定され、コードに書き込まれます (単位: mv)
//分圧後の DDS 出力 1.1v の値は既知なので、測定するために広告またはピーク検出を使用する必要はありません
/ /ただし、小さなエラー データの場合 ベンチトップ マルチメーターを使用して書かれたコードを正確に測定する
//ADC を初期化します
//ここでは例として通常のチャネルのみを取り上げます
//デフォルトではチャネル 0 ~ 3 を開きます
void Adc1_Init(void)
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC |RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1 , ENABLE ); //ADC1 チャネル クロックを有効にする
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //ADC 分周係数 6 を設定 72M/6=12、ADC 最大時間は 14M を超えることはできません
//PA1 はアナログ チャネル入力ピンとして使用されます
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //アナログ入力ピン
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_In it Structure.GPIO_Mode = GPIO_Mode_AIN; // アナログ入力ピン
GPIO_Init(GPIOA, &GPIO_InitStructure);
ADC_DeInit(ADC1); //ADC1 をリセット、ペリフェラル ADC1 のすべてのレジスタをデフォルト値にリセット
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC 動作モード: ADC1 および ADC2 は独立モードで動作
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //アナログ - デジタル変換はシングル チャネル モードで動作
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //アナログ - -デジタル変換は単一の変換モードで動作します
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //変換は外部トリガではなくソフトウェアによって開始されます
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC データは右揃え
ADC_InitStructure.ADC_NbrOfChannel = 3; //ADC の数通常の変換用チャネルを順番に
ADC_Init(ADC1 , &ADC_InitStructure); //ADC_InitStruct で指定されたパラメータに従ってペリフェラル ADCx レジスタを初期化します
//指定された ADC の通常のグループ チャネル、シーケンス、サンプリング時間を設定します
//ADC_ RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_239Cycles5 ); //ADC1、ADC チャネル、サンプリング時間は 239.5 サイクルです
//ADC_ RegularChannelConfig(ADC1, ADC_Channel_12, 2, ADC_SampleTime_239Cycles5 ); //ADC1、ADC チャネル、サンプリング時間は 239.5 サイクル
//ADC_ RegularChannelConfig(ADC1, ADC_Channel_13, 3, ADC_SampleTime_239Cycles5 ); //ADC1、ADC チャネル、サンプリング時間は 239.5 サイクル
ADC_Cmd(ADC1, ENABLE); //指定された ADC1 を有効にする
ADC_ResetCalibration(ADC1); //リセット キャリブレーションを有効にする while(ADC_GetResetCalibrationStatus(ADC1)); //リセット キャリブレーションが終了する まで
待機
ADC_StartCalibration(ADC1); //AD キャリブレーションを開く
(ADC_GetCalibrationStatus(ADC1)); //キャリブレーションの終了を待つ
// ADC_SoftwareStartConvCmd(ADC1, ENABLE); //指定された ADC1 のソフトウェア変換開始機能を有効にする
}
//ADC値の取得
//ch:チャネル値0~3
u16 Get_Adc1(u8 ch)
{ // //指定したADCのレギュラーグループチャネル、シーケンス、サンプリング時間を設定 ADC_REGULARChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 ); //ADC1、ADC チャネル、サンプリング時間は 239.5 サイクル ADC_SoftwareStartConvCmd(ADC1, ENABLE); //指定された ADC1 のソフトウェア変換開始関数を有効にする while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//変換の終わり
return ADC_GetConversionValue(ADC1); //最新のADC1ルールグループの変換結果を返す
}
u16 Get_Adc_Average1(u8 ch,u8 回)
{ u32 temp_val=0; u8t; for(t=0;t<times;t++) { temp_val+=Get_Adc1(ch); 遅延_ms(5); temp_val/timesを返します 。}
/*
//この関数は波形のピーク値を計算するために使用できますが、広告は正確ではないため、私が使用する解決策はピーク検出です
//広告を使用してピーク検出ポートの波形振幅を直接収集する方が正確です
#define N 50
u16 filter(u8 ch,u8 回 )
{ char count,i,j; u32 Value_buf[N]; u32 temp; u32 sum=0; for(count=0;count<N;count++) Value_buf[count] ]= 0; for(count=0;count< N;count++) Value_buf[count]= Get_Adc1(ch); for(j=0;j<(N-1);j++) for(i=0;i< (Nj);i++) if(Value_buf[i] >Value_buf[i+1]) { temp = Value_buf[i]; Value_buf[i]= Value_buf[i+1]; Value_buf[i+1]=temp;
for(count =1;count <
N-1;count++)
sum += Value_buf[count];
return (u16)(合計/(N-2));
}
void adc_ch_data(u8 Channel)
{ u32 adcx[128]; u16 i; for(i=0;i<128;i++) { adcx[i] = Get_Adc_Average1(Channel,10); // チャンネル 1 の電圧を検出 printf ( "%d\r\n",adcx[i]); } } */
void get_resin(void)
{ float res_in=0; フロート adc_ch10=0;
float adc_ch10_v=0;
jidianqi7=0;
late_ms(200);
adc_ch10 = Get_Adc_Average1(ADC_Channel_10,10); // チャンネル 1 の ADC 値を収集
//Y1=0.6715X-1.2403
//adc_ch10_v=((((adc_ch10+1.2403)/0.6715)*2)/80);
adc_ch10_v=((((adc_ch10+1.2403)/0.6715)*2)/110);
// 電圧に変換します
// 2 倍する目的は、ピークツーピーク値を使用することです
// 100 で割る目的は、この値が比較的小さいためです。実際の測定値はわずか 4mv
//そこで4mv出力の後に追加しました 第一段階の倍率は同位相比倍率の80倍です
// なのでコード内で100を割る必要があります 倍率を追加しない場合はこの100を割る必要はありません
//倍率なしの測定結果は正しいですが、振幅が比較的小さいため、不安定な値のジャンプが収集されます 素晴らしいですが、正しい結果が得られます
遅延_ms(200);
if(Res_select==1)
{
res_in=(adc_ch10_v*large_Res)/(ui1-adc_ch10_v);
//入力抵抗計算式:(Ui2*R)/(Ui1-Ui2)
}
else
{ res_in=(adc_ch10_v*little_Res)/(ui1-adc_ch10_v); }
printf("%f\r\n",res_in);
//res_in=res_in/1000;
LCD_ShowxNum(100,0, res_in,5,24,0);//ADC 値を表示
LCD_ShowxNum(100,120, adc_ch10_v,5 , 24,0);//ADC 値を表示
//printf("%f\r\n",res_in);
}
void get_resout(void)
{
float res_out=0;
float adc_ch11=0; float
adc_ch11_1=0
;
float adc_ch11_v1=0; float adc_ch11_v2
=0; = Get_Adc_Average1 (ADC_Channel_12,10); // 取り込みチャネル 11 の ADC 値 //adc_ch11_v1= ((((adc_ch11+1.2403)/0.6715)*2)+1.1; //電圧に変換 //adc_ch11_v1=adc_ch11* 3.3/4096 / _ _ _ _ _ /チャンネル 11 の ADC 値を収集
//adc_ch11_v2=adc_ch11_1*3.3/4096;
//adc_ch11_v2=((((adc_ch11_1+1.2403)/0.6715)*2);
//出力抵抗測定 Ro=(Uo1-Uo2)*R/Uo2 R:負荷抵抗
LCD_ShowxNum (100,180, adc_ch11_v2,5,24,0);//ADC値を表示
//res_out=((adc_ch11_v1-adc_ch11_v2)*2000)/adc_ch11_v2;
res_out=((adc_ch11-adc_ch11_1)*2000)/adc_ch 11_1;
/ / res_out=((adc_ch11-adc_ch11_1)*2000)/adc_ch11_1;
late_ms(2);
//res_out=res_out/1000;
//printf("%f\r\n",res_out);
LCD_ShowxNum(100,30, res_out) ,5,24,0);//ADCの値を表示する
}
void get_Au(void)//Gain
{ u16 Au=0; float Uo=0;//リレーの波形ピーク値は増幅回路を通さない //DC量から出力波形ピーク値を差し引く必要があるピーク検出前 float Ui_v =0; float Uo_v=0; float Ui=0;//波形ピーク Ui= Get_Adc_Average1(ADC_Channel_10,10); Ui_v=((((Ui+1.2403)/0.6715)*2)/100 ); late_ms(200); Uo= Get_Adc_Average1(ADC_Channel_12,10); Uo_v=(((Uo+0.12)*4)-6.35)*2; //Uo_v=(((Uo+1.2403)/0.6715)*2 ); late_ms(10); Au=Uo_v/Ui_v; //printf("%d\r\n",Au); LCD_ShowxNum(100,60, Au,5,24,0);//ADC 値を表示}
入力抵抗、出力抵抗、倍率はすべて関数にパッケージ化されており、main 関数で直接調整できます。
振幅周波数特性曲線の座標表示:
void zuobiao(void)
{ POINT_COLOR = RED; LCD_Display_Dir(0); LCD_ShowString(30,0,210,24,24,"Ri = "); LCD_ShowString(30,30,210,24,24,"R0 = "); // LCD_ShowString(30,60,210,24,24,"fL = "); // LCD_ShowString(30,90,210,24,24,"fH = "); LCD_ShowString(30,60,210,24,24,"Au = "); LCD_DrawLine(0,305,240,305); LCD_DrawLine(15,140,15,320); //x轴y轴 LCD_DrawLine(240,305,230,315); LCD_DrawLine(240,305,230,295); //箭头 LCD_DrawLine(15,140,5,150); LCD_DrawLine(15,140,25,150); //箭头
LCD_DrawLine(40,305,40,300);
LCD_DrawLine(65,305,65,300);
LCD_DrawLine(90,305,90,300);
LCD_DrawLine(115,305,115,300);
LCD_DrawLine(140,305,140,300);
LCD_DrawLine(165,305,165,300);
LCD_DrawLine(195,305,195,300);
LCD_DrawLine(15,275,20,275);
LCD_DrawLine(15,245,20,245);
LCD_DrawLine(15,215,20,215);
LCD_DrawLine(15,185,20,185);
LCD_ShowString(220,307,200,12,12,"Hz");
LCD_ShowString(20,307,200,12,12,"100");
LCD_ShowString(40,307,200,12,12,"200");
LCD_ShowString(60,307,200,12,12,"1K");
LCD_ShowString(80,307,200,12,12,"1.5K");
LCD_ShowString(100,307,200,12,12,"10K");
LCD_ShowString(120,307,200,12,12,"50K");
LCD_ShowString(140,307,200,12,12,"100K");
LCD_ShowString(160,307,200,12,12,"150K");
LCD_ShowString(180,307,200,12,12,"170K");
LCD_ShowString(2,270,200,12,12,"80");
LCD_ShowString(2,240,200,12,12, "100");
LCD_ShowString(2,210,200,12,12,"12O");
LCD_ShowString(2,180,200,12,12,"14O");
LCD_ShowString(7,307,200,12,12,"O");
LCD_ディスプレイ_ディレクトリ(1);
LCD_ShowString(145,0,200,12,12,"ゲイン");
LCD_Display_Dir(0);
}
振幅周波数特性曲線の表示:
//手持ちの AD9850 は周波数を変えても振幅が変わらないため
//9854 は周波数を変えても振幅が変わってしまうため
//振幅周波数特性曲線を測定する場合、DDS の場合はゲインを測定する必要がある出力が一定である場合、毎回変更する必要はありません
。周波数が 2 回変更されると入力振幅が収集されます。//同様に、周波数が変更されると振幅が変化する場合、入力コードは 2 回に 1 回収集される必要があります。周波数が変更される時間。ワークロードは比較的大きい。//
振幅周波数特性曲線は、
float signal[11]={ 100, 200, 500, 1000, 10000, 50000, 100000, 150000, 170000};//DDS を示します。出力周波数
void boxin(void)
{ u32 Ui1=55; //DDS_OUT はマルチメータで直接測定され、コードに書き込まれます (単位: mv) //DDS 分圧後の出力 1.1v の値がわかります。広告やピーク検出で測定する必要はありません//ただし、小さな誤差と正確なデータの場合は、デスクトップ マルチメーターを使用して測定し、コード u8 Au[9]={0,0,0,0,0 ,0,0 を書き込みます,0,0}; u8 i; float adc_ch11_1=0; float adc_ch11_v2=0; for(i=0;i<11;i++) { ad9850_wr_serial(0x00,(double)signal[i]);/ /DDS 出力信号
adc_ch11_1 = Get_Adc_Average1(ADC_Channel_12,10); //取得チャネル 11 の ADC 値
adc_ch11_v2=(((adc_ch11_1+1.2403)/0.6715)*2)+1.1; //電圧に変換
Au[i]=adc_ch11_v2/Ui1 ;
}
// for(i=0;i<8;i++)
// { // au[i]=Au[i]; // } // au[5]=au[4]-30; // au[ 6]=au[4]-60; // au[7]=au[4]-100; LCD_DrawPoint(20,305-Au[0]/20*30); LCD_DrawPoint(40,305-Au[1]/20 *30 ); LCD_DrawPoint(60,305-Au[2]/20*30); LCD_DrawPoint(80,305-Au[3]/20*30); LCD_DrawPoint(100,305-Au[4]/20*30); LCD_DrawPoint(120,305-Au[ 5]/20*30);
LCD_DrawPoint(140,305-Au[6]/20*30);
LCD_DrawPoint(160,305-Au[7]/20*30);
LCD_DrawPoint(180,305-Au[8]/20*30);
LCD_DrawLine(20,305-Au[0]/20*30,40,305-Au[1]/20*30);
LCD_DrawLine(40,305-Au[1]/20*30,60,305-Au[2]/20*30);
LCD_DrawLine(60,305-Au[2]/20*30,80,305-Au[3]/20*30);
LCD_DrawLine(80,305-Au[3]/20*30,100,305-Au[4]/20*30);
LCD_DrawLine(100,305-Au[4]/20*30,120,305-Au[5]/20*30);
LCD_DrawLine(120,305-Au[5]/20*30,140,305-Au[6]/20*30);
LCD_DrawLine(140,305-Au[6]/20*30,160,305-Au[7]/20*30);
LCD_DrawLine(160,305-Au[7]/20*30,180,305-Au[8]/20*30);
// LCD_DrawLine(65,305-Au[1]*t,70,305-Au[1]*t+k2*5-4);
// LCD_DrawLine(70,305-Au[1]*t+k2*5-4,75,305-Au[1]*t+k2*10-5);
// LCD_DrawLine(75,305-Au[1]*t-5+k2*10,80,305-Au[1]*t+k2*15-4);
// LCD_DrawLine(80,305-Au[1]*t-4+k2*15,85,305-Au[1]*t+k2*20-3); // LCD_DrawLine(85,305-Au[1]*t-3
+ k2*20,90,305-Au[2]*t);
// LCD_DrawLine(40,305-Au[0]*t,65,305-Au[1]*t);
// LCD_DrawLine(65,305-Au[1]*t, 90,305-Au[2]*t);
// LCD_DrawLine(90,305-Au[2]*t,115,305-Au[3]*t);
// LCD_DrawLine(115,305-Au[3]*t,140,305-Au[ 4]*t);
// LCD_DrawLine(140,305-Au[4]*t,148,305-Au[5]*t);
// LCD_DrawLine(148,305-Au[5]*t,156,305-Au[6]*t );
// LCD_DrawLine(156,305-Au[6]*t,165,305-Au[7]*t);
// LCD_DrawLine(165,305-Au[7]*t,195,305-Au[8]*t);
}
上基本的な部品は全て動作確認済みで問題ありません。