This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
各位老师们好,我用tm4c123gh6pm这款launchpad做一个控制的系统,这个系统有两个环,内环使用adc0采样一个交流通道,16次硬件平均后触发中断进行一次浮点pid运算,这样内环的运行速度是62.5k左右,然后外环使用adc1采样一个交流通道和两个直流通道,64次硬件平均后触发中断,进行次1次浮点pid,这样外环运行速率就是1Msps/64/3大约为5.2K,芯片系统时钟配置为80M。
现在的问题是,adc采样和外环是都没问题的,内环我通过反转IO来观察,发现根本没有60K,波形紊乱,大约只有20多k,FPU我是#include "driverlib/fpu.h"后加上
ROM_FPUEnable();
ROM_FPULazyStackingEnable();
这样两句开启的,但是发现加不加没有明显变化,听说CCS里process options中浮点支持选项默认开启FPU我就没有深究这一点,然后我在项目属性里把编译器优化里的size-speed开到最大,没有明显变化,float-point mode选为relaxed,现在一下子速度就上去了,但是不论是速度快或慢,我总发现单步跟踪时有些语句不能到达,甚至观察有些语句比如一个0.17 * 1竟然返回了0,所以我现在一头雾水,不知道接下来该怎么调试。
现在我自己感觉可能是1、编译器优化选项开的过大,数据精度损失。2、或者是这两个环都是在中断里面执行的,没有处理好中断应该注意的问题(中断里面的变量我后来都加上了volatile,但是没有变化)3、FPU没有开启成功,运算速度跟不上中断速度导致数据混乱4、或者难道是TM4算不了这么快,但是我确实需要这么快的运算速度啊。
我的表达不太好,不知道有没有描述清楚问题,希望知道的老师们指点迷津,万分感谢。下面附上关键地方的代码:
/*************************adc0 高速电流反馈层************************/ float cur_delta; float modle_factor_add; uint32_t ac_cur_advalue; void adcsq0Int() { ROM_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_4, 0); ROM_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_PIN_4); ROM_ADCSequenceDataGet(ADC0_BASE, ac_cur_sequence, &ac_cur_advalue); ac_cur_now = ac_cur_advalue / 4095.0 * 3.3; //当前交流电流值 cur_delta = ac_cur_now - cur_point; //计算当前电流与指令电流的误差 modle_factor_add = PidDeltaCal(&pid_delta_ac, cur_delta); //pid当前电流误差 modle_factor = modle_factor + modle_factor_add; //计算累加量 modle_factor = modle_factor * 500; //然后调制PWM脉宽值 if (modle_factor > 200 && modle_factor < 800) //为了安全,限制范围在20%~80% adjustPWMWidth((unsigned int) (1000 - modle_factor)); //反向调制 ROM_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_4, 0); ROM_ADCIntClear(ADC0_BASE, ac_cur_sequence); } /*************************adc1电压外环计算*************************/ /* * other_value[3]数组的值依次是 VAC/VDC/IDC */ uint32_t sin_para = 0; float volt_delta; float ism_factor_add; void adcsq1Int() { ROM_GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_2, 0); ROM_GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_2, GPIO_PIN_2); ROM_ADCSequenceDataGet(ADC1_BASE, other_sequence, other_value); //读取直流电压值 dc_volt_now = other_value[1] / 4095.0 * 3.3; //获得当前直流电压值 dc_cur_now = other_value[2] / 4095.0 * 3.3; //当前直流电流 ac_volt_now = other_value[0] / 4095.0 * 3.3; //当前交流电压 volt_delta = dc_volt_now - volt_ref; //计算Vdc - Vref误差值(-2048~2048) ism_factor_add = PidDeltaCal(&pid_delta_dc, volt_delta);//计算PID调节(输出控制在) ism_factor = ism_factor + ism_factor_add; //累加增量式PID的输出结果 //TODO 切断外环进行内环测试 ism_factor = 1; sin_para++; ac_volt_now = 3.3 * sinf(sin_para / 104 * 2 * M_PI); // cur_point = ism_factor * ac_volt_now; //计算当前电流 期望逼近量 cur_point = ac_volt_now; //计算当前电流期望逼近量 if (sin_para > 104) sin_para = 0; ROM_GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_2, 0); ROM_ADCIntClear(ADC1_BASE, other_sequence); }
/******************adc初始化*********************/ void initADC(void) { //首先配置ADC0为电流内环高速采样中断 ROM_ADCSequenceConfigure(ADC0_BASE, ac_cur_sequence, ADC_TRIGGER_ALWAYS, 3);//配置AD采样序列,持续触发采样,最低优先级 ROM_ADCHardwareOversampleConfigure(ADC0_BASE,16); //8位的硬件平均值滤波 ROM_ADCSequenceStepConfigure(ADC0_BASE, ac_cur_sequence, 0,ADC_CTL_CH0 | ADC_CTL_IE |ADC_CTL_END);//CH0<-->PE3,差分采样CH0通道数据,步进0,采样接收产生中断信号 ROM_ADCSequenceEnable(ADC0_BASE, ac_cur_sequence); //使能ADC_IN使用的采样序列 ROM_ADCIntEnable(ADC0_BASE, ac_cur_sequence); ROM_IntEnable(INT_ADC0SS0); ROM_IntMasterEnable(); //使能中断 ROM_ADCIntClear(ADC0_BASE, ac_cur_sequence); //清零中断标志 //然后配置ADC1为电压外环低速采样 ROM_ADCSequenceConfigure(ADC1_BASE, other_sequence, ADC_TRIGGER_ALWAYS, 2);//配置AD采样序列,定时器触发采样,高于内环优先级 ROM_ADCHardwareOversampleConfigure(ADC1_BASE,64); //8位的硬件平均值滤波 ROM_ADCSequenceStepConfigure(ADC1_BASE, other_sequence, 0,ADC_CTL_CH1); //步骤0 ROM_ADCSequenceStepConfigure(ADC1_BASE, other_sequence, 1,ADC_CTL_CH2); //步骤1 ROM_ADCSequenceStepConfigure(ADC1_BASE, other_sequence, 2,ADC_CTL_CH4 | ADC_CTL_IE |ADC_CTL_END); //步骤2,最后产生中断 ROM_ADCSequenceEnable(ADC1_BASE, other_sequence); //使能ADC_IN使用的采样序列 ROM_ADCIntEnable(ADC1_BASE, other_sequence); ROM_IntEnable(INT_ADC1SS1); ROM_IntMasterEnable(); //使能中断 ROM_ADCIntClear(ADC1_BASE, other_sequence); //清零中断标志 }
嗯嗯,谢谢您的解答,我这两天找了很久的原因,刚刚反复检查发现是程序中的所有变量虽然都定义成了volatile float类型,但是计算公式中有些 x * 0.4这种的算式,这里直接使用的0.4在编译器中是默认为double类型的,导致很多运算不能用FPU执行,改成 0.4f 之后就正常了,内环运行时间4.2uS,最快可以跑到200多k,TM4还是很强悍的。至于编译器优化选项,默认也是可以算的很快的。现在总结在这里,后面看到的坛友们不要跟我犯同样的错误。
再次感谢xyz549040622的热心解答!