stm32控制电机
一、總體思路
使用端口GPIOA來連接電機,所以給GPIOA編程就可以控制電機。使用系統時鐘SysTick來周期性的給電機發送脈沖。用四個按鈕來控制需要發送脈沖的個數,每個按鈕被按下就設置給電機發送脈沖的個數,如果上一次給電機發送的脈沖沒有發送完成,這次按鈕發送的脈沖將不被響應。
二、GPIOA端口的設置
由于需要控制兩個電機,所以將GPIOA端口的1,2,3號引腳與電機0相連(分別控制電機的使能,旋轉方向和脈沖),GPIOA的4,5,6號引腳與電機1相連。具體對端口的初始化代碼為:
GPIO_InitTypeDef GPIO_InitStruct; //開啟電機0外設時鐘 DJ_EnablePeriphClock_0(); //初始化電機0 GPIO_InitStruct.GPIO_Pin = DJ_EN_0 | DJ_DR_0 | DJ_MC_0; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(DJ_GPIO_0, &GPIO_InitStruct); //設置電機0的初始化狀態 DJ_DisEnable(DJ_GPIO_0, DJ_EN_0); //關閉電機0
上面的代碼是對與電機0連接的引腳的初始化,電機1的初始化是一樣的,只是引腳不同了。從上面的代碼可以看到引腳的輸出模式是推挽的(為了做Debug),實際應該使用開漏的,由于我們要給電機輸入5V的高電平,所以我們應該在外部接一個上拉電阻,電源為5V。
三、SysTick設置
SysTick是一個系統定時器,系統的滴答是可以配置的,在控制電機的程序中我們將系統滴答設置為100us,理論上可以將系統滴答設置為1/72000000s,由于系統的時鐘為72MHz。每個脈沖間隔為5個滴答。也就是說每隔500us發送一個脈沖,脈沖周期為1ms。
設置系統滴答通過宏:
#define TICK 10000 //100us一個滴答
實際的配置是通過下面代碼:
SysTick_Config(SystemCoreClock / TICK);
為了實現每隔5個系統滴答發送一個脈沖,定義了兩個全局變量TimingDelay和TimingLoad,可以通過函數Timer來設置這個變量的值:
void Timer(__IO uint32_t nTime)
{
TimingDelay = nTime;
TimingLoad = nTime;
}
TimingDelay表示當前距離發送下一個脈沖還需要等待的滴答數,TimingLoad 表示發送脈沖的間隔,如果每個脈沖間隔為5個滴答,則TimingLoad =5。這樣在系統時鐘的每次中斷代碼中將TimingDelay減1,當TimingDelay為0時就向電機發送脈沖(將對應電機脈沖的引腳的值變反就可以了),然后重新將TimingLoad賦值給TimingDelay來準備下一個脈沖的發送。具體代碼如下:
if (TimingDelay)
TimingDelay--;
else
{
TimingDelay = TimingLoad;
if (dj_GetMc()) //判斷是否還需要發送脈沖
{
printfd("
send %dth pulse, %d", dj_GetMc(), 1 - GPIO_ReadOutputDataBit (DJ_GPIO_0, DJ_MC_0)); //用于調試
DJ_IO(1 - GPIO_ReadOutputDataBit (DJ_GPIO_0, DJ_MC_0), DJ_GPIO_0, DJ_MC_0); //用于發送脈沖
dj_DesMc();
}
else
SysTick_Shutdown(); //關閉系統時鐘
}
dj_GetMc函數和dj_DesMc函數分別獲得全局變量dj_McCount的值和對該全局變量減1,這個全局變量代表總共需要發送幾個脈沖。正如開頭說的,按下一個鍵就設置需要發送的脈沖數,當脈沖發完了,就關閉系統定時器。
四、按鍵設置
使用ARM板自帶的WAKEUP,TAMPER,USER1,USER2四個鍵來配置需要發送脈沖的個數,它們分別配置為需要發送2,20,200,2000個脈沖。我們通過中斷的方式來檢查哪個鍵被按下了。配置將四個按鍵與EXTI相連,讓EXTI產生中斷到中斷控制器NVIC。首先需要配置NVIC的搶占優先級和響應優先級,直接調用庫函數就可以了:
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
然后是配置按鍵與EXTI相連,具體配置代碼如下:
static void NVIC_SetVector( IRQn_Type IRQn, uint8_t PreemptionPriority, uint8_t SubPriority)
{
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = IRQn;//EXTI0_IRQn | EXTI9_5_IRQn | EXTI3_IRQn | EXTI15_10_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = PreemptionPriority;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = SubPriority;
NVIC_Init(&NVIC_InitStruct);
}
//WAKEUP鍵
static void EXTI_PA0_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
EXTI_InitTypeDef EXTI_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA, ENABLE);
NVIC_SetVector(EXTI0_IRQn, 0, 0); //配置NVIC
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); //配置GPIOA_Pin0為EXTI0線
EXTI_InitStruct.EXTI_Line = EXTI_Line0;
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt; //中斷模式
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising ; //上升沿觸發
EXTI_Init(&EXTI_InitStruct);
}
上面的代碼顯示了配置WAKEUP鍵,其它鍵也是同樣的配置。當按下一個鍵時,對應的中斷響應函數就會執行,我們在響應函數中判斷全局變量dj_McCount是否為0,如果不為0,說明上一次按鍵的脈沖還沒有發生完成,則直接退出中斷響應函數;如果為0,說明當前沒有在發生脈沖,則設置dj_McCount為2,開啟系統定時器來發送脈沖。代碼如下:
//WAKEUP
void EXTI0_IRQHandler(void)
{
if (EXTI_GetFlagStatus(EXTI_Line0) != RESET) //看是否產生了EXTI_Line0中斷
{
printfd("
exti0");
if (dj_GetMc() == 0)
{
dj_SetMc(1);
SysTick_Startup();
}
EXTI_ClearFlag(EXTI_Line0); //清除中斷標志位
}
}
源代碼:http://pan.baidu.com/s/1uy6PK
總結
- 上一篇: 测序的PCR duplicates及用s
- 下一篇: 月夜思乡(杜甫的月夜思乡,言在彼而意在此