我让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 就是解调出的阻抗和感抗
- // 主循环可以根据这两个值的变化率来触发传送带报警
- }
- }
- }
复制代码
|