0 前言
🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。
为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天要分享的是
🚩 基于STM32单片机的汽车防撞与控制系统
🥇学长这里给一个题目综合评分(每项满分5分)
- 难度系数:4分
- 工作量:4分
- 创新点:3分
1 简介
基于单片机的汽车防撞与控制系统设计
2 主要器件
- STM32F103C8T6主控芯片
- HC-SR04超声波模块
- 光敏传感器
- ESP-01S WIFI模块
- 蜂鸣器
- OLED屏
- 红外传感器模块
3 实现效果
前后有两个HC-SR04超声波模块,可以检测车前和车后是否有障碍物,实验中拿手机挡住前面的超声波模块,蜂鸣器会报警。
红外感应模块可检测车前是否有人,当红外感应模块前面有障碍是,显示屏上由N->Y,代表检测到人。
显示屏上显示超声波模块探测距离
4 设计原理
4.1 HC-SR04超声波模块
简介
HC-SR04超声波模块常用于机器人避障、物体测距、液位检测、公共安防、停车场检测等场所。HC-SR04超声波模块主要是由两个通用的压电陶瓷超声传感器,并加外围信号处理电路构成的。如图:
两个压电陶瓷超声传感器,一个用于发出超声波信号,一个用于接收反射回来的超声波信号。由于发出信号和接收信号都比较微弱,所以需要通过外围信号放大器提高发出信号的功率,和将反射回来信号进行放大,以能更稳定地将信号传输给单片机。模块整体电路如图:
模块参数
(1)模块主要电气参数
- 使用电压:DC—5V
- 静态电流:小于2mA
- 电平输出:高5V
- 电平输出:底0V
- 感应角度:不大于15度
- 探测距离:2cm-450cm
- 高精度 可达0.2cm
(2)模块引脚
超声波模块有4个引脚,分别为Vcc、 Trig(控制端)、 Echo(接收端)、 GND;其中VCC、GND接上5V电源, Trig(控制端)控制发出的超声波信号,Echo(接收端)接收反射回来的超声波信号。模块如图
4.2 ESP-01S WIFI模块
简介
ESP8266 系列模组是深圳市安信可科技有限公司开发的一系列基于乐鑫ESP8266的低功耗UART-WiFi芯片模组,可以方便地进行二次开发,接入云端服务,实现手机3/4G全球随时随地的控制,加速产品原型设计。
尺寸、管脚定义
ESP8266的指令介绍
AT指令可以细分四种类型:
1.测试指令:AT+=?
该命令用于查询设置指令的参数以及取值的范围
2.查询指令:AT+?
该命令用于返回参数的当前值
3.设置指令:AT+=<’’’>
该命令用于设置用户自定义的参数
4.执行指令:AT+
该命令用于执行受模块内部程序控制的变参数不可变的功能
ESP8266的指令测试
可以通过STM开发板转为电平转换的功能连接上ESP8266模块在通过串口显示窗口在PC机上热输入AT指令来进行操作。
ESP8266的AT指令一览
4.3 光照传感器
简介
光敏传感器是最常见的传感器之一,它的种类繁多,主要有:光电管、光电倍增管、光敏电阻、光敏三极管、太阳能电池、红外线传感器、紫外线传感器、光纤式光电传感器、色彩传感器、CCD和CMOS图像传感器等。光传感器是目前产量最多、应用最广的传感器之一,它在自动控制和非电量电测技术中占有非常重要的地位。光敏传感器是利用光敏元件将光信号转换为电信号的传感器,它的敏感波长在可见光波长附近,包括红外线波长和紫外线波长。光传感器不只局限于对光的探测,它还可以作为探测元件组成其他传感器,对许多非电量进行检测,只要将这些非电量转换为光信号的变化即可。
总结:照射光敏二极管的光强不同,通过光敏二极管的电流大小就不同,所以可以通过检测电流大小,达到检测光强的目的。利用这个电流变化,我们串接一个电阻,就可以转换成电压的变化,从而通过ADC读取电压值,判断外部光线的弱。
优点
- 采用灵敏型光敏电阻传感器
- 比较器输出,信号干净,波形好,驱动能力超过15mA。
- 配可调电位器可调节检测光线亮度
- 工作电压3.3V-5V
- 输出形式 :数字开关量输出(0和1)
- 设有固定螺栓孔,方便安装
原理图
5 部分核心代码
//hc_sr04.c源文件:
#include"stm32f10x.h"
#include"hc_sr04.h"
#include"stdio.h"
//hc_sr04引脚初始化
void HC_SR04_Init(void)//初始化hc_sro4的连接引脚
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//开启GPIOB时钟
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;//将hc_sr04的Trig引脚连接到单片机的PB5引脚上,单片机给HC_SR04提供至少10us的脉冲
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;//将hc_sr04的Echo引脚连接到单片机的PB6引脚上,HC_SR04反馈高电平信号给单片机
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
}
//通用定时器Tim2初始化
void Time2_Init(u32 Period , u32 Prescaler)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//开启定时器TIM2的时钟
TIM_TimeBaseStructure.TIM_Period = Period;//自动重装载寄存器的值
TIM_TimeBaseStructure.TIM_Prescaler = Prescaler;//时钟预分频数
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//采样分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
TIM_ClearFlag(TIM2,TIM_FLAG_Update);//清除溢出中断标志位
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//TIM2中断使能
// TIM_Cmd(TIM2,ENABLE);//使能定时器Tim2
}
//NVIC配置
void NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;//中断通道号配置为TIM2
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//无占先优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//无副优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//中断使能
NVIC_Init(&NVIC_InitStructure);//NVIC初始化
}
//给hc_sr04一个启动信号
void hc_sr04_start(void)
{
Trig=1;
delay_us(20);
Trig=0;
}
//计算hc_sr04测出来的值
void hc_sr04_calculate(void)
{
float temp;
while(Echo==1);
hc_sr04_start();//启动hc_sr04超声波传感器
while(Echo==0);
printf("收到20us的脉冲,开始发送8个40KHz的方波信号!\r\n");
delay_ms(500);
printf("hc_sr04正在开始测距.......\r\n");
TIM_SetCounter(TIM2,0);//清空计数器
TIM_Cmd(TIM2,ENABLE);//开启定时器
while(Echo==1);//如果hc_sr04返回低电平说明还未检测到前面有障碍物,就一直执行该程序
TIM_Cmd(TIM2,DISABLE);//停止计数
temp=TIM_GetCounter(TIM2)*340/(2*1000);
printf("距离:%6.2fm\n",temp);
}
//hc_sr04.h头文件:
#ifndef _HC_SRO4_H
#define _HC_SR04_H
#include "stm32f10x.h"
#include "delay.h"
#define Trig PBin(5)
#define Echo PBout(6)
void HC_SR04_Init(void);
void Time2_Init(u32 Period , u32 Prescaler);
void NVIC_Config(void);
void hc_sr04_start(void);
void hc_sr04_calculate(void);
void delay_init();
void uart_init(u32 bound);
#endif
//wifi模块部分
#include "esp8266.h"
#include "string.h"
#include "usart.h"
#include "usart3.h"
#include "stm32f10x.h"
#include "sys.h"
#include "delay.h"
//ESP8266模块和PC进入透传模式
void esp8266_start_trans(void)
{
//设置工作模式 1:station模式 2:AP模式 3:兼容 AP+station模式
esp8266_send_cmd("AT+CWMODE=1","OK",50);
//让Wifi模块重启的命令
esp8266_send_cmd("AT+RST","ready",20);
delay_ms(1000); //延时3S等待重启成功
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
//让模块连接上自己的路由
while(esp8266_send_cmd("AT+CWJAP=\"111\",\"11111111\"","WIFI GOT IP",600));
//=0:单路连接模式 =1:多路连接模式
esp8266_send_cmd("AT+CIPMUX=0","OK",20);
//建立TCP连接 这四项分别代表了 要连接的ID号0~4 连接类型 远程服务器IP地址 远程服务器端口号
while(esp8266_send_cmd("AT+CIPSTART=\"TCP\",\"xxx.xxx.xxx.xxx\",xxxx","CONNECT",200));
//是否开启透传模式 0:表示关闭 1:表示开启透传
esp8266_send_cmd("AT+CIPMODE=1","OK",200);
//透传模式下 开始发送数据的指令 这个指令之后就可以直接发数据了
esp8266_send_cmd("AT+CIPSEND","OK",50);
}
//ESP8266退出透传模式 返回值:0,退出成功;1,退出失败
//配置wifi模块,通过想wifi模块连续发送3个+(每个+号之间 超过10ms,这样认为是连续三次发送+)
u8 esp8266_quit_trans(void)
{
u8 result=1;
u3_printf("+++");
delay_ms(1000); //等待500ms太少 要1000ms才可以退出
result=esp8266_send_cmd("AT","OK",20);//退出透传判断.
if(result)
printf("quit_trans failed!");
else
printf("quit_trans success!");
return result;
}
//向ESP8266发送命令
//cmd:发送的命令字符串;ack:期待的应答结果,如果为空,则表示不需要等待应答;waittime:等待时间(单位:10ms)
//返回值:0,发送成功(得到了期待的应答结果);1,发送失败
u8 esp8266_send_cmd(u8 *cmd,u8 *ack,u16 waittime)
{
u8 res=0;
USART3_RX_STA=0;
u3_printf("%s\r\n",cmd); //发送命令
if(ack&&waittime) //需要等待应答
{
while(--waittime) //等待倒计时
{
delay_ms(10);
if(USART3_RX_STA&0X8000)//接收到期待的应答结果
{
if(esp8266_check_cmd(ack))
{
printf("ack:%s\r\n",(u8*)ack);
break;//得到有效数据
}
USART3_RX_STA=0;
}
}
if(waittime==0)res=1;
}
return res;
}
//ESP8266发送命令后,检测接收到的应答
//str:期待的应答结果
//返回值:0,没有得到期待的应答结果;其他,期待应答结果的位置(str的位置)
u8* esp8266_check_cmd(u8 *str)
{
char *strx=0;
if(USART3_RX_STA&0X8000) //接收到一次数据了
{
USART3_RX_BUF[USART3_RX_STA&0X7FFF]=0;//添加结束符
strx=strstr((const char*)USART3_RX_BUF,(const char*)str);
}
return (u8*)strx;
}
//向ESP8266发送数据
//cmd:发送的命令字符串;waittime:等待时间(单位:10ms)
//返回值:发送数据后,服务器的返回验证码
u8* esp8266_send_data(u8 *cmd,u16 waittime)
{
char temp[5];
char *ack=temp;
USART3_RX_STA=0;
u3_printf("%s",cmd); //发送命令
if(waittime) //需要等待应答
{
while(--waittime) //等待倒计时
{
delay_ms(10);
if(USART3_RX_STA&0X8000)//接收到期待的应答结果
{
USART3_RX_BUF[USART3_RX_STA&0X7FFF]=0;//添加结束符
ack=(char*)USART3_RX_BUF;
printf("ack:%s\r\n",(u8*)ack);
USART3_RX_STA=0;
break;//得到有效数据
}
}
}
return (u8*)ack;
}