【STM32H7的DSP教程】第45章 STM32H7的IIR高通濾波器實現(支援逐個資料的實時濾波)
完整版教程下載地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=94547
第45章 STM32H7的IIR高通濾波器實現(支援逐個資料的實時濾波)
本章節講解IIR高通濾波器實現。
45.1 初學者重要提示
45.2 高通濾波器介紹
45.3 IIR濾波器介紹
45.4 Matlab工具箱filterDesigner生成高通濾波器C標頭檔案
45.5 IIR高通濾波器設計
45.6 實驗例程說明(MDK)
45.7 實驗例程說明(IAR)
45.8 總結
45.1 初學者重要提示
1、本章節提供的高通濾波器支援實時濾波,每次可以濾波一個數據,也可以多個數據,不限制大小。但要注意以下兩點:
- 所有資料是在同一個取樣率下依次採集的資料。
- 每次過濾資料個數一旦固定下來,執行中不可再修改。
2、IIR濾波器的群延遲是一個重要的知識點,詳情在本教程第41章有詳細說明。IIR和FIR一樣,也有群延遲問題。
45.2 高通濾波器介紹
允許高頻訊號通過,而減弱低於截止頻率的訊號通過。比如混合訊號含有50Hz + 200Hz訊號,我們可通過高通濾波器,過濾掉50Hz訊號,讓200Hz訊號通過。
45.3 IIR濾波器介紹
ARM官方提供的直接I型IIR庫支援Q7,Q15,Q31和浮點四種資料型別。其中Q15和Q31提供了快速版本。
直接I型IIR濾波器是基於二階Biquad級聯的方式來實現的。每個Biquad由一個二階的濾波器組成:
y[n] = b0 * x[n] + b1 * x[n-1] + b2 * x[n-2] + a1 * y[n-1] + a2 * y[n-2]
直接I型演算法每個階段需要5個係數和4個狀態變數。
這裡有一點要特別的注意,有些濾波器係數生成工具是採用的下面公式實現:
y[n] = b0 * x[n] + b1 * x[n-1] + b2 * x[n-2] - a1 * y[n-1] - a2 * y[n-2]
比如matlab就是使用上面的公式實現的,所以在使用fdatool工具箱生成的a係數需要取反才能用於直接I型IIR濾波器的函式中。
高階IIR濾波器的實現是採用二階Biquad級聯的方式來實現的。其中引數numStages就是用來做指定二階Biquad的個數。比如8階IIR濾波器就可以採用numStages=4個二階Biquad來實現。
如果要實現9階IIR濾波器就需要將numStages=5,這時就需要其中一個Biquad配置成一階濾波器(也就是b2=0,a2=0)。
45.4 Matlab工具箱filterDesigner生成IIR高通濾波器係數
前面介紹FIR濾波器的時候,我們講解了如何使用filterDesigner生成C標頭檔案,從而獲得濾波器係數。這裡不能再使用這種方法了,主要是因為通過C標頭檔案獲取的濾波器係數需要通過ARM官方的IIR函式呼叫多次才能獲得濾波結果,所以我們這裡換另外一種方法。
下面我們講解如何通過filterDesigner工具箱生成濾波器係數。首先在matlab的命令視窗輸入filterDesigner就能開啟這個工具箱:
filterDesigner介面開啟效果如下:
IIR濾波器的低通,高通,帶通,帶阻濾波的設定會在下面一 一講解,這裡說一下設定後相應引數後如何生成濾波器係數。引數設定好以後點選如下按鈕:
點選Design Filter之後,注意左上角生成的濾波器結構:
預設生成的IIR濾波器型別是Direct-Form II, Second-Order Sections(直接II型,每個Section是一個二階濾波器)。這裡我們需要將其轉換成Direct-Form I, Second-Order Sections,因為本章使用的IIR濾波器函式是Direct-Form I的結構。
轉換方法,點選Edit->Convert Structure,介面如下,這裡我們選擇第一項,並點選OK:
轉換好以後再點選File-Export,第一項選擇Coefficient File(ASCII):
第一項選擇好以後,第二項選擇Decimal:
兩個選項都選擇好以後,點選Export進行匯出,匯出後儲存即可:
儲存後Matlab會自動開啟untitled.fcf檔案,可以看到生成的係數:
% Generated by MATLAB(R) 9.4 and Signal Processing Toolbox 8.0. % Generated on: 15-Aug-2021 20:38:33 % Coefficient Format: Decimal % Discrete-Time IIR Filter (real) % ------------------------------- % Filter Structure : Direct-Form I, Second-Order Sections % Number of Sections : 2 % Stable : Yes % Linear Phase : No SOS Matrix: 1 -2 1 1 -0.98454301474115180070612041163258254528 0.544565360850816415627662081533344462514 1 -2 1 1 -0.744714477864321211519893495278665795922 0.168318873843973093595849377379636280239 Scale Values: 0.632277093897992026327870007662568241358 0.478258337927073562401147910350118763745
由於前面選擇的是4階IIR濾波,生成的結果就是由兩組二階IIR濾波係數組成,係數的對應順序如下:
SOS Matrix: 1 2 1 1 -0.98454301474115180070612041163258254528 0.544565360850816415627662081533344462514 b0 b1 b2 a0 a1 a2 1 2 1 1 -0.744714477864321211519893495278665795922 0.168318873843973093595849377379636280239 b0 b1 b2 a0 a1 a2
注意,實際使用ARM官方的IIR函式呼叫的時候要將a1和a2取反。另外下面兩組是每個二階濾波器的增益,濾波後的結果要乘以這兩個增益數值才是實際結果:
0.632277093897992026327870007662568241358 0.478258337927073562401147910350118763745
實際的濾波係數呼叫方法,看下面的例子即可。
45.5 IIR高通濾波器設計
本章使用的IIR濾波器函式是arm_biquad_cascade_df1_f32。使用此函式可以設計IIR低通,高通,帶通和帶阻濾波器
45.5.1 函式arm_biquad_cascade_df1_init_f32
函式原型:
void arm_biquad_cascade_df1_init_f32( arm_biquad_casd_df1_inst_f32 * S, uint8_t numStages, const float32_t * pCoeffs, float32_t * pState)
函式描述:
這個函式用於IIR初始化。
函式引數:
- 第1個引數是arm_biquad_casd_df1_inst_f32型別結構體變數。
- 第2個引數是2階濾波器的個數。
- 第3個引數是濾波器係數地址。
- 第4個引數是緩衝狀態地址。
注意事項:
結構體arm_biquad_casd_df1_inst_f32的定義如下(在檔案filtering_functions.h檔案):
typedef struct { uint32_t numStages; /**< number of 2nd order stages in the filter. Overall order is 2*numStages. */ float32_t *pState; /**< Points to the array of state coefficients. The array is of length 4*numStages. */ const float32_t *pCoeffs; /**< Points to the array of coefficients. The array is of length 5*numStages */ } arm_biquad_casd_df1_inst_f32;
- numStages表示二階濾波器的個數,總階數是2*numStages。
- pState指向狀態變數陣列,這個陣列用於函式內部計算資料的快取,總大小4*numStages。
- 引數pCoeffs指向濾波因數,濾波因數陣列長度為5*numStages。但要注意pCoeffs指向的濾波因數應該按照如下的逆序進行排列:
{b10, b11, b12, a11, a12, b20, b21, b22, a21, a22, ...}
先放第一個二階Biquad係數,然後放第二個,以此類推。
45.5.2 函式arm_biquad_cascade_df1_f32
函式定義如下:
void arm_biquad_cascade_df1_f32( const arm_biquad_casd_df1_inst_f32 * S, float32_t * pSrc, float32_t * pDst, uint32_t blockSize)
函式描述:
這個函式用於IIR濾波。
函式引數:
- 第1個引數是arm_biquad_casd_df1_inst_f32型別結構體變數。
- 第2個引數是源資料地址。
- 第3個引數是濾波後的資料地址。
- 第4個引數是每次呼叫處理的資料個數,最小可以每次處理1個數據,最大可以每次全部處理完。
45.5.3 filterDesigner獲取高通濾波器係數
設計一個如下的例子:
訊號由50Hz正弦波和200Hz正弦波組成,取樣率1Kbps,現設計一個巴特沃斯濾波器高通濾波器,採用直接I型,截止頻率140Hz,取樣400個數據,濾波器階數設定為4。filterDesigner的配置如下:
配置好高通濾波器後,具體濾波器係數的生成大家參考本章第4小節的方法即可。
45.5.4 高通濾波器實現
通過工具箱filterDesigner獲得高通濾波器係數後在開發板上執行函式arm_biquad_cascade_df1_f32來測試低通濾波器的效果。
#define numStages 2 /* 2階IIR濾波的個數 */ #define TEST_LENGTH_SAMPLES 400 /* 取樣點數 */ #define BLOCK_SIZE 1 /* 呼叫一次arm_biquad_cascade_df1_f32處理的取樣點個數 */ uint32_t blockSize = BLOCK_SIZE; uint32_t numBlocks = TEST_LENGTH_SAMPLES/BLOCK_SIZE; /* 需要呼叫arm_biquad_cascade_df1_f32的次數 */ static float32_t testInput_f32_50Hz_200Hz[TEST_LENGTH_SAMPLES]; /* 取樣點 */ static float32_t testOutput[TEST_LENGTH_SAMPLES]; /* 濾波後的輸出 */ static float32_t IIRStateF32[4*numStages]; /* 狀態快取 */ /* 巴特沃斯高通濾波器係數 140Hz */ const float32_t IIRCoeffs32HP[5*numStages] = { 1.0f, -2.0f, 1.0f, 0.98454301474115180070612041163258254528f, -0.544565360850816415627662081533344462514f, 1.0f, -2.0f, 1.0f, 0.744714477864321211519893495278665795922f, -0.168318873843973093595849377379636280239 }; /* ********************************************************************************************************* * 函 數 名: arm_iir_f32_hp * 功能說明: 呼叫函式arm_iir_f32_hp實現高通濾波器 * 形 參:無 * 返 回 值: 無 ********************************************************************************************************* */ static void arm_iir_f32_hp(void) { uint32_t i; arm_biquad_casd_df1_inst_f32 S; float32_t ScaleValue; float32_t *inputF32, *outputF32; /* 初始化輸入輸出快取指標 */ inputF32 = &testInput_f32_50Hz_200Hz[0]; outputF32 = &testOutput[0]; /* 初始化 */ arm_biquad_cascade_df1_init_f32(&S, numStages, (float32_t *)&IIRCoeffs32HP[0], (float32_t *)&IIRStateF32[0]); /* 實現IIR濾波,這裡每次處理1個點 */ for(i=0; i < numBlocks; i++) { arm_biquad_cascade_df1_f32(&S, inputF32 + (i * blockSize), outputF32 + (i * blockSize), blockSize); } /*放縮係數 */ ScaleValue = 0.632277093897992026327870007662568241358f * 0.478258337927073562401147910350118763745f; /* 列印濾波後結果 */ for(i=0; i<TEST_LENGTH_SAMPLES; i++) { printf("%f, %f\r\n", testInput_f32_50Hz_200Hz[i], testOutput[i]*ScaleValue); } }
執行如上函式可以通過串列埠打印出函式arm_biquad_cascade_df1_f32濾波後的波形資料,下面通過Matlab繪製波形來對比Matlab計算的結果和ARM官方庫計算的結果。
對比前需要先將串列埠打印出的一組資料載入到Matlab中, arm_biquad_cascade_df1_f32的計算結果起名sampledata,載入方法在第13章13.6小結已經講解,這裡不做贅述了。Matlab中執行的程式碼如下:
fs=1000; %設定取樣頻率 1K N=400; %取樣點數 n=0:N-1; t=n/fs; %時間序列 f=n*fs/N; %頻率序列 x1=sin(2*pi*50*t); x2=sin(2*pi*200*t); %50Hz和200Hz正弦波 subplot(211); plot(t, x2); title('濾波後的理想波形'); grid on; subplot(212); plot(t, sampledata); title('ARM官方庫濾波後的波形'); grid on;
Matlab計算結果如下:
從上面的波形對比來看,matlab和函式arm_biquad_cascade_df1_f32計算的結果基本是一致的。為了更好的說明濾波效果,下面從頻域的角度來說明這個問題,Matlab上面執行如下程式碼:
fs=1000; %設定取樣頻率 1K N=400; %取樣點數 n=0:N-1; t=n/fs; %時間序列 f=n*fs/N; %頻率序列 x = sin(2*pi*50*t) + sin(2*pi*200*t); %50Hz和200Hz正弦波合成 subplot(211); y=fft(x, N); %對訊號x做FFT plot(f,abs(y)); xlabel('頻率/Hz'); ylabel('振幅'); title('原始訊號FFT'); grid on; y3=fft(sampledata, N); %經過IIR濾波器後得到的訊號做FFT subplot(212); plot(f,abs(y3)); xlabel('頻率/Hz'); ylabel('振幅'); title('IIR濾波後訊號FFT'); grid on;
Matlab計算結果如下:
上面波形變換前的FFT和變換後FFT可以看出,50Hz的正弦波基本被濾除。
45.6 實驗例程說明(MDK)
配套例子:
V7-230_IIR高通濾波器(支援逐點實時濾波)
實驗目的:
- 學習IIR高通濾波器的實現,支援實時濾波
實驗內容:
- 啟動一個自動重灌軟體定時器,每100ms翻轉一次LED2。
- 按下按鍵K1,列印原始波形資料和濾波後的波形資料。
使用AC6注意事項
特別注意附件章節C的問題
上電後串列埠列印的資訊:
波特率 115200,資料位 8,奇偶校驗位無,停止位 1。
RTT方式列印資訊:
程式設計:
系統棧大小分配:
RAM空間用的DTCM:
硬體外設初始化
硬體外設的初始化是在 bsp.c 檔案實現:
/* ********************************************************************************************************* * 函 數 名: bsp_Init * 功能說明: 初始化所有的硬體裝置。該函式配置CPU暫存器和外設的暫存器並初始化一些全域性變數。只需要呼叫一次 * 形 參:無 * 返 回 值: 無 ********************************************************************************************************* */ void bsp_Init(void) { /* 配置MPU */ MPU_Config(); /* 使能L1 Cache */ CPU_CACHE_Enable(); /* STM32H7xx HAL 庫初始化,此時系統用的還是H7自帶的64MHz,HSI時鐘: - 呼叫函式HAL_InitTick,初始化滴答時鐘中斷1ms。 - 設定NVIC優先順序分組為4。 */ HAL_Init(); /* 配置系統時鐘到400MHz - 切換使用HSE。 - 此函式會更新全域性變數SystemCoreClock,並重新配置HAL_InitTick。 */ SystemClock_Config(); /* Event Recorder: - 可用於程式碼執行時間測量,MDK5.25及其以上版本才支援,IAR不支援。 - 預設不開啟,如果要使能此選項,務必看V7開發板使用者手冊第8章 */ #if Enable_EventRecorder == 1 /* 初始化EventRecorder並開啟 */ EventRecorderInitialize(EventRecordAll, 1U); EventRecorderStart(); #endif bsp_InitKey(); /* 按鍵初始化,要放在滴答定時器之前,因為按鈕檢測是通過滴答定時器掃描 */ bsp_InitTimer(); /* 初始化滴答定時器 */ bsp_InitUart(); /* 初始化串列埠 */ bsp_InitExtIO(); /* 初始化FMC匯流排74HC574擴充套件IO. 必須在 bsp_InitLed()前執行 */ bsp_InitLed(); /* 初始化LED */ }
MPU配置和Cache配置:
資料Cache和指令Cache都開啟。配置了AXI SRAM區(本例子未用到AXI SRAM),FMC的擴充套件IO區。
/* ********************************************************************************************************* * 函 數 名: MPU_Config * 功能說明: 配置MPU * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ static void MPU_Config( void ) { MPU_Region_InitTypeDef MPU_InitStruct; /* 禁止 MPU */ HAL_MPU_Disable(); /* 配置AXI SRAM的MPU屬性為關閉讀Cache和寫Cache */ MPU_InitStruct.Enable = MPU_REGION_ENABLE; MPU_InitStruct.BaseAddress = 0x24000000; MPU_InitStruct.Size = MPU_REGION_SIZE_512KB; MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT _BUFFERABLE; MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT _CACHEABLE; MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; MPU_InitStruct.Number = MPU_REGION_NUMBER0; MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0; MPU_InitStruct.SubRegionDisable = 0x00; MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE; HAL_MPU_ConfigRegion(&MPU_InitStruct); /* 配置FMC擴充套件IO的MPU屬性為Device或者Strongly Ordered */ MPU_InitStruct.Enable = MPU_REGION_ENABLE; MPU_InitStruct.BaseAddress = 0x60000000; MPU_InitStruct.Size = ARM_MPU_REGION_SIZE_64KB; MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; MPU_InitStruct.Number = MPU_REGION_NUMBER1; MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0; MPU_InitStruct.SubRegionDisable = 0x00; MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE; HAL_MPU_ConfigRegion(&MPU_InitStruct); /*使能 MPU */ HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT); } /* ********************************************************************************************************* * 函 數 名: CPU_CACHE_Enable * 功能說明: 使能L1 Cache * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ static void CPU_CACHE_Enable(void) { /* 使能 I-Cache */ SCB_EnableICache(); /* 使能 D-Cache */ SCB_EnableDCache(); }
主功能:
主程式實現如下操作:
- 啟動一個自動重灌軟體定時器,每100ms翻轉一次LED2。
- 按下按鍵K1,列印原始波形資料和濾波後的波形資料。
/* ********************************************************************************************************* * 函 數 名: main * 功能說明: c程式入口 * 形 參: 無 * 返 回 值: 錯誤程式碼(無需處理) ********************************************************************************************************* */ int main(void) { uint8_t ucKeyCode; /* 按鍵程式碼 */ uint16_t i; bsp_Init(); /* 硬體初始化 */ PrintfLogo(); /* 列印例程資訊到串列埠1 */ PrintfHelp(); /* 列印操作提示資訊 */ 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); } 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_iir_f32_hp(); break; default: /* 其它的鍵值不處理 */ break; } } } }
45.7 實驗例程說明(IAR)
配套例子:
V7-230_IIR高通濾波器(支援逐點實時濾波)
實驗目的:
- 學習IIR高通濾波器的實現,支援實時濾波
實驗內容:
- 啟動一個自動重灌軟體定時器,每100ms翻轉一次LED2。
- 按下按鍵K1,列印原始波形資料和濾波後的波形資料。
上電後串列埠列印的資訊:
波特率 115200,資料位 8,奇偶校驗位無,停止位 1。
RTT方式列印資訊:
程式設計:
系統棧大小分配:
RAM空間用的DTCM:
硬體外設初始化
硬體外設的初始化是在 bsp.c 檔案實現:
/* ********************************************************************************************************* * 函 數 名: bsp_Init * 功能說明: 初始化所有的硬體裝置。該函式配置CPU暫存器和外設的暫存器並初始化一些全域性變數。只需要呼叫一次 * 形 參:無 * 返 回 值: 無 ********************************************************************************************************* */ void bsp_Init(void) { /* 配置MPU */ MPU_Config(); /* 使能L1 Cache */ CPU_CACHE_Enable(); /* STM32H7xx HAL 庫初始化,此時系統用的還是H7自帶的64MHz,HSI時鐘: - 呼叫函式HAL_InitTick,初始化滴答時鐘中斷1ms。 - 設定NVIC優先順序分組為4。 */ HAL_Init(); /* 配置系統時鐘到400MHz - 切換使用HSE。 - 此函式會更新全域性變數SystemCoreClock,並重新配置HAL_InitTick。 */ SystemClock_Config(); /* Event Recorder: - 可用於程式碼執行時間測量,MDK5.25及其以上版本才支援,IAR不支援。 - 預設不開啟,如果要使能此選項,務必看V7開發板使用者手冊第8章 */ #if Enable_EventRecorder == 1 /* 初始化EventRecorder並開啟 */ EventRecorderInitialize(EventRecordAll, 1U); EventRecorderStart(); #endif bsp_InitKey(); /* 按鍵初始化,要放在滴答定時器之前,因為按鈕檢測是通過滴答定時器掃描 */ bsp_InitTimer(); /* 初始化滴答定時器 */ bsp_InitUart(); /* 初始化串列埠 */ bsp_InitExtIO(); /* 初始化FMC匯流排74HC574擴充套件IO. 必須在 bsp_InitLed()前執行 */ bsp_InitLed(); /* 初始化LED */ }
MPU配置和Cache配置:
資料Cache和指令Cache都開啟。配置了AXI SRAM區(本例子未用到AXI SRAM),FMC的擴充套件IO區。
/* ********************************************************************************************************* * 函 數 名: MPU_Config * 功能說明: 配置MPU * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ static void MPU_Config( void ) { MPU_Region_InitTypeDef MPU_InitStruct; /* 禁止 MPU */ HAL_MPU_Disable(); /* 配置AXI SRAM的MPU屬性為Write back, Read allocate,Write allocate */ MPU_InitStruct.Enable = MPU_REGION_ENABLE; MPU_InitStruct.BaseAddress = 0x24000000; MPU_InitStruct.Size = MPU_REGION_SIZE_512KB; MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE; MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; MPU_InitStruct.Number = MPU_REGION_NUMBER0; MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1; MPU_InitStruct.SubRegionDisable = 0x00; MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE; HAL_MPU_ConfigRegion(&MPU_InitStruct); /* 配置FMC擴充套件IO的MPU屬性為Device或者Strongly Ordered */ MPU_InitStruct.Enable = MPU_REGION_ENABLE; MPU_InitStruct.BaseAddress = 0x60000000; MPU_InitStruct.Size = ARM_MPU_REGION_SIZE_64KB; MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; MPU_InitStruct.Number = MPU_REGION_NUMBER1; MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0; MPU_InitStruct.SubRegionDisable = 0x00; MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE; HAL_MPU_ConfigRegion(&MPU_InitStruct); /*使能 MPU */ HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT); } /* ********************************************************************************************************* * 函 數 名: CPU_CACHE_Enable * 功能說明: 使能L1 Cache * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ static void CPU_CACHE_Enable(void) { /* 使能 I-Cache */ SCB_EnableICache(); /* 使能 D-Cache */ SCB_EnableDCache(); }
主功能:
主程式實現如下操作:
- 啟動一個自動重灌軟體定時器,每100ms翻轉一次LED2。
- 按下按鍵K1,列印原始波形資料和濾波後的波形資料。
/* ********************************************************************************************************* * 函 數 名: main * 功能說明: c程式入口 * 形 參: 無 * 返 回 值: 錯誤程式碼(無需處理) ********************************************************************************************************* */ int main(void) { uint8_t ucKeyCode; /* 按鍵程式碼 */ uint16_t i; bsp_Init(); /* 硬體初始化 */ PrintfLogo(); /* 列印例程資訊到串列埠1 */ PrintfHelp(); /* 列印操作提示資訊 */ 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); } 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_iir_f32_hp(); break; default: /* 其它的鍵值不處理 */ break; } } } }
45.8 總結
本章節主要講解了IIR濾波器的高通實現,同時一定要注意IIR濾波器的群延遲問題,詳見本教程的第41章。
微信公眾號:armfly_com 安富萊論壇:www.armbbs.cn 安富萊淘寶:https://armfly.taobao.com