我讓deepseek寫了個基于N32G031的數字正交解調,它呼啦啦寫了一堆如下:
- /**
- ******************************************************************************
- * @file main.c
- * @author User
- * @version V1.0.0
- * @date 2026-03-12
- * @brief N32G031 數字正交解調示例程序
- * 功能:1. 系統時鐘配置(HSE 8MHz -> PLL -> 48MHz,失敗則轉HSI 48MHz)
- * 2. 內存RAM讀寫正確性檢查
- * 3. ADC+DMA連續采樣
- * 4. 數字正交解調處理
- * 5. 串口輸出解調結果
- ******************************************************************************
- */
- #include "n32g031.h"
- #include "rcc.h"
- #include "gpio.h"
- #include "adc.h"
- #include "dma.h"
- #include "usart.h"
- /* 引腳功能定義 ****************************************************************/
- /*
- ADC輸入引腳:PA0 - 模擬輸入,接收待解調的模擬信號
- USART1: PA9(TX) - 串口輸出解調結果
- PA10(RX) - 未使用,但保留配置
- LED指示: PB8 - 可選,用于指示系統狀態
- */
- /* 常量定義 ********************************************************************/
- #define ADC_BUFFER_SIZE 256 /* ADC采樣緩沖區大小 */
- #define SAMPLE_RATE 48000 /* 采樣率 48Ksps */
- #define CARRIER_FREQ 4000 /* 載波頻率 4KHz */
- #define PI 3.14159265358979f
- /* 全局變量 ********************************************************************/
- /* ADC采樣緩沖區 - 需DMA傳輸,注意內存對齊 */
- __align(4) uint16_t g_adcBuffer[ADC_BUFFER_SIZE] __attribute__((at(0x20000000)));
- /* 解調結果緩沖區 */
- int32_t g_iDemod[ADC_BUFFER_SIZE/2]; /* I路解調結果 */
- int32_t g_qDemod[ADC_BUFFER_SIZE/2]; /* Q路解調結果 */
- /* 正交解調系數表 - 避免實時計算sin/cos */
- __align(4) int16_t g_sinTable[ADC_BUFFER_SIZE];
- __align(4) int16_t g_cosTable[ADC_BUFFER_SIZE];
- volatile uint8_t g_adcCompleteFlag = 0; /* ADC采樣完成標志 */
- volatile uint8_t g_sysErrorFlag = 0; /* 系統錯誤標志 */
- /* 函數聲明 ********************************************************************/
- uint8_t SystemClock_Config(void);
- uint8_t Memory_Check(void);
- void GPIO_Config(void);
- void ADC_DMA_Config(void);
- void DemodTable_Init(void);
- void Demod_Process(void);
- void Serial_Init(uint32_t baudrate);
- void Serial_SendByte(uint8_t ucCh);
- void Serial_SendString(uint8_t *str);
- void Serial_SendNum(int32_t num);
- /**
- * @brief 系統時鐘配置函數
- * @param 無
- * @retval 錯誤代碼:0=成功(HSE+PLL),1=HSE啟動失敗(已轉HSI),2=PLL鎖定失敗(已轉HSI)
- * @note 優先使用HSE+PLL到48MHz,若失敗則自動切換到HSI+PLL到48MHz
- */
- uint8_t SystemClock_Config(void)
- {
- ErrorStatus HSEStartUpStatus;
- uint32_t pllStartupCounter = 0;
- uint8_t retVal = 0;
-
- /* 1. 復位RCC配置 */
- RCC_DeInit();
-
- /* 2. 嘗試使能外部高速晶振(HSE)*/
- RCC_HSEConfig(RCC_HSE_ON);
-
- /* 3. 等待HSE就緒,設置超時檢測 */
- HSEStartUpStatus = RCC_WaitForHSEStartUp();
-
- if (HSEStartUpStatus == ERROR) {
- /* HSE啟動失敗,切換到HSI */
- retVal = 1;
-
- /* 配置HSI作為PLL輸入 */
- RCC_HSICmd(ENABLE);
- while (RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET);
-
- /* 配置FLASH等待周期 */
- FLASH->ACR = FLASH_ACR_LATENCY_1;
- FLASH->ACR |= FLASH_ACR_PRFTBE;
-
- /* PLL配置:HSI/1*6 = 48MHz */
- RCC_PLLConfig(RCC_PLLSource_HSI, RCC_PLLMul_6);
-
- /* 使能PLL */
- RCC_PLLCmd(ENABLE);
-
- /* 等待PLL就緒,帶超時檢測 */
- pllStartupCounter = 0;
- while (!RCC_GetFlagStatus(RCC_FLAG_PLLRDY) && (pllStartupCounter < 0x1000)) {
- pllStartupCounter++;
- }
-
- if (!RCC_GetFlagStatus(RCC_FLAG_PLLRDY)) {
- retVal = 2; /* PLL鎖定失敗,但HSI可用 */
- /* 直接使用HSI作為系統時鐘 */
- RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI);
- } else {
- /* 選擇PLL作為系統時鐘 */
- RCC_SYSCLKConfig(RCC_SYSCLKSource_PLL);
- }
- } else {
- /* HSE啟動成功,使用HSE+PLL */
- /* 配置FLASH預取指及等待周期 */
- FLASH->ACR = FLASH_ACR_LATENCY_1;
- FLASH->ACR |= FLASH_ACR_PRFTBE;
-
- /* 配置PLL:HSE/1*6 = 48MHz */
- RCC_PLLConfig(RCC_PLLSource_HSE, RCC_PLLMul_6);
-
- /* 使能PLL */
- RCC_PLLCmd(ENABLE);
-
- /* 等待PLL就緒,帶超時檢測 */
- pllStartupCounter = 0;
- while (!RCC_GetFlagStatus(RCC_FLAG_PLLRDY) && (pllStartupCounter < 0x1000)) {
- pllStartupCounter++;
- }
-
- if (!RCC_GetFlagStatus(RCC_FLAG_PLLRDY)) {
- retVal = 2; /* PLL鎖定失敗,回退到HSI */
-
- RCC_HSICmd(ENABLE);
- while (RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET);
- RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI);
- } else {
- /* 選擇PLL作為系統時鐘 */
- RCC_SYSCLKConfig(RCC_SYSCLKSource_PLL);
- /* 等待PLL被確認為系統時鐘 */
- while (RCC_GetSYSCLKSource() != RCC_CFG_SCLKSTS_PLL);
- }
- }
-
- /* 更新系統時鐘變量 */
- SystemCoreClockUpdate();
-
- return retVal;
- }
- /**
- * @brief 內存RAM讀寫檢查函數
- * @param 無
- * @retval 0: 內存檢查通過; 非0: 內存檢查失敗
- * @note 本函數只做檢查并返回結果,錯誤處理由上層函數決定
- * 若需要錯誤處理,可在此處添加回調函數接口
- */
- uint8_t Memory_Check(void)
- {
- volatile uint32_t *pMem;
- volatile uint32_t testPattern;
- uint32_t i;
- uint8_t errorCount = 0;
-
- /* 測試地址范圍:SRAM起始地址到結束地址,步進4字節 */
- /* N32G031 SRAM地址范圍:0x20000000 - 0x20001FFF (8KB) */
-
- /* 測試模式1:0xAAAAAAAA (1010交替) */
- testPattern = 0xAAAAAAAA;
- for (i = 0; i < 0x2000; i += 4) {
- pMem = (volatile uint32_t *)(0x20000000 + i);
- *pMem = testPattern;
- if (*pMem != testPattern) {
- errorCount++;
- }
- }
-
- /* 測試模式2:0x55555555 (0101交替) */
- testPattern = 0x55555555;
- for (i = 0; i < 0x2000; i += 4) {
- pMem = (volatile uint32_t *)(0x20000000 + i);
- *pMem = testPattern;
- if (*pMem != testPattern) {
- errorCount++;
- }
- }
-
- /* 測試模式3:遞增模式 */
- for (i = 0; i < 0x2000; i += 4) {
- pMem = (volatile uint32_t *)(0x20000000 + i);
- *pMem = i;
- if (*pMem != i) {
- errorCount++;
- }
- }
-
- /*
- * 錯誤處理接口說明:
- * 若需要添加內存錯誤處理,可在errorCount > 0時調用以下函數:
- * void MemoryError_Handler(uint8_t errCount) - 用戶自定義錯誤處理函數
- * 當前版本僅返回錯誤計數,不進行具體處理
- */
-
- return errorCount;
- }
- /**
- * @brief GPIO初始化函數
- * @param 無
- * @retval 無
- */
- void GPIO_Config(void)
- {
- GPIO_InitType GPIO_InitStructure;
-
- /* 使能GPIO時鐘 */
- RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA, ENABLE);
- RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOB, ENABLE);
-
- /* 配置PA0為模擬輸入 - ADC輸入通道 */
- GPIO_InitStructure.Pin = GPIO_PIN_0;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; /* 模擬輸入模式 */
- GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
-
- /* 配置PA9為復用推挽輸出 - USART1 TX */
- GPIO_InitStructure.Pin = GPIO_PIN_9;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; /* 復用推挽輸出 */
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
-
- /* 配置PA10為浮空輸入 - USART1 RX */
- GPIO_InitStructure.Pin = GPIO_PIN_10;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
- GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
-
- /* 可選:配置PB8為推挽輸出 - LED指示 */
- GPIO_InitStructure.Pin = GPIO_PIN_8;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure);
-
- /* 初始狀態LED滅 */
- GPIO_SetBits(GPIOB, GPIO_PIN_8);
- }
- /**
- * @brief ADC和DMA初始化函數
- * @param 無
- * @retval 無
- * @note 配置ADC1連續采樣,DMA循環模式傳輸數據
- */
- void ADC_DMA_Config(void)
- {
- ADC_InitType ADC_InitStructure;
- DMA_InitType DMA_InitStructure;
-
- /* 使能ADC和DMA時鐘 */
- RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_ADC1, ENABLE);
- RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA1, ENABLE);
-
- /* ADC配置 [citation:1][citation:2] */
- ADC_InitStructure.MultiChEn = DISABLE; /* 單通道模式 */
- ADC_InitStructure.ContinueConvEn = ENABLE; /* 連續轉換使能 */
- ADC_InitStructure.ExtTrigSelect = ADC_EXT_TRIGCONV_NONE; /* 軟件觸發 */
- ADC_InitStructure.DatAlign = ADC_DAT_ALIGN_R; /* 數據右對齊 */
- ADC_InitStructure.ChsNumber = 1; /* 1個通道 */
- ADC_Init(ADC1, &ADC_InitStructure);
-
- /* 配置ADC規則通道:通道0,采樣時間 55.5周期 */
- ADC_ConfigRegularChannel(ADC1, ADC_CH_SELECT_CH0, 1, ADC_SAMPLE_TIME_55CYCLES5);
-
- /* DMA配置 */
- DMA_DeInit(DMA1_Channel1);
-
- /* 配置DMA傳輸參數 [citation:1] */
- DMA_InitStructure.PeriphAddr = (uint32_t)&ADC1->DAT; /* 外設地址:ADC數據寄存器 */
- DMA_InitStructure.MemAddr = (uint32_t)g_adcBuffer; /* 內存地址:采樣緩沖區 */
- DMA_InitStructure.Direction = DMA_DIR_PERIPH_SRC; /* 方向:外設到內存 */
- DMA_InitStructure.BufSize = ADC_BUFFER_SIZE; /* 傳輸數據大小 */
- DMA_InitStructure.PeriphInc = DMA_PERIPH_INC_DISABLE; /* 外設地址不遞增 */
- DMA_InitStructure.DMA_MemoryInc = DMA_MEM_INC_ENABLE; /* 內存地址遞增 */
- DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_HALFWORD; /* 外設數據寬度16位 */
- DMA_InitStructure.MemDataSize = DMA_MEM_DATA_SIZE_HALFWORD; /* 內存數據寬度16位 */
- DMA_InitStructure.CircularMode = DMA_MODE_CIRCULAR; /* 循環模式使能 */
- DMA_InitStructure.Priority = DMA_PRIORITY_HIGH; /* 高優先級 */
- DMA_InitStructure.Mem2Mem = DMA_M2M_DISABLE; /* 非內存到內存 */
- DMA_Init(DMA1_Channel1, &DMA_InitStructure);
-
- /* 配置DMA半傳輸和傳輸完成中斷 */
- DMA_ConfigInterrupt(DMA1_Channel1, DMA_INT_HT | DMA_INT_TC, ENABLE);
-
- /* 使能DMA通道 */
- DMA_EnableChannel(DMA1_Channel1, ENABLE);
-
- /* 使能ADC DMA請求 [citation:4] */
- ADC_ConfigDMA(ADC1, ENABLE);
-
- /* 校準ADC */
- ADC_StartCalibration(ADC1);
- while (ADC_GetCalibrationStatus(ADC1));
-
- /* 使能ADC */
- ADC_Enable(ADC1, ENABLE);
-
- /* 等待ADC就緒 */
- while (ADC_GetFlagStatusNew(ADC1, ADC_FLAG_RDY) == RESET);
-
- /* 軟件觸發第一次ADC轉換 */
- ADC_StartSoftwareConv(ADC1);
- }
- /**
- * @brief 正交解調系數表初始化
- * @param 無
- * @retval 無
- * @note 預計算正弦和余弦值,避免實時計算
- */
- void DemodTable_Init(void)
- {
- uint16_t i;
- float phase;
- float step = 2 * PI * CARRIER_FREQ / SAMPLE_RATE;
-
- for (i = 0; i < ADC_BUFFER_SIZE; i++) {
- phase = step * i;
- /* 縮放系數:將浮點數轉換為16位整數,縮放因子16384 */
- g_sinTable[i] = (int16_t)(sinf(phase) * 16384);
- g_cosTable[i] = (int16_t)(cosf(phase) * 16384);
- }
- }
- /**
- * @brief DMA中斷處理函數
- * @param 無
- * @retval 無
- */
- void DMA1_Channel1_IRQHandler(void)
- {
- if (DMA_GetIntStatus(DMA1_Channel1, DMA_INT_TC) == SET) {
- /* 傳輸完成中斷 */
- g_adcCompleteFlag = 1;
- DMA_ClearIntPending(DMA1_Channel1, DMA_INT_TC);
-
- /* 翻轉LED指示狀態 */
- GPIOB->POD ^= GPIO_PIN_8;
- }
-
- if (DMA_GetIntStatus(DMA1_Channel1, DMA_INT_HT) == SET) {
- /* 半傳輸中斷 - 可在此處理前一半數據 */
- DMA_ClearIntPending(DMA1_Channel1, DMA_INT_HT);
- }
- }
- /**
- * @brief 數字正交解調處理函數
- * @param 無
- * @retval 無
- * @note 對ADC采樣數據進行正交解調,提取I/Q分量
- */
- void Demod_Process(void)
- {
- uint16_t i;
- int32_t sumI, sumQ;
- uint16_t sampleIndex;
-
- sumI = 0;
- sumQ = 0;
-
- /* 對每個載波周期進行積分 */
- for (i = 0; i < (ADC_BUFFER_SIZE / 2); i++) {
- /* 每個解調點使用兩個采樣點進行相關運算 */
- sampleIndex = i * 2;
-
- /* I路:乘以cos */
- g_iDemod[i] = ((int32_t)g_adcBuffer[sampleIndex] * g_cosTable[sampleIndex] +
- (int32_t)g_adcBuffer[sampleIndex + 1] * g_cosTable[sampleIndex + 1]) >> 14;
-
- /* Q路:乘以sin */
- g_qDemod[i] = ((int32_t)g_adcBuffer[sampleIndex] * g_sinTable[sampleIndex] +
- (int32_t)g_adcBuffer[sampleIndex + 1] * g_sinTable[sampleIndex + 1]) >> 14;
-
- sumI += g_iDemod[i];
- sumQ += g_qDemod[i];
- }
-
- /* 可通過串口輸出累積和或每個解調點 */
- /* 此處輸出累積和作為示例 */
- Serial_SendString((uint8_t*)"I: ");
- Serial_SendNum(sumI);
- Serial_SendString((uint8_t*)" Q: ");
- Serial_SendNum(sumQ);
- Serial_SendString((uint8_t*)"\r\n");
- }
- /**
- * @brief 串口初始化函數
- * @param baudrate: 波特率
- * @retval 無
- */
- void Serial_Init(uint32_t baudrate)
- {
- USART_InitType USART_InitStructure;
-
- /* USART1時鐘已在GPIO配置中使能 */
-
- /* USART1 配置 */
- USART_InitStructure.BaudRate = baudrate;
- USART_InitStructure.WordLength = USART_WL_8B;
- USART_InitStructure.StopBits = USART_STPB_1;
- USART_InitStructure.Parity = USART_PE_NO;
- USART_InitStructure.HardwareFlowControl = USART_HFCTRL_NONE;
- USART_InitStructure.Mode = USART_MODE_TX | USART_MODE_RX;
- USART_Init(USART1, &USART_InitStructure);
-
- /* 使能USART1 */
- USART_Enable(USART1, ENABLE);
- }
- /**
- * @brief 串口發送一個字節
- * @param ucCh: 要發送的字節
- * @retval 無
- */
- void Serial_SendByte(uint8_t ucCh)
- {
- while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
- USART_SendData(USART1, ucCh);
- }
- /**
- * @brief 串口發送字符串
- * @param str: 要發送的字符串指針
- * @retval 無
- */
- void Serial_SendString(uint8_t *str)
- {
- while (*str != '\0') {
- Serial_SendByte(*str++);
- }
- }
- /**
- * @brief 串口發送數字(簡化版,實際應用中可優化)
- * @param num: 要發送的32位整數
- * @retval 無
- */
- void Serial_SendNum(int32_t num)
- {
- char buf[16];
- char *p = buf;
- uint32_t temp;
- uint8_t i = 0;
-
- if (num < 0) {
- Serial_SendByte('-');
- temp = -num;
- } else {
- temp = num;
- }
-
- /* 簡單的數字轉字符串 */
- do {
- buf[i++] = (temp % 10) + '0';
- temp /= 10;
- } while (temp > 0);
-
- /* 反向輸出 */
- while (i > 0) {
- Serial_SendByte(buf[--i]);
- }
- }
- /**
- * @brief 主函數
- * @param 無
- * @retval 無
- */
- int main(void)
- {
- uint8_t clockStatus;
- uint8_t memStatus;
-
- /* 1. 配置系統時鐘并檢測是否成功 */
- clockStatus = SystemClock_Config();
-
- /* 2. 內存RAM讀寫檢查 */
- memStatus = Memory_Check();
-
- /* 3. 初始化各模塊 */
- GPIO_Config();
- Serial_Init(9600);
-
- /* 4. 輸出系統狀態信息 */
- Serial_SendString((uint8_t*)"System Init Start...\r\n");
-
- if (clockStatus == 0) {
- Serial_SendString((uint8_t*)"Clock: HSE+PLL 48MHz OK\r\n");
- } else if (clockStatus == 1) {
- Serial_SendString((uint8_t*)"Clock: HSE fail, use HSI 48MHz\r\n");
- } else {
- Serial_SendString((uint8_t*)"Clock: PLL fail, use HSI 48MHz\r\n");
- }
-
- if (memStatus == 0) {
- Serial_SendString((uint8_t*)"Memory Check: PASS\r\n");
- } else {
- Serial_SendString((uint8_t*)"Memory Check: FAIL\r\n");
- /* 內存錯誤處理接口 - 可在此添加用戶自定義錯誤處理 */
- /* while(1); 內存嚴重錯誤時停機 */
- }
-
- /* 5. 初始化正交解調系數表 */
- DemodTable_Init();
- Serial_SendString((uint8_t*)"Demod Table Init OK\r\n");
-
- /* 6. 配置ADC和DMA */
- ADC_DMA_Config();
- Serial_SendString((uint8_t*)"ADC DMA Init OK\r\n");
-
- /* 7. 配置并使能DMA中斷 */
- NVIC_EnableIRQ(DMA1_Channel1_IRQn);
- NVIC_SetPriority(DMA1_Channel1_IRQn, 1);
-
- Serial_SendString((uint8_t*)"System Init Complete\r\n");
- Serial_SendString((uint8_t*)"Start Demodulation...\r\n");
-
- /* 8. 主循環 */
- while (1) {
- /* 等待DMA傳輸完成中斷標志 */
- if (g_adcCompleteFlag) {
- g_adcCompleteFlag = 0;
-
- /* 進行數字正交解調 */
- Demod_Process();
- }
-
- /* 可添加其他低優先級任務 */
- }
- }
- /* 錯誤處理函數 - 留出接口供用戶自定義實現 */
- void MemoryError_Handler(uint8_t errCount)
- {
- /* 用戶可在此實現內存錯誤處理邏輯 */
- /* 例如:記錄錯誤信息、重啟系統等 */
- }
復制代碼 然后我讓gemini檢查deepseek寫的是否正確,它回答說基本正確,有兩個小地方需要注意下。然后我又讓gemini給我寫一個,gemini嘩啦啦給縮成只下面這么一點,這個數字正交解調我理論看不懂程序也不明白個所以,我問gemini只這么一點就完成了計算濾波功能?gemini說大道至簡,理論很長計算很短,搞的我都懷疑是不是這倆貨都在懵我?gemini還說在2.6ms就能刷新一次,因為DMA 緩沖區大小是 256 個點,它吐出來數據隨后就能算出來。哪位能解釋下這個確定是完整了解調計算嗎?gemini寫的如下:
- /**
- * @file metal_det_dsp.c
- * @brief 高壓振蕩數字正交解調 - 定點數優化版
- * @note 引腳分配: PA0(ADC), PA9(TX), PB8(Status LED)
- */
- #include "n32g031.h"
- #include <math.h>
- /* --- 常量與宏定義 --- */
- #define ADC_BUF_SIZE 256 // 必須是2的冪
- #define SIN_TAB_SIZE 256 // 正弦表長度
- #define DECIMATION_RATIO 64 // CIC抽取倍數
- /* --- 全局變量 --- */
- __align(4) uint16_t g_adcBuffer[ADC_BUF_SIZE]; // DMA直接映射區
- __align(4) uint32_t g_ramTestBuffer[32]; // 專門用于開機RAM自檢的區域
- // 定點數查找表 (Q14格式: 1.0 = 16384)
- int16_t g_sinTable[SIN_TAB_SIZE];
- int16_t g_cosTable[SIN_TAB_SIZE];
- // 解調輸出 (阻抗I, 感抗Q)
- volatile int32_t g_finalI, g_finalQ;
- volatile uint8_t g_dataReady = 0;
- /* --- 函數聲明 --- */
- void RCC_Config(void);
- uint8_t Safe_Memory_Check(void);
- void ADC_DMA_Init(void);
- void DSP_Table_Init(void);
- void Digital_Demod_Process(uint16_t* pRawData, uint16_t len);
- /* --- 1. 系統時鐘配置 (帶容錯機制) --- */
- void RCC_Config(void) {
- uint32_t timeout = 0;
-
- RCC_DeInit();
- RCC_HSEConfig(RCC_HSE_ON); // 開啟外部8M
-
- while (RCC_WaitHSEStartUp() == ERROR && timeout < 500) timeout++;
-
- if (timeout >= 500) {
- // HSE失敗,切換HSI并倍頻
- RCC_PLLConfig(RCC_PLL_Source_HSI, RCC_PLLMul_6);
- } else {
- // HSE成功,8M * 6 = 48MHz
- RCC_PLLConfig(RCC_PLL_Source_HSE, RCC_PLLMul_6);
- }
-
- RCC_PLLCmd(ENABLE);
- while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
- RCC_SYSCLKConfig(RCC_SYSCLKSource_PLL);
- while (RCC_GetSYSCLKSource() != 0x08); // 等待PLL穩定
-
- SystemCoreClockUpdate();
- }
- /* --- 2. 安全內存檢查 (只檢查特定區域以免破壞堆棧) --- */
- uint8_t Safe_Memory_Check(void) {
- uint32_t i;
- // 寫入交替碼測試位線干擾
- for(i=0; i<32; i++) {
- g_ramTestBuffer[i] = (i % 2 == 0) ? 0xAAAAAAAA : 0x55555555;
- }
- for(i=0; i<32; i++) {
- if(g_ramTestBuffer[i] != ((i % 2 == 0) ? 0xAAAAAAAA : 0x55555555)) return 1; // 錯誤
- }
- return 0; // OK
- }
- /* --- 3. 正交解調核心邏輯 (定點數優化) --- */
- // 輸入: ADC原始數據指針,長度
- // 功能: 執行 S * sin 和 S * cos,并進行CIC積分
- void Digital_Demod_Process(uint16_t* pRawData, uint16_t len) {
- static uint32_t phase_acc = 0;
- static uint32_t phase_step = (uint32_t)(4280.0f / 48000.0f * 65536.0f); // 初始步長
-
- int64_t sumI = 0, sumQ = 0;
-
- for (uint16_t i = 0; i < len; i++) {
- uint16_t idx = (phase_acc >> 8) & 0xFF; // 取高8位作為查表索引
-
- // 核心乘累加 (Q14格式)
- sumI += (int32_t)pRawData[i] * g_cosTable[idx];
- sumQ += (int32_t)pRawData[i] * g_sinTable[idx];
-
- phase_acc += phase_step; // 頻率跟蹤累加
- }
-
- // 抽取與結果輸出 (等效CIC濾波)
- g_finalI = (int32_t)(sumI >> 14);
- g_finalQ = (int32_t)(sumQ >> 14);
- g_dataReady = 1;
- }
- /* --- 4. ADC + DMA 配置 --- */
- void ADC_DMA_Init(void) {
- // 開啟GPIOA, ADC, DMA1時鐘
- RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA | RCC_APB2_PERIPH_ADC1, ENABLE);
- RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA1, ENABLE);
- // ADC配置為連續轉換模式
- ADC_InitType ADC_InitStruct;
- ADC_InitStruct.ContinueConvEn = ENABLE;
- ADC_InitStruct.DatAlign = ADC_DAT_ALIGN_R;
- ADC_InitStruct.ChsNumber = 1;
- ADC_Init(ADC1, &ADC_InitStruct);
-
- ADC_ConfigRegularChannel(ADC1, ADC_CH_SELECT_CH0, 1, ADC_SAMPLE_TIME_13CYCLES5);
- // DMA配置: 循環模式
- DMA_InitType DMA_InitStruct;
- DMA_DeInit(DMA1_Channel1);
- DMA_InitStruct.PeriphAddr = (uint32_t)&ADC1->DAT;
- DMA_InitStruct.MemAddr = (uint32_t)g_adcBuffer;
- DMA_InitStruct.Direction = DMA_DIR_PERIPH_SRC;
- DMA_InitStruct.BufSize = ADC_BUF_SIZE;
- DMA_InitStruct.CircularMode = DMA_MODE_CIRCULAR;
- DMA_InitStruct.MemDataSize = DMA_MEM_DATA_SIZE_HALFWORD;
- DMA_InitStruct.PeriphDataSize = DMA_PERIPH_DATA_SIZE_HALFWORD;
- DMA_InitStruct.DMA_MemoryInc = DMA_MEM_INC_ENABLE;
- DMA_Init(DMA1_Channel1, &DMA_InitStruct);
-
- DMA_ConfigInterrupt(DMA1_Channel1, DMA_INT_TC | DMA_INT_HT, ENABLE); // 半滿和全滿中斷
- DMA_EnableChannel(DMA1_Channel1, ENABLE);
-
- ADC_ConfigDMA(ADC1, ENABLE);
- ADC_Enable(ADC1, ENABLE);
- while(ADC_GetFlagStatusNew(ADC1, ADC_FLAG_RDY) == RESET);
- ADC_StartSoftwareConv(ADC1);
- }
- /* --- 5. 查表初始化 --- */
- void DSP_Table_Init(void) {
- for(int i=0; i<256; i++) {
- g_sinTable[i] = (int16_t)(sin(2.0 * 3.14159 * i / 256.0) * 16384);
- g_cosTable[i] = (int16_t)(cos(2.0 * 3.14159 * i / 256.0) * 16384);
- }
- }
- /* --- 6. 中斷服務函數 --- */
- void DMA1_Channel1_IRQHandler(void) {
- if (DMA_GetIntStatus(DMA1_Channel1, DMA_INT_HT)) {
- DMA_ClearIntPending(DMA1_Channel1, DMA_INT_HT);
- // 處理前半段數據
- Digital_Demod_Process(&g_adcBuffer[0], ADC_BUF_SIZE/2);
- }
- if (DMA_GetIntStatus(DMA1_Channel1, DMA_INT_TC)) {
- DMA_ClearIntPending(DMA1_Channel1, DMA_INT_TC);
- // 處理后半段數據
- Digital_Demod_Process(&g_adcBuffer[ADC_BUF_SIZE/2], ADC_BUF_SIZE/2);
- }
- }
- int main(void) {
- RCC_Config();
-
- if (Safe_Memory_Check() != 0) {
- // RAM錯誤處理接口
- while(1);
- }
-
- DSP_Table_Init();
- ADC_DMA_Init();
-
- NVIC_EnableIRQ(DMA1_Channel1_IRQn);
-
- while(1) {
- if (g_dataReady) {
- g_dataReady = 0;
- // 此處 g_finalI 和 g_finalQ 就是解調出的阻抗和感抗
- // 主循環可以根據這兩個值的變化率來觸發傳送帶報警
- }
- }
- }
復制代碼
|