基于STM32单片机的简单红外循迹的实现
此次红外循迹是我在做毕设过程无意中实现的,所有有些地方不够精确完美,还请各位友友们多多指点校正。这篇博客也是小弟第一篇博客,
小弟不才,文笔不怎么行,可能有些语句不太通顺的地方,只能让各位将就一下了。那么接下来就进入正题吧。
一、硬件选择
①首先我们需要一个单片机开发板,在这里我使用的是STM32F103RCT6型号的单片机,这个大家也可以自己买其他的类型;②然后就是电机和电机
驱动模块,市面上的电机有很多种,有带编码器的,也有不带编码器的,由于此次循迹只是简单的巡线操作,所以我用的是不带编码器的直流减速
电机,大部分的小车其实都够用了,而驱动模块选的是L298N模块,这个应该大家还是比较熟悉吧,后续我也会详细介绍的;③然后电源部分的话,
你可以选择分开给驱动模块和单片机单独供电,也可以用一个电源就行了,我在这里用的两节18650的锂电池给驱动模块供电,然后用了一个移动
电源给单片机供电;④循迹模块我用的是红外传感器,这个其实也有很多类型的,有数字信号的,也有模拟信号的,我用的是简单的输出数字信号
的TCRT5000传感器,这个在某宝上也便宜,大家可以根据自己需要自行选择。这差不多就是全部硬件了,后面我会分享给大家如何去实现红外循迹
的具体实现过程。
二、循迹原理介绍
其实红外循迹还是比较简单的,当然这里我指的是我自己实现的功能,本次循迹我只用了两路循迹模块,所以你们在视频中看到的循迹效果可能不是
很稳定,但是至少还是没有出现什么意外,小车成功的在轨道上跑动起来了。红外传感器的工作原理是这样的,它上面有两个管子,一个发射管,用
来向外发射红外线,还有一个接收管,用来接收反射回来的红外线,这个TCRT5000的有效范围好像只有8mm到30mm,根据它的检测距离以及它对不同
颜色的感应程度,就可以判断地面上的轨迹了;如果地面上是黑色,由于红外线会被黑色吸收,导致发出的光不能被反射回来,接收管就收不到信号,
它的数字输出引脚D0就会变为高电平,并且模块上的信号灯也处于熄灭状态,这个时候我们就知道小车已经到黑线上了,就可以让小车转弯;而当地
面上是白色的时候,红外线发出后会被反射回来,接收到反射信号后,模块的数字输出信号就会变为低电平,这个时候模块上的信号灯就会亮起来,
我们就让小车直走就行了。这就是红外循迹的整个原理,还是容易理解的,至于具体接线情况,我在这里就不多啰嗦了,相信大家对单片机和模块的
接线还是可以做到的,下面我们就可以进行程序的编写了。
三、循迹程序介绍
我在这里就直接给你们上循迹的程序吧,里面有注释应该也差不多看得明白,我把电机转动程序也放在下面了,方便有些同学们可以更好的理解。
哦,对了,我用的是STM32库函数版本写的程序,如果有用51单片机或者想用寄存器进行编程的朋友们也可以把相关思路转换一下就行了。
①/***循迹模块初始化程序***/
GPIO_InitTypeDef initstruct; //这是定义一个GPIO的结构体,用于保存循迹模块的引脚信息
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,ENABLE); //开启GPIO的时钟,这一步很关键,可以理解为一个开关
initstruct.GPIO_Pin = GPIO_Pin_0; //这里我用到的是PB0引脚,你们可以对照自己的引脚改一下
initstruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; //一般情况下接收引脚的信号选择浮空输入模式就行了,你们也可以试着用上拉或者下拉模式
GPIO_Init(GPIOB,&initstruct); //这是对刚才你天的信息进行初始化保存的一个函数
initstruct.GPIO_Pin = GPIO_Pin_7; //同理
initstruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; //同理
GPIO_Init(GPIOA,&initstruct); //同理
②/***小车开始循迹的程序***/
#define XJLEFT GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0) //这两个是我在头文件里面的宏定义,其实也可以不用只有写,我只是为了后面方便管理
#define XJRIGHT GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_7)
XJleft = XJLEFT; //这是我定义的两个变量,用来记录循迹模块输出引脚上的电平值
XJright = XJRIGHT;
if((XJleft==0) && (XJright==0)) //这种情况就是小车两个循迹模块都没有检测到黑线,所以我让小车直走
car_go(60);
if((XJleft==0) && (XJright==1)) //这种情况是右边循迹模块感应到黑线,也就是要向右边拐弯了
{
car_right_two(80); //这其实就是一个向右转弯的函数,你们可以根据自己的情况来写
delay_ms(70); //我在这里加一点延时,是因为我之前测试的时候小车有点卡顿的感觉,加点延时就会好一些
if((XJleft==0) && (XJright==0)) //这里再嵌套一个 if 判断,是为了让小车回转过后可以继续向前跑,让它更稳定一点,也是为了防止小车乱晃
car_go(60);
}
if((XJleft==1) && (XJright==0)) //这个情况是左边的循迹模块感应到黑线,也就是要向左边拐弯了
{
car_left_two(80); //后面的其实和上面原理差不多
delay_ms(70);
if((XJleft==0) && (XJright==0))
car_go(60);
}
if((XJleft==1) && (XJright==1)) //这种情况是左右两个循迹模块都感应到黑线,不过这个没有运用到巡线操作中,是我用来把小车拿起来让它停止的
car_stop();
这下面就是小车电机转动的程序了,我就把PWM控制电机速度的部分拿来了,具体的原理就不再介绍了,大家对着程序参考一下应该也能理解,
其实就是一些固定的格式于步骤。
③/***电机PWM初始化程序***/
TIM_TimeBaseInitTypeDef time4initstruct; //这和前面GPIO的一样,也是定义一个结构体,用来保存定时器的信息
TIM_OCInitTypeDef ocinitstruct; //定义一个结构体,用来保存定时器通道的信息
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE); //开启定时器时钟 (其实开启时钟就是一个开关,因为单片机设置了默认把设备关掉来节省电源
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //开启GPIO的时钟 所以如果我们要使用定时器,GPIO端口或者像串口等一些其他的外设的时候
//就要先把这个时钟开关打开,这样设备才能正常工作)
time4initstruct.TIM_Period = 200; //这里可能你们有疑惑,其实这个是设置定时器的重装载值
time4initstruct.TIM_Prescaler = 7200-1; //这里是设置定时器的预分频系数
//以上两个参数联合起来使用,是用来设置定时器的计时周期的,比如重装载值我设置为200,预分频系数我设置为7200,至于为什么
//这里要减一,可以百度搜索一下,我在这就不过多赘述了;由于STM32单片机的时钟频率是72MHz,分频系数为7200,那么分频后,
//时钟频率就是10KHz,那么计时一个数的时间就是10KHz分之1秒,也就是十分之一毫秒,而重装载值我设置的是200,那么整个定时
//的周期就是20ms,整个定时器频率就是50Hz,至于为什么我要设置为50Hz,因为网上说的好像是PWM波控制电机差不多要这个频率
time4initstruct.TIM_CounterMode = TIM_CounterMode_Up; //这里是配置计数模式,有向上模式,向下模式,向上向下模式,这里我选择向上计数
time4initstruct.TIM_ClockDivision = TIM_CKD_DIV1; //这里是设置时钟分频因子,这个参数我没怎么用过,这里设置为不分频就行了
TIM_TimeBaseInit(TIM4,&time4initstruct); //然后把配置好的信息进行初始化保存
ocinitstruct.TIM_OCMode = TIM_OCMode_PWM1; //这里是配置定时器通道的模式,即PWM波产生模式,一般有PWM1、PWM2两种,这里我选择PWM1,两种
//模式具体什么含义可以自行百度搜一下
ocinitstruct.TIM_OCPolarity = TIM_OCPolarity_High; //这是设置通道的有效电平极性,这里设置为高电平有效
ocinitstruct.TIM_OutputState = TIM_OutputState_Enable; //这是一个使能开关,即开启通道使能,让其可以产生PWM波
TIM_OC3Init(TIM4,&ocinitstruct); //把配置好的信息进行初始化保存
TIM_OC4Init(TIM4,&ocinitstruct); //同理
TIM_Cmd(TIM4,ENABLE); //使能定时器,让其开始工作
TIM_OC3PreloadConfig(TIM4,TIM_OCPreload_Enable); //至于这后面的三个函数是开启定时器和通道上的预装载使能位,说白了就是让定时器可以重新加载计时
TIM_OC4PreloadConfig(TIM4,TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM4,ENABLE);
④/***电机速度控制程序***/
这里我只列出一个小车前进的程序,至于小车后退,转弯原理是一样的,大家可以参照根据自己情况进行修改
GPIO_ResetBits(GPIOB,GPIO_Pin_7); //给左边电机一个低电平,左边电机正转 相反,给它高电平就反转
GPIO_ResetBits(GPIOA,GPIO_Pin_4); //给右边电机一个低电平,右边电机正转
TIM_SetCompare3(TIM4,100); //设置左边电机的速度,这里的数值100要与前面定时器那里的重装载值要对应上,速度值为0到200范围内,数值越大,电机转动越快
TIM_SetCompare4(TIM4,100);
好了,以上就是本偏博客的所有内容了,由于本人初次接触STM32,加上第一次写博客没有太多经验,还有不好的地方望各位伙伴们指点校正,
以后我也会将更多的好玩有意义的内容分享给大家的,希望小伙伴们喜欢([表情] ω [表情])
最后小车循迹的视频点击下方链接即可观看:
https://www.bilibili.com/video/BV1h34y1x7AR?spm_id_from=333.999.0.0
基于STM32单片机的简单红外循迹的实现的更多相关文章
- Micropython教程之TPYBoard制作蓝牙+红外循迹小车
1.实验目的 学习在PC机系统中扩展简单I/O接口的方法. 进一步学习编制数据输出程序的设计方法. 学习蓝牙模块的接线方法及其工作原理. 学习L298N电机驱动板模块的接线方法. 学习蓝牙控制小车的工 ...
- 基于STM32单片机光学指纹识别模块(FPM10A)全教程(基于C语言)
本文转载,其来源在参考中:1,稍加修改,因为近期使用到这个模块,故而加以整理! 1.平台 首先我使用的是 奋斗 STM32 开发板 MINI板 基于STM32单片机光学指纹识别模块(FPM10A)全教 ...
- 单片机DIY制作-基于STM32单片机甲醛二氧化碳温度湿度采集系统
基于STM32单片机甲醛二氧化碳温度湿度采集系统 实践制作DIY-GC008-甲醛二氧化碳温度湿度采集系统 一.功能说明: 基于STM32单片机设计-甲醛二氧化碳温度湿度采集系统 二.功能介绍: 1. ...
- 51单片机和STM32单片机区别在那里
大部分朋友可能都知道51单片机和stm32单片机也知道一般入门会先学习51单片机在学习stm32单片机会简单一些,但是对于51单片机和stm32单片机的具体区别却不知道了,有些人觉得没必要,但是我个 ...
- 基于STM32的学习型通用红外遥控设备的设计实现(三)
CPU: STM32 调试平台: STM32F103ZET和STM32F103VBT 软件平台: Keil uVision4 电路设计: Altium Designer v6.9 http://blo ...
- STM32单片机应用与全案例实践 /stm32自学笔记 第二版 pdf
STM32单片机应用与全案例实践pdf https://pan.baidu.com/s/16WrivuLcHvLTwS__Zcwl6Q 4rj3 stm32自学笔记 第二版 pdf https://p ...
- 基于51单片机IIC通信的PCF8591学习笔记
引言 PCF8591 是单电源,低功耗8 位CMOS 数据采集器件,具有4 个模拟输入.一个输出和一个串行I2C 总线接口.3 个地址引脚A0.A1 和A2 用于编程硬件地址,允许将最多8 个器件连接 ...
- 单片机课程设计——《基于AT89S52单片机和DS1302时钟芯片的电子时钟(可蓝牙校准)》
引言 本设计以AT89S52单片机为控制核心,时钟芯片DS1302提供时钟源,配合LCD1602液晶显示模块,组成基本硬件系统,同时利用HC-05嵌入式蓝牙串口通讯模块,可在手机端进行日期.时间的校准 ...
- 关于STM32单片机的IAP实现
基于STM32F103单片机的IAP实现(虽然该篇文章不会详细写出实现细节,但是会从一个全局的角度讲述,实际的实现细节只需根据datasheet即可完成). 一.基础概念 什么是IAP?IAP即在应用 ...
随机推荐
- 用 EXISTS 或 NOT EXISTS 用法
项目中遇到这么个情况: t1表 和 t2表 都是150w条数据,600M的样子,都不算大. 但是这样一句查询 ↓ select * from t1 where phone not in (selec ...
- IIS 虚拟目录 VS 站点
1.虚拟目录是站点的一个子目录,虚拟目录是建立在站点下面的. 2.一个站点下面,可以建立多个虚拟目录.各个虚拟目录都是以虚拟目录名称来进行区分. 3.新建的独立站点就和IIS中的默认站点一样,各个站点 ...
- 报错 ——Error evaluating expression 'id != null id > 0'.
Exception in thread "main" org.apache.ibatis.exceptions.PersistenceException: ### Error qu ...
- Vtune工具简介
VTune是 Intel 提供的一个强大的应用程序性能分析软件,VTune Amplifier XE 2011 集成了Intel VTune Performance Analyzer 和 Thread ...
- go语言学习入门篇 2--轻量级线程的实现
很多有过 JVM 相关语言工作经验的程序员或许都遇到过如下问题: 超出 thread 限制导致内存溢出.在作者的笔记本的 linux 上运行,这种情况一般发生在创建了 11500 个左右的 threa ...
- Linux C申请内存三种基本方式
一份代码可以知道具体方式和原理: int main() { int stack_a; int stack_b; static int static_c; static int static_d; in ...
- url斜杠问题——重定向
path('hello',hello), path('hello/',hello), 有什么区别? 没有斜杠:只能访问hello 有斜杠:可以访问hello和hello/ 分析有斜杠的: hello- ...
- 数据库篇:mysql日志类型之 redo、undo、binlog
前言 可以说mysql的多数特性都是围绕日志文件实现,而其中最重要的有以下三种 redo 日志 undo 日志 binlog 日志 关注公众号,一起交流:微信搜一搜: 潜行前行 1 redo日志 in ...
- Shiro Session放到Redis中常遇到的问题
Shiro会话管理:https://shiro.apache.org/session-management.html#SessionManagement-CustomSessionIDs Redis主 ...
- mq 的缺点 ?
系统可用性降低 系统引入的外部依赖越多,越容易挂掉,本来你就是 A 系统调用 BCD 三个系统的 接口就好了,人 ABCD 四个系统好好的,没啥问题,你偏加个 MQ 进来,万一 MQ 挂了咋整?MQ ...