Below is the motordriver.c code I’ve written. My goal is to execute a specific scenario where sometimes 3-4 motors need to operate simultaneously. I have arranged this scenario using a case structure. For example:
case 1200:
X_MotorSet(1, 40, 200, 14000, backward);
B_MotorSet(1, 40, 200, 2500, forward);
In this case, I want the X and B motors to run simultaneously. The parameters in the code are as follows (translated from Turkish to English): min_speed, max_speed, ramp, target, direction.
However, the software doesn’t work as expected. First, the X motor runs, and only after it finishes, the B motor starts. How can I prevent this? What I actually want is for the X motor to take a step, then the B motor to take a step, and so on, alternating their movements.
Could you help me with this? Is there something I’m missing in the code? How can I achieve this with a case structure?
/*
* MotorDriver.c
*
* Created on: Jan 11, 2023
* Author: ARGE
*/
#include "stm32f4xx.h"
#include "main.h"
#include "MotorDriver.h"
#include "RelayDriver.h"
#include "SPI_Transfer.h"
#include "Tarifler.h"
extern struct MotorName_t MotorName;
extern TIM_HandleTypeDef htim1;
extern TIM_HandleTypeDef htim2;
extern TIM_HandleTypeDef htim3;
void MotorDriver_Init(){
HAL_TIM_Base_Start_IT(&htim1);
HAL_TIM_Base_Start_IT(&htim2);
HAL_TIM_Base_Start_IT(&htim3);
HAL_GPIO_WritePin(EN_X_GPIO_Port, EN_X_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(EN_Y_GPIO_Port, EN_Y_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(EN_A_GPIO_Port, EN_A_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(EN_B_GPIO_Port, EN_B_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(CS_X_GPIO_Port, CS_X_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(CS_Y_GPIO_Port, CS_Y_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(CS_A_GPIO_Port, CS_A_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(CS_B_GPIO_Port, CS_B_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(CS_X_GPIO_Port, CS_X_Pin, GPIO_PIN_RESET);
ConfigDriver(XMotor, CS_X_GPIO_Port, CS_X_Pin);
HAL_GPIO_WritePin(CS_X_GPIO_Port, CS_X_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(CS_Y_GPIO_Port, CS_Y_Pin, GPIO_PIN_RESET);
ConfigDriver(YMotor, CS_Y_GPIO_Port, CS_Y_Pin);
HAL_GPIO_WritePin(CS_Y_GPIO_Port, CS_Y_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(CS_A_GPIO_Port, CS_A_Pin, GPIO_PIN_RESET);
ConfigDriver(AMotor, CS_A_GPIO_Port, CS_A_Pin);
HAL_GPIO_WritePin(CS_A_GPIO_Port, CS_A_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(CS_B_GPIO_Port, CS_B_Pin, GPIO_PIN_RESET);
ConfigDriver(BMotor, CS_B_GPIO_Port, CS_B_Pin);
HAL_GPIO_WritePin(CS_B_GPIO_Port, CS_B_Pin, GPIO_PIN_SET);
}
//Motor Yonlerinde bir farklılık olduğunda senaryo ve sw konumları ile ilgili
//guncellemeye gereksinim bırakmaması için bu kısımdan değiştirilmelidir.
void MotorYon(uint8_t MotorNo, uint8_t Yon) {
switch (MotorNo) {
case XMotor:
if (Yon == geri)
HAL_GPIO_WritePin(DIR_X_GPIO_Port, DIR_X_Pin, GPIO_PIN_SET);
else if (Yon == ileri)
HAL_GPIO_WritePin(DIR_X_GPIO_Port, DIR_X_Pin, GPIO_PIN_RESET);
MotorName.X[yon] = Yon;
break;
case YMotor:
if (Yon == ileri)
HAL_GPIO_WritePin(DIR_Y_GPIO_Port, DIR_Y_Pin, GPIO_PIN_RESET);
else if (Yon == geri)
HAL_GPIO_WritePin(DIR_Y_GPIO_Port, DIR_Y_Pin, GPIO_PIN_SET);
MotorName.Y[yon] = Yon;
break;
case AMotor:
if (Yon == geri)
HAL_GPIO_WritePin(DIR_A_GPIO_Port, DIR_A_Pin, GPIO_PIN_SET);
else if (Yon == ileri)
HAL_GPIO_WritePin(DIR_A_GPIO_Port, DIR_A_Pin, GPIO_PIN_RESET);
MotorName.A[yon] = Yon;
break;
case BMotor:
if (Yon == ileri)
HAL_GPIO_WritePin(DIR_B_GPIO_Port, DIR_B_Pin, GPIO_PIN_SET);
else if (Yon == geri)
HAL_GPIO_WritePin(DIR_B_GPIO_Port, DIR_B_Pin, GPIO_PIN_RESET);
MotorName.B[yon] = Yon;
break;
}
}
void MotorEnable(int MotorNo, int Durum) {
switch (MotorNo) {
case XMotor:
if (Durum == ac)
HAL_GPIO_WritePin(EN_X_GPIO_Port, EN_X_Pin, GPIO_PIN_RESET);
else if (Durum == kapat)
HAL_GPIO_WritePin(EN_X_GPIO_Port, EN_X_Pin, GPIO_PIN_SET);
break;
case YMotor:
if (Durum == ac)
HAL_GPIO_WritePin(EN_Y_GPIO_Port, EN_Y_Pin, GPIO_PIN_RESET);
else if (Durum == kapat)
HAL_GPIO_WritePin(EN_Y_GPIO_Port, EN_Y_Pin, GPIO_PIN_SET);
break;
case AMotor:
if (Durum == ac)
HAL_GPIO_WritePin(EN_A_GPIO_Port, EN_A_Pin, GPIO_PIN_RESET);
else if (Durum == kapat)
HAL_GPIO_WritePin(EN_A_GPIO_Port, EN_A_Pin, GPIO_PIN_SET);
break;
case BMotor:
if (Durum == ac)
HAL_GPIO_WritePin(EN_B_GPIO_Port, EN_B_Pin, GPIO_PIN_RESET);
else if (Durum == kapat)
HAL_GPIO_WritePin(EN_B_GPIO_Port, EN_B_Pin, GPIO_PIN_SET);
break;
}
}
/*
rampa:1-500 arasında; 500 rampa fazla, 1 düşük rampa
min_hiz:1
max_hiz:1-100 arasında
motor_hedef:1-2.147483648 step adımı arasında
*/
void Ramp(int32_t Motor[6]){
if(Motor[rampa]>200){
Motor[rampa]-=(500/Motor[rampa]);//1 er 1 er veya 2şer azalt//Gecikme Azalır, Hız artar
delay_us(MotorName.X[rampa]);
}
else if(Motor[rampa]>20 && Motor[rampa]<200){
Motor[rampa]-=(1000/Motor[rampa]);//20Ms olana kadar hız artar
delay_us(Motor[rampa]);
}
else{//4000/40 = 10Ms maksimum hıza ayarlanmış olur.
Motor[rampa] = 4000/Motor[max_hiz];//max hız min gecikme
delay_us(Motor[rampa]);
}
}
void X_MotorDrive() {
while(MotorName.X[motor_konum] <= MotorName.X[motor_hedef]){
HAL_GPIO_TogglePin(STEP_X_GPIO_Port, STEP_X_Pin); //motor_hiz,motor_pulse,motor_konum,max_hiz,yon,rampa_egim
MotorName.X[motor_konum]++;
Ramp(MotorName.X);//Çağrılan motor parametreleriyle rampa hesaplanarak burada gecikme sağlanır.
}
HAL_GPIO_WritePin(EN_X_GPIO_Port, EN_X_Pin, GPIO_PIN_SET);
}
void Y_MotorDrive() {
while (MotorName.Y[motor_konum] <= MotorName.Y[motor_hedef]) {
HAL_GPIO_TogglePin(STEP_Y_GPIO_Port, STEP_Y_Pin); //motor_hiz,motor_pulse,motor_konum,max_hiz,yon,rampa_egim
MotorName.Y[motor_konum]++;
Ramp(MotorName.Y);//Çağrılan motor parametreleriyle rampa hesaplanarak burada gecikme sağlanır.
}
HAL_GPIO_WritePin(EN_Y_GPIO_Port, EN_Y_Pin, GPIO_PIN_SET);
}
//***************************************************************
void A_MotorDrive() {
while (MotorName.A[motor_konum] <= MotorName.A[motor_hedef]) {
HAL_GPIO_TogglePin(STEP_A_GPIO_Port, STEP_A_Pin); //motor_hiz,motor_pulse,motor_konum,max_hiz,yon,rampa_egim
MotorName.A[motor_konum]++;
Ramp(MotorName.A);//Çağrılan motor parametreleriyle rampa hesaplanarak burada gecikme sağlanır.
}
HAL_GPIO_WritePin(EN_A_GPIO_Port, EN_A_Pin, GPIO_PIN_SET);
}
void B_MotorDrive() {
while (MotorName.B[motor_konum] <= MotorName.B[motor_hedef]) {
HAL_GPIO_TogglePin(STEP_B_GPIO_Port, STEP_B_Pin); //motor_hiz,motor_pulse,motor_konum,max_hiz,yon,rampa_egim
MotorName.B[motor_konum]++;
Ramp(MotorName.B);//Çağrılan motor parametreleriyle rampa hesaplanarak burada gecikme sağlanır.
}
HAL_GPIO_WritePin(EN_B_GPIO_Port, EN_B_Pin, GPIO_PIN_SET);
}
void X_MotorSet(int32_t Min_Hiz, int32_t Max_Hiz, int32_t Rampa, int32_t Mesafe, uint8_t Yon) {
if (HAL_GPIO_ReadPin(LIMIT_X_GPIO_Port, LIMIT_X_Pin) == 0 && Yon == ileri) {
MotorName.Home[XMotor] = HomeYapildi;
} else {
MotorName.X[rampa] = Rampa;
MotorName.X[min_hiz] = Min_Hiz;
MotorName.X[max_hiz] = Max_Hiz;
MotorName.X[motor_hedef] = Mesafe;
MotorName.X[motor_konum] = 1;
MotorYon(XMotor, Yon);
MotorEnable(XMotor, ac);
X_MotorDrive();
}
}
void Y_MotorSet(int32_t Min_Hiz, int32_t Max_Hiz, int32_t Rampa, int32_t Mesafe, uint8_t Yon) {
if (HAL_GPIO_ReadPin(LIMIT_Y_GPIO_Port, LIMIT_Y_Pin) == 1 && Yon == ileri){
MotorName.Home[YMotor] = HomeYapildi;
} else {
MotorName.Y[rampa] = Rampa;
MotorName.Y[min_hiz] = Min_Hiz;
MotorName.Y[max_hiz] = Max_Hiz;
MotorName.Y[motor_hedef] = Mesafe;
MotorName.Y[motor_konum] = 1;
MotorYon(YMotor, Yon);
MotorEnable(YMotor, ac);
Y_MotorDrive();
}
}
//***************************************************************************
void A_MotorSet(int32_t Min_Hiz, int32_t Max_Hiz, int32_t Rampa, int32_t Mesafe, uint8_t Yon) {
if (HAL_GPIO_ReadPin(LIMIT_A_GPIO_Port, LIMIT_A_Pin) == 1 && Yon == ileri){
MotorName.Home[AMotor] = HomeYapildi;
} else {
MotorName.A[rampa] = Rampa;
MotorName.A[min_hiz] = Min_Hiz;
MotorName.A[max_hiz] = Max_Hiz;
MotorName.A[motor_hedef] = Mesafe;
MotorName.A[motor_konum] = 1;
MotorYon(AMotor, Yon);
MotorEnable(AMotor, ac);
A_MotorDrive();
}
}
void B_MotorSet(int32_t Min_Hiz, int32_t Max_Hiz, int32_t Rampa, int32_t Mesafe, uint8_t Yon) {
if (HAL_GPIO_ReadPin(LIMIT_B_GPIO_Port, LIMIT_B_Pin) == 1 && Yon == geri){
MotorName.Home[BMotor] = HomeYapildi;
} else {
MotorName.B[rampa] = Rampa;
MotorName.B[min_hiz] = Min_Hiz;
MotorName.B[max_hiz] = Max_Hiz;
MotorName.B[motor_hedef] = Mesafe;
MotorName.B[motor_konum] = 1;
MotorYon(BMotor, Yon);
MotorEnable(BMotor, ac);
B_MotorDrive();
}
}
//***************************************************************************
//****************************************************************************
I implemented the scenario using a case structure where multiple motors are configured to run simultaneously. For example:
case 1200:
X_MotorSet(1, 40, 200, 14000, backward);
B_MotorSet(1, 40, 200, 2500, forward);
I expected the X and B motors to move alternately, with one motor taking a step and then the other motor taking a step. However, in practice, the software executes the commands sequentially, with the X motor completing its entire movement before the B motor starts. I was expecting both motors to alternate or interleave their steps.
3
I was expecting both motors to alternate or interleave their steps.
I implemented the scenario using a case structure where multiple
motors are configured to run simultaneously. For example:
case 1200:
X_MotorSet(1, 40, 200, 14000, backward);
B_MotorSet(1, 40, 200, 2500, forward);
The first function is executed, followed by the second one. Nothing is parallel here.
You need (if you want main loop) to write functions which only do one thing without any delays and check what to do next. But cant wait fro the next phase.
You need to implement such a non blocking state machine.
Like every other function in your program, X_MotorSet
does what it does: you call it, it runs, and returns when it’s done. Then control proceeds to the next statement, which in your case is a call to B_MotorSet
.
I expected the X and B motors to move alternately, with one motor taking a step and then the other motor taking a step
In that case, you need different functions, or perhaps to call these functions with different parameters. You need the function to move the motor one step, and return. And, like read(2), you need that function to indicate when the motor is “done”, whatever that means.
Then you want a loop that runs each motor one step at a time until … something. When both motors are done? That’s up to you.