本帖最后由 resumebb 于 2020-7-24 16:19 編輯
一、硬件
1.硬件準備:57步進電機(型號57CM18),驅(qū)動器TB6600,開發(fā)板STM32F407ZGT6,SN-4NDO限位金屬傳感器,檢測面在9mm左右。

2.連線
驅(qū)動器右邊分有兩個區(qū)域
Signal:用于驅(qū)動器與開發(fā)板連接,進行電機的控制驅(qū)動。
ENA接口:當此信號有效時,驅(qū)動器將自動切斷電機繞組電流,使電機處于自由狀態(tài)(無保持轉(zhuǎn)矩)。當此信號不連接時默認為無效狀態(tài),這時電機繞組通以電流,可正常工作。
DIR接口:控制電機旋轉(zhuǎn)方向,信號有效時電機順時針旋轉(zhuǎn),無效時逆時針旋轉(zhuǎn)。
PUL接口:步進電機驅(qū)動器把控制器發(fā)出的脈沖信號轉(zhuǎn)化為步進電機的角位移,驅(qū)動器每接受一個脈沖信號 PUL,就驅(qū)動步進電機旋轉(zhuǎn)一個步距角,PUL 的頻率和步進電機的轉(zhuǎn)速成正比。對于最佳輸入要求,此信號占空比最好 1:1,脈沖信號的頻率不大于100KHz。
連接方式有兩種方法:
(1)共陽極連接

將驅(qū)動器的ENA+,DIR+,PUL+接地, 陰極接電,也就是開發(fā)板的相對應(yīng)的控制管腳。
(2)共陰極連接

如STM32F407接線如下:
ENA+(驅(qū)動器) PE6(開發(fā)板)
DIR+(驅(qū)動器) PE5(開發(fā)板)
PUL+(驅(qū)動器) PC7(開發(fā)板)
ENA- DIR- PUL-(驅(qū)動器) GND(開發(fā)板)
3. High Voltage區(qū)域
該區(qū)域用于驅(qū)動器與步進電機連接。
和下圖類似:

電機接法:

這里我采用的是驅(qū)動器接法是共陰極接法

對于電源,開發(fā)板使用3.3v,電機使用12v,1A,可根據(jù)實際情況調(diào)整。

4.細分
根據(jù)需求,該驅(qū)動器最多支持32細分,根據(jù)指示的S1,S2,S3開關(guān)狀態(tài)調(diào)整驅(qū)動器側(cè)面的dip撥碼進行細分選擇,同樣可以通過S4,S5,S6三個開關(guān)控制電流大小,最大支持3.5A,峰值電流為4.0A。
我這里采用了4細分。具體如下圖:

5.故障問題

PWR:綠燈,電源指示燈。
ALARM:紅燈,故障(過流、過熱和欠壓)時亮。紅燈亮起時,表明驅(qū)動器出故障了,
請立即切斷驅(qū)動器電源,排除故障后再繼續(xù)操作。
6.限位金屬傳感器雖然說是傳感器,但其實就是一個開關(guān)量,就跟光電開關(guān)一樣。有兩種接法: 
藍線接地,棕線接電源,黑色線作為輸出接入開發(fā)板作為輸入,在PNP接法中,常態(tài)黑色線為低電平,當傳感器檢測到物體時,會輸出24V正電壓。 
NPN接法差別就是檢測到物體時,黑線輸出的是負電壓。 
我這里將傳感器的黑線輸出連接至KEY0作為對開發(fā)板的輸入,當檢測到物體時,PB0引腳會變?yōu)榈碗娖健?/font>
二、代碼
驅(qū)動器代碼參照正點原子的例程,然后針對具體的情況做了相應(yīng)的更改
主要用到了四個函數(shù)
void Driver_Init(void);//驅(qū)動器初始化
void TIM8_OPM_RCR_Init(u16 arr, u16 psc);//TIM8_CH2 初始化 單脈沖+重復(fù)計數(shù)模式
void Locate_Rle(long num, u32 frequency, DIR_Type dir) //相對定位函數(shù)
void Locate_Abs(long num, u32 frequency);/絕對定位函數(shù)
1.驅(qū)動初始化
由于ENA和DIR使用的引腳為PE6,PE5,因此在初始化中對它們進行相關(guān)的初始化即可(可以根據(jù)自己的開發(fā)板來更改引腳)。
整體流程:
定義GPIO結(jié)構(gòu)體
使能GPIOE時鐘
對結(jié)構(gòu)體進行相關(guān)初始化,推挽輸出,上拉等
設(shè)置PE5,輸出為高電平沿順時針方向
設(shè)置PE6,輸出為低電平,使能輸出
- void Driver_Init(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
-
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
-
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
- GPIO_Init(GPIOE, &GPIO_InitStructure);
-
- GPIO_SetBits(GPIOE,GPIO_Pin_5);
- GPIO_ResetBits(GPIOE,GPIO_Pin_6);
- }
復(fù)制代碼
2.定時器
定時器的時基單元主要有三個寄存器組成:16位計數(shù)器,自動重轉(zhuǎn)載寄存器(包括一個影子寄存器),預(yù)分頻器(控制計數(shù)器時鐘),其中預(yù)分頻計數(shù)器的時鐘頻率1——65535。
16位向上、向下、向上/向下自動裝載計數(shù)器
● 16位可編程(可以實時修改)預(yù)分頻器,計數(shù)器時鐘頻率的分頻系數(shù)為1~65536之間的任意
數(shù)值
● 4個獨立通道:
─ 輸入捕獲
─ 輸出比較
─ PWM生成(邊緣或中間對齊模式)
─ 單脈沖模式輸出
● 使用外部信號控制定時器和定時器互連的同步電路
● 如下事件發(fā)生時產(chǎn)生中斷/DMA: ─ 更新:計數(shù)器向上溢出/向下溢出,計數(shù)器初始化(通過軟件或者內(nèi)部/外部觸發(fā))
─ 觸發(fā)事件(計數(shù)器啟動、停止、初始化或者由內(nèi)部/外部觸發(fā)計數(shù))
─ 輸入捕獲
─ 輸出比較
● 支持針對定位的增量(正交)編碼器和霍爾傳感器電路
● 觸發(fā)輸入作為外部時鐘或者按周期的電流管理
因為用到TIME8與GPIOC(進行端口復(fù)用),所以使能對應(yīng)的時鐘。將GPIOC的Pin7復(fù)用為TIME8,對TIME8的結(jié)構(gòu)體進行變量初始化,查開發(fā)手冊可以知道,PC7復(fù)用功能為TIME8的CH2。
整體流程
配置TIME8,GPIOC時鐘。
初始化TIM8,設(shè)置ARR(自動裝填值即周期),PSC(時鐘預(yù)分頻系數(shù))
設(shè)置TIM8_CH2的PWM模式,使能TIM2_CH2輸出
使能TIM2
- <span style="background-color: rgb(255, 255, 255);">/</span>***********************************************
- //TIM8_CH2(PC7) 單脈沖輸出+重復(fù)計數(shù)功能初始化
- //TIM8 時鐘頻率 84*2=168MHz
- //arr:自動重裝值
- //psc:時鐘預(yù)分頻數(shù)
- ************************************************/
- void TIM8_OPM_RCR_Init(u16 arr,u16 psc)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
- TIM_OCInitTypeDef TIM_OCInitStructure;
- NVIC_InitTypeDef NVIC_InitStructure;
-
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8,ENABLE); //TIM8時鐘使能
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); //使能PORTC時鐘
-
- GPIO_PinAFConfig(GPIOC,GPIO_PinSource7,GPIO_AF_TIM8); //GPIOC7復(fù)用為定時器8
-
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //GPIOC7
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //復(fù)用功能
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //速度100MHz
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽復(fù)用輸出
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; //下拉
- GPIO_Init(GPIOC,&GPIO_InitStructure); //初始化PF9
-
- TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
-
- TIM_TimeBaseStructure.TIM_Period = arr; //設(shè)置在下一個更新事件裝入活動的自動重裝載寄存器周期的值
- TIM_TimeBaseStructure.TIM_Prescaler =psc; //設(shè)置用來作為TIMx時鐘頻率除數(shù)的預(yù)分頻值
- TIM_TimeBaseStructure.TIM_ClockDivision = 0; //設(shè)置時鐘分割:TDTS = Tck_tim
- TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上計數(shù)模式
- TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure); //根據(jù)TIM_TimeBaseInitStruct中指定的參數(shù)初始化TIMx的時間基數(shù)單位
- TIM_ClearITPendingBit(TIM8,TIM_IT_Update);
-
- TIM_UpdateRequestConfig(TIM8,TIM_UpdateSource_Regular); /********* 設(shè)置只有計數(shù)溢出作為更新中斷 ********/
- TIM_SelectOnePulseMode(TIM8,TIM_OPMode_Single);/******* 單脈沖模式 **********/
-
- TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //選擇定時器模式:TIM脈沖寬度調(diào)制模式2
- TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比較輸出2使能
- TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable; /****** 比較輸出2N失能 *******/
- TIM_OCInitStructure.TIM_Pulse = arr>>1; //設(shè)置待裝入捕獲比較寄存器的脈沖值,右移一位
- TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //輸出極性:TIM輸出比較極性高
- TIM_OC2Init(TIM8, &TIM_OCInitStructure); //根據(jù)TIM_OCInitStruct中指定的參數(shù)初始化外設(shè)TIMx
-
- TIM_OC2PreloadConfig(TIM8, TIM_OCPreload_Enable); //CH2預(yù)裝載使能
- TIM_ARRPreloadConfig(TIM8, ENABLE); //使能TIMx在ARR上的預(yù)裝載寄存器
-
- TIM_ITConfig(TIM8, TIM_IT_Update ,ENABLE); //TIM8 使能或者失能指定的TIM中斷
-
- NVIC_InitStructure.NVIC_IRQChannel = TIM8_UP_TIM13_IRQn; //TIM8中斷
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //先占優(yōu)先級1級
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //從優(yōu)先級1級
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
- NVIC_Init(&NVIC_InitStructure); //根據(jù)NVIC_InitStruct中指定的參數(shù)初始化外設(shè)NVIC寄存器
-
- TIM_ClearITPendingBit(TIM8, TIM_IT_Update); //清除TIMx的中斷待處理位:TIM 中斷源
- TIM_Cmd(TIM8, ENABLE); //使能TIM8
- }
- 3.中斷服務(wù)函數(shù)
- void TIM8_UP_TIM13_IRQHandler(void)
- {
- if(TIM_GetITStatus(TIM8,TIM_FLAG_Update)!=RESET)//更新中斷
- {
- TIM_ClearITPendingBit(TIM8,TIM_FLAG_Update);//清除更新中斷標志位
- if(is_rcr_finish==0)//重復(fù)計數(shù)器未設(shè)置完成
- {
- if(rcr_integer!=0) //整數(shù)部分脈沖還未發(fā)送完成
- {
- TIM8->RCR=RCR_VAL;//設(shè)置重復(fù)計數(shù)值
- rcr_integer--;//減少RCR_VAL+1個脈沖
- }else if(rcr_remainder!=0)//余數(shù)部分脈沖 不為0
- {
- TIM8->RCR=rcr_remainder-1;//設(shè)置余數(shù)部分
- rcr_remainder=0;//清零
- is_rcr_finish=1;//重復(fù)計數(shù)器設(shè)置完成
- }else goto out; //rcr_remainder=0,直接退出
- TIM_GenerateEvent(TIM8,TIM_EventSource_Update);//產(chǎn)生一個更新事件 重新初始化計數(shù)器
- TIM_CtrlPWMOutputs(TIM8,ENABLE); //MOE 主輸出使能
- TIM_Cmd(TIM8, ENABLE); //使能TIM8
- if(motor_dir==CW) //如果方向為順時針
- current_pos+=(TIM8->RCR+1);//加上重復(fù)計數(shù)值
- else //否則方向為逆時針
- current_pos-=(TIM8->RCR+1);//減去重復(fù)計數(shù)值
- }else
- {
- out: is_rcr_finish=1;//重復(fù)計數(shù)器設(shè)置完成
- TIM_CtrlPWMOutputs(TIM8,DISABLE); //MOE 主輸出關(guān)閉
- TIM_Cmd(TIM8, DISABLE); //關(guān)閉TIM8
- printf("當前位置=%ld\r\n",current_pos);//打印輸出
- }
- }
- }
復(fù)制代碼
4.相對定位函數(shù)
首先判斷脈沖如果小于0就停止運行。頻率的取值在20-100000Hz之間,如果不在這個范圍內(nèi)就終止。
通過傳入的參數(shù)dir可以知道旋轉(zhuǎn)方向,若為順時針,就用當前位置加上一個脈沖對應(yīng)的步距,如果是逆時針就減去。
最后獲取重復(fù)計數(shù)器的整數(shù)和余數(shù)部分,開啟TIM8
6.限位傳感器中斷初始化
- void EXTIX_Init(void)
- {
-
- //PB0使用Exit0號中斷線,PG1使用Exit1,PC2使用Exit2,PA3使用Exit3
- NVIC_InitTypeDef NVIC_InitStructure;
- EXTI_InitTypeDef EXTI_InitStructure;
- GPIO_InitTypeDef GPIO_InitStructure;
-
-
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB|RCC_AHB1Periph_GPIOG|RCC_AHB1Periph_GPIOC|RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOB,GPIOG,GPIOC,GPIOA時鐘
-
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//使能SYSCFG時鐘(中斷需要使用AFIO時鐘)
-
-
-
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PB0對應(yīng)IO配置
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//普通輸入模式
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100M
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
- GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB0
-
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //PG1對應(yīng)IO配置
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//普通輸入模式
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100M
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
- GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化GPIOG1
-
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PC2對應(yīng)IO配置
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//普通輸入模式
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100M
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
- GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化GPIOC2
-
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //PA3對應(yīng)IO配置
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//普通輸入模式
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100M
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
- GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA3
-
-
-
-
- SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource0);//PB0 連接到中斷線0
- SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOG, EXTI_PinSource1);//PG1 連接到中斷線1
- SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource2);//PC2 連接到中斷線2
- SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource3);//PA3 連接到中斷線3
-
- //配置0號中斷線
- EXTI_InitStructure.EXTI_Line = EXTI_Line0|EXTI_Line1 | EXTI_Line2 | EXTI_Line3;//LINE0
- EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中斷事件
- //初始狀態(tài)為低電平,當檢測到物體時,KEY0輸出高電平,此時INT0導(dǎo)通,變?yōu)榈碗娖剑磸纳仙靥冎料陆笛貢r觸發(fā)
- EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
- EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能LINE0
- EXTI_Init(&EXTI_InitStructure);//配置
-
-
- NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;//PB0對應(yīng)的外部中斷0
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;//不區(qū)分優(yōu)先級,只需要電平轉(zhuǎn)換時進入中斷即可
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中斷通道
- NVIC_Init(&NVIC_InitStructure);//配置
-
- NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;//外部中斷2
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;//搶占優(yōu)先級3
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;//子優(yōu)先級2
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中斷通道
- NVIC_Init(&NVIC_InitStructure);//配置
-
-
- NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;//外部中斷3
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;//搶占優(yōu)先級2
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;//子優(yōu)先級2
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中斷通道
- NVIC_Init(&NVIC_InitStructure);//配置
-
-
- NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;//外部中斷4
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;//搶占優(yōu)先級1
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;//子優(yōu)先級2
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中斷通道
- NVIC_Init(&NVIC_InitStructure);//配置
-
- }
復(fù)制代碼
7.電平檢測與中斷服務(wù)函數(shù)
- u8 Check_Sensor_State(void)
- {
-
- //高電平?jīng)]有檢測到
- if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == SET)
- {
- return NO_Tagger;
- }
- //低電平檢測到
- else
- {
- return Tagger;
- }
- }
復(fù)制代碼 四個服務(wù)函數(shù)根據(jù)自己的需求寫,可以正轉(zhuǎn)反轉(zhuǎn),加減速,停止啥的
- void EXTI0_IRQHandler(void)
- {
- if(EXTI_GetITStatus(EXTI_Line0) == SET)
- {
- //可以停止,可以反轉(zhuǎn)
- EXTI_ClearITPendingBit(EXTI_Line0);
- }
- }
復(fù)制代碼
6.main函數(shù)
主函數(shù)也很簡單,先進行相關(guān)初始化,通過按鍵操控電機,按下wkup就通過絕對定位函數(shù)回到零點,按下key0就以500hz的頻率順時針發(fā)送200脈沖,假如不設(shè)置細分,該操作就是順時針旋轉(zhuǎn)一圈,key1也是一樣,逆時針發(fā)送500脈沖。這里設(shè)置了一個計數(shù)器i,工作了50次后led會有一個提示。
7.結(jié)果
最終運行程序,電機就會轉(zhuǎn)動起來,同時驅(qū)動器下面的led燈會閃爍藍色的燈光,通過脈沖加頻率可以調(diào)整速度,也可以通過細分設(shè)定去調(diào)節(jié)。當用金屬擋在傳感器前時,黑色線輸出正電壓,PB0變?yōu)榈碗娖剑瑱z測函數(shù)檢測到電平發(fā)生變化,進入中斷,停止電機或者反轉(zhuǎn)都行,拿開物體后,電機恢復(fù)原來的運動狀態(tài)。
中斷服務(wù)函數(shù)里面可以根據(jù)具體需求來寫,可以正轉(zhuǎn)反轉(zhuǎn)停止各種,我這里主函數(shù)開始一直讓電機順時針旋轉(zhuǎn),當檢測到物體后進入中斷,調(diào)取中斷服務(wù)函數(shù),打印一下exti(代碼寫成exit了)提示信息 ,然后設(shè)置電機進行逆時針旋轉(zhuǎn),當傳感器沒有被遮擋后,又恢復(fù)順時針旋轉(zhuǎn)。
完整項目(步進電機驅(qū)動+限位傳感器)
需要用到驅(qū)動可以下載我打包的驅(qū)動包,將其放置在HARDWARE目錄下,使用時調(diào)用driver.h文件即可,在使用時,根據(jù)具體電路圖或者開發(fā)手冊,調(diào)整驅(qū)動器對應(yīng)的引腳號,電平,定時器,通道等初始化設(shè)置即可。
博客:https://blog.csdn.net/qq_41573860/article/details/107254090
|