目录
一、设计背景和意义
1.1设计背景
随着人们生活质量的不断提升,宠物在人类生活中的地位逐渐从"陪伴者"上升为"家庭成员"。尤其在城市生活节奏加快、人口结构变化的背景下,宠物成为许多家庭缓解孤独、丰富精神生活的重要方式。然而,与之相对的是,宠物饲养过程中的管理难题也逐渐凸显。尤其是在宠物活动自由度较高的情况下,宠物意外走失、突发健康状况未被及时察觉等问题频繁发生,给宠物本身带来潜在风险,也让主人承受了不小的心理与经济负担。目前市面上虽已有部分宠物定位设备或健康监测产品,但普遍存在功能单一、系统集成度低、智能化水平不高的问题。许多产品仅能实现基础的GPS定位功能,无法同步监测宠物的健康数据,且缺乏有效的互动方式,例如远程语音唤回或状态告警等,无法在紧急情况下为主人提供有力支持。部分带有心率或体温监测功能的高端设备虽然技术先进,但价格昂贵,难以大范围普及。
1.2设计意义
本研究的实施不仅能够提升宠物看护的智能化水平,提高宠物安全与健康保障能力,还可以为后续智能宠物硬件的开发提供理论支撑和实践基础。更重要的是,该系统具有良好的推广前景,不仅适用于普通家庭养宠场景,也可延伸应用于宠物医院、寄养中心、动物救助机构等多种领域,对推动智慧养宠、促进宠物科技产业发展具有积极的现实意义与长远价值。
二、实物效果展示
2.1实物图片

2.2实物演示视频
【开源】基于STM32的宠物防丢监控定位系统
三、硬件功能简介
3.1项目功能详解
1)心率血氧检测:检测宠物的心率、血氧数据。
2)体温检测:检测宠物的体温数据。
3)阈值设定:设定宠物的心率、血氧、体温的阈值数据。
4)异常报警:心率、血氧、体温数据超过阈值,蜂鸣器报警。
5)GPS定位:实时定位宠物的经纬度坐标数据。
6)蓝牙App:与系统进行连接,将心率、血氧、体温、经纬度数据。
7)远离报警:当宠物远离蓝牙的范围,自动开启报警提醒主人。
8)语音呼唤:当宠物远离主人的蓝牙手机范围,语音呼唤宠物返回。
9)数据显示:0.96OLED屏幕显示全部的传感器数据以及传感器的阈值等数据。
3.2元器件清单
- 主控STM32F103C8T6最小系统板
- 0.96OLED显示屏幕
- JDY-31蓝牙模块
- DS18B20温度传感器
- MAX30102心率血氧传感器
- GPS定位模块
- 按键
四、主框图与软件流程图
主框图

流程图

五、硬件PCB展示


六、软件程序设计
cpp
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
//#include "OLED.h"
#include "string.h"
#include "max30102.h"
#include "ds18b20.h"
#include "beep.h"
#include "key.h"
#include "timer.h"
#include "oled.h"
/**** 数据变量 ****/
#define STM32_RX1_BUF Usart1RecBuf
#define STM32_Rx1Counter Rx1Counter
#define STM32_RX1BUFF_SIZE USART1_RXBUFF_SIZE
#define GPS_STR_LEN 48
unsigned char display[16];
int temp_door = 38; //体温上限
int oxy_door = 90; //血氧下限
int heart_door = 100; //心率上线
uint8_t send_flag = 0;
uint8_t send_time = 3;
uint8_t printd_flag = 0;
/**** 菜单变量 ****/
uint8_t option = 0; //阈值选项
uint8_t key_num = 0; //按键赋值
uint8_t page_id = 1; //页面ID
/**** 功能函数声明 ****/
void oled_show_onepage(); //第一屏显示内容
void oled_show_twopage(); //第二屏显示内容
void get_all_sensor_data(); //传感器数据采集
void Sensor_Data_Handle(); //不同模式下控制效果
int main(void)
{
delay_init();
OLED_Init(); //OLED初始化
uart2_init(9600);
USART1_Config();
uart3_init(9600);
DS18B20_Init();
MAX30102_Init();
un_min=0x3FFFF;
un_max=0;
Max30102_right_data();
BEEP_Init();
beep = 0;
KEY_Init();
TIME_Config();
while(1)
{
get_all_sensor_data(); //传感器数据采集
if(Time_Period[1]>1000) //Time_Period[1] 在定时器中累加
{
Time_Period[1] = 0;
if(page_id == 1){ //屏幕更新
oled_show_onepage();
}else if(page_id == 2){
oled_show_twopage();
}
if(send_flag==1){ //发送语音提醒
send_time++;
if(send_time>=5){
send_time=0;
BY_U2_SendBuff(sound_buf,7);
}
}
printd_flag = !printd_flag;
if(printd_flag==1){ //蓝牙消息发送
printf("\r\n\r\n\r\n\r\n");
printf("*********************\r\n");
printf("心率:%d次/分钟 血氧:%d%%\r\n",dis_hr,dis_spo2);
printf("体温:%d℃\r\n",body_temp);
printf("经度:%10.6f\r\n",longitude_Degree);
printf("纬度:%10.6f\r\n",latitude_Degree);
printf("*********************\r\n");
}
}
Sensor_Data_Handle(); //数据处理
}
}
void Sensor_Data_Handle()
{
//体温超过上限 或 心率超过上限 或 血氧低于下限且大于0,蜂鸣器报警提醒
if(body_temp>temp_door||dis_hr>heart_door||(dis_spo2<oxy_door&&dis_spo2>0))beep=1;
else beep=0;
}
void get_all_sensor_data() //获取数据
{
body_temp = DS18B20_Get_Temp(); //获取体温数据
Get_Max30102_Data(); //获取心率血氧
}
// 心(0) 率(1) 血(2) 氧(3) 体(4) 温(5) ℃(6) 宠(7) 物(8) 状(9) 态(10) 正(11) 常(12) 经(13) 纬(14) 度(15) 阈(16) 值(17)
void oled_show_onepage(){
OLED_ShowChinese(16*0,0,0,16,1); //心
OLED_ShowChinese(16*1,0,1,16,1); //率
OLED_ShowChar(16*2,0,':',16,1);
OLED_ShowNum(16*2+8,0,dis_hr,3,16,1); //心率数据
OLED_ShowChinese(16*4,0,2,16,1); //血
OLED_ShowChinese(16*5,0,3,16,1); //氧
OLED_ShowChar(16*6,0,':',16,1);
OLED_ShowNum(16*6+8,0,dis_spo2,3,16,1); //血氧数据
OLED_ShowChinese(16*0,16,4,16,1); //体
OLED_ShowChinese(16*1,16,5,16,1); //温
OLED_ShowChar(16*2,16,':',16,1);
OLED_ShowNum(16*2+8,16,body_temp,2,16,1); //体温数据
OLED_ShowNum(16*6+8,16,lanya_flag,3,16,1);
sprintf((char *)display,"%10.6f ",longitude_Degree);
OLED_ShowChinese(16*0,32,13,16,1); //经
OLED_ShowChinese(16*1,32,15,16,1); //度
OLED_ShowChar(16*2,32,':',16,1);
OLED_ShowString(16*3,32,(u8*)display,16, 1);//显示经度
sprintf((char *)display,"%10.6f ",latitude_Degree);
OLED_ShowChinese(16*0,48,14,16,1); //纬
OLED_ShowChinese(16*1,48,15,16,1); //度
OLED_ShowChar(16*2,48,':',16,1);
OLED_ShowString(16*3,48,(u8*)display,16, 1);//显示纬度
OLED_Refresh();
}
void oled_show_twopage(){
uint8_t a,b,c,d;
if(option==1){a=0;b=1;c=1;d=1;}
else if(option==2){a=1;b=0;c=1;d=1;}
else if(option==3){a=1;b=1;c=0;d=1;}
else {a=1;b=1;c=1;d=1;}
OLED_ShowChinese(16*0,0,0,16,1); // "心"
OLED_ShowChinese(16*1,0,1,16,1); // "率"
OLED_ShowChinese(16*2,0,16,16,1); // "阈"
OLED_ShowChinese(16*3,0,17,16,1); // "值"
OLED_ShowChar(16*4,0,':',16,1); // ":"
OLED_ShowNum(16*4+8,0,heart_door,3,16,a); // heart_door
OLED_ShowChinese(16*0,16,2,16,1); // "血"
OLED_ShowChinese(16*1,16,3,16,1); // "氧"
OLED_ShowChinese(16*2,16,16,16,1); // "阈"
OLED_ShowChinese(16*3,16,17,16,1); // "值"
OLED_ShowChar(16*4,16,':',16,1); // ":"
OLED_ShowNum(16*4+8,16,oxy_door,3,16,b); // oxy_door
OLED_ShowChinese(16*0,32,4,16,1); // "体"
OLED_ShowChinese(16*1,32,5,16,1); // "温"
OLED_ShowChinese(16*2,32,16,16,1); // "阈"
OLED_ShowChinese(16*3,32,17,16,1); // "值"
OLED_ShowChar(16*4,32,':',16,1); // ":"
OLED_ShowNum(16*4+8,32,temp_door,3,16,c); // temp_door
OLED_Refresh();
}
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) //检测更新中断是否发生
{
key_num = KEY_Scan(0); //按键扫描赋值
switch(key_num)
{
case 1: //按键1按下
if(page_id==1){
page_id=2;
OLED_Clear();oled_show_twopage();
}else if(page_id==2){
option++;
if(option>3){
option=0;
page_id=1;
OLED_Clear();oled_show_onepage();
}else oled_show_twopage();
}
break;
case 2: //按键2按下
if(page_id==2){
if(option==1)heart_door+=1;
else if(option==2)oxy_door+=1;
else if(option==3)temp_door+=1;
oled_show_twopage();
}
break;
case 3: //按键3按下
if(page_id==2){
if(option==1)heart_door-=1;
else if(option==2)oxy_door-=1;
else if(option==3)temp_door-=1;
oled_show_twopage();
}
break;
case 4: //按键4按下
lanya_flag = 0; //未连接蓝牙时,按键手动将标志位置0
break;
}
Time_Period[0]++;
Time_Period[1]++;
if(Time_Period[0]>1000)
{
lanya_flag++; //蓝牙断连后,标志位每秒钟累加
if(lanya_flag>=10)send_flag=1; //超过10之后,开始发送提醒语音
else send_flag=0;
Time_Period[0] = 0;
}
TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清楚更新中断标志位,如果不清除,会一直进中断
}
}
七、项目资料包内容
