本設計基于MSP430G2553單片機,主要用了PWM輸出和捕獲功能,控制算法是PID.
設置二級菜單,功能一:調速功能;通過按鍵加減占空比調速,通過返回按鍵退出此功能。
功能二:定速功能:通過按鍵設置目標轉速,確認按鍵按下后,啟動電機,自動調整到目標轉速,通過返回按鍵退出此功能。
(附件限制了大小,能上傳的也就只有程序了,有相關視頻去B站搜索:飛檐走壁王不羈,即可觀看相關視頻)
IMG20191225124140.jpg (2.12 MB, 下載次數: 81)
下載附件
2019-12-25 13:31 上傳
單片機源程序如下:
- #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)
2019-12-25 13:28 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|