完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
#include "msp430x14x.h"
#include "cry12864.h" #include "12864.c" #define Num_of_Results 32 /*typedef unsigned char uchar; typedef unsigned int uint;*/ /************************PID结构体和函数声明**********************/ struct PID { float SetSpeed; //定义设定值 float ActualSpeed; //定义实际值 float err; //定义偏差值 float err_next; //定义上一个偏差值 float err_last; //定义最上前的偏差值 float Kp,Ki,Kd; //定义比例、积分、微分系数 }pid; void PID_init(); void int_clk(); void int_pwm(); void init_TB(void); float PID_realize(float speed); uint tamp; void int_ADC(void); /*******************12864显示声明******************/ uint T=20;//初始化目标温度 const uchar hang1[] = {"温度测量与控制 "}; const uchar hang2[] = {"当前电压:"}; const uchar hang3[] = {"当前温度:"}; const uchar hang4[] = {"目标温度:"}; uint wendu; unsigned long sum = 0; void mubiaowendu(uint T); static uint results[Num_of_Results]; //保存ADC转换结果的数组 void Trans_val(uint Hex_Val); uchar shuzi[] = {"0123456789.V℃:"}; /************按键声明************/ void P1_IODect(); void P10_Onclick(); void P11_Onclick(); void P12_Onclick(); void P13_Onclick(); void GPIO_init(); /***************************主函数*************************/ void main( void ) { /*下面六行程序关闭所有的IO口*/ P1DIR = 0XFF;P1OUT = 0XFF; P2DIR = 0XFF;P2OUT = 0XFF; P3DIR = 0XFF;P3OUT = 0XFF; P4DIR = 0XFF;P4OUT = 0XFF; P5DIR = 0XFF;P5OUT = 0XFF; P6DIR = 0XFF;P6OUT = 0XFF; WDTCTL = WDTPW + WDTHOLD; //关狗 P6DIR |= BIT2;P6OUT |= BIT2; //关闭电平转换 Ini_Lcd(); //初始化液晶 mubiaowendu(T); Disp_HZ(0x80,hang1,8); //第一行显示“温度测量与控制” GPIO_init();//IO初始化 int_clk(); PID_init(); int_pwm(); int_ADC(); init_TB(); _EINT();//使能总中断 while(1) { pid.ActualSpeed = wendu/100.0; //当前温度 if(pid.ActualSpeed<=(T-10)) TBCCR1=0; //如果温差小于10度就全速加热 else //温差大于10度启用PID控制 TACCR1=800-(uint)tamp*10; } } /******************************************* 函数名称:ADC12ISR 功 能:ADC中断服务函数,在这里用多次平均的 计算P6.0口的模拟电压数值 参 数:无 返回值 :无 ********************************************/ #pragma vector=ADC_VECTOR __interrupt void ADC12ISR (void) { static uint index = 0; results[index++] = ADC12MEM0; // Move results if(index == Num_of_Results) { uchar i; index = 0; for(i = 0; i < Num_of_Results; i++) { sum += results[i]; } sum >>= 5; //除以32 Trans_val(sum); } } /******************************************* 函数名称:Trans_val 功 能:将16进制ADC转换数据变换成三位10进制 真实的模拟电压数据,并在液晶上显示 参 数:Hex_Val--16进制数据 n--变换时的分母等于2的n次方 返回值 :无 ********************************************/ void Trans_val(uint Hex_Val) { unsigned long caltmp; uint Curr_Volt; uint a=137;//温度系数 uchar t1,i,j; uchar ptr[5]; uchar tmp[6]; caltmp = Hex_Val; caltmp = (caltmp << 5) + Hex_Val; //caltmp = Hex_Val * 33 caltmp = (caltmp << 3) + (caltmp << 1); //caltmp = caltmp * 10 Curr_Volt = caltmp >> 12; //Curr_Volt = caltmp / 2^n ptr[0] = Curr_Volt / 100; //Hex->Dec变换 t1 = Curr_Volt - (ptr[0] * 100); ptr[2] = t1 / 10; ptr[3] = t1 - (ptr[2] * 10); ptr[1] = 10; //shuzi表中第10位对应符号"." ptr[4] = 11; //第11位表示符号"V" //在液晶上显示变换后的结果 wendu = ((Curr_Volt)-100)*a; tmp[5]=12;//第12位表示符号"℃" tmp[4]=wendu%10; tmp[3]=wendu/10%10; tmp[2]=10; tmp[1]=wendu/100%10; tmp[0]=wendu/1000%10; Disp_HZ(0x90,hang2,5); for(i=0;i<5;i++) { //这部分显示第二行的“当前电压:”和数值 Delay_Nms(10); Write_Data(shuzi[ptr[i]]); } Disp_HZ(0x88,hang3,5); for(j=0;j<6;j++) { //这部分显示第三行的“当前温度:”和数值 Delay_Nms(10); Write_Data(shuzi[tmp[j]]); } } /**********在液晶上第四行显示“目标温度:”和数值*********/ void mubiaowendu(uint T) { uchar k; uchar MBWD[6]; MBWD[5]=12;//第12位表示符号"℃" MBWD[1]=T%10; MBWD[0]=T/10%10; MBWD[2]=10; MBWD[3]=T/100%10; MBWD[4]=T/1000%10; Disp_HZ(0x98,hang4,5); for(k=0;k<6;k++) { Delay_Nms(10); Write_Data(shuzi[MBWD[k]]); } } /********************按键部分处理函数*********************/ void GPIO_init() { //-----设定P1.6的输出初始值----- //P1DIR |= BIT6;//设定P1.6为输出 //P1OUT &= ~BIT6;//设定P1.6初值 //-----配置P1.3中断参数----- P1DIR &= ~(BIT0+BIT1+BIT2+BIT3); //设P1.0~P1.3为输入 P1IES |= (BIT0+BIT1+BIT2+BIT3); // P1.0~P1.3设为下降沿中断 P1IE |= (BIT0+BIT1+BIT2+BIT3) ; // 允许P1.0~P1.3中断 } #pragma vector = PORT1_VECTOR __interrupt void PORT1_ISR(void) { //-----启用Port1事件检测函数----- P1_IODect();//事件检测通过,则会调用事件处理函数 P1IFG=0; //退出中断前必须手动清除IO口中断标志 } void P1_IODect() { uint Push_Key=0; //-----排除输出IO的干扰后,锁定唯一被触发的中断标志位----- Push_Key = P1IFG&(~P1DIR); //-----延时一段时间,避开机械抖动区域----- __delay_cycles(10000); //消抖延时 //----判断按键状态是否与延时前一致----- if((P1IN&Push_Key)==0) //如果该次按键确实有效 { //----判断具体哪个IO被按下,调用该IO的事件处理函数----- switch(Push_Key){ case BIT0: P10_Onclick(); break; case BIT1: P11_Onclick(); break; case BIT2: P12_Onclick(); break; case BIT3: P13_Onclick(); break; default: break; //任何情况下均加上default } } } void P10_Onclick() { T=40; mubiaowendu(T); } void P11_Onclick() { T=60; mubiaowendu(T); } void P12_Onclick() { T++; mubiaowendu(T); } void P13_Onclick() { T--; mubiaowendu(T); } /********************初始化ADC****************************/ void int_ADC(void) { /*P5DIR|=BIT5;P5OUT&=~BIT5; //关闭数码管显示 P6DIR|=BIT6;P6OUT&=~BIT6; //半闭数码管显示 P6DIR|=BIT5;P6OUT&=~BIT5;*/ //半闭数码管显示 P6SEL |= 0x01; // 使能ADC通道P6.0 ADC12CTL0 = ADC12ON+SHT0_8+MSC; // 打开ADC,设置采样时间 ADC12CTL1 = SHP+CONSEQ_2; // 使用采样定时器 ADC12IE = 0x01; // 使能ADC中断 ADC12CTL0 |= ENC; // 使能转换 ADC12CTL0 |= ADC12SC; // 开始转换 } /*************************初始化时钟*********************************/ void int_clk() { uchar i; BCSCTL1&=~XT2OFF; //打开XT振荡器 BCSCTL2|=SELM1+SELS;//MCLK 8M and SMCLK 1M do { IFG1 &= ~OFIFG; //清除振荡错误标志 for(i = 0; i < 100; i++) _NOP(); //延时等待 } while ((IFG1 & OFIFG) != 0); //如果标志为1继续循环等待 IFG1&=~OFIFG; } /*************************初始化PWM*****************************/ void int_pwm() { P2DIR |= 0x02; P2SEL |= 0x02; TACCR0 = 800; // PWM Period/2 TACCTL1 = OUTMOD_7; // CCR1 toggle/set TACCR1 = 400; // CCR1 PWM duty cycle TACTL = TASSEL_2 + MC0; // ACLK, up-down mode } /************************Time_B初始化*************************/ void init_TB(void) { TBCCTL0 = CCIE; // TBCCR0 interrupt enabled TBCCR0 = 20000; TBCTL = TBSSEL_2 + MC_1; // SMCLK, upmode } /************************Time_B中断*************************/ #pragma vector=TIMERB0_VECTOR __interrupt void Timer_B (void) { tamp = (uint)PID_realize(T); } /*****************PID变量初始化函数**************************/ void PID_init() { pid.SetSpeed=0.0; pid.ActualSpeed=0.0; pid.err=0.0; pid.err_last=0.0; pid.err_next=0.0; pid.Kp=1.0; pid.Ki=0.0; pid.Kd=0.0; } /*************************PID运算函数 ***************************/ float PID_realize(float speed) { float incrementSpeed; pid.SetSpeed=speed; pid.err=pid.SetSpeed-pid.ActualSpeed; incrementSpeed=pid.Kp*(pid.err)+pid.Ki*pid.err+pid.Kd*(pid.err-2*pid.err_next+pid.err_last); pid.ActualSpeed+=incrementSpeed; pid.err_last=pid.err_next; pid.err_next=pid.err; return incrementSpeed; } |
|
相关推荐
2个回答
|
|
这里的参数整定
void PID_init() { pid.SetSpeed=0.0; pid.ActualSpeed=0.0; pid.err=0.0; pid.err_last=0.0; pid.err_next=0.0; pid.Kp=1.0; pid.Ki=0.0; pid.Kd=0.0; } |
|
|
|
PID参数整定有很多的参考文档,你可以在百度上面查到。但是也都是一些经验心得,具体还需要自己实际调才明白,一般是先整定P,到达系统平衡点的时候减小到原来的60%到80%,然后加上D直到系统稳定,如果此时系统稳定值和实际值由偏差,可以加入一点I,但是这个I的量一定要很小,因为是累加,所以不能太大,必要时还要加入清零
|
|
|
|
只有小组成员才能发言,加入小组>>
3018个成员聚集在这个小组
加入小组2901 浏览 1 评论
MSP430FR5994 使用库函数 定时器触发AD问题请教
3419 浏览 2 评论
请问怎么把下面51单片机的代码改成msp430 g2 pocket的代码,还有改下时间变成30秒
2329 浏览 1 评论
4787 浏览 1 评论
2560 浏览 1 评论
1299浏览 3评论
MSP430FR5994 使用库函数 定时器触发AD问题请教
3419浏览 2评论
2901浏览 1评论
1466浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-15 03:19 , Processed in 1.144292 second(s), Total 82, Slave 65 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号