Bytebeat, Interruptions, Arduino UNO (atMega328p)

Bonjour à tous,

Mon souhait est de creer un module bytebeat a l'aide de l'arduino UNO qui pourrait prendre une formule depuis une interface utilisateur (ecran OLED).

En faisant des recherche je suis tombé sur ce topic: One-line algorithmic music.
Les sketchs utilisent souvent du portMapping/portRegister pour obtenir une pwm rapide.

Ce que je ne comprends pas, c'est, comment peuvent t'ils sonner a peu près pareil même si certains sketchs semblent plus lourd que d'autres ?

En effet, en me basant sur les sketchs existants et en bidouillant les différents valeurs, j'obtiens un résultat mais dont la modification du dutyCycle semble bien plus lent et différent de l'onde générée par leur sketchs.

Mon code est lourd car j'utilise différentes bibliothèques pour convertir une formule sous la forme d'une chaine en résultat qui viendra moduler le dutyCycle de la pwm générée.

Mes questions:
mon projet est t'il trop ambitieux pour une atMega328p ?
Les interruptions ne sont t'elles pas supposées fonctionner en parallele du loop et permettre de gerer rapidement cette modulation (du dutyCycle) ?
Auriez vous des solutions ou des axes de travail a me proposer pour continuer ce projet ?

Le code :

#include "Arduino.h"
#include <SPI.h>
#include <Wire.h>

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_GrayOLED.h>

#include "tinyexpr.h"

#include <TimerOne.h>

/*
PIN A5 <--> OLED SCK
PIN A4 <--> OLED SDA

PIN A1 <--> Symbol Pot

PIN 10 <--> MCP CS
PIN 11 <--> MCP SDI
PIN 13 <--> MCP SCK
*/

/* DISPLAY */
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

int indexOled = 0;
const int OLED_ARRAY_SIZE = (((SCREEN_WIDTH / 6) - 1) * 4) - 1;
char oledArray[OLED_ARRAY_SIZE] = {' '};

/* ARRAYS */
const int NUMBER_ARRAY_SIZE = 11;
const short numberArray[NUMBER_ARRAY_SIZE] = {' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
short numberArrayIndex = 0;

const int PSI_ARRAY_SIZE = 14;
const short psiArray[PSI_ARRAY_SIZE] = {'t', '%', '^', '&', '|', '>', '<', '(', ')', '!', '/', '+', '-', '*'};
short psiArrayIndex = 0;

/* PINS */
const int PIN_BUTTON_NUMBER = 2;
const int PIN_BUTTON_PSI = 3;
const int PIN_BUTTON_T = 7;
const int PIN_BUTTON_BACKWARD = 4;
const int PIN_BUTTON_FORWARD = 5;
// const int PIN_BUTTON_RESET = 13;
const int PIN_OUTPUT_PWM = 9;
const int PIN_KNOB_MENU = A1;

/* FORMULA */
int indexFormula = 0;
//(width / sizeCharOled) * lines
const int FORMULA_SIZE = ((SCREEN_WIDTH / 6) - 1) * 4;
char formula[FORMULA_SIZE] = {' '};
char *previousFormula = NULL;

void copy(char *src, char *dst, int len)
{
  for (int i = 0; i < len - 1; i++)
  {
    *dst++ = *src++;
  }
}

/* DELAYS */
const unsigned long buttonEventInterval = 150;
unsigned long previousTimeButtonEvent = 0;

const unsigned long blinkEventInterval = 500;
unsigned long previousTimeBlinkEvent = 0;

const unsigned long freqEventInterval = 1000;
unsigned long previousTimeFreqEvent = 0;
long count = 0;

/* INTERPRETER */
te_expr *expr;
double t = 0.0;
int err;
double byteBeatResult = 0;

/* STATES */
const int STATE_BUTTON_DEFAULT = 0;
const int STATE_BUTTON_NUMBER = 1;
const int STATE_BUTTON_PSI = 2;
const int STATE_BUTTON_T = 3;
const int STATE_BUTTON_FORWARD = 4;
const int STATE_BUTTON_BACKWARD = 5;

int buttonState = STATE_BUTTON_DEFAULT;
int lastButtonState = buttonState;

int blinkState = 0;
int lastBlinkState = blinkState;

void gen_audio()
{
  /*Serial.print("t: ");
  Serial.print(t);
  Serial.print(", ");
  Serial.print("result: ");
  Serial.println(byteBeatResult);*/
  Timer1.setPwmDuty(PIN_OUTPUT_PWM, byteBeatResult);
  if (t == 255)
  {
    t = 0;
  }

  t += 1.0;
}

void setup()
{
  // Serial.begin(9600);

  pinMode(PIN_BUTTON_NUMBER, INPUT_PULLUP);
  pinMode(PIN_BUTTON_PSI, INPUT_PULLUP);
  pinMode(PIN_BUTTON_T, INPUT_PULLUP);
  pinMode(PIN_BUTTON_BACKWARD, INPUT_PULLUP);
  pinMode(PIN_BUTTON_FORWARD, INPUT_PULLUP);
  // pinMode(PIN_BUTTON_RESET, INPUT_PULLUP);
  pinMode(PIN_OUTPUT_PWM, OUTPUT);

  formula[FORMULA_SIZE - 1] = '\0';
  previousFormula[FORMULA_SIZE - 1] = '\0';

  Timer1.initialize(50000);
  Timer1.pwm(9, 0);
  Timer1.attachInterrupt(gen_audio);

  indexOled = 1;

  formula[0] = 't';
  formula[1] = '+';
  formula[2] = '0';
  //  formula[3] = '6';
  //  formula[4] = '+';
  //  formula[5] = ' ';
  //  formula[6] = '8';

  oledArray[0] = 't';
  oledArray[1] = '+';
  oledArray[2] = '0';
  //  oledArray[3] = '6';
  //  oledArray[4] = '+';
  //  oledArray[5] = ' ';
  //  oledArray[6] = '8';

  /*
    display.setTextSize(1);              // Normal 1:1 pixel scale
    display.setTextColor(SSD1306_WHITE); // Draw white text
    display.setCursor(indexOled * 6, 0); // Start at top-left corner
    display.cp437(true);


    if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C))
    { // Address 0x3C for 128x32
      Serial.println(F("SSD1306 allocation failed"));
      for (;;)
        ; // Don't proceed, loop forever
    }

    display.clearDisplay();
    display.print(oledArray);
    display.display();
    */
}

void loop()
{
  unsigned long currentTime = millis();

  if (currentTime - previousTimeButtonEvent >= buttonEventInterval)
  {
    // BUTTON_NUMB
    if (digitalRead(PIN_BUTTON_NUMBER) == LOW)
    {
      if (lastButtonState == buttonState && indexOled != 0)
      {
        indexOled--;
      }

      int menuKnobValue = map(analogRead(PIN_KNOB_MENU), 1024, 0, 0, 10);
      int result = numberArray[menuKnobValue];

      formula[indexOled] = result;
      oledArray[indexOled] = result;
      indexOled++;

      buttonState = STATE_BUTTON_NUMBER;
    }
    else if (digitalRead(PIN_BUTTON_PSI) == LOW)
    {
      if (lastButtonState == buttonState)
        indexOled--;

      int menuKnobValue = map(analogRead(PIN_KNOB_MENU), 1024, 0, 0, 10);
      int result = psiArray[menuKnobValue];
      formula[indexOled] = result;
      oledArray[indexOled] = result;
      indexOled++;

      buttonState = STATE_BUTTON_PSI;
    }
    else if (digitalRead(PIN_BUTTON_T) == LOW)
    {
      if (lastButtonState == buttonState)
        indexOled--;

      formula[indexOled] = 't';
      oledArray[indexOled] = 't';
      indexOled++;

      buttonState = STATE_BUTTON_T;
    }
    else if (digitalRead(PIN_BUTTON_FORWARD) == LOW)
    {
      if (indexOled != 80)
        indexOled++;
      buttonState = STATE_BUTTON_FORWARD;
    }
    else if (digitalRead(PIN_BUTTON_BACKWARD) == LOW)
    {
      if (indexOled != 0)
        indexOled--;

      buttonState = STATE_BUTTON_BACKWARD;
    }
    else
    {
      buttonState = STATE_BUTTON_DEFAULT;
    }

    // Pour incrementer lors du relachement du bouton dans le cas de number, psi et t button
    if ((lastButtonState == STATE_BUTTON_NUMBER || lastButtonState == STATE_BUTTON_PSI || lastButtonState == STATE_BUTTON_T) && buttonState == 0)
    {
      indexOled++;
    }

    previousTimeButtonEvent = currentTime;
  }

  // Ameliorer ca pour que ca soit plus reactif
  if (currentTime - previousTimeBlinkEvent >= blinkEventInterval)
  {
    // Pour clean les fullBlocks du oled //
    for (int i = 0; i < OLED_ARRAY_SIZE; i++)
    {
      if (oledArray[i] == (char)219)
        oledArray[i] = formula[i];
    }

    if (blinkState)
    {
      // fullBlock code
      if (indexOled == 0)
        oledArray[indexOled] = (char)219;
      else
        oledArray[indexOled - 1] = (char)219;
    }
    else
    {
      if (indexOled == 0)
        oledArray[indexOled] = formula[indexOled];
      else
        oledArray[indexOled - 1] = formula[indexOled - 1];
    }
    blinkState = !blinkState;
    previousTimeBlinkEvent = currentTime;
  }

  // TODO gerer la position plutot avec un objet ?
  int prevX = display.getCursorX();
  int prevY = display.getCursorY();

  display.clearDisplay();
  display.setCursor(0, 0);

  // J'ai du soustraire - 2 sinon ca debordai de lecran en bas a gauche
  for (int i = 0; i < OLED_ARRAY_SIZE - 2; i++)
  {
    display.print(oledArray[i]);
  }

  display.setCursor(indexOled * 6, prevY);

  lastButtonState = buttonState;

  // Serial.print("previousFormula: ");
  // Serial.print(previousFormula);
  // Serial.print(", ");
  // Serial.print("formula: ");
  // Serial.print(formula);
  // Serial.print(", ");
  // Serial.print("t: ");
  // Serial.print(t);
  // Serial.print(", ");
  // Serial.print("result: ");
  // Serial.println(byteBeatResult);

  if (strcmp(previousFormula, formula) == 0)
  {
    // Serial.print("equals, ");
  }
  else
  {
    // Serial.print("not equals, ");
    te_free(expr);
    int varCount = 0;
    for (char element : formula)
    {
      if (element == 't')
        varCount += 1;
    }

    te_variable vars[] = {{"t", &t}};
    expr = te_compile(formula, vars, varCount, &err);
    previousFormula = strdup(formula);
  }
  if (expr)
  {
    // Serial.print("evaluation");
    byteBeatResult = te_eval(expr);
    // OCR1A = byteBeatResult; // DutyCycle Can be changed as needed.
  }
  else
  {
    Serial.print("Parse error at ");
    Serial.println(err + '0');
  }
  // Serial.println();

  /*
    Serial.print("previousFormula: ");
    Serial.print(previousFormula);
    Serial.print(", ");
    Serial.print("formula: ");
    Serial.print(formula);
    Serial.print(", ");
    Serial.print("t: ");
    Serial.print(t);
    Serial.print(", ");
    Serial.print("result: ");
    Serial.println(byteBeatResult);
    */
}

Merci

EDIT: code nettoyé

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.