完整版教程下載下傳位址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=94547
第49章 STM32F429的自适應濾波器實作,無需Matlab生成系數(支援實時濾波)
本章節講解LMS最小均方自适應濾波器實作,無需Matlab生成系數,可以自學習。
49.1 初學者重要提示
49.2 自适應濾波器介紹
49.3 LMS最小均方自适應濾波器介紹
49.4 Matlab自适應濾波器實作
49.5 自适應濾波器設計
49.6 實驗例程說明(MDK)
49.7 實驗例程說明(IAR)
49.8 總結
- ARM DSP庫提供了LMS最小均方自适應濾波和歸一化最小均方自适應濾波器,推薦使用歸一化方式,因為歸一化方法的步長更容易設定。
- 自适應濾波器的濾波因數步長設定比較考究,詳見本章教程第5.3小結。
自适應濾波器能夠根據輸入信号自動調整濾波系數進行數字濾波。作為對比,非自适應濾波器有靜态的濾波器系數,這些靜态系數一起組成傳遞函數。
對于一些應用來說,由于事先并不知道需要進行操作的參數,例如一些噪聲信号的特性,是以要求使用自适應的系數進行處理。在這種情況下,通常使用自适應濾波器,自适應濾波器使用回報來調整濾波器系數以及頻率響應。
随着處理器性能的增強,自适應濾波器的應用越來越常見,時至今日它們已經廣泛地用于手機以及其它通信裝置、數位錄像機和數位照相機以及醫療監測裝置中。
49.3 LMS最小均方介紹
LMS 最小均方自适應濾波器能夠"學習"未知的傳輸特性。LMS濾波器使用梯度下降方法,根據瞬時錯誤信号更新濾波系數。自适應濾波器常用于通信系統、均衡器和降噪。
LMS 濾波器由以下兩個部分組成。第一部分是 FIR 濾波器。第二部分是系數更新機制。LMS 濾波器具有兩個輸入信号。x[n] 是FIR 濾波器輸入,而參考輸入d[n]對應 FIR 濾波器的預期輸出。更新 FIR濾波器系數,以便 FIR濾波器的輸出與參考輸入比對。濾波器系數更新機制基于 FIR 濾波器輸出和參考輸入之間的差異。當濾波器調整時,"錯誤信号"e[n]傾向于為零。LMS 處理功能接受輸入和參考輸入信号,并生成濾波器輸出和錯誤信号。

輸出信号 y[n] 由标準 FIR 濾波器計算:
y[n] = b[0] * x[n] + b[1] * x[n-1] + b[2] * x[n-2] + ...+ b[numTaps-1] * x[n-numTaps+1]
誤差信号等于參考信号 d[n] 和濾波器輸出之間的內插補點:
e[n] = d[n] - y[n]。
在計算每個樣本的誤差信号後,計算濾波器狀态變量的瞬時能量:
E = x[n]^2 + x[n-1]^2 + ... + x[n-numTaps+1]^2。
然後在逐個樣本的基礎上更新濾波器系數 b[k]:
b[k] = b[k] + e[n] * (mu/E) * x[n-k],對于 k=0, 1, ..., numTaps-1
其中 mu 是步長,并且控制系數收斂速度。在函數arm_lms_norm_init_f32中,pCoeffs 指向大小為 numTaps 的濾波器系數數組。系數按時間倒序存儲:
{b[numTaps-1], b[numTaps-2], b[N-2], ..., b[1], b[0]}
pState 指向一個大小為 numTaps + blockSize - 1 的狀态數組。 狀态緩沖區中的樣本按順序存儲:
{x[n-numTaps+1], x[n-numTaps], x[n-numTaps-1], x[n-numTaps-2]....x[0], x[1], .. ., x[blockSize-1]}
注意,狀态緩沖區的長度超過了濾波器系數數組的長度 blockSize-1 個樣本。
首先建立兩個混合信号,便于更好測試濾波器效果。
混合信号Mix_Signal_1 = 信号Signal_Original_1+白噪聲。
混合信号Mix_Signal_2 = 信号Signal_Original_2+白噪聲。
Fs = 1000; %采樣率
N = 1000; %采樣點數
n = 0:N-1;
t = 0:1/Fs:1-1/Fs; %時間序列
Signal_Original_1 =sin(2*pi*10*t)+sin(2*pi*20*t)+sin(2*pi*30*t);
Noise_White_1 = [0.3*randn(1,500), rand(1,500)]; %前500點高斯分部白噪聲,後500點均勻分布白噪聲
Mix_Signal_1 = Signal_Original_1 + Noise_White_1; %構造的混合信号
Signal_Original_2 = [zeros(1,100), 20*ones(1,20), -2*ones(1,30), 5*ones(1,80), -5*ones(1,30), 9*ones(1,140), -4*ones(1,40), 3*ones(1,220),
12*ones(1,100), 5*ones(1,20), 25*ones(1,30), 7 *ones(1,190)];
Noise_White_2 = 0.5*randn(1,1000); %高斯白噪聲
Mix_Signal_2 = Signal_Original_2 + Noise_White_2; %構造的混合信号
濾波代碼實作如下:
%****************************************************************************************
%
% 信号Mix_Signal_1 和 Mix_Signal_2 分别作自适應濾波
%
%***************************************************************************************
%混合信号 Mix_Signal_1 自适應濾波
N=1000; %輸入信号抽樣點數N
k=100; %時域抽頭LMS算法濾波器階數
u=0.001; %步長因子
%設定初值
yn_1=zeros(1,N); %output signal
yn_1(1:k)=Mix_Signal_1(1:k); %将輸入信号SignalAddNoise的前k個值作為輸出yn_1的前k個值
w=zeros(1,k); %設定抽頭權重初值
e=zeros(1,N); %誤差信号
%用LMS算法疊代濾波
for i=(k+1):N
XN=Mix_Signal_1((i-k+1):(i));
yn_1(i)=w*XN';
e(i)=Signal_Original_1(i)-yn_1(i);
w=w+2*u*e(i)*XN;
end
subplot(4,1,1);
plot(Mix_Signal_1); %Mix_Signal_1 原始信号
axis([k+1,1000,-4,4]);
title('原始信号');
subplot(4,1,2);
plot(yn_1); %Mix_Signal_1 自适應濾波後信号
axis([k+1,1000,-4,4]);
title('自适應濾波後信号');
%混合信号 Mix_Signal_2 自适應濾波
N=1000; %輸入信号抽樣點數N
k=500; %時域抽頭LMS算法濾波器階數
u=0.000011; %步長因子
%設定初值
yn_1=zeros(1,N); %output signal
yn_1(1:k)=Mix_Signal_2(1:k); %将輸入信号SignalAddNoise的前k個值作為輸出yn_1的前k個值
w=zeros(1,k); %設定抽頭權重初值
e=zeros(1,N); %誤差信号
%用LMS算法疊代濾波
for i=(k+1):N
XN=Mix_Signal_2((i-k+1):(i));
yn_1(i)=w*XN';
e(i)=Signal_Original_2(i)-yn_1(i);
w=w+2*u*e(i)*XN;
end
subplot(4,1,3);
plot(Mix_Signal_2); %Mix_Signal_1 原始信号
axis([k+1,1000,-10,30]);
title('原始信号');
subplot(4,1,4);
plot(yn_1); %Mix_Signal_1 自适應濾波後信号
axis([k+1,1000,-10,30]);
title('自适應濾波後信号');
Matlab運作效果:
49.5 自适應器設計
自适應濾波器的主要通過下面兩個函數實作,支援逐點實時濾波。
49.5.1 函數arm_lms_norm_init_f32
函數原型:
void arm_lms_norm_init_f32(
arm_lms_norm_instance_f32 * S,
uint16_t numTaps,
float32_t * pCoeffs,
float32_t * pState,
float32_t mu,
uint32_t blockSize);
函數描述:
此函數用于自适應濾波器初始化。
函數參數:
- 第1個參數是arm_lms_norm_instance_f32類型結構體變量。
- 第2個參數是濾波因數個數。
- 第3個參數是濾波因數位址。
- 第4個參數指向狀态變量數組,這個數組用于函數内部計算資料的緩存。
- 第5個參數用于設定濾波因數更新的步長。
- 第6個參數是每次處理的資料個數,最小可以每次處理1個資料,最大可以每次全部處理完。
49.5.2 函數arm_lms_norm_f32
void arm_lms_norm_f32(
arm_lms_norm_instance_f32 * S,
const float32_t * pSrc,
float32_t * pRef,
float32_t * pOut,
float32_t * pErr,
uint32_t blockSize);
此函數用于自适應濾波器實時濾波。
- 第2個參數是源資料位址。
- 第3個參數是參考資料位址,需要使用者提供想要逼近的波形效果。
- 第4個參數是輸出資料位址。
- 第5個參數是誤差資料位址。
注意事項:
結構體arm_lms_norm_instance_f32的定義如下(在檔案arm_math.h檔案):
typedef struct
{
uint16_t numTaps; /**< number of coefficients in the filter. */
float32_t *pState; /**< points to the state variable array. The array is of length
numTaps+blockSize-1. */
float32_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps. */
float32_t mu; /**< step size that control filter coefficient updates. */
float32_t energy; /**< saves previous frame energy. */
float32_t x0; /**< saves previous input sample. */
} arm_lms_norm_instance_f32;
1、參數numTaps用于設定濾波因數個數。
2、pState指向狀态變量數組,這個數組用于函數内部計算資料的緩存。
3、參數pCoeffs指向濾波因數,濾波因數數組長度為numTaps。但要注意pCoeffs指向的濾波因數應該按照如下的逆序進行排列:
{b[numTaps-1], b[numTaps-2], b[N-2], ..., b[1], b[0]}
但滿足線性相位特性的FIR濾波器具有奇對稱或者偶對稱的系數,偶對稱時逆序排列還是他本身。
4、參數mu用于設定濾波因數更新的步長。
5、blockSize 這個參數的大小沒有特殊要求,最小可以每次處理1個資料,最大可以每次全部處理完。
49.5.3 濾除200Hz正弦波測試(含不同步長測試,重要)
原始波形200Hz + 50Hz正弦波,濾除200Hz正弦波測試:
/*
*********************************************************************************************************
* 函 數 名: arm_lms_f32_test1
* 功能說明: 原始波形200Hz + 50Hz正弦波,濾除200Hz正弦波。
* 形 參: 無
* 返 回 值: 無
*********************************************************************************************************
*/
void arm_lms_f32_test1(void)
{
uint32_t i;
float32_t *inputF32, *outputF32, *inputREF, *outputERR;
arm_lms_norm_instance_f32 lmsS={0};
for(i=0; i<TEST_LENGTH_SAMPLES; i++)
{
/* 50Hz正弦波+200Hz正弦波,采樣率1KHz */
testInput_f32_50Hz_200Hz[i] = arm_sin_f32(2*3.1415926f*50*i/1000) +
arm_sin_f32(2*3.1415926f*200*i/1000);
testInput_f32_REF[i] = arm_sin_f32(2*3.1415926f*50*i/1000);
}
/* 如果是實時性的濾波,僅需清零一次 */
memset(lmsCoeffs32,0,sizeof(lmsCoeffs32));
memset(lmsStateF32,0,sizeof(lmsStateF32));
/* 初始化輸入輸出緩存指針 */
inputF32 = (float32_t *)&testInput_f32_50Hz_200Hz[0]; /* 原始波形 */
outputF32 = (float32_t *)&testOutput[0]; /* 濾波後輸出波形 */
inputREF = (float32_t *)&testInput_f32_REF[0]; /* 參考波形 */
outputERR = (float32_t *)&test_f32_ERR[0]; /* 誤差資料 */
/* 歸一化LMS初始化 */
arm_lms_norm_init_f32 (&lmsS, /* LMS結構體 */
NUM_TAPS, /* 濾波器系數個數 */
(float32_t *)&lmsCoeffs32[0], /* 濾波 */
&lmsStateF32[0], /* 濾波器系數 */
0.1, /* 步長 */
blockSize); /* 處理的資料個數 */
/* 實作LMS自适應濾波,這裡每次處理1個點 */
for(i=0; i < numBlocks; i++)
{
arm_lms_norm_f32(&lmsS, /* LMS結構體 */
inputF32 + (i * blockSize), /* 輸入資料 */
inputREF + (i * blockSize), /* 輸出資料 */
outputF32 + (i * blockSize), /* 參考資料 */
outputERR + (i * blockSize), /* 誤差資料 */
blockSize); /* 處理的資料個數 */
}
/* 列印濾波後結果 */
for(i=0; i<TEST_LENGTH_SAMPLES; i++)
{
printf("%f, %f, %f\r\n", testInput_f32_50Hz_200Hz[i], outputF32[i], test_f32_ERR[i]);
}
}
下面是濾波因數步長調節為0.1時的濾波器效果,淺藍色是原始波形,黃色黃色是濾波後波形,綠色是誤內插補點:
步長為0.01時效果,可以看到逼近參考波形的速度較慢:
步長為1的效果,逼近參考波形的速度更快,前面的波形由一段陡增。
關于步長,沒有特别好的方式直接鎖定那種步長大小更合适,一般的處理思路是按照10倍關系先鎖定範圍,比如先測試步長為1,0.1,0.001等來測試,然後進一步設定一個合适的值。
49.5.4 濾除白噪聲測試(一)
原始波形由任意波形+ 高斯分布白噪聲 + 均勻分布白噪聲組成,濾除高斯分布白噪聲 + 均勻分布白噪聲。
/*
*********************************************************************************************************
* 函 數 名: arm_lms_f32_test2
* 功能說明: 原始波形由任意波形+ 高斯分布白噪聲 + 均勻分布白噪聲組成,濾除高斯分布白噪聲 + 均勻分布白噪聲。
* 形 參: 無
* 返 回 值: 無
*********************************************************************************************************
*/
void arm_lms_f32_test2(void)
{
uint32_t i;
arm_lms_norm_instance_f32 lmsS;
float32_t *inputF32, *outputF32, *inputREF, *outputERR;
/* 如果是實時性的濾波,僅需清零一次 */
memset(lmsCoeffs32,0,sizeof(lmsCoeffs32));
memset(lmsStateF32,0,sizeof(lmsStateF32));
/* 初始化輸入輸出緩存指針 */
inputF32 = (float32_t *)&MixData[0]; /* 原始波形 */
outputF32 = (float32_t *)&testOutput[0]; /* 濾波後輸出波形 */
inputREF = (float32_t *)&OrigalData[0]; /* 參考波形 */
outputERR = (float32_t *)&test_f32_ERR[0]; /* 誤差資料 */
/* 歸一化LMS初始化 */
arm_lms_norm_init_f32 (&lmsS, /* LMS結構體 */
NUM_TAPS, /* 濾波器系數個數 */
(float32_t *)&lmsCoeffs32[0], /* 濾波 */
&lmsStateF32[0], /* 濾波器系數 */
0.01, /* 步長 */
blockSize); /* 處理的資料個數 */
/* 實作LMS自适應濾波,這裡每次處理1個點 */
for(i=0; i < numBlocks; i++)
{
arm_lms_norm_f32(&lmsS, /* LMS結構體 */
inputF32 + (i * blockSize), /* 輸入資料 */
inputREF + (i * blockSize), /* 輸出資料 */
outputF32 + (i * blockSize), /* 參考資料 */
outputERR + (i * blockSize), /* 誤差資料 */
blockSize); /* 處理的資料個數 */
}
/* 列印濾波後結果 */
for(i=0; i<TEST_LENGTH_SAMPLES; i++)
{
printf("%f, %f, %f\r\n", MixData[i], outputF32[i], test_f32_ERR[i]);
}
}
下面是濾波因數步長調節為0.01時的濾波器效果,淺藍色是原始波形,黃色黃色是濾波後波形,綠色是誤內插補點:
這個波形做了兩個周期,前1024點和後1024點,後面1024點濾除白噪聲的效果已經比較好,而前1024的點的前半段一直在逼近我們設定的參考波形中。另外從誤內插補點波形中,我們可以看到原始波形跳變的地方,誤內插補點也會有一個跳變,然後向0趨近。這是自适應濾波器特性決定的,不斷的調節濾波器系數中。
我們再來看下将濾波因數步長調節為0.1時的效果:
可以看到逼近速度很快,但是逼近效果一般,也就是白噪聲的濾除效果一般。
49.5.5 濾除白噪聲測試(二)
原始波形10Hz正弦波 + 20Hz正弦波 + 30Hz正弦波 + 高斯分布白噪聲 + 均勻分布白噪聲。濾除高斯分布白噪聲 + 均勻分布白噪聲。
/*
*********************************************************************************************************
* 函 數 名: arm_lms_f32_test3
* 功能說明: 10Hz正弦波 + 20Hz正弦波 + 30Hz正弦波 + 高斯分布白噪聲 + 均勻分布白噪聲,濾除高斯分布白噪聲 + 均勻分布白噪聲
* 形 參: 無
* 返 回 值: 無
*********************************************************************************************************
*/
void arm_lms_f32_test3(void)
{
uint32_t i;
arm_lms_norm_instance_f32 lmsS;
float32_t *inputF32, *outputF32, *inputREF, *outputERR;
/* 如果是實時性的濾波,僅需清零一次 */
memset(lmsCoeffs32,0,sizeof(lmsCoeffs32));
memset(lmsStateF32,0,sizeof(lmsStateF32));
/* 初始化輸入輸出緩存指針 */
inputF32 = (float32_t *)&MixData1[0]; /* 原始波形 */
outputF32 = (float32_t *)&testOutput[0]; /* 濾波後輸出波形 */
inputREF = (float32_t *)&OrigalData1[0]; /* 參考波形 */
outputERR = (float32_t *)&test_f32_ERR[0]; /* 誤差資料 */
/* 歸一化LMS初始化 */
arm_lms_norm_init_f32 (&lmsS, /* LMS結構體 */
NUM_TAPS, /* 濾波器系數個數 */
(float32_t *)&lmsCoeffs32[0], /* 濾波 */
&lmsStateF32[0], /* 濾波器系數 */
0.1, /* 步長 */
blockSize); /* 處理的資料個數 */
/* 實作LMS自适應濾波,這裡每次處理1個點 */
for(i=0; i < numBlocks; i++)
{
arm_lms_norm_f32(&lmsS, /* LMS結構體 */
inputF32 + (i * blockSize), /* 輸入資料 */
inputREF + (i * blockSize), /* 輸出資料 */
outputF32 + (i * blockSize), /* 參考資料 */
outputERR + (i * blockSize), /* 誤差資料 */
blockSize); /* 處理的資料個數 */
}
/* 列印濾波後結果 */
for(i=0; i<TEST_LENGTH_SAMPLES; i++)
{
printf("%f, %f, %f\r\n", MixData1[i], outputF32[i], test_f32_ERR[i]);
}
}
配套例子:
V6-234_自适應濾波器實作,無需Matlab生成系數(支援實時濾波)
實驗目的:
- 學習LMS最小均方濾波器。
實驗内容:
- 啟動一個自動重裝軟體定時器,每100ms翻轉一次LED2。
- 按下按鍵K1,列印測試波形1和濾波後的波形資料。
- 按下按鍵K2,列印測試波形2和濾波後的波形資料。
- 按下按鍵K3,列印測試波形3和濾波後的波形資料。
使用AC6注意事項
特别注意附件章節C的問題
上電後序列槽列印的資訊:
波特率 115200,資料位 8,奇偶校驗位無,停止位 1。
RTT方式列印資訊:
程式設計:
系統棧大小配置設定:
硬體外設初始化
硬體外設的初始化是在 bsp.c 檔案實作:
/*
*********************************************************************************************************
* 函 數 名: bsp_Init
* 功能說明: 初始化所有的硬體裝置。該函數配置CPU寄存器和外設的寄存器并初始化一些全局變量。隻需要調用一次
* 形 參:無
* 返 回 值: 無
*********************************************************************************************************
*/
void bsp_Init(void)
{
/*
STM32F429 HAL 庫初始化,此時系統用的還是F429自帶的16MHz,HSI時鐘:
- 調用函數HAL_InitTick,初始化滴答時鐘中斷1ms。
- 設定NVIC優先級分組為4。
*/
HAL_Init();
/*
配置系統時鐘到168MHz
- 切換使用HSE。
- 此函數會更新全局變量SystemCoreClock,并重新配置HAL_InitTick。
*/
SystemClock_Config();
/*
Event Recorder:
- 可用于代碼執行時間測量,MDK5.25及其以上版本才支援,IAR不支援。
- 預設不開啟,如果要使能此選項,務必看V5開發闆使用者手冊第8章
*/
#if Enable_EventRecorder == 1
/* 初始化EventRecorder并開啟 */
EventRecorderInitialize(EventRecordAll, 1U);
EventRecorderStart();
#endif
bsp_InitKey(); /* 按鍵初始化,要放在滴答定時器之前,因為按鈕檢測是通過滴答定時器掃描 */
bsp_InitTimer(); /* 初始化滴答定時器 */
bsp_InitUart(); /* 初始化序列槽 */
bsp_InitExtIO(); /* 初始化擴充IO */
bsp_InitLed(); /* 初始化LED */
}
主功能:
主程式實作如下操作:
- 啟動一個自動重裝軟體定時器,每100ms翻轉一次LED2。
- 按下按鍵K1,列印測試波形1和濾波後的波形資料。
- 按下按鍵K2,列印測試波形2和濾波後的波形資料。
- 按下按鍵K3,列印測試波形3和濾波後的波形資料。
/*
*********************************************************************************************************
* 函 數 名: main
* 功能說明: c程式入口
* 形 參: 無
* 返 回 值: 錯誤代碼(無需處理)
*********************************************************************************************************
*/
int main(void)
{
uint8_t ucKeyCode; /* 按鍵代碼 */
uint16_t i;
bsp_Init(); /* 硬體初始化 */
PrintfLogo(); /* 列印例程資訊到序列槽1 */
PrintfHelp(); /* 列印操作提示資訊 */
bsp_StartAutoTimer(0, 100); /* 啟動1個100ms的自動重裝的定時器 */
/* 進入主程式循環體 */
while (1)
{
bsp_Idle(); /* 這個函數在bsp.c檔案。使用者可以修改這個函數實作CPU休眠和喂狗 */
if (bsp_CheckTimer(0)) /* 判斷定時器逾時時間 */
{
/* 每隔100ms 進來一次 */
bsp_LedToggle(2); /* 翻轉LED的狀态 */
}
ucKeyCode = bsp_GetKey(); /* 讀取鍵值, 無鍵按下時傳回 KEY_NONE = 0 */
if (ucKeyCode != KEY_NONE)
{
switch (ucKeyCode)
{
case KEY_DOWN_K1: /* K1鍵按下 */
arm_lms_f32_test1();
break;
case KEY_DOWN_K2: /* K2鍵按下 */
arm_lms_f32_test2();
break;
case KEY_DOWN_K3: /* K3鍵按下 */
arm_lms_f32_test3();
break;
default:
/* 其它的鍵值不處理 */
break;
}
}
}
}
/*
*********************************************************************************************************
* 函 數 名: bsp_Init
* 功能說明: 初始化所有的硬體裝置。該函數配置CPU寄存器和外設的寄存器并初始化一些全局變量。隻需要調用一次
* 形 參:無
* 返 回 值: 無
*********************************************************************************************************
*/
void bsp_Init(void)
{
/*
STM32F407 HAL 庫初始化,此時系統用的還是F407自帶的16MHz,HSI時鐘:
- 調用函數HAL_InitTick,初始化滴答時鐘中斷1ms。
- 設定NVIC優先級分組為4。
*/
HAL_Init();
/*
配置系統時鐘到168MHz
- 切換使用HSE。
- 此函數會更新全局變量SystemCoreClock,并重新配置HAL_InitTick。
*/
SystemClock_Config();
/*
Event Recorder:
- 可用于代碼執行時間測量,MDK5.25及其以上版本才支援,IAR不支援。
- 預設不開啟,如果要使能此選項,務必看V5開發闆使用者手冊第8章
*/
#if Enable_EventRecorder == 1
/* 初始化EventRecorder并開啟 */
EventRecorderInitialize(EventRecordAll, 1U);
EventRecorderStart();
#endif
bsp_InitKey(); /* 按鍵初始化,要放在滴答定時器之前,因為按鈕檢測是通過滴答定時器掃描 */
bsp_InitTimer(); /* 初始化滴答定時器 */
bsp_InitUart(); /* 初始化序列槽 */
bsp_InitLed(); /* 初始化LED */
}
/*
*********************************************************************************************************
* 函 數 名: main
* 功能說明: c程式入口
* 形 參: 無
* 返 回 值: 錯誤代碼(無需處理)
*********************************************************************************************************
*/
int main(void)
{
uint8_t ucKeyCode; /* 按鍵代碼 */
uint16_t i;
bsp_Init(); /* 硬體初始化 */
PrintfLogo(); /* 列印例程資訊到序列槽1 */
PrintfHelp(); /* 列印操作提示資訊 */
bsp_StartAutoTimer(0, 100); /* 啟動1個100ms的自動重裝的定時器 */
/* 進入主程式循環體 */
while (1)
{
bsp_Idle(); /* 這個函數在bsp.c檔案。使用者可以修改這個函數實作CPU休眠和喂狗 */
if (bsp_CheckTimer(0)) /* 判斷定時器逾時時間 */
{
/* 每隔100ms 進來一次 */
bsp_LedToggle(2); /* 翻轉LED的狀态 */
}
ucKeyCode = bsp_GetKey(); /* 讀取鍵值, 無鍵按下時傳回 KEY_NONE = 0 */
if (ucKeyCode != KEY_NONE)
{
switch (ucKeyCode)
{
case KEY_DOWN_K1: /* K1鍵按下 */
arm_lms_f32_test1();
break;
case KEY_DOWN_K2: /* K2鍵按下 */
arm_lms_f32_test2();
break;
case KEY_DOWN_K3: /* K3鍵按下 */
arm_lms_f32_test3();
break;
default:
/* 其它的鍵值不處理 */
break;
}
}
}
}
本章節主要講解了自适應濾波器,功能比較強勁,熟練應用需要多做測試。
微信公衆号:armfly_com
安富萊論壇:www.armbbs.cn
安富萊淘寶:https://armfly.taobao.com