這是我們暑假參加比賽的作品,含源碼,實物圖,原理圖。請大家多多指教,一起學習 。本作品設計了一種可以同時檢測心率和體溫,并可以實現計步功能的手表,該裝置包括單片機控制器、MLX90614紅外測溫模塊、MMA7455計步模塊、系統實時時鐘、Pulse Sensor心率模塊、OLED12864顯示模塊、nRF24L01無線通信模塊和計算機控制軟件、電源九部分。
利用MLX90614紅外測溫模塊及Pulse Sensor心率模塊采集到人的實時體溫和心率數據,通過nRF24L01無線通信模塊將采集到的數據發送到單片機控制器,經過STC89LE5A60S2微控制器進行數據處理,再將數據傳到OLED12864顯示,并通過數據線串口發送數據到電腦,然后通過LabVIEW軟件對采集到的數據進一步的處理和分析。
同時本作品還可以將計步模塊的數據通過STC89LE5A60S2單片機送到OLED12864顯示,實現計步功能。該作品可當作一個便攜式家用醫療小系統,實時監測體溫和心率,并可實現戶外運動的計步功能,達到方便、快捷、可自由移動的目的。
實物圖計步器功能:
QQ圖片20160816115604.jpg (2.74 MB, 下載次數: 127)
下載附件
手表端
2017-2-28 19:06 上傳
下面是電路原理圖:
56.png (66.47 KB, 下載次數: 127)
下載附件
手表端原理圖
2017-2-28 19:11 上傳
下面是整機圖:
QQ圖片20160816115614.jpg (2.35 MB, 下載次數: 133)
下載附件
耳聞模塊
2017-2-28 19:06 上傳
QQ圖片20160816130415.jpg (2.34 MB, 下載次數: 127)
下載附件
心率儀
2017-2-28 19:06 上傳
5656.png (28.66 KB, 下載次數: 126)
下載附件
耳聞原理圖
2017-2-28 19:11 上傳
56565665.png (34.59 KB, 下載次數: 128)
下載附件
2017-2-28 19:20 上傳
0.png (58.13 KB, 下載次數: 125)
下載附件
2017-2-28 23:42 上傳
多功能醫療健康手表設計的所有資料下載
(里面包含2個單片機源程序,分別實現了2個功能MLX90614程序-發送-耳溫和手表顯示):
程序.rar
(253.42 KB, 下載次數: 240)
2017-2-28 19:12 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
計步程序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;
- }
-
-
- }
- }
-
- …………余下代碼請下載附件……
復制代碼 |