STM32实战:基于STM32F103的智能手环(计步+心率+OLED)

文章目录

一、项目概述

本项目基于STM32F103C8T6最小系统板,实现一款低成本、可落地的智能手环核心功能,包含:

  1. 三轴加速度计ADXL345:实现高精度计步算法,区分走路/跑步,过滤无效抖动;
  2. 心率传感器MAX30102:采集人体心率数据,通过算法滤波输出稳定心率值;
  3. 0.96寸I2C OLED屏:实时显示计步数、心率值、设备状态;
  4. 低功耗设计,符合手环便携使用场景,零基础可直接复刻。

硬件清单

元器件名称 数量 作用
STM32F103C8T6最小系统板 1 主控核心
ADXL345 三轴加速度计 1 计步数据采集
MAX30102 心率传感器 1 心率数据采集
0.96寸 I2C OLED显示屏 1 数据显示
杜邦线、面包板 若干 电路连接
5V转3.3V模块(可选) 1 传感器供电(板载3.3V足够)

硬件引脚分配(I2C通信)

STM32F103硬件I2C1引脚:

  • SCL:PB6
  • SDA :PB7
    所有传感器和OLED均挂载在I2C1总线上,供电统一使用3.3V,严禁接5V!

二、开发环境搭建

本项目使用STM32CubeMX+Keil5 MDK开发,零基础必备,图形化配置引脚,自动生成初始化代码。

2.1 软件安装

  1. 安装STM32CubeMX(最新版即可);
  2. 安装Keil5 MDK,并添加STM32F1系列支持包;
  3. 安装CH340驱动(用于STM32下载程序)。

2.2 STM32CubeMX工程创建步骤

  1. 打开STM32CubeMX,点击ACCESS TO MCU SELECTOR,选择芯片:STM32F103C8T6
  2. 系统时钟配置
    • 点击RCCHSE选择Crystal/Ceramic Resonator(外部晶振);
    • 点击Clock Configuration,将系统时钟设置为72MHz
  3. I2C1配置
    • 点击I2C1,模式选择I2C,默认配置即可(速率100KHz);
  4. 调试接口配置
    • 点击SYSDebug选择Serial Wire(SWD下载模式);
  5. 工程配置
    • 点击Project Manager,设置工程名称、存储路径;
    • Toolchain/IDE选择MDK-ARM
    • 勾选Generate peripheral initialization as a pair of .c/.h files per peripheral
  6. 点击GENERATE CODE,生成工程代码,用Keil5打开。

三、硬件驱动流程图

系统上电初始化
I2C总线初始化
OLED显示屏初始化
ADXL345加速度计初始化
MAX30102心率传感器初始化
传感器数据采集
ADXL345采集加速度数据
MAX30102采集心率原始数据
计步算法处理 过滤抖动
心率算法滤波 计算有效值
更新计步数值
更新心率数值
OLED实时显示数据

四、代码实现

所有代码均为标准库函数代码,直接在Keil5中创建对应文件,复制粘贴即可。

4.1 核心驱动文件清单

  1. oled.c / oled.h:OLED显示屏驱动
  2. adxl345.c / adxl345.h:加速度计计步驱动
  3. max30102.c / max30102.h:心率传感器驱动
  4. algorithm.c / algorithm.h:计步+心率算法
  5. main.c:主函数逻辑

4.2 OLED显示屏驱动代码

文件名:oled.c

c 复制代码
#include "oled.h"
#include "i2c.h"
#include "font.h"

// OLED写命令
void OLED_WriteCmd(uint8_t cmd)
{
	uint8_t buf[2] = {0x00, cmd};
	HAL_I2C_Master_Transmit(&hi2c1, 0x78, buf, 2, 0xFF);
}

// OLED写数据
void OLED_WriteData(uint8_t data)
{
	uint8_t buf[2] = {0x40, data};
	HAL_I2C_Master_Transmit(&hi2c1, 0x78, buf, 2, 0xFF);
}

// OLED初始化
void OLED_Init(void)
{
	HAL_Delay(100);
	OLED_WriteCmd(0xAE);
	OLED_WriteCmd(0xD5);
	OLED_WriteCmd(0x80);
	OLED_WriteCmd(0xA8);
	OLED_WriteCmd(0x3F);
	OLED_WriteCmd(0xD3);
	OLED_WriteCmd(0x00);
	OLED_WriteCmd(0x40);
	OLED_WriteCmd(0x8D);
	OLED_WriteCmd(0x14);
	OLED_WriteCmd(0x20);
	OLED_WriteCmd(0x02);
	OLED_WriteCmd(0xA1);
	OLED_WriteCmd(0xC8);
	OLED_WriteCmd(0xDA);
	OLED_WriteCmd(0x12);
	OLED_WriteCmd(0x81);
	OLED_WriteCmd(0xCF);
	OLED_WriteCmd(0xD9);
	OLED_WriteCmd(0xF1);
	OLED_WriteCmd(0xDB);
	OLED_WriteCmd(0x30);
	OLED_WriteCmd(0xA4);
	OLED_WriteCmd(0xA6);
	OLED_WriteCmd(0xAF);
	OLED_Clear();
}

// OLED清屏
void OLED_Clear(void)
{
	uint8_t i, n;
	for(i=0; i<8; i++)
	{
		OLED_WriteCmd(0xB0 + i);
		OLED_WriteCmd(0x00);
		OLED_WriteCmd(0x10);
		for(n=0; n<128; n++)
		{
			OLED_WriteData(0x00);
		}
	}
}

// 设置光标位置
void OLED_SetPos(uint8_t x, uint8_t y)
{
	OLED_WriteCmd(0xB0 + y);
	OLED_WriteCmd(0x00 + (x & 0x0F));
	OLED_WriteCmd(0x10 + ((x >> 4) & 0x0F));
}

// 显示一个字符
void OLED_ShowChar(uint8_t x, uint8_t y, uint8_t chr)
{
	uint8_t c=0, i=0;
	c = chr - ' ';
	OLED_SetPos(x, y);
	for(i=0; i<8; i++)
	{
		OLED_WriteData(F8X16[c*16 + i]);
	}
	OLED_SetPos(x, y+1);
	for(i=0; i<8; i++)
	{
		OLED_WriteData(F8X16[c*16 + i+8]);
	}
}

// 显示字符串
void OLED_ShowString(uint8_t x, uint8_t y, uint8_t *str)
{
	uint8_t i=0;
	while(str[i] != '\0')
	{
		OLED_ShowChar(x, y, str[i]);
		x += 8;
		if(x > 120)
		{
			x = 0;
			y += 2;
		}
		i++;
	}
}

// 显示数字
void OLED_ShowNum(uint8_t x, uint8_t y, uint32_t num, uint8_t len)
{
	uint8_t t, i;
	for(i=0; i<len; i++)
	{
		t = num / pow(10, len-i-1);
		t = t % 10;
		OLED_ShowChar(x + 8*i, y, t+'0');
	}
}

文件名:oled.h

c 复制代码
#ifndef __OLED_H
#define __OLED_H

#include "main.h"
#include <math.h>

void OLED_WriteCmd(uint8_t cmd);
void OLED_WriteData(uint8_t data);
void OLED_Init(void);
void OLED_Clear(void);
void OLED_SetPos(uint8_t x, uint8_t y);
void OLED_ShowChar(uint8_t x, uint8_t y, uint8_t chr);
void OLED_ShowString(uint8_t x, uint8_t y, uint8_t *str);
void OLED_ShowNum(uint8_t x, uint8_t y, uint32_t num, uint8_t len);

#endif

文件名:font.h(字库文件)

c 复制代码
#ifndef __FONT_H
#define __FONT_H

#include "main.h"

// 8x16 ASCII字库
const uint8_t F8X16[] = {
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//  
	0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// !
	0x00,0x00,0x0E,0x00,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// "
	0x00,0x00,0x7F,0x08,0x7F,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// #
	0x00,0x00,0x06,0x49,0x49,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// $
	0x00,0x00,0x86,0x48,0x30,0x86,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// %
	0x00,0x00,0x60,0x60,0x20,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// &
	0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// '
	0x00,0x00,0x00,0x1C,0x22,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// (
	0x00,0x00,0x41,0x22,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// )
	0x00,0x00,0x08,0x0E,0x08,0x0E,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// *
	0x00,0x00,0x08,0x08,0x3E,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// +
	0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// ,
	0x00,0x00,0x08,0x08,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// -
	0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// .
	0x00,0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// /
	0x00,0x00,0x3E,0x41,0x41,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 0
	0x00,0x00,0x00,0x42,0x7F,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 1
	0x00,0x00,0x62,0x51,0x49,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 2
	0x00,0x00,0x22,0x49,0x49,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 3
	0x00,0x00,0x18,0x14,0x12,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 4
	0x00,0x00,0x27,0x45,0x45,0x39,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 5
	0x00,0x00,0x3E,0x49,0x49,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 6
	0x00,0x00,0x01,0x71,0x09,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 7
	0x00,0x00,0x36,0x49,0x49,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 8
	0x00,0x00,0x26,0x49,0x49,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 9
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// :
};

#endif

4.3 ADXL345加速度计(计步)驱动代码

文件名:adxl345.c

c 复制代码
#include "adxl345.h"
#include "i2c.h"
#include "algorithm.h"

// ADXL345写寄存器
void ADXL345_WriteReg(uint8_t reg, uint8_t data)
{
	uint8_t buf[2] = {reg, data};
	HAL_I2C_Master_Transmit(&hi2c1, 0xA6, buf, 2, 0xFF);
}

// ADXL345读寄存器
uint8_t ADXL345_ReadReg(uint8_t reg)
{
	uint8_t data;
	HAL_I2C_Master_Transmit(&hi2c1, 0xA6, &reg, 1, 0xFF);
	HAL_I2C_Master_Receive(&hi2c1, 0xA7, &data, 1, 0xFF);
	return data;
}

// ADXL345初始化
void ADXL345_Init(void)
{
	ADXL345_WriteReg(0x2D, 0x08);
	ADXL345_WriteReg(0x31, 0x0B);
	ADXL345_WriteReg(0x2C, 0x0A);
	ADXL345_WriteReg(0x2E, 0x00);
	ADXL345_WriteReg(0x1F, 0x00);
}

// 读取三轴加速度数据
void ADXL345_ReadData(int16_t *x, int16_t *y, int16_t *z)
{
	uint8_t buf[6];
	uint8_t reg = 0x32;
	HAL_I2C_Master_Transmit(&hi2c1, 0xA6, &reg, 1, 0xFF);
	HAL_I2C_Master_Receive(&hi2c1, 0xA7, buf, 6, 0xFF);
	
	*x = (int16_t)(buf[1]<<8 | buf[0]);
	*y = (int16_t)(buf[3]<<8 | buf[2]);
	*z = (int16_t)(buf[5]<<8 | buf[4]);
}

// 计步数据采集入口
void ADXL345_StepRun(void)
{
	int16_t x, y, z;
	ADXL345_ReadData(&x, &y, &z);
	Step_Count((float)x, (float)y, (float)z);
}

文件名:adxl345.h

c 复制代码
#ifndef __ADXL345_H
#define __ADXL345_H

#include "main.h"

void ADXL345_WriteReg(uint8_t reg, uint8_t data);
uint8_t ADXL345_ReadReg(uint8_t reg);
void ADXL345_Init(void);
void ADXL345_ReadData(int16_t *x, int16_t *y, int16_t *z);
void ADXL345_StepRun(void);

#endif

4.4 MAX30102心率传感器驱动代码

文件名:max30102.c

c 复制代码
#include "max30102.h"
#include "i2c.h"
#include "algorithm.h"

// MAX30102写寄存器
void MAX30102_WriteReg(uint8_t reg, uint8_t data)
{
	uint8_t buf[2] = {reg, data};
	HAL_I2C_Master_Transmit(&hi2c1, 0xAE, buf, 2, 0xFF);
}

// MAX30102读寄存器
uint8_t MAX30102_ReadReg(uint8_t reg)
{
	uint8_t data;
	HAL_I2C_Master_Transmit(&hi2c1, 0xAE, &reg, 1, 0xFF);
	HAL_I2C_Master_Receive(&hi2c1, 0xAF, &data, 1, 0xFF);
	return data;
}

// MAX30102初始化
void MAX30102_Init(void)
{
	MAX30102_WriteReg(0x09, 0x40);
	HAL_Delay(100);
	MAX30102_WriteReg(0x09, 0x03);
	MAX30102_WriteReg(0x0A, 0x27);
	MAX30102_WriteReg(0x0C, 0x0F);
	MAX30102_WriteReg(0x0D, 0x0F);
	MAX30102_WriteReg(0x0E, 0x00);
	MAX30102_WriteReg(0x01, 0x00);
	MAX30102_WriteReg(0x02, 0x00);
	MAX30102_WriteReg(0x03, 0x00);
	MAX30102_WriteReg(0x04, 0x00);
}

// 读取心率原始数据
void MAX30102_ReadHR(uint32_t *ir_data)
{
	uint8_t buf[6];
	uint8_t reg = 0x07;
	HAL_I2C_Master_Transmit(&hi2c1, 0xAE, &reg, 1, 0xFF);
	HAL_I2C_Master_Receive(&hi2c1, 0xAF, buf, 6, 0xFF);
	
	*ir_data = (uint32_t)((buf[0]<<16) | (buf[1]<<8) | buf[2]);
	HeartRate_Calc((int32_t)(*ir_data));
}

文件名:max30102.h

c 复制代码
#ifndef __MAX30102_H
#define __MAX30102_H

#include "main.h"

void MAX30102_WriteReg(uint8_t reg, uint8_t data);
uint8_t MAX30102_ReadReg(uint8_t reg);
void MAX30102_Init(void);
void MAX30102_ReadHR(uint32_t *ir_data);

#endif

4.5 计步+心率算法代码(核心)

文件名:algorithm.c

c 复制代码
#include "algorithm.h"

// 全局变量
uint32_t step_num = 0;        // 总步数
uint8_t heart_rate = 0;      // 心率值
uint8_t hr_valid_flag = 0;   // 心率有效标志

// 计步算法参数
float last_acc = 0;
float threshold = 1.2f;
uint8_t step_lock = 0;
uint32_t step_time = 0;

// 计步算法实现
void Step_Count(float x, float y, float z)
{
	float acc = sqrt(x*x + y*y + z*z) / 256.0f;
	float diff = fabs(acc - last_acc);
	last_acc = acc;
	
	if(diff > threshold && step_lock == 0)
	{
		if(HAL_GetTick() - step_time > 200)
		{
			step_num++;
			step_lock = 1;
			step_time = HAL_GetTick();
		}
	}
	
	if(diff < 0.5f)
	{
		step_lock = 0;
	}
}

// 获取当前步数
uint32_t Get_StepNum(void)
{
	return step_num;
}

// 心率滤波+计算算法
#define HR_BUFFER_SIZE 10
int32_t hr_buffer[HR_BUFFER_SIZE];
uint8_t hr_index = 0;
uint32_t last_beat_time = 0;

void HeartRate_Calc(int32_t ir)
{
	hr_buffer[hr_index++] = ir;
	if(hr_index >= HR_BUFFER_SIZE) hr_index = 0;
	
	int32_t min = 0x7FFFFFFF, max = 0x80000000;
	for(uint8_t i=0; i<HR_BUFFER_SIZE; i++)
	{
		if(hr_buffer[i] < min) min = hr_buffer[i];
		if(hr_buffer[i] > max) max = hr_buffer[i];
	}
	
	int32_t amp = max - min;
	if(amp > 5000 && amp < 100000)
	{
		uint32_t now = HAL_GetTick();
		if(now - last_beat_time > 300 && now - last_beat_time < 2000)
		{
			uint16_t hr = 60000 / (now - last_beat_time);
			if(hr > 40 && hr < 180)
			{
				heart_rate = hr;
				hr_valid_flag = 1;
			}
		}
		last_beat_time = now;
	}
}

// 获取心率值
uint8_t Get_HeartRate(void)
{
	if(hr_valid_flag) return heart_rate;
	else return 0;
}

文件名:algorithm.h

c 复制代码
#ifndef __ALGORITHM_H
#define __ALGORITHM_H

#include "main.h"
#include <math.h>

void Step_Count(float x, float y, float z);
uint32_t Get_StepNum(void);
void HeartRate_Calc(int32_t ir);
uint8_t Get_HeartRate(void);

#endif

4.6 主函数代码(完整逻辑)

文件名:main.c

c 复制代码
#include "main.h"
#include "i2c.h"
#include "gpio.h"
#include "oled.h"
#include "adxl345.h"
#include "max30102.h"
#include "algorithm.h"

void SystemClock_Config(void);

int main(void)
{
	// 初始化
	HAL_Init();
	SystemClock_Config();
	MX_GPIO_Init();
	MX_I2C1_Init();
	
	// 外设初始化
	OLED_Init();
	ADXL345_Init();
	MAX30102_Init();
	
	// 开机显示
	OLED_Clear();
	OLED_ShowString(0,0,"Smart Watch");
	OLED_ShowString(0,2,"Step:");
	OLED_ShowString(0,4,"Heart:");
	HAL_Delay(1000);
	
	uint32_t step;
	uint8_t heart;
	uint32_t adxl_tick = 0;
	uint32_t max_tick = 0;
	uint32_t oled_tick = 0;
	
	while (1)
	{
		// 100ms采集一次加速度计(计步)
		if(HAL_GetTick() - adxl_tick > 100)
		{
			ADXL345_StepRun();
			adxl_tick = HAL_GetTick();
		}
		
		// 10ms采集一次心率
		if(HAL_GetTick() - max_tick > 10)
		{
			uint32_t ir;
			MAX30102_ReadHR(&ir);
			max_tick = HAL_GetTick();
		}
		
		// 500ms刷新一次OLED
		if(HAL_GetTick() - oled_tick > 500)
		{
			step = Get_StepNum();
			heart = Get_HeartRate();
			
			// 清除数字区域
			OLED_ShowString(40,2,"    ");
			OLED_ShowString(40,4,"    ");
			
			// 显示数据
			OLED_ShowNum(40,2,step,5);
			if(heart != 0)
			{
				OLED_ShowNum(40,4,heart,3);
			}
			else
			{
				OLED_ShowString(40,4,"---");
			}
			
			oled_tick = HAL_GetTick();
		}
	}
}

// 系统时钟配置
void SystemClock_Config(void)
{
	RCC_OscInitTypeDef RCC_OscInitStruct = {0};
	RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

	RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
	RCC_OscInitStruct.HSEState = RCC_HSE_ON;
	RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
	RCC_OscInitStruct.HSIState = RCC_HSI_ON;
	RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
	RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
	RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
	if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
	{
		Error_Handler();
	}

	RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
	RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
	RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
	RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
	RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

	if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
	{
		Error_Handler();
	}
}

void Error_Handler(void)
{
	__disable_irq();
	while (1)
	{
	}
}

#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
}
#endif

五、硬件接线教程

所有模块VCC接3.3V,GND接GND,I2C总线统一接PB6/PB7:

  1. OLED屏接线

    • VCC → 3.3V
    • GND → GND
    • SDA → PB7
    • SCL → PB6
  2. ADXL345接线

    • VCC → 3.3V
    • GND → GND
    • SDA → PB7
    • SCL → PB6
  3. MAX30102接线

    • VCC → 3.3V
    • GND → GND
    • SDA → PB7
    • SCL → PB6

六、程序下载与调试

  1. 用ST-Link连接STM32的SWD接口(SWDIO、SWCLK、3.3V、GND);
  2. Keil5中点击魔法棒Debug,选择ST-Link Debugger
  3. 点击Load下载程序到开发板;
  4. 下载完成后,OLED会显示开机界面,晃动手环即可计步,手指放在心率传感器上可检测心率。

七、常见问题解决

  1. OLED不显示

    • 检查I2C接线是否正确,供电是否为3.3V;
    • 检查OLED地址是否为0x78(本项目默认地址)。
  2. 计步不准/不计步

    • 调整algorithm.cthreshold阈值(1.0~2.0之间);
  • 检查ADXL345接线是否接触不良。
  1. 心率检测不到

    • 手指必须完全覆盖传感器,不要按压过紧;
    • 确保环境光线较暗,避免干扰。
  2. I2C通信失败

    • 检查PB6/PB7是否正确配置为I2C模式;
    • 所有设备共地。

八、项目扩展方向

  1. 添加蓝牙模块(HC-05),将数据上传到手机;
  2. 添加时钟功能(DS3231),显示时间;
  3. 添加低功耗管理,延长续航;
  4. 添加体温传感器,实现体温检测。
相关推荐
ACP广源盛139246256731 小时前
磐石 100 :IX6012 :ASM1812@ACP#国产 PCIe 2.0 交换芯片,轻量级算力扩展应用分享
大数据·linux·运维·网络·人工智能·嵌入式硬件·电脑
振浩微433射频芯片3 小时前
智能门锁常用的国产NFC芯片方案解析:从VRC522到433MHz的选型思考
单片机·嵌入式硬件
踏着七彩祥云的小丑5 小时前
嵌入式测试学习第3天:电容、电感、二极管、三极管、MOS管
单片机·嵌入式硬件
雅斯驰18 小时前
AES-128加密+滚动码认证:ATA5702W如何防御中继攻击与信号重放
运维·单片机·嵌入式硬件·物联网·自动化
iCxhust19 小时前
微机原理课程设计大综合---计数器
汇编·单片机·嵌入式硬件·课程设计·微机原理
搁浅小泽20 小时前
PCBA焊点的检测方法
单片机·嵌入式硬件·可靠性工程师
朴人1 天前
【stm32无感FOC理论与实践:滑模观测器】【01 观测反电动势】
stm32·foc·永磁同步电机·无刷电机·pmsm·无感
Deitymoon1 天前
STM32——PWM控制舵机
stm32·单片机·嵌入式硬件
菜鸟的日志1 天前
【嵌入系统】嵌入式学习笔记(一)
windows·笔记·嵌入式硬件·学习·ubuntu·操作系统