S型曲線公式
步進電機的速度從0變為一個比較大的速度,需要一個加速過程,否則會産生振動或是電機的堵轉。電機加速通常有T型曲線和S型曲線兩種方式。S型曲線相對于T型曲線,S型曲線的速度不會突變。S型曲線的原始公式如下:
y=K/(1+Exp(a-b*x))(K>0,b>0)
Exp是指數函數,由這個公式可以看出y會随着x的增大,逼近K。把這個公式應用到電機控制之中,K看成最大的速度Vmax,x看成時間t的變量,那麼t=0時,就是電機的初始速度,即V0=Vmax/(1+Exp(a-b*(0)))=Vmax/(1+Exp(a));反推求出a與V0,Vmax之間的關系,a=In((Vmax-V0)/V0).b決定曲線的快慢,b越大V變化越快,也就越快接近Vmax。
單片機一般采用定時器來産生脈沖控制電機的轉動,産生脈沖的頻率決定電機轉動的快慢,這個頻率與單片機的晶振的頻率nXtal,定時器的預分頻nPrevXtal,定時器的自動重裝載寄存器的資料Xload有關,晶振的頻率由硬體決定,定時器的預分頻在單片機的初始化的時候設定,那麼我們要改變電機的運作速度,就隻能通過改變定時器的的自動重裝載寄存器的資料。通常的做法是把自動重裝載寄存器的資料放到一個數組裡面,現在要做的是如何生成這個數組的資料。我這裡介紹使用上位機VC編寫界面來生成這個數組及曲線。如下圖:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5CMiVjM1ETN5IGN1cTMjhDZ0YGZ4YzMhhTN5ImYykTO38CX0JXZ252bj91Ztl2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
軟體界面需要設定的資料有:晶振頻率nXtal,預分頻nPrevXtal,步進電機驅動器細分nPrevMotor,運作的最大速度nMaxSpeed,達到最大速度時的位置坐标(對應界面上的極限)nMaxPoint以及a,b參數是通過滑動條設定,a對應起始速度,b對應加速快慢.
速度與自動重裝載寄存器的關系
電機的轉速的機關一般是rpm,即一分鐘多少轉.如果電機的轉速是V(rpm),那麼自動重裝載寄存器的資料應該是多少?步進電機驅動器細分為nPrevMotor,那麼單片機發脈沖的速度是nPrevMotorV/60每秒,即定時器一秒鐘産生中斷的個數。
**1/(Xload/(nXtal/nPrevXtal))=(nPrevMotorV/60)**
Xload=60nXtal/(nPrevXtalnPrevMotor*V)
其中V=Vmax/(1+Exp(a-bt)),即
**Xload=60nXtal*(1+Exp(a-bt))/(nPrevXtalnPrevMotor*Vmax)**
Xload是自動重裝載寄存器的資料,nXtal是晶振頻率,nPrevXtal是預分頻系數。
VC生成數組的代碼如下:
int nMaxPoint,nXtal,nPrevXtal,nPrevMotor,nMaxSpeed;
nMaxPoint = GetDlgItemInt(IDC_EDIT_MAX_POINT);
nXtal = GetDlgItemInt(IDC_EDIT_XTAL);
nPrevXtal = GetDlgItemInt(IDC_EDIT_PREV_XTAL);
nPrevMotor = GetDlgItemInt(IDC_EDIT_MOTOR_F);
nMaxSpeed = GetDlgItemInt(IDC_EDIT_SPEED_MAX);
double k;
k= (double)nMaxSpeed;
CString strArray;
unsigned short nTimerCount;
strArray.AppendFormat(_T("/*============================================================================\r\n"));
strArray.AppendFormat(_T("晶振頻率 = %d;\r\n"),nXtal);
strArray.AppendFormat(_T("預分頻頻率 = %d;\r\n"),nPrevXtal);
strArray.AppendFormat(_T("極限點 = %d;\r\n"),nMaxPoint);
strArray.AppendFormat(_T("極限轉速 = %d;\r\n"),nMaxSpeed);
strArray.AppendFormat(_T("周脈沖數 = %d;\r\n"),nPrevMotor);
strArray.AppendFormat(_T("S型曲線\r\n"));
strArray.AppendFormat(_T("============================================================================*/\r\nunsigned int code WaitTable[]={\r\n"));
for(int i= 0;i<nMaxPoint;i++)
{
nTimerCount = (nXtal)*(1+exp(a-b*i))/(nPrevXtal*nPrevMotor*nMaxSpeed);
strArray.AppendFormat(_T("0x%04X, "),nTimerCount);
if (((i+1)%10)==0)
{
strArray.AppendFormat(_T(" // %d\r\n"),(i/10+1)*10);
}
}
strArray.AppendFormat(_T("};\r\n"));
SetDlgItemText(IDC_EDIT_DISPLAY,strArray);
就這樣生成一個S曲線的資料數組,隻需要把這個這個數組拷貝到你的單片機程式裡面,定時器使用比較中斷的方式,在中斷處理函數裡面,移動數組的下标即可。當然如果單片機是stm32,還可以使用DMA的方式來做,這樣可以減少中斷.
S型曲線界面的繪制
這個S曲線的顯示使用的是一個Picture控件顯示,根據輸入晶振頻率,預分頻,最大速度,極限點。。來繪制,使用GDI相關接口在Picture控件視窗面繪制.代碼如下:
int CSCurveDlg::DrawCurve(void)
{
CWnd* pWnd = GetDlgItem(IDC_EDIT_DISPLAY);
if(NULL!=pWnd)
{
RECT rect;
pWnd->GetClientRect(&rect);
int nHeight = rect.bottom-rect.top-4;
int nWidth = rect.right-rect.left-4;
CDC* pDC = pWnd->GetDC();
pDC->FillSolidRect(&rect,RGB(255,255,255));
POINT p1,p2;
int i;
double y1,y2;
double k;
k = (double)GetDlgItemInt(IDC_EDIT_SPEED_MAX);
int nYmax=DrawTable(pDC,nWidth,nHeight);
int nMaxPoint = GetDlgItemInt(IDC_EDIT_MAX_POINT);
CSliderCtrl* pSlider1 = (CSliderCtrl*)GetDlgItem(IDC_SLIDER_ACC);
b=(double)(((double)pSlider1->GetPos())/20);
for (i=0;i<nMaxPoint;i++)
{
y1 = (nYmax-5)/(1+exp(a-(b*i)));
y2 = (nYmax-5)/(1+(exp(a-b*(i+1))));
p1.x=i*nWidth/nMaxPoint;
p2.x=(i+1)*nWidth/nMaxPoint;
p1.y = nHeight-y1;
p2.y = nHeight-y2;
pDC->MoveTo(p1);
pDC->LineTo(p2);
}
}
return 0;
}
源碼下載下傳