完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
看到网上有好多做微型激光雕刻机的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) /******************************************************************************* * 函数名 : PendMessageQueue * 描述 : 等待消息队列,当消息队列为空时,所在任务挂起 * 输入参数 : eventPointer 队列事件块指针,timeout 等待时间,1mS为单位 * 返回参数 : *******************************************************************************/ static u8 PostMessageQueue (u8 Priority, void *messagePointer) /******************************************************************************* * 函数名 : PostMessageQueue * 描述 : 发送一个消息到消息队列中,处于等待的任务会自动运行 * 输入参数 : eventPointer 队列事件块指针,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) /******************************************************************************* * 函数名 : Stop * 描述 : 停止某一路的软件定时器 * 输入参数 : id为0、1、2... * 返回参数 : 无 *******************************************************************************/ OS.Timer.StartAt(u8 id, u32 delay, function registerFunction) /******************************************************************************* * 函数名 : StartAt * 描述 : 启动0.1ms软件定时器,由用户指定软件定时器的编号 * 输入参数 : ID:指定的定时器编号 * : delay:延时节拍数,以系统节拍为单位 * : registerFunction: 注册回调执行函数,延时超时后,执行此函数。 * 返回参数 : *******************************************************************************/ OS.Timer.Start(TimerhandleModeEnum handleMode, u32 delay, function registerFunction) /******************************************************************************* * 函数名 : Start * 描述 : 启动1MS软件定时器由系统指定定时器编号 * 输入参数 : handleMode: 两种处理方式,一种直接在节拍中断中处理,适合费用低的, * 另一种在消息中处理,适合处理费用高的。 * : delay:延时节拍数,以系统节拍为单位 * : registerFunction: 注册回调执行函数,延时超时后,执行此函数。 * 返回参数 : u8类型,返回ID号,从0开始,若失败则返回invalid(-1) *******************************************************************************/ 由于我没有专用的步进电机控制器,只有原来做小车时的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]; /******************************************** 函数:JiSuan 功能:计算马达4个控制端的正弦波查表数据 参数:无 返回:无 说明: ********************************************/ void JiSuan( void ) { u8 i; for (i=0;i<100;i++) { if (i { Moto_A1 = Sin-0x3ff; Moto_A2 = 0; Moto_B1 = 0; Moto_B2 = Sin[i+MAICHONG1]-0x3ff; } else if (i Moto_A1 = Sin-0x3ff; Moto_A2 = 0; Moto_B1 = Sin[i-MAICHONG1]-0x3ff; Moto_B2 = 0; } else if (i Moto_A1 = 0; Moto_A2 = Sin[i-MAICHONG2]-0x3ff; Moto_B1 = Sin[i-MAICHONG1]-0x3ff; Moto_B2 = 0; } else if (i Moto_A1 = 0; Moto_A2 = Sin[i-MAICHONG2]-0x3ff; Moto_B1 = 0; Moto_B2 = 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); //必须清除中断标志位否则一直中断 } |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1786 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1622 浏览 1 评论
1089 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
730 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1680 浏览 2 评论
1942浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
739浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
576浏览 3评论
598浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
560浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-25 16:25 , Processed in 1.502901 second(s), Total 48, Slave 41 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号