1.前言最近在做双三相永磁同步电机的FOC从9月才开始学习写的文章可能会有许多不对的地方还请大佬指出。2. 硬件平台介绍1控制器TMS320F28377D2采样电阻5mΩ2.三相电流采样架构设计EPWM → 触发 ADC SOC → ADC 完成EOC → ADC中断 → 计算三相电流 → 滤波 → RS422通过串口发送数据到PC选择DSP的ADC采样端口我选择ADCINA4、ADCINA3、ADCIN15。通过看手册如下图此芯片有4个ADC大家可以根据自己的要求进行选择。5. ADC 初始化代码5.1 启动 ADC 模块电源和时钟// // 1️⃣ 启动 ADC 模块电源和时钟 // CpuSysRegs.PCLKCR13.bit.ADC_A 1; // 使能 ADC-A 时钟 CpuSysRegs.PCLKCR13.bit.ADC_C 1; // 使能 ADC-C 时钟 // 启动 ADC 模块电源 AdcaRegs.ADCCTL1.bit.ADCPWDNZ 1; AdccRegs.ADCCTL1.bit.ADCPWDNZ 1; // 设置 ADC 时钟分频 (系统时钟 / 4)约200/4 50Mhz手册 AdcaRegs.ADCCTL2.bit.PRESCALE 6; AdccRegs.ADCCTL2.bit.PRESCALE 6;5.2 设置中断触发时机采样完成后触发更稳定// 设置中断触发时机采样完成后触发更稳定 AdcaRegs.ADCCTL1.bit.INTPULSEPOS 1; AdccRegs.ADCCTL1.bit.INTPULSEPOS 1;5.3 设置分辨率和输入方式// 设置为 12 位分辨率、单端输入 // 配置 ADCA AdcaRegs.ADCCTL2.bit.RESOLUTION 0; // 0 12-bit, 1 16-bit AdcaRegs.ADCCTL2.bit.SIGNALMODE 0; // 0 single-ended, 1 differential // 配置 ADCC // AdccRegs.ADCCTL2.bit.RESOLUTION 0; // 12-bit AdccRegs.ADCCTL2.bit.SIGNALMODE 0; // 单端输入5.3 配置 ADC通道、SOC采样通道与触发方式// --- A 通道 --- AdcaRegs.ADCSOC0CTL.bit.CHSEL 4; // ADCINA4 AdcaRegs.ADCSOC0CTL.bit.ACQPS 15; // 采样保持窗口 AdcaRegs.ADCSOC0CTL.bit.TRIGSEL 5; // 触发源 EPWM1 SOCA // --- B 通道 --- AdcaRegs.ADCSOC1CTL.bit.CHSEL 3; // ADCINA3 AdcaRegs.ADCSOC1CTL.bit.ACQPS 15; AdcaRegs.ADCSOC1CTL.bit.TRIGSEL 5; // 触发源 EPWM1 SOCA // --- C 通道 --- AdccRegs.ADCSOC0CTL.bit.CHSEL 15; // ADCIN15 AdccRegs.ADCSOC0CTL.bit.ACQPS 15; AdccRegs.ADCSOC0CTL.bit.TRIGSEL 5; // 触发源 EPWM1 SOCA通过查询手册可以发现触发源EPWM1为5AdcaRegs.ADCSOC0CTL.bit.TRIGSEL 5; // 触发源 EPWM1 SOCA。。5.4 配置中断触发每个 SOC 具有对应的转换结束EOC信号。该 EOC 信号可用于触发 ADC 中断。ADC 可以配置为在采集窗口结束时或电压转换结束时生成 EOC 脉冲。这是使用 ADCCTL1 寄存器中的位 INTPULSEPOS 配置的。有关准确的 EOC 脉冲位置请参见手册第 10.2 节。每个 ADC 模块共有 4 个可配置的 ADC 中断。这些中断可由 16 个 EOC 信号中的任何一个触发。每个 ADCINT 的标志位可以直接读取或者由中断可以传递到 PIE。// 4️ 中断配置例如用ADCA中断读取所有结果 AdcaRegs.ADCINTSEL3N4.bit.INT3SEL 0; // 选择 EOC0 作为触发中断的结束通道 AdcaRegs.ADCINTSEL3N4.bit.INT3E 1; // 使能ADCINT3中断 AdcaRegs.ADCINTFLGCLR.bit.ADCINT3 1; // 清除标志 AdcaRegs.ADCINTSEL3N4.bit.INT3CONT 1; //no continue mode5.5 PIE 中断绑定InitPieCtrl(); // 初始化PIE控制器 IER 0x0000; // 清空中断使能寄存器 IFR 0x0000; // 清空中断标志寄存器 InitPieVectTable(); // 初始化PIE中断向量表 // 注册EPWM中断服务程序 EALLOW; PieVectTable.EPWM1_INT EPWM1_INT; // 绑定EPWM1中断 PieVectTable.EPWM2_INT EPWM2_INT; // 绑定EPWM2中断 PieVectTable.EPWM3_INT EPWM3_INT; // 绑定EPWM3中断 PieVectTable.EPWM6_INT EPWM6_INT; // 绑定EPWM6中断 PieVectTable.EPWM7_INT EPWM7_INT; // 绑定EPWM7中断 PieVectTable.EPWM8_INT EPWM8_INT; // 绑定EPWM8中断 PieVectTable.ADCA3_INT ADCA3_INT; // ISR 映射 EDIS; // 使能PIE级和CPU级中断 IER | M_INT3; PieCtrlRegs.PIEIER3.bit.INTx1 1; // 使能PIE组3的INT1EPWM1 PieCtrlRegs.PIEIER3.bit.INTx2 1; // 使能PIE组3的INT2EPWM2 PieCtrlRegs.PIEIER3.bit.INTx3 1; // 使能PIE组3的INT3EPWM3 PieCtrlRegs.PIEIER3.bit.INTx6 1; // 使能PIE组3的INT6EPWM6 PieCtrlRegs.PIEIER3.bit.INTx7 1; // 使能PIE组3的INT7EPWM7 PieCtrlRegs.PIEIER3.bit.INTx8 1; // 使能PIE组3的INT8EPWM8 IER | M_INT10; PieCtrlRegs.PIEIER10.bit.INTx3 1; // 使能PIE组10的INT1ADCA3 // 初始化关键外设 initADC(); // 配置ADC模块电流采样 initEPWM1(); initEPWM2(); initEPWM3(); initEPWM6(); initEPWM7(); initEPWM8(); EINT; // 使能全局中断 ERTM; // 使能实时调试中断6. EPWM 触发 ADC 的配置// 中断配置 (可用于实时控制更新) EPwm1Regs.ETSEL.bit.INTEN 1; // 使能 EPWM 中断 EPwm1Regs.ETSEL.bit.INTSEL 1; // 当计数器到达零点触发中断 EPwm1Regs.ETPS.bit.INTPRD 1; // 每次事件都触发中断 // ADC 触发配置 (用于采样同步) EPwm1Regs.ETSEL.bit.SOCAEN 1; // 使能 ADC EPwm1Regs.ETSEL.bit.SOCASEL 5; // 下降计数到 CMPB 触发最佳 EPwm1Regs.ETPS.bit.SOCAPRD ET_1ST; // 每次事件触发一次 SOC7. 中断函数三相电流计算与滤波7.1 去偏置// 偏置校准函数上电不通电机时调用 void Calibrate_Current_Offset(void) { int i; const uint16_t N 512; uint32_t sumA 0, sumB 0, sumC 0; for(i 0; i N; i) { // 强制触发 ADC 转换否则ADCRESULT不会更新 AdcaRegs.ADCSOCFRC1.all 0x0003; // 触发SOC0和SOC1 AdccRegs.ADCSOCFRC1.all 0x0001; // 触发SOC0 // 等待转换完成可延时约1~2μs DELAY_US(10); sumA AdcaResultRegs.ADCRESULT0; sumB AdcaResultRegs.ADCRESULT1; sumC AdccResultRegs.ADCRESULT0; DELAY_US(50); } Ia_offset (float)sumA / N; Ib_offset (float)sumB / N; Ic_offset (float)sumC / N; }7.2 转换为实际电流根据 Rshunt#define VREF 3.3f #define ADC_MAX 4095.0f #define K_AMP 8.0f #define R_SHUNT 0.005f #define FILTER_N 16 #define USE_IC_MEAS 1 #define FUSION_WEIGHT_MEAS 0.3f // 预计算电流系数 const float CURRENT_SCALE 0.02015f; // ADC 转电流 (A)7.3 滤波EWMA / 滑动平均interrupt void ADCA3_INT(void) { int i; // 1️读取ADC并扣除偏置 float Ia_raw (float)(AdcaResultRegs.ADCRESULT0 - Ia_offset); float Ib_raw (float)(AdcaResultRegs.ADCRESULT1 - Ib_offset); float Ic_raw (float)(AdccResultRegs.ADCRESULT0 - Ic_offset); // 2️ EWMA滤波 Ia_filt1 FILTER_ALPHA * Ia_raw (1 - FILTER_ALPHA) * Ia_filt1; Ib_filt1 FILTER_ALPHA * Ib_raw (1 - FILTER_ALPHA) * Ib_filt1; Ic_filt1 FILTER_ALPHA * Ic_raw (1 - FILTER_ALPHA) * Ic_filt1; // 3️滑动窗口均值滤波 Ia_buf[filter_idx] Ia_filt1; Ib_buf[filter_idx] Ib_filt1; Ic_buf[filter_idx] Ic_filt1; filter_idx (filter_idx 1) % FILTER_LEN; float sumIa0, sumIb0, sumIc0; for(i0;iFILTER_LEN;i){ sumIa Ia_buf[i]; sumIb Ib_buf[i]; sumIc Ic_buf[i]; } // 4️转换为实际电流 (A) Ia (sumIa / FILTER_LEN) * CURRENT_SCALE; Ib (sumIb / FILTER_LEN) * CURRENT_SCALE; Ic (sumIc / FILTER_LEN) * CURRENT_SCALE; // 5️ ✅ 修正三相极性根据测试结果 //Ia -Ia; // Ia 反了 // Ib -Ib; // Ib 反了 // Ic 保持原样 // 清除中断标志 AdcaRegs.ADCINTFLGCLR.bit.ADCINT3 1; PieCtrlRegs.PIEACK.all PIEACK_GROUP10; }7.4 输出变量给 上位机void RS422_SendCurrentsFrame(float Ia, float Ib, float Ic) { Uint16 buf[6]; // 3 个 float每个 float 4 字节 2 个 Uint16 memcpy(buf[0], Ia, 4); memcpy(buf[2], Ib, 4); memcpy(buf[4], Ic, 4); Uint16 tail[4] {0x00, 0x00, 0x80, 0x7F}; // 帧尾 0x7F800000 int i,y; // 1️⃣ 打开发送 RS422_Enable_TX(); // 2️⃣ 发送 3 个 float for(i 0; i 6; i) { RS422_SendByte(buf[i] 0xFF); // 低字节 RS422_SendByte((buf[i] 8) 0xFF); // 高字节 } // 3️⃣ 发送帧尾 for( y 0; y 4; y) RS422_SendByte(tail[y]); // 4️⃣ 等待 FIFO 清空 uint32_t timeout 1000000; while(ScibRegs.SCIFFTX.bit.TXFFST ! 0 timeout--); DELAY_US(100); // 确保发送完成 // 5️⃣ 关闭发送 RS422_Disable_TX(); }