基于STM32F103C8T6的智能红外循迹避障小车

一,硬件原理图设计

二,代码实现

1.电机

        编程思路:控制核心板IO口的电平(即电机驱动模块的AIN1,AIN2,BIN1,BIN2)从而控制AO1、AO2、BO1、BO2的电平高低,进而控制电机使其正转、反转、不转。由于单纯地拉高拉低电平只能让电机在转与不转的状态切换,故决定利用TIM4的两个通道分别产生两路PWM信号来控制电机速度,四个电机两个一组,同一侧的两个连接在同一个PWM上。(#include "dianji.h"文件中同时写了对循迹模块引脚的初始化)

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

#define IN1 PCin(13)
#define IN2 PCin(14)
#define IN3 PCin(15)
#define IN4 PBin(12)

void GPIO_XUJI_Init(void);
void Motor_Init(void);
void PWM_Init(void);
void PWM_SetCompare(int16_t Compare);
void Motor_SetSpeed1(float Speed);
void Motor_SetSpeed2(float Speed);

#endif
#include "dianji.h"

//循迹模块引脚初始化
void GPIO_XUJI_Init(void){
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14| GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOC, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
}

//电机引脚初始化
void Motor_Init(void)
{
	//电机正反转引脚配置
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9| GPIO_Pin_5| GPIO_Pin_4;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	PWM_Init();
}

//PWM初始化
void PWM_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);	//开启定时器2的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);		//开启GPIO时钟
	
	
	/**********   PWM引脚的GPIO配置   **********/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;				//对定时器GPIO设置为复用推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7|GPIO_Pin_6;							
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	TIM_InternalClockConfig(TIM4);
	
	
	//TIM4配置
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;		//TIM4配置
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
	TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;		//自动重装载值    ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = 36 - 1;		//设置预分频值  PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseInitStructure);
	//C8T6的主频为72MHZ,设置的PWM频率为 72M/((ARR+1)*(PSC+1))=72M/(100*36)=20KHZ
	
	
	//TIM4的通道1配置
	TIM_OCInitTypeDef TIM_OCInitStructure;		
	//TIM_OCStructInit(&TIM_OCInitStructure);
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//PWM1模式
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;	//设置极性为高
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;	//比较输出使能
	TIM_OCInitStructure.TIM_Pulse = 0;		//CCR
	TIM_OC1Init(TIM4, &TIM_OCInitStructure);
	TIM_OC1PreloadConfig(TIM4,TIM_OCPreload_Enable);//使能预装载寄存器
		//TIM4的通道2配置
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//PWM1模式
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;	//设置极性为高
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;	//比较输出使能
	TIM_OCInitStructure.TIM_Pulse = 0;		//CCR
	TIM_OC2Init(TIM4, &TIM_OCInitStructure);
	TIM_OC2PreloadConfig(TIM4,TIM_OCPreload_Enable);//使能预装载寄存器
	TIM_Cmd(TIM4, ENABLE);		//使能TIM4
}

//设置占空比
void PWM_SetCompare(int16_t Compare)
{
	TIM_SetCompare2(TIM4, Compare);
	TIM_SetCompare1(TIM4, Compare);
}




void Motor_SetSpeed1(float Speed)   //设置电机1 2 转速,有符号量,正反转
{
	if (Speed <0)
	{
		GPIO_SetBits(GPIOB, GPIO_Pin_8);
		GPIO_ResetBits(GPIOB, GPIO_Pin_9);//反转
		PWM_SetCompare(-Speed);       
	}
	else if(Speed>0)
	{
		GPIO_ResetBits(GPIOB, GPIO_Pin_8);
		GPIO_SetBits(GPIOB, GPIO_Pin_9);//正转
		PWM_SetCompare(Speed);      
	}
	else if(Speed == 0)
	{
		GPIO_SetBits(GPIOB, GPIO_Pin_8);
		GPIO_SetBits(GPIOB, GPIO_Pin_9);//停止
		PWM_SetCompare(100);      
	}
}

void Motor_SetSpeed2(float Speed)   //设置电机3 4 转速,有符号量,正反转
{
	if (Speed<0)
	{
		GPIO_SetBits(GPIOB, GPIO_Pin_5);
		GPIO_ResetBits(GPIOB, GPIO_Pin_4);//反转
		PWM_SetCompare(-Speed);       
	}
	else if(Speed >0)
	{
		GPIO_ResetBits(GPIOB, GPIO_Pin_5);
		GPIO_SetBits(GPIOB, GPIO_Pin_4);//正转
		PWM_SetCompare(Speed);      
	}
	else if(Speed == 0)
	{
		GPIO_SetBits(GPIOB, GPIO_Pin_5);
		GPIO_SetBits(GPIOB, GPIO_Pin_4);//停止
		PWM_SetCompare(100);     
	}
}

2.红外循迹

        编程思路:检测到黑线时红外模块将会返回低电平,否则返回高电平。
故只需要读取对应的IO端口电平用以控制小车转向从而实现巡线。(我使用的是四路循迹,中间两路用来检测黑线,两边的两路用来检测非黑线)

循迹逻辑:(黑色路线宽度为:大于P2到P3之间距离,小于P1到P4之间距离) 

case1:P2,P3检测到黑线,P1,P4未检测到黑线时,所有电机都正转

case2:P1,P2,P3检测到黑线,P4未检测到黑线时;或者P1,P2检测到黑线,P3,P4未检测 到黑线时;或者P1检测到黑线,P2,P3,P4未检测时;或者P2检测到黑线,P1,P3,P4未检测时到黑线时;以上四种情况皆为 P4侧电机正转,P1侧电机反转,使车身向P1侧转向。

case3:P2,P3,P4检测到黑线,P1未检测到黑线时;或者P3,P4检测到黑线,P1,P2未检测 到黑线时;或者P4检测到黑线,P1,P2,P3未检测时;或者P3检测到黑线,P1,P2,P4未检测时到黑线时;以上四种情况皆为 P4侧电机反转,P1侧电机正转,使车身向P4侧转向。

case4:其他所有情况,皆为所有电机都停止(包括P1,P2,P3,P4都检测到黑线的情况,由于自然光的原因,在车轮未放在地上时, P1,P2,P3,P4都会检测到自然光中黑线,故该情况下所有电机也都停止)

if((!IN1)&&(!IN3)&&IN2&&IN4){
				Motor_SetSpeed1(35);
				Motor_SetSpeed2(35);
			}
		else if(((!IN1)&&(!IN3)&&(!IN4)&&(IN2)) || ((!IN3)&&(!IN4)&&(IN1)&&(IN2))||((!IN3)&&(IN1)&&(IN2)&&(IN4)) || ((!IN4)&&(IN1)&&(IN3)&&(IN2))){
		    Motor_SetSpeed1(30);	
		    Motor_SetSpeed2(-30);//右转
			}
		else if(((!IN1)&&(!IN3)&&(!IN2)&&(IN4)) || ((!IN1)&&(IN3)&&(!IN2)&&(IN4))||((!IN1)&&(IN3)&&(IN2)&&(IN4)) || ((IN1)&&(IN3)&&(!IN2)&&(IN4))){
				Motor_SetSpeed1(-30);
				Motor_SetSpeed2(30);//左转
		}
		else{
				Motor_SetSpeed1(0);
				Motor_SetSpeed2(0);
		}

3.避障

        编程思路:红外避障模块检测到障碍时,会返回一个低电平。通过判断IO口的电平继而控制蜂鸣器。

#ifndef _BEEP_H
#define _BEEP_H
#include "sys.h"
void Beep_Init(void);

#endif
#include "beep.h"
void Beep_Init(void){
  //GPIO 避障端口设置
  GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_6; 
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;	
  GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	//GPIO 蜂鸣器端口设置
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; 
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	
  GPIO_Init(GPIOA, &GPIO_InitStructure);
	PAout (0)=1;
}
if(PAin(4)==0||PAin(6)==0)
			PAout (0)=0;
		else
			PAout (0)=1;

4.main函数

#include "stm32f10x.h" 
#include "usart.h"
#include "delay.h"
#include "dianji.h"
#include "beep.h"

int main(void) 
{ 
	delay_init();
	uart_init(9600);
	Beep_Init();
	GPIO_XUJI_Init();
  Motor_Init();
	while(1) 
	{	
		if(PAin(4)==0||PAin(6)==0)
			PAout (0)=0;
		else
			PAout (0)=1;
		
		
		if((!IN1)&&(!IN3)&&IN2&&IN4){
				Motor_SetSpeed1(35);
				Motor_SetSpeed2(35);
			}
		else if(((!IN1)&&(!IN3)&&(!IN4)&&(IN2)) || ((!IN3)&&(!IN4)&&(IN1)&&(IN2))||((!IN3)&&(IN1)&&(IN2)&&(IN4)) || ((!IN4)&&(IN1)&&(IN3)&&(IN2))){
		    Motor_SetSpeed1(30);	
		    Motor_SetSpeed2(-30);//右转
			}
		else if(((!IN1)&&(!IN3)&&(!IN2)&&(IN4)) || ((!IN1)&&(IN3)&&(!IN2)&&(IN4))||((!IN1)&&(IN3)&&(IN2)&&(IN4)) || ((IN1)&&(IN3)&&(!IN2)&&(IN4))){
				Motor_SetSpeed1(-30);
				Motor_SetSpeed2(30);//左转
		}
		else{
				Motor_SetSpeed1(0);
				Motor_SetSpeed2(0);
		}
	}	
}

三,TB6612FNG 驱动模块

        TB6612FNG 模块相对于传统的 L298N 效率上提高很多,体积上也大幅度减少,在额定范围内,芯片基本不发热,当然也就显得更加娇贵,所以我们建议有一定动手能力的朋友使用,接线的时候务必 细心细心再细心,注意正负极性。

1.TB6612 的的用法:

TB6612 是双驱动,也就是可以驱动两个电机

下面分别是控制两个电机的 IO 口

STBY 口接单片机的 IO 口清零电机全部停止,置 1 通过 AIN1 AIN2,BIN1,BIN2 来控

制正反转

VM 接 12V 以内电源

VCC 接 5V 电源

GND 接电源负极

驱动 1 路

PWMA 接单片机的 PWM 口

真值表:

AIN1    0       0         1

AIN2    0       1         0

          停止  正传   反转

A01

AO2 接电机 1 的两个脚驱动 2 路

PWMB 接单片机的 PWM 口

真值表:

BIN1    0        0       1

BIN2    0        1       0

          停止   正传   反转

B01

B02 接电机 2 的两个脚驱动 2 路

2.逻辑真值表

3.占空比

PWM 占空比大小的改变通过对输出比较寄存器 TIMx_
CCR 以及自动重装载寄存器TIMx_ARR
的数值操作来实现,例如当 CCR=203 ,ARR=255 时,占空比为 204/256=80%。编程时将速度变量值写入 CCR寄存器,从而达到改变占空比和对电机调速的目的。

3) 运行性能和建议

1.器件输出状
态在驱动/制动之间切换时,电机转速和 PWM 占空比之

间能保持较好的线性关系,其运行控制效果好于器件在驱动/停止状态之间

切换,所以表 1 中的 INl/IN2 一般不采用 L/L 控制组合。

2.fPWM 较高时,电机运行连续平稳、噪音小,但器件功耗会随频率升

高而增大;fPWM 较低时,利于降低功耗,并能提高调速线性度,但过低的

频率可能导致电机转动连贯性的降低。通常 fPWM>1 kHz 时,器件能够稳定

的控制电机。

3.过大的 PWM 占空比会影响电机驱动电流的稳定性和器件的输出负载

能力,应根据不同的速度要求合理设定占空比范围。

4.器件工作温度过高会导致其输出功率的下降,电路 PCB 设计中应保

证足够面积的覆铜,这样有助于散热,利于器件长时间稳定工作

四,结果演示

循迹避障小车

作者:Mr,Right

物联沃分享整理
物联沃-IOTWORD物联网 » 基于STM32F103C8T6的智能红外循迹避障小车

发表评论