基于STM32F103的老人摔倒报警装置

暑假里搞了一下数学建模,然后其余时间学了一些STM32,大概上是把一些基础的东西都弄明白了,更高级的操作只能等以后有时间再做深究了。这个摔倒报警装置是本人第一次用32做的一个小项目了,部分模块的代码是直接移植正点原子的,大家有什么问题的话可以多看一下正点原子的代码,写的还是很不错的。初学32,感觉能做出这样一个作品还是比较有成就感的,希望大家有什么问题都能和我一起探讨一下,共同进步!

简述STM32F103

ARM公司的高性能"Cortex-M3"内核
1.25DMips/MHz,而ARM7TDMI只有0.95DMips/MHz
一流的外设
1μs的双12位ADC,4兆位/秒的UART,18兆位/秒的SPI,18MHz的I/O翻转速度
低功耗
在72MHz时消耗36mA(所有外设处于工作状态),待机时下降到2μA
最大的集成度
复位电路、低电压检测、调压器、精确的RC振荡器等
简单的结构和易用的工具

下面介绍作品:

功能简介

  1. 正常情况下,能查看自身运动时的加速度、角度及步数数据。
  2. 在跌倒情况下,能立即感应,并向已设好的从机发送命令,同时向特定的号码拨打电话。
  3. 在总接收装置内能选择性接受并查看所有数据。

工作流程

工作流程

模块介绍

NRF24L01和MPU6050

OLED和SIM800C

软件设计

Part 1:
在单片机1中通过MPU6050的DMP处理器自主处理原始数据,得到pitch、roll、yaw这三个角度数据和加速度,减少的单片机的运算量,降低负荷,再通过NRF24L01在循环中传输经过处理之后的数据,兼顾到MP6050的噪声较大和单片机数据刷新需要较快,循环分为一组三次,每三次的传输,第一次发送数据到地址一,第二次发送数据到地址二,第三次将数据舍弃,并重复该过程。同时在发送过程中,在数据的末尾加上校验位,检验数据发送是否正确,是否有误发误收的情况。

Part 2:
在单片机2中,利用中断接收单片机1所发送的数据,以减少主程序的工作量,接收到数据之后在OLED上实时显示3种航向角数据,在中断接受数据的同时,对数据进行处理,检测老人是否摔倒,如果检测出摔倒,中断中立刻赋值标志位,在主程序执行的时候判断标志位是否为一,然后通过SIM800C模块对已经设定好的电话号码进行拨打。从而达到呼救和提醒家人的目的。

Part 3:
单片机3中可以接受前两块单片机所有传输的数据,按下按键KEY_0,是查看单片机1所发送的加速度数据,按下按键KEY_1是查看单片机1发送的航向角数据,按下按键KEY_UP是查看单片机2发送的数据。

部分代码(发送数据方)

#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "timer.h"
#include "led.h"
#include "mpu6050.h"
#include "inv_mpu.h"
#include "inv_mpu_dmp_motion_driver.h" 
#include "24l01.h" 
 


extern u8 TX_ADDRESS[TX_ADR_WIDTH];
extern u8 RX_ADDRESS[RX_ADR_WIDTH];


//串口1发送1个字符 
//c:要发送的字符
void usart1_send_char(u8 c)
{   	
	while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET); //循环发送,直到发送完毕   
	USART_SendData(USART1,c);  
} 

//传送数据给匿名四轴上位机软件(V2.6版本)
//fun:功能字. 0XA0~0XAF
//data:数据缓存区,最多28字节!!
//len:data区有效数据个数
void usart1_niming_report(u8 fun,u8*data,u8 len)
{
	u8 send_buf[32];
	u8 i;
	if(len>28)return;	//最多28字节数据 
	send_buf[len+3]=0;	//校验数置零
	send_buf[0]=0X88;	//帧头
	send_buf[1]=fun;	//功能字
	send_buf[2]=len;	//数据长度
	for(i=0;i<len;i++)send_buf[3+i]=data[i];			//复制数据
	for(i=0;i<len+3;i++)send_buf[len+3]+=send_buf[i];	//计算校验和	
	for(i=0;i<len+4;i++)usart1_send_char(send_buf[i]);	//发送数据到串口1 
}


//发送加速度传感器数据和陀螺仪数据
//aacx,aacy,aacz:x,y,z三个方向上面的加速度值
//gyrox,gyroy,gyroz:x,y,z三个方向上面的陀螺仪值
void mpu6050_send_data(short aacx,short aacy,short aacz,short gyrox,short gyroy,short gyroz)
{
	u8 tbuf[12]; 
	tbuf[0]=(aacx>>8)&0XFF;
	tbuf[1]=aacx&0XFF;
	tbuf[2]=(aacy>>8)&0XFF;
	tbuf[3]=aacy&0XFF;
	tbuf[4]=(aacz>>8)&0XFF;
	tbuf[5]=aacz&0XFF; 
	tbuf[6]=(gyrox>>8)&0XFF;
	tbuf[7]=gyrox&0XFF;
	tbuf[8]=(gyroy>>8)&0XFF;
	tbuf[9]=gyroy&0XFF;
	tbuf[10]=(gyroz>>8)&0XFF;
	tbuf[11]=gyroz&0XFF;
	usart1_niming_report(0XA1,tbuf,12);//自定义帧,0XA1
}	

//通过串口1上报结算后的姿态数据给电脑
//aacx,aacy,aacz:x,y,z三个方向上面的加速度值
//gyrox,gyroy,gyroz:x,y,z三个方向上面的陀螺仪值
//roll:横滚角.单位0.01度。 -18000 -> 18000 对应 -180.00  ->  180.00度
//pitch:俯仰角.单位 0.01度。-9000 - 9000 对应 -90.00 -> 90.00 度
//yaw:航向角.单位为0.1度 0 -> 3600  对应 0 -> 360.0度
void usart1_report_imu(short aacx,short aacy,short aacz,short gyrox,short gyroy,short gyroz,short roll,short pitch,short yaw)
{
	u8 tbuf[28]; 
	u8 i;
	for(i=0;i<28;i++)tbuf[i]=0;//清0
	tbuf[0]=(aacx>>8)&0XFF;
	tbuf[1]=aacx&0XFF;
	tbuf[2]=(aacy>>8)&0XFF;
	tbuf[3]=aacy&0XFF;
	tbuf[4]=(aacz>>8)&0XFF;
	tbuf[5]=aacz&0XFF; 
	tbuf[6]=(gyrox>>8)&0XFF;
	tbuf[7]=gyrox&0XFF;
	tbuf[8]=(gyroy>>8)&0XFF;
	tbuf[9]=gyroy&0XFF;
	tbuf[10]=(gyroz>>8)&0XFF;
	tbuf[11]=gyroz&0XFF;	
	tbuf[18]=(roll>>8)&0XFF;
	tbuf[19]=roll&0XFF;
	tbuf[20]=(pitch>>8)&0XFF;
	tbuf[21]=pitch&0XFF;
	tbuf[22]=(yaw>>8)&0XFF;
	tbuf[23]=yaw&0XFF;
	usart1_niming_report(0XAF,tbuf,28);//飞控显示帧,0XAF
} 




 int main(void)
 {	
  u8 report=1;			//默认开启上报
	u16 t=0;
	u32 step_cnt;
	u32 res;
	u16 i;
	u8 address1[5]={0x34,0x43,0x10,0x10,0x02};
	u8 address2[5]={0x34,0x43,0x10,0x10,0x03};
	u8 tmp_buf[33];
	float pitch,roll,yaw; 		//欧拉角
	short aacx,aacy,aacz;		//加速度传感器原始数据
	short gyrox,gyroy,gyroz;	//陀螺仪原始数据
	short temp;					//温度	
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	 //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
	uart_init(500000);	 	//串口初始化为500000
	delay_init();	//延时初始化 
	LED_Init();		  			//初始化与LED连接的硬件接口
	MPU_Init();					//初始化MPU6050
	NRF24L01_Init(); 
	 
	 
 	/*u16 led0pwmval=0;
	u16 a=17000;
	u8 dir=1;	
	delay_init();	    	 //延时函数初始化	  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 	 //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
	uart_init(115200);	 //串口初始化为115200
 	LED_Init();			     //LED端口初始化
 	TIM3_PWM_Init(19999,71);	 // 72分频,最高频率20000
  while(1)
	{
 		delay_ms(500);	 
		if(dir)led0pwmval+=500;
		else led0pwmval-=500;

 		if(led0pwmval>18000)dir=0;
		if(led0pwmval==0)dir=1;		
		a+=500;
		if(a>19500) a=17500;
		TIM_SetCompare2(TIM3,a);   //以45°为基本转动单位
		LED0=!LED0;
		delay_ms(200);
	 }	*/
  while(mpu_dmp_init()&&NRF24L01_Check())	
	{
		delay_ms(200);
	}
	while(1)
	{
		NRF24L01_TX_Mode();
		if(mpu_dmp_get_data(&pitch,&roll,&yaw)==0)
		{ 
			temp=MPU_Get_Temperature();	//得到温度值
			MPU_Get_Accelerometer(&aacx,&aacy,&aacz);	//得到加速度传感器数据
			MPU_Get_Gyroscope(&gyrox,&gyroy,&gyroz);	//得到陀螺仪数据
			res=dmp_get_pedometer_step_count(&step_cnt);
			if(res)step_cnt=0;
			if(report)mpu6050_send_data(aacx,aacy,aacz,gyrox,gyroy,gyroz);//用自定义帧发送加速度和陀螺仪原始数据
			if(report)usart1_report_imu(aacx,aacy,aacz,gyrox,gyroy,gyroz,(int)(roll*100),(int)(pitch*100),(int)(yaw*10));
			//LED0=!LED0;
			//delay_ms(200);
			if(t%3==0)
			{   
				for(i=0;i<5;i++)
				{
					TX_ADDRESS[i]=address1[i];
					RX_ADDRESS[i]=address1[i];
				}
			  tmp_buf[0]=temp/1000+'0';
		    tmp_buf[1]=temp/100%10+'0';
		    tmp_buf[2]=temp/10%10+'0';
		    tmp_buf[3]=temp%10+'0';
		    temp=pitch*10;
		    if(temp<0)
	    	{
		    	temp=-temp;
		    	tmp_buf[4]='-';
	    	}
	  	  else
	  		  tmp_buf[4]='+';
	      tmp_buf[5]=temp/1000+'0';
	  	  tmp_buf[6]=temp/100%10+'0';
		  tmp_buf[7]=temp/10%10+'0';
		  tmp_buf[8]=temp%10+'0';
				
				temp=roll*10;
		    if(temp<0)
	    	{
		    	temp=-temp;
		    	tmp_buf[9]='-';
	    	}
	  	  else
	  	    tmp_buf[9]='+';
	      tmp_buf[10]=temp/1000+'0';
	  	  tmp_buf[11]=temp/100%10+'0';
		  tmp_buf[12]=temp/10%10+'0';
		  tmp_buf[13]=temp%10+'0';
				
			temp=yaw*10;
		    if(temp<0)
	    	{
		    	temp=-temp;
		    	tmp_buf[14]='-';
	    	}
	  	  else
	  		  tmp_buf[14]='+';
	    	tmp_buf[15]=temp/1000+'0';
	  	  tmp_buf[16]=temp/100%10+'0';
		    tmp_buf[17]=temp/10%10+'0';
		    tmp_buf[18]=temp%10+'0';
	  	  
				temp=step_cnt;
		    if(temp<0)
	    	{
		    	temp=-temp;
		    	tmp_buf[19]='-';
	    	}
	  	  else
	  		  tmp_buf[19]='+';
	    	tmp_buf[20]=temp/1000+'0';
	  	  tmp_buf[21]=temp/100%10+'0';
		    tmp_buf[22]=temp/10%10+'0';
		    tmp_buf[23]=temp%10+'0';
				tmp_buf[27]=0+'0';//校验位
				
	  	  NRF24L01_TxPacket(tmp_buf);//向NRF1传输数据(航向角数据)
				//delay_ms(10);
		    
				
				LED0=!LED0;
	      delay_ms(100);
		  }
			if(t%3==1)
			{
				for(i=0;i<5;i++)
				{
					TX_ADDRESS[i]=address2[i];
					RX_ADDRESS[i]=address2[i];
				}
				tmp_buf[0]=temp/1000+'0';
		    tmp_buf[1]=temp/100%10+'0';
		    tmp_buf[2]=temp/10%10+'0';
		    tmp_buf[3]=temp%10+'0';
				
				temp=aacx*10;
		    if(temp<0)
	    	{
		    	temp=-temp;
		    	tmp_buf[4]='-';
	    	}
	  	  else
	  		  tmp_buf[4]='+';
	    	tmp_buf[5]=temp/10000+'0';
	  	  tmp_buf[6]=temp/1000%10+'0';
		    tmp_buf[7]=temp/100%10+'0';
		    tmp_buf[8]=temp/10%10+'0';
				tmp_buf[9]=temp%10+'0';
				
				temp=aacy*10;
		    if(temp<0)
	    	{
		    	temp=-temp;
		    	tmp_buf[10]='-';
	    	}
	  	  else
	  	    tmp_buf[10]='+';
	    	tmp_buf[11]=temp/10000+'0';
	  	  tmp_buf[12]=temp/1000%10+'0';
		    tmp_buf[13]=temp/100%10+'0';
		    tmp_buf[14]=temp/10%10+'0';
				tmp_buf[15]=temp%10+'0';
				
				temp=aacz*10;
		    if(temp<0)
	    	{
		    	temp=-temp;
		    	tmp_buf[16]='-';
	    	}
	  	  else
	  		  tmp_buf[16]='+';
	    	tmp_buf[17]=temp/10000+'0';
	  	  tmp_buf[18]=temp/1000%10+'0';
		    tmp_buf[19]=temp/100%10+'0';
		    tmp_buf[20]=temp/10%10+'0';
				tmp_buf[21]=temp%10+'0';
	  	  
				temp=step_cnt;
		    if(temp<0)
	    	{
		    	temp=-temp;
		    	tmp_buf[22]='-';
	    	}
	  	  else
	  		  tmp_buf[22]='+';
	    	tmp_buf[23]=temp/1000+'0';
	  	  tmp_buf[24]=temp/100%10+'0';
		    tmp_buf[25]=temp/10%10+'0';
		    tmp_buf[26]=temp%10+'0';
				tmp_buf[27]=1+'0';//校验位
				
				NRF24L01_TxPacket(tmp_buf);//向NRF2传输数据(加速度数据)
				
				LED0=!LED0;
	      delay_ms(100);
			}
			t++;
			if(t==100)t=0;
			//LED0=!LED0;
	    //delay_ms(200);
	  }
		//LED0=!LED0;
	  //delay_ms(200);
	} 	
 }
 
 

遇到的问题

1.NRF一发多收,一收多发数据相互干扰
2.在外部中断接受NRF数据,但是中断进不去
3.MPU6050传输数据不稳定,噪声较大

学习STM32F103的感悟

学习两个月的STM32F103ZET6,从看正点原子的视频开始,慢慢理解库函数如何开发,串口通信,无线通信,以及TFT屏,OLED屏,各类传感器模块,再到从ZET6的程序移植到C8T6上的程序,对定时器,外部中断的配置理解更深,学会看开发指南,查芯片手册数据手册,对着原理图接线,出现问题及时用仿真器硬件调试。对于大多数问题都有了自己的认识。在今后的学习过程中,可能会深入到更高级的应用中去,类似于SD卡,文件操作,UCOS,EMWIN,也可能学习性能更高的F4、H7系列。

全部代码请见链接:
https://download.csdn.net/download/weixin_44062268/11729330

  • 11
    点赞
  • 144
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
基于STM32F103R6的声光报警器程序需要利用STM32F103R6微控制器的特性和功能,实现声音和光线的报警功能。 首先,我们需要连接声音和光线传感器到相应的引脚上,以检测环境中的声音和光线强度。可以使用ADC模块对模拟信号进行采样,或者使用GPIO模块对数字信号进行读取。 然后,在主程序中设置一个循环,不断读取环境中的声音和光线数据。可以通过编程语言的延时函数来控制采样频率。通过比较采样值和预设的阈值,判断是否触发报警。 当声音或光线强度超过预设阈值时,触发报警动作。可以通过PWM模块来控制蜂鸣器的频率和占空比,产生不同的声音。同时,可以通过控制LED的亮灭来实现光线报警。 在报警过程中,可以配合LCD显示模块,显示相关信息,如报警种类、报警级别等。还可以加入按键控制,通过按键来设置报警阈值和关闭报警功能。 基于STM32F103R6的声光报警器程序还可以进行功能扩展。例如,利用网络模块添加远程监控功能,将报警信息发送至服务器;或者添加存储模块,记录报警信息以备查阅。 总结起来,基于STM32F103R6的声光报警器程序能够针对环境中的声音和光线强度进行监测,一旦超过预设阈值,触发声音和光线报警,实现及时的警报功能。这种程序可以应用于许多场景,如家庭安防、工业监测等。
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值