2023年10月7日 星期六

[小專題]三合一復健球(未完成)

 

[小專題]三合一復健球(未完成)

112.10.08

1.

 

 

2.程式介紹

#include <Arduino.h>

#include <SoftwareSerial.h>

#include <OLED.h>

enum TM7711_Mode

{

  diff_10Hz = 1,

  Temp = 2,

  diff_40Hz = 3,

};

struct Press

{

  uint8_t state;

  int frep;

  unsigned long startTime;

  unsigned long countdownTime;

  unsigned long diffTime;

};

struct ButtonData

{

  bool isStart;

  int time;

};

const uint8_t Start_Button = 2;

const uint8_t Time_Button = 3;

const uint8_t Buzzer = 4;

const uint8_t TM7711_SCK = 5;

const uint8_t TM7711_DOUT = 6;

const uint8_t BT_RX = 7;

const uint8_t BT_TX = 8;

SoftwareSerial BT(BT_RX, BT_TX);

OLED oled(128, 64);

const uint8_t Mean_Size = 10;

uint8_t Mean_Count = 0;

int data[Mean_Size];

unsigned long data_sum = 0;

const unsigned long data_max = 1024;

const unsigned long data_min = 0;

unsigned long data_reference = 0;

unsigned long oled_time = 0;

char *oled_num = new char[10];

bool data_isUp = false;

Press press;

ButtonData button;

char BT_data;

void Correction();

int TM7711read(TM7711_Mode mode);

unsigned long Averagefilter(int *buf, unsigned long bufmax, unsigned long bufmin);

void Pressjudge();

void BuzzerMode(bool isStart);

void OLED_display();

char *int2char(int num);

void setup()

{

  Serial.begin(9600);

  // === OLED init ===

  oled.begin();

  oled.init(2, WHITE);

  oled.print(0, 20, "Initializing...", true);

  // === TM7711 init ===

  pinMode(TM7711_SCK, OUTPUT);

  pinMode(TM7711_DOUT, INPUT);

  Correction();

  // === Button init ===

  pinMode(Start_Button, INPUT);

  pinMode(Time_Button, INPUT);

  // === Buzzer init ===

  pinMode(Buzzer, OUTPUT);

  // === BT init ===

  BT.begin(9600);

  BT_data = 'n';

  Serial.println("Initialized");

  oled.clear();

  oled.print(0, 20, "Initialized", true);

  delay(2000);

  oled.clear();

  oled.print(0, 20, "Time: 0min", true);

}

void loop()

{

  if (BT.available())

    BT_data = BT.read();

  if ((!digitalRead(Start_Button) || BT_data == 'S') && !button.isStart && button.time)

  {

    oled.clear();

    oled.print(0, 20, "Initializing...", true);

    Correction();

    Correction();

    button.isStart = true;

    data_isUp = data_reference > 512 ? true : false;

    press.frep = 0;

    press.state = 0;

    BT_data = 'n';

    BuzzerMode(true);

    Serial.println("Start");

    BT.print("S");

    oled.clear();

    oled.print(0, 20, "Start", true);

    delay(2000);

    press.diffTime = press.startTime = oled_time = millis();

    oled.init(1, WHITE);

    OLED_display();

  }

  else if ((BT_data == '0' || BT_data == '1' || BT_data == '2' || BT_data == '3') && !button.isStart)

  {

    button.time = BT_data - '0';

    press.countdownTime = button.time * 60000;

    BT_data = 'n';

    BuzzerMode(false);

    Serial.print("Time: ");

    Serial.print(button.time);

    Serial.println("min");

    oled.clear();

    oled.print(0, 20, "Time: ", false);

    oled._print(OLED_char, 2, int2char(button.time), "min");

    oled.display();

    delay(250);

  }

  else if ((!digitalRead(Time_Button)) && !button.isStart)

  {

    button.time = (button.time + 1) % 4;       // 0, 1, 2, 3

    press.countdownTime = button.time * 60000; // 0s, 60s, 120s, 240s

    BT_data = 'n';

    switch (button.time)

    {

    case 0:

      BT.print("a");

      break;

    case 1:

      BT.print("b");

      break;

    case 2:

      BT.print("c");

      break;

    case 3:

      BT.print("d");

      break;

    default:

      break;

    }

    BuzzerMode(false);

    Serial.print("Time: ");

    Serial.print(button.time);

    Serial.println("min");

    oled.clear();

    oled.print(0, 20, "Time: ", false);

    oled._print(OLED_char, 2, int2char(button.time), "min");

    oled.display();

 

    delay(250);

  }

 

  if (!button.isStart || button.time == 0)

    return;

 

  if (millis() - press.startTime >= press.countdownTime) // End

  {

    button.isStart = false;

    Serial.println("End");

    oled.clear();

    BT.print(press.frep);

    oled.init(2, WHITE);

    oled.print(0, 20, "End", true);

    delay(2000);

    BT.print("E");

    oled.clear();

    oled.print(0, 20, "This time: ", false);

    oled._print(OLED_char, 2, int2char(press.frep), "times");

    oled.display();

    BuzzerMode(true);

 

    while (digitalRead(Start_Button))

      yield();

    oled.clear();

    oled.print(0, 20, "Time: ", false);

    oled._print(OLED_char, 2, int2char(button.time), "min");

    oled.display();

    delay(250);

  }

 

  data[Mean_Count] = TM7711read(diff_40Hz);

  data_sum = Averagefilter(data, data_max, data_min);

  Mean_Count = (Mean_Count + 1) % Mean_Size;

 

  Pressjudge();

  Serial.print(data_reference);

  Serial.print(" ");

  Serial.print(data_sum);

  Serial.print(" ");

  Serial.println(press.frep);

 

  if (millis() - oled_time > 1000 && button.isStart)

  {

    OLED_display();

    oled_time = millis();

    BT.print(press.frep);

  }

 

  delay(25);

}

 

void Correction()

{

  data_sum = 0;

  for (uint8_t i = 0; i < 50; i++)

  {

    data[Mean_Count] = TM7711read(diff_40Hz);

    Mean_Count = (Mean_Count + 1) % Mean_Size;

    if (i > 10)

      data_sum += Averagefilter(data, data_max, data_min);

 

    delay(25);

  }

 

  data_reference = data_sum / 40;

  Mean_Count = 0;

}

 

int TM7711read(TM7711_Mode mode = diff_10Hz)

{

  int buf = 0;

 

  for (int i = 0; i < 24; i++)

  {

    digitalWrite(TM7711_SCK, HIGH);

    buf <<= 1;

    delayMicroseconds(5);

    if (digitalRead(TM7711_DOUT))

      buf |= 1;

    digitalWrite(TM7711_SCK, LOW);

  }

 

  for (int i = 0; i < mode; i++)

  {

    digitalWrite(TM7711_SCK, HIGH);

    delayMicroseconds(1);

    digitalWrite(TM7711_SCK, LOW);

    if (mode - i != 1)

      delayMicroseconds(1);

  }

 

  return buf / 256;

}

 

unsigned long Averagefilter(int *buf, unsigned long bufmax = 1024, unsigned long bufmin = 0)

{

  unsigned long ret = 0;

  for (int i = 0; i < Mean_Size; i++)

  {

    ret += buf[i];

  }

 

  ret /= Mean_Size;

  ret = min(ret, bufmax);

  ret = max(ret, bufmin);

 

  return ret;

}

 

void Pressjudge()

{

  if (!press.state && millis() - press.diffTime > 750)

  {

    if (data_sum > data_reference + data_reference * 0.75 && !data_isUp)

    {

      press.state = 1;

      press.diffTime = millis();

    }

    else if (data_sum < data_reference - data_reference * 0.75 && data_isUp)

    {

      press.state = 2;

      press.diffTime = millis();

    }

  }

  else if (press.state && millis() - press.diffTime > 300)

  {

    if ((press.state == 1 && data_sum > data_reference) &&

        (press.state == 2 && data_sum < data_reference))

      return;

 

    press.state = 0;

    press.frep++;

    press.diffTime = millis();

    BuzzerMode(false);

  }

}

 

void BuzzerMode(bool isStart)

{

  if (isStart)

  {

    tone(Buzzer, 1000, 200);

    delay(200);

    noTone(Buzzer);

    tone(Buzzer, 1000, 200);

    delay(200);

    noTone(Buzzer);

  }

  else

  {

    tone(Buzzer, 1000, 200);

    delay(200);

    noTone(Buzzer);

  }

}

 

void OLED_display()

{

  oled.clear();

  oled.print(0, 14, "Remaining time: ", false);

  oled._print(OLED_char, 2, int2char((press.countdownTime - (millis() - press.startTime)) / 1000), "sec");

  oled.print(0, 42, "Press: ", false);

  oled._print(OLED_char, 2, int2char(press.frep), "times");

  oled.display();

}

 

char *int2char(int num)

{

  sprintf(oled_num, "%d", num);

  return oled_num;

}

 

沒有留言:

張貼留言