标题:
一个单片机PWM调压程序,怎么编写PID函数调节电压?
[打印本页]
作者:
lern01
时间:
2018-12-14 19:11
标题:
一个单片机PWM调压程序,怎么编写PID函数调节电压?
本帖最后由 lern01 于 2018-12-14 19:59 编辑
一个PWM调压程序,怎么编写PID函数来调节电压?也望大老能指点,十分地感谢!
附单片机程序:
#include "stc12c5a60s2.h"
#include "intrins.h"
#define ADC_POWER 0x80 //ADC电源控制位,0-关闭,1-打开
#define ADC_FLAG 0x10 //ADC结束标志位
#define ADC_START 0x08 //ADC启动控制位
#define ADC_SPEEDLL 0x00 //540 clocks--选择转换速度
unsigned char Lcd_Dis1_table[] = {"SetValue: "}; //第一行显示框架
unsigned char Lcd_Dis2_table[] = {"Voltage : "}; //第二行显示框架
float Show, NUM;
unsigned char volt = 0; //作为显示的数据
bit flag300ms = 1; //300ms定时标志
unsigned char T0RH = 0; //T0重载值的高字节
unsigned char T0RL = 0; //T0重载值的低字节
//PID算法公式:
sbit key1 = P2^7; //定义按键1
sbit key2 = P2^6; //定义按键2
sbit key3 = P2^5; //定义按键3
sbit key4 = P2^4; //定义按键4
sbit key_gnd = P2^3; //定义接地
void ConfigTimer0(unsigned int ms);
void InitADC();
void InitPWM();
void PWM0_change(unsigned char type, unsigned char change);
void Delay(unsigned int n);
void KeyAction(unsigned char keycod);
void NumToString(unsigned char num);
void ValueToString(unsigned char *str, unsigned int val);
unsigned int GetADCResult(unsigned char ch); //读取输入电压模数转换函数
extern void KeyScan();
extern void KeyDriver();
extern void InitLcd1602();
extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);
void main()
{
unsigned int val;
unsigned char str[10];
key_gnd = 0;
EA = 1; //开总中断
ConfigTimer0(10); //配置T0定时10ms
InitADC();
InitPWM();
InitLcd1602();
LcdShowStr(0, 0, Lcd_Dis1_table);
LcdShowStr(0, 1, Lcd_Dis2_table);
while(1)
{
KeyDriver();
if(flag300ms)
{
flag300ms = 0;
val = GetADCResult(7);
ValueToString(str, val);
LcdShowStr(9, 1, str);
}
NumToString(volt);
/* NUM = 10 * NUM;
Show = ldata;
if((NUM < (Show - 0.1))||(NUM > (Show + 0.1)))
{
if(NUM < (Show - 0.1))
{
if((Show - 0.1) - NUM > 1)
{
PWM1_change(1, 0X05);
}
else
{
PWM1_change(1, 0X01);
}
}
else
{
if(NUM - (Show + 0.1) > 1)
{
PWM1_change(0, 0X05);
}
else
{
PWM1_change(0, 0X01);
}
}
Delay(500);
}
else
{
Delay(2000);
} */
}
}
void NumToString(unsigned char num)
{
unsigned char str[10];
str[0] = num/100 + '0';
str[1] = num/10%100 + '0';
str[2] = '.';
str[3] = num%10 + '0';
str[4] = 'V';
str[5] = '\0';
LcdShowStr(9, 0, str);
}
/*------------ADC 取值 --------------*/
unsigned int GetADCResult(unsigned char ch) //ch--AD输入通道
{
unsigned int val = 0;
ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ADC_START |ch;
_nop_(); _nop_(); _nop_(); _nop_(); _nop_();
while(!(ADC_CONTR & ADC_FLAG)); //等待AD转换完成
ADC_CONTR &= ~ADC_FLAG; //关闭ADC
val = ADC_RES;
val = (val << 2) | (0x03 & ADC_RESL);
return val; //返回A/D转换结果
}
void InitADC()
{
P1ASF = 0x80; //设置P1.7为AD输入通道
ADC_RES = 0; //清除高8位RES和低2位RESL
ADC_RESL = 0;
ADC_CONTR = ADC_POWER | ADC_SPEEDLL;
Delay(20); //打开ADC电源并延时
}
/* ADC转换值转为实际电压值的字符串形式,str-字符串指针,val-AD转换值 */
void ValueToString(unsigned char *str, unsigned int val)
{
NUM = (val * 5.03) / 1024.0;
str[0] = (unsigned int)NUM/10 + '0';
str[1] = (unsigned int)NUM%10 + '0';
str[2] = '.';
str[3] = (unsigned int)(NUM*10)%10 + '0';
str[4] = (unsigned int)(NUM*100)%10 + '0';
str[5] = 'V';
str[6] = '\0';
}
void InitPWM()
{
CCON = 0; //Initial PCA control register
//PCA timer stop runing
//Clear CF flag
//Clear all module interrupt flag
CL = CH = 0; //Reset PCA base timer
CMOD = 0x02; //Set PCA timer clock source as Fousc/2 0X00:以系统时钟/12 为时钟源,0X02:系统时钟/2,0x08:系统时钟
//Disable PCA timer overflow interrupt
CCAP0L = CCAP0H = 0xff; //起始占空比,0XC0:占空比为25%,0X80:占空比为50%,0X40:占空比为75%
PCA_PWM0 = 0x00;
CCAPM0 = 0x42;//0X42:8位PWM P1.4输出,无中断;0X53:8位PWM输出,下降沿产生中断;0X63:上升沿产生中断;0X73:跳变沿产生中断
CR = 1; //计时器开始工作
}
void PWM0_change(unsigned char type, unsigned char change) //type=0减占空比,1增加占空比 change: 0X0C约5%,0X05约2%
{
if(type == 0)
{
if(CCAP0L < 0xff) //占空比 < 90%
{
CCAP0L += change;
CCAP0H += change;
}
}
else
{
if(CCAP0L > 0x00) // > 10%
CCAP0L -= change;
CCAP0H -= change;
}
}
void KeyAction(unsigned char keycod)
{
switch(keycod)
{
case 0x26:
if(volt < 50);
{
volt++;
PWM0_change(1, 0x05);
}
break;
case 0x28:
if(volt > 0)
{
volt--;
PWM0_change(0, 0x05);
}
break;
case 0x27:
if(volt < 50)
{
volt += 10;
PWM0_change(1, 0x0C);
}
break;
case 0x25:
if(volt > 0)
{
volt -= 10;
PWM0_change(0, 0x0C);
}
break;
default: break;
}
}
void Delay(unsigned int n)
{
unsigned int x;
while (n--)
{
x = 500;
while (x--);
}
}
/*
void DelayMs(unsigned char ms) //延时程序
{
unsigned int i;
while(ms--)
{
for(i=0; i<850; i++)
;
}
}
*/
/* 配置并启动T0,ms-T0定时时间 */
void ConfigTimer0(unsigned int ms)
{
unsigned long tmp; //临时变量
tmp = 11059200 / 12; //定时器计数频率
tmp = (tmp * ms) / 1000; //计算所需的计数值
tmp = 65536 - tmp; //计算定时器重载值
tmp = tmp + 12; //补偿中断响应延时造成的误差
T0RH = (unsigned char)(tmp>>8); //定时器重载值拆分为高低字节
T0RL = (unsigned char)tmp;
TMOD &= 0xF0; //清零T0的控制位
TMOD |= 0x01; //配置T0为模式1
TH0 = T0RH; //加载T0重载值
TL0 = T0RL;
ET0 = 1; //使能T0中断
TR0 = 1; //启动T0
}
/* T0中断服务函数,执行300ms定时 */
void InterruptTimer0() interrupt 1
{
static unsigned char tmr300ms = 0;
TH0 = T0RH; //重新加载重载值
TL0 = T0RL;
KeyScan();
tmr300ms++;
if (tmr300ms >= 30) //定时300ms
{
tmr300ms = 0;
flag300ms = 1;
}
}
复制代码
作者:
疯子本人
时间:
2018-12-18 13:57
pid函数网上都有的,你可以去网上找找,然后把pid函数返回来的值传给所要控制的函数就可以了
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1