/*****************************************************
CodeWizardAVR V1.25.6 Professional
Chip type : ATmega48
Clock frequency : 8 MHz
Memory model : Small
External SRAM size : 0
Data Stack size : 128
*****************************************************/
#include <mega48.h>
#include <delay.h>
#include <adc.h>
#include <nokia3310.h>
#define ADC 100 //ADC目标读数(相当于目标电压)
#define kp 9 //P系数/请小心全局数据溢出!
#define ki 1 //I系数/取消则I=0
#define kd 3 //D系数/取消则D=0
unsigned int adc_data;
int wc0, wc1, wc2, xz, pwm; //当前,上次,再上次的误差,修正,输出
void main(void)
{
TCCR1A=0b10000001; //OCR1A正比例PWM/相位修正模式
TCCR1B=0b00000001; //时钟1分频
OCR1AL=0; //PWM占空比调整0-255
DDRB.1=1; //输出PWM
lcd_init(); lcd_cls(); //LCD初始化
while (1)
{
delay_ms(98); //简易的间隔检测时间设定
adc_start(5); //启动某通道ADC/参考电压5V/8bit
adc_data=adc_read(); //等待和读结果/电压=ADC_DATA*98/5
wc2=wc1;
wc1=wc0;
wc0=ADC-adc_data; //误差值=目标值-当前值
xz=wc0*kp+(wc0+wc1+wc2)*ki+((wc0-wc1)-(wc1-wc2))*kd; //修正值=比例放大+积分放大+微分放大
pwm=pwm+xz; //输出值=旧数值+修正值
if(pwm>255) pwm=255; if(pwm<0) pwm=0; //输出值限幅
OCR1AL=pwm;
lcd_gotoxy(0,1); //LCD显示
lcd_putsf("PWM:",4); lcd_putbyte(OCR1AL);
lcd_gotoxy(0,3);
lcd_putsf("ADC:",4); lcd_putbyte(adc_data);
};
}
如下图:
单片机通过PWM输出供电,驱动3个串联电阻,其中50K是一个电位器,人为不断的旋动电位器,来模拟负载无规律的变化。
目标要求:100uF电容两端的电压不受负载的影响,即ADC读数要求稳定在100左右。
大概的输出电压mV = 5000mV * ADC读数 / 255
调整 P、I、D 这三个系数,还有调整间隔检测时间,即可调整负载电压的稳定度和皱纹度。
本例比较简单,没有多少语句,且都是16位的整数运算,适合8位单片机运行,但是它并没有按照PID的公式来套(说实话我对那些公式也是一知半解),它只是按照PID的思路来工作而已,所以,这个程序只能说是山寨程序,适合要求不高的场所。还好,它的语句短、运行速度特快
PWM电压调整与PID控制.rar