完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
上节代码问题
上节代码应该是能搜到的控制ULN2003驱动步进28BYJ-48最通用的方法了,但是上节代码的执行会导致整个系统进行阻塞。如果电机运转10圈可能导致41s的阻塞时间,这对于任何系统工程都是致命的。 在这41s中整个cpu都在改变IO口状态和delay_ms中循环,主要流程如下: A相 --> delay_us(1000) --> AB相 --> delay_us(1000) --> B相 --> delay_us(1000) --> BC相 --> delay_us(1000) --.... --> delay_us(1000) --> A相 --> .... 其他任务得不到及时执行,这对于CPU是一种浪费,同时极大的影响系统及时性。 分析原因主要是由于delay_us(1000)造成的。 改进改进 本节将仍然采用八拍(天龙八步),即1-2相驱动方式驱动,电机旋转函数中将不再使用delay_us(1000),而是将每步相位的保持时间放在定时器函数中进行,基本可以实现异步控制步进电机,同时执行其他程序进行。本教程采用STM32F103驱动ULN2003控制步进电机28BYJ-48运转。 改进步进电机程序
/* 步进电机1参数宏 */ #define LA PAout(1) /* A相 */ #define LB PAout(2) /* B相 */ #define LC PAout(3) /* C相 */ #define LD PAout(4) /* D相 */ /* A相 */ #define LA_GPIO_PORT GPIOA #define LA_GPIO_PIN GPIO_Pin_1 #define LA_GPIO_CLK RCC_APB2Periph_GPIOA /* B相 */ #define LB_GPIO_PORT GPIOA #define LB_GPIO_PIN GPIO_Pin_2 #define LB_GPIO_CLK RCC_APB2Periph_GPIOA /* C相 */ #define LC_GPIO_PORT GPIOA #define LC_GPIO_PIN GPIO_Pin_3 #define LC_GPIO_CLK RCC_APB2Periph_GPIOA /* D相 */ #define LD_GPIO_PORT GPIOA #define LD_GPIO_PIN GPIO_Pin_4 #define LD_GPIO_CLK RCC_APB2Periph_GPIOA
/** * @name: Step_Motor_Init * @description: 步进电机初始化端口 * @param {*} * @return {*} */ void Step_Motor_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; RCC_APB2PeriphClockCmd(LA_GPIO_CLK | LB_GPIO_CLK | LC_GPIO_CLK | LD_GPIO_CLK, ENABLE); /* A相端口初始化 */ GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_Pin = LA_GPIO_PIN; GPIO_Init(LA_GPIO_PORT, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = LB_GPIO_PIN; GPIO_Init(LA_GPIO_PORT, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = LC_GPIO_PIN; GPIO_Init(LA_GPIO_PORT, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = LD_GPIO_PIN; GPIO_Init(LA_GPIO_PORT, &GPIO_InitStruct); GPIO_ResetBits(LA_GPIO_PORT, LA_GPIO_PIN); GPIO_ResetBits(LB_GPIO_PORT, LB_GPIO_PIN); GPIO_ResetBits(LC_GPIO_PORT, LC_GPIO_PIN); GPIO_ResetBits(LD_GPIO_PORT, LD_GPIO_PIN); }
/* 私有类型定义------------------------------------------------- */ typedef enum _PIN_BIT { PLA = 0x01, PLB = 0x02, PLC = 0x04, PLD = 0x08, } Pin_Bit;
/* 类型定义 ------------------------------------------ */ STRUCT(StepMotor_t) { /* *state: bit0 0 表示电机处于非运行; 1 表示开启运行 * bit1 0 表示电机正转 1 反转 */ uint8_t state; /* 每步时间片 */ uint16_t step_slice; /* 总步数 4096为一圈*/ u32 step_num; void (*run)(StepMotor_t *motor); };
/* 变量定义 ---------------------------------------------------- */ StepMotor_t StepMotor = {0x01, 1200, 8192, Step_Motor_Start_InTimer}; 增加定时器程序
/* 宏定义 ----------------------------------------------- */ #define TIMx TIM3 #define TIMx_APBxClock_Func RCC_APB1PeriphClockCmd #define TIMx_CLK_EN RCC_APB1Periph_TIM3 #define TIMx_IRQn TIM3_IRQn #define TIMx_IRQnHandler TIM3_IRQHandler
/* 类型定义 --------------------------------------------- */ STRUCT(Timer_t) { /* * state: 可以复用,通过判断bit0; * bit0 0表示非运行, 1表示运行 */ uint8_t state; uint16_t psc; uint16_t arr; /* 中断次数 */ u32 times; };
/* 变量定义 --------------------------------------------- */ Timer_t Timer = {0, 72, 0xffff, 8};
/* 函数定义 --------------------------------------------- */ void TIM_Configuration(uint16_t psc, uint16_t arr) { TIMx_APBxClock_Func(TIMx_CLK_EN, ENABLE); /* 时机单元设置 */ TIM_TimeBaseInitTypeDef TIM_TBInitStruct; TIM_TBInitStruct.TIM_CounterMode = TIM_CounterMode_Up; TIM_TBInitStruct.TIM_Period = arr - 1; TIM_TBInitStruct.TIM_Prescaler = psc - 1; TIM_TBInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInit(TIMx, &TIM_TBInitStruct); /* 开中断 */ TIM_ITConfig(TIMx, TIM_IT_Update, ENABLE); NVIC_InitTypeDef NVIC_InitStruct; /* 中断设置 */ NVIC_InitStruct.NVIC_IRQChannel = TIMx_IRQn; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStruct); /* 清除中断标志位 */ TIM_ClearITPendingBit(TIMx, TIM_IT_Update); }
/* 函数定义 --------------------------------------------- */ void TIM_Configuration(uint16_t psc, uint16_t arr) { TIMx_APBxClock_Func(TIMx_CLK_EN, ENABLE); /* 时机单元设置 */ TIM_TimeBaseInitTypeDef TIM_TBInitStruct; TIM_TBInitStruct.TIM_CounterMode = TIM_CounterMode_Up; TIM_TBInitStruct.TIM_Period = arr - 1; TIM_TBInitStruct.TIM_Prescaler = psc - 1; TIM_TBInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInit(TIMx, &TIM_TBInitStruct); /* 开中断 */ TIM_ITConfig(TIMx, TIM_IT_Update, ENABLE); NVIC_InitTypeDef NVIC_InitStruct; /* 中断设置 */ NVIC_InitStruct.NVIC_IRQChannel = TIMx_IRQn; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStruct); /* 清除中断标志位 */ TIM_ClearITPendingBit(TIMx, TIM_IT_Update); }
/** * @name: Step_Motor_Handler * @description: 在TIM IRQ中进行处理,设置/改变相位状态值 * @param {*} * @return {*} */ void Step_Motor_Handler(void) { if(Timer.times) { Timer.times--; Set_PhaseState(&StepMotor); } else /* 任务完成 */ { printf("Timer timing over n"); TIM_Cmd(TIMx, DISABLE); /* 关闭硬件定时器 */ Timer.state &= ~0x01; /* 软件定时器置0非运行态,可以其他程序调用 */ StepMotor.state &= ~0x01; /* motor状态为置0,非运行 */ Step_Motor_Stop(&StepMotor); /* 电机各个相位置0 */ } }
/** * @name: Set_PhaseState * @description: 定时器中断中调用,设置电机相位状态 * @param {*} * @return {*} */ void Set_PhaseState(StepMotor_t *motor) { /* 保存上次的相位数组下标 */ static uint8_t i = 0; /* 判断正反转 */ if(!(motor->state & 0x02)) { LA = (uint8_t)((steps&PLA) >> 0); LB = (uint8_t)((steps&PLB) >> 1); LC = (uint8_t)((steps&PLC) >> 2); LD = (uint8_t)((steps&PLD) >> 3); } else { LA = (uint8_t)((steps[7-i]&PLA) >> 0); LB = (uint8_t)((steps[7-i]&PLB) >> 1); LC = (uint8_t)((steps[7-i]&PLC) >> 2); LD = (uint8_t)((steps[7-i]&PLD) >> 3); } i++; if(i >= 8) { i = 0; } }
/** * @name: Step_Motor_Start_InTimer * @description: 步进电机开始运行。设置软件定时器和硬件定时器,并开启硬件定时器功能。 * @param {StepMotor_t} *motor * @return {*} */ void Step_Motor_Start_InTimer(StepMotor_t *motor) { /* 运行开始,电机开启运行置0 */ motor->state &= ~0x01; /* 软件定时器设置 */ Timer.state |= 0x01; /* 软件定时器开启 */ Timer.arr = motor->step_slice; Timer.times = motor->step_num + 1; /* 硬件定时器设置 */ TIM_SetAutoreload(TIMx, Timer.arr); printf("step motor start ... n"); TIM_Cmd(TIMx, ENABLE); /* 产生中断事件 */ TIM_GenerateEvent(TIMx, TIM_EventSource_Update); } 结果显示
int main(void) { uint32_t t = 0; initSysTick(); NVIC_PriorityGroupConfig(2); Usart1_Init(115200); LED1_Init(); Step_Motor_Init(); TIM_Configuration(72, 20000); printf("Hardware init ok.n"); for(;;) { t++; /* 开启步进电机任务,可以在其他任务中进行 */ if(0 == t % 1500) StepMotor.state |= 0x01; if(StepMotor.state & 0x01) { StepMotor.run(&StepMotor); } /* 其他任务 */ if(t % 100 == 1) { LED1_Toggle(); printf("led togglen"); } if(t >= 2000) t = 0; delay_ms(10); } }
|
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1792 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1626 浏览 1 评论
1094 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
732 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1682 浏览 2 评论
1943浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
740浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
577浏览 3评论
600浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
562浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-26 08:31 , Processed in 0.806543 second(s), Total 48, Slave 42 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号