基于STM32的智能循迹小车设计(基础版)

基于STM32的智能循迹小车设计(基础版)

硬件准备

1、小车底盘+四直流电机(带轮)

在这里插入图片描述

2、STM32F103C8T6核心板

在这里插入图片描述

3、12V 8700mAh锂电池(可以用几节18650锂电池)

在这里插入图片描述

4、循迹模块

选择的是TCRT500L,五路集成在一起,集成度比较高,但是可能不如五个单独的循迹模块好用
在这里插入图片描述
5、L298N电机驱动模块
四驱车为啥用L298N电机驱动模块?
可以把左边的两个电机并联,用输出A控制。把右边的两个电机并联,用输出B控制。
在这里插入图片描述
12V供电接电源正极,供电GND接电源负极和核心板GND,5V供电接核心板5V和循迹模块5V,然后循迹模块GND接核心板GND,所有设备就都可以上电了。(最好设置几个开关,安全且方便调试)
另外,接线最好先试触,避免短路。

6、杜邦线、开关若干

软件设计

1、电机调速

通过输出PWM控制电机转速

PWM初始化(以A1为例)

void TIM2_CH2_PWM_Init(void)
{
    
    
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;  
	TIM_OCInitTypeDef  TIM_OCInitStructure;//定义三个结构体
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);  
//开启相关时钟

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; 
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
 //A1 GPIO初始化
	TIM_TimeBaseStructure.TIM_Period = 199; 
	TIM_TimeBaseStructure.TIM_Prescaler =7199; 
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; 
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); 
	// 定时器初始化
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; 
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; 
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; 
	TIM_OC2Init(TIM2, &TIM_OCInitStructure);  
	//定时器通道初始化
	TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); 
 	//预装值初始化
	TIM_Cmd(TIM2, ENABLE);  	
	//打开定时器
}

初始化完后,输出PWM控制电机转速,注意,TIM_SetCompare2(TIM2,n);n越小占空比越大,点假转速越快,一下代码就是A1输出PWM占空比更大,它所对应的电机转速就越快。 具体的数据是多少,需要自己根据不同的场地去摸索,不停地调试。

void left()
{
    
    
		TIM_SetCompare2(TIM2,20); 
		TIM_SetCompare3(TIM2,120);
}

2、循迹模块检测

GPIOB初始化,同时将B4 B5 B6 B7 B8设置为上拉输入

void GPIOB_Init()	
{
    
    
  GPIO_InitTypeDef GPIO_InitStructure;	
  RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE); 
	
  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_4 | GPIO_Pin_5  | GPIO_Pin_6 | GPIO_Pin_7| GPIO_Pin_8;	
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOB, &GPIO_InitStructure); 
}

宏定义,少打字,B4 B5 B6 B7 B8 分别对应L1 L2 M R2 R1

#define L1 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_4)
#define L2 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5)
#define M GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6)
#define R2 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7)
#define R1 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_8) // L1 L2 M R2 R1 

读取函数

void Read_Date(void)
{
    
    
 	L1;
	L2;
	M;
	R2;
	R1;
}

3、主函数(用读取的循迹数据控制电机)

用了一个比较笨的但是很直接的方法,将所有的情况都罗列出来。
思路:如果L1检测到,那必须bigright;如果R1检测到,那必须bigleft;
那中间的那三位,还有8种,将这8种枚举就可。

int main()
{
    
    
	SysTick_Init(72);
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 
	USART1_Init(9600);
	GPIOB_Init();
	TIM2_CH2_PWM_Init();
	TIM2_CH3_PWM_Init();
	while(1)
	{
    
    	
		Read_Date();
	 if(L1==0&&L2==0&&M==0&&R2==0&&R1==0)
	  {
    
    
	  go();		
	  delay_ms(10);
	  }
		
	 if(L1==0&&L2==1&&M==1&&R2==1&&R1==0)
	  {
    
    
	 go();      
	  delay_ms(10);
	  }	  
		if(L1==0&&L2==0&&M==1&&R2==0&&R1==0)
	  {
    
    
	 go();      
	  delay_ms(10);
	  }	  
	 if(L1==0&&L2==1&&M==0&&R2==0&&R1==0)
	  {
    
    
	 right();   
	  delay_ms(10);
	  }
 	 if(L1==0&&L2==0&&M==0&&R2==1&&R1==0)
	  {
    
    
	 left();   
	  delay_ms(10); 
	  }
		if(L1==0&&L2==1&&M==1&&R2==0&&R1==0)
	  {
    
    
	  right();   
	  delay_ms(10); 
	  }
		if(L1==0&&L2==1&&M==0&&R2==1&&R1==0)
	  {
    
    
	  go();   
	  delay_ms(10); 
	  }
		if(L1==0&&L2==0&&M==1&&R2==1&&R1==0)
	  {
    
    
	  left();   
	  delay_ms(10); 
	  }
	  if(R1==1)
	  {
    
    
	  bigleft();   
	  delay_ms(10);
	  }
	  if(L1==1)
	  {
    
    
	  bigright();
	  delay_ms(10); 
	  }
  }	
}


工程文件现已上传到资源,2积分即可下载。

猜你喜欢

转载自blog.csdn.net/Rendezvous1/article/details/108253614