STM32红外寻迹小车(寄存器版)

最近学习了STM32,想通过制作一辆小车来加深对STM32的理解,在平时学习时经常用正点原子提供的源代码稍加该装就行,但是正点原子没有提供关于红外寻迹模板的相关程序。尽管网上很多关于STM32的红外寻迹的资料和源代码,但是几乎没有寄存器版本的源代码。有些博主有寄存器版的程序源码但是得花钱才能下载。那么今天我就分享一下制作寻迹小车的经验和程序源码。
一、红外寻迹小车原理
循迹模块我用的是红外传感器。黑线的检测原理是红外发射管发射光线到路面,红外光遇到白底则被反射,接收管接收到反射光,经施密特触发器整形后输出低电平;当红外光遇到黑线时则被吸收,接收管没有接收到反射光,经施密特触发器整形后输出高电平。简单的说就是当红外寻迹模板遇见黑线时会产生一个高电平,遇见白线时会返回一个低电平。所以根据原理设计思路为当左侧红外传感器遇见黑线时左拐,右边红外传感器遇见黑线时右拐。这样就可以完成

寻迹

黑线寻迹

白线寻迹

原理

左侧红外传感器遇见黑线时左拐,右边红外传感器遇见黑线时右拐。

当左侧红外传感器遇见黑线时右拐,右侧红外传感器遇见黑线时左拐。

二、寻迹小车设计注意事项
(1)因为硬件条件有限,反应速度不是很快会有一定的误差,所以小车的速度要尽量慢下来,从而弥补硬件的不足让小车有足够的反应时间。
(2)在设置两个红外传感器的IO口模式时要设置为浮空输入,这样才能通过程序读取IO口的状态来判断。
(3)在测试小车时尽量在光线较暗的条件下来测试小车,避免光线过亮影响测试。
(4)红外寻迹模块的OUT不能接在有上拉电阻的IO口
三、寻迹小车程序
1.新建工程在工程文件下新建MOTER、TIMER、XUNJI这3个文件夹,然后在各自文件夹下建立相关文件小写的.c和.h文件。
2.timer.c的程序如下:

#include "timer.h"
void TIM3_Int_Init(u16 arr,u16 psc)//初识化定时器3
{
	RCC->APB1ENR|=1<<1;	//TIM3时钟使能    
 	TIM3->ARR=arr;  	//设定计数器自动重装值//刚好1ms    
	TIM3->PSC=psc;  	//预分频器7200,得到10Khz的计数时钟		  
	TIM3->DIER|=1<<0;   //允许更新中断	  
	TIM3->CR1|=0x01;    //使能定时器3
 	 MY_NVIC_Init(1,3,TIM3_IRQn,2);//抢占1,子优先级3,组2									 
}
void TIM3_PWM_Init(u16 arr,u16 psc)
{		 					 
	//此部分需手动修改IO口设置
	RCC->APB1ENR|=1<<1; 		//TIM3时钟使能    
	RCC->APB2ENR|=1<<3;    	//使能PORTB时钟	
	RCC->APB2ENR|=1<<2; 		//使能PORTA时钟
	GPIOB->CRL&=0XFFFFFFF0;	//PB0输出
	GPIOB->CRL|=0X0000000B;	//复用功能输出 
	GPIOA->CRL&=0XF0FFFFFF;	//PA6输出
	GPIOA->CRL|=0X0B000000; //复用输出

	TIM3->ARR=arr;			//设定计数器自动重装值 
	TIM3->PSC=psc;			//预分频器不分频
	
	TIM3->CCMR1|=6<<4;  	//CH1 PWM2模式		 
	TIM3->CCMR1|=1<<3; 		//CH1预装载使能	
	TIM3->CCMR2|=6<<4;		//CH3预装载使能 
	TIM3->CCMR2|=1<<3;    //CH3输出使能
	TIM3->CCER|=1<<0;   	//OC1 输出使能	 
	TIM3->CCER|=1<<8; 
	TIM3->CR1=0x0080;   	//ARPE使能 
	TIM3->CR1|=0x01;    	//使能定时器3 	

	STBY=1;
}

timer.h代码如下:

#ifndef __TIMER_H
#define __TIMER_H
#include "sys.h"
#define left TIM3->CCR1 
#define right TIM3->CCR3

void TIM3_Int_Init(u16 arr,u16 psc);
void TIM3_PWM_Init(u16 arr,u16 psc);
#endif

moter.c代码如下:

RCC->APB2ENR|=1<<2;         //使能PORTA时钟
	RCC->APB2ENR|=1<<3;		 //使能PORTB时钟
	RCC->APB2ENR|=1<<4; 		//使能PORTC时钟
	
	GPIOA->CRL&=0XFF0FFFFF;
  	GPIOA->CRL|=0X00300000;
    GPIOA->ODR|=1<<5;      
	
	GPIOA->CRL&=0X0FFFFFFF;
    GPIOA->CRL|=0X30000000;
	GPIOA->ODR|=1<<7; 
	
	GPIOB->CRL&=0XFFFFFF0F;
    GPIOB->CRL|=0X00000030;
	GPIOB->ODR|=1<<1;
	
	GPIOB->CRL&=0XFFFFF0FF;
    GPIOB->CRL|=0X00000300;
	GPIOB->ODR|=1<<2;
	GPIOB->CRL&=0XFFFF0FFF;
    GPIOB->CRL|=0X00003000;
	GPIOB->ODR|=1<<3;
	GPIOB->CRL&=0XFFF0FFFF;
    GPIOB->CRL|=0X00030000;
	GPIOB->ODR|=1<<4; 	
	
	GPIOC->CRL&=0XFFF0FFFF;
    GPIOC->CRL|=0X00030000;
	GPIOC->ODR|=1<<4; 	
	
	GPIOC->CRL&=0XFF0FFFFF;
    GPIOC->CRL|=0X00300000;
	GPIOC->ODR|=1<<5;

moter.h代码如下:

#ifndef __MOTER_H
#define __MOTER_H	 
#include "sys.h"
//电机端口定义(PWMA  PB0  PWMB  PA6)  
#define AIN2 PBout(1)
#define AIN1 PBout(2)
#define STBY PBout(3)
#define BIN2 PCout(5)
#define BIN1 PCout(4)
void MOTER_Init(void);	//初始化		 				    
#endif

xunji.c代码如下:

#include "xunji.h"
void XUNji_init(void)
{
	RCC->APB2ENR|=1<<4; 		//使能PORTC时钟
	GPIOC->CRL&=0XF0FFFFFF;
  	GPIOC->CRL|=0X08000000;//PC6浮空输入
  	GPIOC->CRL&=0X0FFFFFFF;
  	GPIOC->CRL|=0X80000000;//PC7浮空输入
}

xunji.h代码如下

#ifndef __XUNJI_H
#define __XUNJI_H	 
#include "sys.h"
#define left_led PCin(6)
#define right_led PCin(7)
void XUN_Init(void);	//初始化		 				    
#endif

这段代码中很容易犯错误为#define left_led PCout(6) #define right_led PCout(7)
因为我们要读取IO口的状态所以不能用out必须用in写成#define left_led PCin(6)和#define right_led PCin(7)
test.c代码如下:

#include "sys.h"
#include "delay.h"
#include "usart.h" 
#include "moter.h" 
#include "timer.h" 
#include "xunji.h"
void HOU(void)//定义后退函数
{
	AIN1=0;
	AIN2=1;
	BIN1=0;
	BIN2=1;
}

void STOP(void)//停
{
	AIN1=0;
	AIN2=0;
	BIN1=1;
	BIN2=1;
}

void YOU(void)//右拐
{
	AIN1=1;
	AIN2=0;
	BIN1=1;
	BIN2=1;
}

void ZUO(void)//左拐
{
	AIN1=0;
	AIN2=0;
	BIN1=1;
	BIN2=0;
}

void GO(void)//前进
{
	AIN1=1;
	AIN2=0;
	BIN1=1;
	BIN2=0;
}

int main(void)
{					   
	Stm32_Clock_Init(9);	//系统时钟设置
	uart_init(72,115200);	//串口初始化为115200
	delay_init(72);	   	 	//延时初始化 
  	TIM3_PWM_Init(899,0);	//不分频。PWM频率=72000/(899+1)=80Khz
	MOTER_Init();
	void XUN_Init();
	left=400;
	right=400;
  	while(1)
	{
		if(left_led == 1 && right_led == 1)//左右寻迹探头识别到黑线
		{
			GO();//前进
		}
		else
		{
			if(left_led == 1 && right_led == 0)//小车右边出线,左转修正
			{
				ZUO();//左转
			}
			if(left_led == 0 && right_led == 1)//小车左边出线,右转修正
			{
				YOU();//右转
			}		
		}		
	}
}

以上就是我在调试寻迹小车时的程序,和得到的一些注意事项。分享给大家希望对大家有所帮骤。如果有问题希望大家评论区留言我及时改正。