这是我们暑假参加比赛的作品,含源码,实物图,原理图。请大家多多指教,一起学习。本作品设计了一种可以同时检测心率和体温,并可以实现计步功能的手表,该装置包括单片机控制器、MLX90614红外测温模块、MMA7455计步模块、系统实时时钟、Pulse Sensor心率模块、OLED12864显示模块、nRF24L01无线通信模块和计算机控制软件、电源九部分。
利用MLX90614红外测温模块及Pulse Sensor心率模块采集到人的实时体温和心率数据,通过nRF24L01无线通信模块将采集到的数据发送到单片机控制器,经过STC89LE5A60S2微控制器进行数据处理,再将数据传到OLED12864显示,并通过数据线串口发送数据到电脑,然后通过LabVIEW软件对采集到的数据进一步的处理和分析。
同时本作品还可以将计步模块的数据通过STC89LE5A60S2单片机送到OLED12864显示,实现计步功能。该作品可当作一个便携式家用医疗小系统,实时监测体温和心率,并可实现户外运动的计步功能,达到方便、快捷、可自由移动的目的。
实物图计步器功能:
下面是电路原理图:
下面是整机图:
多功能医疗健康手表设计的所有资料下载
(里面包含2个单片机源程序,分别实现了2个功能MLX90614程序-发送-耳温和手表显示):
程序.rar
(253.42 KB, 下载次数: 235)
计步程序jibu.h文件:
- #include<reg51.h>
- #include <intrins.h>
- //#define uchar unsigned char
- //#define uint unsigned int
- void KeyScan1(void);
- sbit Key_jibu=P2^0;
- #define SET_TR2 AUXR |= 0x10
- #define CLR_TR2 AUXR &= ~0x10
- #define SET_ET2 IE2 |= 0x04
- #define CLR_ET2 IE2 &= ~0x04
- //nop指令个数定义
- #define nops() {_nop_();_nop_();_nop_();_nop_();_nop_();}
- bit start_flag=0;
- //端口定义,可修改
- sbit SDA1=P1^1; //IIC数据线定义 (可自行定义引脚)
- sbit SCL=P1^0; //IIC时钟线定义 (可自行定义引脚)
- //内部数据定义
- unsigned char IIC_ad_main; //器件从地址
- unsigned char IIC_ad_sub; //器件子地址
- unsigned char *IIC_buf; //发送接收数据缓冲区
- unsigned char IIC_num; //发送接收数据缓个数
- unsigned int step_num=0;
- unsigned char x1,y1,z1;
- int x,y,z;
- bit x_flag=0;
- //bit z_flag=0;
- #define ack 1 //主应答
- #define no_ack 0 //从应答
- /*延时子程序,实现按键消抖功能*/
- void delayms( )
- { int i=10,j=110;
- for(i=10;i>0;i--)
- for(j=110;j>0;j--);
- }
- void send232byte(unsigned char bytebuf)
- {
- SBUF=bytebuf;
- while(!TI);
- TI=0;
- }
- void IIC_start(void){
- SCL=0;
- SDA1=1;
- _nop_();
- SCL=1;
- nops();
- SDA1=0;
- nops();
- SCL=0;
- }
- //************************************************
- //送停止位SDA=0->1
- void IIC_stop(void){
- SCL=0;
- _nop_();
- SDA1=0;
- _nop_();
- SCL=1;
- nops();
- SDA1=1;
- nops();
- SCL=0;
- }
- //************************************************
- //主应答(包括ack:SDA=0和no_ack:SDA=0)
- void IIC_ack_main(bit ack_main){
- SCL=0;
- if(ack_main)SDA1=0; //ack主应答
- else SDA1=1; //no_ack无需应答
- nops();
- SCL=1;
- nops();
- SCL=0;
- }
- //*************************************************
- //字节发送程序
- //发送c(可以是数据也可以是地址),送完后接收从应答
- //不考虑从应答
- void send_byte(unsigned char c)
- {
- unsigned char i;
- for(i=0;i<8;i++)
- {
- SCL=0;
- if((c<<i) & 0x80)SDA1=1; //判断发送位
- else SDA1=0;
- _nop_();
- SCL=1;
- nops();
- SCL=0;
-
- nops();
- SCL=0;
- }
- nops();
- SDA1=1; //发送完8bit,释放总线准备接受应答位
- _nop_();
- SCL=1;
- nops(); //sda上数据即是从应答位
- SCL=0; //不考虑从应答但要控制好时序
- }
- //**************************************************
- //字节接收程序
- //接受器件传来的数据,此程序应配合主应答函数IIC-ack main()使用
- //return: uchar型1字节
- unsigned char read_byte(void){
- unsigned char i;
- unsigned char c;
- c=0;
- SCL=0;
- _nop_();
- SDA1=1; //置数据线为输入方式
- for(i=0;i<8;i++){
- _nop_();
- SCL=0; //置时钟线为低,准备接收数据位
- nops();
- SCL=1; //置时钟线为高,使数据线上数据有效
- _nop_();
- c<<=1;
- if(SDA1)c+=1; //读数据位,将接收的数据存c
- }
- SCL=0;
- return c;
- }
- //***************************************************
- //向无子地址器件发送单字节数据
- void send_to_byte(unsigned char ad_main,unsigned char c){
- IIC_start();
- send_byte(ad_main); //发送器件地址
- send_byte(c); //发送数据c
- IIC_stop();
- }
- //***************************************************
- //向有子地址器件发送多字节数据
- void send_to_nbyte(unsigned char ad_main,unsigned char ad_sub,unsigned char *buf,unsigned char num)
- { unsigned char i;
- IIC_start();
- send_byte(ad_main); //发送器件地址
- send_byte(ad_sub); //发送器件子地址
- for(i=0;i<num;i++){
- send_byte(*buf); //发送数据buf
- buf++;
- }
- IIC_stop();
- }
- //***************************************************
- //从无子地址器件读单字节数据
- //function:器件地址,所读数据存在接收缓冲区当前字节
- void read_from_byte(unsigned char ad_main,unsigned char *buf){
- IIC_start();
- send_byte(ad_main); //发送器件
- *buf=read_byte();
- IIC_ack_main(no_ack); //无需应答<no_ack=0>
- IIC_stop();
- }
- //***************************************************
- //从有子地址器件读多个字节数据
- //function:
- void read_from_nbyte(unsigned char ad_main,unsigned char ad_sub,unsigned char *buf,unsigned char num){
- unsigned char i;
- IIC_start();
- send_byte(ad_main);
- send_byte(ad_sub);
- for(i=0;i<num-1;i++){
- *buf=read_byte();
- IIC_ack_main(ack); //,主应答<ack=1>
- buf++;
- }
- *buf=read_byte;
- buf++; //本次指针调整无意义,目的是操作后buf指向下一地址
- IIC_ack_main(no_ack); //无需应答<no_ack=0>
- IIC_stop();
- }
- unsigned char MMA7455_readbyte(unsigned char address)
- {
- unsigned char ret = 100;
- IIC_start(); //启动
- send_byte(0x3A); //写入设备ID及写信号
- send_byte(address); //X地址
- IIC_start(); //重新发送开始
- send_byte(0x3B); //写入设备ID及读信号
- ret = read_byte(); //读取一字节
- IIC_stop();
- return ret;
- }
- //写入
- void MMA7455_writebyte(unsigned char address, unsigned char thedata)
- {
- IIC_start(); //启动
- send_byte(0x3A); //写入设备ID及写信号
- send_byte(address); //X地址
- send_byte(thedata); //写入设备ID及读信号
- IIC_stop();
- }
- //初始化
- //初始化为指定模式
- void MMA7455_init()
- { //2g输出 测量模式
- MMA7455_writebyte(0x16, 0x05);
- //根据实际环境修改校验值
- /*MMA7455_writebyte(0x10,0x10);//校正X值
- MMA7455_writebyte(0x12,0x30);//校正Y值
- MMA7455_writebyte(0x14,0x00);//校正Z值 */
- }
- /************************显示程序**********************************/
- void display()
- {
- if (step_num/10000>0) //万
- OLED_ShowNum(0+8*5,4,step_num/10000,1,8*16);
- else
- OLED_ShowNum(0+8*5,4,0,1,8*16);
- if (step_num/1000>0) //千
- OLED_ShowNum(0+8*6,4,step_num%10000/1000,1,8*16);
- else
- OLED_ShowNum(0+8*6,4,0,1,8*16);
- if (step_num/100>0) //百
- OLED_ShowNum(0+8*7,4,step_num%1000/100,1,8*16);
- else
- OLED_ShowNum(0+8*7,4,0,1,8*16);
- if (step_num/10>0) //十
- OLED_ShowNum(0+8*8,4,step_num%100/10,1,8*16);
- else
- OLED_ShowNum(0+8*8,4,0,1,8*16);
- //个
- OLED_ShowNum(0+8*9,4,step_num%10,1,8*16);
- }
- /************读取重力信息**************/
- void Dat_dispose()
- {
- if(start_flag)
- { x1=MMA7455_readbyte(0x06);
- y1=MMA7455_readbyte(0x07);
- z1=MMA7455_readbyte(0x08);
- }
- x=x1;
- y=y1;
- z=z1;
- if((x&0x80)==0x00)
- { x=(int)((x*196)/127); //转变成加速度值
- }
- else { x=255-x;
- x=(int)((x*196)/127);//转变成加速度值
- x=(-1)*x;
- }
- if((y&0x80)==0x00)
- { y=(int)((y*196)/127); //转变成加速度值
- }
- else { y=255-y;
- y=(int)((y*196)/127);//转变成加速度值
- y=(-1)*y;
- }
- if((z&0x80)==0x00)
- { z=(int)(((z-10)*196)/127); //转变成加速度值
- }
- else { z=255-z;
- z=(int)(((z+12)*196)/127);//转变成加速度值
- z=(-1)*z;
- }
- if(start_flag)
- {
- if(y>30&&x_flag==0&&z>70&&z<100)
- {x_flag=1;
- step_num++;}
- else if(y<0)
- { x_flag=0;}
- }
- else x_flag=0;
- }
复制代码
主程序:
- #include "REG51.h"
- #include "OLED.h"
- //#include "bmp.h"
- #include "DS1302.h"
- #include "NRF24L01.h"
- #include "key_deal.h"
- #include "MMA7455.h"
- #define false 0
- #define true 1
- #define FOSC 11059200L //系统时钟
- #define BAUD 115200 //波特率
- #define T0MS (65536-FOSC/12/500) //500HZ in 12T MODE
- #define ADC_POWER 0x80 //ADC POWER CONTROL BIT
- #define ADC_FLAG 0x10 //ADC COMPLETE FLAG
- #define ADC_START 0x08; //ADC START CONTROL BIT
- #define ADC_SPEEDLL 0x00 //540 CLOCKS
- #define ADC_SPEEDL 0x20 //360 CLOCKS
- #define ADC_SPEEDH 0x40 //180 CLOCKS
- #define ADC_SPEEDHH 0x60 //90 CLOCKS
- #define ADC_MASK 0x01
- void ADC_init(unsigned char channel);
- void InitTimer0(void);
- unsigned char ReturnPulse(void);
- unsigned int analogRead(unsigned char channel);
- unsigned char PulsePin = 5; // Pulse Sensor purple wire connected to analog pin 0(P1.0为传感器输入口)
- int fadeRate = 0; // used to fade LED on with PWM on fadePin
- unsigned char pp1;
- unsigned char pp0;
- unsigned char pp2;
- unsigned char pp3;
- unsigned int PL1=0;
- void UART_init(void);
- void Send(void);
- // these variables are volatile because they are used during the interrupt service routine!
- volatile unsigned int BPM; // used to hold the pulse rate
- volatile unsigned int Signal; // holds the incoming raw data
- volatile unsigned int IBI = 600; // holds the time between beats, must be seeded!
- volatile bit Pulse = false; // true when pulse wave is high, false when it's low
- volatile bit QS = false; // becomes true when Arduoino finds a beat.
- volatile int rate[10]; // array to hold last ten IBI values
- volatile unsigned long sampleCounter = 0; // used to determine pulse timing
- volatile unsigned long lastBeatTime = 0; // used to find IBI
- volatile int Peak =512; // used to find peak in pulse wave, seeded
- volatile int Trough = 512; // used to find trough in pulse wave, seeded
- volatile int thresh = 512; // used to find instant moment of heart beat, seeded
- volatile int amp = 100; // used to hold amplitude of pulse waveform, seeded
- volatile bit firstBeat = true; // used to seed rate array so we startup with reasonable BPM
- volatile bit secondBeat = false; // used to seed rate array so we startup with reasonable BPM
- static unsigned char order=0;
- unsigned char DisBuff[4]={0};
- void Int0_Init(void);
- //void Int1_Init(void);
- void Display_Init(void);
- static unsigned char data temp[10];
- bit data T0_FLAG=0;
- bit data key_flag;
- bit data key_flag1;
- unsigned int mode1 = 0;
- void delay(unsigned int n)
- {
- unsigned int i,j;
- for(i=0;i<n;i++)
- for(j=0;j<100;j++);
- }
- int main(void)
- { //u8 t;
- //delay_init(); //延时函数初始化
- // NVIC_Configuration(); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 LED_Init(); //LED端口初始化
- OLED_Init(); //初始化OLED
- Ds1302_Init();
- InitTimer0();
- Display_Init();
- ADC_init(PulsePin);
- //InitTimer1();
- Int0_Init();
- init_NRF24L01();
- SetRX_Mode();
- UART_init();
- //Int1_Init();
- while(1)
- {
- delay_ms(10);
-
- Ds1302_Read_Time();
- /*判断按键2是否启动测试*/
- if(0 == Key_Down)
- {
- delay_ms(100);
- if(0 == Key_Down)
- {
- mode1=mode1+1;
- }
- }
-
- /* 测心率 */
- if(mode1==1)
- {
- OLED_ShowCHinese(0,0,0); //心
- OLED_ShowCHinese(16,0,1); //率
- OLED_ShowString(32,0,":");
- OLED_ShowCHinese(0,2,2); //体
- OLED_ShowCHinese(16,2,3); //温
- OLED_ShowString(32,2,":");
-
- if (QS == true&&PL1>1000)
- { // Quantified Self flag is true when arduino finds a heartbeat
-
- QS = false;
- delay(100);
- OLED_ShowNum(0+8*5,0,DisBuff[2],1,8*16); //百位显示
- OLED_ShowNum(0+8*6,0,DisBuff[1],1,8*16); //个十位显示
- OLED_ShowNum(0+8*7,0,DisBuff[0],1,8*16);
- OLED_ShowString(64,0,"bpm");
-
- ///判断是否异常
- if((DisBuff[1]*10+DisBuff[0])<100&&(DisBuff[1]*10+DisBuff[0])>=60&&DisBuff[2]!=1)
- {
- OLED_ShowCHinese(0+8*12,0,24); //正常
- OLED_ShowCHinese(0+8*14,0,26);
- }
- else if(DisBuff[1]==0&&DisBuff[2]==0&&DisBuff[0]==0)
- {
- OLED_ShowCHinese(0+8*12,0,29); //空
- OLED_ShowCHinese(0+8*14,0,29);
- }
- else
- {
- OLED_ShowCHinese(0+8*12,0,25); //异常
- OLED_ShowCHinese(0+8*14,0,26);
- }
-
- }
- delay(138); // take a break 19.6ms
- /*温度测量 */
- if(nRF24L01_RxPacket(temp)&&PL1>1000) //接收温度
- {
- SetTX_Mode();
- delay(100);
- OLED_ShowString(56,2,".");
- OLED_ShowCHinese(72,2,19);
- OLED_ShowNum(0+8*5,2,temp[3]%100/10,1,8*16); //temp[3]存放十位
- OLED_ShowNum(0+8*6,2,temp[3]%10,1,8*16); //个位
- OLED_ShowNum(0+8*8,2,temp[2]%100/10,1,8*16); //temp[2]存放小数位
- if(temp[3]>=36&&temp[3]<38)
- {
- OLED_ShowCHinese(0+8*12,2,24);
- OLED_ShowCHinese(0+8*14,2,26);
- }
- else
- {
- OLED_ShowCHinese(0+8*12,2,25);
- OLED_ShowCHinese(0+8*14,2,26);
- }
- temp[4] = ReturnPulse();
- nRF24L01_TxPacket(temp);
- SetRX_Mode();
-
- }
- if(PL1>1000)
- {
- PL1=0;
- Send();
- }
- }
- if(mode1>=3)
- {
- mode1=0;
- OLED_ShowCHinese(0,0,29); //心
- OLED_ShowCHinese(16,0,29); //率
- OLED_ShowCHinese(32,0,29);
- OLED_ShowCHinese(64,0,29);
- OLED_ShowCHinese(72,0,29);
- OLED_ShowCHinese(48,0,29);
- OLED_ShowCHinese(56,0,29);
- OLED_ShowCHinese(40,0,29);
- OLED_ShowCHinese(0+8*12,0,29);
- OLED_ShowCHinese(0+8*14,0,29);
-
-
- OLED_ShowCHinese(0,2,29); //
- OLED_ShowCHinese(16,2,29); //
- OLED_ShowCHinese(32,2,29);
- OLED_ShowCHinese(72,2,29);
- OLED_ShowCHinese(64,2,29);
- OLED_ShowCHinese(48,2,29);
- OLED_ShowCHinese(56,2,29);
- OLED_ShowCHinese(40,2,29);
- OLED_ShowCHinese(0+8*12,2,29);
- OLED_ShowCHinese(0+8*14,2,29);
-
- }
-
- OLED_ShowNum(0+8*10,4,time_buf1[6]/10,1,8*16);
- OLED_ShowNum(0+8*11,4,time_buf1[6]%10,1,8*16);
- if(0 == time_buf1[6])
- {
- OLED_ShowNum(0+8*7,4,time_buf1[5]/10,1,8*16);
- OLED_ShowNum(0+8*8,4,time_buf1[5]%10,1,8*16);
- if(0 == time_buf1[5])
- {
- EA = 0; //////
- OLED_ShowNum(0+8*4,4,time_buf1[4]/10,1,8*16);
- OLED_ShowNum(0+8*5,4,time_buf1[4]%10,1,8*16);
- if(0 == time_buf1[4])
- {
- OLED_ShowNum(0+8*9,6,time_buf1[3]/10,1,8*16);
- OLED_ShowNum(0+8*10,6,time_buf1[3]%10,1,8*16);
- OLED_ShowCHinese(8*12,6,WEEK[time_buf1[7]]);
- if(0 == time_buf1[3])
- {
- OLED_ShowNum(0+8*6,6,time_buf1[2]/10,1,8*16);
- OLED_ShowNum(0+8*7,6,time_buf1[2]%10,1,8*16);
- if(0 == time_buf1[2])
- {
- OLED_ShowNum(0+8*3,6,time_buf1[1]/10,1,8*16);
- OLED_ShowNum(0+8*4,6,time_buf1[1]%10,1,8*16);
- }
- }
- }
-
- InitTimer0(); //每隔一小时,重新初始化一次
- }
-
- }
- /* 时间调整/计步按键判断 */
- //按键判断
- if(key_flag == 1) //进入按键扫描
- {
- KeyScan();
- key_flag = 0;
- mode1=0;
- }
-
-
- }
- }
-
- …………余下代码请下载附件……
复制代码 |