In this article we interface servo motor & use ultrasonic sensor to detect small object. In our case the servo motor will rotate 450 in each step and ultrasonic sensor detects any object nearby. Before start first go through my servo motor control & ultrasonic sensor article. In our basic timer part we learn about prescaler & counter period (ARR). For servo motor we need 50Hz frequency signal. In this article we use system clock as 48MHz internal clock. For PWM the formula is-
PWM frequency fPWM = fcpu/((1+Prescaler)*(1+ARR))
Let ARR=19999 then Prescaler will be 47. It will generate 20ms wave signal. Servo motor works on duty cycle. The CCRx register of timer determine the duty cycle. So if we went to generate .025% duty cycle, the CCRx register value will be (0.025*(1+ARR)-1) = (0.025*(1+19999)-1)=499. For every rotation the CCRx value will be-
Here I use TIM1 Channel 1 as PWM timer PIN, so for each direction our desire value will be-
Every 450 change cycle we need some delay function for the servo motor to change position. If we use HAL_delay function the system clock will halt and no farther execution. In our case we use system clock as delay function. In every direction we measure the distance using ultrasonic sensor. For interfacing ultrasonic sensor we need an EXIT pin & GPIO pin. Since for our delay function we use system clock, in ultrasonic sensor Trigger pin we use system delay function as follow-
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_9,GPIO_PIN_SET);
for(uint16_t i=0;i<780;i++)
__ASM volatile ("NOP"); //F_CPU=48MHz and every cycle 0.020833us time
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_9,GPIO_PIN_RESET);
Here we use assembly language NOP (No Operation ) function for delay & GPIOC Pin 9 as trig pin. When we trigger the trig pin of ultrasonic sensor, it send 8cycle ultrasonic burst. The ECHO pin will go high and remain high until an ultrasonic burst is detecting back. Since sound wave travels at 3.43m/s, we need timer to calculate time. We use TIM17 for time count. Set prescaler value 47 & counter period (ARR) 65535, so every pulse will be 1us. In our previous IR Decode principle we learn about pulse detection using EXIT. Initialize EXIT with rising/falling edge detection. In rising pulse start the counter & at falling edge stop the counter.
The pulse detection program as follow-
extern TIM_HandleTypeDef htim17;
if(flag)
{
pulse_width=TIM17 -> CNT ;
pulse_width=pulse_width/200; // since it reflect
distance=(3.43*pulse_width); // Distance in cm
switch(direction)
{
case 1: sprintf(display_direction,"West:%.2fcm ",distance);
OLCD_write_string(2,0,display_direction);
break;
case 2: sprintf(display_direction,"SW:%.2fcm ",distance);
OLCD_write_string(2,0,display_direction);
break;
case 3: sprintf(display_direction,"South:%.2fcm ",distance);
OLCD_write_string(2,0,display_direction);
break;
case 4: sprintf(display_direction,"WE:%.2fcm ",distance);
OLCD_write_string(2,0,display_direction);
break;
case 0: sprintf(display_direction,"East:%.2fcm ",distance);
OLCD_write_string(2,0,display_direction);
break;
}
TIM17->CNT=0;
flag=0;
}
else
{
HAL_TIM_Base_Start(&htim17);
flag=1;
TIM17->CNT=0;
}
Here we use I2C1 for 0.91″ OLED for display. For controlling servo motor & ultrasonic sensor trigger we use another timer in this case. In my case I use TIM16 for schedule servo motor & ultrasonic sensor. Setting for TIM16 as prescaler 4799 & Counter Period (ARR) 65535, so frequency of TIM16 is-
Frequency of TIM16 fTIM16 = 48MHz/(1+4799) = 10kHz or TTIM16 = 0.1ms
So that Timer Interrupt occurs at every Tint = 0.1ms*65535 = 6.5535s. Enable global Interrupt for TIM16 & in TIM16 interrupt service routine the coding as follow-
switch(direction)
{
case 0: TIM1->CCR1=499; // West side
for(uint16_t j=0;j<8000;j++)
for(uint16_t i=0;i<4800;i++) // .8s
__ASM volatile ("NOP"); // F_CPU=48MHz and every cycle 0.020833us time
break;
case 1: TIM1->CCR1=999; // South-West side
break;
case 2: TIM1->CCR1=1499; // South side
break;
case 3: TIM1->CCR1=1999; // South-East side
break;
case 4: TIM1->CCR1=2499; // East side
break;
}
for(uint16_t j=0;j<8000;j++)
for(uint16_t i=0;i<480;i++) // 80ms
__ASM volatile ("NOP"); // F_CPU=48MHz and every cycle 0.020833us time
direction++;
if(direction>=5) direction=0;
/****** Ultrasonic Sensor Function ******************/
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_9,GPIO_PIN_SET);
for(uint16_t i=0;i<780;i++)
__ASM volatile ("NOP"); //F_CPU=48MHz and every cycle 0.020833us time
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_9,GPIO_PIN_RESET);
/******************************************************************************/
Every 6.5535s the Timer 16 generates an interrupt and PWM frequency would change & trig pin of ultrasonic sensor would activate. Here we use system clock as delay function. For every frequency change the servo motor need some time to reach destination. All coding has done in stm32f0xx_it.c file. In main program file is just initialization.
#include "ssd1306.h"
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1); // PWM start for channel 1 TIM1
HAL_TIM_Base_Start_IT(&htim16); // Global interrupt for TIM16
init_OLED();
clear_display();
OLCD_write_string(0,0,"Small Rader");
while(1){
}
Some useful function of PWM-
HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel);
HAL_TIM_PWM_Stop(TIM_HandleTypeDef *htim, uint32_t Channel);
HAL_TIM_PWM_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel);
HAL_TIM_PWM_Stop_IT(TIM_HandleTypeDef *htim, uint32_t Channel);
HAL_TIM_PWM_Start_DMA(TIM_HandleTypeDef *htim, uint32_t Channel, const uint32_t *pData,uint16_t Length);
HAL_TIM_PWM_Stop_DMA(TIM_HandleTypeDef *htim, uint32_t Channel);
All Parameter Setting