基于stm32的红外巡线小车(基础版)

基于stm32的红外巡线小车(基础版)

前两天做了一个红外巡线小车,想记录一下整个过程,也让自己掌握的更牢固,同时也分享给大家看看。在此要特别感谢实验室的学长,帮我解决一些问题到晚上一点多,同时帮我优化了控制的逻辑。这个小车比较基础,主要是分享给新手,同时我自己学的也不是很深入,如果文章有错的地方,还请多指正。那么话不多说,我们来看制作过程。

  1. 硬件篇
  2. 软件篇

一、硬件篇
1.stmf103c8t6最小系统板在这里插入图片描述
2.l298n电机驱动模块
将控制电机的4个io口接到L298N的逻辑输入接口,输出A和输出B分别连接两个电机。12V供电接电源正极,5V供电接单片机5V供电,gnd接电源负极和单片机gnd。在这里插入图片描述
3.两个红外传感器
红外传感器有三个接口,一个vcc一个gnd,另一个是返回数据。在这里插入图片描述
4.锂电池(7.4V~12V)
5.小车底盘(两个电机)
相关的io口接线在函数中都有配置,在这就不写了
二、软件篇
制作红外巡线小车主要需要红外传感器的函数和电机pwm驱动的函数,另外还需要添加正点原子的delay文件和sys文件。
1红外传感器
首先我们要明白红外传感器的原理,当红外灯检测到黑线时返回给io口的值是0,检测到黑线外(亮光位置)时,返回的值是1。知道了这些,我们就只需要读取io口的值,就可以判断小车的巡线情况。
我在头文件中定义了#define DO1 PAin(1)
#define DO2 PAin(2)
这两句代码就是读取PA1,PA2两个io口的值,这种定义是基于sys库函数的,比较方便。
red.c

#include "red.h"
u8 redray1_findblack;
u8 redray2_findblack;

void REDRAY_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOA, &GPIO_InitStructure);
}

void REDRAY_Scan(void)
{
	if(DO1==0)redray1_findblack=1;
	else redray1_findblack=0;
	if(DO2==0)redray2_findblack=1;
	else redray2_findblack=0;
	
}

2.电机驱动(pwm)
首先配置电机的io口,然后配置这些io口的pwm。pwm的配置这里就不降讲了,可以看一下网上的stm32的基础教程,这里讲一下怎么计算pwm的占空比和频率:
首先我们看motor.c中的TIM_SetCompare1(TIM4,pwm1);其中pwm1是捕获比较寄存器值,TIM4_PWM_Init(u16 arr,u16 psc)函数中arr是自动重装载寄存器周期的值,psc是时钟频率除数的预分频值。
知道了这些我们就可以计算占空比和频率,
占空比:pwm1/arr100%
频率:72M / ((arr+1)
(psc+1))(单位:Hz)这里主频是72MHz
motor.c

#include "motor.h"
#include "stm32f10x.h"
void MOTOR_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  
	
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9;	//两个输出端
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOB, &GPIO_InitStructure);
}

void TIM4_PWM_Init(u16 arr,u16 psc)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB  | RCC_APB2Periph_AFIO, ENABLE);
	
	//GPIO_PinRemapConfig(GPIO_Remap_TIM4, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO
	
	//初始化TIM4
	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

	//初始化TIM4 Channel1 PWM模式	 
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
	
	TIM_OCInitStructure.TIM_Pulse = 0;
	TIM_OC1Init(TIM4, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM4 OC1
	TIM_OCInitStructure.TIM_Pulse = 0;
	TIM_OC2Init(TIM4, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM4 OC2
	TIM_OCInitStructure.TIM_Pulse = 0;
	TIM_OC3Init(TIM4, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM4 OC3
	TIM_OCInitStructure.TIM_Pulse = 0;
	TIM_OC4Init(TIM4, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM4 OC4


	TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);  //使能TIM4在CCR1上的预装载寄存器

	TIM_Cmd(TIM4, ENABLE);  //使能TIM4
	
}
void motor_control(u16 pwm1,u16 pwm2,u16 pwm3,u16 pwm4)
{
	TIM_SetCompare1(TIM4,pwm1);
	TIM_SetCompare2(TIM4,pwm2);
	TIM_SetCompare3(TIM4,pwm3);
	TIM_SetCompare4(TIM4,pwm4);
}

3.主函数
main.c
小车行进时大致有4种情况,两个红外灯都检测到光亮(直走或者超出黑线范围),左光亮右黑线(前方右转),右光亮左黑线(前方左转),都是黑线(这种情况一般不会出现)。通过if else就可以将小车的基本逻辑表示出来,但是注意上面提到两个红外灯都检测到光亮还可能是超出黑线范围,也就是要拐弯时拐不过来,小车冲过了,所以我们还要考虑这种情况。
我们可以设置一个记录上一次拐弯情况的功能,当超出了黑线范围,但是记录了上一刻的转弯情况,让小车继续转弯,这样就可以回到黑线上。

#include "sys.h"
#include<stdio.h>
#include "red.h"
#include "motor.h"
#include "stm32f10x.h"
#include "delay.h"

extern u8 redray1_findblack;
extern u8 redray2_findblack;

int main(void)
{
	u8 stat = 0;
	 REDRAY_Init();//利用红外对管来检测黑线
	 delay_init(72);	    //延时函数初始化	  
		TIM4_PWM_Init(1000-1,720-1);  
	while(1)
	{
		REDRAY_Scan();
		if(redray1_findblack ==1&&redray2_findblack==0)
				{
					stat = 0;
					motor_control(0,0,0,1000);
				}
		else if(redray1_findblack ==0&&redray2_findblack==1)
				{
					stat = 1;
					motor_control(1000,0,0,0);
				}
		else if(redray1_findblack ==1&&redray2_findblack==1)
				{
					if(stat == 0)
				  {
						motor_control(0,0,0,1000);
				  }
					else
					{
						motor_control(1000,0,0,0);
					}
				}
		else 
				{
					motor_control(1000,0,0,1000);
				}
	}
}

另外还有delay函数和sys函数,在网上一搜就能收到,我就不写了。
以上是比较基础的控制逻辑,如果想要更好的控制,可以考虑一下下面这个图在这里插入图片描述
如果能实现小车的每一个状态之间的变换逻辑,那么这个小车就很强大了。

  • 36
    点赞
  • 277
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值