🎀 文章作者:二土电子
🌸 关注公众号获取更多资料!
🐸 期待大家一起学习交流!
一、前言
超速、酒驾、疲劳驾驶已经成为导致我国交通事故多发的三大因素。其中,因酒驾产生的车祸和刑事案件数量最多,同时由于中国车辆保有量的逐渐递增,汽车事故的总量也在逐渐递增,这严重影响了我国的道路安全以及国民的生命健康。在国家加强酒驾醉驾处置办法以后,因酒驾醉驾导致的事故数量在逐年递减。目前,国内最为常见的检测酒驾的方法是便携式酒精检测仪和血检相结合的一种检测模式,这种模式存在的问题就在于,一是不能有效地对所有车辆驾驶员进行检测,二是无法实时检测驾驶员的酒驾情况。所以,为了减少因酒驾醉驾产生的交通事故,营造和谐安详的道路行驶氛围。本系统设计是采用单片机技术的智能防酒驾系统,在软件设计和硬件建设的基础上,进行对司机的实时现场监控,有效地检测出司机的酒驾状况,预警驾驶员的酒驾醉驾状况,以增强驾驶者酒后驾车的警示效果,从源头控制酒驾事故的产生,这能对当前道路交通安全的提高起到关键作用。
二、项目要求
- 利用红外传感器和压力传感器来实现系统的开关,只有当红外传感器检测到有物体经过且压力传感器检测到压力时开启系统,否则系统处于关闭状态;
- 利用酒精传感器检测酒精浓度,判断是否存在酒驾行为;
- 利用蜂鸣器实现当存在酒驾时报警;
- 通过OLED显示屏显示驾驶员存在酒驾行为时驾驶员的位置显示;
- 通过短信通讯模块实现存在酒驾时通知其紧急联系人的功能;
- 通过GPS模块检测驾驶员位置;
三、硬件选型
- 红外传感器选用常用的光电开关;
- 压力传感器选用电阻式薄膜压力传感器;
- 酒精浓度传感器选用MQ-3;
- 蜂鸣器选用常用的低电平触发的有源蜂鸣器;
- 选用0.96寸OLED作为显示器件;
- 选用SIM900A来发送短信;
- 选用ATGM336H来实现经纬度定位;
- 选用STM32F103C8T6作为主控;
四、程序设计
本设计中使用的一些外设,比如OLED、ATGM336H、SIM900A,这些都可以在之前的系列文章中找到详细介绍,这里不再赘述,这里住品种介绍一下之前没有出现过的酒精浓度传感器。
4.1 酒精浓度检测程序
检测酒精浓度实际就是检测MQ-3模块的输出电压,酒精浓度越高,输出引脚的电压越大,因此我们只需要配置一个ADC去检测输出引脚的电压即可,需要注意的是MQ-3输出电压应该在0~5V,注意电压控制,防止电压过大导致MCU被损坏,酒精浓度检测程序如下
// 酒精浓度检测
adValue = Get_ADC_Value(1,10); // 获取AD值
alcohol = ((float)adValue / 0xFFF) * 3.3; // 计算实际电压
alcohol = alcohol * (125 / 3.3); // 计算酒精浓度
alcohol = alcohol - 37.9;
if (alcohol <= 0)
{
alcohol = 0;
}
ADC相关的配置程序也可以在速成笔记系列中找到,这里也不再赘述。
4.2 酒驾驾驶提醒
本项目需要实现在检测到酒驾时通过短信提醒紧急联系人,程序设计如下
// 酒驾提醒
if (alcohol >= 20)
{
BEEP = 0; // 蜂鸣器报警
sprintf ((char*)gStr,"Dangerous Drive");
Med_Oled_ShowString(10,7,gStr,8);
// 发送短信
if (gSendMessageFlag != 1) // 之前没法送过短信
{
USART_Cmd(USART2, DISABLE); // 关闭串口2
App_Sim900a_SendMsg();
gSendMessageFlag = 1; // 发送短信标志位置1
USART_Cmd(USART2, ENABLE); // 使能串口2
}
}
实际发送短信的程序在外设系列的SIM900A中有介绍,不再赘述。
4.3 经纬度信息显示
最后介绍一下如何将GPS检测到的经纬度信息显示到OLED,之前已经有好几个小伙伴提到这个问题,这里简单提供一种实现思路
/*
*==============================================================================
*函数名称:Data_Transfor
*函数功能:数据转换
*输入参数:无
*返回值:无
*备 注:无
*==============================================================================
*/
void Data_Transfor (void)
{
float latitude = 0; // 存储纬度信息
u16 temp1 = 0; // 临时变量1,存储整数
float longitude = 0; // 存储经度信息
u16 temp2 = 0; // 临时变量2,存储整数
u8 string[20]; // OLED显示内容
latitude = strtod(receDataFrame.latitude,NULL); // 字符串转换成浮点数
longitude = strtod(receDataFrame.longitude,NULL); // 字符串转换成浮点数
// 纬度信息处理
// 五位纬度信息
if ((latitude - 10000.0) >= 0)
{
// 前三位需要单独拿出来组成一个数
temp1 = (((u16)latitude / 10000) % 10) * 100 + (((u16)latitude / 1000) % 10) * 10 + ((u16)latitude / 100) % 10;
latitude = latitude - (float)temp1 * 100;
latitude = (float)temp1 + latitude / 60;
// printf ("latitude:%.3f\r\n",latitude);
}
else // 四位纬度信息
{
// 前两位需要单独拿出来组成一个数
temp1 = (((u16)latitude / 1000) % 10) * 10 + ((u16)latitude / 100) % 10;
latitude = latitude - (float)temp1 * 100;
latitude = (float)temp1 + latitude / 60;
// printf ("latitude:%.3f\r\n",latitude);
}
// 经度信息处理
// 五位经度信息
if ((longitude - 10000.0) >= 0)
{
// 前三位需要单独拿出来组成一个数
temp2 = (((u16)longitude / 10000) % 10) * 100 + (((u16)longitude / 1000) % 10) * 10 + ((u16)longitude / 100) % 10;
longitude = longitude - (float)temp2 * 100;
longitude = (float)temp2 + longitude / 60;
// printf ("longitude:%.3f\r\n",longitude);
}
else // 四位经度信息
{
// 前两位需要单独拿出来组成一个数
temp2 = (((u16)longitude / 1000) % 10) * 10 + ((u16)longitude / 100) % 10;
longitude = longitude - (float)temp2 * 100;
longitude = (float)temp2 + longitude / 60;
// printf ("longitude:%.3f\r\n",longitude);
}
sprintf ((char*)string,"Long:%.1f ",longitude);
Med_Oled_ShowString(10,3,string,8);
sprintf ((char*)string,"Lat:%.1f ",latitude);
Med_Oled_ShowString(10,5,string,8);
}
五、使用说明
最后简单介绍一下,我们如果想要修改紧急联系人的手机号时需要使用到Unicode转换工具,这个在SIM900A的文章中也介绍过,这里不再赘述