STM32F1编写简单的五路黑白循迹

STM32F1编写简单的五路黑白循迹

一、小车模型设计

1)硬件搭配:四轮小车底盘、五路红外循迹传感器、L298N两路电机驱动模块、STM32F103RC最小系统板、电源、降压模块。

2)说明:这里只用到了两路电机驱动模块,是因为我将同一边的电机进行了并联;使用的电源应大于7V,才能有效的驱动小车行驶;降压模块的作用是将电压调节到适合单片机最小系统板工作的5V供电。

3)组装起来大概长这个模样
在这里插入图片描述

二、循迹程序设计

(在最后面我提供了工程文件的下载链接,大家可以下载验证)

1)需要配置的外设:五个GPIO输入口,两个定时器输出PWM波(这里只有两路也可以只配置一个定时器,因为一个定时器可以输出4路PWM波);

2)GPIO口配置(五路输入):

// 端口宏定义:

#define TRACK_PORT 					GPIOA//选择A端口
#define TRACK_PORT_CLK			    RCC_APB2Periph_GPIOA//端口A时钟

#define TRACK_INFRARED_L2_PIN		GPIO_Pin_9//左2传感器对应的引脚
#define TRACK_INFRARED_L1_PIN		GPIO_Pin_8//左1传感器对应的引脚
#define TRACK_INFRARED_M_PIN		GPIO_Pin_7//中间传感器对应的引脚
#define TRACK_INFRARED_R1_PIN		GPIO_Pin_6//右1传感器对应的引脚
#define TRACK_INFRARED_R2_PIN		GPIO_Pin_5//右2传感器对应的引脚

// 端口模式配置函数:

void Track_Init(void)//循迹端口初始化
{
	GPIO_InitTypeDef GPIO_InitStructure;//GPIO结构体定义

	RCC_APB2PeriphClockCmd(TRACK_PORT_CLK ,ENABLE);//打开端口时钟
	
	GPIO_InitStructure.GPIO_Pin = TRACK_INFRARED_M_PIN | TRACK_INFRARED_L1_PIN | TRACK_INFRARED_L2_PIN |
								  TRACK_INFRARED_R1_PIN | TRACK_INFRARED_R2_PIN;//配置传感器读取引脚
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//配置为输入上拉模式
	GPIO_Init(TRACK_PORT,&GPIO_InitStructure);//初始化端口
	

3)定时器TIM配置:

//定时器配置宏定义:


void Motor_Init(void)
{
	uint16_t PrescalerValue;//分频参数变量
	GPIO_InitTypeDef GPIO_InitStruct;//GPIO配置结构体定义
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;//TIM配置结构体定义
	TIM_OCInitTypeDef TIM_OCInitStruct;//TIM输出结构体定义

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3 | RCC_APB1Periph_TIM2,ENABLE);//开启TIM2、TIM3的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO,ENABLE);//开启GPIO的时钟与端口复用时钟
	
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;//配置TIM3的CH3和CH4输出引脚
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;//模式设定为复用模式
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;//设定引脚速率
	GPIO_Init(GPIOB,&GPIO_InitStruct);//根据结构体参数初始化GPIOB
	
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;//配置TIM2的CH3和CH4输出引脚
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;//模式设定为复用模式
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;//设定引脚速率
	GPIO_Init(GPIOA,&GPIO_InitStruct);//根据结构体参数初始化GPIOA

	TIM_DeInit(TIM3);//复位TIM3
	TIM_DeInit(TIM2);//复位TIM2
	
	PrescalerValue = (uint16_t) (SystemCoreClock / 4000000 ) - 1;//分频系数计算
	TIM_TimeBaseStruct.TIM_Period = SPEED_PERIOD;//重载寄存器的值,定时周期
	TIM_TimeBaseStruct.TIM_Prescaler = PrescalerValue;//预分频
	TIM_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_DIV1;//时钟切割
	TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStruct);//使用结构体参数初始化TIM3
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStruct);//使用结构体参数初始化TIM2
	
	TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;//PWM模式为1
	TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;//使能TIM得输出
	TIM_OCInitStruct.TIM_Pulse = STARTER_SPEED;//比较寄存器的值
	TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;//通道1的有效电平为高电平;
	
	TIM_OC3Init(TIM3,&TIM_OCInitStruct);//使用结构体参数初始化TIM3的CH3输出PWM波
	TIM_OC3Init(TIM2,&TIM_OCInitStruct);//使用结构体参数初始化TIM2的CH3输出PWM波
	
	TIM_OC4Init(TIM3,&TIM_OCInitStruct);//使用结构体参数初始化TIM3的CH4输出PWM波
	TIM_OC4Init(TIM2,&TIM_OCInitStruct);//使用结构体参数初始化TIM2的CH4输出PWM波
	
	
	TIM_OC3PreloadConfig(TIM3,TIM_OCPreload_Enable);//允许随时修改TIM3 CCR3比较寄存器的值;
	TIM_OC4PreloadConfig(TIM3,TIM_OCPreload_Enable);//允许随时修改TIM3 CCR4比较寄存器的值;
	
	TIM_OC3PreloadConfig(TIM2,TIM_OCPreload_Enable);//允许随时修改TIM2 CCR3比较寄存器的值;
	TIM_OC4PreloadConfig(TIM2,TIM_OCPreload_Enable);//允许随时修改TIM2 CCR4比较寄存器的值;

	TIM_Cmd(TIM3,ENABLE);//开启TIM3
	TIM_Cmd(TIM2,ENABLE);//开启TIM2
}

4)电机驱动函数:

/*******
功  能:左边电机驱动函数
形  参:cont1  配置CCR3比较寄存器的值(占空比调整)
       cont2  配置CCR4比较寄存器的值(占空比调整)
返回值: 无
说  明:当cont1大于0,cont2为0时,电机正转,反之则反转(这里仔细理解一下,后面函数会使用到)
******/
void Motor_L_Cont(uint16_t cont1,uint16_t cont2)
{
	TIM3->CCR3 = cont1; 
	TIM3->CCR4 = cont2;
}

/*******
功  能:右边电机驱动函数
形  参:cont1  配置CCR3比较寄存器的值(占空比调整)
       cont2  配置CCR4比较寄存器的值(占空比调整)
返回值: 无
说  明:当cont1大于0,cont2为0时,电机正转,反之则反转(这里仔细理解一下,后面函数会使用到)
******/
void Motor_R_Cont(uint16_t cont1,uint16_t cont2)
{
	TIM2->CCR3 = cont1; 
	TIM2->CCR4 = cont2;
}

/*******
功  能:双边电机驱动函数
形  参:L_speed  设置左电机前进的转速
       R_speed  设置右电机前进的转速
返回值: 无
说  明:这里调用左电机驱动和右电机驱动函数,
******/
void Motor_Speed_Adjust(uint16_t L_speed,uint16_t R_speed)
{
	Motor_L_Cont(L_speed,0);
	Motor_R_Cont(R_speed,0);
}

/*******
功  能:小车旋转函数(左右电机反方向转动)
形  参:fx  为1时,逆时针转动(左电机反转,右电机正转)
           为0时,顺时针转动(左电机正转,右电机反转)
返回值: 无
说  明:这里使用到的STARTER_SPEED,为宏定义的初始占空参数,这里调用左电机驱动和右电机驱动函数,
******/
void Motor_Opposite(u8 fx)//旋转
{
	if(fx)
	{
		Motor_L_Cont(0,STARTER_SPEED);
		Motor_R_Cont(STARTER_SPEED,0);
	}
	else
	{
		Motor_L_Cont(STARTER_SPEED,0);
		Motor_R_Cont(0,STARTER_SPEED);
	}	
}
/********
功  能:后退,左右电机反转
形  参:无
返回值: 无
说  明:这里使用到的STARTER_SPEED,为宏定义的初始占空参数,这里调用左电机驱动和右电机驱动函数,
******/
void Motor_Retreat(void)
{
	Motor_L_Cont(0,STARTER_SPEED);
	Motor_R_Cont(0,STARTER_SPEED);
}

5)循迹函数:

/********
功  能:读取5个传感器输出的状态
形  参:无
返回值:state 传感器状态
说  明:传感器检测到白线输出1,黑线输出0。。
		因为使用的时GPIOA端口的5到9引脚,这里直接读出GPIOA所有引脚的状态,
		然后将得到的数据向右移动5位,去掉0到4引脚的数据,
		再与上0x001f,得到5到9引脚的状态,
******/
u8 Get_Infrared_State(void)
{
	u8 state = 0;
	state = (u8)(GPIO_ReadInputData(TRACK_PORT) >> 5) & 0x001f;

	return state;
}

/********
功  能:循迹调整函数
形  参:无
返回值: 无
说  明:根据获取到的传感器输出状态,进行左右电机的速度调整
******/
void Track_Adjust(void)
{
	u8 flag = 1;//是否复位标志
	u8 state = 0;//状态获取变量定义
	
	while(flag)
	{
		state = Get_Infrared_State();//获取传感器状态
		switch(state)
		{
			case 0b00000: 
			case 0b10001: 
			case 0b00001: 
			case 0b10000: Motor_Speed_Adjust(0,0); break;//停止

			case 0b10011: Motor_Speed_Adjust(STARTER_SPEED-100,STARTER_SPEED+100); break;//右偏1级
			case 0b10111: Motor_Speed_Adjust(STARTER_SPEED-250,STARTER_SPEED+250); break;//右偏2级
			case 0b00111: Motor_Speed_Adjust(STARTER_SPEED-400,STARTER_SPEED+400); break;//右偏3级
			case 0b01111: Motor_Opposite(L); break;//右偏4级,

			case 0b11001: Motor_Speed_Adjust(STARTER_SPEED+100,STARTER_SPEED-100); break;//左偏1级
			case 0b11101: Motor_Speed_Adjust(STARTER_SPEED+250,STARTER_SPEED-250); break;//左偏2级
			case 0b11100: Motor_Speed_Adjust(STARTER_SPEED+400,STARTER_SPEED-400); break;//左偏3级
			case 0b11110: Motor_Opposite(R); break;//左偏4级
			
			case 0b11011: Motor_Speed_Adjust(STARTER_SPEED,STARTER_SPEED);flag = 0; break;//正常
			
			case 0b11111: Motor_Speed_Adjust(0,0); break;
			
			default: Motor_Speed_Adjust(0,0); break;
		}
	}
}

工程文件下载链接:
链接:https://pan.baidu.com/s/1SUit597TkdzdcgemiXCrsA
提取码:sdsa

(好的,到这里就完了。写的非常简单,不足的地方请各位不吝赐教)

  • 40
    点赞
  • 276
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 16
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是东山啊_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值