Position Control of DC Motor with STM32F4 StdPeriph

Position Control of DC Motor with STM32F4 StdPeriph

Hello everyone, in this article we are going to talk about position controlling of a DC motor with a potantiometer in STM32F4 and Std periph Driver library. I will use the STM32F429ZI-Nucleo developer board.

Firstly I want to talk about what exactly we will do in this example.

I have a DC motor and a H_Bridge DC motor driver. I also linked a potansiometer and this DC motor by their rotational parts. So I let the potansiometer to rotate when the DC motor rotated. I will connect this potansiometer to my microcontrollers' Analog to Digital converter pin. I will read the voltage level of this potansiometer and result of the potansiometers value I will decide the position of the DC motor.

I also will use the DMA channel of the ADC and I will make some calculations. To decide the angle value of the DC motor.

You can see the mechanism of the linkage potansiometer and the DC motor at below image:
Mechanism of the Linkage of Potansiometer and DC Motor
I also use below DC motor driver which bought from Aliexpress.
DC-Motor-Driver
Below image you can see the all parts as connected each other.
Connected the parts together

I want to tell what I have done now in this example :

I have got two potantiometers, we will use the one of them to set the angle value of the motor rotation. The other potantiometer will be connected to the DC motor. This potantiometer will measure the rotation angle of the motor.

We always try to make them equal. In another projects you can set this setting value from the the USART, CAN or SPI etc...

Now let's write some code.

First we will read both analog values with DMA on ADC. We are going to use multi channel ADC reading with DMA. I have talked about it on this link.


uint16_t ADCValues[2] = {0,0};

    GPIO_InitTypeDef      GPIO_InitStruct;
    DMA_InitTypeDef       DMA_InitStruct;
    ADC_InitTypeDef       ADC_InitStruct;
    ADC_CommonInitTypeDef ADC_CommonInitStruct;

    // Enable related clock buses
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOD, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);//ADC2 is connected to the APB2 peripheral bus

    //We will set the channel as DMA_Channel_1
    DMA_InitStruct.DMA_Channel = DMA_Channel_1;
    //We will set the source as ADC2s' Data and memory ADCValues
    DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&ADC2->DR;
    DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)&ADCValues;
    //Set the direction as Periphal to Memory
    DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralToMemory;
    //We will use 6 adc channel. and buffer size is 2
    DMA_InitStruct.DMA_BufferSize = 2;
    DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
    //We will set data sizes as 16-bit
    DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    //DMA circular mode enables the dma to start when it is done
    DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStruct.DMA_Priority = DMA_Priority_High;
    DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;
    DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
    DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    //Initialize the DMA
    DMA_Init(DMA2_Stream2, &DMA_InitStruct);
    //Enable the DMA
    DMA_Cmd(DMA2_Stream2, ENABLE);

    //Configure the related pins to read analog voltage. 
    //So we will set the pin mode as Analog ınput
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 ;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL ;
    //Initialize the related pins
    GPIO_Init(GPIOC, &GPIO_InitStruct);


    ADC_CommonInitStruct.ADC_Mode = ADC_Mode_Independent;
    ADC_CommonInitStruct.ADC_Prescaler = ADC_Prescaler_Div2;
    ADC_CommonInitStruct.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
    ADC_CommonInitStruct.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
    ADC_CommonInit(&ADC_CommonInitStruct);
 
    ADC_DeInit();
    ADC_InitStruct.ADC_Resolution = ADC_Resolution_8b;
    ADC_InitStruct.ADC_ScanConvMode = ENABLE;
    ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;
    ADC_InitStruct.ADC_ExternalTrigConv = 0;
    ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
    ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStruct.ADC_NbrOfConversion = 2;
    ADC_Init(ADC2, &ADC_InitStruct);

    ADC_RegularChannelConfig(ADC2, ADC_Channel_10, 1, ADC_SampleTime_144Cycles);//PC0
    ADC_RegularChannelConfig(ADC2, ADC_Channel_11, 2, ADC_SampleTime_144Cycles);//PC1


    ADC_DMARequestAfterLastTransferCmd(ADC2, ENABLE);
    ADC_DMACmd(ADC2, ENABLE);
    ADC_Cmd(ADC2, ENABLE);
    ADC_SoftwareStartConv(ADC2);

Now our analog voltages will bwe transferred into the ADCValues array and will be kept in that array. After that we will set our while loop to decide the rotation direction and set the pin HIGH or LOW. I have three functions to rotateLeft, rotateRight and stop. The DC motor driver which I used make combinations with the IN1 and IN2 values. When one of them HIGH and the other one is LOW it will rotate to a direction when you reversed it it will reverse the motor.

Take a look at below functions to make rotations both directions and stop the DC-Motor.

//function to rotate motor to the left side
void fnc_rotateLeft()
{
	GPIO_SetBits(GPIOD, GPIO_Pin_12);
	GPIO_ResetBits(GPIOD, GPIO_Pin_13);
	fnc_waitCycle(10000);
}
//function to rotate motor to the right side
void fnc_rotateRight()
{
	GPIO_ResetBits(GPIOD, GPIO_Pin_12);
	GPIO_SetBits(GPIOD, GPIO_Pin_13);
	fnc_waitCycle(10000);
}
//function to stop motor
void fnc_rotateStop()
{
	GPIO_ResetBits(GPIOD, GPIO_Pin_12);
	GPIO_ResetBits(GPIOD, GPIO_Pin_13);
}
//maybe you will a wait function.
void fnc_waitCycle(uint16_t cycle)
{
	while(cycle) cycle--;
}
You will call above functions in the while loop like below :

while(1) 
    {
			if(ADCValues[0] < ADCValues[1]) fnc_rotateLeft();
			else if(ADCValues[0] > ADCValues[1]) fnc_rotateRight();
			else fnc_rotateStop(); //stop if there is no rotation command
			
    } 

Now you are good to control a DC Motor with selected DC motor driver.

That is all in this article.

Have a good DC motor controlling.

Burak hamdi TUFAN


Tags


Share this Post

Send with Whatsapp

Post a Comment

Success! Your comment sent to post. It will be showed after confirmation.
Error! There was an error sending your comment.

Comments

  • There is no comment. Be the owner of first comment...