STM32灭火小车控制系统(来自LLC团队)

STM32灭火小车控制系统(来自LLC团队)

蓝牙、五路火焰传感器,STM32单片机,四路循迹巡线模块

第1章 绪论

1.1、 灭火小车控制系统的设计背景和意义

火灾在现实生活中是非常普遍的,它被称为三大自然灾害之一。消防人员时时刻刻冲到第一线,面临生命危险,在这种背景下,智能寻迹灭火系统应运而生,实现了对安全防护的质的提高,也大大地减低了消防人员的危险。在智能灭火系统中应用单片机来代替人的思考,还可以实现自动化控制,简化了灭火的工作流程,使单片机代替多余的消防人员,节省了国家不必要的支出,减低了危险。 随着社会与国家的发展,在经济迅速增长的同时,各种危险场所不可避免的火灾频繁出现,给社会安全造成了很多隐患,于是现代火灾及时补救已成为迫在眉睫需要解决的问题,救火早一刻就少一分损失,消防救援人员固然速度已经很快,但也需要一段不小的时间,而且进入救火现场还有生命危险的可能,于是消防机器小车的理念诞生了。

灭火小车控制系统的研究除了在科学研究方面具有深远的意义,它也是一个很好的教学平台。通过它可以使学生将理论与实践紧密地结合起来,提高学生的动手能力、创造能力、协作能力和综合能力。目前国家所提倡的素质教育中,能力培养是核心。灭火小车提供了一个对学生的能力进行培养的大舞台。对推动高校的科技创新和产学研一体化产生了积极作用,也为提高我国在智能机器领域的国际地位做出了积极贡献。

1.2、 国内国际研究现状

我国的机器人研究开发工作始于 20 世纪 70 年代初,到现在已经历了 30 年的历程。前 10 年处于研究单位自行开展研究工作状态,发展比较缓慢。 1985 年后开始列入国家有关计划,发展比较快。在机器人基础技术方面:诸如机器人机构的运动学、动力学分析与综合研究,机器人运动的控制算法及机器人编程语言的研究,机器人内外部传感器的研究与开发,具有多传感器控制系统的研究,离线编程技术、遥控机器人的控制技术等均取得长足进展,并在实际工作中得到应用。

在机器人的单元技术和基础元部件的研究开发方面:诸如交直流伺服电机及其驱动系统、测速发电机、光电编码器、液压(气动)元部件、滚珠丝杠、直线滚动导轨、谐波减速器、 RV 减速器、十字交叉滚子轴承、薄壁轴承等均开发出一些样机或产品。但这些元部件距批量化生产还有一段距离。我国近几年机器人自动化生产线已经不断出现,并给用户带来显著效益。随着我国工业企业自动化水平的不断提高,机器人自动化线的市场也会越来越大,并且逐渐成为自动化生产线的主要方式。我国机器人自动化生产线装备的市场刚刚起步,而国内装备制造业正处于由传统装备向先进制造装备转型的时期,这就给机器人自动化生产线研究开发者带来巨大商机。据预测,目前我国仅汽车行业、电子和家电行业、烟草行业、新能源电池行业等,年需求此类自动化线就达 300 多条,产值约为上百亿元人民币。我国消防装备研究部门从 1997 年开始对消防 灭火机器人进行科研开发, 2002 年 6 月,由公安部上海消防研究所、上海交通大学、上海消防局三家单位共同承担的国家 863 项目 " 履带式、轮式消防灭火机器人 " 研制成功并顺利通过国家验收。消防灭火机器人,又称自行式水 - 泡沫消防炮,是一种结合多种消防灭火手段为一体的新型消防装备。

2002 年 9 月 8 日,灭火机器人参加公安消防部队北京协作区反恐演习中受到公安部消防局陈家强局长的高度评价;

2002 年我国云南、湖北省相继配备灭火机器人;

2003 年 9 月,灭火机器人在湖北省首次投入实战;

2003 年 10 月,我国江苏省、香港地区、马来西亚开始大规模配备消防灭火机器人。

我国灭火小车科研事业从实验室走向生产车间最终战斗在火场一线,为我国消防装备的发展注入了新鲜血液,填补了国内空白。消防的社会意义在于它将对人类生存安全作为终极关怀,消防装备作为一种重要的火灾扑救手段,已经在消防灭火救援中显示越来越重要的作用。消防装备科研应始终贯彻 " 从火场中来,到火场中去 " 的指导思想,贴近火场一线,急火场之所急。

不仅在我国,在世界上消防工作也是一个大难题,各国政府都千方百计地将火灾的损失降到最低点。 1984 年 11 月,在日本东京的一个电缆隧道内发生了一起火灾,消防队员不得不在浓烟和高温的危险环境下在隧道内灭火。这次火灾之后,东京消防部开始对能在恶劣条件下工作的消防机器人进行研究,目前已有五种用途的消防机器人投入使用。

遥控消防机器人 1986 年第一次使用了这种机器人。当消防人员难于接近火灾现场灭火时,或有爆炸危险时,便可使用这种机器人。这种机器人装有履带,最大行驶速度可达 10 公里 / 小时,每分钟能喷出 5 吨水或 3 吨泡沫。

喷射灭火机器人 这种机器人于 1989 年研制成功,属于遥控消防机器人的一种,用于在狭窄的通道和地下区域进行灭火。机器人高 45 厘米,宽 74 厘米,长 120 厘火焰,喷嘴将水流转变成高压水雾喷向火焰。

消防侦察机器人 消防侦察机器人诞生于 1991 年,用于收集火灾现场周围的各种信息,并在有浓烟或有毒气体的情况下,支援消防人员。机器人有 4 条履带,一只操作臂和 9 种采集数据用的采集装置,包括摄像机、热分布指示器和气体浓度测量仪。消防的社会意义在于它将对人类生存安全作为终极关怀,消防装备作为一种重要的火灾扑救手段,已经在消防灭火救援中显示越来越重要的作用。

1.3、 灭火小车控制系统 的目标

本设计开发的智能灭火小车控制系统应用范围十分广泛, 设计的灭火小车能够实现自动循迹、检测火源、吹风灭火、报警等功能,救灾人员可以利用手机APP通过蓝牙无线模块对小车进行远程精确控制,让小车能制精确地到达火灾发生点;把各个功能设计为多个独立的模块,便于更改和维护。 本设计具有 很好的开发前景,将会 受到广大安全防护人员的欢迎。

第2章 灭火小车控制系统介绍

2.1 灭火小车功能概述

经过文献查阅和实际情况调研,了解到目前的消防系统的研究与设计一般采用的方案大都为: 通过人为报警,再由消防人员开着消防车去起火现场进行灭火。那样消防人员会随时面临着危险。通过自己的想法。采用的方案为:通过火焰传感器、检测到起火地点的温度的因素与其标准区间值不符,小车自动根据设定好的路线去灭火或者通过手机控制小车的方向进行灭火,极大地降低了火灾对消防员人身安全的威胁。

该控制系统的最大特点:

  1. 结构简单

  2. 体积小、功率低

  3. 信号无干扰,传输准确度高

  4. 成本低廉

  5. 安全

系统各个功能模块简介:

  1. 四路循迹模块:主要用来让小车按照设定好的路线前进。

  2. 电源模块:主要用来分别区分给单片机与电机、风扇电机驱动模块供电。

  3. 五路火焰传感器模块:主要用来对火焰传感器给单片机传值的功能。

  4. 电机驱动模块:主要用来驱动两个减速直流电机,实现小车的前进、左转、右转、停车等功能。

  5. 风扇驱动模块:主要是用来控制风扇是否吹风,来实现小车灭火 功能。

  6. 蓝牙模块:通过手机软件来控制灭火小车的状态。
    在这里插入图片描述
    图 2-1 灭火小车整体模块图

2.2、工作原理

在灭火小车的设计中,工作原理:首先小车通过四路循迹模块,根据我们设定好的路线前进,然后小车的五路火焰传感器检测前方是否有火焰信号,如果检测不到火焰信号,则小车往前行走;当在小车在行走的过程中检测到火焰信号时,五路火焰传感器将信号发送到芯片,然后单片机控制小车停止,同时控制电路驱动风扇旋转,将火吹灭。

2.3、主要设计内容

用STM32F103单片机作为控制核心,加上四路循迹模块,五路火焰传感器模块,电机驱动小车四轮行走以及风扇转动,电源模块以及OLED显示模块,设计一个灭火小车。设计包括以下内容:

( 1 ) 自动沿预设轨道行驶,小车在行驶过程中,能够自动检测预先设好的轨道,实现直道、弯道和弧形轨道的前进。

( 2 )当小车到达火源地后,自动停车同时启动灭火风扇进行灭火,消除火源后随着路线返回起点。

( 3 )能通过手机的软件,通过蓝牙模块,切换为手动和自动循迹模式,手动模式时能控制小车到达想要的地点。

2.4、本章小结

本章结合目前的灭火小车对当前的小车进行了系统的概述,小车具备的功能以及系统控制的工作原理,通过阅读本章内容可对该系统有一个总体的了解。

第3章 系统硬件设计

3.1、硬件设计框图

本控制系统硬件设计框图 3-1 如下所示:
在这里插入图片描述
图 3-1硬件设计框图

在灭火小车控制系统的设计中,以STM32单片机为控制核心,用了一片 L298N电机驱动板模块用于驱动两个变速电机。 12V 电源单独给电机供电,首先STM32单片机根据火焰检测电路是否有火焰信号,来判断小车是否继续循迹前进。如果没有该火焰信号,则一直按照循迹巡线进行。手机APP控制单片机根据程序设计的要求做出相应的判断送给电机驱动模块,让小车来实现前进、左转、右转、停车等基本功能。到达火灾地点时,单片机通过晶闸管导通风扇控制电路,驱动风扇灭火。

3.2 、硬件设计及主控芯片介绍

在灭火小车控制系统的设计中,共用了一片STM32F103ZET6 单片机作为本控制系统的主控芯片,硬件设计模块共分为:4路循迹模块、电机驱动模块、电源模块、五路火焰检测模块、风扇模块。

3.2.1、STM32F103ZET6主控芯片介绍

STM32F103ZET6 简介

stm32是一个低功耗,高性能32位单片机,片内含4k Bytes ISP(In-system programmable)的可反复擦写1000次的Flash只读程序存储器。主要性能有:与MCS-51单片机产品兼容、全静态操作:0Hz~33Hz、 三级加密程序存储器、32个可编程I/O口线、三个16位定时器/计数器、八个中断源、全双工UART串行通道、掉电后中断可唤醒、看门狗定时器、双数据指针、掉电标识符、易编程。

STM32它拥有的资源包括:48KB SRAM、256KB FLASH、2 个基本定时器、4 个通用定时器、2个高级定时器、2个DMA 控制器(共 12 个通道)、3 个SPI、2个IIC、5个串口、1个USB、1个CAN、3个12位ADC、1个12位DAC、1个SDIO接口及51 个通用IO口,该芯片性价比极高。

各个引脚说明如下

PB6 接电机驱动的IN1;

PB7接电机驱动IN2;

PB8接电机驱动IN3;

PB9接电机驱动IN4;

PA2接蓝牙模块的RXT;

PA3接蓝牙模块的TXD;

PA6接电机驱动ENA,作为右电机调速;

PA7接电机驱动ENB,作为左电机调速;
在这里插入图片描述
图3-2.1 STM32F103引脚图

3.2.2、4路循迹模块系统方案设计

采用脉冲调制反射红外发射接收器作为循迹传感器,调制信号带有交流分量,可减少外界的大量干扰。信号采集部分就相当于智能循迹小车的眼睛,有它完成黑线识别并产生高、低平信号传送到控制单元,然后单片机生成指令来控制驱动模块来控制两个直流电机的工作状态,来完成自动循迹。工作电流为10mA-50mA,输出为TTL电平。
在这里插入图片描述
图3-2.1循迹模块

3.2.3、驱动电机系统方案设计

方案 1 :采用专用芯片 L298N 作为电机驱动芯片。 L298N 是一个具有高电压大电流的全桥驱动芯片,它相应频率高,一片 L298N 可以分别控制两个直流 电机,而且还带有控制使能端。用该芯片作为电机驱动,操作方便,稳定性好,性能优良。

L298N 是 SGS 公司的产品,内部包含 4 通道逻辑驱动电路。是一种二相和四相电机的专用驱动器,即内含二个 H 桥的高电压大电流双全桥式驱动器,接收标准 TTL 逻辑电平信号,可驱动 46V 、 2A 以下的电机。其引脚排列如图 3-7 中 U4 所示, 1 脚和 15 脚可单独引出连接电流采样电阻器,形成电流传感信号。 L298 可驱动 2 个电机, OUT1 、 OUT2 和 OUT3 、 OUT4 之间分别接 2 个电动机。 5 、 7 、 10 、 12 脚接输入控制电平,控制电机的正反转, ENA , ENB 接控制使能端,控制电机的停转。也利用单片机产生 PWM 信号接到 ENA , ENB 端子,对电机的转速进行调节。

1 L298N 的逻辑功能:

表 3-2 SHARP GP2D12 实物图
在这里插入图片描述
2 外形及封装:
在这里插入图片描述
图 3-2.3 L298N 实物图

方案 2 :对于直流电机用分立元件构成驱动电路。由分立元件构成电机驱动电路,结构简单,价格低廉,在实际应用中应用广泛。但是这种电路工作性能不够稳定。

因此我们选用了方案 1 。

驱动电路的设计如图 3-2.3(2) 所示:
在这里插入图片描述
图 3-2.3 驱动电机模块原理图

3.2.4 、电源系统方案设计

由于本系统需要电池供电,我考虑了如下集中方案为系统供电。

方案 1 : 采用 8 节 1.5V 干电池供电,电压达到 12V ,给支流电机供电,然后将 12V 电压再次降压、稳压后给单片机系统和其他芯片供电。并且电池的价格比较低。

方案 2 :采用 3 节 4.2V 可充电式锂电池串联共 12.6V 给直流电机供电,经过 7812 的电压变换后给支流电机供电,然后将 12V 电压再次降压、稳压后给单片机系统和其他芯片供电。锂电池的电量比较足,并且可以充电,重复利用,因此,这种方案比较可行。但锂电池的价格过于昂贵,使用锂电池会大大超出我的预算,因此,我放弃了这种方案。

方案 3 :采用 12V 蓄电池为直流电机供电,将 12V 电压降压、稳压后给单片机系统和其他芯片供电。蓄电池具有较强的电流驱动能力以及稳定的电压输出性能。但蓄电池的体积过于庞大,在小型电动车上使用极为不方便,

综上考虑,我选择了方案 1 。

采用稳压芯片给各个芯片提供稳定的工作电压,其芯片的具体参数如下:

稳压芯片 LM7805CV 、 LM7812CV

1 . LM7805CV 的技术指标如下表 :

表 3-3 稳压芯片 7805 参数
在这里插入图片描述
2 . 电源模块电路原理图

由于单片机及所有的传感器系统供电采用的是 5V 的电源,而车体要良好的运行电机的供电电压应该达到 12V ,所以在电源的处理上采用了稳压芯片 7805CV 和 7812CV 。
在这里插入图片描述
图 3-2.4 电源部分电路图

通过对比三个方案,发现第三个方案要比前两个更加的可靠稳定,这一点对灭火机器人的性能的发挥很重要。所以,选择第三种方案。

3.2.5 、五路火焰检测系统设计

方案 1 :火焰传感器是模拟传感器。它利用红外敏感型元件 AC4067 对红外信号强度的检测并将其转换为机器人可以识别的信号,从而来检测火焰信号。如下图为火焰传感器电路。
在这里插入图片描述
图 3-2.5 火焰传感电路

火焰传感器可以用来探测波长在 700nm ~ 1000nm 范围内的红外线的短波近红外线(SW-NIR),通过电信号(电压信号)进行输出。探测角度为 60º ;,其中红外线波长在 880nm 附近时,其灵敏度达到最大。红外火焰探头将外界红外光的强弱变化转化为电流的变化,通过 A/D 转换器反映为 0 ~ 255 范围内数值的变化。外界红外光越强,数值越小;红外光越弱,数值越大。在机器人设计中,红外火焰探头起着非常重要的作用,它可以用作机器人的眼睛来寻找火源或其他物体。利用它可以制作灭火小车、足球机器人等。

3.2.6 、 车体方案设计

方案 1 :购买玩具电动车。购买的玩具电动车具有组装完整的车架车轮、电机及其驱动电路。但是一般的说来,玩具电动车具有如下缺点:首先,这种玩具电动车由于装配紧凑,使得各种所需传感器的安装十分不方便。其次,这种电动车一般都是前轮转向后轮驱动,不能适应该题目的方格地图,不能方便迅速的实现原地保持坐标转 90 度甚至 180 度的弯角。再次,玩具电动车的电机多为玩具直流电机,力矩小,空载转速快,负载性能差,不易调速。而且这种电动车一般都价格不菲。因此我们放弃了此方案。

方案 2 :自己制作电动车。经过反复考虑论证,我制定了左右两轮分别驱动,前万向轮转向的方案。即左右轮分别用两个转速和力矩基本完全相同的直流减速电机进行驱动,车体前部装一个万向轮。这样,当两个直流减速电机转向相反同时转速相同时就可以实现电动车的原地旋转,由此可以轻松的实现小车坐标不变的 90 度和 180 度的转弯。

在安装时我保证两个驱动电机同轴。当小车前进时,左右两驱动轮与前万向轮形成了三点结构。这种结构使得小车在前进时比较平稳,可以避免出现后轮过低而使左右两驱动轮驱动力不够的情况。为了防止小车重心的偏移,前万向轮起支撑作用。

对于车架材料的选择,我们经过比较选择了有机玻璃。用有机玻璃做的车架比塑料车架更加牢固,比铁制小车更轻便,美观。

综上考虑,我们选择了方案 2 。

3.2.7 、风扇模块设计

灭火风扇的驱动电路如图 3-2.7所示。其中 Port 接到单片机的 P0.5 、 P0.6 接口上。单片机输出 Port 控制信号用以驱动灭火电机动作。由于选用的是增强型 MOS 管,所以,当 Port 信号为高时, MOS 管在 V GS 下开始工作, MOS 导通,风扇开始动作,进行灭火;当 Port 信号为低时,由于增强型 MOS 管特点, V GS =0 时, i D =0 。此时, MOS 截止,风扇不动作。
在这里插入图片描述
图 3-2.7 风扇控制电路

3.2.8、蓝牙模块设计

使用HC-05蓝牙模块就接受APP的蓝牙数据。挂载在STM32板UART中。HC-05 蓝牙串口通信模块,是基于 Bluetooth Specification V2.0 带 EDR 蓝牙协议的 数传模块。无线工作频段为 2.4GHz ISM,调制方式是 GFSK。模块最大发射功率为 4dBm, 接收灵敏度-85dBm,板载 PCB 天线,可以实现 10 米距离通信。 模块采用邮票孔封装方式,模块大小 27mm×13mm×2mm,方便客户嵌入应用系统之 内,自带 LED 灯,可直观判断蓝牙的连接状态。 模块采用 CSR 的 BC417 芯片,支持 AT 指令,用户可根据需要更改角色(主、从模式) 以及串口波特率、设备名称等参数,使用灵活。实物图如下:

在这里插入图片描述

图3-2.7(1)蓝牙模块实物图
在这里插入图片描述
图3-2.7(2)工作原理图
在这里插入图片描述
图3-2.7(3)蓝牙模块与手机通讯

3.3 本章小结

本章通过框图的形式介绍了各个系统模块的设计,4路循迹模块、驱动电机模块、电源模块、五路火焰检测模块、风扇控制、蓝牙模块等几部分的设计思路作了详细分析,通过阅读本章内容可对本智能灭火小车控制系统的硬件设计全面了解。

第4章 系统软件 设计

对于一个完整控制系统来说,除了要有一个完整的硬件控制以外,还应该有一个能充分发挥硬件功能的软件系统来支持它,本章将详细介绍4路循迹巡线模块、电机驱动、五路火焰检测模块、风扇驱动的软件实现方法。

4.1 软件设计思路

根据总体设计的思想及本系统实现的功能,在软件设计中完成以下功能。
在这里插入图片描述
图 4-1 系统软件图

  1. 4路循迹巡线模块主程序:

  2. 电机驱动模块主程序:主要用来控制两个直流减速电机,实现前进、后退、前左转、前右转、后左转、后右转、停车等功能。

  3. 火焰检测模块主程序:主要通过火焰传感器探测是否有火源。

  4. 风扇模块程序:主要用来控制一个报警器和风扇,实现报警、吹风等功能。

通过各种功能模块得到我们需要的东西,并且通过Keil 软件公司提供的Keil5软件利用代码来具体实现我们需要的功能。

4.2、各功能模块软件程序设计

在各个硬件功能模块的基础上,针对其预定实现的相应功能对各个功能模块进行软件程序设计。

4.2.1、Main主程序代码

利用main主程序代码检测火焰传感器信号

#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "timer.h"
#include "moter.h"
#include "oled.h"
#include "linewalking.h"
#include "fire.h"

//电机 1 PWM(EN)使用GPIOA.6 --- PA.6

//电机 2 PWM(EN)使用GPIOA.7 --- PA.7

//电机的初始化

//分别PB11 PB12 PB13 PB14

//蓝牙模块 PA.9  ---> RXD

//     PA.10  ---> TXD

// 

int Flag = 0;

int main(void)
{			
    delay_init();	  	 //延时函数初始化	 
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 	 //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    uart_init(9600);	 //串口初始化为9600
    LED_Init();			   //LED端口初始化
    TIM3_PWM_Init(899,719);	 //72分频。PWM频率=72000000/(900*720)
    Moter_GPIO_Init();//电机的GPIO初始化
    LineWalking_GPIO_Init();// 巡线传感器GPIO初始化接口
    Fire_GPIO_Init();
    KEY_Init();
    while(1)
    {					 

        if(KEY0 == 0)

        {
            delay_ms(20);		

            while(KEY0 == 0);

            Flag++;

            if(Flag == 3)

            Flag = 0;

        }

        if(Flag == 2)

        {

            if(fire1||fire3||fire4||fire5)

            {

                delay_ms(10);

                if(fire1||fire3||fire4||fire5)

                {

                    moter_stop();

                    GPIO_SetBits(GPIOD,GPIO_Pin_2);

                	LED1 = 0;
                }			
            }

            else {

                GPIO_ResetBits(GPIOD,GPIO_Pin_2);

                app_LineWalking();

                LED1 = 1;

            }

        }		

    }	 

}

4.2.2、Pwm代码

通过程序代码实现车速的调整功能

void TIM3_PWM_Init(u16 arr,u16 psc)

{  

	GPIO_InitTypeDef GPIO_InitStructure;

	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

	TIM_OCInitTypeDef  TIM_OCInitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);	//使能定时器3时钟

 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA  | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟

	//GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射  TIM3_CH2->PB5   

  //设置该引脚为复用输出功能,输出TIM3 CH2的PWM脉冲波形	GPIOA.6 GPIOA.7

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7|GPIO_Pin_6; //TIM_CH1 TIM_CH2

	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出

	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO

  //初始化TIM3

	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值

	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 

	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim

	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式

	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

	//初始化TIM3 Channel2 PWM模式   

 

 //------------------注意!!!----------------------//

 //在模式PWM1中有效电平于无效电平  such as (TIM_OCPolarity_Low)有效 则为低电平  否则无效电平为高电平

	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1

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

	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性低

	TIM_OC2Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC2

 

	TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR2上的预装载寄存器

	//初始化TIM3 Channel1 PWM模式   

	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1

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

	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性低

	TIM_OC1Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC1


	TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR2上的预装载寄存器

	TIM_Cmd(TIM3, ENABLE);  //使能TIM3

}

4.2.3、电机驱动代码

通过电机驱动程序代码实现小车的前进,后退,右转左转功能

void Moter_GPIO_Init(void)
{
    //电机的GPIO 初始化

    GPIO_InitTypeDef  GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	 //使能PB端口时钟

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_8|GPIO_Pin_9;				 //端口配置

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz

    GPIO_Init(GPIOB, &GPIO_InitStructure);				 //根据设定参数初始化

    GPIO_SetBits(GPIOB,GPIO_Pin_4); 					 // 输出高 

    GPIO_SetBits(GPIOB,GPIO_Pin_5); 					 // 输出高

    GPIO_SetBits(GPIOB,GPIO_Pin_8); 					 // 输出高

    GPIO_SetBits(GPIOB,GPIO_Pin_9); 					 // 输出高

}//前进

void moter_run(u16 pwm1,u16 pwm2)
{
    IN1 = 1; IN2 = 0;

    IN3 = 1; IN4 = 0;

    TIM_SetCompare1(TIM3,pwm1);	//	电机1占空比  

    TIM_SetCompare2(TIM3,pwm2);	//	电机2占空
}//暂停

void moter_stop(void)
{
	IN1 = 0; IN2 = 0;
	IN3 = 0; IN4 = 0;
	TIM_SetCompare1(TIM3,0);	//	电机1占空比  
	TIM_SetCompare2(TIM3,0);	//	电机2占空比 

}

//后退
void moter_back(u16 pwm1, u16 pwm2)
{
	IN1 = 0; IN2 = 1;

	IN3 = 0; IN4 = 1;

	TIM_SetCompare1(TIM3,pwm1);	//	电机1占空比  
	TIM_SetCompare2(TIM3,pwm2);	//	电机2占空比 

}


// Function    moter_left

//@author     yuan

//left

void moter_left(u16 pwm1, u16 pwm2)
{

	IN1 = 0; IN2 = 0;

	IN3 = 1; IN4 = 0;

	TIM_SetCompare1(TIM3,pwm1);	//	电机1占空比  

	TIM_SetCompare2(TIM3,pwm2);	//	电机2占空比 

}//Right

void moter_right(u16 pwm1,u16 pwm2)

{
	IN1 = 1; IN2 = 0;

	IN3 = 0; IN4 = 0;

	TIM_SetCompare1(TIM3,pwm1);	//	电机1占空比  

	TIM_SetCompare2(TIM3,pwm2);	//	电机2占空比 

}

4.2.4、蓝牙串口代码

利用蓝牙串口代码实现数据的传输以及通信功能

void uart_init(u32 bound){

//GPIO端口设置

GPIO_InitTypeDef GPIO_InitStructure;

USART_InitTypeDef USART_InitStructure;

NVIC_InitTypeDef NVIC_InitStructure;

 

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);	//使能USART1,GPIOA时钟

 

//USART1_TX  GPIOA.9

 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9

     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出

     GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9



     //USART1_RX	 GPIOA.10初始化

     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10

     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入

     GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  

     //Usart1 NVIC 配置

     NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能

    NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器

      //USART 初始化设置

    USART_InitStructure.USART_BaudRate = bound;//串口波特率

    USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式

    USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位

    USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位

    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制

    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式

    USART_Init(USART1, &USART_InitStructure); //初始化串口1

    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断

    USART_Cmd(USART1, ENABLE);           //使能串口1

}

 

void USART1_IRQHandler(void)         //串口1中断服务程序

{
	u8 Res;

#if SYSTEM_SUPPORT_OS 		//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.

	OSIntEnter();   

#endif

	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)

	{

		Res =USART_ReceiveData(USART1);	//读取接收到的数据
		if(Res == 69) //E

		moter_stop();	

		if(Res == 65) //A

		{

            moter_run(300,300);

            LED = !LED;

		}

		if(Res == 66) //B
	
		moter_left(300,0);	

		if(Res == 67) //C

		moter_right(0,300);

		if(Res == 68) //D

		moter_back(300,300);	

//				OLED_Clear();  //清屏函数,清完屏,

//				OLED_ShowString(10,12,"ok");

		if((USART_RX_STA&0x8000)==0)//接收未完成

			{

//			OLED_ShowString(10,10,"ok");

			if(USART_RX_STA&0x4000)//接收到了0x0d

			{

    //			OLED_ShowString(10,10,"ok");

                if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始

                else USART_RX_STA|=0x8000;	//接收完成了 

			}

			else //还没收到0X0D

			{	
                if(Res==0x0d)USART_RX_STA|=0x4000;

                else

                {

                USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;

                USART_RX_STA++;

                if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收	 
			}		 

		}

	}  		 

} 

#if SYSTEM_SUPPORT_OS 	//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.

	OSIntExit();  										 

#endif

}

4.2.5、循迹代码

利用循迹代码实现小车路线的检测功能以及对于小车的正确路径行驶功能。

#include "linewalking.h"

#include "moter.h"

#include "delay.h"

void LineWalking_GPIO_Init(void)

{
    GPIO_InitTypeDef  GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	 //使能PC端口时钟	

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15|GPIO_Pin_12;				 //端口配置

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz

    GPIO_Init(GPIOC, &GPIO_InitStructure);					 //根据设定参数初始化 

    GPIO_SetBits(GPIOB,GPIO_Pin_13); 			  // 输出高 

    GPIO_SetBits(GPIOB,GPIO_Pin_14); 			 // 输出高

    GPIO_SetBits(GPIOB,GPIO_Pin_15); 			 // 输出高

    GPIO_SetBits(GPIOB,GPIO_Pin_12); 			 // 输出高

}


//从车身后面往前看: 左侧到右边巡线传感器顺序为  L1 L2 |黑线| R1  R2	 对应原理图 IN2 IN1 |黑线| IN3 IN4

void bsp_GetLineWalking(int *p_iL1, int *p_iL2, int *p_iR1, int *p_iR2)

{

    *p_iL1 = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);  //L1

    *p_iL2 = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14);  //L2

    *p_iR1 = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_15);  //R1

    *p_iR2 = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12);	//R2	
}

void app_LineWalking(void)

{

    int LineL1 = 1, LineL2 = 1, LineR1 = 1, LineR2 = 1;

    bsp_GetLineWalking(&LineL1, &LineL2, &LineR1, &LineR2);	//获取黑线检测状态	

    if( (LineL1 == LOW || LineL2 == LOW) && LineR2 == LOW) //左大弯

    {    
        moter_SpinLeft(300, 300);
    	delay_ms(80);

    }
    else if ( LineL1 == LOW && (LineR1 == LOW || LineR2 == LOW)) //右大弯
    { 

        moter_SpinRight(300, 300);
        delay_ms(80);

    }  
    else if( LineL1 == LOW ) //左最外侧检测
    {  
        moter_SpinLeft(300, 300);
        delay_ms(10);

    }
    else if ( LineR2 == LOW) //右最外侧检测
    {  
        moter_SpinRight(300, 300);
        delay_ms(10);
    }
    else if (LineL2 == LOW && LineR1 == HIGH) //中间黑线上的传感器微调车左转
    {  
   		moter_left(0,300);  
    }
    else if (LineL2 == HIGH && LineR1 == LOW) //中间黑线上的传感器微调车右转
    {  
    	moter_right(300,0);  
    }
    else if(LineL2 == LOW && LineR1 == LOW) // 都是黑色, 加速前进
    {  
    	moter_run(300,300);
    }	
}

4.2.6、风扇灭火代码

利用风扇灭火代码实现小车的灭火功能

#include "stm32f10x.h"          // Device header

#include "fire.h"

void Fire_GPIO_Init(void)

{
    GPIO_InitTypeDef  GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOD, ENABLE);	 //使能PC端口时钟

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13;				 //端口配置

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	 //IO口速度为50MHz

    GPIO_Init(GPIOA, &GPIO_InitStructure);		 //根据设定参数初始化

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;	 //端口配置

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz

    GPIO_Init(GPIOD, &GPIO_InitStructure);					 

    GPIO_SetBits(GPIOA,GPIO_Pin_9);

    GPIO_SetBits(GPIOA,GPIO_Pin_10); 			// 输出高 

    GPIO_SetBits(GPIOA,GPIO_Pin_11); 			// 输出高

    GPIO_SetBits(GPIOA,GPIO_Pin_12); 			// 输出高

    GPIO_SetBits(GPIOA,GPIO_Pin_13); 			// 输出高

    GPIO_ResetBits(GPIOD,GPIO_Pin_2);
}

4.2.7、Android端代码

利用Android端代码实现对于小车的手机控制功能

La<Button
     android:layout_width="100dp"

     android:layout_height="wrap_content"

      android:id="@+id/forword"
      android:layout_gravity="center_horizontal"

      android:text="前进"

      android:textSize="20dp"

      android:layout_margin="20dp"

      android:background="@drawable/button"

      />

    <LinearLayout

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:orientation="horizontal"

     android:layout_gravity="center"

     \>

      <Button

        android:id="@+id/left_btn"

        android:layout_width="100dp"

        android:layout_height="wrap_content"

        android:text="左转"

        android:textSize="20dp"

        android:background="@drawable/button"

        />

      <Button

        android:id="@+id/stop_btn"

        android:layout_width="100dp"

        android:layout_height="wrap_content"

        android:text="停止"

        android:textSize="20dp"

        android:layout_marginLeft="20dp"

        android:background="@drawable/button"

        />

      <Button

		android:id="@+id/right_btn"

        android:layout_width="100dp"

        android:layout_height="wrap_content"

        android:text="右转"

        android:textSize="20dp"

        android:layout_marginLeft="20dp"

       android:background="@drawable/button"

       />

    </LinearLayout>

    <Button

      android:id="@+id/back"

      android:layout_width="100dp"

      android:layout_height="wrap_content"

      android:layout_gravity="center"

       android:text="后退"

      android:textSize="20dp"

      android:background="@drawable/button"

 android:layout_margin="20dp"

/>

4.2.8、Java代码

class ButtonListener implements View.OnTouchListener {

   public boolean onTouch(View v, MotionEvent event) {

      switch (v.getId()){

       case R.id.forword:

          if(event.getAction() == MotionEvent.ACTION_UP){//放开事件

            message[0]= (byte) 0x45;//设置要发送的数值

            bluesend(message);//发送数值

            Log.d("cy08",""+message[0]);

          }

         if(event.getAction() == MotionEvent.ACTION_DOWN){//按下事件

            message[0]= (byte) 0x41;//设置要发送的数值

            bluesend(message);//发送数值

           Log.d("cy08",""+message[0]);

          }

          break;

        case R.id.back:

          if(event.getAction() == MotionEvent.ACTION_UP){//放开事件

           message[0]= (byte) 0x45;//设置要发送的数值

            bluesend(message);//发送数值

            Log.d("cy08",""+message[0]);

          }

         if(event.getAction() == MotionEvent.ACTION_DOWN){//按下事件

            message[0]= (byte) 0x44;//设置要发送的数值

           bluesend(message);//发送数值

           Log.d("cy08",""+message[0]);

          }

          break;

        case R.id.stop_btn:

          if(event.getAction() == MotionEvent.ACTION_UP){//放开事件

            message[0]= (byte) 0x45;//设置要发送的数值

           bluesend(message);//发送数值

            Log.d("cy08",""+message[0]);

         }

          if(event.getAction() == MotionEvent.ACTION_DOWN){//按下事件

            message[0]= (byte) 0x45;//设置要发送的数值

            bluesend(message);//发送数值
            Log.d("cy08",""+message[0]);

         }

          break;

       case R.id.left_btn:

          if(event.getAction() == MotionEvent.ACTION_UP){//放开事件

           message[0]= (byte) 0x45;//设置要发送的数值

            bluesend(message);//发送数值

            Log.d("cy08",""+message[0]);

         }

          if(event.getAction() == MotionEvent.ACTION_DOWN){//按下事件

            message[0]= (byte) 0x42;//设置要发送的数值

            bluesend(message);//发送数值

            Log.d("cy08",""+message[0]);

          }

          break;

        case R.id.right_btn:

          if(event.getAction() == MotionEvent.ACTION_UP){//放开事件

            message[0]= (byte) 0x45;//设置要发送的数值

            bluesend(message);//发送数值

            Log.d("cy08",""+message[0]);

          }

          if(event.getAction() == MotionEvent.ACTION_DOWN){//按下事件

            message[0]= (byte) 0x43;//设置要发送的数值

            bluesend(message);//发送数值

            Log.d("cy08",""+message[0]);

          }

          break;

        default:

          break;

      }

      return false;

    }

  }

4.3、本章小结

本章用流程图的方法说明了智能寻迹灭火小车控制系统的软件设计,并对系统中主要程序的设计作了详细说明,通过阅读本章内容可以全面了解本控制系统的软件设计。

第5章 仿真调试

5.1、硬件调试

本次实验硬件的 调试主要运用到的是keil5的C语言代码编写,串口调试助手在小车上的代码调试,首先,在正式代码编写之前,需要先了解到几个步骤;

  1. 在调试程序之前,需要先确认各个模块的正确运行,所以需要我们先简单编写keil5程序,完成对于模块的简单使用,防止模块本身的问题造成的实验影响,

  2. 调试程序时,首先用全速运行的方法进行总体调试,以便快速发现程序中存在问题的部分。然后设置断点调试。主要针对有问题的程序调试,更快地确定出现问题的位置。最后,利用单步调试方法,分析程序中出现的问题,解决问题,使程序正常运行。

  3. 在多次调试不成功的基础上,考虑思路是否正确,如果确定思路无误,考虑两个问题:一是程序中是否有笔误的地方;二是运行软件是否正常。

在这里插入图片描述
图 5-1 系统硬件调试图

5.2、软件调试

本次APP使用的开发软件是Android studio,我们在蓝牙的连接上采用的是通过Mac地址自动连接已配对的蓝牙设备,按下按键时,会向蓝牙设备发送“ABCD”字符的十六进制数。

调试过程中,需要注意stm32接收的字符是ASCII码,所以在接收时需要用ASCII码来进行识别,否则无法识别到APP发送的数据。

手机按键在按下前进后退等时,会发送相应指令的数据,而松开时会立刻发送停止的指令,这样可以实现在按键松开时可以立刻停车。

在这里插入图片描述
在这里插入图片描述
图 5-2 系统软件调试图

5.3、本章小结

本章将硬件调试与软件调试分开叙述,并对调试过程中出现的问题作了详细的分析。 通过对硬件调试的基础上,根据其功能和特性,完成了软件的调试,整个程序能够实现预定的功能。在综合调试中尤其要注意各子程序之间的调用、返回。 可对智能寻迹灭火小车控制系统的整个调试过程有较全面的了解

第6章 结论

本次电子系统综合设计按照“循迹自动灭火小车”需要实现的功能通过以 stm32为主要核心板,用各种模块完成我们此次任务,通过各种模块的功能实现我们也得到了许多的设计结论,

( 1 )、控制小车循迹行动;

当循迹小车时,需要我们掌握好对于路线识别的准确判断,因此我们通过设定路线进行循迹,并且对于小车的循迹功能,我们还可以额外尝试增加一个避障功能,防止当小车循迹出错的时候出现小车的安全问题,及时的保护好我们的小车。

(2 )、控制风扇灭火。

当启动小车前进时一样,也有很大的瞬时的电流。所以需要延时程序来调整。

(3 )、火焰传感器识别。

当我们使用小车时,火焰传感识别的功能非常重要,因此我们必须得保证好火焰传感器的灵敏程度,需要我们在远距离就能够发现火焰的扩散,并及时停车灭火。所以购买火焰传感器的钱一定不能省,保护小车安全

通过硬件调试及软件的编程,达到了此次设计要求,实现了基本功能以及其一些扩展功能。该系统不仅能够对风扇的灵活控制,进行路线的自动巡航,并且还可以实现小车的具体运动控制,对小车进行调整。即包含手动,也包含自动蓝牙控制功能,完成实验设计需要的要求。通过本次实际,我们对于各芯片的工作原理有了更深入的认识,能够理论联系实际,同时也建立起了很强的思考能力和合作动手的能力,是一次非常好的学习与锻炼能力的机会!

感谢LLC团队提供的资料

猜你喜欢

转载自blog.csdn.net/weixin_44908159/article/details/107452715