基于STM32单片机OneNet物联网智能手环脉搏心率计步器体温显示设计

  • 1、项目简介
  • 1.1 系统功能
  • 1.2 演示视频
  • 2、部分电路设计
  • 2.1 STM32单片机核心板电路设计
  • 2.2 Pulsesensor脉搏心率传感器模块电路设计
  • 2.3 ADXL345倾角传感器模块计步电路设计
  • 2.4 LCD1602液晶显示模块电路设计
  • 2.5 ESP8266 WIFI无线通信电路设计
  • 3、单片机代码展示
  • 3.1 系统初始化
  • 3.2 LCD1602显示程序
  • 3.3 ADXL345程序


1、项目简介

1.1 系统功能

  • 本设计由STM32F103C8T6单片机核心板电路+esp8266 wifi模块+ADXL345传感器电路+心率传感器电路+温度传感器+lcd1602电路组成。
  • 功能介绍:
  • 1、通过重力加速度传感器ADXL345检测人的状态,计算出走路步数、走路距离和平均速度。
  • 2、通过心率传感器实时检测心率,通过温度传感器检测温度。
  • 3、lcd1602实时显示步数、距离和平均速度、心率以及温度值。
  • 4、连接onenet云平台,在云平台显示心率、步数、温度、距离等信息

通过本篇内容,可编写开题报告、任务书、毕业论文等。

1.2 演示视频

2、部分电路设计

2.1 STM32单片机核心板电路设计

  • 基于 ARM Cortex-M3内核的STM32F1系列单片机属于主流STM32单片机,其中增强型STM32F103子系列单片机的CPU 主频高达72MHz,片内Flash容量高达1MB,芯片引脚数量多达144个,有 QFN、LQFP、CSP、BGA 等多种芯片封装形式,并具有多种片内外设、USB接口和CAN 接口。根据STM32F103单片机片内Flash容量的不同,ST 公司将其分为小容量(16-32KB)、中等容量(64-128KB)、大容量(256KB-1MB)3种。
  • 电源电路:为单片机提供稳定的工作电压,通常采用3.3V电源供电。电源电路的设计要保证单片机在不同工作条件下都能获得稳定的电压输出,以确保单片机的正常工作。
  • 晶振电路:提供单片机工作所需的时钟信号。晶振电路通过晶振和电容组成,为单片机提供稳定的工作脉冲,确保单片机的定时和同步需求。
  • 复位电路:实现单片机的复位功能,类似于电脑的重启。复位电路通过电容和电阻的配合,实现单片机在上电启动时的自动复位,以及通过手动按键实现复位功能,保证单片机在程序跑飞或异常情况下能够重新开始执行程序。

STM32单片机是一种功能强大、易于使用、灵活且可靠的32位微控制器,基于ARM Cortex™-M内核。其主要功能特点包括:

  • 高性能和低功耗:STM32系列单片机提供多种内核选择,如Cortex-M0、Cortex-M3、Cortex-M4等,满足不同应用场景对性能的需求,同时保持低功耗特性。
  • 多种通信和外设接口:STM32单片机具备广泛的通信和外设接口,如I2C、SPI、USART、USB等,便于开发者实现各种复杂功能。
  • 易于开发和调试:STM32单片机提供了丰富的软件和硬件工具,如HAL库、CubeMX等,帮助开发者快速创建和调试嵌入式系统。
  • 高集成度和设计灵活性:STM32系列单片机全系列产品共用大部分引脚、软件和外设,优异的兼容性为开发人员带来最大的设计灵活性

单片机最小系统原理图如下图所示:


基于STM32单片机OneNet物联网智能手环脉搏心率计步器体温显示设计_课程设计

实物图:


基于STM32单片机OneNet物联网智能手环脉搏心率计步器体温显示设计_物联网_02

2.2 Pulsesensor脉搏心率传感器模块电路设计

  • 脉搏心率传感器是用来测试心跳速率的传感器,实质是一款集成了放大电路和噪声消除电路的光学心率传感器。可以通过此传感器开发出和心率有关的互动作品。传感器可以戴在手指或者耳垂上。光电传感器将脉搏信号转换为电信号,此装置需要把手指放在传感器表盘上,光电传感器,此传感器是集成了放大电路和噪声消除电路的光学心率传感器,光电传感器一侧的发光二极管发光,当脉搏跳动时,指尖或者耳垂的动脉血管血容量发生周期性变化,透过指尖的光强度同时发生变化。另一侧的光电三极管将接收到的红外光信号转化为电信号。
  • 心率检测电路由pulsesensor心率传感器与LM393比较器构成,将DO与AO引脚连接到STM32单片机引脚上,进行数据采集。

其具体电路原理图如下图所示:

基于STM32单片机OneNet物联网智能手环脉搏心率计步器体温显示设计_物联网_03

实物图如下图所示:

基于STM32单片机OneNet物联网智能手环脉搏心率计步器体温显示设计_stm32_04

基于STM32单片机OneNet物联网智能手环脉搏心率计步器体温显示设计_物联网_05

2.3 ADXL345倾角传感器模块计步电路设计

  • 本设计选择倾角传感器ADXL345模块实时检测相关的状态信息。ADXL345是一款小而薄的超低功耗3轴加速度计,分辨率高(13位),测量范围达± 16g。
  • 数字输出数据为16位二进制补码格式,可通过SPI(3线或4线)或I2C数字接口访问。ADXL345非常适合移动设备应用。它可以在倾斜检测应用中测量静态重力加速度,还可以测量运动或冲击导致的动态加速度。其高分辨率(3.9mg/LSB),能够测量不到1.0°的倾斜角度变化。
  • 该器件提供多种特殊检测功能。活动和非活动检测功能通过比较任意轴上的加速度与用户设置的阈值来检测有无运动发生。敲击检测功能可以检测任意方向的单振和双振动作。自由落体检测功能可以检测器件是否正在掉落。这些功能可以独立映射到两个中断输出引脚中的一个。

电路原理图:

  • 实物图:

2.4 LCD1602液晶显示模块电路设计

  • LCD显示器分为字段显示和字符显示两种。其中字段显示与LED显示相似,只要送对应的信号到相应的管脚就能显示。字符显示是根据需要显示基本字符。本设计采用的是字符型显示。系统中采用LCD1602作为显示器件输出信息。与传统的LED数码管显示器件相比,液晶显示模块具有体积小、功耗低、显示内容丰富等优点,而且不需要外加驱动电路,现在液晶显示模块已经是单片机应用设计中最常用的显示器件了。LCD1602可以显示2行16个汉字。

其具体电路原理图如下图所示:


基于STM32单片机OneNet物联网智能手环脉搏心率计步器体温显示设计_stm32_06



2.5 ESP8266 WIFI无线通信电路设计

  • ESP8266-01s是由安信可科技开发的Wi-Fi模块,其核心处理器是ESP8266,这款处理器在较小的尺寸封装中集成了业界领先的Tensilica L106 超低功耗 32 位微型 MCU,支持 80 MHz 和 160 MHz 的主频,并带有 16 位精简模式。ESP8266-01s 支持RTOS,集成Wi-Fi MAC/BB/RF/PA/LNA,支持标准的IEEE802.11 b/g/n协议和完整的TCP/IP协议栈。这使得用户可以为现有设备添加联网功能,或者构建独立的网络控制器。
  • ESP8266-01s 以其高性能和低成本的特性,为Wi-Fi功能的嵌入提供了无限可能,特别适用于物联网和智能家居等应用场景

其具体电路原理图如下图所示:


基于STM32单片机OneNet物联网智能手环脉搏心率计步器体温显示设计_脉搏_07



3、单片机代码展示

3.1 系统初始化

void HardWare_Init(void)
{
	Usart1_Init(115200);							//串口1,打印信息用
  Usart2_Init(115200);	 //串口2,驱动ESP8266用
  TIM3_Int_Init(49,7199);//50ms  	
  EXTIX_Init();		// 初始化外部中断

  Lcd_GPIO_init();  //初始化lcd引脚
  Lcd_Init();		  //初始化lcd屏幕
  delay_ms(200);

  Init_ADXL345();
  if(Single_Read_ADXL345(0X00)==0xe5)	
  {
    delay_ms(5);
  }
  else
  {
    delay_ms(3);
  }

  ConnectionOneNet();  //连接OneNET云平台
}

3.2 LCD1602显示程序

void Lcd_Init( void )  //初始化
{  
  Lcd_GPIO_init();
  delay_us(1500);                     //延时15ms
  Lcd_Write_Command( 0x38,0);       // 写指令38H 不检测忙信号
  delay_us(500);				      //延时5ms
  Lcd_Write_Command( 0x38,0);       // 写指令38H 不检测忙信号
  delay_us(500);					  //延时5ms
  Lcd_Write_Command( 0x38,0);       // 写指令38H 不检测忙信号
  //以后每次写指令、读/写数据操作之前需检测忙信号
  Lcd_Write_Command( 0x38,1);       //显示模式设置 
  Lcd_Write_Command( 0x08,1);		  //显示关闭
  Lcd_Write_Command( 0x01,1);       //显示清屏
  Lcd_Write_Command( 0x06,1);       //显示光标移动设置 
  Lcd_Write_Command( 0x0C,1); 	  //显示开、光标不显示
} 
/******************************************************/

void Lcd_En_Toggle(void) //发使能脉冲
{
	SET_EN;        //使能1
	delay_us(5);   //延时160us
	CLE_EN;
}

void Lcd_Busy(void)//判断忙
{
  unsigned int later0=0;
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_GPIO_DATA, ENABLE);    //打开DATA端口时钟 

  GPIO_InitStructure.GPIO_Pin  = GPIO_DATA_0_PIN|GPIO_DATA_1_PIN|GPIO_DATA_2_PIN|GPIO_DATA_3_PIN|GPIO_DATA_4_PIN|GPIO_DATA_5_PIN|GPIO_DATA_6_PIN|GPIO_DATA_7_PIN; //  DB8~DB15
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //输入模式 = 上拉输入
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50M时钟速度
  GPIO_Init(GPIO_DATA_7, &GPIO_InitStructure);      //打开忙检测端口

  CLE_RS; //RS = 0
  //delay_us(1);   //延时10us
  SET_RW; //RW = 1
  //delay_us(1);   //延时10us
  SET_EN; //EN = 1
  //delay_us(2);   //延时20us
  while ((GPIO_ReadInputDataBit(GPIO_DATA_7,GPIO_DATA_7_PIN))&&(later0<20000)) //循环等待忙检测端口 = 0
  {
    delay_us(5);
    later0++;	
  }
  CLE_EN; //EN = 0

  //恢复端口为输出状态 
  RCC_APB2PeriphClockCmd(RCC_GPIO_DATA, ENABLE);    //打开DATA端口时钟 
  GPIO_InitStructure.GPIO_Pin  = GPIO_DATA_0_PIN|GPIO_DATA_1_PIN|GPIO_DATA_2_PIN|GPIO_DATA_3_PIN|GPIO_DATA_4_PIN|GPIO_DATA_5_PIN|GPIO_DATA_6_PIN|GPIO_DATA_7_PIN; //  DB8~DB15
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50M时钟速度
  GPIO_Init(GPIO_DATA_7, &GPIO_InitStructure);
} 

void Gpio_data(unsigned char x)  //端口置入数据
{  
  GPIO_ResetBits(GPIO_DATA_0, GPIO_DATA_0_PIN);  //DB0
  GPIO_ResetBits(GPIO_DATA_0, GPIO_DATA_1_PIN);  //DB1
  GPIO_ResetBits(GPIO_DATA_0, GPIO_DATA_2_PIN);  //DB2
  GPIO_ResetBits(GPIO_DATA_0, GPIO_DATA_3_PIN);  //DB3
  GPIO_ResetBits(GPIO_DATA_0, GPIO_DATA_4_PIN);  //DB4
  GPIO_ResetBits(GPIO_DATA_0, GPIO_DATA_5_PIN);  //DB5
  GPIO_ResetBits(GPIO_DATA_0, GPIO_DATA_6_PIN);  //DB6
  GPIO_ResetBits(GPIO_DATA_0, GPIO_DATA_7_PIN);  //DB7
  if(x&0X01)GPIO_SetBits(GPIO_DATA_0, GPIO_DATA_0_PIN);//DB0
  if(x&0X02)GPIO_SetBits(GPIO_DATA_0, GPIO_DATA_1_PIN);//DB1
  if(x&0X04)GPIO_SetBits(GPIO_DATA_0, GPIO_DATA_2_PIN);//DB2
  if(x&0X08)GPIO_SetBits(GPIO_DATA_0, GPIO_DATA_3_PIN);//DB3
  if(x&0X10)GPIO_SetBits(GPIO_DATA_0, GPIO_DATA_4_PIN);//DB4
  if(x&0X20)GPIO_SetBits(GPIO_DATA_0, GPIO_DATA_5_PIN);//DB5
  if(x&0X40)GPIO_SetBits(GPIO_DATA_0, GPIO_DATA_6_PIN);//DB6
  if(x&0X80)GPIO_SetBits(GPIO_DATA_0, GPIO_DATA_7_PIN);//DB7
}


//向液晶里面写入指令  时序:RS=L,RW=L,Data0-Data7=指令码,E=高脉冲
void Lcd_Write_Command(unsigned char x,char Busy) 
{ 
  if(Busy) Lcd_Busy();
  //delay_us(1);   //延时10us
    CLE_RS;  //RS = 0 
  //delay_us(1);   //延时10us
  CLE_RW;  //RW = 0 
  //delay_us(4);   //延时40us
  Gpio_data(x);  //端口置入数据
  //delay_us(4);   //延时40us
  Lcd_En_Toggle();  //发使能脉冲
  //delay_us(1);   //延时100us
  Lcd_Busy(); //测忙

}
//毕设咨询、购买实物、毕设指导
//打开下方连接咨询:
//https://docs.qq.com/doc/DVm51bXRXS2FGZHds
//向液晶里面写入数据  时序:RS=H,RW=L,Data0-Data7=指令码,E=高脉冲
void Lcd_Write_Data( unsigned char x) //向液晶里面写入数据 
{ 
  Lcd_Busy(); //测忙
  //delay_us(1);   //延时10us
  SET_RS;   //RS = 1 
  //delay_us(1);   //延时10us
  CLE_RW;   //RW = 0
  //delay_us(4);   //延时40us
  Gpio_data(x);
  //delay_us(4);   //延时40us
  Lcd_En_Toggle();  //发使能脉冲
  //delay_us(1);   //延时100us
  Lcd_Busy(); //测忙

} 

void Lcd_SetXY(unsigned char x,unsigned char y)   //字符初始位置设定,x表示列,y表示行 
{ 
  unsigned char addr; 
  if(y==0) 
    addr=0x80+x; 
  else if(y==1)
    addr=0xC0+x; 
  Lcd_Write_Command(addr,1) ; 
} 
/******************************************************/

void Lcd_Puts(unsigned char x,unsigned char y, unsigned char *string) //向1602写一个字符串 
{ 
  Lcd_SetXY(x,y); 
  while(*string) 
  { 
    Lcd_Write_Data(*string); 
    string++; 
  } 
}

void Lcd_1Put(unsigned char x,unsigned char y, unsigned char Data0)
{
  Lcd_SetXY(x,y); 
  Lcd_Write_Data(Data0); 
}

3.3 ADXL345程序

/**************************************
向IIC总线发送一个字节数据
**************************************/
void ADXL345_SendByte(unsigned char dat)
{
    unsigned char i;
    SCL_OUT();
    SDA_OUT();
    for (i=0; i<8; i++)         //8位计数器
    {
        delay_us(5);             //延时
        if(dat&0x80)  //SDA = CY;               //送数据口
        {SET_SDA();}
        else
        {CLE_SDA();}       
        delay_us(5);             //延时
        SET_SCL();//SCL = 1;                //拉高时钟线
        delay_us(5);             //延时
        CLE_SCL();//SCL = 0;                //拉低时钟线
        dat <<= 1;              //移出数据的最高位
    }
    ADXL345_RecvACK();
}

/**************************************
从IIC总线接收一个字节数据
**************************************/
unsigned char ADXL345_RecvByte(void)
{
    unsigned char i;
    unsigned char Mid;
    unsigned char dat = 0;
    SDA_INT();
    SCL_OUT();

    for (i=0; i<8; i++)         //8位计数器
    {
        dat <<= 1;
        delay_us(5);            //延时
        SET_SCL();

			if(SDA_VAL()== Bit_SET)   //CY = SDA;                   //读应答信号
			{
				Mid = 1;
			}
			else
			{
				Mid = 0;
			}
		
//        Mid=SDA_VAL();
        if(Mid) dat++;
        delay_us(5);     
        CLE_SCL();//SCL = 0;                //拉低时钟线
    }
    return dat;
}

//******单字节写入*******************************************

void Single_Write_ADXL345(uchar REG_Address,uchar REG_data)
{
    ADXL345_Start();                  //起始信号
    ADXL345_SendByte(SlaveAddress);   //发送设备地址+写信号
    ADXL345_SendByte(REG_Address);    //内部寄存器地址,请参考中文pdf22页 
    ADXL345_SendByte(REG_data);       //内部寄存器数据,请参考中文pdf22页 
    ADXL345_Stop();                   //发送停止信号
}

//********单字节读取*****************************************
uchar Single_Read_ADXL345(uchar REG_Address)
{  uchar REG_data;
    ADXL345_Start();                          //起始信号
    ADXL345_SendByte(SlaveAddress);           //发送设备地址+写信号
    ADXL345_SendByte(REG_Address);            //发送存储单元地址,从0开始	
    ADXL345_Start();                          //起始信号
    ADXL345_SendByte(SlaveAddress+1);         //发送设备地址+读信号
    REG_data=ADXL345_RecvByte();              //读出寄存器数据
	ADXL345_SendACK(1);   
	ADXL345_Stop();                           //停止信号
    return REG_data; 
}
//*********************************************************
//
//连续读出ADXL345内部加速度数据,地址范围0x32~0x37
//
//*********************************************************
void Multiple_Read_ADXL345(void)
{   uchar i;
    ADXL345_Start();                          //起始信号
    ADXL345_SendByte(SlaveAddress);           //发送设备地址+写信号
    ADXL345_SendByte(0x32);                   //发送存储单元地址,从0x32开始	
    ADXL345_Start();                          //起始信号
    ADXL345_SendByte(SlaveAddress+1);         //发送设备地址+读信号
	 for (i=0; i<6; i++)                      //连续读取6个地址数据,存储中BUF
    {
        BUF[i] = ADXL345_RecvByte();          //BUF[0]存储0x32地址中的数据
        if (i == 5)
        {
           ADXL345_SendACK(1);                //最后一个数据需要回NOACK
        }
        else
        {
          ADXL345_SendACK(0);                //回应ACK
       }
   }
    ADXL345_Stop();                          //停止信号
    delay_ms(5);
}


//*****************************************************************

//初始化ADXL345,根据需要请参考pdf进行修改************************
void Init_ADXL345(void)
{
   Single_Write_ADXL345(0x31,0x0B);   //测量范围,正负16g,13位模式
   Single_Write_ADXL345(0x2C,0x08);   //速率设定为12.5 参考pdf13页
   Single_Write_ADXL345(0x2D,0x08);   //选择电源模式   参考pdf24页
   Single_Write_ADXL345(0x2E,0x80);   //使能 DATA_READY 中断
   Single_Write_ADXL345(0x1E,0x00);   //X 偏移量 根据测试传感器的状态写入pdf29页
   Single_Write_ADXL345(0x1F,0x00);   //Y 偏移量 根据测试传感器的状态写入pdf29页
   Single_Write_ADXL345(0x20,0x05);   //Z 偏移量 根据测试传感器的状态写入pdf29页
}