#include "main.h"
#include <stdio.h>
#include <stdbool.h>
// Definisi untuk pin-pin 7-segment
// Common Cathode
#define SEG_A_PIN GPIO_PIN_0
#define SEG_B_PIN GPIO_PIN_1
#define SEG_C_PIN GPIO_PIN_2
#define SEG_D_PIN GPIO_PIN_4
#define SEG_E_PIN GPIO_PIN_12 // PB12
#define SEG_F_PIN GPIO_PIN_6
#define SEG_G_PIN GPIO_PIN_1 // PB1
// Definisi untuk pin-pin LED dan Buzzer
#define LED_NORMAL_PIN GPIO_PIN_5 // Green LED
#define LED_ALERT_PIN GPIO_PIN_7 // Red LED
#define BUZZER_PIN GPIO_PIN_8 // Buzzer
UART_HandleTypeDef huart1;
volatile int pulseCount = 0;
unsigned long startTime = 0;
bool counting = false;
bool hasStarted = false; // Ini bisa disederhanakan, tapi kita biarkan dulu
int bpm = 0;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
void displayBPM(int bpm); // Deklarasi fungsi displayBPM
// Redirect printf ke UART
int __io_putchar(int ch) {
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
// Callback untuk interrupt GPIO (saat tombol ditekan)
__attribute__((weak)) void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
if (GPIO_Pin == GPIO_PIN_3) { // Pin PA3 untuk input pulsa
// Untuk menghindari bounce, bisa tambahkan debounce di sini
// Untuk simulasi Wokwi, ini mungkin tidak terlalu kritis,
// tapi untuk hardware fisik sangat direkomendasikan.
// Contoh sederhana:
static unsigned long last_interrupt_time = 0;
unsigned long current_time = HAL_GetTick();
if (current_time - last_interrupt_time < 200) { // Debounce 200ms
return;
}
last_interrupt_time = current_time;
printf("DEBUG: Interrupt detected on PA3! Pin: %d\r\n", GPIO_Pin);
if (!counting) { // Jika belum mulai menghitung, mulai hitungan baru
pulseCount = 0;
counting = true;
hasStarted = true; // Mengindikasikan bahwa proses telah dimulai
startTime = HAL_GetTick();
printf("Counting started for 15 seconds...\r\n");
}
// Tambahkan pulsa hanya jika mode counting sedang aktif
if (counting) {
pulseCount++;
printf("Pulse detected! Current pulse count: %d\r\n", pulseCount);
}
}
}
int main(void)
{
// Inisialisasi HAL dan sistem
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
printf("Heart Rate Monitor Ready\n");
printf("Press the button on PA3 to start counting pulses.\n");
while (1) {
if (counting && (HAL_GetTick() - startTime >= 15000)) { // Pengukuran selama 15 detik
counting = false; // Hentikan hitungan
hasStarted = false; // Reset status untuk pengukuran berikutnya
// Hitung BPM (pulsa dalam 15 detik * 4 = pulsa dalam 60 detik)
bpm = pulseCount * 4;
printf("-----------------------------\r\n");
printf("Measurement complete.\r\n");
printf("Total Pulses: %d\r\n", pulseCount);
printf("Calculated BPM: %d\r\n", bpm);
// Tampilkan BPM pada 7-segment display (hanya digit satuan)
displayBPM(bpm);
// Kontrol LED dan Buzzer berdasarkan BPM
if (bpm < 60) {
printf("Alert: Low Heart Rate (Bradycardia)\r\n");
HAL_GPIO_WritePin(GPIOA, LED_ALERT_PIN, GPIO_PIN_RESET); // Matikan LED Merah
HAL_GPIO_WritePin(GPIOA, LED_NORMAL_PIN, GPIO_PIN_SET); // Nyalakan LED Hijau (opsional, bisa diganti peringatan)
HAL_GPIO_WritePin(GPIOA, BUZZER_PIN, GPIO_PIN_SET); // Nyalakan Buzzer
HAL_Delay(1000); // Buzzer dan LED Hijau menyala 1 detik
HAL_GPIO_WritePin(GPIOA, LED_NORMAL_PIN, GPIO_PIN_RESET); // Matikan LED Hijau
HAL_GPIO_WritePin(GPIOA, BUZZER_PIN, GPIO_PIN_RESET); // Matikan Buzzer
} else if (bpm > 100) {
printf("Alert: High Heart Rate (Tachycardia)\r\n");
HAL_GPIO_WritePin(GPIOA, LED_ALERT_PIN, GPIO_PIN_SET); // Nyalakan LED Merah
HAL_GPIO_WritePin(GPIOA, LED_NORMAL_PIN, GPIO_PIN_RESET); // Matikan LED Hijau
HAL_GPIO_WritePin(GPIOA, BUZZER_PIN, GPIO_PIN_SET); // Nyalakan Buzzer
HAL_Delay(1000); // Buzzer dan LED Merah menyala 1 detik
HAL_GPIO_WritePin(GPIOA, LED_ALERT_PIN, GPIO_PIN_RESET); // Matikan LED Merah
HAL_GPIO_WritePin(GPIOA, BUZZER_PIN, GPIO_PIN_RESET); // Matikan Buzzer
} else {
printf("Heart Rate Normal\r\n");
HAL_GPIO_WritePin(GPIOA, LED_ALERT_PIN, GPIO_PIN_RESET); // Matikan LED Merah
HAL_GPIO_WritePin(GPIOA, LED_NORMAL_PIN, GPIO_PIN_SET); // Nyalakan LED Hijau
HAL_GPIO_WritePin(GPIOA, BUZZER_PIN, GPIO_PIN_RESET); // Pastikan Buzzer mati
}
printf("-----------------------------\r\n\n");
// Tunggu sebentar sebelum siap untuk pengukuran berikutnya,
// atau tunggu tombol ditekan lagi untuk memulai.
// HAL_Delay(2000); // Opsional: Beri jeda 2 detik sebelum memungkinkan pengukuran baru
}
// Pastikan 7-segment selalu menampilkan digit terakhir BPM jika tidak ada alert
// Atau hanya tampilkan saat selesai pengukuran
// Jika Anda ingin display selalu on, Anda bisa memindahkan displayBPM(bpm); ke sini,
// tetapi akan selalu menampilkan digit 0 sampai ada perhitungan pertama.
// displayBPM(bpm); // Jika ingin selalu menampilkan BPM terakhir
}
}
// Fungsi untuk menampilkan digit pada 7-segment display (Common Cathode)
// Hanya menampilkan digit satuan dari angka BPM
void displayBPM(int bpm) {
int digit = bpm % 10; // Ambil digit satuan
// Matikan semua segmen terlebih dahulu untuk menghindari ghosting
HAL_GPIO_WritePin(GPIOA, SEG_A_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, SEG_B_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, SEG_C_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, SEG_D_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, SEG_E_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, SEG_F_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, SEG_G_PIN, GPIO_PIN_RESET);
switch (digit) {
case 0: // 0: A B C D E F
HAL_GPIO_WritePin(GPIOA, SEG_A_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, SEG_B_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, SEG_C_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, SEG_D_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, SEG_E_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, SEG_F_PIN, GPIO_PIN_SET);
break;
case 1: // 1: B C
HAL_GPIO_WritePin(GPIOA, SEG_B_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, SEG_C_PIN, GPIO_PIN_SET);
break;
case 2: // 2: A B G E D
HAL_GPIO_WritePin(GPIOA, SEG_A_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, SEG_B_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, SEG_G_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, SEG_E_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, SEG_D_PIN, GPIO_PIN_SET);
break;
case 3: // 3: A B G C D
HAL_GPIO_WritePin(GPIOA, SEG_A_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, SEG_B_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, SEG_G_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, SEG_C_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, SEG_D_PIN, GPIO_PIN_SET);
break;
case 4: // 4: F G B C
HAL_GPIO_WritePin(GPIOA, SEG_F_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, SEG_G_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, SEG_B_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, SEG_C_PIN, GPIO_PIN_SET);
break;
case 5: // 5: A F G C D
HAL_GPIO_WritePin(GPIOA, SEG_A_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, SEG_F_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, SEG_G_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, SEG_C_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, SEG_D_PIN, GPIO_PIN_SET);
break;
case 6: // 6: A F G E C D
HAL_GPIO_WritePin(GPIOA, SEG_A_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, SEG_F_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, SEG_G_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, SEG_E_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, SEG_C_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, SEG_D_PIN, GPIO_PIN_SET);
break;
case 7: // 7: A B C
HAL_GPIO_WritePin(GPIOA, SEG_A_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, SEG_B_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, SEG_C_PIN, GPIO_PIN_SET);
break;
case 8: // 8: A B C D E F G
HAL_GPIO_WritePin(GPIOA, SEG_A_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, SEG_B_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, SEG_C_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, SEG_D_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, SEG_E_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, SEG_F_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, SEG_G_PIN, GPIO_PIN_SET);
break;
case 9: // 9: A B C D F G
HAL_GPIO_WritePin(GPIOA, SEG_A_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, SEG_B_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, SEG_C_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, SEG_D_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, SEG_F_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, SEG_G_PIN, GPIO_PIN_SET);
break;
default: // Matikan semua segmen jika bukan digit 0-9
break;
}
}
// Inisialisasi GPIO
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
// Aktifkan clock untuk GPIOA dan GPIOB
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
// Konfigurasi Tombol (PA3) sebagai input interrupt
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; // Tombol terhubung ke GND saat ditekan
GPIO_InitStruct.Pull = GPIO_PULLUP; // Gunakan pull-up internal
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// Konfigurasi pin output untuk LED (PA5, PA7) dan Buzzer (PA8) di GPIOA
GPIO_InitStruct.Pin = LED_NORMAL_PIN | LED_ALERT_PIN | BUZZER_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// Konfigurasi pin output untuk 7-Segment di GPIOA (A, B, C, D, F)
GPIO_InitStruct.Pin = SEG_A_PIN | SEG_B_PIN | SEG_C_PIN | SEG_D_PIN | SEG_F_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// Konfigurasi pin output untuk 7-Segment di GPIOB (E, G)
GPIO_InitStruct.Pin = SEG_E_PIN | SEG_G_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
// Konfigurasi NVIC untuk interrupt PA3
// EXTI3_IRQn sesuai dengan PA3
HAL_NVIC_SetPriority(EXTI3_IRQn, 0, 0); // Prioritas 0 (tertinggi)
HAL_NVIC_EnableIRQ(EXTI3_IRQn);
}
// Inisialisasi UART1
void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 9600;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
// Error Handling (jika diperlukan)
}
}
// Konfigurasi Clock Sistem (HSI internal oscillator)
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
// Reset semua pengaturan RCC
HAL_RCC_DeInit();
// Konfigurasi HSI oscillator
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; // Tidak menggunakan PLL
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
// Error Handling (jika diperlukan)
}
// Konfigurasi clock bus
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK |
RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; // Sumber SYSCLK dari HSI
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
// Error Handling (jika diperlukan)
}
}Loading
stm32-bluepill
stm32-bluepill