基于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振荡器等
简单的结构和易用的工具
下面介绍作品:
功能简介
- 正常情况下,能查看自身运动时的加速度、角度及步数数据。
- 在跌倒情况下,能立即感应,并向已设好的从机发送命令,同时向特定的号码拨打电话。 ;
- 在总接收装置内能选择性接受并查看所有数据。
工作流程
模块介绍
软件设计
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