main.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. #include <stdio.h>
  2. #include <pico.h>
  3. #include "pico/stdlib.h"
  4. #include "hardware/clocks.h"
  5. #include "pico/stdlib.h"
  6. #include "pico/binary_info.h"
  7. #include "hardware/i2c.h"
  8. #include "pico/multicore.h"
  9. #include "hardware/irq.h"
  10. #include "hardware/adc.h"
  11. #include "hardware/clocks.h"
  12. #include "display.h"
  13. #include "sd1306.h"
  14. #define ADC_BUF_LEN 0x100
  15. #define ADC_SAMPLE_CLOCK 3000 // 3000 sps
  16. #define HEARTBEAT_SAMPLE_CLOCK 50 // 50Hz
  17. uint16_t adc_buffer[ADC_BUF_LEN]; // ADC用リングバッファ
  18. volatile uint16_t read_pointer = 0; // バッファ用ポインタ
  19. volatile uint16_t write_pointer = 0;
  20. // ADC割り込み
  21. void adc_handler(void)
  22. {
  23. #define LOCAL_BUFFER_SIZE (ADC_SAMPLE_CLOCK / HEARTBEAT_SAMPLE_CLOCK)
  24. static int local_counter = 0;
  25. static uint16_t local_buffer[LOCAL_BUFFER_SIZE];
  26. while(! adc_fifo_is_empty()) {
  27. local_buffer[local_counter++] = (adc_fifo_get() & 0xFFF);
  28. if(local_counter >= LOCAL_BUFFER_SIZE) {
  29. uint32_t total = 0;
  30. // 平均を取る
  31. for(int i = 0 ; i < local_counter; i++ )
  32. total += local_buffer[i];
  33. adc_buffer[write_pointer++] = (uint16_t)(total / local_counter);
  34. write_pointer &= ADC_BUF_LEN - 1;
  35. local_counter = 0;
  36. }
  37. }
  38. }
  39. int main(void)
  40. {
  41. uint32_t adc_clk;
  42. stdio_init_all();
  43. // Display初期化
  44. multicore_reset_core1();
  45. multicore_launch_core1(display);
  46. // ADC初期化
  47. adc_init();
  48. adc_gpio_init(26);
  49. adc_select_input(0);
  50. adc_fifo_setup(true, false, 1, true, false);
  51. // ADCサンプリングクロック設定
  52. adc_clk = clock_get_hz(clk_adc);
  53. adc_set_clkdiv(adc_clk/ADC_SAMPLE_CLOCK);
  54. // ADC割り込み
  55. irq_set_exclusive_handler(ADC_IRQ_FIFO, adc_handler);
  56. irq_set_enabled(ADC_IRQ_FIFO, true);
  57. // ADC割り込み有効化&ADCスタート
  58. adc_irq_set_enabled(true);
  59. adc_run(true);
  60. // メインループ
  61. #define HEARTBEAT_THRESHOLD 1430 // 心拍のしきい値
  62. #define HYSTERESIS 50 // ヒステリシス
  63. #define HEARTBEAT_COUNT 10 // 基準心拍数
  64. #define LOWEST_VALUE 1240 // 約1V
  65. uint32_t last_time = 0; // 前回の時間
  66. uint32_t heartbeat_counter = 0; // 脈拍カウンタ
  67. bool ex_threshold = false; // しきい値フラグ
  68. while(true) {
  69. if(write_pointer != read_pointer) {
  70. uint16_t pos_y = 0;
  71. uint8_t pixel;
  72. uint16_t offset;
  73. uint16_t val = adc_buffer[read_pointer++] & 0xFFF;
  74. read_pointer &= ADC_BUF_LEN - 1;
  75. // 心拍センサー用の調整
  76. if( val > LOWEST_VALUE ) { // ADCの値から約1Vを切り捨てる
  77. val -= LOWEST_VALUE;
  78. }
  79. else val = 1;
  80. // ドット位置の計算
  81. pos_y = (val * OLED_HEIGHT) / (4096 - LOWEST_VALUE) ;
  82. offset = (pos_y / 8) * OLED_WIDTH;
  83. pixel = 0x01 << (pos_y % 8);
  84. // ディスプレイバッファ横スクロール
  85. memmove(&(display_buffer[1]),&(display_buffer[0]), OLED_BUF_LEN-(1+24));
  86. display_buffer[0] = 0x0;
  87. display_buffer[OLED_WIDTH] = 0x0;
  88. display_buffer[OLED_WIDTH*2] = 0x0;
  89. display_buffer[OLED_WIDTH*3] = 0x0;
  90. // ドットを打つ
  91. display_buffer[offset] = pixel;
  92. // 心拍カウンタ
  93. if((val > HEARTBEAT_THRESHOLD) && !ex_threshold)
  94. ex_threshold = true;
  95. if(val < (HEARTBEAT_THRESHOLD - HYSTERESIS)){
  96. if(ex_threshold) {
  97. heartbeat_counter++;
  98. if(heartbeat_counter >= HEARTBEAT_COUNT) {
  99. // 現在時刻をミリ秒で得る
  100. uint32_t current_time = to_ms_since_boot(get_absolute_time());
  101. if(last_time == 0) {
  102. last_time = current_time;
  103. }
  104. else {
  105. // 脈拍数を3桁の数で表示する
  106. uint32_t past_ms = current_time - last_time;
  107. uint32_t heartrate = 60 * 1000 * HEARTBEAT_COUNT / past_ms;
  108. char s[16];
  109. sprintf(s, "%3d", (int)heartrate);
  110. display_putchar(s[0], 15, 3, true);
  111. display_putchar(s[1], 14, 3, true);
  112. display_putchar(s[2], 13, 3, true);
  113. last_time = current_time;
  114. }
  115. heartbeat_counter = 0;
  116. }
  117. }
  118. ex_threshold = false;
  119. }
  120. }
  121. }
  122. }