红外循迹——开环(俗称:死程序)

目录

一、前言

二、代码

三、总结


一、前言

学习的过程是先易后难的,所以我先为大家讲解普通的死程序去循迹,后面再讲PID控制的循迹。好了,废话少说,直接来程序思路。

首先,我们要知道,让小车向前跑,但是黑线是弯的,这个时候就需要去转向,比如黑线在小车的左侧,我们需要左边加一个传感器,检测到左边的黑线,传给小车一个信号,让小车左转,顺着黑线走;同理黑线在右边,我们用上述一样的方法;所以总结一下,给小车多加几个传感器,反馈黑线位置,让小车知道怎么转。

具体的要结合程序,大家就一目了然了,在这里先跟大家说几个点:

1,注意别买错红外传感器,本人上过太多的当了,希望大家别和我一样,少花一些冤枉钱,最重要的是少浪费一些时间。

如果大家是买单个的,不要买这类这个模块完全没用,就买这个样子的好一点,但是这种单个的红外传感器,检测效果差,而且只能识别黑线,不同的环境,检测效果不一样,要自己去调灵敏度,相当的麻烦,如果有小伙伴是应付一下期末检测,那这个也勉勉强强。

2,如果大家是买多路的合在一起的那种,我不建议大家去买这类

 虽然很便宜只要10块左右,但是一点用都没有,完全没有效果,还不如用单个的呢,如果大家是做着玩玩,就可以买亚博的,但是大家要注意,亚博的传感器,他的位置跟普通的多路传感器的位置不一样,而且市面上大部分你买到的红外传感器,检测到黑线都是给高电平,而亚博是给低电平,这一点是值得注意的。

如果是要搞竞赛的小伙伴们,就用这种灰度传感器,灵敏度自调,且不仅检测黑线,还检测红线。

 3,大家注意在定义管脚的时候,有些管脚是不能直接用的,需要修改部分程序。就比如STM32F103C8T6的PC3大家查了就知道它是电源指示灯的管脚。

4,循迹模块的路数越多,越准越稳。

二、代码

xunji.h

#ifndef __XUNJI_H
#define	__XUNJI_H

//这里的xunji_x就是代表读取到相应管脚的高低电平

#define xunji_1 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_12)
#define xunji_2 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_13)
#define xunji_3 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14)
#define xunji_4 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_15)

void xunji_config(void);
void Read_xunji_Date(void);  //读循迹模块返回的值

#endif

xunji.c

#include "stm32f10x.h"                  // Device header
#include "xunji.h"

	#include "Motor.h"
	
void xunji_config(void)	
{
  GPIO_InitTypeDef GPIO_InitStructure;	
  RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE); // 使能PC端口时钟
	
  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_12 | GPIO_Pin_13  | GPIO_Pin_14 | GPIO_Pin_15;	//选择对应的引脚
  GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IPU ;//配置GPIO模式,输入上拉,这里是检测的作用,所以用上拉输入    
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOB, &GPIO_InitStructure);  //初始化PC端口
}

void Read_xunji_Date(void)
{
 xunji_1;
 xunji_2;
 xunji_3;
 xunji_4;
	//红外检测到黑线,令xunji_x=1,意思就是红外检测到黑线发送高电平
		 if(xunji_1==0&&xunji_2==0&&xunji_3==0&&xunji_4==0)//没有检测到黑线
	  {
	CarGo();//小车直行  
	
	  }
		  if(xunji_1==1&&xunji_2==0&&xunji_3==0&&xunji_4==0)//最左边检测到黑线
	  {
	 CarBigRight();	  //左转大

	  }

		if(xunji_1==0&&xunji_2==0&&xunji_3==0&&xunji_4==1)//最右边检测到黑线
	  {
	 CarBigLeft(); //右转大

	  }
	 if(xunji_1==0&&xunji_2==1&&xunji_3==0&&xunji_4==0)//依次类推,不过多赘述
	  {
	CarGo();//小车直行		  
	
	  }
			 if(xunji_1==0&&xunji_2==1&&xunji_3==1&&xunji_4==0)
	  {
	CarGo();//小车直行		  
	
	  }
			 if(xunji_1==0&&xunji_2==0&&xunji_3==1&&xunji_4==0)
	  {
	CarGo();//小车直行		  
	
	  }
		 if(xunji_1==1&&xunji_2==1&&xunji_3==0&&xunji_4==0)
	  {
	 CarRight();	  //左转小

	  }
		 if(xunji_1==0&&xunji_2==0&&xunji_3==1&&xunji_4==1)
	  {
	 CarLeft();	  //右转小

	  }
		
		
		
}

pwm.c

#include "stm32f10x.h"                  // Device header
//这里设置的ARR,PSC就是让PWM最大为100,更直观,方便的使用
void PWM_Init(void)
	
{
	//	用结构体初始化输出比较单元,不同函数不同的GPIO(A0)
	
		//RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//开启AFIO的时钟
	//GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE);//部分重映射
//	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//关闭调试端口的复用
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	GPIO_InitTypeDef GPIO_Initstructure;
	GPIO_Initstructure.GPIO_Mode= GPIO_Mode_AF_PP;//复用推挽输出
	GPIO_Initstructure.GPIO_Pin= GPIO_Pin_2;
	GPIO_Initstructure.GPIO_Speed= GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_Initstructure);
	
	

	GPIO_Initstructure.GPIO_Mode= GPIO_Mode_AF_PP;//复用推挽输出
	GPIO_Initstructure.GPIO_Pin= GPIO_Pin_1;
	GPIO_Initstructure.GPIO_Speed= GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_Initstructure);

	
	TIM_InternalClockConfig(TIM2);
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	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=720 - 1;//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
	
	
	
	TIM_OCInitTypeDef TIM_OCInitStructure;//结构体变量需要赋值
	TIM_OCStructInit(&TIM_OCInitStructure);//结构体赋初始值的函数
	TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//输出比较模式

	TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//输出比较的极性

	TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//输出比较的使能

	TIM_OCInitStructure.TIM_Pulse =0;//设置CCR的
	
	TIM_OC3Init(TIM2,&TIM_OCInitStructure);//注意函数区别
	TIM_OC3PreloadConfig(TIM2 , TIM_OCPreload_Enable);
	TIM_OC2Init(TIM2,&TIM_OCInitStructure);
	TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);

	TIM_Cmd(TIM2,ENABLE);
}
void PWM_SetCompare3(uint16_t Compare3)
	
{
	TIM_SetCompare3(TIM2,Compare3);
	
}
void PWM_SetCompare2(uint16_t Compare2)
	
{
	TIM_SetCompare2(TIM2,Compare2);
	
}


Motor.c

#include "stm32f10x.h"                  // Device header

#include "PWM.h"
void Motor_Init(void)//定义要使用的管脚
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	GPIO_InitTypeDef GPIO_Initstructure;
	GPIO_Initstructure.GPIO_Mode= GPIO_Mode_Out_PP;
	GPIO_Initstructure.GPIO_Pin= GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
	GPIO_Initstructure.GPIO_Speed= GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_Initstructure);
	GPIO_SetBits(GPIOA,GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);
	
	
	PWM_Init();
}

//如果你们想让小车倒着走,只需要将GPIO_SetBits与	GPIO_ResetBits交换一下就可以了

void CarGo(void)//小车直行函数
{
   
  TIM_SetCompare2(TIM2 , 60);//数值越小速度越慢
  TIM_SetCompare3(TIM2 , 60);  
	GPIO_SetBits(GPIOA, GPIO_Pin_4);
		GPIO_ResetBits(GPIOA, GPIO_Pin_5);
	GPIO_SetBits(GPIOA, GPIO_Pin_6);
		GPIO_ResetBits(GPIOA, GPIO_Pin_7);
}

void CarBigLeft(void)//小车右转大函数
{
  TIM_SetCompare2(TIM2 ,0);
  TIM_SetCompare3(TIM2, 60);
GPIO_SetBits(GPIOA, GPIO_Pin_4);
		GPIO_ResetBits(GPIOA, GPIO_Pin_5);
	GPIO_SetBits(GPIOA, GPIO_Pin_6);
		GPIO_ResetBits(GPIOA, GPIO_Pin_7);
}

void CarBigRight(void)//小车左转大函数
{
  
  TIM_SetCompare2(TIM2, 60);
  TIM_SetCompare3(TIM2 , 0);
GPIO_SetBits(GPIOA, GPIO_Pin_4);
		GPIO_ResetBits(GPIOA, GPIO_Pin_5);
	GPIO_SetBits(GPIOA, GPIO_Pin_6);
		GPIO_ResetBits(GPIOA, GPIO_Pin_7);
  
}
void CarLeft(void)//小车右转小函数
{
  TIM_SetCompare2(TIM2 , 40);
  TIM_SetCompare3(TIM2, 60);
GPIO_SetBits(GPIOA, GPIO_Pin_4);
		GPIO_ResetBits(GPIOA, GPIO_Pin_5);
	GPIO_SetBits(GPIOA, GPIO_Pin_6);
		GPIO_ResetBits(GPIOA, GPIO_Pin_7);
}

void CarRight(void)//小车左转小函数
{
  
  TIM_SetCompare2(TIM2, 60);
  TIM_SetCompare3(TIM2 , 40);
GPIO_SetBits(GPIOA, GPIO_Pin_4);
		GPIO_ResetBits(GPIOA, GPIO_Pin_5);
	GPIO_SetBits(GPIOA, GPIO_Pin_6);
		GPIO_ResetBits(GPIOA, GPIO_Pin_7);
  
}

main.c

//提高PWM的频率,让电机在堵转的时候无声,人耳听到的频率在20Hz-20kHz
#include "stm32f10x.h"                  // Device header

#include "Delay.h"
#include "OLED.h"
#include "Motor.h"
#include "xunji.h"

int main(void)
{
	
	
SystemInit();	//开启系统时钟
	xunji_config();//循迹管脚的初始化

	OLED_Init();
	Motor_Init();

	
	while (1)
	{
	
		Read_xunji_Date(); //读循迹线值
	  
	  //车前4个循迹模块从左到右分别是xunji_1,xunji_2,xunji_3,xunji_4
   

	}
	
}

三、总结

说实话,我当时就是自己一个人慢慢摸索,网上查资料,当时觉得好难啊,确确实实很累,没有人指导自己,但是我不断地坚持学习,我克服了许多困难,现在我觉得这个循迹再简单不过,虽然我谈不上有什么多大的进步,但是我一直在成长,看着自己比昨天更厉害,这种感觉真的很好,相信大家也会学有所成!

其实,我还发现一个小BUG,就是有时候电脑没办法打开百度网盘的链接,但是手机可以,这就很神奇。

链接:https://pan.baidu.com/s/1JxuH_H6eXbQ0hxsRKBB83g?pwd=yl66 
提取码:yl66

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

暖风醉思人

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

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

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

打赏作者

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

抵扣说明:

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

余额充值