一、功能介绍
1.心率实时检测,心率数值显示在LCD1602屏幕上
2.利用超声波测量身高,显示在LCD1602屏幕上
3.通过ADC读取体重,通过计算BMI指数,给出肥胖指数,显示在LCD1602屏幕上
4.DS1302读取年月日和实时时间,显示在LCD1602屏幕上
5.心率阈值可以通过按键修改,DS1302的年月日和时间都可以通过按键设置
6.设计了LCD1602的多级菜单,通过按键翻页,选择功能,增强交互性
二、设计软件
程序采用Keil5编写,重点代码都有详细注释,容易理解。仿真用Proteus绘制。
三、原理图
1.芯片采用STM32F103R6
2.心率和体重通过电位器模拟
3.按键采用硬件消抖
三、软件讲解
1.RTC部分
#include "DS1302.h"
extern char DS1302_start_Data[7]={0x24,0x04,0x19,0x14,0x00,0x00,0x07};//年月日时分秒周
struct TIMEData TimeData;
char read_time[7];
char DS1302_data_1[10];
char DS1302_data_2[8];
void ds1302_gpio_init()//CE,SCLK端口初始化
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PC.11 CE
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOC.11
GPIO_ResetBits(GPIOB,GPIO_Pin_2);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //PC.12 SCLK
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOC.12
GPIO_ResetBits(GPIOB,GPIO_Pin_3);
}
void ds1302_DATAOUT_init()//配置双向I/O端口为输出态
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; //PC.10 DATA
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOC.10
GPIO_ResetBits(GPIOB,GPIO_Pin_4);
}
void ds1302_DATAINPUT_init()//配置双向I/O端口为输入态
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; //PC.10 DATA
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOC.10
}
void ds1302_write_onebyte(unsigned char data)//向DS1302发送一字节数据
{
unsigned char count=0;
ds1302_DATAOUT_init();
SCLK_L;
for(count=0;count<8;count++)
{ SCLK_L;
if(data&0x01)
{DATA_H;}
else{DATA_L;}//先准备好数据再发送
SCLK_H;//拉高时钟线,发送数据
data>>=1;
}
}
void ds1302_wirte_rig(unsigned char address,unsigned char data)//向指定寄存器地址发送数据
{
unsigned char temp1=address;
unsigned char temp2=data;
CE_L;SCLK_L;Delay_us(1);
CE_H;Delay_us(2);
ds1302_write_onebyte(temp1);
ds1302_write_onebyte(temp2);
CE_L;SCLK_L;Delay_us(2);
}
unsigned char ds1302_read_rig(unsigned char address)//从指定地址读取一字节数据
{
unsigned char temp3=address;
unsigned char count=0;
unsigned char return_data=0x00;
CE_L;SCLK_L;Delay_us(3);
CE_H;Delay_us(3);
ds1302_write_onebyte(temp3);
ds1302_DATAINPUT_init();//配置I/O口为输入
Delay_us(2);
for(count=0;count<8;count++)
{
Delay_us(2);//使电平持续一段时间
return_data>>=1;
SCLK_H;Delay_us(4);//使高电平持续一段时间
SCLK_L;Delay_us(14);//延时14us后再去读取电压,更加准确
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_4))
{return_data=return_data|0x80;}
}
Delay_us(2);
CE_L;DATA_L;
return return_data;
}
void ds1302_init()
{
ds1302_wirte_rig(0x8e,0x00);//关闭写保护
ds1302_wirte_rig(0x80,DS1302_start_Data[5]);//seconds
ds1302_wirte_rig(0x82,DS1302_start_Data[4]);//minutes
ds1302_wirte_rig(0x84,DS1302_start_Data[3]);//hours
ds1302_wirte_rig(0x86,DS1302_start_Data[2]);//date
ds1302_wirte_rig(0x88,DS1302_start_Data[1]);//months
ds1302_wirte_rig(0x8a,DS1302_start_Data[6]);//days
ds1302_wirte_rig(0x8c,DS1302_start_Data[0]);//year
ds1302_wirte_rig(0x8e,0x80);//关闭写保护
}
void ds1302_read_time()
{
read_time[0]=ds1302_read_rig(0x81);//读秒
read_time[1]=ds1302_read_rig(0x83);//读分
read_time[2]=ds1302_read_rig(0x85);//读时
read_time[3]=ds1302_read_rig(0x87);//读日
read_time[4]=ds1302_read_rig(0x89);//读月
read_time[5]=ds1302_read_rig(0x8B);//读星期
read_time[6]=ds1302_read_rig(0x8D);//读年
}
void ds1302_read_realTime()
{
ds1302_read_time(); //BCD码转换为10进制
TimeData.second=(read_time[0]>>4)*10+(read_time[0]&0x0f);
TimeData.minute=((read_time[1]>>4)&(0x07))*10+(read_time[1]&0x0f);
TimeData.hour=(read_time[2]>>4)*10+(read_time[2]&0x0f);
TimeData.day=(read_time[3]>>4)*10+(read_time[3]&0x0f);
TimeData.month=(read_time[4]>>4)*10+(read_time[4]&0x0f);
TimeData.week=read_time[5];
TimeData.year=(read_time[6]>>4)*10+(read_time[6]&0x0f)+2000;
DS1302_data_1[0]='2';
DS1302_data_1[1]='0';
DS1302_data_1[2]='0'+(TimeData.year-2000)/10;
DS1302_data_1[3]='0'+(TimeData.year-2000)%10;
DS1302_data_1[4]='-';
DS1302_data_1[5]='0'+TimeData.month/10;
DS1302_data_1[6]='0'+TimeData.month%10;
DS1302_data_1[7]='-';
DS1302_data_1[8]='0'+TimeData.day/10;
DS1302_data_1[9]='0'+TimeData.day%10;
DS1302_data_2[0]='0'+TimeData.hour/10;
DS1302_data_2[1]='0'+TimeData.hour%10;
DS1302_data_2[2]=':';
DS1302_data_2[3]='0'+TimeData.minute/10;
DS1302_data_2[4]='0'+TimeData.minute%10;
DS1302_data_2[5]=':';
DS1302_data_2[6]='0'+TimeData.second/10;
DS1302_data_2[7]='0'+TimeData.second%10;
}
年月日时分秒封装在数组里,方便修改
2.多级界面部分代码
*-----------开机动画---------------*/
void StartMenu(void)
{
WrString1602(0,"The BMI Health");
}
/*------------------------------------*/
/*-----------界面2:各项数据显示页---------------*/
void SubmenuTwo(void) //数据页面
{
WrByte1602(0,7,' '); //消影
WrByte1602(1,7,' '); //消影
WrByte1602(1,8,' '); //消影
WrByte1602(0,0,'B');
WrByte1602(0,1,'M');
WrByte1602(0,2,'I');
WrByte1602(0,3,'=');
WrByte1602(1,0,'H');
WrByte1602(1,1,'=');
WrByte1602(1,5,'C');
WrByte1602(1,6,'M');
WrByte1602(1,9,'W');
WrByte1602(1,10,'=');
WrByte1602(1,14,'K');
WrByte1602(0,8,'P');
WrByte1602(0,9,'=');
WrByte1602(1,15,'G');WrByte1602(1,11,AsciiCode[temp1%1000/100]); //显示体重百位
WrByte1602(1,12,AsciiCode[temp1%100/10]);//显示体重十位
WrByte1602(1,13,AsciiCode[temp1%10]);//显示体重个位
WrByte1602(1,2,AsciiCode[UltrasonicWave_Distance%256/100]);//显示身高百位
WrByte1602(1,3,AsciiCode[UltrasonicWave_Distance%256%100/10]);//身高十位
WrByte1602(1,4,AsciiCode[UltrasonicWave_Distance%256%10]); //身高个位
bmi=temp1*10000/((UltrasonicWave_Distance%256)*(UltrasonicWave_Distance%256));//BMI值=体重/(身高*身高)
WrByte1602(0,4,AsciiCode[bmi%1000/100]); //显示BMI百位
WrByte1602(0,5,AsciiCode[bmi%100/10]);//显示BMI十位
WrByte1602(0,6,AsciiCode[bmi%10]);//显示BMI个位
WrByte1602(0,10,AsciiCode[temp2%1000/100]); //显示脉搏百位
WrByte1602(0,11,AsciiCode[temp2%100/10]);//显示脉搏十位
WrByte1602(0,12,AsciiCode[temp2%10]);//显示脉搏个位
}
/*-------------------------------------------------------*/