本设计基于MSP430G2553单片机,主要用了PWM输出和捕获功能,控制算法是PID.
设置二级菜单,功能一:调速功能;通过按键加减占空比调速,通过返回按键退出此功能。
功能二:定速功能:通过按键设置目标转速,确认按键按下后,启动电机,自动调整到目标转速,通过返回按键退出此功能。
(附件限制了大小,能上传的也就只有程序了,有相关视频去B站搜索:飞檐走壁王不羁,即可观看相关视频)
单片机源程序如下:
- #include <msp430G2553.h>
- #include "Lcd1602.h"
- unsigned int DUTY=1000; //PWM占空比 (DUTY/10000)%
- #define uchar unsigned char
- #define uint unsigned int
- uchar flag=0,disp_table[6],cap_table[10],n=0;
- volatile uint fre_num=0;
- long sum=0;
- uint Redge,frequence,key=4,count=0,speed=0,yes=0,fanhui=0;
- uint Period[10];
- volatile long AvgPeriod;
- unsigned char distr[3];
- //uint Real,Target;
- /*------------------PID参数初始化----------------------*/
- float kp=0.0457,ki=0.005,kd=0.1; //PI控制参数设置
- float error=0,Last_error=0,Prev_error=0;
- float IncremDuty;
- /****************************增量式PI控制函数******************************/
- float Incremental_PID(float Real,float Target)
- {
- error = Target - Real;
- IncremDuty = kp*(2.45*error - 3.5*Last_error + 1.25*Prev_error) ;
- Prev_error = Last_error;
- Last_error = error;
- return IncremDuty;
- }
- /****************************************字符类型转换函数***********************************************/
- char int_to_char(char x)
- {
- distr[0] = (x/10) + 0x30;
- distr[1] = x%10 + 0x30;
- distr[2] = '\0';
- }
- /*---------------------数字转换成字符------------------------------------------------*/
- void num_to_char(uint k)
- {
- uchar i=0;
- // disp_table[0] = k/10000 + 0x30; //'0'的ASCII码0x30
- disp_table[0] = k%10000/1000 + 0x30;
- disp_table[1] = k%1000/100 + 0x30;
- disp_table[2] = k%100/10 + 0x30;
- disp_table[3] = k%10 + 0x30;
- disp_table[4] = 0x20;
- disp_table[5] = '\0';
- for(i=0;i<4;i++) //去掉无效的前导'0'字符
- {
- if(disp_table[i]==0x30)
- disp_table[i] = 0x20; //0x20是空格的ASCII码
- else
- break;
- }
- }
- void long_to_char(long k)
- {
- uchar j=0;
- cap_table[0] = k/100000000 + 0x30; //'0'的ASCII码0x30
- cap_table[1] = k%100000000/10000000 + 0x30;
- cap_table[2] = k%10000000/1000000 + 0x30;
- cap_table[3] = k%1000000/100000 + 0x30;
- cap_table[4] = k%100000/10000 + 0x30;
- cap_table[5] = k%10000/1000 + 0x30;
- cap_table[6] = k%1000/100 + 0x30;
- cap_table[7] = k%100/10 + 0x30;
- cap_table[8] = k%10 + 0x30;
- cap_table[9] = '\0';
- for(j=0;j<8;j++) //去掉无效的前导'0'字符
- {
- if(cap_table[j]==0x30)
- cap_table[j] = 0x20; //0x20是空格的ASCII码
- else
- break;
- }
- }
- /*****************************************系统时钟源设置******************************************************/
- void OSC_CLK_Init(void)
- {
- if (CALBC1_8MHZ == 0xFF || CALDCO_8MHZ == 0xFF)
- {while(1);} // If calibration constants erased, trap CPU!!
- BCSCTL1 = CALBC1_8MHZ; // Set range
- DCOCTL = CALDCO_8MHZ; // Set DCO step + modulation
- IFG1 &= ~OFIFG; // Clear OSCFault flag
- BCSCTL2 |= SELM_1 + DIVS_3 ; // Set MCLK=8MHz, SMCLK/
- }
- /****************************************PWM设置函数(比较模块)**************************************************/
- void PWM()
- {
- TA1CTL=TASSEL_2+MC_1+TACLR; //(定时器A1控制寄存器 )SMCLK 1MHZ+不分频+增计数+清零
- TA1CCTL2=OUTMOD_7; //(定时器A1捕获控制寄存器2)高电平 PWM
- TA1CCR0=10000-1; //周期10000us==10ms 100HZ
- TA1CCR2=DUTY; //高电平时间
- }
- /********************************************捕获模块寄存器设置*******************************************************/
- //P1.2端口设置为捕获功能,用于测量信号频率 ,当捕获频率f=1MHz时
- //能捕获到最大信号周期为65.536ms,频率为15.26Hz(最低信号频率)
- void Timer_A0_1_CAP()
- {
- TACTL = TASSEL_2 + MC_2 + ID_3 + TACLR; //SMCLK=1MHz/8=0.125MHz,连续计数模式,清TAR
- TACCTL1 = CAP + CCIS_0 + SCS + CM_1 + CCIE;//CCISxA,开捕获,上升沿捕获,使能,同步捕获
- }
- /*******************************************GPIO设置*****************************************************/
- void IO_RE()
- {
- P2DIR |=BIT4; //pwm输出 P2.4
- P2SEL |=BIT4; //
- P1DIR&=~BIT2; //转速捕获 P1.2
- P1SEL|=BIT2; //
- //查询方式
- P1DIR&=~(BIT0+BIT1+BIT3+BIT4); //四个用户按键 0加速 1减速 3加50 4减50
- P1OUT|=BIT0+BIT1+BIT3+BIT4; //输出高电平
- P1REN|=BIT0+BIT1+BIT3+BIT4; //上拉(硬件有上拉)
- P1DIR|=BIT7; //P1.7 LED指示灯 用于调试
- }
- /**************************************按键消抖延时函数*******************************************************/
- void delay_Nms(unsigned int n)
- {
- unsigned int i;
- unsigned int j;
- for(i = n;i > 0;i--)
- for(j = 100;j > 0;j--)
- _NOP();
- }
- /****************************************主函数***************************************************/
- void main(void)
- {
- WDTCTL = WDTPW | WDTHOLD; //
- OSC_CLK_Init(); //SMCLK 1M
- Timer_A0_1_CAP(); //定时器A
- lcdinit();
- IO_RE();
- _EINT(); //开总中断
- while(1)
- {
- /**************************************一级菜单************************************************/
- if(key==4) //主界面
- {
- disp_str(1,0," A: MODE 1 ");
- disp_str(2,0," B: MODE 2 ");
- DUTY=1000;
- PWM();
- }
- //功能选项一
- if(!(P1IN&BIT0))
- {
- delay_Nms(10);
- if(!(P1IN&BIT0))
- {
- while(!(P1IN&BIT0));
- {
- key=1;
- }
- }
- }
- //功能选项二
- if(!(P1IN&BIT1))
- {
- delay_Nms(10);
- if(!(P1IN&BIT1))
- {
- while(!(P1IN&BIT1));
- {
- key=2;
- }
- }
- }
- /*******************************************对应功能***************************************************/
- switch(key)
- {
- /********************************************功能一***************************************************/
- case 1:
- while(1)
- {
- if(count==0) //清除主界面
- {
- count=1;
- lcd_clr();
- }
- /********************功能一主页面***********************/
- disp_str(1,0,"DUTY=");
- int_to_char(DUTY/100); //占空比数值显示
- disp_str(1,6," ");
- disp_str(1,9,distr);
- disp_str(1,11,"% ");
- disp_str(2,0,"n="); //转速
- disp_str(2,6,"r/min ");
- /*****************计算显示频率(转速)*********************/
- if(flag==1)
- {
- frequence = (uint)(125000/AvgPeriod)*30; //计算信号转速
- num_to_char(frequence);
- disp_str(2,2,disp_table);
- flag = 0;
- }
- /*********************************************加速按键1************************************************/
- if(!(P1IN&BIT0)&&key==1)
- {
- delay_Nms(10);
- if(!(P1IN&BIT0)&&key==1)
- {
- disp_str(1,5,"+1%");
- while(!(P1IN&BIT0)&&key==1);
- {
- P1OUT^=BIT7;
- DUTY+=100;
- if(DUTY>9000)
- {
- DUTY=9000;
- }
- PWM();
- disp_str(1,5," ");
- }
- }
- }
- /*********************************************减速按键2**************************************************/
- if(!(P1IN&BIT1)&&key==1)
- {
- delay_Nms(10);
- if(!(P1IN&BIT1)&&key==1)
- {
- disp_str(1,5,"-1%");
- while(!(P1IN&BIT1)&&key==1);
- {
- P1OUT^=BIT7;
- DUTY-=100;
- if(DUTY<1000)
- {
- DUTY=1000;
- }
- PWM();
- disp_str(1,5," ");
- }
- }
- }
- /*********************************************返回按键4*********************************************/
- if(!(P1IN&BIT4))
- {
- delay_Nms(10);
- if(!(P1IN&BIT4))
- {
- while(!(P1IN&BIT4));
- {
- key=4;
- break;
- }
- }
- }
- }
- ;
- break;
- /********************************************功能二******************************************/
- case 2:
- while(1)
- {
- if(count==0) //清除主界面
- {
- count=1;
- lcd_clr();
- }
- DUTY=0;
- PWM();
- disp_str(1,1,"Input:");
- disp_str(2,1,"speed:");
- /*****************计算显示频率(转速)*********************/
- if(flag==1)
- {
- frequence = (uint)(125000/AvgPeriod)*30; //计算信号转速
- num_to_char(frequence);
- disp_str(2,7,disp_table);
- flag = 0;
- }
- /*******************************************加按键1***********************************************/
- if(!(P1IN&BIT0)&&key==2)
- {
- delay_Nms(10);
- if(!(P1IN&BIT0)&&key==2)
- {
- while(!(P1IN&BIT0)&&key==2);
- {
- speed+=60;
- if(speed>2400) speed = 2400;
- }
- }
- }
- /*******************************************减按键2***********************************************/
- if(!(P1IN&BIT1)&&key==2)
- {
- delay_Nms(10);
- if(!(P1IN&BIT1)&&key==2)
- {
- while(!(P1IN&BIT1)&&key==2);
- {
- speed-=60;
- if(speed<900) speed = 900;
- }
- }
- }
- num_to_char(speed);
- disp_str(1,7,disp_table);
- /*********************************************确认按键3*********************************************/
- if(!(P1IN&BIT3)&&key==2)
- {
- delay_Nms(10);
- if(!(P1IN&BIT3)&&key==2)
- {
- while(!(P1IN&BIT3)&&key==2);
- {
- yes=3;
- }
- }
- }
- if(yes==3)
- {
- DUTY=900;
- PWM();
- while(fanhui==0) //如果没有按返回按键
- {
- delay_Nms(150);
- if(flag==1) //检测当前风扇转速并显示
- {
- frequence = (uint)(125000/AvgPeriod)*30; //计算信号转速
- num_to_char(frequence);
- disp_str(2,7,disp_table); //显示当前转速
- flag = 0;
- }
- //根据设定转速进行PID调节
- if(fabs(frequence-speed)>20)
- {
- DUTY = DUTY + (int)Incremental_PID(frequence,speed);
- TA1CCR2 = DUTY;
- }
- if(!(P1IN&BIT4))
- {
- delay_Nms(10);
- if(!(P1IN&BIT4))
- {
- while(!(P1IN&BIT4));
- {
- fanhui=1;
- break;
- }
- }
- }
- }
- if(!(P1IN&BIT4))
- {
- delay_Nms(10);
- if(!(P1IN&BIT4))
- {
- while(!(P1IN&BIT4));
- {
- fanhui=0;speed=0;DUTY=0;yes=0;
- key=4;
- break;
- }
- }
- }
- }
- /*********************************************返回按键4*********************************************/
- }
- break;
- }
- }
- }
- /******************************************************************
- * TA0.1 P1.2捕获中断
- * 捕获测频原理:分别记录第1次和第2次捕获到上升沿的时刻Redge1、Redge2,
- * 则信号周期为:Period = Redge2 - Redge1
- *******************************************************************/
- #pragma vector = TIMER0_A1_VECTOR
- __interrupt void TIMER0_A1_ISR(void)
- {
- switch(TAIV)
- {
- case 0x02: //Vector 2:TACCR1 CCIFG
- if(fre_num == 0) // 捕获上升沿信号
- {
- Redge = TACCR1;
- fre_num++;
- }
- else
- {
- _DINT();
- if(TACCR1 > Redge) //第二次捕获上升沿
- Period[n] = TACCR1 - Redge; //计算周期
- else
- Period[n] = 65536 + TACCR1 - Redge;
- Redge = TACCR1; //保存上次捕获值
- sum += (long)Period[n];
- n++;
- if(n==10)
- {flag=1;AvgPeriod = sum/10;n=0;sum=0;} //取10次捕获值的平均
- _EINT();
- }
- break;
- case 0x0A:
- //溢出次数计数
- break;
- default: break;
- }
- }
复制代码
所有资料51hei提供下载:
test speed 程序.rar
(71.68 KB, 下载次数: 34)
|