[i=s] 本帖最后由 宇岚 于 2025-5-14 19:21 编辑 [/i]<br />
<br />
#申请原创# #技术资源#
一、简介
随着科技持续进步,人们对于健康的要求越来越高,智能可穿戴手表应运而生;本项目旨在使用常见不同模块实现简易的智能手表框架,主控选型上采用极海半导体推出的工业级基础拓展型MCU:APM32E030R8T6,这款MCU集成搭载 Arm® Cortex®-M0 + 内核,工作主频 72MHz,采用 12 寸 55nm 先进工艺,具有内置 64KB Flash、8KB SRAM、2 个 I2C、2 个 USART、2个 位高精度 ADC 等丰富资源,符合本次项目要求;
二、系统框图
本项目使用APM32E030R8T6作为主控,使用到的模块有:DS18B20、MAX30102、ATGM336H以及ADXL345等,可实现温度、血压、血氧的测量、GPS定位、计时功能以及步数感应功能;

三、模块实现
下面将从模块原理、硬件设计和程序设计三部分详细介绍各个模块的实现思路:
温度传感器
温度获取功能使用的是DS18B20,其控制命令和数据都是以数字信号的方式输入输出,相比较于模拟温度传感器,具有功能强大、硬件简单、易扩展、抗干扰性强等特点.
模块工作原理
DS18B20作为单线半双工通信,共有6种信号类型:复位脉冲、应答脉冲、写0、写1、读0和读1;

复位脉冲:主机输出低电平保持至少480us,然后释放总线,电平拉高保持15~60us;

应答信号:DS18B20拉低电平保持60~240us;

写时序:写"0" 输出低电平60us,释放总线延迟2us; 写"1" 输出低电平2us,释放总线延迟60us;

读时序:输出电平延时2us,转输入模式延时12us,读取总线电平(15us以内),延时50us;

硬件设计

引脚描述:
引脚名称 |
描述 |
VCC |
供给电压5V |
GND |
地线 |
I/O |
通信引脚,接PA12 |
程序设计
第一步,模块初始化,初始化PA12引脚,配置其为上拉推挽模式;
u8 DS18B20_Init(void)
{
GPIO_Config_T GPIO_InitStructure;
RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOA); //使能PORTA口时钟
GPIO_InitStructure.pin = GPIO_Pin_12; //PORTA12 推挽输出
GPIO_InitStructure.mode = GPIO_Mode_Out_PP; //配置为输出
GPIO_InitStructure.speed = GPIO_Speed_50MHz;
GPIO_Config(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_PIN_12); //输出12
DS18B20_Rst();
}
第二步,复位模块,先拉低PA12引脚5ms,再拉高PA12引脚保持5ms;
第三步,发送指令0xCC,跳过ROM是,再发送指令0x44,开启转换,最后发送0xBE,读取数据;
short DS18B20_Get_Temp(void)
{
u8 temp;
u8 TL,TH;
short tem;
DS18B20_Start (); // ds1820 start convert
delay_ms(5); //延迟5ms
DS18B20_Rst(); //ds18b20 复位
delay_ms(5); //延迟5ms
DS18B20_Check();
DS18B20_Write_Byte(0xcc); // 发送0xCC
DS18B20_Write_Byte(0x44); // 发送0x44
DS18B20_Write_Byte(0xbe); // 发送0xBE
TL=DS18B20_Read_Byte(); // LSB
TH=DS18B20_Read_Byte(); // MSB
if(TH>7)
{
TH=~TH;
TL=~TL;
temp=0;//温度为负
}else temp=1;//温度为正
tem=TH; //获得高八位
tem<<=8;
tem+=TL;//获得底八位
tem=(float)tem*0.625;//转换
if(temp)return tem; //返回温度值
else return -tem;
}
第四步,读取两个字节 TH 和 TL ;
第五步,根据DS18B20的温度运算法则进行数据处理;
至此,DS18B20模块读取温度功能实现;
GPS定位模块
ATGM336H是一种高性能的GPS模块,可以在较低功耗下提供高精度、高可靠性的位置信息服务。它采用了SiRFstarIII技术,并支持多种导航卫星系统,包括GPS、GLONASS、Galileo、QZSS和SBAS。ATGM336H可以快速获取卫星信号,提供高达10Hz的位置刷新速率,并能在较弱的GPS信号环境下保持高精度。
模块工作原理
我们将模块的TX和RX通过串口通信串口助手,ATGM336H利用串口发送定位信息给主控芯片,串口波特率为9600,可以看到,模块会通过串口不断打印**数据;**

其中信息头的第一个是消息ID,通过查阅芯片手册,简单的含义如下:
缩写标识符 |
含义 |
BD |
BDS,北斗二代卫星系统 |
GP |
GPS |
GL |
GLONASS |
GA |
Galileo |
GN |
GNSS,全球卫星导航系统 |
需要关注其中的“GNRMC”这条信息,将这条信息解析:
$GNRMC,015135.000,A,4159.65553,N,12136.79345,E,0.52,0.00,191123,,,A*7F
- 消息ID —— \$GNRMC
- 定位点的UTC时间 —— 015135.000
- 定位状态 —— A:定位;V:导航(我们进行定位时,如果该位为A表示数据有效,该位为V表示数据无效)
- 纬度 —— 4159.65553
- 纬度方向 —— N
- 经度 —— 12136.79345
- 经度方向 —— E
硬件设计
实物图如下

引脚定义以及接线如下表所示
引脚名称 |
描述 |
VCC |
电源(3.3V-5V) |
GND |
地线 |
TXD |
发送引脚,接PA9 |
RXD |
接收引脚,接PA10 |
PPS |
时钟脉冲引脚,PA11 |
软件设计
第一步,初始化模块,初始化USART1模块的两个引脚PA9和PA10,配置串口波特率为9600;
第二步,等待ATGM336H信号连接成功,当连接成功时,PPS引脚会拉低再拉高;
void ATGM336_Baisc_Init(void) //模块信号引脚初始化
{
GPIO_Config_T GPIO_InitStructure; //定义一个设置GPIO功能的变量
RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOA); //使能GPIOA时钟
uart1_Init(9600); //串口初始化
GPIO_InitStructure.pin = GPIO_Pin_11; //准备设置PA11
GPIO_InitStructure.speed = GPIO_Speed_50MHz; //IO速率50M
GPIO_InitStructure.mode = GPIO_Mode_IPD; //下拉输入
GPIO_Config(GPIOA, &GPIO_InitStructure); //设置PA11
}
void ATGM336_Init(void)
{
int i;
uart1_Init(9600); //USART1初始化
bool Point_flag;
while(!GPIO_ReadInputBit(GPIOA,GPIO_Pin_11)) //等待PPS引脚拉低
{
if(Point_flag == 0){ //显示函数
for(i=0;i<11;i++)
{
for(i=0;i<11;i++)OLED_ShowChar(0+(i*4),7,' ',1,0);delay_ms(10);
Point_flag = 1;
}
}
else
{ //显示函数
for(i=0;i<11;i++){OLED_ShowChar(0+(i*4),7,' ',1,0);}
Point_flag = 0;
delay_ms(10);
}
if(setc == 0)
break;////如果拉低,跳出循环
}
if(GPIO_ReadInputBit(GPIOA,GPIO_Pin_11))//改变标志位
GPS_state = 1;
for(i=0;i<9;i++){OLED_ShowChar(0+(i*4),7,' ',1,0);}
}
第三步,USART模块接收信息并解析
void GetsGpsBuffer()
{
char *subString;
char *subStringNext;
char i = 0;
char usefullBuffer[2];
if (Save_Data.isGetData)
{
Save_Data.isGetData = false;
//截取数据帧前六部分 |对地航速 对地航向 日期
//$GNRMC,112536.000,A,2322.75023,N,11326.28605,E,| 0.00, 0.00, 100722,,,A*78
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)
{
switch (i)
{
// 获取UTC时间
case 1:memcpy(Save_Data.UTCTime, subString, subStringNext - subString);break;
// 获取UTC时间
case 2:memcpy(usefullBuffer, subString, subStringNext - subString);break;
// 获取纬度信息
case 3:memcpy(Save_Data.latitude, subString, subStringNext - subString);break;
// 获取N/S
case 4:memcpy(Save_Data.N_S, subString, subStringNext - subString);break;
// 获取经度信息
case 5:memcpy(Save_Data.longitude, subString, subStringNext - subString);break;
// 获取E/W
case 6:memcpy(Save_Data.E_W, subString, subStringNext - subString);break;
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); // 解析错误
}
}
}
}
}
第四步,数据转换,获取的信息里,单位是**“度-分”,需要将其转换为常用单位“度”;
void Data_Transfor (void)
{
float latitude_temp1,latitude_temp2_min,latitude = 0, ; // 存储纬度信息
float longitude_temp1,longitude_temp2_min,longitude = 0; // 存储经度信息
latitude = strtod(receDataFrame.latitude,NULL); // 字符串转换成浮点数
longitude = strtod(receDataFrame.longitude,NULL); // 字符串转换成浮点数
// 纬度信息处理
latitude_temp1 = (uint16_t)latitude/100; //提取度-分中度的不分
latitude_temp2_min = (latitude%100 )/60 //提取度-分中,分的部分并将其转为度
latitude = (float)latitude_temp1 + latitude_temp2_min;
// 经度信息处理
// 五位经度信息
longitude_temp1 = (uint16_t)longitude/100; //提取度-分中度的不分
longitude_temp2_min = (longitude%100 )/60 //提取度-分中,分的部分并将其转为度
latitude = (float)longitude_temp1 + longitude_temp2_min;
}
至此,GPS模块功能实现完成
四、文献出处
1.本片所涉及软件代码基于APM32E030官方SDK库,可在官网直接下载使用;
https://www.geehy.com/design/document
2.本问所设计参考文章有:
https://blog.csdn.net/qq_44016222/article/details/141892460?ops_request_misc=%257B%2522request%255Fid%2522%253A%252200602cae32b01e8caf708299723effe6%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=00602cae32b01e8caf708299723effe6&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-2-141892460-null-null.142^v102^pc_search_result_base6&utm_term=max30102%E5%BF%83%E7%8E%87%E8%A1%80%E6%B0%A7%E4%BC%A0%E6%84%9F%E5%99%A8&spm=1018.2226.3001.4187 -----MAX30102心率血氧传感器(IIC协议 STM32)-CSDN博客
https://blog.csdn.net/qq_44016222/article/details/141891589?ops_request_misc=%257B%2522request%255Fid%2522%253A%25225a1bfb03841971f12cfefecb83cbb8c1%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=5a1bfb03841971f12cfefecb83cbb8c1&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-141891589-null-null.142^v102^pc_search_result_base6&utm_term=ADXL345&spm=1018.2226.3001.4187
-----【STM32外设系列】GPS定位模块(ATGM336H)-CSDN博
3.由于篇幅原因,该项目分为上下两章详细描述;
下篇地址贴上,有兴趣的友友们可以前往: https://bbs.21ic.com/icview-3452194-1-1.html
基于APM32E030R8T6为主控的智能手表方案,作者着重介绍了项目的整体框架以及温度传感器和GPS定位定位模块的使用。期待后续作品。