2017-07-05 4 views
0

Ich bin ziemlich neu in Arduino Programmierung. Ich habe aber schon eine Weile codiert. Ich versuche gerade ein polyphones Piano mit der Arduino IDE und einem Digispark Attiny85 Entwicklungsboard zu programmieren. Um mehrere Noten gleichzeitig zu spielen, verwende ich Sinus-Tabellen und schnelle PWM. Dies ist mein Code:Attiny85 mit globalen Variablen in Timer-Interrupts

int val = 1; 
uint8_t C = 0; 
uint8_t D = 0; 
uint8_t E = 0; 
uint8_t F = 0; 
uint8_t G = 0; 
uint8_t A = 0; 
uint8_t B = 0; 

static uint8_t sin_C[123] = {16,16,17,18,19,20,20,21,22,23,23,24,25,25,26,27,27,28,28,29,29,30,30,30,31,31,31,31,31,31,31,31,31,31,31,31,31,31,30,30,30,29,29,28,28,27,27,26,25,25,24,23,23,22,21,20,20,19,18,17,16,16,15,14,13,12,11,11,10,9,8,8,7,6,6,5,4,4,3,3,2,2,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,2,2,3,3,4,4,5,6,6,7,8,8,9,10,11,11,12,13,14,15,15}; 
static uint8_t sin_D[110] = {16,16,17,18,19,20,21,22,23,23,24,25,26,26,27,28,28,29,29,30,30,30,31,31,31,31,31,31,31,31,31,31,31,31,30,30,30,29,29,28,27,27,26,25,25,24,23,22,21,20,20,19,18,17,16,15,14,13,12,11,11,10,9,8,7,6,6,5,4,4,3,2,2,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,2,2,3,3,4,5,5,6,7,8,8,9,10,11,12,13,14,15,15}; 
static uint8_t sin_E[98] = {16,17,18,19,20,21,22,23,23,24,25,26,27,27,28,29,29,30,30,31,31,31,31,31,31,31,31,31,31,31,30,30,30,29,28,28,27,26,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,5,4,3,3,2,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,2,2,3,4,4,5,6,7,8,8,9,10,11,12,13,14,15}; 
static uint8_t sin_F[92] = {16,17,18,19,20,21,22,23,24,25,26,27,27,28,29,29,30,30,31,31,31,31,31,31,31,31,31,31,30,30,30,29,28,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,3,2,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,2,2,3,4,4,5,6,7,8,9,10,11,12,13,14,15}; 
static uint8_t sin_G[82] = {16,17,18,19,20,22,23,24,25,26,27,28,28,29,30,30,31,31,31,31,31,31,31,31,31,30,30,29,29,28,27,26,25,24,23,22,21,20,19,17,16,15,14,12,11,10,9,8,7,6,5,4,3,2,2,1,1,0,0,0,0,0,0,0,0,0,1,1,2,3,3,4,5,6,7,8,9,11,12,13,14,15}; 
static uint8_t sin_A[73] = {16,17,18,20,21,22,24,25,26,27,28,29,29,30,31,31,31,31,32,31,31,31,31,30,29,29,28,27,26,25,24,22,21,20,18,17,16,14,13,11,10,9,7,6,5,4,3,2,2,1,0,0,0,0,0,0,0,0,0,1,2,2,3,4,5,6,7,9,10,11,13,14,15}; 
static uint8_t sin_B[65] = {16,17,19,20,22,23,24,26,27,28,29,30,30,31,31,31,32,31,31,31,30,30,29,28,27,26,24,23,22,20,19,17,16,14,12,11,9,8,7,5,4,3,2,1,1,0,0,0,0,0,0,0,1,1,2,3,4,5,7,8,9,11,12,14,15}; 

ISR(TIMER0_COMPA_vect) { 
    C++; 
    D++; 
    E++; 
    F++; 
    G++; 
    A++; 
    B++; 
    if(C>122) { 
    C = 0; 
    } 
    if(D>109) { 
    D = 0; 
    } 
    if(E>97) { 
    E = 0; 
    } 
    if(F>91) { 
    F = 0; 
    } 
    if(G>81) { 
    G = 0; 
    } 
    if(A>72) { 
    A = 0; 
    } 
    if(B>64) { 
    B = 0; 
    } 
    int values[7] = {sin_C[C],sin_D[D],sin_E[E],sin_F[F],sin_G[G],sin_A[A],sin_B[B]}; 
    OCR0A = values[val]; 
} 

void setup() { 
    DDRB |= (1<<PB0); 
    TCNT0 = 0; 
    TCCR0A=0; 
    TCCR0B=0; 
    TCCR0A |=(1<<COM0A1); 
    TCCR0A |=(1<<WGM01); 
    TCCR0A |=(1<<WGM00); 
    TCCR0B |= (1 << CS00); 
    OCR0A=254; 
    TIMSK |= (1<<OCIE0A); 
} 

void loop() { 
} 

Derzeit bin ich nicht in der Lage, eine Variable zu verwenden, zu kontrollieren, was beachten sollte ich spielen, das heißt diese Linie nicht einmal funktioniert, obwohl es kompiliert:

OCR0A = values[val]; 

wo val ist eine globale Variable, die ich gesetzt habe.

Ich frage mich, ob es eine bestimmte Art und Weise, dies zu tun oder die gleiche Wirkung zu erzielen, als ob ich die Linie

OCR0A = values[1] + values[3] + values[5]; 

für die zuvor einen Ersatz erwähnte die ATtiny85 gibt einen D-Akkord, wie es sollte . Ich möchte jedoch, dass die Notizen durch Schaltflächen gesteuert werden, so dass ich sie ändern kann, während das Programm läuft, und eine globale Variable ist die einzige Möglichkeit, die ich mir vorstellen kann. Irgendwelche Lösungen würden sehr geschätzt.

+0

Bevor jemand fragt, habe ich versucht, das flüchtige Tag hinzuzufügen, das nichts ändert. – Mattasdqwe

Antwort

0

Die Verwendung von globalen Vars ist die einzige Möglichkeit, Daten zwischen Ihrer Hauptprogrammschleife und Interrupt-Handlern zu kommunizieren.

Während ich diese Antwort geschrieben habe, habe ich festgestellt, dass Sie wirklich in Ihren Sinustabellen signierte Werte verwenden sollten. Signierte Addition ist erforderlich, damit die Mathematik ordnungsgemäß funktioniert.

Diese Zeile:

OCR0A = values[val]; 

kann nur einen monophonen Klang.

Sie sind auf dem richtigen Weg mit diesem:

int values[7] = {sin_C[C],sin_D[D],sin_E[E],sin_F[F],sin_G[G],sin_A[A],sin_B[B]}; 

though.

Also, ja, eine weitere globale var sollte es tun:

unsigned char notes_played; // bits 0-7 map C-D notes 

Und in Ihrem ISR:

ISR(TIMER0_COMPA_vect) 
{ 
    //... 

    int values[7] = {sin_C[C],sin_D[D],sin_E[E],sin_F[F],sin_G[G],sin_A[A],sin_B[B]}; 

    int ocr_value = 0; 
    for (unsigned char mask = 1, i = 0; mask < 0x80; mask <<= 1, ++i) 
    { 
     if (mask & note_played) 
      ocr_value += (signed char)(values[i] - 16); // hints that using signed values 
                 // in sine tables may be more 
                 // efficient. 
    } 

    // need to 'clip' OCR here? 
    if (ocr_value < -(OCR_RANGE/2)) 
     ocr_value = -(OCR_RANGE/2); 
    if (ocr_value > (OCR_RANGE/2)) 
     ocr_value = (OCR_RANGE/2); 

    OCRA0 = (unsigned char)((ocr_value + OCR_ZERO) & 0xFF); 
} 

I OCR_RANGE und OCR_ZERO hinzugefügt haben, die auf den Spannungsbereich AC steuert der gefilterten Ausgabe. Bereich: 0-255. (OCR_RANGE = 256 kann überlaufen). OCR_ZERO steuert den mittleren Punkt (typischerweise 127), Sie sollten das initiale OCRA0 in Setup() auf OCR_ZERO setzen.

Eine letzte Anmerkung. Bei der Deklaration Ihre Sinus-Tabellen:

static uint8_t sin_B[65] =  //... This gets store in data space, which is limited 
static const uint8_t sin_B[65] = //... This gets stored on flash, which has plenty of room. 

die Sinus-Tabellen so groß wie möglich zu machen, und die Unterbrechung so schnell wie möglich kann wirklich einen großen Unterschied in der Klangqualität machen.