最近学习了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();//右转
}
}
}
}
以上就是我在调试寻迹小车时的程序,和得到的一些注意事项。分享给大家希望对大家有所帮骤。如果有问题希望大家评论区留言我及时改正。