程式可以在單片機上運行,但是有很大的心率誤差,模塊剛放上指尖的資料還是正常的,但是過一會瞬間達到200(最大值),不知該如何解決
請大神指教。
代碼如下
//MCU:STC12C5A60S2
//ADC PIN:P1.0
//SYSTEM CLOCK:11.0592MHz
//Baudrate:115200
//UART:P3.0 P3.1
//**********************************************************************//
#include <STC12C5A60S2.h>
#include "stdio.h"
#include <LCD1602.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 UART_init(void);
void ADC_init(unsigned char channel);
void T0_init(void); dat);
void UART_send(char dat);
unsigned char PulsePin = 0; // Pulse Sensor purple wire connected to analog pin 0(P1.0為AD口)
sbit blinkPin = P2^0; // pin to blink led at each beat
sbit fadePin = P2^3; // pin to do fancy classy fading blink at each beat
sbit led1 = P2^1;
sbit led2 = P2^2;
int fadeRate = 0; // used to fade LED on with PWM on fadePin
// 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. 當Arduoino找到一個節拍時,就變成了true
volatile int rate[10]; // array to hold last ten IBI values 陣列來保存最后10個IBI值
volatile unsigned long sampleCounter = 0; // used to determine pulse timing 用于確定脈沖定時
volatile unsigned long lastBeatTime = 0; // used to find IBI 用來找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 用于種子率陣列,所以我們啟動合理的BPM
volatile bit secondBeat = false; // used to seed rate array so we startup with reasonable BPM 用于種子率陣列,所以我們啟動合理的BPM
static unsigned char order=0;
unsigned char code ucForum0[]="Pulsesensor test";
unsigned char code ucForum1[]=" BPM: ";
unsigned char DisBuff[4]={0};
void sys_init()
{
UART_init(); // we agree to talk fast!
ADC_init(PulsePin);
T0_init(); // sets up to read Pulse Sensor signal every 2mS
LCD1602_Init(); //液晶初始化
}
void main(void)
{
sys_init();
LCD1602_DisplayString(ucForum0); //顯示的內容
LCD1602_MoveToPosition(1,0); //顯示位置移動到指定位置
LCD1602_DisplayString(ucForum1); //顯示的內容
while(1)
{
sendDataToProcessing('S', Signal); // send Processing the raw Pulse Sensor data 發送處理原始脈沖傳感器資料
if (QS == true){ // Quantified Self flag is true when arduino finds a heartbeat Quantified Self標志為真
fadeRate = 255; // Set 'fadeRate' Variable to 255 to fade LED with pulse 將“fadeRate”變數設定為255,使LED帶脈沖淡出
sendDataToProcessing('B',BPM); // send heart rate with a 'B' prefix 發送帶“B”前綴的心率
sendDataToProcessing('Q',IBI); // send time between beats with a 'Q' prefix 在節拍之間發送帶有“Q”前綴的時間
QS = false; // reset the Quantified Self flag for next time 為下一次重置量化自我標志
LCD1602_MoveToPosition(1,9);
LCD1602_DisplayString(DisBuff);
}
//ledFadeToBeat();
delay(138); // take a break 19.6ms
}
}
//void ledFadeToBeat(){
// fadeRate -= 15; // set LED fade value 設定LED淡出值
// fadeRate = constrain(fadeRate,0,255); // keep LED fade value from going into negative numbers! 保持LED衰減值不變成負數!
// analogWrite(fadePin,fadeRate); // fade LED 消失
// }
void sendDataToProcessing(char symbol, int dat ){
putchar(symbol); // symbol prefix tells Processing what type of data is coming 符號前綴告訴處理什么型別的資料
printf("%d\r\n",dat); // the data to send culminating in a carriage return 以回車結束的資料發送
}
void UART_init(void)
{
PCON &= 0x7f; //波特率不倍速
SCON = 0x50; //8位資料,可變波特率
BRT = 0xFD; //獨立波特率產生器初值
AUXR |= 0x04; //時鐘設定為1T模式
AUXR |= 0x01; //選擇獨立波特率產生器
AUXR |= 0x10; //啟動波特率產生
}
char putchar(unsigned char dat)
{
TI=0;
SBUF=dat;
while(!TI);
TI=0;
return SBUF;
}
void T0_init(void){
// Initializes Timer0 to throw an interrupt every 2mS. 初始化Timer0以每隔2毫秒拋出一個中斷。
TMOD |= 0x01; //16bit TIMER 16位定時器
TL0=T0MS;
TH0=T0MS>>8;
TR0=1; //start Timer 0 定時器0開始
ET0=1; //enable Timer Interrupt 啟用定時器中斷
EA=1; // MAKE SURE GLOBAL INTERRUPTS ARE ENABLED 確保啟用了全域中斷
}
void ADC_init(unsigned char channel)
{
P1ASF=ADC_MASK<<channel; //enable PlusePin as ADC INPUT 啟用PlusePin作為ADC輸入
ADC_RES=0; //clear former ADC result 清除以前的ADC結果
ADC_RESL=0; //clear former ADC result 清除以前的ADC結果
AUXR1 |= 0x04; //adjust the format of ADC result 調整ADC結果的格式
ADC_CONTR=channel|ADC_POWER|ADC_SPEEDLL|ADC_START; //power on ADC and start conversion 打開ADC電源并開始轉換
}
unsigned int analogRead(unsigned char channel)
{
unsigned int result;
ADC_CONTR &=!ADC_FLAG; //clear ADC FLAG 清除ADC標志
result=ADC_RES;
result=result<<8;
result+=ADC_RESL;
ADC_CONTR|=channel|ADC_POWER|ADC_SPEEDLL|ADC_START;
return result;
}
// Timer 0中斷子程式,每2MS中斷一次,讀取AD值,計算心率值
void Timer0_rountine(void) interrupt 1
{
int N;
unsigned char i;
// keep a running total of the last 10 IBI values 保持最后10個IBI值的運行總數
unsigned int runningTotal = 0; // clear the runningTotal variable 清除runningTotal變數
EA=0; // disable interrupts while we do this 在執行此操作時禁用中斷
TL0=T0MS;
TH0=T0MS>>8; //reload 16 bit TIMER0 重新加載16位TIMER0
Signal = analogRead(PulsePin); // read the Pulse Sensor 讀取脈沖傳感器
sampleCounter += 2; // keep track of the time in mS with this variable 用這個變數跟蹤時間,單位為mS
N = sampleCounter - lastBeatTime; // monitor the time since the last beat to avoid noise 監控從最后一拍開始的時間,以避免噪音
// find the peak and trough of the pulse wave 找出脈沖波的波峰和波谷
if(Signal < thresh && N > (IBI/5)*3){ // avoid dichrotic noise by waiting 3/5 of last IBI 通過等待3/5的最后一次IBI來避免二色性噪聲
if (Signal < Trough){ // T is the trough 0是谷值
Trough = Signal; // keep track of lowest point in pulse wave 記錄脈沖波的最低點
}
}
if(Signal > thresh && Signal > Peak){ // thresh condition helps avoid noise 反復條件有助于避免噪音
Peak = Signal; // P is the peak
} // keep track of highest point in pulse wave 記錄脈搏波的最高點
// NOW IT'S TIME TO LOOK FOR THE HEART BEAT 現在是時候檢查心跳了
// signal surges up in value every time there is a pulse 每有一個脈沖,信號的值就會激增
if (N > 250){ // avoid high frequency noise 避免高頻噪音
if ( (Signal > thresh) && (Pulse == false) && (N > (IBI/5)*3) ){
Pulse = true; // set the Pulse flag when we think there is a pulse 當我們認為有脈沖時,設定脈沖標志
blinkPin=0; // turn on pin 13 LED 打開13號引腳LED
IBI = sampleCounter - lastBeatTime; // measure time between beats in mS 以毫秒為單位測量節拍之間的時間
lastBeatTime = sampleCounter; // keep track of time for next pulse 記錄下一個脈沖的時間
if(secondBeat){ // if this is the second beat, if secondBeat == TRUE 如果這是第二拍,如果secondBeat == TRUE
secondBeat = false; // clear secondBeat flag
for(i=0; i<=9; i++){ // seed the running total to get a realisitic BPM at startup 種子運行總數,以獲得一個實際的BPM啟動
rate[i] = IBI;
}
}
if(firstBeat){ // if it's the first time we found a beat, if firstBeat == TRUE 如果這是我們第一次找到一個節拍,如果firstBeat == TRU
firstBeat = false; // clear firstBeat flag
secondBeat = true; // set the second beat flag
EA=1; // enable interrupts again 再次啟用中斷
return; // IBI value is unreliable so discard it IBI值是不可靠的,所以放棄它
}
for(i=0; i<=8; i++){ // shift data in the rate array 在速率陣列中移動資料
rate[i] = rate[i+1]; // and drop the oldest IBI value 去掉最老的IBI值
runningTotal += rate[i]; // add up the 9 oldest IBI values 將9個最古老的IBI值相加
}
rate[9] = IBI; // add the latest IBI to the rate array 將最新的IBI添加到速率陣列中
runningTotal += r
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/75733.html
標籤:硬件使用
