Preface
This article mainly aims at the realization of the car's various functions in the process of specific implementation principles, procedures and algorithms, as well as the problems encountered in a unified interpretation and explanation. So far, combined with the structure module of the previous article, all the work of the smart car project has been completed, and there must be a lot of room for optimization, but considering that the ultimate goal of this project is to understand embedded programming more deeply, so this project has to explore a broader world.
drive control
PWM Configuration of Driver Module
In order to control the speed of the car, it is necessary to input PWM wave to the enabling pin of L298N motor drive module. Changing the duty cycle can adjust the speed of the car.
The PWM configuration is as follows:
/** * @brief: Initialize the output configuration of PWM, and use TIM3 to output four PWM waves at the same time to control the speed of four motors. * @param: arr-Automatic reload value psc-clock pre-dividing coefficient * @retval NONE * @Others:GPIO_PinAFConfig Functions must be multiplexed step by step. They cannot be combined with a single multiplexed function, or they have only one output. **/ void TIM3_PWM_Init(u16 arr,u16 psc) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); //TIM3 Clock Enablation RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //Enabling GPIOA Clock RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); //Enabling GPIOB Clock //The GPIO_PinAFConfig function must be multiplexed step by step. It cannot be combined with a multiplexed function, or only one output can be obtained. GPIO_PinAFConfig(GPIOA,GPIO_PinSource6,GPIO_AF_TIM3); //GPIOA6 multiplexed to Timer 3 GPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_TIM3); //GPIOA7 Multiplexed to Timer 3 GPIO_PinAFConfig(GPIOB,GPIO_PinSource0,GPIO_AF_TIM3); //GPIOB0 multiplexed to Timer 3 GPIO_PinAFConfig(GPIOB,GPIO_PinSource1,GPIO_AF_TIM3); //GPIOB1 multiplexed into timer 3 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //Reuse function GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //Speed 100MHz GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //Push-pull multiplexing output GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //Pull up GPIO_Init(GPIOA,&GPIO_InitStructure); //Initialize PF9 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //Reuse function GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //Speed 100MHz GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //Push-pull multiplexing output GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //Pull up GPIO_Init(GPIOB,&GPIO_InitStructure); TIM_TimeBaseStructure.TIM_Prescaler=psc; //Timer frequency division TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //Upward Counting Mode TIM_TimeBaseStructure.TIM_Period=arr; //Automatic reload value TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);//Initialization timer 3 //Initialize TIM3 PWM mode TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //Select Timer Mode: TIM Pulse Width Modulation Mode 2 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //Comparing output enablement TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //Output Polarity: TIM Output is Low Polarity TIM_OC1Init(TIM3, &TIM_OCInitStructure); //Initialize peripheral TIM3OC1 according to the parameters specified by T TIM_OC2Init(TIM3, &TIM_OCInitStructure); //Initialize peripheral TIM3OC2 according to the parameters specified by T TIM_OC3Init(TIM3, &TIM_OCInitStructure); //Initialize peripheral TIM3OC3 according to the parameters specified by T TIM_OC4Init(TIM3, &TIM_OCInitStructure); //Initialize peripheral TIM3OC4 according to the parameters specified by T TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); //Preload Register Enabling TIM3 on CCR1 TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //Preload Register Enabling TIM3 on CCR1 TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable); //Preload Register Enabling TIM3 on CCR1 TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable); //Preload Register Enabling TIM3 on CCR1 TIM_ARRPreloadConfig(TIM3,ENABLE); TIM_Cmd(TIM3, ENABLE); //Enabling TIM3 }
Driver implementation
Now equivalent to the drive module has been completed, in order to make the car move, the IN1~IN4 pin level needs to be operated.
Step 1:IO Port Initialization
/** * @brief: IO Port for Initialization Control Motor Forward and Reverse and Brake * @param: NONE * @retval: NONE * @Others: When choosing IO, be careful not to conflict with the hardware interface of STM32, for example, IO occupied the first time I chose. LCD An interface of the screen, resulting in abnormal initialization of LCD **/ void CAR_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);//Enabling GPIOF Clock RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);//Enabling GPIOG Clock //IO initialization settings GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_3 | GPIO_Pin_5 | GPIO_Pin_7 | GPIO_Pin_15 | GPIO_Pin_13 | GPIO_Pin_14;//LED 0 and LED 1 correspond to IO port GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//Common Output Mode GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//push-pull GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//Pull up GPIO_Init(GPIOF, &GPIO_InitStructure);//Initialize GPIO GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//Common Output Mode GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//push-pull GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//Pull up GPIO_Init(GPIOG, &GPIO_InitStructure);//Initialize GPIO GPIO_SetBits(GPIOF,GPIO_Pin_1 | GPIO_Pin_3 | GPIO_Pin_5 | GPIO_Pin_7 | GPIO_Pin_15 | GPIO_Pin_13 | GPIO_Pin_14); GPIO_SetBits(GPIOG,GPIO_Pin_1); }
Step 2: Driving function: including forward, backward, steering, parking
/** * @brief: Gear speed conversion function, set 1-4 gears, the gear linear conversion to the corresponding PWM wave output * @param: Gear value * @retval: pulse * @Others: NONE **/ u16 gear_trans(u16 gear) { u16 Pulse=0; switch(gear) { case 0x00: Pulse=500; break; case 0x01: Pulse=350; break; case 0x02: Pulse=300; break; case 0x03: Pulse=200; break; case 0x04: Pulse=100; break; default: break; } return Pulse; } /** * @brief: Forward Function, Control Car Forward * @param: Gear value * @retval: NONE * @Others: NONE **/ void drive(u16 gear) { u16 Pulse; Pulse=gear_trans(gear); GPIO_ResetBits(GPIOF,GPIO_Pin_1); GPIO_SetBits(GPIOF,GPIO_Pin_3); GPIO_SetBits(GPIOF,GPIO_Pin_5); GPIO_ResetBits(GPIOF,GPIO_Pin_7); GPIO_SetBits(GPIOF,GPIO_Pin_15); GPIO_ResetBits(GPIOG,GPIO_Pin_1); GPIO_SetBits(GPIOF,GPIO_Pin_14); GPIO_ResetBits(GPIOF,GPIO_Pin_13); TIM_SetCompare1(TIM3,Pulse); //Modify the comparison value and duty cycle TIM_SetCompare2(TIM3,Pulse); //Modify the comparison value and duty cycle TIM_SetCompare3(TIM3,Pulse); //Modify the comparison value and duty cycle TIM_SetCompare4(TIM3,Pulse); //Modify the comparison value and duty cycle } /** * @brief: Backward function * @param: Gear value * @retval: NONE * @Others: NONE **/ void reverse(u16 gear) { u16 Pulse; Pulse=gear_trans(gear); GPIO_SetBits(GPIOF,GPIO_Pin_1); GPIO_ResetBits(GPIOF,GPIO_Pin_3); GPIO_ResetBits(GPIOF,GPIO_Pin_5); GPIO_SetBits(GPIOF,GPIO_Pin_7); GPIO_ResetBits(GPIOF,GPIO_Pin_15); GPIO_SetBits(GPIOG,GPIO_Pin_1); GPIO_ResetBits(GPIOF,GPIO_Pin_14); GPIO_SetBits(GPIOF,GPIO_Pin_13); TIM_SetCompare1(TIM3,Pulse); //Modify the comparison value and duty cycle TIM_SetCompare2(TIM3,Pulse); //Modify the comparison value and duty cycle TIM_SetCompare3(TIM3,Pulse); //Modify the comparison value and duty cycle TIM_SetCompare4(TIM3,Pulse); //Modify the comparison value and duty cycle } /** * @brief: Parking function * @param: NONE * @retval: NONE * @Others: NONE **/ void stop(void) { GPIO_ResetBits(GPIOF,GPIO_Pin_1); GPIO_ResetBits(GPIOF,GPIO_Pin_3); GPIO_ResetBits(GPIOF,GPIO_Pin_5); GPIO_ResetBits(GPIOF,GPIO_Pin_7); GPIO_ResetBits(GPIOF,GPIO_Pin_15); GPIO_ResetBits(GPIOG,GPIO_Pin_1); GPIO_ResetBits(GPIOF,GPIO_Pin_14); GPIO_ResetBits(GPIOF,GPIO_Pin_13); } /** * @brief: Left turn function, using one side wheel to lock turn * @param: Turning gear * @retval: NONE * @Others: NONE **/ void left_move(u16 gear_change) { u16 Pulse; Pulse=gear_trans(gear_change); GPIO_ResetBits(GPIOF,GPIO_Pin_1); GPIO_SetBits(GPIOF,GPIO_Pin_3); GPIO_SetBits(GPIOF,GPIO_Pin_5); GPIO_ResetBits(GPIOF,GPIO_Pin_7); GPIO_SetBits(GPIOF,GPIO_Pin_15); GPIO_ResetBits(GPIOG,GPIO_Pin_1); GPIO_SetBits(GPIOF,GPIO_Pin_14); GPIO_ResetBits(GPIOF,GPIO_Pin_13); TIM_SetCompare1(TIM3,500); //Modify the comparison value and lock the left wheel TIM_SetCompare2(TIM3,500); //Modify the comparison value and lock the left wheel TIM_SetCompare3(TIM3,Pulse); //Modify the comparison value and duty cycle TIM_SetCompare4(TIM3,Pulse); //Modify the comparison value and duty cycle } /** * @brief: Right turn function, using one side wheel to lock turn * @param: Turning gear * @retval: NONE * @Others: NONE **/ void right_move(u16 gear_change) { u16 Pulse; Pulse=gear_trans(gear_change); GPIO_ResetBits(GPIOF,GPIO_Pin_1); GPIO_SetBits(GPIOF,GPIO_Pin_3); GPIO_SetBits(GPIOF,GPIO_Pin_5); GPIO_ResetBits(GPIOF,GPIO_Pin_7); GPIO_SetBits(GPIOF,GPIO_Pin_15); GPIO_ResetBits(GPIOG,GPIO_Pin_1); GPIO_SetBits(GPIOF,GPIO_Pin_14); GPIO_ResetBits(GPIOF,GPIO_Pin_13); TIM_SetCompare1(TIM3,Pulse); //Modify the comparison value and duty cycle TIM_SetCompare2(TIM3,Pulse); //Modify the comparison value and duty cycle TIM_SetCompare3(TIM3,500); //Modify the comparison value to lock the right wheel TIM_SetCompare4(TIM3,500); //Modify the comparison value to lock the right wheel } /** * @brief: Left-turn function, using one forward and one backward turn * @param: Turning gear * @retval: NONE * @Others: NONE **/ void left_move_2(u16 gear_change) { u16 Pulse; Pulse=gear_trans(gear_change); GPIO_SetBits(GPIOF,GPIO_Pin_1); GPIO_ResetBits(GPIOF,GPIO_Pin_3); GPIO_ResetBits(GPIOF,GPIO_Pin_5); GPIO_SetBits(GPIOF,GPIO_Pin_7); GPIO_SetBits(GPIOF,GPIO_Pin_15); GPIO_ResetBits(GPIOG,GPIO_Pin_1); GPIO_SetBits(GPIOF,GPIO_Pin_14); GPIO_ResetBits(GPIOF,GPIO_Pin_13); TIM_SetCompare1(TIM3,Pulse); //Modify the comparison value and duty cycle TIM_SetCompare2(TIM3,Pulse); //Modify the comparison value and duty cycle TIM_SetCompare3(TIM3,Pulse); //Modify the comparison value and duty cycle TIM_SetCompare4(TIM3,Pulse); //Modify the comparison value and duty cycle } /** * @brief: Right turn function, using one side forward and one side backward turn * @param: Turning gear * @retval: NONE * @Others: NONE **/ void right_move_2(u16 gear_change) { u16 Pulse; Pulse=gear_trans(gear_change); GPIO_ResetBits(GPIOF,GPIO_Pin_1); GPIO_SetBits(GPIOF,GPIO_Pin_3); GPIO_SetBits(GPIOF,GPIO_Pin_5); GPIO_ResetBits(GPIOF,GPIO_Pin_7); GPIO_ResetBits(GPIOF,GPIO_Pin_15); GPIO_SetBits(GPIOG,GPIO_Pin_1); GPIO_ResetBits(GPIOF,GPIO_Pin_14); GPIO_SetBits(GPIOF,GPIO_Pin_13); TIM_SetCompare1(TIM3,Pulse); //Modify the comparison value and duty cycle TIM_SetCompare2(TIM3,Pulse); //Modify the comparison value and duty cycle TIM_SetCompare3(TIM3,Pulse); //Modify the comparison value and duty cycle TIM_SetCompare4(TIM3,Pulse); //Modify the comparison value and duty cycle } /** * @brief: Forward function, mainly for remote control mode * @param: pulse value * @retval: NONE * @Others: NONE **/ void drive_pulse(int pulse) { GPIO_ResetBits(GPIOF,GPIO_Pin_1); GPIO_SetBits(GPIOF,GPIO_Pin_3); GPIO_SetBits(GPIOF,GPIO_Pin_5); GPIO_ResetBits(GPIOF,GPIO_Pin_7); GPIO_SetBits(GPIOF,GPIO_Pin_15); GPIO_ResetBits(GPIOG,GPIO_Pin_1); GPIO_SetBits(GPIOF,GPIO_Pin_14); GPIO_ResetBits(GPIOF,GPIO_Pin_13); TIM_SetCompare1(TIM3,pulse); //Modify the comparison value and duty cycle TIM_SetCompare2(TIM3,pulse); //Modify the comparison value and duty cycle TIM_SetCompare3(TIM3,pulse); //Modify the comparison value and duty cycle TIM_SetCompare4(TIM3,pulse); //Modify the comparison value and duty cycle } /** * @brief: Back-off function, mainly for remote control mode * @param: pulse value * @retval: NONE * @Others: NONE **/ void reverse_pulse(int pulse) { GPIO_SetBits(GPIOF,GPIO_Pin_1); GPIO_ResetBits(GPIOF,GPIO_Pin_3); GPIO_ResetBits(GPIOF,GPIO_Pin_5); GPIO_SetBits(GPIOF,GPIO_Pin_7); GPIO_ResetBits(GPIOF,GPIO_Pin_15); GPIO_SetBits(GPIOG,GPIO_Pin_1); GPIO_ResetBits(GPIOF,GPIO_Pin_14); GPIO_SetBits(GPIOF,GPIO_Pin_13); TIM_SetCompare1(TIM3,pulse); //Modify the comparison value and duty cycle TIM_SetCompare2(TIM3,pulse); //Modify the comparison value and duty cycle TIM_SetCompare3(TIM3,pulse); //Modify the comparison value and duty cycle TIM_SetCompare4(TIM3,pulse); //Modify the comparison value and duty cycle } /** * @brief: Turning function, mainly for remote control mode * @param: pulse1-On the left, pulse 2 - on the right * @retval: NONE * @Others: NONE **/ void turn_pulse(int pulse1,int pulse2) { GPIO_ResetBits(GPIOF,GPIO_Pin_1); GPIO_SetBits(GPIOF,GPIO_Pin_3); GPIO_SetBits(GPIOF,GPIO_Pin_5); GPIO_ResetBits(GPIOF,GPIO_Pin_7); GPIO_SetBits(GPIOF,GPIO_Pin_15); GPIO_ResetBits(GPIOG,GPIO_Pin_1); GPIO_SetBits(GPIOF,GPIO_Pin_14); GPIO_ResetBits(GPIOF,GPIO_Pin_13); TIM_SetCompare1(TIM3,pulse1); //Modify the comparison value and duty cycle TIM_SetCompare2(TIM3,pulse1); //Modify the comparison value and duty cycle TIM_SetCompare3(TIM3,pulse2); //Modify the comparison value and duty cycle TIM_SetCompare4(TIM3,pulse2); //Modify the comparison value and duty cycle }
Now you can get your car moving. Comfortable.
Patrol function
Here I use four patrol sensors, one on the left and right sides and two on the middle part. The number and location of the sensors are different, so the corresponding algorithms to realize patrol are different. The specific algorithm problems can be consulted with relevant information.
Initialization of Patrol Sensor
Configuration of IO ports that need to receive patrol sensor signals
/** * @brief: Initialization of IO Port Connected by Trace Sensor * @param: NONE * @retval: NONE * @others: Initially, the switch indicator on the track module was always on because the wrong IO port was selected. PC0 and PC2 were used. Change to PF2 and PF4, why? **/ void Trace_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE); //Enabling GPIOF Clock GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_2 | GPIO_Pin_4 | GPIO_Pin_6; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; //Reuse function GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //Speed 100MHz GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //Push-pull multiplexing output GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; //Pull up GPIO_Init(GPIOF,&GPIO_InitStructure); }
Receiving and transmitting signals
To collect and record the line information collected by the patrol line sensor
/** * @brief: Scanning function of tracking module, referring to STM32 button experiment * @param: modeļ¼==1 Represents support for continuous pressing, == 0 means support for continuous pressing * @retval: 4 Number of each tracing module, return 1 to indicate No. 1 sensor pressure line * @others: NONE **/ u8 TRACE_Scan(u8 mode) { static u8 trace_up=1;//Press the button to loosen the sign if(mode)trace_up=1; //Support Click if(trace_up&&(TRACE1==1||TRACE2==1||TRACE3==1||TRACE4==1)) { delay_ms(10);//debounce trace_up=0; if(TRACE1==1)return 1; else if(TRACE2==1)return 2; else if(TRACE3==1)return 3; else if(TRACE4==1)return 4; } else if(TRACE1==0&&TRACE2==0&&TRACE3==0&&TRACE4==0)trace_up=1; return 0;// Press without key }
Patrol Line Realization
Only rectangular patrol lines are compiled here. If other shape lines need to be patrolled, relevant information can be consulted.
/** * @brief: Track execution module (rectangular patrol line), according to the detected sensor signal to make corresponding actions * @param: NONE * @retval: NONE * @others: Because this project is mainly used to practice programming ability, so only rectangular patrol lines are written here. There is no in-depth study of other linetype situations and various algorithms. **/ void TRACE_Implement(void) { extern u16 GEAR; u8 Edge_Flag=0;//Rectangular 90 degree angle detection, after detection of this flag position 1 u8 trace_scan; trace_scan=TRACE_Scan(0);//Number of the sensor that gets the pressure line if(trace_scan) { switch(trace_scan) { case TRACE1_SCAN: //Leftmost sensor detected left_move_2(GEAR+2);//Turn left at a higher speed Edge_Flag = 1;//90 degree mark position 1 delay_ms(150);//Turn 90 degrees to the end left_move(GEAR);//Little Left Turn break; case TRACE2_SCAN: //Right-most sensor detected right_move_2(GEAR+2); Edge_Flag = 1; delay_ms(150); right_move(GEAR); LED0=!LED0; break; case TRACE3_SCAN: //Detection of left-middle sensor if(Edge_Flag==1)//It shows that it has just passed a 90 degree bend. { right_move(GEAR);//Turn right when the middle left sensor is pressing the line Edge_Flag=0; } else { left_move(GEAR);//Without 90 degree bend, turn left when the left sensor is pressing the line in the middle } LED1=!LED1; break; case TRACE4_SCAN: //Detection of the middle right sensor if(Edge_Flag==1) { left_move(GEAR); Edge_Flag=0; } else { right_move(GEAR); } LED0=!LED0; LED1=!LED1; break; } }else delay_ms(10); }
Barrier avoidance function
As mentioned earlier, we have built an obstacle avoidance platform using steering gear and ultrasonic sensors. Now we need to initialize it and complete ranging and obstacle avoidance.
PWM configuration of steering gear
The angle of the steering gear is controlled by PWM wave. By inputting different duty cycles of PWM wave to the steering gear, the steering gear can reach different angle positions.
/** * @brief: PWM Output Configured with Driving Obstacle Avoidance Yuntai Steering Machine * @param: arr-Automatic reload value psc-clock pre-dividing coefficient * @retval: NONE * @others: NONE **/ void TIM4_PWM_Init(u16 arr,u16 psc) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; TIM_OCInitTypeDef TIM_OCInitStructure; /* Turn on the clock */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE); GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_TIM4); //GPIOB6 Multiplexed to Timer 4 /* Configure GPIO mode and IO port */ GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;// PB6 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOB,&GPIO_InitStructure); //TIM4 timer initialization TIM_TimeBaseInitStructure.TIM_Period = arr; //PWM frequency = 72000/(199+1)=36Khz// Set the value of the automatic reload register cycle TIM_TimeBaseInitStructure.TIM_Prescaler = psc;//Set as TIM4 clock frequency pre-dividing value TIM_TimeBaseInitStructure.TIM_ClockDivision = 0; TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM Upward Counting Mode TIM_TimeBaseInit(TIM4, &TIM_TimeBaseInitStructure); //PWM initialization initializes peripheral TIM4 according to the parameters specified in TIM_OCInitStruct TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//PWM Output Enablation TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low; TIM_OC1Init(TIM4,&TIM_OCInitStructure); //Note that TIM_OC1Init is initialized here instead of TIM_OCInit, otherwise an error will occur. Because firmware libraries have different versions TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);//Preload Register Enabling TIM4 on CCR1 TIM_Cmd(TIM4,ENABLE);//Enabling TIM4 peripherals }
Initial configuration of ultrasonic sensor
/** * @brief: Ultrasound sensor initialization, * @param: NONE * @retval: NONE * @others: NONE **/ void HCSR04_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG , ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//Enabling SYSCFG Clock GPIO_InitStructure.GPIO_Pin = TRIG_PIN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_Init(SONAR_PORT, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = ECHO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; GPIO_Init(SONAR_PORT, &GPIO_InitStructure); SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOG, GPIO_PinSource3); // Interrupt line and interrupt initialization configuration EXTI_ClearITPendingBit(EXTI_Line3); /* External interrupt initialization for receiving detection signals */ EXTI_InitStructure.EXTI_Line = EXTI_Line3; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); /* External interrupt priority setting */ NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;//External interruption 3 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//Enabling external interruption of channels NVIC_Init(&NVIC_InitStructure); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); /* TIM2 Interrupt initialization for counting and timing */ TIM_TimeBaseInitStructure.TIM_Prescaler = 83;//Frequency dividing coefficient 83, frequency 1 MHz, theoretical measurement accuracy 0.34 mm TIM_TimeBaseInitStructure.TIM_Period = 50000;//The counting period is 50000, equivalent to 0.05s, and the maximum measuring range is 17m. TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); TIM_ITConfig( //Enables or disables specified TIM interrupts TIM2, //TIM2 TIM_IT_Update | //TIM interrupt source TIM_IT_Trigger, //TIM Trigger Interrupt Source ENABLE //Enable ); TIM_Cmd(TIM2, DISABLE); TIM_ClearFlag(TIM2, TIM_FLAG_Update); /* TIM2 Interrupt priority setting */ NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //TIM2 interruption NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ Channel Enablation NVIC_Init(&NVIC_InitStructure); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE); /* TIM5 Interrupt initialization to start the ranging function */ TIM_TimeBaseInitStructure.TIM_Prescaler = 83; TIM_TimeBaseInitStructure.TIM_Period = 100; TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInit(TIM5, &TIM_TimeBaseInitStructure); TIM_ITConfig( //Enables or disables specified TIM interrupts TIM5, //TIM5 TIM_IT_Update | //TIM interrupt source TIM_IT_Trigger, //TIM Trigger Interrupt Source ENABLE //Enable ); TIM_Cmd(TIM5, ENABLE); TIM_ClearFlag(TIM5, TIM_FLAG_Update); /* TIM5 Interrupt priority setting */ NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn; //TIM5 interruption NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ channel enabled NVIC_Init(&NVIC_InitStructure); }
Ranging function
According to the instructions of HC-SR05, it is necessary to trigger a high level not less than 10us. The following function realizes this function
/*Distance measure--------------------------------------------------*/ /** * @brief: Start the ranging function and trigger the ultrasonic sensor * @param: NONE * @retval: NONE * @others: The delay function inside this function must be reentrant because it is placed inside the interrupt function of TIM5 STM32 The delay function in the routine is not reentrant, so here we customize the reentrant delay function. **/ void HCSR04_StartMeasure(void) { GPIO_SetBits(SONAR_PORT, TRIG_PIN); delay_us_unpre(40); // The width of trig signal must be greater than 10us. //It appears in the interrupt function of timer 5, so the system delay cannot be used. // Customize the normal delay function to solve the problem of delay failure GPIO_ResetBits(SONAR_PORT, TRIG_PIN); //Printf ("Test start!"); the // printf function is also a non-reentrant function, which causes interruption failure after opening. }
Processing counter counting value to get ranging distance
/** * @brief: Ranging function * @param: TIM2 Counting value * @retval: Ranging distance, units:cm * @others: NONE **/ float HCSR04_GetDistance(u32 count) { float distance; // distance = measurement/2/1000*340 = measurement/59 (cm) measurement-units:us distance = (float)count / 58.8 ; return distance; }
Realization of Obstacle Avoidance
There are some algorithms involved here, which are easy to understand, that is, when an obstacle is detected, what kind of operation should be done after the obstacle is detected, and so on. Of course, obstacle avoidance can be realized in different ways, and it can be studied and optimized by itself.
/** * @brief: Obstacle avoidance task can be accomplished by corresponding operation using the obtained ranging distance * @param: NONE * @retval: NONE * @others: Initial real-time performance was not resolved because the function used a lot of delay, and now it is based on ranging distance. Real-time problem can be solved by implementing corresponding operations. **/ void Obstacle_avoid(void) { extern u16 GEAR; if(UltrasonicWave_Distance<30) { reverse(GEAR); while(UltrasonicWave_Distance<=40); stop(); TIM_SetCompare1(TIM4, 181);//Left turn of detector 45 degrees delay_ms(500); if(UltrasonicWave_Distance<30) { TIM_SetCompare1(TIM4, 191);//Detector turning right 45 degrees delay_ms(500); if(UltrasonicWave_Distance<30) { reverse(GEAR); while(UltrasonicWave_Distance<=40); right_move_2(GEAR+1); delay_ms(500); TIM_SetCompare1(TIM4, 186);//Detector return zero position drive(GEAR); } else { right_move_2(GEAR+1); delay_ms(500); TIM_SetCompare1(TIM4, 186);//Detector return zero position drive(GEAR); } } else { left_move_2(GEAR+1); delay_ms(500); drive(GEAR); TIM_SetCompare1(TIM4, 186);//Detector return zero position } } }