原创 使用LM2677制作的3V至24V数控可调恒压源(7)

2016-6-1 17:57 1332 25 25 分类: MCU/ 嵌入式 文集: 硬件小模块

数字PID方案(二)

数字控制方案(一)算法简单,实现直观,而且在100us的调节周期下,已经能够获得很平稳的输出了。可是现在还是想让调节更智能一些。因为使用方案(一),即使MCU知道当前采集到的输出值并不正确,但是它没有途径去更改,因为它走的是一条单行道。指令给的是多少,反馈引脚加的就是多少,执行方案(一)的MCU会想,反正我按照指令去执行了,即使结果不正确,也不关我的事了。

如果要根据输出来调整输入,就需要引入数字PID方案。这就引出了数字控制方案(二),它采用了增量式的数字PID算法。增量式数字PID算法的用途非常广泛,几乎能想到的控制,都可以用它来实现,最常见的如直流电机的速度闭环。

对于LM2677的电路来说,设定值就是用户输入的理想输出电压,输出值就是LM2677的实际输出电压,控制量就是加在LM2677反馈引脚上的DAC输出值。LM2677MCU程序需要实现的功能就是,采集LM2677的实际输出电压,和用户输入的理想输出电压比较,根据比较出来的偏差,调整LM2677反馈引脚上的DAC输出值,直到使实际输出电压等于理想输出电压。

100us的调节时间,用定时器TIM2的溢出中断来实现,但是PID调节的计算并不在中断服务程序中。TIM2_IRQHandler仅仅做了一件事情,就是启动一次ADC扫描。扫描完成之后,ADC的数据会经由DMA通道传输到指定地址的数组中,DMA1_Channel1_IRQHandlerDMA中断,当需要扫描的ADC通道都转换完成之后,DMA中断被触发,在这里进行PID运算。

void TIM2_IRQHandler(void)

{

if(TIM_GetITStatus(TIM2,TIM_IT_Update) != RESET) {

TIM_ClearITPendingBit(TIM2, TIM_IT_Update);

auu.dmaFlag = TRUE;

adc_startScan();

}

}

 

void DMA1_Channel1_IRQHandler(void)

{

if(DMA_GetITStatus(DMA1_IT_TC1) != RESET) {

DMA_ClearITPendingBit(DMA1_IT_TC1);

if (auu.dmaFlag == TRUE) {

auu.dmaFlag = FALSE;

regular_pid();

}

}

}

PID为数字增量式,buu.vol_set是用户给定的输出电压值,buu.vol_out为实际采回来的输出电压值,auu.voltageOutADC的运算结果,auu.voltageFeedDAC的给定结果。

struct __pid {

int32_t vol_set;

int32_t vol_out;

int32_t vol_feed;

int32_t vol_preError;

int32_t vol_preDError;

int32_t vol_P;

int32_t vol_I;

int32_t vol_D;

int32_t deadline;

};

struct __pid buu;

 

uint8_t regular_pid(void)

{

int32_t i = 0;

int32_t error_t, derror_t, dderror_t;

 

for (auu.voltageOut = 0, i = 2; i < ADC_NUM; i++) 

auu.voltageOut += adcResult;

auu.voltageOut /= (ADC_NUM - 2);

auu.voltageOut = (auu.voltageOut * (VOUT_RES_H + VOUT_RES_L) / VOUT_RES_L)

* (3300 / 4) / (4096 / 4);  

 

buu.vol_set = auu.voltageSet;

buu.vol_out = auu.voltageOut;

 

error_t = buu.vol_set - buu.vol_out;

derror_t = error_t - buu.vol_preError;

dderror_t = derror_t - buu.vol_preDError;

 

buu.vol_preError = error_t;

buu.vol_preDError = derror_t;

 

if (!((error_t < buu.deadline) && (error_t > -buu.deadline)))

buu.vol_feed += buu.vol_P * derror_t + buu.vol_I * error_t / 100 

+ buu.vol_D * dderror_t / 100;

auu.voltageFeed = buu.vol_feed / 1000;

 

auu.voltageFeed = 3114 - auu.voltageFeed;

 

if (auu.voltageFeed > 3114 + 980)

auu.voltageFeed = 3114 + 980;

if (auu.voltageFeed < 3114 - 980)

auu.voltageFeed = 3114 - 980;

 

DAC_SetChannel1(auu.voltageFeed);

return 0;

}

这是一个很典型的增量式数字PID算法,error_t是误差,derror_t是误差之差,dderror_t是误差之差的差。通过PID运算buu.vol_feed之后,乘以相应的比例,给出DAC的值。正常的情况下,输出电压会以一个缓慢的趋势到达指令值。实际情况是,这“一个缓慢的趋势”与负载大小有关系,负载大,则趋势快;负载小,则趋势慢。所以在不同的负载电流下,需要不一样的PID参数值。

(调节PID参数,是一件吃力不讨好的事情,枯燥无趣,而且很难掌握一个绝对的规律。所以才会有那么多人去研究更高级的PID算法,比如神经网络、模糊数学、马尔可夫算法等等~~~尼玛用好控制理论真是一门很不简单的工作~~~~)

三个PID参数分别为buu.vol_P、buu.vol_I、buu.vol_D。不同的参数会获得不同特性的输出。经过调试,发现如果使用下面的参数表,会获得相当不错的波形。

这几张张表中都没有0A负载电流的情况,是因为负载太小时PID失去了调节能力。不论指令电压给了多少,输出电压都几乎等于输入电压。而加大负载之后,输出电压会调节到指令电压位置。

文章评论0条评论)

登录后参与讨论
我要评论
0
25
关闭 站长推荐上一条 /2 下一条