网络知识 娱乐 基于STM32设计的老人防摔倒报警设备(OneNet)

基于STM32设计的老人防摔倒报警设备(OneNet)

1. 前言

我国独生子女,以及人口老龄化等问题,正逐渐成为一个重大的社会问题,老年人机体能力的下降,摔倒引起的安全和危害愈来愈突出,国家和社会越来越关注老年人的健康和安全,开发一个能够实时检测出老年人是否摔倒,并且能及时告知监护人的摔倒检测以及报警系统具有重要的现实意义。本系统包括检测摔倒模块、GPS定位模块和通信模块三部分,通过检测老年人日常状态,可以得知老年人的状态,如果监测到老年人摔倒了,此时会通过网络把检测结果发出,获得老年人摔倒地点的GPS定位,并且通过GPRS通讯发短信给预设的监护人。

2. 设计需求

(1)针对老年人现实需求,针对老年人室内、外活动或出行的安全监测要求,比较选择合理的技术方案,设计系统功能
(2) 通过查阅文献和调研比较,可选择基于加速度传感器、陀螺仪、摄像头等单传感器,或多传感器融合的方式,配合适当的检测算法,进行状态检测判断;
(3)方案确定后,开发设计电路板、检测模块、定位模块、通信模块等,设计开发可穿戴式设备,配合算法,检测摔倒情况,准确率达到85%以上。
(4)检测到摔倒等意外情况后,能通过网络将GPS定位信息、时间、摔倒等信息,通过适当的方式进行报警和通知监护人。
(5)监测数据可通过网络发送到云平台进行处理;

功能总结:

(1)采用STM32单片机作为主控芯片,配合其他模块完成功能设计

(2)通信模块采用SIM800C,支持上传采集的GPS经纬度数据到云端服务器,云端采用OneNet物联网平台。

(3)老人摔倒检测采用MPU6050陀螺仪检测,当检测到老人摔倒之后,会通过SIM800C发送短信到紧急联系人,设备上的蜂鸣器会发出警报声,周围行人听到也可以进行帮助;并且会将GPS数据上传到云端,通过地图显示老人的位置,家人通过短信知道老人摔倒后,通过云端地图显示的位置,可以快速赶到老人身边,或者报警求助,报告位置。

(4)老人摔倒后,如果自己能行动,没有大问题,可以自己按下设备上的按键取消蜂鸣器报警,并且通过SIM800C向家人发送一条短信,报平安。

image-20220420095034592

image-20220420095049894

image-20220420095105080

image-20220420101301592

image-20220420101636550

image-20220427103141400

image-20220427103207490

3. 硬件选型

主控芯片采用STM32RCT6,通信模块采用SIM800C,GPS采集使用ATGM336北斗BDS+GPS双模模块,老人摔倒检测模块采用MPU6050陀螺仪。

3.1 SIM800C

SIM800C模块是一款高性能高性价比工业级的GSM/GPRS模块。本模块采用SIMCOM公司的工业级四频850/900/ 1800/1900MHz SM800芯片,可以低功耗实现语音、SMS、数据和传真信息的传输。

image-20220411154906282

模块特点:

1、支持极限DC5V-18V宽电压输入

2、有电源使能开关引脚EN

3、支持锂电池供电接口VBAT3.5-4.5V

4、输入支持移动和联通手机卡Micro SIM卡

5、送51/STM32/ARDUINO驱动例程

image-20220416115302900

1、DC 5V-18V电源输入,推荐使用DC 9V

2、电源开始使能引脚默认使能

3、电源地

4、GSM模块的TXD引脚接其它模块的RXD

5、GSM模块的RXD引脚接其它模块的TXD

6、数据终端准备

7、内核音频输出引脚

8、内核音频输出引脚

9、锂电池输入引脚,DC 3.5 - 4.5V

10、电源地

11、启动引脚和GND短路可实现开机自启动

12、电源地

13、RTC外置电池引脚

14、内核振铃提示引脚

15、内合音频输入引脚

16、内核音频输入引脚

加粗的引脚一般都用到。

image-20220416120423490

建议使用V_IN单独供电DC5-18V输入(推荐使用9V),或者VBAT供电锂电池两种供电方式这两种供电方式最稳定。如果只是简单调试,也可使用USB-TTL或者开发板的5V直接给模块供电。不过一般电脑或者开发板的功率有限,可能会不稳定。请根据具体情况自己取舍选择合适电源。

总结:

模块本身支持自适应波特率,可以自动根据发送过去的指令计算对应的波特率,一般使用115200即可。

模块调试总结:

(1)供电电压5V也可以,采用电脑USB供电(直接插电脑USB口)。正常供电之后,模块上有电源指示灯。

(2)SIM800C的TX脚接单片机的RX脚

(3)SIM800C的RX脚接单片机的TX脚

(4)SIM800C的第11个引脚(PWK)和12个引脚(GND)短接接在一起,才可以开机。

image-20220416121804182

电源正常后,右上角有一个黄色的电源灯。

image-20220416121820844

通过串口发送AT指令过去测试模块效果。

image-20220416124331731

3.2 STM32F103C8T6开发板

image-20220415212842500

3.3 GPS模块

GPS模块正常定位后,模块上的LED灯会按照1秒钟闪烁一次。

返回的字段里 G N R M C 表示当前定位的 G P S 经纬度,解析代码只需要解析 GNRMC表示当前定位的GPS经纬度,解析代码只需要解析 GNRMC表示当前定位的GPS经纬度,解析代码只需要解析GNRMC字段。

第一次启动GPS模块,定位差不多要几分钟时间,定位成功后,第二次启动定位就很快,最好是在室外,室内信号差,定位时间更久。

$GNGGA,114955.000,2842.4158,N,11549.5439,E,1,05,3.8,54.8,M,0.0,M,,*4F
$GNGLL,2842.4158,N,11549.5439,E,114955.000,A,A*4D
$GPGSA,A,3,10,31,18,,,,,,,,,,5.7,3.8,4.2*37
$BDGSA,A,3,07,10,,,,,,,,,,,5.7,3.8,4.2*2A
$GPGSV,3,1,10,10,49,184,42,12,16,039,,14,54,341,,18,22,165,23*7B
$GPGSV,3,2,10,22,11,318,,25,51,055,,26,24,205,,29,13,110,*7C
$GPGSV,3,3,10,31,50,287,36,32,66,018,*7F
$BDGSV,1,1,04,03,,,07,05,,,29,07,79,246,33,10,52,232,19*62
$GNRMC,114955.000,A,2842.4158,N,11549.5439,E,0.00,44.25,061117,,,A*4D
$GNVTG,44.25,T,,M,0.00,N,0.00,K,A*14
$GNZDA,114955.000,06,11,2017,00,00*47
$GPTXT,01,01,01,ANTENNA OK*35

链接:https://item.taobao.com/item.htm?spm=a230r.1.14.1.19e01b15k6vJWG&id=550058686581&ns=1&abbucket=11#detail

image-20220415202559464

3.4 MPU6050陀螺仪

image-20220417111522704

3.5 蜂鸣器

image-20220415203419349

4. 创建产品与设备

4.1 创建产品

官网地址: https://open.iot.10086.cn/

image-20220408143221729

image-20220408143241526

image-20220408143327664

image-20220408143350583

4.2 创建设备

点击创建好的产品名称,进入设备创建页面。

image-20220408143506700

添加设备。

image-20220408143526173

image-20220408143643023

添加成功会,点击详情,查看详细信息。

image-20220408143702421

添加APIkey

image-20220408143751585

image-20220408143821165

设备添加成功。

image-20220408143845361

这个页面的设备ID和APIKEY需要保存下来,接下来SIM800C上传数据到onenet平台,就需要使用这个参数。

设备ID  :  920668935
APIKey :  XMwqaSZATs=ZlXq4Tk4NA44WTl4=

4.3 创建数据流模板

image-20220408144101594

image-20220408144132950

添加成功。

image-20220408144155641

5. STM32程序设计

如果需要整个项目资料以及完整的源码,可以去这里下载:
https://download.csdn.net/download/xiaolong1126626497/85896547

这里有项目运行的演示视频:

基于STM32设计的老人防摔倒报警设备(OneNet)

5.1 硬件接线

SIM800C接线说明:
GND----GND
PA2----SIM800C_RXD
PA3----SIM800C_TXD

CH340模块接线说明:
GND----GND
RX-----PA9

GPS接线说明: (波特率需要根据GPS模块实际情况进行修改)
GND----GND
VCC---3.3V
PB11----GPS_TX


蜂鸣器模块:  高电平响
BEEP----->PB8

板载LED灯:
LED1--PC13  低电平亮


板载按键: 
KEY1--PA0  按下为高电平


外接按键:
KEY1 -PB3 按下是低电平
KEY2 -PB2 按下是低电平


外接LED灯模块:
LED1-PB4 低电平亮
LED2-PB5 低电平亮


硬件接线:
1 VCC 3.3V/5V 电源输入     ---->3.3V
2 GND 地线                  --->接GND
3 IIC_SDA IIC 通信数据线     -->PB6
4 IIC_SCL IIC 通信时钟线		   -->PB7
5 MPU_INT 中断输出引脚			 ---->未接
6 MPU_AD0 IIC 从机地址设置引脚-->PA15
			AD0引脚说明:ID=0X68(悬空/接 GND) ID=0X69(接 VCC)
			
			
注意:陀螺仪初始化的时候,必须正常摆放才可以初始化成功

5.2 keil工程

image-20220420094337682

image-20220420095901589

5.3 原理图

最终的设计需要画PCB板,打板,下面是绘制的原理图和PCB板子效果。

image-20220420094522472

image-20220420094719548

5.4 main.c代码

#include "stm32f10x.h"
#include "delay.h"
#include "usart.h"
#include 
#include "timer.h"
#include "sim800c.h"
#include "gps.h"
#include "mpu6050.h"
#include "inv_mpu.h"
#include "inv_mpu_dmp_motion_driver.h" 
#include "led.h"
#include "key.h"
#include 

u8 mpu6050_fall_flag=0; //跌倒警告  1跌倒  0正常

u32 OneNet_Sendtime=0;
u32 time_cnt=0;

//烟雾超标提示
u8 sim800c_buff[100];
double Longitude=120.196517; //经度
double latitude=30.194493;  //纬度


//跌倒检测
#define g 1024
#define PI 3.14
uint8_t tumble_count = 0;
void tumble_handle(short ax,short ay,short az)
{
    uint16_t result = 0;
    uint16_t angle_x;
    uint16_t angle_y;    
    uint16_t angle_z;
 
    result = sqrt(ax * ax + ay * ay + az * az);
 
    //判断为静止
    if (result < g ) 
    {
        printf("没有摔倒.!rn");
    }
 
    angle_x = (atan(ax / sqrt(ay * ay + az * az))) * 180 / PI;
    angle_y = (atan(ay / sqrt(ax * ax + az * az))) * 180 / PI;
    angle_z = (atan(az / sqrt(ax * ax + ay * ay))) * 180 / PI;
 
 
    if ((abs(angle_x) > 45 ) || (abs(angle_y) > 45) || (abs(angle_z) > 45 )) 
    {
        tumble_count ++;
        if (tumble_count >= 3) 
        {
            printf("摔倒.rn");
            tumble_count = 0;
        }
    }
    else 
    {
        tumble_count = 0;
    }
}


int main(void)
{
    u8 key_val=0;
    u8 key2_val=0;
    short aacx,aacy,aacz;		//加速度传感器原始数据
	u32 state=0;
	USART_X_Init(USART1,72,115200); //串口初始化
	printf("串口初始化完成!rn");
    
    //板载蜂鸣器
    beep_init();
  
    //板载按键初始化
    KEY_Init();
    //板载LED灯初始化
    LED_Init();
    
    //外接LED初始化
    LED2_Init();
    //外接按键初始化
    KEY2_Init();
    
    //接SIM800C
	TIM2_Init(72,20000);//辅助串口3接收,超时时间为20ms
    USART_X_Init(USART2,36,115200); //可能的波特率(测试):  57600 、9600、115200
	
    //接GPS模块
	USART_X_Init(USART3,36,9600);//接GPS模块
    TIM3_Init(72,20000);//辅助串口3接收,超时时间为20ms
	
    while(MPU6050_Init())							//初始化MPU6050
    {
        printf("MPU6050陀螺仪初始化失败!rn");
        DelayMs(1000);
    }
    while(1)
    {
        state=mpu_dmp_init();
        if(state==0)break;
        printf("MPU6050陀螺仪设置DMP失败!  temp=%d rn",state);
        DelayMs(1000);
    }
    printf("正常程序执行!rn");
    
	//延时等待
	printf("延时等待rn");
	DelayMs(1000);
	DelayMs(1000);
	DelayMs(1000);
	DelayMs(1000);
	printf("开始初始化SIM800C rn");
	
	//初始化SIM800C  
	while(1)
	{
			state=SIM800C_InitCheck();
			if(state==0)break;
			DelayMs(1000);
			printf("SIM800C初始化状态:%drn",state);
	}
	
	//设置文本模式
    while(1)
	{
			state=SIM800C_SetNoteTextMode();
			if(state==0)break;
			DelayMs(1000);
			printf("设置文本模式状态:%drn",state);
	}
	//同步网络时间
	//SIM800C_NtpUpdate();
	
  printf("正在进行GPRS数据通信初始化.rn");
	//GPRS数据通信初始化
	state=SIM800C_GPRS_Init();
  printf("GPRS数据通信初始化:%drn",state);
  
	while(1)
	{
        delay_ms(1);
        OneNet_Sendtime++;
        time_cnt++;
        
        //板载按键值获取
        key_val=KEY_GetValue();
        //按键按下
        if(key_val)
        {
            BEEP=!BEEP;
            BEEP2=!BEEP2;
            mpu6050_fall_flag=!mpu6050_fall_flag;
            printf("板载按键按下.!rn");
            printf("mpu6050_fall_flag:%drn",mpu6050_fall_flag);
        }
        
      
//        //外接按键初始化
//        key2_val=KEY2_GetValue();
//        //按键按下
//        if(key2_val)
//        {
//            BEEP=!BEEP;
//            printf("外接按键按下.!rn");  
//        }
        
        //状态灯闪烁
        if(time_cnt>=200)
        {
            time_cnt=0;
            LED1=!LED1;
        }
        
		 //向云端发送一次数据(每次选择发送一种数据)
		 if(OneNet_Sendtime>=4000) //单位ms
		 {
            printf("时间到达.上传数据...rn");
            OneNet_Sendtime=0;
			      
            
              MPU6050_Get_Data(&aacx,&aacy,&aacz);	//得到加速度传感器数据
              printf("加速度传感器数据:x=%d y=%d z=%drn",aacx,aacy,aacz);
              
             //跌倒检测夹角检测判断--方式1
             tumble_handle(aacx,aacy,aacz);
                 
             //通过Z轴的变化判断摔倒姿态--方式2
             //具体环境需要根据实测的数据进行调试
              if(aacz<-13851)
              {
                    BEEP=1;
                    BEEP2=1;
                    mpu6050_fall_flag=1;
                    printf("摔倒...rn");
              }
              
                //判断老人是否摔倒
                 if(mpu6050_fall_flag)
                 {
                        //蜂鸣器报警
                        BEEP=0;
                        sprintf((char*)sim800c_buff,"Old man fall warning!!! Longitude:%f,latitude:%f",Longitude,latitude);
                        //发送短信
                        if(SIM800C_SendNote((u8*)"18171571217",sim800c_buff,strlen((char*)sim800c_buff))==0)
                        {
                            printf("短信发送成功rn");
                        }
                        else
                        {
                            printf("短信发送失败rn");
                        }	                
                 }
                 else
                 {
                      //向OneNet上传经纬度数据
                      OneNet_HTTP_GPS_DataUpdate("GPS",Longitude,latitude);
                 }                 
		 }
         
		//实时接收SIM800C收到的数据
         if(USART2_RX_FLAG)
         {
             USART2_RX_BUFF[USART2_RX_CNT]='';
             USART2_RX_CNT=0;
             USART2_RX_FLAG=0;
             printf("USART2_RX_BUFF=%srn",USART2_RX_BUFF);
             memset(USART2_RX_BUFF,0,sizeof(USART2_RX_BUFF));
         }
		 
         //实时接收GPS收到的数据
         if(USART3_RX_FLAG)
         {
             USART3_RX_BUFF[USART3_RX_CNT]='';
             
            //解析GPS经纬度信息
            GPS_GPRMC_Decoding(USART3_RX_BUFF,&Longitude,&latitude);
            printf("USART3_RX_BUFF=%srn",USART3_RX_BUFF);
            printf("经度:%f,纬度:%frn",Longitude,latitude);

            memset(USART3_RX_BUFF,0,sizeof(USART3_RX_BUFF));
            USART3_RX_CNT=0;
            USART3_RX_FLAG=0;
         }
	 }
}