Summary of STM32 Car Project in Summer Holiday

Keywords: less angular Mobile

It took two weeks to finally get the car ready because for another project in the group, I was only deeply involved at the beginning and later stages of the project.It involves the improvement of ultrasound driver, car obstacle avoidance algorithm, and the complete code of Bluetooth control.

First, briefly describe the functions of the car: 1. ultrasonic obstacle avoidance; 2. Bluetooth control.

The Bluetooth control functions include 1. driving the car to move forward, backward, left and right; 2. driving the car out of the rectangle on the ground.

1. Problems and solutions encountered while debugging the car.

Unlike debugging C-language code, you can always see the value of each variable, and this time we are using the STM32C8T6 super mini-board.This board is very evil. The program that works normally on the mini board is identical to pin-to-pin diagram and port reuse, but it does not work on the mini board.

(1) Many inaccurate data returned by ultrasound results in abnormal car motion.

The data measured by the ultrasonic range element is not precise and is obviously affected by the actual environment, so there are many abnormal data in the large amount of returned data, which can lead to abnormal movement of the car.And our solution is clear - filtering out some apparently unusual data.Ultrasound module (HC-SR04) ranges from 0 to 400 cm. We filter out the data returned by the module which is larger than 500 cm, and improve the accuracy of ranging by averaging the data received several times, which makes the car more stable in motion.

(2) Lack of consideration for extreme situations

When designing the motion algorithm for the car, we did not take into account the abnormal data caused by the ultrasound module itself when the car was moving diagonally against the wall.Because this time our design is to place three ultrasound modules in front of the car to detect obstacles in front, left and right of the car.Our solution to this problem is: when the car decides that it should go straight, judge the data returned by the left and right ultrasonic modules simultaneously under the execution statement. If the distance between one side is less than 5 cm, the car turns to the other side.

(3) The relationship between ultrasound obstacle avoidance and Bluetooth control is not fully understood.

In the design of the program, we consider Bluetooth control and ultrasonic obstacle avoidance as two independent programs. The design idea is that Bluetooth control and ultrasonic obstacle avoidance cannot be executed simultaneously.But the fact is that Bluetooth control is initiated by serial interrupt, that is, the function of Bluetooth control is not affected while ultrasonic obstacle avoidance is running.However, Bluetooth control cannot change and keep the car moving for a long time, because after the serial interrupt service function is executed, the program will continue to cycle the car moving state continuously in the ultrasonic obstacle avoidance.In order to be able to jump out of obstacle avoidance during Bluetooth control, we add a while loop to the Bluetooth control loop, which jumps out when the difference between the value in the receiving data register and 57 is zero.So when the jump-out cycle condition is not met, the program will remain stuck in the while cycle and will not enter the obstacle-avoiding program.

(4) Then there is a temporary requirement - let the car run out of a rectangular pattern, the length and width of which can be customized each time through the Bluetooth serial port

The movement of the car is influenced by many external environments, such as the smoothness of the ground and the remaining battery capacity.For the design idea of this function algorithm, we first measure the driving speed of the car, and then calculate the turning angle speed of the car.Calculate how long it takes the car to turn 90 degrees based on its angular speed.The turning time of the car is then adjusted without interruption to make the car turn 90 degrees.

2. Program Source

(1) ultrasonic obstacle avoidance

#ifndef __HCSR_H
#define __HCSR_H
#include "sys.h"

void TIM2_Cap_Init(u16 arr,u16 psc);

#endif


-----------------------------------------------------------------------
#include "sys.h"

void TIM2_Cap_Init(u16 arr,u16 psc)
{		 
	RCC->APB1ENR|=1<<0;   	//TIM2 Clock Enabling 
	RCC->APB2ENR|=1<<2;    	//Enable PORTA clock  
	RCC->APB2ENR|=1<<3;    	//Enable PORTB clock  
	
	
	GPIOA->CRL&=0XFFFF000F;	//PA0,PA1 set before clearing  
	GPIOA->CRL|=0X00008880;	//PA0,PA1 input  
	GPIOA->ODR|=0<<1;		//PA0,PA1 Dropdown
	GPIOA->ODR|=0<<2;		//PA0,PA1 Dropdown
	GPIOA->ODR|=0<<3;		//PA0,PA1 Dropdown
	
	
  GPIOB->CRL&=0X000FFFFF;//Pre-PB7 Cleanup Settings
  GPIOB->CRL|=0X33300000;//PB7 Push-Pull Output
  GPIOB->ODR|=1<<7;      //PB7 Output High
	GPIOB->ODR|=1<<6;
	GPIOB->ODR|=1<<5;
	
	
 	TIM2->ARR=arr;  		//Set counter auto-reset value   
	TIM2->PSC=psc;  		//prescaler 
	//CH2
	TIM2->CCMR1|=1<<8;		//CC2S=01 Select input IC1 to map to TI1
 	TIM2->CCMR1|=1<<12; 	//IC2F=0001 Configure input filter to sample with Fck_int, valid after 2 events
 	TIM2->CCMR1|=0<<10; 	//IC2PS=00 Configure input crossover, no crossover 
	TIM2->CCER|=0<<5; 		//CC2P=0 Rising Edge Capture
	TIM2->CCER|=1<<4; 		//CC2E=1 Allows the value of the capture counter to be transferred to the capture register
	//CH3
	TIM2->CCMR2|=1<<0;		//CC3S=01 Select input IC1 to map to TI1
 	TIM2->CCMR2|=1<<4; 		//IC3F=0001 Configure input filter to sample with Fck_int, valid after 2 events
 	TIM2->CCMR2|=0<<2; 		//IC3PS=00 Configure input crossover, no crossover 
	TIM2->CCER|=0<<9; 		//CC3P=0 Rising Edge Capture
	TIM2->CCER|=1<<8; 		//CC3E=1 Allows the value of the capture counter to be transferred to the capture register
	//CH4
	TIM2->CCMR2|=1<<8;		//CC4S=01 Select input IC1 to map to TI1
 	TIM2->CCMR2|=1<<12; 	//IC4F=0001 Configure input filter to sample with Fck_int, valid after 2 events
 	TIM2->CCMR2|=0<<10; 	//IC4PS=00 Configure input crossover, no crossover
	TIM2->CCER|=0<<13; 		//CC4P=0 Rising Edge Capture
	TIM2->CCER|=1<<12; 		//CC4E=1 Allows the value of the capture counter to be transferred to the capture register
	
 
	//Interrupt Enabling
	TIM2->DIER|=1<<2;   	//Allow capture 2 interrupts	
	TIM2->DIER|=1<<3;   	//Allow Capture 3 Interrupts	
	TIM2->DIER|=1<<4;   	//Allow capture of 4 interrupts	
	
	TIM2->DIER|=1<<0;   	//Allow update interruption	
	TIM2->CR1|=0x01;    	//Enable Timer 2
	MY_NVIC_Init(2,0,TIM2_IRQn,2);//Preemption 2, Subpriority 0, Group 2	   
}

(2) Bluetooth control function

#ifndef __SMG_H
#define __SMG_H 
#include "sys.h"
#include "delay.h"


#define USART_REC_LEN > 200 // Define the maximum number of characters to receive
#define EN_USART3_RX > 1 //enable (1)/disable (0) serial port reception
extern u8  USART3_RX_BUF[USART_REC_LEN]; //Receive buffer, maximum USART_REC_LEN bytes, last byte is a line break
extern u16 USART3_RX_STA;         		//Receive status flag



#endif


------------------------------------------------------------------------
#include "sys.h"
#include "lanya.h"
#include "delay.h"
#include "usart.h"
#include "dianji.h"

u8 BTFlag;
#if EN_USART1_RX 
 
void Juxing()//Rectangular Motion Function of Cart
{
	u8 chang,kuan,x,y;//chang, kuan are the values of the length and width of the rectangle the car will take, respectively
	delay_ms(200);
	printf("Chang:\r\n");
	while(1)
	{
		printf("Input Chang:\r\n");
		delay_ms(200);
		if(USART1->SR&(1<<5))//Jump out of loop when serial port receives message
		{
			chang=USART1->DR-'0';//Convert character data to integer data
			break;
		} 
	}
	printf("Long:%d\r\n",chang);//Print data received by serial port
	USART1->SR=0;//Receive flag bits of serial port zeroed in preparation for next receive width data
	while(1)
	{
		printf("Input Kuan:\r\n");
		delay_ms(200);
		if(USART1->SR&(1<<5))
		{
			kuan=USART1->DR-'0';//Jump out of loop when serial port receives data
			break;
		}
	}
	printf("wide:%d\r\n",kuan);//Print Width Data
	//Current trolley speed is 0.25 m/sec. The trolley uses 40 ms for every 1 cm walk, so it takes 40 ms for every 1 cm walk to drive the trolley with the for function
	for(x=0;x<chang*10;x++)//Straight Length
	{
		GO(300,300);
		delay_ms(40);
	}
	RIGHT(300,300);//Right Turn
	delay_ms(785);
	for(y=0;y<kuan*10;y++)//Straight Walk Width
	{
		GO(300,300);
		delay_ms(40);
	}
	RIGHT(300,300);//Right Turn
	delay_ms(785);
	for(x=0;x<chang*10;x++)//Straight Length
	{
		GO(300,300);
		delay_ms(40);
	}
	RIGHT(300,300);//Right Turn
	delay_ms(785);
	for(y=0;y<kuan*10;y++)//Straight Walk Width
	{
		GO(300,300);
		delay_ms(40);
	}
	RIGHT(300,300);//Right Turn
	delay_ms(785);
	STOP();
}
//Send character message through Bluetooth serial port Control car movement by judging character message
u8 USART1_RX_BUF[USART_REC_LEN];    
u16 USART1_RX_STA=0;      	  
void USART1_IRQHandler(void)
{
	char res;	//Define a character variable'res'
	if(USART1->SR&(1<<5))
	{		
		res=USART1->DR;// Make res equal to the data received by the serial port
		printf("\r\n%d",res);		
		//Change the car motion state by judging the value of res and send the motion state to the mobile phone through the serial port
		if(res==50)//
		{	
			GO(300,300);//Car Forward
			printf("\r\nGo Stright");
		}
		else if(res==56)	
		{
			BACK(300,300);//Car Back
			printf("\r\nGo Back");
		}
		else if(res== 52)
		{
			LEFT(300,300);//Car turns left
			printf("\r\nTurn Left");			
		}
		else if(res==54)
		{
			RIGHT(300,300);//Car turns right
			printf("\r\nTurn Right");
		}
		else if(res==53)
		{
			STOP();//Car stop
			printf("\r\nStop");
		}
		else if(res=='7')//Car walk rectangle
		{
			delay_ms(200);
			Juxing();//Rectangular Motion Function of Cart
		}
	}
} 
#endif		
 
 

(3) Principal functions

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "hcsr.h"
#include "lanya.h"
#include "dianji.h"
//Timer 2 Channel 1-4 Input Capture Configuration
//arr: auto-reload value
//psc: clock Prescale frequency

//Capture Status
//[7]: 0, no successful capture; 1, successful capture once.
//[6]: 0, not yet captured high level; 1, captured high level.
//[5:0]: Number of overflows after capturing a high level
u8  TIM2CH1_CAPTURE_STA=0;	//Input Capture Status		    				
u16	TIM2CH1_CAPTURE_Date2;	//Data 2
u16 TIM2CH1_CAPTURE_Date1;	//Data 1
//CH2
u8  TIM2CH2_CAPTURE_STA=0;	//Input Capture Status		    				
u16	TIM2CH2_CAPTURE_Date2;	//Data 2
u16 TIM2CH2_CAPTURE_Date1;	//Data 1
//CH3
u8  TIM2CH3_CAPTURE_STA=0;	//Input Capture Status		    				
u16	TIM2CH3_CAPTURE_Date2;	//Data 2
u16 TIM2CH3_CAPTURE_Date1;	//Data 1
//CH4
u8  TIM2CH4_CAPTURE_STA=0;	//Input Capture Status		    				
u16	TIM2CH4_CAPTURE_Date2;	//Data 2
u16 TIM2CH4_CAPTURE_Date1;	//Data 1
 
//Timer 2 interrupt service program	 
void TIM2_IRQHandler(void)
{ 		    
	u16 tsr;
	tsr=TIM2->SR;
	//CH2 Interrupt Processing
	if((TIM2CH2_CAPTURE_STA&0X80)==0)//Not Captured Successfully	
	{
		if(tsr&0X01)//overflow
		{	    
			if(TIM2CH2_CAPTURE_STA&0X40)//High level captured
			{
				if((TIM2CH2_CAPTURE_STA&0X3F)==0X3F)//High level is too long
				{
					TIM2CH2_CAPTURE_STA|=0X80;//Tag captured once successfully
					TIM2CH2_CAPTURE_Date2=0XFFFF;
				}else TIM2CH2_CAPTURE_STA++;
			}	 
		}
		if(tsr&0x04)//Capture 2 A capture event occurs
		{	
			if(TIM2CH2_CAPTURE_STA&0X40)		//Capture a falling edge 		
			{	  			
				TIM2CH2_CAPTURE_STA|=0X80;		//Marker successfully captured a high level pulse width
			    TIM2CH2_CAPTURE_Date2=TIM2->CCR2;	//Get the current capture value.
	 			TIM2->CCER&=~(1<<5);			//CC2P=0 set to Rising Edge Capture
			}else  								//Not yet started, capturing the rising edge for the first time
			{ 
				TIM2CH2_CAPTURE_Date2=0;
				TIM2CH2_CAPTURE_STA=0X40;		//Tag captured rising edge
				TIM2CH2_CAPTURE_Date1=TIM2->CCR2;
				TIM2->CCER|=1<<5; 				//CC2P=1 set to Down Edge Capture 
			}		    
		}			     	    					   
 	}
	//CH3 Interrupt Processing
	if((TIM2CH3_CAPTURE_STA&0X80)==0)//Not Captured Successfully	
	{
		if(tsr&0X01)//overflow
		{	    
			if(TIM2CH3_CAPTURE_STA&0X40)//High level captured
			{
				if((TIM2CH3_CAPTURE_STA&0X3F)==0X3F)//High level is too long
				{
					TIM2CH3_CAPTURE_STA|=0X80;//Tag captured once successfully
					TIM2CH3_CAPTURE_Date2=0XFFFF;
				}else TIM2CH3_CAPTURE_STA++;
			}	 
		}
		if(tsr&0x08)//Capture 3 A capture event occurs
		{	
			if(TIM2CH3_CAPTURE_STA&0X40)		//Capture a falling edge 		
			{	  			
				TIM2CH3_CAPTURE_STA|=0X80;		//Marker successfully captured a high level pulse width
			    TIM2CH3_CAPTURE_Date2=TIM2->CCR3;	//Get the current capture value.
	 			TIM2->CCER&=~(1<<9);			//CC3P=0 set to Rising Edge Capture
			}else  								//Not yet started, capturing the rising edge for the first time
			{ 
				TIM2CH3_CAPTURE_Date2=0;
				TIM2CH3_CAPTURE_STA=0X40;		//Tag captured rising edge
				TIM2CH3_CAPTURE_Date1=TIM2->CCR3;
				TIM2->CCER|=1<<9; 				//CC3P=1 set to Down Edge Capture 
			}		    
		}			     	    					   
 	}
	//Interrupt handling in CH4
	if((TIM2CH4_CAPTURE_STA&0X80)==0)//Not Captured Successfully	
	{
		if(tsr&0X01)//overflow
		{	 
			if(TIM2CH4_CAPTURE_STA&0X40)//High level captured
			{
				if((TIM2CH4_CAPTURE_STA&0X3F)==0X3F)//High level is too long
				{
					TIM2CH4_CAPTURE_STA|=0X80;//Tag captured once successfully
					TIM2CH4_CAPTURE_Date2=0XFFFF;
				}else TIM2CH4_CAPTURE_STA++;
			}	 
		}
		if(tsr&0x10)//Capture 4 A capture event occurs
		{	
			if(TIM2CH4_CAPTURE_STA&0X40)		//Capture a falling edge 		
			{	  			
				TIM2CH4_CAPTURE_STA|=0X80;		//Marker successfully captured a high level pulse width
			    TIM2CH4_CAPTURE_Date2=TIM2->CCR4;	//Get the current capture value.
	 			TIM2->CCER&=~(1<<13);			//CC4P=0 set to Rising Edge Capture
			}else  								//Not yet started, capturing the rising edge for the first time
			{ 
				TIM2CH4_CAPTURE_Date2=0;
				TIM2CH4_CAPTURE_STA=0X40;		//Tag captured rising edge
				TIM2CH4_CAPTURE_Date1=TIM2->CCR4;
				TIM2->CCER|=1<<13; 				//CC4P=1 set to Down Edge Capture 
			}		    
		}			     	    					   
 	}
	
	
	TIM2->SR=0;//Clear interrupt flag bits 	    
}

u32 CEJU2(void)
{
	while(1)
	{
		u32 temp2=0;
		PBout(7)=1;                        //Open TRIG
		delay_us(20);
		PBout(7)=0;												 //Close TRIG
		if(TIM2CH2_CAPTURE_STA&0X80)			//Successfully captured a high level
		{
			temp2=TIM2CH2_CAPTURE_STA&0X3F;
			temp2*=65536;						//Total Overflow Time
			temp2+=TIM2CH2_CAPTURE_Date2;		
			temp2-=TIM2CH2_CAPTURE_Date1;		//Get total high level time
			temp2*=0.017;										//Get Distance
			printf("TIM2_CH2_LENGTH:%d cm\r\n",temp2);		//Print Distance
			TIM2CH2_CAPTURE_Date1=0;
 			TIM2CH2_CAPTURE_STA=0;				//Open next capture
 		}
		if(temp2<500) return temp2;   //Return distance value
		else return 0;
	}
}

u32 CEJU3(void)
{
	while(1)
	{
		u32 temp2=0;
		PBout(6)=1;
		delay_us(20);
		PBout(6)=0;
		if(TIM2CH3_CAPTURE_STA&0X80)			//Successfully captured a high level
		{
			temp2=TIM2CH3_CAPTURE_STA&0X3F;
			temp2*=65536;						//Total Overflow Time
			temp2+=TIM2CH3_CAPTURE_Date2;		
			temp2-=TIM2CH3_CAPTURE_Date1;		//Get total high level time
			temp2*=0.017;									
			printf("TIM2_CH3_LENGTH:%d cm\r\n",temp2);	
			TIM2CH3_CAPTURE_Date1=0;
 			TIM2CH3_CAPTURE_STA=0;				//Open next capture
 		}
		if(temp2<500) return temp2;
		else return 0;
	}
}


u32 CEJU4(void)
{
	while(1)
	{
		u32 temp2=0;
		
			PBout(5)=1;
			delay_us(20);
			PBout(5)=0;
			if(TIM2CH4_CAPTURE_STA&0X80)			//Successfully captured a high level
			{
				temp2=TIM2CH4_CAPTURE_STA&0X3F;
				temp2*=65536;						//Total Overflow Time
				temp2+=TIM2CH4_CAPTURE_Date2;		
				temp2-=TIM2CH4_CAPTURE_Date1;		//Get total high level time
				temp2*=0.017;
				printf("TIM2_CH4_LENGTH:%d cm\r\n",temp2);		
				TIM2CH4_CAPTURE_Date1=0;
				TIM2CH4_CAPTURE_STA=0;				//Open next capture
			}
		if(temp2<500) return temp2;        
			else return 0;
	}
}

int main(void)
{	
	u32 i=3,j;
	u32 temp2=0,temp3=0,temp4=0;
	extern u8 opq;
	Stm32_Clock_Init(9);					  	//Initialize the system clock		
	delay_init(72);								//Initialization Delay	
	uart_init(72,9600);						//Serial port initialization
	
	TIM2_Cap_Init(0XFFFF,72-1);					//Ultrasound initialization, counted at 2 Mhz frequency 
	TIM_PWM1_Init(1000-1,36-1); 	//Motor initialization, no frequency division.PWM Frequency=72000/(899+1)=80Khz
		printf("Choose moudle:");
	
			CEJU2();           //Ultrasound Pre-Initialization
			CEJU3();
			CEJU4();
			delay_ms(1000);
	
			while(1)  
			{		
				while(USART1->DR-57)     //Jump out of the loop when receiving data of type 9
				{
					;
				}
				temp2=0;        //For each new cycle, zero temp2, temp3, temp4
				temp3=0;
				temp4=0;
				while(i)       //Detect the value of three positive ultrasound returns
				{
					j=CEJU4();
					temp4+=j;
					if(j!=0) i--; 
				}
				temp4=temp4/3;   //Take the average of the values returned by the third ultrasound to reduce the error
				i=3;
				j=0;
				if(temp4<40)     //If the distance ahead is less than 40cm, make a judgment
				{
					while(i)				//Detect the value of three times left ultrasound return
					{
						j=CEJU2();
						temp2+=j;
						if(j!=0) i--; 
					}
					temp2=temp2/3;
					i=3;
					j=0;
					if(temp2<40)    //If the left distance is less than 40cm, make a judgment
					{
						while(i)     //Detect the value of three right ultrasound returns
						{
							j=CEJU3();
							temp3+=j;
							if(j!=0) i--; 
						}
						temp3=temp3/3;
						i=3;
						j=0;
						if(temp3<40)     //If the right distance is less than 40cm, go back and turn left
						{
							BACK(300,300);
							printf("back\r\n");
							delay_ms(500);
							LEFT(300,300);
							delay_ms(500);
						}
						else             //Turn right if the right distance is greater than 40cm
						{
							RIGHT(300,300);
							printf("right\r\n");
							delay_ms(500);
						}
					}
					else								//Turn left if the right distance is greater than 40cm
					{
						LEFT(300,300);
						printf("left\r\n");
						delay_ms(500);
					}
				}
				else                  //If the front distance is greater than 40cm, judge
				{
					while(i)						//Detect the value of three times left ultrasound return
					{
						j=CEJU2();
						temp2+=j;
						if(j!=0) i--; 
					}
					temp2=temp2/3;
					i=3;
					j=0;
					if(temp2<=5)				//Turn right if left distance is less than 5cm
					{
						RIGHT(200,200);
						delay_ms(500);
					}	
					while(i)							//Detect the value of three right ultrasound returns
					{
						j=CEJU3();
						temp3+=j;
						if(j!=0) i--; 
					}
					temp3=temp3/3;
					i=3;
					j=0;
					if(temp3<=5)				//Turn left if the right distance is less than 5cm
					{
						LEFT(200,200);
						delay_ms(500);
					}
					GO(300,300);				//Straight
					delay_ms(500);
				printf("go\r\n");
				}
				TIM2->CNT=0;          //Zero CNT value for each loop
		}
}




 

Posted by glory452 on Wed, 31 Jul 2019 18:27:50 -0700