目录
1 .功能设计
本次设计实现的功能:使用称重模块对体重进行测量,将体重数值实时显示在显示屏上;使用心率采集模块,测量用户的实时心率,并将数据显示在显示屏上。可以设定心率阈值,如果数据超出正常范围,进行报警。报警方式:采用蓝牙模块,发送报警信息到用户手机上!心率的采集受开关控制,按键按下时,开启心率采集,按键没有按下,则不采集。另外,系统还有一个受开关控制的电机,按键按下时,电机转动。
功能完成后的效果如下:
演示视频如下;
智能床演示视频1
智能床演示视频2
2.硬件方案
1.单片机
单片机选择正点原子的stm32mini板,板载芯片型号是stm32f103rct6,实物图如下:
正点原子Mini板(DFRobot Romeo V2.2) 是一款开源的嵌入式开发板,具有Arduino兼容性,由DFRobot(创客工具领域的知名公司)推出。该开发板基于Atmega328P微控制器,集成了丰富的硬件资源和接口,方便开发者进行快速的原型设计和开发。
主要特点和功能包括:
1. 丰富的接口资源:板载了丰富的接口和硬件资源,包括数字输入/输出口、模拟输入口、PWM输出口、串口、I2C、SPI等,方便连接和控制外部设备。
2. USB接口:通过USB接口可以方便地与计算机进行通信和编程。
3. 电源管理:板载了稳压电路和电源管理模块,可以接受多种电源输入(5V)、并提供电源供应给其他外部设备。
4. 尺寸小巧:正点原子Mini板尺寸小巧,便于嵌入到各种项目中,适合携带和移动应用。
2.显示器
显示器选择TFT液晶屏,实物图如下:
TFT液晶屏(Thin-Film Transistor Liquid Crystal Display)是一种广泛应用于消费电子产品的平面显示技术。它采用薄膜晶体管(TFT)作为驱动元件,可实现高分辨率、高亮度和快速刷新率的图像显示。
TFT液晶屏的主要特点和优势包括:
1. 高画质和色彩表现:TFT液晶屏可以实现高分辨率的图像显示,能够呈现细腻、清晰的画面。此外,它还具有广色域和优秀的色彩表现能力,可以呈现生动逼真的图像。
2. 快速刷新率:TFT液晶屏的刷新率较高,能够实现流畅的视频播放和动画效果。
3. 视角宽广:TFT液晶屏具有广视角特性,观看角度变化时图像的亮度和对比度变化较小,使得多人同时观看时能够保持较好的显示效果。
4. 节能省电:TFT液晶屏采用薄膜晶体管作为驱动元件,其工作电流较低,能够省电和减少能源消耗。
5. 薄型轻便:TFT液晶屏结构简单,整体厚度较薄,使得产品具有较小的尺寸和轻便的特点,有利于便携性和设计创新。
TFT液晶屏广泛应用于各种电子设备中,包括智能手机、平板电脑、电视、电子显示器、汽车导航系统等。它不仅适用于个人消费电子产品,还被广泛应用于工业控制、医疗设备、广告显示和户外显示等领域。随着技术的不断进步,TFT液晶屏不断提升性能,未来可能会更加薄型、高分辨率和能效更高。
3.称重模块
称重模块选择HX711,实物图:
HX711是一款集成了24位ADC(模数转换器)的增益放大器芯片。它常用于称重传感器与微控制器之间的连接,通过将称重传感器的模拟信号放大并转换为数字信号,实现精确的重量测量。
HX711芯片的主要特点和功能包括:
1. 高精度ADC:HX711芯片内部集成了24位的Σ-Δ(sigma-delta)ADC,能够实现高精度的模拟信号转换。
2. 可调增益:HX711芯片内部具有可调的增益放大器,支持不同量程下称重传感器的连接,以适应不同应用需求。
3. 低噪声:HX711芯片具有低噪声设计,能够减少环境和电源的干扰,提高测量的稳定性和准确性。
4. 内部校准:HX711芯片内部具有自动零点校准和内部参考电压的选项,可以提供更准确的测量结果。
5. 串行接口:HX711芯片通过串行接口(如SPI)与微控制器进行通信,简化了与外部系统的连接和控制。
6. 低功耗:HX711芯片在静态状态下具有低功耗特性,适用于功耗敏感的应用场景。
HX711芯片常用于称重应用,如厨房电子秤、工业称重装置、嵌入式测量系统等。它的高精度和稳定性使得重量测量更加精确可靠。同时,HX711芯片的简单接口设计和丰富的开发资源,方便了开发者的使用和二次开发。
4.心率测量模块
心率测量采用的传感器是MAX30102,实物图:
MAX30102是一款集成了心率和血氧饱和度(SpO2)测量功能的模块芯片。它使用光学传感器来非侵入性地监测心率和血氧水平,适用于健康监测、运动追踪、医疗设备等应用领域。
MAX30102芯片的主要特点和功能包括:
1. 心率监测:MAX30102芯片通过光学传感器测量皮肤上的血液脉搏信号,可以实时监测心率。
2. 血氧饱和度(SpO2)监测:MAX30102芯片利用红外LED和红色LED对血液中的血氧水平进行监测,测量结果以SpO2百分比的形式提供。
3. 光学传感器集成:MAX30102芯片集成了高度集成的光学传感器,包括LED、光电二极管(photodetector)和模拟前端,用于采集光学信号并将其转换为数字信号。
4. 低功耗:MAX30102芯片具有低功耗特性,适合于便携式设备和可穿戴设备应用。
5. 灵活的接口和配置选项:MAX30102芯片支持I2C接口进行通信,并提供了丰富的配置选项,如采样速率、增益控制等,以适应不同应用场景的需求。
6. 简化的算法和数据处理:MAX30102芯片可以提供经过滤波和算法处理后的心率和血氧测量结果,减少了外部处理器的工作量。
MAX30102芯片广泛应用于各种健康监测和医疗设备中,包括智能手环、智能手表、健康追踪器、医疗传感器等。通过非侵入性的方式,它可以提供关键的生理参数监测,帮助用户实时了解和管理自己的健康状况。
5.蓝牙模块
蓝牙模块选用HC08,实物图:
蓝牙模块是一种用于无线通信的设备,能够实现设备之间的短距离数据传输和通信。蓝牙模块通常包含了蓝牙无线通信所需的硬件和软件功能,可以轻松地与其他蓝牙设备进行配对和通信。
蓝牙模块的主要特点和功能包括:
1. 无线通信:蓝牙模块通过蓝牙无线技术实现设备之间的数据传输和通信,通常工作在2.4 GHz频段。
2. 低功耗:蓝牙模块通常具有低功耗特性,适用于电池供电的设备,并能够有效延长电池寿命。
3. 小型化和集成:蓝牙模块通常具有小尺寸和高度集成的设计,方便嵌入到各种设备中,并与其他硬件模块集成使用。
4. 通信范围:蓝牙模块通常适用于短距离通信,通信范围一般在几米到几十米之间,最大通信距离取决于模块的功率和环境条件。
6.蜂鸣器模块
蜂鸣器选择高电平触发的,有源蜂鸣器。
7.电机及其驱动模块
电机选择最简单的直流电机,二端口。实物图如下:
由于单片机的IO输出电流能力有限,无法直接驱动该直流电机工作,所以还需要使用电机的驱动模块。驱动模块选择L298N,实物图如下:
8.开关
开关是使用mini板子上自带的开关。
3.程序设计
接线方式为:
//HX711_SCK---> PA6
//HX711_DOUT---> PA7
//MAX30102 IIC_SCL---> PC11
//MAX30102 IIC_SDA---> PC12
//MAX30102 INT---> PC13
//BEEP---> PC0
//蓝牙 RX---> PA2
//蓝牙 TX---> PA3
//L298N_IN1--->PA4 L298N_IN2--->PA5
//(L298N需要额外供电)
本次程序的难点是,MAX30102的驱动编写。这里我不详细展开,我们直接给出主函数代码:
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "lcd.h"
#include "HX711.h"
#include "max30102.h"
#include "myiic.h"
#include "algorithm.h"
#include "key.h"
//HX711_SCK---> PA6
//HX711_DOUT---> PA7
//MAX30102 IIC_SCL---> PC11
//MAX30102 IIC_SDA---> PC12
//MAX30102 INT---> PC13
//BEEP---> PC0
//蓝牙 RX---> PA2
//蓝牙 TX---> PA3
//L298N_IN1--->PA4 L298N_IN2--->PA5
//(L298N需要额外供电)
//心率数据
uint32_t aun_ir_buffer[500]; //IR LED sensor data
int32_t n_ir_buffer_length; //data length
uint32_t aun_red_buffer[500]; //Red LED sensor data
int32_t n_sp02; //SPO2 value
int8_t ch_spo2_valid; //indicator to show if the SP02 calculation is valid
int32_t n_heart_rate; //heart rate value
int8_t ch_hr_valid; //indicator to show if the heart rate calculation is valid
uint8_t uch_dummy;
//variables to calculate the on-board LED brightness that reflects the heartbeats
uint32_t un_min, un_max, un_prev_data;
int i;
int32_t n_brightness;
float f_temp;
u8 temp_num=0;
u8 temp[6];
u8 str[100];
u8 dis_hr=0,dis_spo2=0;
u8 SendData[7]="alarm\r\t"; //要发送到串口的报警信息
u16 hr_yuzhi=70; //心率阈值 超出此范围 则蜂鸣器报警
#define MAX_BRIGHTNESS 255
/**********************************************************************
* @ 函数名 :获取心率数据
********************************************************************/
static void Heart_num(void){
i=0;
un_min=0x3FFFF;
un_max=0;
//dumping the first 100 sets of samples in the memory and shift the last 400 sets of samples to the top
for(i=100;i<500;i++)
{
aun_red_buffer[i-100]=aun_red_buffer[i];
aun_ir_buffer[i-100]=aun_ir_buffer[i];
//update the signal min and max
if(un_min>aun_red_buffer[i])
un_min=aun_red_buffer[i];
if(un_max<aun_red_buffer[i])
un_max=aun_red_buffer[i];
}
//take 100 sets of samples before calculating the heart rate.
for(i=400;i<500;i++)
{
un_prev_data=aun_red_buffer[i-1];
while(MAX30102_INT==1);
max30102_FIFO_ReadBytes(REG_FIFO_DATA,temp);
aun_red_buffer[i] = (long)((long)((long)temp[0]&0x03)<<16) | (long)temp[1]<<8 | (long)temp[2]; // Combine values to get the actual number
aun_ir_buffer[i] = (long)((long)((long)temp[3] & 0x03)<<16) |(long)temp[4]<<8 | (long)temp[5]; // Combine values to get the actual number
if(aun_red_buffer[i]>un_prev_data)
{
f_temp=aun_red_buffer[i]-un_prev_data;
f_temp/=(un_max-un_min);
f_temp*=MAX_BRIGHTNESS;
n_brightness-=(int)f_temp;
if(n_brightness<0)
n_brightness=0;
}
else
{
f_temp=un_prev_data-aun_red_buffer[i];
f_temp/=(un_max-un_min);
f_temp*=MAX_BRIGHTNESS;
n_brightness+=(int)f_temp;
if(n_brightness>MAX_BRIGHTNESS)
n_brightness=MAX_BRIGHTNESS;
}
//send samples and calculation result to terminal program through UART
if(ch_hr_valid == 1 && n_heart_rate<120)//**/ ch_hr_valid == 1 && ch_spo2_valid ==1 && n_heart_rate<120 && n_sp02<101
{
dis_hr = n_heart_rate;
dis_spo2 = n_sp02;
}
else
{
dis_hr = 0;
dis_spo2 = 0;
}
}
maxim_heart_rate_and_oxygen_saturation(aun_ir_buffer, n_ir_buffer_length, aun_red_buffer, &n_sp02, &ch_spo2_valid, &n_heart_rate, &ch_hr_valid);
}
int main(void)
{
delay_init(); //延时函数初始化
uart_init(9600); //串口初始化为9600
USART2_init(9600); //串口2初始化函数
LED_Init(); //初始化与LED连接的硬件接口
LCD_Init();
KEY_Init(); //初始化与按键连接的硬件接口
BEEP_Init(); //蜂鸣器初始化
Init_HX711pin(); //HX711管脚初始化
Get_Maopi(); //称毛皮重量
delay_ms(1000);
delay_ms(1000);
Get_Maopi(); //重新获取毛皮重量
max30102_init(); //初始化max30102
un_min=0x3FFFF;
un_max=0;
n_ir_buffer_length=500; //buffer length of 100 stores 5 seconds of samples running at 100sps
//read the first 500 samples, and determine the signal range
for(i=0;i<n_ir_buffer_length;i++)
{
while(MAX30102_INT==1); //wait until the interrupt pin asserts
max30102_FIFO_ReadBytes(REG_FIFO_DATA,temp);
aun_red_buffer[i] = (long)((long)((long)temp[0]&0x03)<<16) | (long)temp[1]<<8 | (long)temp[2]; // Combine values to get the actual number
aun_ir_buffer[i] = (long)((long)((long)temp[3] & 0x03)<<16) |(long)temp[4]<<8 | (long)temp[5]; // Combine values to get the actual number
if(un_min>aun_red_buffer[i])
un_min=aun_red_buffer[i]; //update signal min
if(un_max<aun_red_buffer[i])
un_max=aun_red_buffer[i]; //update signal max
}
un_prev_data=aun_red_buffer[i];
//calculate heart rate and SpO2 after first 500 samples (first 5 seconds of samples)
maxim_heart_rate_and_oxygen_saturation(aun_ir_buffer, n_ir_buffer_length, aun_red_buffer, &n_sp02, &ch_spo2_valid, &n_heart_rate, &ch_hr_valid);
POINT_COLOR=RED;
LCD_ShowString(30,100,200,16,16,"heart_rate:");
LCD_ShowString(30,120,200,16,16,"heart_rate_yuzhi:");
LCD_ShowxNum(160,120,hr_yuzhi,4,16,0);//显示心率阈值
//sprintf((char*)lcd_id,"LCD ID:%04X",lcddev.id);//将LCD ID打印到lcd_id数组。
while(1)
{
Get_Weight();
LCD_ShowxNum(30,30,Weight_Shiwu,4,16,0);//显示重量
LCD_ShowString(65,30,200,16,16,"g");
LCD_ShowString(30,60,200,24,24,"Mini STM32 ^_^");
if(KEY0==0)
{
Heart_num(); //获取数据
// BEEP=1;
}
else
{
n_heart_rate=0;
// BEEP=0;
}
if(KEY1==0) //K1按下 电机转
{
IN1=1;
IN2=0;
BEEP=1;
}
else //否则 不转
{
IN1=0;
IN2=0;
BEEP=0;
}
if( n_heart_rate<120)
{
LCD_ShowxNum(110,100,n_heart_rate,4,16,0);//显示心率
if(n_heart_rate>hr_yuzhi) //心率大于阈值
{
BEEP=1; //报警
for(i=0;i<7;i++) //向手机发送报警信息
{
while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET) ; /* Loop until the end of transmission */
USART_SendData(USART2,SendData[i]);
}
}
else
{
BEEP=0;
}
}
LED0=!LED0;
delay_ms(100);
}
}
文件工程截图: