找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2|回复: 0
打印 上一主题 下一主题
收起左侧

哪位能帮忙解释下AI写数字正交解调是否正确?

[复制链接]
跳转到指定楼层
楼主
ID:1066092 发表于 2026-3-12 15:38 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
我让deepseek写了个基于N32G031的数字正交解调,它呼啦啦写了一堆如下:
  1. /**
  2.   ******************************************************************************
  3.   * @file    main.c
  4.   * @author  User
  5.   * @version V1.0.0
  6.   * @date    2026-03-12
  7.   * @brief   N32G031 数字正交解调示例程序
  8.   *          功能:1. 系统时钟配置(HSE 8MHz -> PLL -> 48MHz,失败则转HSI 48MHz)
  9.   *                2. 内存RAM读写正确性检查
  10.   *                3. ADC+DMA连续采样
  11.   *                4. 数字正交解调处理
  12.   *                5. 串口输出解调结果
  13.   ******************************************************************************
  14.   */

  15. #include "n32g031.h"
  16. #include "rcc.h"
  17. #include "gpio.h"
  18. #include "adc.h"
  19. #include "dma.h"
  20. #include "usart.h"

  21. /* 引脚功能定义 ****************************************************************/
  22. /*
  23.    ADC输入引脚:PA0 - 模拟输入,接收待解调的模拟信号
  24.    USART1:    PA9(TX) - 串口输出解调结果
  25.                 PA10(RX) - 未使用,但保留配置
  26.    LED指示:    PB8 - 可选,用于指示系统状态
  27. */

  28. /* 常量定义 ********************************************************************/
  29. #define ADC_BUFFER_SIZE         256                 /* ADC采样缓冲区大小 */
  30. #define SAMPLE_RATE             48000               /* 采样率 48Ksps */
  31. #define CARRIER_FREQ            4000                /* 载波频率 4KHz */
  32. #define PI                      3.14159265358979f

  33. /* 全局变量 ********************************************************************/
  34. /* ADC采样缓冲区 - 需DMA传输,注意内存对齐 */
  35. __align(4) uint16_t g_adcBuffer[ADC_BUFFER_SIZE] __attribute__((at(0x20000000)));

  36. /* 解调结果缓冲区 */
  37. int32_t g_iDemod[ADC_BUFFER_SIZE/2];    /* I路解调结果 */
  38. int32_t g_qDemod[ADC_BUFFER_SIZE/2];    /* Q路解调结果 */

  39. /* 正交解调系数表 - 避免实时计算sin/cos */
  40. __align(4) int16_t g_sinTable[ADC_BUFFER_SIZE];
  41. __align(4) int16_t g_cosTable[ADC_BUFFER_SIZE];

  42. volatile uint8_t g_adcCompleteFlag = 0;  /* ADC采样完成标志 */
  43. volatile uint8_t g_sysErrorFlag = 0;     /* 系统错误标志 */

  44. /* 函数声明 ********************************************************************/
  45. uint8_t SystemClock_Config(void);
  46. uint8_t Memory_Check(void);
  47. void GPIO_Config(void);
  48. void ADC_DMA_Config(void);
  49. void DemodTable_Init(void);
  50. void Demod_Process(void);
  51. void Serial_Init(uint32_t baudrate);
  52. void Serial_SendByte(uint8_t ucCh);
  53. void Serial_SendString(uint8_t *str);
  54. void Serial_SendNum(int32_t num);

  55. /**
  56.   * @brief  系统时钟配置函数
  57.   * @param  无
  58.   * @retval 错误代码:0=成功(HSE+PLL),1=HSE启动失败(已转HSI),2=PLL锁定失败(已转HSI)
  59.   * @note   优先使用HSE+PLL到48MHz,若失败则自动切换到HSI+PLL到48MHz
  60.   */
  61. uint8_t SystemClock_Config(void)
  62. {
  63.     ErrorStatus HSEStartUpStatus;
  64.     uint32_t pllStartupCounter = 0;
  65.     uint8_t retVal = 0;
  66.    
  67.     /* 1. 复位RCC配置 */
  68.     RCC_DeInit();
  69.    
  70.     /* 2. 尝试使能外部高速晶振(HSE)*/
  71.     RCC_HSEConfig(RCC_HSE_ON);
  72.    
  73.     /* 3. 等待HSE就绪,设置超时检测 */
  74.     HSEStartUpStatus = RCC_WaitForHSEStartUp();
  75.    
  76.     if (HSEStartUpStatus == ERROR) {
  77.         /* HSE启动失败,切换到HSI */
  78.         retVal = 1;
  79.         
  80.         /* 配置HSI作为PLL输入 */
  81.         RCC_HSICmd(ENABLE);
  82.         while (RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET);
  83.         
  84.         /* 配置FLASH等待周期 */
  85.         FLASH->ACR = FLASH_ACR_LATENCY_1;
  86.         FLASH->ACR |= FLASH_ACR_PRFTBE;
  87.         
  88.         /* PLL配置:HSI/1*6 = 48MHz */
  89.         RCC_PLLConfig(RCC_PLLSource_HSI, RCC_PLLMul_6);
  90.         
  91.         /* 使能PLL */
  92.         RCC_PLLCmd(ENABLE);
  93.         
  94.         /* 等待PLL就绪,带超时检测 */
  95.         pllStartupCounter = 0;
  96.         while (!RCC_GetFlagStatus(RCC_FLAG_PLLRDY) && (pllStartupCounter < 0x1000)) {
  97.             pllStartupCounter++;
  98.         }
  99.         
  100.         if (!RCC_GetFlagStatus(RCC_FLAG_PLLRDY)) {
  101.             retVal = 2;  /* PLL锁定失败,但HSI可用 */
  102.             /* 直接使用HSI作为系统时钟 */
  103.             RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI);
  104.         } else {
  105.             /* 选择PLL作为系统时钟 */
  106.             RCC_SYSCLKConfig(RCC_SYSCLKSource_PLL);
  107.         }
  108.     } else {
  109.         /* HSE启动成功,使用HSE+PLL */
  110.         /* 配置FLASH预取指及等待周期 */
  111.         FLASH->ACR = FLASH_ACR_LATENCY_1;
  112.         FLASH->ACR |= FLASH_ACR_PRFTBE;
  113.         
  114.         /* 配置PLL:HSE/1*6 = 48MHz */
  115.         RCC_PLLConfig(RCC_PLLSource_HSE, RCC_PLLMul_6);
  116.         
  117.         /* 使能PLL */
  118.         RCC_PLLCmd(ENABLE);
  119.         
  120.         /* 等待PLL就绪,带超时检测 */
  121.         pllStartupCounter = 0;
  122.         while (!RCC_GetFlagStatus(RCC_FLAG_PLLRDY) && (pllStartupCounter < 0x1000)) {
  123.             pllStartupCounter++;
  124.         }
  125.         
  126.         if (!RCC_GetFlagStatus(RCC_FLAG_PLLRDY)) {
  127.             retVal = 2;  /* PLL锁定失败,回退到HSI */
  128.             
  129.             RCC_HSICmd(ENABLE);
  130.             while (RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET);
  131.             RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI);
  132.         } else {
  133.             /* 选择PLL作为系统时钟 */
  134.             RCC_SYSCLKConfig(RCC_SYSCLKSource_PLL);
  135.             /* 等待PLL被确认为系统时钟 */
  136.             while (RCC_GetSYSCLKSource() != RCC_CFG_SCLKSTS_PLL);
  137.         }
  138.     }
  139.    
  140.     /* 更新系统时钟变量 */
  141.     SystemCoreClockUpdate();
  142.    
  143.     return retVal;
  144. }

  145. /**
  146.   * @brief  内存RAM读写检查函数
  147.   * @param  无
  148.   * @retval 0: 内存检查通过; 非0: 内存检查失败
  149.   * @note   本函数只做检查并返回结果,错误处理由上层函数决定
  150.   *         若需要错误处理,可在此处添加回调函数接口
  151.   */
  152. uint8_t Memory_Check(void)
  153. {
  154.     volatile uint32_t *pMem;
  155.     volatile uint32_t testPattern;
  156.     uint32_t i;
  157.     uint8_t errorCount = 0;
  158.    
  159.     /* 测试地址范围:SRAM起始地址到结束地址,步进4字节 */
  160.     /* N32G031 SRAM地址范围:0x20000000 - 0x20001FFF (8KB) */
  161.    
  162.     /* 测试模式1:0xAAAAAAAA (1010交替) */
  163.     testPattern = 0xAAAAAAAA;
  164.     for (i = 0; i < 0x2000; i += 4) {
  165.         pMem = (volatile uint32_t *)(0x20000000 + i);
  166.         *pMem = testPattern;
  167.         if (*pMem != testPattern) {
  168.             errorCount++;
  169.         }
  170.     }
  171.    
  172.     /* 测试模式2:0x55555555 (0101交替) */
  173.     testPattern = 0x55555555;
  174.     for (i = 0; i < 0x2000; i += 4) {
  175.         pMem = (volatile uint32_t *)(0x20000000 + i);
  176.         *pMem = testPattern;
  177.         if (*pMem != testPattern) {
  178.             errorCount++;
  179.         }
  180.     }
  181.    
  182.     /* 测试模式3:递增模式 */
  183.     for (i = 0; i < 0x2000; i += 4) {
  184.         pMem = (volatile uint32_t *)(0x20000000 + i);
  185.         *pMem = i;
  186.         if (*pMem != i) {
  187.             errorCount++;
  188.         }
  189.     }
  190.    
  191.     /*
  192.      * 错误处理接口说明:
  193.      * 若需要添加内存错误处理,可在errorCount > 0时调用以下函数:
  194.      * void MemoryError_Handler(uint8_t errCount) - 用户自定义错误处理函数
  195.      * 当前版本仅返回错误计数,不进行具体处理
  196.      */
  197.    
  198.     return errorCount;
  199. }

  200. /**
  201.   * @brief  GPIO初始化函数
  202.   * @param  无
  203.   * @retval 无
  204.   */
  205. void GPIO_Config(void)
  206. {
  207.     GPIO_InitType GPIO_InitStructure;
  208.    
  209.     /* 使能GPIO时钟 */
  210.     RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA, ENABLE);
  211.     RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOB, ENABLE);
  212.    
  213.     /* 配置PA0为模拟输入 - ADC输入通道 */
  214.     GPIO_InitStructure.Pin        = GPIO_PIN_0;
  215.     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AIN;      /* 模拟输入模式 */
  216.     GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
  217.    
  218.     /* 配置PA9为复用推挽输出 - USART1 TX */
  219.     GPIO_InitStructure.Pin        = GPIO_PIN_9;
  220.     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;    /* 复用推挽输出 */
  221.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  222.     GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
  223.    
  224.     /* 配置PA10为浮空输入 - USART1 RX */
  225.     GPIO_InitStructure.Pin        = GPIO_PIN_10;
  226.     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN_FLOATING;
  227.     GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
  228.    
  229.     /* 可选:配置PB8为推挽输出 - LED指示 */
  230.     GPIO_InitStructure.Pin        = GPIO_PIN_8;
  231.     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
  232.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  233.     GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure);
  234.    
  235.     /* 初始状态LED灭 */
  236.     GPIO_SetBits(GPIOB, GPIO_PIN_8);
  237. }

  238. /**
  239.   * @brief  ADC和DMA初始化函数
  240.   * @param  无
  241.   * @retval 无
  242.   * @note   配置ADC1连续采样,DMA循环模式传输数据
  243.   */
  244. void ADC_DMA_Config(void)
  245. {
  246.     ADC_InitType ADC_InitStructure;
  247.     DMA_InitType DMA_InitStructure;
  248.    
  249.     /* 使能ADC和DMA时钟 */
  250.     RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_ADC1, ENABLE);
  251.     RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA1, ENABLE);
  252.    
  253.     /* ADC配置 [citation:1][citation:2] */
  254.     ADC_InitStructure.MultiChEn       = DISABLE;                /* 单通道模式 */
  255.     ADC_InitStructure.ContinueConvEn  = ENABLE;                 /* 连续转换使能 */
  256.     ADC_InitStructure.ExtTrigSelect   = ADC_EXT_TRIGCONV_NONE;  /* 软件触发 */
  257.     ADC_InitStructure.DatAlign        = ADC_DAT_ALIGN_R;        /* 数据右对齐 */
  258.     ADC_InitStructure.ChsNumber       = 1;                      /* 1个通道 */
  259.     ADC_Init(ADC1, &ADC_InitStructure);
  260.    
  261.     /* 配置ADC规则通道:通道0,采样时间 55.5周期 */
  262.     ADC_ConfigRegularChannel(ADC1, ADC_CH_SELECT_CH0, 1, ADC_SAMPLE_TIME_55CYCLES5);
  263.    
  264.     /* DMA配置 */
  265.     DMA_DeInit(DMA1_Channel1);
  266.    
  267.     /* 配置DMA传输参数 [citation:1] */
  268.     DMA_InitStructure.PeriphAddr      = (uint32_t)&ADC1->DAT;   /* 外设地址:ADC数据寄存器 */
  269.     DMA_InitStructure.MemAddr         = (uint32_t)g_adcBuffer;  /* 内存地址:采样缓冲区 */
  270.     DMA_InitStructure.Direction       = DMA_DIR_PERIPH_SRC;     /* 方向:外设到内存 */
  271.     DMA_InitStructure.BufSize         = ADC_BUFFER_SIZE;        /* 传输数据大小 */
  272.     DMA_InitStructure.PeriphInc       = DMA_PERIPH_INC_DISABLE; /* 外设地址不递增 */
  273.     DMA_InitStructure.DMA_MemoryInc   = DMA_MEM_INC_ENABLE;     /* 内存地址递增 */
  274.     DMA_InitStructure.PeriphDataSize  = DMA_PERIPH_DATA_SIZE_HALFWORD; /* 外设数据宽度16位 */
  275.     DMA_InitStructure.MemDataSize     = DMA_MEM_DATA_SIZE_HALFWORD;    /* 内存数据宽度16位 */
  276.     DMA_InitStructure.CircularMode    = DMA_MODE_CIRCULAR;      /* 循环模式使能 */
  277.     DMA_InitStructure.Priority        = DMA_PRIORITY_HIGH;      /* 高优先级 */
  278.     DMA_InitStructure.Mem2Mem         = DMA_M2M_DISABLE;        /* 非内存到内存 */
  279.     DMA_Init(DMA1_Channel1, &DMA_InitStructure);
  280.    
  281.     /* 配置DMA半传输和传输完成中断 */
  282.     DMA_ConfigInterrupt(DMA1_Channel1, DMA_INT_HT | DMA_INT_TC, ENABLE);
  283.    
  284.     /* 使能DMA通道 */
  285.     DMA_EnableChannel(DMA1_Channel1, ENABLE);
  286.    
  287.     /* 使能ADC DMA请求 [citation:4] */
  288.     ADC_ConfigDMA(ADC1, ENABLE);
  289.    
  290.     /* 校准ADC */
  291.     ADC_StartCalibration(ADC1);
  292.     while (ADC_GetCalibrationStatus(ADC1));
  293.    
  294.     /* 使能ADC */
  295.     ADC_Enable(ADC1, ENABLE);
  296.    
  297.     /* 等待ADC就绪 */
  298.     while (ADC_GetFlagStatusNew(ADC1, ADC_FLAG_RDY) == RESET);
  299.    
  300.     /* 软件触发第一次ADC转换 */
  301.     ADC_StartSoftwareConv(ADC1);
  302. }

  303. /**
  304.   * @brief  正交解调系数表初始化
  305.   * @param  无
  306.   * @retval 无
  307.   * @note   预计算正弦和余弦值,避免实时计算
  308.   */
  309. void DemodTable_Init(void)
  310. {
  311.     uint16_t i;
  312.     float phase;
  313.     float step = 2 * PI * CARRIER_FREQ / SAMPLE_RATE;
  314.    
  315.     for (i = 0; i < ADC_BUFFER_SIZE; i++) {
  316.         phase = step * i;
  317.         /* 缩放系数:将浮点数转换为16位整数,缩放因子16384 */
  318.         g_sinTable[i] = (int16_t)(sinf(phase) * 16384);
  319.         g_cosTable[i] = (int16_t)(cosf(phase) * 16384);
  320.     }
  321. }

  322. /**
  323.   * @brief  DMA中断处理函数
  324.   * @param  无
  325.   * @retval 无
  326.   */
  327. void DMA1_Channel1_IRQHandler(void)
  328. {
  329.     if (DMA_GetIntStatus(DMA1_Channel1, DMA_INT_TC) == SET) {
  330.         /* 传输完成中断 */
  331.         g_adcCompleteFlag = 1;
  332.         DMA_ClearIntPending(DMA1_Channel1, DMA_INT_TC);
  333.         
  334.         /* 翻转LED指示状态 */
  335.         GPIOB->POD ^= GPIO_PIN_8;
  336.     }
  337.    
  338.     if (DMA_GetIntStatus(DMA1_Channel1, DMA_INT_HT) == SET) {
  339.         /* 半传输中断 - 可在此处理前一半数据 */
  340.         DMA_ClearIntPending(DMA1_Channel1, DMA_INT_HT);
  341.     }
  342. }

  343. /**
  344.   * @brief  数字正交解调处理函数
  345.   * @param  无
  346.   * @retval 无
  347.   * @note   对ADC采样数据进行正交解调,提取I/Q分量
  348.   */
  349. void Demod_Process(void)
  350. {
  351.     uint16_t i;
  352.     int32_t sumI, sumQ;
  353.     uint16_t sampleIndex;
  354.    
  355.     sumI = 0;
  356.     sumQ = 0;
  357.    
  358.     /* 对每个载波周期进行积分 */
  359.     for (i = 0; i < (ADC_BUFFER_SIZE / 2); i++) {
  360.         /* 每个解调点使用两个采样点进行相关运算 */
  361.         sampleIndex = i * 2;
  362.         
  363.         /* I路:乘以cos */
  364.         g_iDemod[i] = ((int32_t)g_adcBuffer[sampleIndex] * g_cosTable[sampleIndex] +
  365.                        (int32_t)g_adcBuffer[sampleIndex + 1] * g_cosTable[sampleIndex + 1]) >> 14;
  366.         
  367.         /* Q路:乘以sin */
  368.         g_qDemod[i] = ((int32_t)g_adcBuffer[sampleIndex] * g_sinTable[sampleIndex] +
  369.                        (int32_t)g_adcBuffer[sampleIndex + 1] * g_sinTable[sampleIndex + 1]) >> 14;
  370.         
  371.         sumI += g_iDemod[i];
  372.         sumQ += g_qDemod[i];
  373.     }
  374.    
  375.     /* 可通过串口输出累积和或每个解调点 */
  376.     /* 此处输出累积和作为示例 */
  377.     Serial_SendString((uint8_t*)"I: ");
  378.     Serial_SendNum(sumI);
  379.     Serial_SendString((uint8_t*)"  Q: ");
  380.     Serial_SendNum(sumQ);
  381.     Serial_SendString((uint8_t*)"\r\n");
  382. }

  383. /**
  384.   * @brief  串口初始化函数
  385.   * @param  baudrate: 波特率
  386.   * @retval 无
  387.   */
  388. void Serial_Init(uint32_t baudrate)
  389. {
  390.     USART_InitType USART_InitStructure;
  391.    
  392.     /* USART1时钟已在GPIO配置中使能 */
  393.    
  394.     /* USART1 配置 */
  395.     USART_InitStructure.BaudRate            = baudrate;
  396.     USART_InitStructure.WordLength          = USART_WL_8B;
  397.     USART_InitStructure.StopBits            = USART_STPB_1;
  398.     USART_InitStructure.Parity              = USART_PE_NO;
  399.     USART_InitStructure.HardwareFlowControl = USART_HFCTRL_NONE;
  400.     USART_InitStructure.Mode                = USART_MODE_TX | USART_MODE_RX;
  401.     USART_Init(USART1, &USART_InitStructure);
  402.    
  403.     /* 使能USART1 */
  404.     USART_Enable(USART1, ENABLE);
  405. }

  406. /**
  407.   * @brief  串口发送一个字节
  408.   * @param  ucCh: 要发送的字节
  409.   * @retval 无
  410.   */
  411. void Serial_SendByte(uint8_t ucCh)
  412. {
  413.     while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
  414.     USART_SendData(USART1, ucCh);
  415. }

  416. /**
  417.   * @brief  串口发送字符串
  418.   * @param  str: 要发送的字符串指针
  419.   * @retval 无
  420.   */
  421. void Serial_SendString(uint8_t *str)
  422. {
  423.     while (*str != '\0') {
  424.         Serial_SendByte(*str++);
  425.     }
  426. }

  427. /**
  428.   * @brief  串口发送数字(简化版,实际应用中可优化)
  429.   * @param  num: 要发送的32位整数
  430.   * @retval 无
  431.   */
  432. void Serial_SendNum(int32_t num)
  433. {
  434.     char buf[16];
  435.     char *p = buf;
  436.     uint32_t temp;
  437.     uint8_t i = 0;
  438.    
  439.     if (num < 0) {
  440.         Serial_SendByte('-');
  441.         temp = -num;
  442.     } else {
  443.         temp = num;
  444.     }
  445.    
  446.     /* 简单的数字转字符串 */
  447.     do {
  448.         buf[i++] = (temp % 10) + '0';
  449.         temp /= 10;
  450.     } while (temp > 0);
  451.    
  452.     /* 反向输出 */
  453.     while (i > 0) {
  454.         Serial_SendByte(buf[--i]);
  455.     }
  456. }

  457. /**
  458.   * @brief  主函数
  459.   * @param  无
  460.   * @retval 无
  461.   */
  462. int main(void)
  463. {
  464.     uint8_t clockStatus;
  465.     uint8_t memStatus;
  466.    
  467.     /* 1. 配置系统时钟并检测是否成功 */
  468.     clockStatus = SystemClock_Config();
  469.    
  470.     /* 2. 内存RAM读写检查 */
  471.     memStatus = Memory_Check();
  472.    
  473.     /* 3. 初始化各模块 */
  474.     GPIO_Config();
  475.     Serial_Init(9600);
  476.    
  477.     /* 4. 输出系统状态信息 */
  478.     Serial_SendString((uint8_t*)"System Init Start...\r\n");
  479.    
  480.     if (clockStatus == 0) {
  481.         Serial_SendString((uint8_t*)"Clock: HSE+PLL 48MHz OK\r\n");
  482.     } else if (clockStatus == 1) {
  483.         Serial_SendString((uint8_t*)"Clock: HSE fail, use HSI 48MHz\r\n");
  484.     } else {
  485.         Serial_SendString((uint8_t*)"Clock: PLL fail, use HSI 48MHz\r\n");
  486.     }
  487.    
  488.     if (memStatus == 0) {
  489.         Serial_SendString((uint8_t*)"Memory Check: PASS\r\n");
  490.     } else {
  491.         Serial_SendString((uint8_t*)"Memory Check: FAIL\r\n");
  492.         /* 内存错误处理接口 - 可在此添加用户自定义错误处理 */
  493.         /* while(1); 内存严重错误时停机 */
  494.     }
  495.    
  496.     /* 5. 初始化正交解调系数表 */
  497.     DemodTable_Init();
  498.     Serial_SendString((uint8_t*)"Demod Table Init OK\r\n");
  499.    
  500.     /* 6. 配置ADC和DMA */
  501.     ADC_DMA_Config();
  502.     Serial_SendString((uint8_t*)"ADC DMA Init OK\r\n");
  503.    
  504.     /* 7. 配置并使能DMA中断 */
  505.     NVIC_EnableIRQ(DMA1_Channel1_IRQn);
  506.     NVIC_SetPriority(DMA1_Channel1_IRQn, 1);
  507.    
  508.     Serial_SendString((uint8_t*)"System Init Complete\r\n");
  509.     Serial_SendString((uint8_t*)"Start Demodulation...\r\n");
  510.    
  511.     /* 8. 主循环 */
  512.     while (1) {
  513.         /* 等待DMA传输完成中断标志 */
  514.         if (g_adcCompleteFlag) {
  515.             g_adcCompleteFlag = 0;
  516.             
  517.             /* 进行数字正交解调 */
  518.             Demod_Process();
  519.         }
  520.         
  521.         /* 可添加其他低优先级任务 */
  522.     }
  523. }

  524. /* 错误处理函数 - 留出接口供用户自定义实现 */
  525. void MemoryError_Handler(uint8_t errCount)
  526. {
  527.     /* 用户可在此实现内存错误处理逻辑 */
  528.     /* 例如:记录错误信息、重启系统等 */
  529. }
复制代码
然后我让gemini检查deepseek写的是否正确,它回答说基本正确,有两个小地方需要注意下。然后我又让gemini给我写一个,gemini哗啦啦给缩成只下面这么一点,这个数字正交解调我理论看不懂程序也不明白个所以,我问gemini只这么一点就完成了计算滤波功能?gemini说大道至简,理论很长计算很短,搞的我都怀疑是不是这俩货都在懵我?gemini还说在2.6ms就能刷新一次,因为DMA 缓冲区大小是 256 个点,它吐出来数据随后就能算出来。哪位能解释下这个确定是完整了解调计算吗?gemini写的如下:
  1. /**
  2. * @file    metal_det_dsp.c
  3. * @brief   高压振荡数字正交解调 - 定点数优化版
  4. * @note    引脚分配: PA0(ADC), PA9(TX), PB8(Status LED)
  5. */

  6. #include "n32g031.h"
  7. #include <math.h>

  8. /* --- 常量与宏定义 --- */
  9. #define ADC_BUF_SIZE     256       // 必须是2的幂
  10. #define SIN_TAB_SIZE     256       // 正弦表长度
  11. #define DECIMATION_RATIO 64        // CIC抽取倍数

  12. /* --- 全局变量 --- */
  13. __align(4) uint16_t g_adcBuffer[ADC_BUF_SIZE]; // DMA直接映射区
  14. __align(4) uint32_t g_ramTestBuffer[32];       // 专门用于开机RAM自检的区域

  15. // 定点数查找表 (Q14格式: 1.0 = 16384)
  16. int16_t g_sinTable[SIN_TAB_SIZE];
  17. int16_t g_cosTable[SIN_TAB_SIZE];

  18. // 解调输出 (阻抗I, 感抗Q)
  19. volatile int32_t g_finalI, g_finalQ;
  20. volatile uint8_t g_dataReady = 0;

  21. /* --- 函数声明 --- */
  22. void RCC_Config(void);
  23. uint8_t Safe_Memory_Check(void);
  24. void ADC_DMA_Init(void);
  25. void DSP_Table_Init(void);
  26. void Digital_Demod_Process(uint16_t* pRawData, uint16_t len);

  27. /* --- 1. 系统时钟配置 (带容错机制) --- */
  28. void RCC_Config(void) {
  29.     uint32_t timeout = 0;
  30.    
  31.     RCC_DeInit();
  32.     RCC_HSEConfig(RCC_HSE_ON); // 开启外部8M
  33.    
  34.     while (RCC_WaitHSEStartUp() == ERROR && timeout < 500) timeout++;
  35.    
  36.     if (timeout >= 500) {
  37.         // HSE失败,切换HSI并倍频
  38.         RCC_PLLConfig(RCC_PLL_Source_HSI, RCC_PLLMul_6);
  39.     } else {
  40.         // HSE成功,8M * 6 = 48MHz
  41.         RCC_PLLConfig(RCC_PLL_Source_HSE, RCC_PLLMul_6);
  42.     }
  43.    
  44.     RCC_PLLCmd(ENABLE);
  45.     while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
  46.     RCC_SYSCLKConfig(RCC_SYSCLKSource_PLL);
  47.     while (RCC_GetSYSCLKSource() != 0x08); // 等待PLL稳定
  48.    
  49.     SystemCoreClockUpdate();
  50. }

  51. /* --- 2. 安全内存检查 (只检查特定区域以免破坏堆栈) --- */
  52. uint8_t Safe_Memory_Check(void) {
  53.     uint32_t i;
  54.     // 写入交替码测试位线干扰
  55.     for(i=0; i<32; i++) {
  56.         g_ramTestBuffer[i] = (i % 2 == 0) ? 0xAAAAAAAA : 0x55555555;
  57.     }
  58.     for(i=0; i<32; i++) {
  59.         if(g_ramTestBuffer[i] != ((i % 2 == 0) ? 0xAAAAAAAA : 0x55555555)) return 1; // 错误
  60.     }
  61.     return 0; // OK
  62. }

  63. /* --- 3. 正交解调核心逻辑 (定点数优化) --- */
  64. // 输入: ADC原始数据指针,长度
  65. // 功能: 执行 S * sin 和 S * cos,并进行CIC积分
  66. void Digital_Demod_Process(uint16_t* pRawData, uint16_t len) {
  67.     static uint32_t phase_acc = 0;
  68.     static uint32_t phase_step = (uint32_t)(4280.0f / 48000.0f * 65536.0f); // 初始步长
  69.    
  70.     int64_t sumI = 0, sumQ = 0;
  71.    
  72.     for (uint16_t i = 0; i < len; i++) {
  73.         uint16_t idx = (phase_acc >> 8) & 0xFF; // 取高8位作为查表索引
  74.         
  75.         // 核心乘累加 (Q14格式)
  76.         sumI += (int32_t)pRawData[i] * g_cosTable[idx];
  77.         sumQ += (int32_t)pRawData[i] * g_sinTable[idx];
  78.         
  79.         phase_acc += phase_step; // 频率跟踪累加
  80.     }
  81.    
  82.     // 抽取与结果输出 (等效CIC滤波)
  83.     g_finalI = (int32_t)(sumI >> 14);
  84.     g_finalQ = (int32_t)(sumQ >> 14);
  85.     g_dataReady = 1;
  86. }

  87. /* --- 4. ADC + DMA 配置 --- */
  88. void ADC_DMA_Init(void) {
  89.     // 开启GPIOA, ADC, DMA1时钟
  90.     RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA | RCC_APB2_PERIPH_ADC1, ENABLE);
  91.     RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA1, ENABLE);

  92.     // ADC配置为连续转换模式
  93.     ADC_InitType ADC_InitStruct;
  94.     ADC_InitStruct.ContinueConvEn = ENABLE;
  95.     ADC_InitStruct.DatAlign = ADC_DAT_ALIGN_R;
  96.     ADC_InitStruct.ChsNumber = 1;
  97.     ADC_Init(ADC1, &ADC_InitStruct);
  98.    
  99.     ADC_ConfigRegularChannel(ADC1, ADC_CH_SELECT_CH0, 1, ADC_SAMPLE_TIME_13CYCLES5);

  100.     // DMA配置: 循环模式
  101.     DMA_InitType DMA_InitStruct;
  102.     DMA_DeInit(DMA1_Channel1);
  103.     DMA_InitStruct.PeriphAddr = (uint32_t)&ADC1->DAT;
  104.     DMA_InitStruct.MemAddr = (uint32_t)g_adcBuffer;
  105.     DMA_InitStruct.Direction = DMA_DIR_PERIPH_SRC;
  106.     DMA_InitStruct.BufSize = ADC_BUF_SIZE;
  107.     DMA_InitStruct.CircularMode = DMA_MODE_CIRCULAR;
  108.     DMA_InitStruct.MemDataSize = DMA_MEM_DATA_SIZE_HALFWORD;
  109.     DMA_InitStruct.PeriphDataSize = DMA_PERIPH_DATA_SIZE_HALFWORD;
  110.     DMA_InitStruct.DMA_MemoryInc = DMA_MEM_INC_ENABLE;
  111.     DMA_Init(DMA1_Channel1, &DMA_InitStruct);
  112.    
  113.     DMA_ConfigInterrupt(DMA1_Channel1, DMA_INT_TC | DMA_INT_HT, ENABLE); // 半满和全满中断
  114.     DMA_EnableChannel(DMA1_Channel1, ENABLE);
  115.    
  116.     ADC_ConfigDMA(ADC1, ENABLE);
  117.     ADC_Enable(ADC1, ENABLE);
  118.     while(ADC_GetFlagStatusNew(ADC1, ADC_FLAG_RDY) == RESET);
  119.     ADC_StartSoftwareConv(ADC1);
  120. }

  121. /* --- 5. 查表初始化 --- */
  122. void DSP_Table_Init(void) {
  123.     for(int i=0; i<256; i++) {
  124.         g_sinTable[i] = (int16_t)(sin(2.0 * 3.14159 * i / 256.0) * 16384);
  125.         g_cosTable[i] = (int16_t)(cos(2.0 * 3.14159 * i / 256.0) * 16384);
  126.     }
  127. }

  128. /* --- 6. 中断服务函数 --- */
  129. void DMA1_Channel1_IRQHandler(void) {
  130.     if (DMA_GetIntStatus(DMA1_Channel1, DMA_INT_HT)) {
  131.         DMA_ClearIntPending(DMA1_Channel1, DMA_INT_HT);
  132.         // 处理前半段数据
  133.         Digital_Demod_Process(&g_adcBuffer[0], ADC_BUF_SIZE/2);
  134.     }
  135.     if (DMA_GetIntStatus(DMA1_Channel1, DMA_INT_TC)) {
  136.         DMA_ClearIntPending(DMA1_Channel1, DMA_INT_TC);
  137.         // 处理后半段数据
  138.         Digital_Demod_Process(&g_adcBuffer[ADC_BUF_SIZE/2], ADC_BUF_SIZE/2);
  139.     }
  140. }

  141. int main(void) {
  142.     RCC_Config();
  143.    
  144.     if (Safe_Memory_Check() != 0) {
  145.         // RAM错误处理接口
  146.         while(1);
  147.     }
  148.    
  149.     DSP_Table_Init();
  150.     ADC_DMA_Init();
  151.    
  152.     NVIC_EnableIRQ(DMA1_Channel1_IRQn);
  153.    
  154.     while(1) {
  155.         if (g_dataReady) {
  156.             g_dataReady = 0;
  157.             // 此处 g_finalI 和 g_finalQ 就是解调出的阻抗和感抗
  158.             // 主循环可以根据这两个值的变化率来触发传送带报警
  159.         }
  160.     }
  161. }
复制代码



分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表