基于STM32的智能导盲系统
闲来无事,用手头STM32做个项目。
成品功能:
1、垃圾车可以可以按照规定的路线自动行驶,当红外传感器检测到有人靠近后可以自动停车,电机驱动打开垃圾桶盖;
2、垃圾桶内设红外传感器,当垃圾桶内的垃圾已经装满的时候,单片机会通过短信模块自动发送短信给管理人员;
3、小车装有GPS定位,可以通过GPS实时查看垃圾车的位置,当垃圾已满或超重时会提醒有关人员进行垃圾清理。
材料
- STM32F103C8T6芯片最小系统板
- OLED液晶显示屏
- 5个红外检测模块
- 杜邦线
- GSM模块
- GPS模块
- 人体红外模块
- 一个模块小车
- 一个电池盒
- 四节5号电池
- ULN2003驱动模块
- 一个舵机
- 一个开关
- 一个小垃圾桶(纸盒子也行)
- 用keil5进行开发
小车为
开始制作。
整体示意图
这里画了一个简单的示意图,方便后续设计思路
系统流程图
还有系统原理图等在资料中。
制作过程
1、首先测试GPS,找到地址(经纬度)数据。再测试GSM,通过AT指令使其可以发短信(也可测试打电话,本项目用不到),然后在板子中测试,再测试GPS,找到地址(经纬度)数据。
2、测试小车自动循迹。
3、测试小车
GPS模块调试
模块原理
GPS(ATK-NEO-6M GPS)模块
设置好后,模块接收NMEA码并解析出我们需要的数据。
例如:
每个都代表着不同的数据。可以参考:GPS的NMEA码的详细解释定义
具体的模块已经配置好了,我们使用就可以了。
硬件连接
1、给模块供5V电、GND接地。
2、模块接到板子串口1上(模块TX接板子PA10、模块RX接板子PA9)。
代码调试
1、代码要做的就是将这个过程自动化。收集到数据之后自动处理。
2、部分代码如下
void parseGpsBuffer()
{
char *subString;
char *subStringNext;
char i = 0;
if (Save_Data.isGetData)
{
Save_Data.isGetData = false;
u2_printf("**************\r\n");
u2_printf(Save_Data.GPS_Buffer);
for (i = 0 ; i <= 6 ; i++)
{
if (i == 0)
{
if ((subString = strstr(Save_Data.GPS_Buffer, ",")) == NULL)
errorLog(1);
}
else
{
subString++;
if ((subStringNext = strstr(subString, ",")) != NULL)
{
char usefullBuffer[2];
switch(i)
{
case 1:memcpy(Save_Data.UTCTime, subString, subStringNext - subString);break; //??è?UTCê±??
case 2:memcpy(usefullBuffer, subString, subStringNext - subString);break; //??è?UTCê±??
case 3:memcpy(Save_Data.latitude, subString, subStringNext - subString);break; //??è??3?èD??¢
case 4:memcpy(Save_Data.N_S, subString, subStringNext - subString);break; //??è?N/S
case 5:memcpy(Save_Data.longitude, subString, subStringNext - subString);break; //??è??-?èD??¢
case 6:memcpy(Save_Data.E_W, subString, subStringNext - subString);break; //??è?E/W
default:break;
}
subString = subStringNext;
Save_Data.isParseData = true;
if(usefullBuffer[0] == 'A')
Save_Data.isUsefull = true;
else if(usefullBuffer[0] == 'V')
Save_Data.isUsefull = false;
}
else
{
errorLog(2);
}
}
}
}
}
GSM模块(ATK-SIM800C)AT调试
硬件连接
1、模块供5V电,GND接地。
2、模块接到板子串口2上(模块TX接板子PA2、模块RX接板子PA3)。
模块原理
首先用AT指令测试模块,达到可以发短信,打电话。
下边是部分AT指令:
AT | 返回 | 作用 |
---|---|---|
AT | OK | 模块通讯正常 |
AT+CPIN? | +CPIN:READY | 查询 SIM 卡的状态,主要是 PIN 码 |
AT+CSQ | +CSQ: 24,0 | 查询信号质量 |
AT+COPS? | +COPS:0,0,”CHINA MOBILE” | 查询当前运营商 |
AT+CGMI | SIMCOM_Ltd | 查询模块制造商 |
AT+CGMM | SIMCOM_SIM800C | 查询模块型号 |
AT+CGSN | 866104023267696 | 查询产品序列号(集 IMEI 号) |
AT+CNUM | +CNUM:””,”136******”,”129”,7,4 | 查询本机号码 |
ATE1 | OK | 设置回显模式(默认开启) |
ATD10086; | OK | 用于拨打任意电话号码 |
ATA | OK | 应答电话 |
ATH | OK | 挂断电话 |
AT+CMGF=1 | OK | 置短消息模式,设置为文本模式 |
AT+CSCS=“GSM” | OK | 用于设置 TE 字符集,纯英文为GSM,中英文为UCS2 |
AT+CMGS | > | 用于发短信 |
英文短信的发送
- 设置字符集为
AT+CSCS="GSM"
; - 设置文本模式为
AT+CMGF=1
; - 发送短信的目的人为
AT+CMGS="18********"
; - 然后模块返回:
>
,此时我们输入我们需要发送的内容:ATK-SIM800C MSG SEND TEST
; - 在发送完内容以后, 最后以十六进制(HEX)格式单独发送(不用添加回车):
1A
(即 0X1A),即可启动一次短信发送。 - 稍等片刻,在短信成功发送后,模块返回如: +CMGS: 39,的确认信息,表示短信成功发送
中文短信的发送
- 首先发送
AT+CMGF=1
, 设置为文本模式; - 设置文本模式参数
AT+CSMP=17,167,2,25
; - 设置字符集为
AT+CSCS="UCS2"
; - 首先要用将号码和发送内容转换为UNICODE 字符串,
1.号码182********,转换后的 UNICODE 字符串(去掉空格后)为:
2.00310038003200390030003100390035003600330032
3.ATK-SIM800C 中英文短信发送测试,装换后的 UNICODE 字符串为:
4.00410054004B002D00530049004D003800300030004300204E2D82F1658777ED4FE153D
190016D4B8BD5
由于使用了 UCS2字符集,所有字符/数字/汉字,都必须使用 UNICODE 编码
- 发送:
AT+CMGS=”00310038003200390030003100390035003600330032”
,这个指
令,然后模块返回:>
- 此时我们输入我们需要发送的内容:
00410054004B002D00530049004D003800300030004300204E2D82F1658777ED4FE153D 190016D4B8BD5
注意,此可以不用发送回车了; - 在发送完内容以后,最后以十六进制(HEX)格式当独发送(不用添加回
车):1A
(即 0X1A),启动一次短信发送。
一次中英文短信发送成功。
代码测试
- 我么要做的就是将这个过程自动化。
- 部分代码如下。
void sim800c_test(void)
{
OLED_Clear();
sim800c_send_cmd((u8*)0X1A,"+CMGS:",10);
IWDG_ReloadCounter();
while(sim800c_send_cmd("AT","OK",100))//检测是否应答AT指令
{
OLED_ShowString(0,0,"SBLJZ ",16); //连接成功
sim800c_send_cmd((u8*)0X1A,"+CMGS:",10);
}
printf("ATE0");
OLED_ShowString(0,0,"LJCG ",16); //连接成功
delay_ms(10);
while(sim800c_send_cmd("AT+CMGF=1","OK",200)){} //设置文本模式
OLED_ShowString(0,2,"WBMS ",16);//文本模式
while(sim800c_send_cmd("AT+CSCS=\"GSM\"","OK",200)){} //设置TE字符集为UCS2
OLED_ShowString(0,4,"ZFMS ",16);//字符模式
//发送短信测试
OLED_ShowString(0,4,"ZZSZ ",16); //正在发送
if(sim800c_send_cmd("AT+CMGS=\"10086\"",">",800) == 0);
printf("Test!/r/nTest1\r\n");
IWDG_ReloadCounter();
if(sim800c_send_cmd((u8*)0X1A,"+CMGS:",800)==0){OLED_ShowString(0,6," FSCG ",16);return;}
OLED_ShowString(0,6," FSSB ",16);
IWDG_ReloadCounter();
USART_RX_STA=0;
if(USART_RX_STA&0X8000)sim_at_response(1);//检查从GSM模块接收到的数据
}
- 将短信内容改为:
I am full,I am 110'46E,40°51′
- 进行测试,收到的短信内容为所发的就可以了。
人体红外检测模块及红外检测模块
模块原理:
红外检测模块:通过一个红外发射管和一个红外接受管来检测路径上是否有不可反射红外线的东西。这里主要用来黑线循迹。
人体红外热释电模块:用来检测前方是否有人。实现停车装卸垃圾。
代码测试
人体红外检测模块及红外检测模块都是开关量检测。我们只需要检测到高电平做出相应的动作即可。
小车
模块作用:主要作为载体,进行黑线循迹。检测到有人后停下,垃圾满后停下。
ULN2003驱动
这里由于单片机驱动力不够,无法直接驱动小车。我们用UNL2003驱动小车。带上一个独立的9V电源给小车供电。这里我们只驱动电机正转,意思就是只能向前走。ULN2003是负极驱动。驱动板的接线方式为:给驱动板的正负极接电源(干电池串联组成的9V直流电源)正极负极,电机的所有正极都接到一起,接到电源的正极,负极接到四个ULN2003的输出极上,单片机出来四根控制极接到对应的四个控制引脚上,这样单片机高电平输出的时候,ULN2003输出极输出,电机转动。(也可以通过输出一个pwm波来控制电机转速,这里我们电源电压没采用12V的,驱动四个电机,速度本也不快,就没有做速度控制,如果用作pwm输出,请注意单片机引脚要有定时器复用功能。)这里就是个单片机IO口输出,就不放代码了。
自动循迹
说说明:这里车很垃圾,我也很垃圾。就只做了个绕行一圈,没有做其他路况,可根据自身情况增加其他路况。
示意图
这里就做个直行和拐一些弯。做的很垃圾。勿喷!!!
解释一下:
红外检测没有遇到黑色的线的时候,反馈检测不到反馈的值,当遇到黑色的线,发射的红外线就会反射,接受极就会检测到高电平。
直行的时候四个电平都是低电平。
当3号红外探头检测到高电平的时候,说有前边有向右的转弯,让右边前一个电机停转,左边两个电机继续走,直到再次四个检测到空。
当四号探头检测高高电平的时候,说明已经走过很多了,这个时候让右边两个电机停止,当3号检测到的时候,开右边一个电机这时候恢复到上边那种情况。
可根据自己的情况微调电机。这是向右转弯。向左转弯是一样的。这里不再赘述了。
//五种状态 0:都没踩到 1:左二踩到 2:左12踩到 3:右1 4:右12踩到
//没有检测到 Off 检测到 On
int Infrared_Find()
{
if((Infrared_1 == Off)&&(Infrared_2 == Off)&&(Infrared_3== Off)&&(Infrared_4 == Off)) //四个都没检测到
{
return 5;
}
else if((Infrared_1 == On)&&(Infrared_2 == Off)&&(Infrared_3== Off)&&(Infrared_4 == Off))
{
return 1;
}
else if((Infrared_1 == Off)&&(Infrared_2 == On)&&(Infrared_3== Off)&&(Infrared_4 == Off))
{
return 2;
}
else if((Infrared_1 == Off)&&(Infrared_2 == Off)&&(Infrared_3== On)&&(Infrared_4 == Off))
{
return 3;
}
else if((Infrared_1 == Off)&&(Infrared_2 == Off)&&(Infrared_3== Off)&&(Infrared_4 == On))
{
return 4;
}
else if((Infrared_1 == On)&&(Infrared_2 == On)&&(Infrared_3== Off)&&(Infrared_4 == On))
{
return 6;
}
else if((Infrared_1 == Off)&&(Infrared_2 == Off)&&(Infrared_3== On)&&(Infrared_4 == On))
{
return 7;
}
return 0;
}
//小车前进
void Motor_Go()
{
Motor_1_Go;
Motor_2_Go;
Motor_3_Go;
Motor_4_Go;
}
//小车右转
void Motor_Right()
{
Motor_1_Go;
Motor_3_Go;
Motor_2_Stop;
Motor_4_Stop;
}
//小车左转
void Motor_Lift()
{
Motor_2_Go;
Motor_4_Go;
Motor_1_Stop;
Motor_3_Stop;
}
//小车停止
void Motor_Stop()
{
Motor_1_Stop;
Motor_2_Stop;
Motor_3_Stop;
Motor_4_Stop;
}
舵机
这里采用的是180度舵机,舵机是一个固定pwm输出就对应一个角度的装置。我们将舵机固定到自己的模拟垃圾桶的盖子上,实现自动控制。每次打开垃圾桶打开盖子10s后自动关闭垃圾桶盖子。
这里可以根据自己装舵机的方向,去调整舵机开关时候角度对应的pwm值。
底层配置这里就不放出来了。
if(LED_Peo) //人体红外检测到有人
{
TIM_SetCompare2(TIM3,194); //开一次垃圾桶
}
else
{
TIM_SetCompare2(TIM3,183);
}
最后完善代码逻辑。
当检测到前方有人的时候就停下,打开垃圾桶,然后关闭垃圾桶,当垃圾丢满的时候,给手机发送当前位置进行提醒。当检测到没人的时候就走。
最后附上完整的项目文件。自行下载。
https://download.csdn.net/download/weixin_42320020/88223660
这个项目到这里就算完了。
还有很多不足的地方,希望大佬可以指正。也希望和爱好者交流学习。
禁止转载!!!