标题:
基于MSP430G2553的直流电机调速测速装置源程序
[打印本页]
作者:
炫啦
时间:
2019-12-25 13:32
标题:
基于MSP430G2553的直流电机调速测速装置源程序
本设计基于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
作者:
luozhao
时间:
2019-12-26 08:39
感谢分享
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1