
هدف ما از انجام این پروژه چیست؟
هدف از انجام این پروژه، آشنایی کامل با عملکرد و راهاندازی ماژول ضربان قلب GebraBit BH1790GLC با استفاده از برد Arduino UNO است. در این پروژه یاد میگیریم که چگونه سنسور اپتیکال BH1790GLC با استفاده از بازتاب نور سبز از سطح پوست، تغییرات جریان خون را تشخیص داده و آن را به سیگنال الکتریکی قابل اندازهگیری تبدیل میکند. هدف دیگر، آموزش نحوهی ایجاد ارتباط I²C بین سنسور و آردوینو، خواندن دادههای خام نوری و پردازش آنها برای بهدستآوردن مقدار ضربان قلب (BPM) است. همچنین در طی این پروژه با مفاهیم مهمی مانند تنظیم نرخ نمونهبرداری، شدت نور LED آشنا میشویم. در نهایت خروجی به صورت عددی و در Monitor Serial نمایش داده میشود تا بتوان رفتار سیگنال ضربان قلب را در لحظه مشاهده کرد.
در این آموزش چه چیزهایی یاد میگیریم؟
- نحوهی کار سنسور BH1790GLC و مفهوم اندازهگیری اپتیکال ضربان قلب با استفاده از نور بازتابی از پوست.
- برقراری ارتباط I²C بین سنسور و برد آردوینو و شناسایی آدرس دستگاه در شبکه I²C.
- خواندن دادههای خام نوری (LED ON/OFF) از رجیسترهای داخلی سنسور.
- نصب و استفاده از کتابخانههای ROHM و GebraBit در Arduino IDE برای راهاندازی سریع سنسور.
- تبدیل دادههای خام به سیگنال قابل تحلیل و محاسبهی تعداد ضربان قلب بر حسب BPM.
- تنظیم پارامترهای عملکرد سنسور مانند شدت LED، نرخ نمونهبرداری و زمان یکپارچهسازی برای بهبود دقت.
- نمایش سیگنال و نتایج ضربان قلب بهصورت عددی در Serial Monitor و Serial Plotter.
برای شروع این پروژه به چه چیزهایی نیاز داریم؟
برای اجرای این پروژه به سختافزار و نرمافزار نیاز داریم. عناوین این سختافزارها و نرمافزارها در جدول زیر به شما ارائه شده است و میتوانید با کلیک بر روی هر یک، آن را تهیه/دانلود کرده و برای شروع آماده شوید.
| سختافزارهای مورد نیاز | نرمافزارهای مورد نیاز |
| Arduino UNO (یا بردهای سازگار مثل Nano / Mega) | Arduino IDE |
| ماژول ضربان قلب GebraBit BH1790GLC | درایور USB Arduino (CH340 یا مشابه) |
| کابل USB برای اتصال آردوینو به کامپیوتر | کتابخانههای BH1790GLC و FlexiTimer2 |
| سیم جامپر (M–F) یا بردبورد برای اتصال I²C | |
ابتدا مانند تصویر زیر ماژول ضربان قلب GebraBit BH1790GLC را به صورت زیر به آردوینو متصل می کنیم:

- توجه کنید که برای راه اندازی این ماژول احتیاج به Logic Level Converter دارید و در صورت اتصال مستقیم ماژول به آردوینو امکان آسیب به سنسور خواهد شد.
- پس از اتصال آردوینو به ماژول توسط Logic Level Converter، کتابخانه BH1790GLC دانلود و به نرم افزار آردوینو اضافه و برنامه پیوست را اجرا کنید.
سورس کد
برای اجرای این پروژه به bh1790.h احتیاج داریم.
ثابتهای عمومی: کدهای بازگشت (Return Codes)
#define BH1790_RC_OK (0)
#define BH1790_RC_NO_EXIST (-1)
#define BH1790_RC_I2C_ERR (-2)
کدهای وضعیت توابع کتابخانه:
- OK یعنی موفق،
- NO_EXIST یعنی سنسور پیدا نشد (پاسخ/ID نامعتبر)،
- I2C_ERR یعنی خطای ارتباط I²C.
آدرس I²C سنسور
#define BH1790_SLAVE_ADDRESS (0x5BU)
آدرس 7بیتی I²C سنسور 0x5B است. (پس در اسکنر I²C باید همین آدرس دیده شود.)
آدرس رجیسترها
#define BH1790_PARTID (0x10U) // R
#define BH1790_RESET (0x40U) // W
#define BH1790_MEAS_CTRL1 (0x41U) // R/W
#define BH1790_MEAS_CTRL2 (0x42U) // R/W
#define BH1790_MEAS_START (0x43U) // R/W
#define BH1790_DATAOUT_LEDOFF_LSBS (0x54U) // R
#define BH1790_DATAOUT_LEDOFF_MSBS (0x55U) // R
#define BH1790_DATAOUT_LEDON_LSBS (0x56U) // R
#define BH1790_DATAOUT_LEDON_MSBS (0x57U) // R
#define BH1790_MANUFACTURERID (0x92U) // R
رجیسترهای مهم برای:
- شناسهها (PARTID, MANUFACTURERID)
- ریست نرمافزاری (RESET)
- کنترل اندازهگیری (MEAS_CTRL1/2, شروع با MEAS_START)
- خواندن داده خام در دو وضعیت: وقتی LED خاموش است (LEDOFF) و روشن است (LEDON)؛ هرکدام ۲ بایت (LSB/MSB) دارند.
مقادیر مورد انتظار شناسهها
#define BH1790_PARTID_VAL (0x0DU)
#define BH1790_MANUFACTURERID_VAL (0xE0U)
وقتی این رجیسترها را بخوانید، باید این مقادیر را برگردانند. برای تشخیص صحیح بودن چیپ استفاده میشود.
پارامترهای پیکربندی — رجیستر RESET
// 7bit: SWRESET
#define BH1790_PRM_SWRESET (0x01U)
نوشتن این مقدار «ریست نرمافزاری» سنسور را انجام میدهد.
پارامترهای پیکربندی — رجیستر MEAS_CTRL1
// 7bit: RDY
#define BH1790_PRM_CTRL1_RDY (0x01U) // فعال بودن اسیلاتور داخلی
// 2bit: LED_LIGHTING_FREQ (فرکانس مدولهکردن LED)
#define BH1790_PRM_CTRL1_FREQ_128HZ (0x00U)
#define BH1790_PRM_CTRL1_FREQ_64HZ (0x01U)
// 1-0bit: RCYCLE (نرخ خواندن داده)
#define BH1790_PRM_CTRL1_RCYCLE_64HZ (0x01U)
#define BH1790_PRM_CTRL1_RCYCLE_32HZ (0x02U)
- بیت RDY: آمادهبودن بلوک کلاک/اسیلاتور.
- LED_LIGHTING_FREQ: فرکانس روشن/خاموششدن پالس LED (۶۴ یا ۱۲۸ هرتز).
- RCYCLE: نرخ خروجی/نمونهبرداری داده (۳۲ یا ۶۴ هرتز).
پارامترهای پیکربندی — رجیستر MEAS_CTRL2
// 7-6bit: LED_EN (حالت درایو LED1/LED2)
#define BH1790_PRM_CTRL2_EN_NONE (0x00U) // LED1: Pulsed, LED2: Pulsed
#define BH1790_PRM_CTRL2_EN_LED1 (0x01U) // LED1: Constant, LED2: Pulsed
#define BH1790_PRM_CTRL2_EN_LED2 (0x02U) // LED1: Pulsed, LED2: Constant
#define BH1790_PRM_CTRL2_EN_LED1_LED2 (0x03U) // LED1: Constant, LED2: Constant
// 5bit: LED_ON_TIME (زمان روشنبودن هر پالس)
#define BH1790_PRM_CTRL2_ONTIME_0_3MS (0x00U)
#define BH1790_PRM_CTRL2_ONTIME_0_6MS (0x01U)
// 3-0bit: LED_CURRENT (جریان LED)
#define BH1790_PRM_CTRL2_CUR_0MA (0x00U)
#define BH1790_PRM_CTRL2_CUR_1MA (0x08U)
#define BH1790_PRM_CTRL2_CUR_2MA (0x09U)
#define BH1790_PRM_CTRL2_CUR_3MA (0x0AU)
#define BH1790_PRM_CTRL2_CUR_6MA (0x0BU)
#define BH1790_PRM_CTRL2_CUR_10MA (0x0CU)
#define BH1790_PRM_CTRL2_CUR_20MA (0x0DU)
#define BH1790_PRM_CTRL2_CUR_30MA (0x0EU)
#define BH1790_PRM_CTRL2_CUR_60MA (0x0FU)
LED_EN: تعیین میکند LED1/LED2 بهصورت پالسی یا ثابت درایو شوند. (برای برخی بردها هر دو LED سبز هستند.)
:LED_ON_TIME: عرض پالس روشنبودن LED (۰٫۳ یا ۰٫۶ میلیثانیه).
: LED_CURRENT: جریان درایو LED از ۰ تا ۶۰ mA (انتخاب متناسب با روشنایی/مصرف).
شروع اندازهگیری — رجیستر MEAS_START
#define BH1790_PRM_MEAS_ST (0x01U)
نوشتن این بیت، روند اندازهگیری را استارت میکند.
شناسههای نوعِ پارامتر (برای API سطح بالاتر)
#define BH1790_PRM_CTRL1_FREQ (0U)
#define BH1790_PRM_CTRL1_RCYCLE (1U)
#define BH1790_PRM_CTRL2_EN (2U)
#define BH1790_PRM_CTRL2_ONTIME (3U)
#define BH1790_PRM_CTRL2_CUR (4U)
برای اینکه در توابع پیکربندی، نوع پارامتر را با یک ID ارجاع بدهید (سوئیچ/کیس روی نوع پارامتر).
پروتوتایپ توابع عمومی
int8_t bh1790_Init(void);
int8_t bh1790_SoftReset(void);
// I2C must be implemented by user
int8_t bh1790_Write(uint8_t adr, uint8_t *data, uint8_t size);
int8_t bh1790_Read (uint8_t adr, uint8_t *data, uint8_t size);
: bh1790_Init: راهاندازی اولیه (چکِ IDها، تنظیم رجیسترها، آمادهسازی).
: bh1790_SoftReset: ریست نرمافزاری.
: bh1790_Write/Read: رابط سطح پایین I²C که باید توسط شما یا لایهی پلتفرم پیادهسازی شود (ارسال آدرس رجیستر و داده/دریافت داده).
جمعبندی کاربردی
- برای راهاندازی: با bh1790_Init() و سپس تنظیمهای دلخواه در MEAS_CTRL1/2، بعد MEAS_START را ست کنید.
- دادهی خام از چهار رجیستر DATAOUT_* خوانده میشود (دو بایت LED خاموش و دو بایت LED روشن). اختلاف/نسبت این دو، پایهی استخراج سیگنال ضربان است.
- اگر I²C خطا داد یا IDها مطابق نبودند، کدهای بازگشت منفی به شما میگویند مشکل از سختافزار/اتصال/آدرسدهی است.
اگر خواستی، همین هدر را مبنا بگیریم و یک پیادهسازی آردوینویی (Wire) برای bh1790_Write/Read و یک init نمونه با تنظیمات پیشنهادی 32Hz/LED 10–20mA آماده کنم.
- برنامه نمونه در آردوینو
بعد از اتصال ماژول به آردوینو و اضافه کردن کتابخانه سنسور به نرم افزار آردوینو به مسیر زیر بروید و کد نمونه را باز کنید.
File > Examples > BH1790GLC
شرح فایل نمونه
این کد در واقع برنامهی اصلی آردوینو برای خواندن ضربان قلب از سنسور BH1790GLC است. گامبهگام (بلوکبهبلوک) توضیحش می دهیم:
تعریفها و متغیرهای اولیه
#define SAMPLING_CNT_32HZ (32)
BH1790GLC bh1790glc;
volatile bool timer_flg;
void timer_isr(void);
static uint8_t s_cnt_freq = 0;
: SAMPLING_CNT_32HZ تعداد نمونهها در هر چرخهی ۱ ثانیه است (چون نرخ نمونهبرداری ۳۲ هرتز است).
: bh1790glc یک شیء از کلاس درایور سنسور BH1790GLC است.
: timer_flg یک فلگ (علامت) است که توسط تایمر تنظیم میشود و در loop() بررسی میگردد.
: s_cnt_freq شمارندهی نمونهها است.
تابع setup()
void setup() {
uint16_t ret16 = ERROR_NONE;
timer_flg = false;
Serial.begin(115200);
while (!Serial);
- مقدار اولیهی خطا صفر میشود.
- ارتباط سریال برای نمایش دادهها با سرعت 115200 بیت راهاندازی میشود.
- while(!Serial) منتظر میماند تا ارتباط سریال برقرار شود.
Wire.begin();
Wire.setClock(400000L);
فعالسازی I²C برای ارتباط با سنسور.
تنظیم فرکانس I²C روی 400kHz (حالت fast mode).
s_cnt_freq = 0;
ret16 = hr_bh1790_Init();
مقداردهی اولیه شمارنده.
فراخوانی تابع hr_bh1790_Init() برای راهاندازی سنسور (چک شناسه و تنظیم رجیسترهای کنترلی).
if (ret16 == ERROR_NONE) {
Serial.println(F("BPM, wearing"));
اگر راهاندازی موفق باشد، پیغام آغاز محاسبهی ضربان چاپ میشود.
FlexiTimer2::stop();
FlexiTimer2::set(250, 1.0/8000, timer_isr); // 32Hz timer
FlexiTimer2::start();
از کتابخانهی FlexiTimer2 برای ساخت تایمر دقیق نرمافزاری استفاده میشود.
تنظیم تایمر بهطوریکه هر 31.25 میلیثانیه (≈32Hz) تابع timer_isr() اجرا شود.
هر بار که تایمر تریگر میشود، فلگ timer_flg را فعال میکند.
ret16 = hr_bh1790_StartMeasure();
شروع اندازهگیری از سنسور (فعال کردن رجیستر MEAS_START).
در صورت خطا، پیغام مناسب چاپ میشود.
} else {
Serial.println(F("Error: hr_bh1790_Init function"));
اگر سنسور پیدا نشود یا مقدار ID اشتباه باشد، خطا در سریال چاپ میشود.
تابع loop()
void loop() {
uint8_t bpm = 0U;
uint8_t wearing = 0U;
uint16_t ret16 = ERROR_NONE;
متغیرهای محلی برای ذخیرهی ضربان قلب (BPM) و وضعیت تماس انگشت (wearing) تعریف میشوند.
if (timer_flg) {
ret16 = hr_bh1790_Calc(s_cnt_freq);
در هر تریگر تایمر (وقتی timer_flg=true شود)، یک نمونهی جدید از دادههای سنسور گرفته و پردازش میشود.
تابع hr_bh1790_Calc() وظیفهی محاسبهی داخلی و فیلترکردن دادهها را دارد.
if (ret16 == ERROR_NONE) {
s_cnt_freq++;
if (s_cnt_freq >= SAMPLING_CNT_32HZ) {
s_cnt_freq = 0;
hr_bh1790_GetData(&bpm, &wearing);
Serial.print(bpm, DEC);
Serial.print(F(","));
Serial.println(wearing, DEC);
}
- در هر فراخوانی موفق، شمارندهی نمونه افزایش مییابد.
- بعد از جمع شدن ۳۲ نمونه (۱ ثانیه)، شمارنده صفر و دادهی BPM و وضعیت پوشیدن خوانده میشود.
- مقادیر در پورت سریال چاپ میشوند (مثلاً: 78,1 یعنی 78 ضربه در دقیقه و در حال تماس با پوست).
} else {
Serial.println(F("Error: hr_bh1790_Calc function"));
در صورت خطا در پردازش داده، پیغام هشدار چاپ میشود.
timer_flg = false;
}
}
در پایان هر سیکل، فلگ ریست میشود تا در تریگر بعدی تایمر دوباره فعال گردد.
تابع وقفهی تایمر
void timer_isr(void) {
timer_flg = true;
}
این تابع هر 31.25 میلیثانیه اجرا میشود و صرفاً فلگ را فعال میکند تا loop() بداند زمان نمونهگیری رسیده است.
تابع bh1790_Write()
int8_t bh1790_Write(uint8_t adr, uint8_t *data, uint8_t size)
{
byte rc = 0;
int8_t ret = 0;
rc = bh1790glc.write(adr, data, size);
if (rc == 0) ret = BH1790_RC_OK;
else ret = BH1790_RC_I2C_ERR;
return (ret);
}
- این تابع دادهای را در رجیستر خاصی از BH1790GLC مینویسد.
- از تابع write() کتابخانهی ROHM استفاده میکند.
- اگر نوشتن موفق بود، BH1790_RC_OK برمیگرداند، در غیر اینصورت خطای I²C.
تابع bh1790_Read()
int8_t bh1790_Read(uint8_t adr, uint8_t *data, uint8_t size)
{
byte rc = 0;
int8_t ret = 0;
rc = bh1790glc.read(adr, data, size);
if (rc == 0) ret = BH1790_RC_OK;
else ret = BH1790_RC_I2C_ERR;
return (ret);
}
مشابه تابع قبل اما برای خواندن داده از رجیسترها.
دادهها در بافر data ذخیره میشوند.
در صورت موفقیت، مقدار بازگشتی صفر (OK) است.
جمعبندی عملکرد کلی
- :setup()ارتباط I²C، سریال و تایمر را آماده میکند و سنسور را راهاندازی میکند.
- :loop()هر 31ms دادهی جدید میخواند، هر ثانیه یک بار BPM را محاسبه و چاپ میکند.
- :timer_isr()فقط زمانبندی نمونهگیری را کنترل میکند.
- bh1790_Read/Write() :دسترسی سطح پایین به رجیسترهای سنسور از طریق I²C را فراهم میکنند.
اجرای کد
آردوینو خود را به کامپیوتر متصل کنید و مدل و پورت آردوینو خود را انتخاب کنید. سپس نمونه کد را ابتدا Verify و سپس Upload کنید . بعد از Upload کردن کد Serial Monitor را باز کرده و می توانید خروجی های سنسور را مشاهده کنید .
