天天看點

stm32制作的微型雕刻機 ,你可以不?

附上:點選參考

購買元器件附帶3D封裝:https://weidian.com/?userid=1238350417&wfr=c&ifr=shopdetail

看到網上有好多做微型雷射雕刻機的DIY,手頭正好有幾個拆下來的筆記本光驅,把光驅裡的步進電機拆了出來,做了這個雕刻機。由于我手頭沒有雷射頭,偷懶用原子筆來代替雷射頭。

采用STM32F103ZET6最小系統闆做的三軸關聯,步進電機驅動沒有采用專門的驅動闆,使用了L298N或者L9110S,由STM32的PWM來控制步進電機。

現在隻實作了最基本的幾個功能,支援G代碼 G0,G1,G2,G3和M3(Z軸下降),M5(Z軸上升),圖形界面和按鈕控制現在還沒有做。

作業系統采用風舞天的MSOS作業系統,最大支援8個任務是在UCOS基礎上簡化而來的。MSOS的支援郵箱資訊和8個互斥量,GUI是自己加的。

源代碼檔案目錄中Keil_RAM目錄裡的工程檔案是直接在RAM中調試,KEIL用JLINK下載下傳到系統闆中不會擦除FLASH中的内容,直接用RAM進行調試和仿真。Keil_FLASH目錄裡的工程檔案是直接在FLASH中調試,KEIL用JLINK下載下傳到系統闆中會更新FLASH中的内容。這2個目錄共用系統檔案和驅動程式。

G代碼生成使用的是Inkscape

我G代碼下載下傳使用的是G-CODE SENDER來下載下傳到開發闆,還沒有做SD卡脫機。

MSOS任務的參數數量在OS.H 中定義

#define TaskSum        4           任務總數。現在定義了4個,如果超過4個就必須修改,最大支援8個任務,包括GUI的任務

#define TaskStackSum     100         任務棧深度,如果函數調用多的話這個值需加大

#define QueueStackSum   20     消息隊列深度,總共可以有20個等待處理的消息,超出20個的話會丢失消息

建立任務前還需定義任務句柄,建立任務後任務句柄的值同時也是任務的優先級

u8 CtrlTaskPriority ;  控制任務

u8 PWMTaskPriority ;  PWM任務

u8 ShowTaskPriority ;  顯示解析任務

優先級按照建立的順序,最早建立的是優先級最高,GUI任務GUI_API.CreateTask();必須最後建立,如果不用GUI任務,則最低優先級的任務不能有OS.PendMessageQueue函數,必須為死循環。

任務資訊的傳遞使用PostMessageQueue 和PendMessageQueue 函數

static void * PendMessageQueue (u32 timeout)

static u8 PostMessageQueue (u8 Priority, void *messagePointer)

互斥量使用OSMutexLock 和OSMutexUnLock ,互斥量最大為8個,編号為0-7,其中第7個我用在GUI上了

u8 OSMutexLock (u8 OSMutexNum)

void  OSMutexUnLock (u8 OSMutexNum)

同時MSOS提供軟體定時器,提供2種模式,1種由使用者指定定時器編号時間間隔為0.1MS(1s需要delay = 10000),1種由系統自動配置設定定時器編号時間間隔為1ms(1s需要delay = 1000)。

使用

   OS.Timer.Start = Start;

   OS.Timer.StopAt = StopAt; 

   OS.Timer.StartAt = StartAt; 

OS.Timer.StopAt(u8 id) 

OS.Timer.StartAt(u8 id, u32 delay, function registerFunction)

OS.Timer.Start(TimerhandleModeEnum handleMode, u32 delay, function registerFunction)

由于我沒有專用的步進電機控制器,隻有原來做小車時的L298N電機驅動子產品,它有2個H橋可以驅動1個兩相四線制步進電機,在網上找了步進電機的驅動方法

它按A、AB、B、BC、C、CD、D、DA的順序交替進行線圈的勵磁。

     A  B  C  D 

T1 1  0  0  0 

T2 1  1  0  0 

T3 0  1  0  0 

T4 0  1  1  0 

T5 0  0  1  0 

T6 0  0  1  1 

T7 0  0  0  1 

T8 1  0  0  1  

T1-T8表示脈沖周期;ABCD表示電機的各相,1表示此時有一個脈沖,0表示沒有脈沖。

但程式編好後下載下傳到開發闆,發現步進電機的運作很不平穩,聲音很大,且1個步距隻有8個脈沖周期,定位的間距很大,出來的效果很不好。再上網查詢專用的步進電機驅動器有脈沖分頻,可以控制很小的控制角度,是以我就改用正弦波進行驅動,ABCD的正弦波角度差90度,步進電機旋轉一圈共需要256個脈沖,這樣每個脈沖的步距很小,且運作很平穩。

我的程式中使用TIM3、TIM4、TIM5為PWM脈沖輸出,TIM2作為定時器,根據控制需要來設定PWM的脈寬。

這是TIM的初始化程式

u16 psc = 49;

TIMx_Init(TIM2,1023,psc);                  

//定時時間為72MHz/50/1024=1.4KHz               

TIM3_PWM_Init(1023,psc);                       

//使用TIM3-5做PWM單獨輸出,TIM3 A相;TIM4 B相;TIM5 C相

TIM4_PWM_Init(1023,psc);       

TIM5_PWM_Init(1023,psc);

這個是PWM對應4相的脈寬計算

#define MAICHONG        128                        //每相馬達的脈沖數量,總脈沖數為256個

#define MAICHONG1        MAICHONG/4                        //馬達的脈沖數量

#define MAICHONG2        MAICHONG/2                        //馬達的脈沖數量

#define MAICHONG3        MAICHONG/4*3                        //馬達的脈沖數量

const

u16  Sin[]={        

//128個脈沖的時序,用正弦波函數發生器産生的,自己懶得去減0x3FF,在計算每相脈沖時自動計算

0x3FF,0x431,0x463,0x495,0x4C7,0x4F8,0x528,0x558,0x587,0x5B5,0x5E1,0x60D,0x638,0x661,0x688,0x6AE

,0x6D3,0x6F5,0x716,0x735,0x752,0x76D,0x786,0x79C,0x7B1,0x7C3,0x7D2,0x7E0,0x7EB,0x7F3,0x7FA,0x7FD

,0x7FE,0x7FD,0x7FA,0x7F3,0x7EB,0x7E0,0x7D2,0x7C3,0x7B1,0x79C,0x786,0x76D,0x752,0x735,0x716,0x6F5

,0x6D3,0x6AE,0x688,0x661,0x638,0x60D,0x5E1,0x5B5,0x587,0x558,0x528,0x4F8,0x4C7,0x495,0x463,0x431

};

u16 Moto_A1[MAICHONG];

u16 Moto_A2[MAICHONG];

u16 Moto_B1[MAICHONG];

u16 Moto_B2[MAICHONG];

void

JiSuan(

void

)

{

u8 i;

for

(i=0;i<100;i++)

{

if

(i<MAICHONG1)

{

Moto_A1[i] = Sin[i]-0x3ff;

Moto_A2[i] = 0;                               

Moto_B1[i] = 0;

Moto_B2[i] = Sin[i+MAICHONG1]-0x3ff;                                       

}

else

if

(i<MAICHONG2)

{

Moto_A1[i] = Sin[i]-0x3ff;       

Moto_A2[i] = 0;               

Moto_B1[i] = Sin[i-MAICHONG1]-0x3ff;

Moto_B2[i] = 0;                               

}                       

else

if

(i<MAICHONG3)

{

Moto_A1[i] = 0;       

Moto_A2[i] = Sin[i-MAICHONG2]-0x3ff;               

Moto_B1[i] = Sin[i-MAICHONG1]-0x3ff;

Moto_B2[i] = 0;                               

}                               

else

if

(i<MAICHONG)

{

Moto_A1[i] = 0;       

Moto_A2[i] = Sin[i-MAICHONG2]-0x3ff;               

Moto_B1[i] = 0;       

Moto_B2[i] = Sin[i-MAICHONG3]-0x3ff;                       

}               

}       

}

這個是步進電機資料的結構體

typedef

struct

{

u8 Flag;               

//需要脈沖輸出标志

u8 Dir;                       

//步進電機方向

u32 Step;               

//步進電機需要的脈沖數量

s32 Current;       

//步進電機目前位置

s32 Target;               

//步進電機目标位置

}MOTO_Struct;

具體的步進電機控制在TIM2中斷中實作,具體的函數如下

void

TIM2_IRQHandler(

void

)

//定時器中斷函數

{

u16 t;                               

//目前脈沖位置的臨時變量

if

(TIM_GetITStatus(TIM2,TIM_IT_Update)!=RESET)        

//判斷是否定時中斷

{

if

(Moto_X.Flag)

{

if

(Moto_X.Step > 0)

{               

Moto_X.Step--;                       

if

(Moto_X.Dir)

{

Moto_X.Current++;

}

else

{

Moto_X.Current--;

}

t= Moto_X.Current%MAICHONG;

TIM_SetCompare1(TIM4,Moto_A1[t]);

//改變PWM占空比               

TIM_SetCompare2(TIM4,Moto_A2[t]);

//改變PWM占空比               

TIM_SetCompare3(TIM4,Moto_B1[t]);

//改變PWM占空比               

TIM_SetCompare4(TIM4,Moto_B2[t]);

//改變PWM占空比                       

}

else

{

Moto_X.Flag = 0;

TIM_SetCompare1(TIM4,0);

//改變PWM占空比               

TIM_SetCompare2(TIM4,0);

//改變PWM占空比               

TIM_SetCompare3(TIM4,0);

//改變PWM占空比               

TIM_SetCompare4(TIM4,0);

//改變PWM占空比                                                       

}

}

if

(Moto_Y.Flag)

{               

if

(Moto_Y.Step > 0)

{               

Moto_Y.Step--;                       

if

(Moto_Y.Dir)

{

Moto_Y.Current++;

}

else

{

Moto_Y.Current--;

}

t= Moto_Y.Current%MAICHONG;

TIM_SetCompare1(TIM3,Moto_A1[t]);

//改變PWM占空比               

TIM_SetCompare2(TIM3,Moto_A2[t]);

//改變PWM占空比               

TIM_SetCompare3(TIM3,Moto_B1[t]);

//改變PWM占空比               

TIM_SetCompare4(TIM3,Moto_B2[t]);

//改變PWM占空比                       

}

else

{

Moto_Y.Flag = 0;

TIM_SetCompare1(TIM3,0);

//改變PWM占空比               

TIM_SetCompare2(TIM3,0);

//改變PWM占空比               

TIM_SetCompare3(TIM3,0);

//改變PWM占空比               

TIM_SetCompare4(TIM3,0);

//改變PWM占空比                                                       

}       

}                       

if

(Moto_Z.Flag)

{               

if

(Moto_Z.Step > 0)

{               

Moto_Z.Step--;                       

if

(Moto_Z.Dir)

{

Moto_Z.Current++;

}

else

{

Moto_Z.Current--;

}

t= Moto_Z.Current%MAICHONG;

TIM_SetCompare1(TIM5,Moto_A1[t]);

//改變PWM占空比               

TIM_SetCompare2(TIM5,Moto_A2[t]);

//改變PWM占空比               

TIM_SetCompare3(TIM5,Moto_B1[t]);

//改變PWM占空比               

TIM_SetCompare4(TIM5,Moto_B2[t]);

//改變PWM占空比                       

}

else

{

Moto_Z.Flag = 0;

TIM_SetCompare1(TIM5,0);

//改變PWM占空比               

TIM_SetCompare2(TIM5,0);

//改變PWM占空比               

TIM_SetCompare3(TIM5,0);

//改變PWM占空比               

TIM_SetCompare4(TIM5,0);

//改變PWM占空比                                                       

}       

}                       

}       

TIM_ClearITPendingBit(TIM2, TIM_FLAG_Update);

//必須清除中斷标志位否則一直中斷

}

stm32制作的微型雕刻機 ,你可以不?

學習  幹貨  識别二維碼,加關注