0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何使用PIC微控制器和脈搏傳感器進(jìn)行心跳監(jiān)測(cè)

科技觀察員 ? 來源:circuitdigest ? 作者:蘇拉夫·古普塔 ? 2022-11-01 16:53 ? 次閱讀

心跳率是監(jiān)測(cè)任何人健康狀況的最重要參數(shù)。在可穿戴設(shè)備的現(xiàn)代時(shí)代,有很多設(shè)備可以測(cè)量心跳、血壓、腳步聲、燃燒的卡路里和許多其他東西。這些設(shè)備內(nèi)部有脈沖傳感器來感應(yīng)脈搏率。今天,我們還將使用帶有PIC微控制器的脈沖傳感器來計(jì)算每分鐘的心跳次數(shù)和心跳間隔,這些值將進(jìn)一步顯示在16x2字符LCD上。我們將在本項(xiàng)目中使用PIC16F877A PIC微控制器。我們已經(jīng)將脈沖傳感器與Arduino連接起來,用于患者監(jiān)測(cè)系統(tǒng)。

必需組件

PIC16F877A 微控制器

20 兆赫晶體

33pF電容 2個(gè)

4.7k 電阻器 1 個(gè)

16x2 字符液晶顯示器

10K 電位器,用于 LCD 的對(duì)比度控制

SEN-11574 脈沖傳感器

魔術(shù)貼帶

5V電源適配器

面包板和連接線

脈沖傳感器 SEN-11574

為了測(cè)量心跳,我們需要一個(gè)脈搏傳感器。在這里,我們選擇了SEN-11574脈沖傳感器,它可以在網(wǎng)上或線下商店輕松買到。我們使用此傳感器是因?yàn)橹圃焐烫峁┝耸纠a,但那是Arduino代碼。我們?yōu)镻IC微控制器轉(zhuǎn)換了該代碼。

pYYBAGNg3nSAaVSmAABIPnC_ZGs821.jpg

該傳感器非常小,非常適合通過耳垂或指尖讀取心跳。它的直徑為 0.625“,圓形 PCB 側(cè)的厚度為 0.125”。

該傳感器提供模擬信號(hào),傳感器可由3V或5V驅(qū)動(dòng),傳感器的電流消耗為4 mA,非常適合移動(dòng)應(yīng)用。傳感器配有三根電線,末端帶有 24 英寸長(zhǎng)的連接電纜和 berg 公接頭。此外,傳感器還配有魔術(shù)貼指帶,可將其佩戴在指尖上。

脈沖傳感器原理圖也由制造商提供,也可在 sparkfun.com 上購(gòu)買。

poYBAGNg3naAUieNAAA7CFTKDNk329.png

傳感器原理圖由光學(xué)心率傳感器、降噪RC電路或濾波器組成,如原理圖所示。R2、C2、C1、C3 和運(yùn)算放大器 MCP6001 用于可靠的放大模擬輸出。

用于心跳監(jiān)測(cè)的其他傳感器很少,但SEN-11574脈沖傳感器廣泛用于電子項(xiàng)目。

脈沖傳感器與PIC微控制器接口的電路圖

pYYBAGNg3DWAWiWCAAFAWbbjT9g413.png

在這里,我們已經(jīng)連接了脈沖傳感器跨 2德·微控制器的引腳單位。由于傳感器提供模擬數(shù)據(jù),我們需要通過進(jìn)行必要的計(jì)算將模擬數(shù)據(jù)轉(zhuǎn)換為數(shù)字信號(hào)。

20Mhz的晶體振蕩器通過兩個(gè)陶瓷33pF電容器連接在微控制器單元的兩個(gè)OSC引腳上。液晶屏通過微控制器的RB端口連接。

poYBAGNg3neAb-moAAEDQ6MutQk950.jpg

PIC16F877A 心跳監(jiān)護(hù)儀代碼說明

對(duì)于初學(xué)者來說,代碼有點(diǎn)復(fù)雜。制造商提供了SEN-11574傳感器的示例代碼,但它是為Arduino平臺(tái)編寫的。我們需要轉(zhuǎn)換微芯片 PIC16F877A 的計(jì)算結(jié)果。本項(xiàng)目結(jié)束時(shí)將提供完整的代碼,并附有演示視頻。并且可以從此處下載支持的C文件。

我們的代碼流相對(duì)簡(jiǎn)單,我們使用開關(guān)大小寫來執(zhí)行步驟。根據(jù)制造商的說法,我們需要每 2 毫秒從傳感器獲取數(shù)據(jù)。因此,我們使用了計(jì)時(shí)器中斷服務(wù)例程,它將每 2 毫秒觸發(fā)一個(gè)函數(shù)。

switch語句中的代碼流將如下所示:

案例1:讀取ADC

案例2:計(jì)算心跳和IBI

情況 3:在液晶屏上顯示心跳和 IBI

案例 4:空閑(不執(zhí)行任何操作)

定時(shí)器中斷功能中,我們將程序的狀態(tài)更改為情況 1:每 2 毫秒讀取一次 ADC。

因此,在 main 函數(shù)中,我們定義了程序狀態(tài)和所有開關(guān)情況。

void main() {

system_init();

main_state = READ_ADC;

while (1) {

switch (main_state) {

case READ_ADC:

{

adc_value = ADC_Read(0); // 0 is the channel number

main_state = CALCULATE_HEART_BEAT;

break;

}

case CALCULATE_HEART_BEAT:

{

calculate_heart_beat(adc_value);

main_state = SHOW_HEART_BEAT;

break;

}

case SHOW_HEART_BEAT:

{

if (QS == true) { // A Heartbeat Was Found

// BPM and IBI have been Determined

// Quantified Self "QS" true when Arduino finds a heartbeat

QS = false; // reset the Quantified Self flag for next time

// 0.9 used for getting better data. actually should not be used

BPM = BPM * 0.9;

IBI = IBI / 0.9;

lcd_com(0x80);

lcd_puts("BPM:- ");

lcd_print_number(BPM);

lcd_com(0xC0);

lcd_puts("I.B.I:- ");

lcd_print_number(IBI);

}

}

main_state = IDLE;

break;

case IDLE:

{

break;

}

default:

{

}

}

}

}

我們使用 PIC16F877A 的兩個(gè)硬件外設(shè):定時(shí)器0 和 ADC。

在 timer0.c 文件中,

TMR0 = (uint8_t)(tmr0_mask & (256-(((2 *_XTAL_FREQ)/(256*4))/1000)));

此計(jì)算提供 2 毫秒計(jì)時(shí)器中斷。計(jì)算公式為

// TimerCountMax - (((delay(ms) * Focs(hz)) / (PreScale_Val * 4)) / 1000)

如果我們看到timer_isr函數(shù),它是-

void timer_isr() {

main_state = READ_ADC;

}

在此函數(shù)中,程序狀態(tài)每 2ms 更改為 READ_ADC。

然后,CALCULATE_HEART_BEAT函數(shù)取自 Arduino 示例代碼。

void calculate_heart_beat(int adc_value) {

Signal = adc_value;

sampleCounter += 2; // keep track of the time in mS with this variable

int 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

if (Signal < T) { // T is the trough

T = Signal; // keep track of lowest point in pulse wave

}

}

………….

………………………..

此外,下面給出了完整的代碼,并通過注釋進(jìn)行了很好的解釋。這種心跳傳感器數(shù)據(jù)可以進(jìn)一步上傳到云端,并從任何地方通過互聯(lián)網(wǎng)進(jìn)行監(jiān)控,從而使其成為基于物聯(lián)網(wǎng)的心跳監(jiān)測(cè)系統(tǒng)。

/*

* File: main.c

* Author: Sourav Gupta

* By:- circuitdigest.com

* Created on September 30, 2018, 2:26 PM

*/


// PIC16F877A Configuration Bit Settings


// 'C' source line config statements


// CONFIG

#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)

#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)

#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)

#pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled)

#pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3/PGM pin has PGM function; low-voltage programming enabled)

#pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)

#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)

#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)


#include

#include

#include

#include

#include

#include "supporing_cfilelcd.h"

#include "supporing_cfileeusart1.h"

#include "supporing_cfileadc.h"

#include "supporing_cfiletmr0.h"


/*

Hardware related definition

*/

#define _XTAL_FREQ 200000000 //Crystal Frequency, used in delay


/*

Program Flow related definition

*/


#define READ_ADC 1

#define CALCULATE_HEART_BEAT 2

#define SHOW_HEART_BEAT 3

#define IDLE 0

#define DEFAULT -1


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 P = 512; // used to find peak in pulse wave, seeded

volatile int T = 512; // used to find trough in pulse wave, seeded

volatile int thresh = 530; // used to find instant moment of heart beat, seeded

volatile int amp = 0; // used to hold amplitude of pulse waveform, seeded

volatile bool firstBeat = true; // used to seed rate array so we startup with reasonable BPM

volatile bool secondBeat = false; // used to seed rate array so we startup with reasonable BPM


volatile int BPM; // int that holds raw Analog in 0. updated every 2mS

volatile int Signal; // holds the incoming raw data

volatile int IBI = 600; // int that holds the time interval between beats! Must be seeded!

volatile bool Pulse = false; // "True" when User's live heartbeat is detected. "False" when not a "live beat".

volatile bool QS = false; // becomes true when finds a beat.


int main_state = -1;

int adc_value = 0;


int tune = 0;

/*

Other Specific definition

*/

void system_init(void);


void calculate_heart_beat(int adc_value) {


Signal = adc_value;


sampleCounter += 2; // keep track of the time in mS with this variable

int 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

if (Signal < T) { // T is the trough?

T = Signal; // keep track of lowest point in pulse wave

}

}


if (Signal > thresh && Signal > P) { // thresh condition helps avoid noise

P = 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

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 = false; // clear secondBeat flag

int i;

for (i = 0; i <= 9; i++) { // seed the running total to get a realisitic BPM at startup?

rate[i] = IBI;

}

}


if (firstBeat) { // if it's the first time we found a beat, if firstBeat == TRUE

firstBeat = false; // clear firstBeat flag

secondBeat = true; // set the second beat flag

//pulse_tmr_handle = bsp_harmony_start_tmr_cb_periodic(PULSE_CHECK_TIME_INTERVAL, 0, pulse_read_cb); // enable interrupts again

return; // IBI value is unreliable so discard it

}



// keep a running total of the last 10 IBI values

uint16_t runningTotal = 0; // clear the runningTotal variable

int i;

for (i = 0; i <= 8; i++) { // shift data in the rate array?

rate[i] = rate[i + 1]; // and drop the oldest IBI value

runningTotal += rate[i]; // add up the 9 oldest IBI values

}


rate[9] = IBI; // add the latest IBI to the rate array

runningTotal += rate[9]; // add the latest IBI to runningTotal

runningTotal /= 10; // average the last 10 IBI values

BPM = 60000 / runningTotal; // how many beats can fit into a minute? that's BPM!

QS = true; // set Quantified Self flag

// QS FLAG IS NOT CLEARED INSIDE THIS ISR

}

}

if (Signal < thresh && Pulse == true) { // when the values are going down, the beat is over?

Pulse = false; // reset the Pulse flag so we can do it again

amp = P - T; // get amplitude of the pulse wave

thresh = amp / 2 + T; // set thresh at 50% of the amplitude

P = thresh; // reset these for next time

T = thresh;

}


if (N > 2500) { // if 2.5 seconds go by without a beat

thresh = 530; // set thresh default

P = 512; // set P default

T = 512; // set T default

lastBeatTime = sampleCounter; // bring the lastBeatTime up to date

firstBeat = true; // set these to avoid noise

secondBeat = false; // when we get the heartbeat back

}


}





void main() {


system_init();

main_state = READ_ADC;

while (1) {

switch (main_state) {

case READ_ADC:

{

adc_value = ADC_Read(0);

main_state = CALCULATE_HEART_BEAT;

break;

}

case CALCULATE_HEART_BEAT:

{

calculate_heart_beat(adc_value);

main_state = SHOW_HEART_BEAT;

break;

}

case SHOW_HEART_BEAT:

{

if (QS == true) { // A Heartbeat Was Found

// BPM and IBI have been Determined

// Quantified Self "QS" true when arduino finds a heartbeat

QS = false; // reset the Quantified Self flag for next time


// 0.9 used for getting better data. actually should not be used

//BPM = BPM * 0.9;

// IBI = IBI / 0.9;

//IBI = IBI * 2;

// tune = BPM / 2;

//lcd_com(0x01);

lcd_com(0x80);

lcd_puts("BPM:- ");

lcd_print_number(BPM);

lcd_puts (" ");

lcd_com(0xC0);

lcd_puts("I.B.I:- ");

lcd_print_number(IBI);

lcd_puts (" ");



}

}


main_state = IDLE;

break;



case IDLE:

{

break;

}

default:

{


}

}

}

}

/*

This Function is for system initializations.

*/


void system_init(void){

TRISB = 0x00;

lcd_init(); // This will initialize the lcd

TMR0_Initialize();

TMR0_StartTimer();

INTERRUPT_GlobalInterruptEnable();

INTERRUPT_PeripheralInterruptEnable();

ADC_Init();

}


/*

* Custom timer callback function

*/


void timer_isr() {

main_state = READ_ADC;

}


void interrupt INTERRUPT_InterruptManager (void)

{

// interrupt handler

if(INTCONbits.TMR0IE == 1 && INTCONbits.TMR0IF == 1)

{

TMR0_ISR();

}

}

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 微控制器
    +關(guān)注

    關(guān)注

    48

    文章

    7454

    瀏覽量

    150853
  • 傳感器
    +關(guān)注

    關(guān)注

    2545

    文章

    50445

    瀏覽量

    751049
  • PIC
    PIC
    +關(guān)注

    關(guān)注

    8

    文章

    507

    瀏覽量

    87427
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    如何將超聲波傳感器HC-SR04與PIC微控制器連接

    為了讓任何項(xiàng)目活躍起來,我們需要使用傳感器。傳感器充當(dāng)所有嵌入式應(yīng)用的眼睛和耳朵,它幫助數(shù)字微控制器了解這個(gè)真實(shí)模擬世界中實(shí)際發(fā)生的事情。在本教程中,我們將學(xué)習(xí)如何將超聲波傳感器HC-
    的頭像 發(fā)表于 01-01 10:08 ?3668次閱讀
    如何將超聲波<b class='flag-5'>傳感器</b>HC-SR04與<b class='flag-5'>PIC</b><b class='flag-5'>微控制器</b>連接

    基于JN5139的ZigBee無線傳感器網(wǎng)絡(luò)體溫脈搏監(jiān)測(cè)系統(tǒng)

    摘要:提出一種支持體溫與脈搏監(jiān)測(cè)的ZigBee無線傳感器網(wǎng)絡(luò)系統(tǒng)。采用傳感器終端、無線路由和基站3類基于JN5139
    發(fā)表于 11-02 15:17

    脈搏傳感器介紹

    何謂脈搏傳感器?脈搏波是心臟發(fā)送血液時(shí)產(chǎn)生的血管的體積變化波形,監(jiān)測(cè)該體積變化的檢測(cè)稱為脈搏
    發(fā)表于 05-20 04:21

    玩的就是心跳 | 用 PulseSensor 脈搏傳感器測(cè)心率

    PulseSensor,玩的,就是心跳!PulseSensor 是一款用于脈搏心率測(cè)量的光電反射式模擬傳感器將其佩戴于手指、耳垂等處利用人體組織在血管搏動(dòng)時(shí)造成透光率不同來進(jìn)行
    發(fā)表于 09-28 16:24

    智能熱傳感器如何與微控制器結(jié)合使用?

    智能熱傳感器是什么?智能熱傳感器如何與微控制器結(jié)合使用?為什么流行的存在傳感器通常不是最佳的感測(cè)模式?
    發(fā)表于 06-15 06:30

    MAX1169 ADC與PIC微控制器的接口

    MAX1169 ADC與PIC微控制器的接口 摘要:本應(yīng)用筆記介紹如何連接MAX1169模數(shù)轉(zhuǎn)換(ADC)至PIC®微控制器
    發(fā)表于 01-23 21:18 ?641次閱讀
    MAX1169 ADC與<b class='flag-5'>PIC</b><b class='flag-5'>微控制器</b>的接口

    基于ARM微控制器的動(dòng)態(tài)傾角傳感器設(shè)計(jì)

    本內(nèi)容提供了基于ARM微控制器的動(dòng)態(tài)傾角傳感器設(shè)計(jì),歡迎大家下載
    發(fā)表于 09-06 14:33 ?119次下載
    基于ARM<b class='flag-5'>微控制器</b>的動(dòng)態(tài)傾角<b class='flag-5'>傳感器</b>設(shè)計(jì)

    傳感器PIC微控制器構(gòu)成相對(duì)濕度計(jì)

    用一個(gè)具有容性響應(yīng)的傳感器和一只PIC微控制器(MCU)就可以構(gòu)成一個(gè)相對(duì)濕度計(jì)。
    發(fā)表于 06-15 14:19 ?1398次閱讀
    用<b class='flag-5'>傳感器</b>和<b class='flag-5'>PIC</b><b class='flag-5'>微控制器</b>構(gòu)成相對(duì)濕度計(jì)

    PIC微控制器技術(shù)及應(yīng)用 1-12章

    本書以美國(guó)Microchip(微芯)公司的PIC微控制器為例,詳細(xì)介紹了PIC微控制器基礎(chǔ)知識(shí)、基本應(yīng)用開發(fā),以及高級(jí)應(yīng)用開發(fā)。
    發(fā)表于 04-26 11:29 ?2次下載

    PIC微控制器技術(shù)及應(yīng)用 13-23章

    本書以美國(guó)Microchip(微芯)公司的PIC微控制器為例,詳細(xì)介紹了PIC微控制器基礎(chǔ)知識(shí)、基本應(yīng)用開發(fā),以及高級(jí)應(yīng)用開發(fā)。
    發(fā)表于 04-26 11:29 ?1次下載

    PIC微控制器技術(shù)及應(yīng)用 24-29章

    本書以美國(guó)Microchip(微芯)公司的PIC微控制器為例,詳細(xì)介紹了PIC微控制器基礎(chǔ)知識(shí)、基本應(yīng)用開發(fā),以及高級(jí)應(yīng)用開發(fā)。
    發(fā)表于 04-26 11:29 ?1次下載

    脈搏傳感器的原理說明

    脈搏傳感器分別有好多種,分別有脈搏傳感器、壓力傳感器、聲波傳感器、光學(xué)
    的頭像 發(fā)表于 02-21 20:15 ?7095次閱讀

    脈搏傳感器原理說明

    在我的世界里,脈搏傳感器分別有好多種,分別有脈搏傳感器、壓力傳感器、聲波傳感器、光學(xué)
    發(fā)表于 05-31 09:13 ?4514次閱讀

    PIC16F17146系列微控制器簡(jiǎn)化設(shè)計(jì)

    PIC16F17146系列微控制器(MCU)配有全套模擬聚焦外圍設(shè)備,用于創(chuàng)建低成本傳感器應(yīng)用。
    的頭像 發(fā)表于 09-21 10:35 ?1069次閱讀

    如何將指紋傳感器PIC微控制器連接

    目前,我們?cè)谌粘I钪须S處可見基于指紋的系統(tǒng),例如辦公室考勤,銀行員工驗(yàn)證,自動(dòng)取款機(jī)中的現(xiàn)金提取或存款,政府辦公室的身份驗(yàn)證等。我們已經(jīng)將其與Arduino和Raspberry Pi接口,今天我們將指紋傳感器PIC微控制器
    的頭像 發(fā)表于 11-07 16:08 ?3195次閱讀
    如何將指紋<b class='flag-5'>傳感器</b>與<b class='flag-5'>PIC</b><b class='flag-5'>微控制器</b>連接