Étape 6: Code
OCTOSynth-0,2
//
Joe Marshall 2011
Filtre résonnant basée sur Meeblip (meeblip.noisepages.com)
Interrompre le code de configuration basé sur le code de Martin Nawrath (http://interface.khm.de/index.php/lab/experiments/arduino-dds-sinewave-generator/)
oscillateurs et optimisation assembleur inline par moi.
//
apport essentiel est de 8 entrées capacitives sur l’entrée numérique 6,7 et entrées analogiques 0-6
chaque entrée est un seul fil, passe à quelque chose de métallique au toucher
(J’ai utilisé un tas de gros boulons)
//
détection de cela se faite en getNoteKeys, à l’aide de la méthode décrite au :
http://www.Arduino.cc/Playground/code/CapacitiveSensor
//
J’utilise l’assembleur avec une boucle déroulée avec 16 registres pour détecter ce
Cela rend les choses beaucoup plus précis que la boucle C décrite sur le lien ci-dessus
car nous mesurons le délai pertinent dans les cycles de processeur unique.
Il semble être heureux même avec la puissance de la batterie, détection jusqu'à 8 simultanés
touches.
Les vagues sont tous définis au sommet, parce que nous sommes l’obligeant à s’aligner sur les limites de 256 octets
Cela rend le code oscillateur plus rapide (en calculant une compensation de la vague est juste
une question de remplacer l’octet de poids faible de l’adresse).
Cela étant dit, autres trucs arduino probablement obtient chargé ici en premier
parce que l’attribut alignée semble ajouter quelques centaines d’octets du code
#define TEST_PATTERN_INTRO
#define FILTER_LPF_NONE
#define FILTER_LPF_HACK
Tableau de 256 valeurs de sinus / un sinus période / stockées dans la mémoire flash
char sine256 [256] __attribute__ ((aligned(256))) = {}
0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45,
48, 51, 54, 57, 59, 62, 65, 67, 70, 73, 75, 78, 80, 82, 85, 87,
89, 91, 94, 96, 98, 100, 102, 103, 105, 107, 108, 110, 112, 113, 114, 116,
117, 118, 119, 120, 121, 122, 123, 123, 124, 125, 125, 126, 126, 126, 126, 126,
127, 126, 126, 126, 126, 126, 125, 125, 124, 123, 123, 122, 121, 120, 119, 118,
117, 116, 114, 113, 112, 110, 108, 107, 105, 103, 102, 100, 98, 96, 94, 91,
89, 87, 85, 82, 80, 78, 75, 73, 70, 67, 65, 62, 59, 57, 54, 51,
48, 45, 42, 39, 36, 33, 30, 27, 24, 21, 18, 15, 12, 9, 6, 3,
0, -3, -6, -9, -12, -15, -18, -21, -24, -27, -30, -33, -36 -39, -42, -45,
-48 -51 -54, -57, -59, -62, -65, -67, -70, -73, -75, -78, -80, -82, -85, -87,
-89 -91 -94, -96, -98, -100, -102, -103, -105, -107, -108, -110, -112, -113, -114, -116,
-117 -118 -119, -120, -121, -122, -123, -123, -124, -125, -125, -126, -126, -126, -126, -126,
-127 -126 -126, -126, -126, -126, -125, -125, -124, -123, -123, -122, -121, -120, -119, -118,
-117 -116 -114, -113, -112, -110, -108, -107, -105, -103, -102, -100, -98, -96, -94, -91,
-89 -87 -85, -82, -80, -78, -75, -73, -70, -67, -65, -62, -59, -57, -54, -51,
-48 -45, -42, -39, -36, -33, -30, -27, -24, -21, -18, -15, -12, -9, -6, -3
};
char square256 [256] __attribute__ ((aligned(256))) = {}
127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
-127 -127 -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127,
-127 -127 -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127,
-127 -127 -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127,
-127 -127 -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127,
-127 -127 -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127,
-127 -127 -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127,
-127 -127 -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127,
-127 -127 -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127
};
char triangle256 [256] __attribute__ ((aligned(256))) = {}
-127, -125, -123, -121, -119, -117, -115, -113, -111, -109 -107, -105, -103, -101, -99, -97,
-95 -93 -91, -89, -87, -85, -83, -81, -79, -77, -75, -73, -71, -69, -67, -65,
-63, -61, -59, -57, -55, -53, -51, -49, -47, -45 -43, -41, -39, -37, -35, -33,
-31 -29, -27, -25, -23, -21, -19, -17, -15, -13, -11, -9, -7, -5, -3, -1,
1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31,
33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63,
65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95,
97, 99, 101, 103, 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, 127,
129, 127, 125, 123, 121, 119, 117, 115, 113, 111, 109, 107, 105, 103, 101, 99,
97, 95, 93, 91, 89, 87, 85, 83, 81, 79, 77, 75, 73, 71, 69, 67,
65, 63, 61, 59, 57, 55, 53, 51, 49, 47, 45, 43, 41, 39, 37, 35,
33, 31, 29, 27, 25, 23, 21, 19, 17, 15, 13, 11, 9, 7, 5, 3,
1 -1, -3, -5, -7, -9, -11, -13, -15, -17, -19, -21, -23, -25, -27, -29,
-31 -33 -35, -37, -39, -41, -43, -45, -47, -49, -51, -53, -55, -57, -59, -61,
-63 -65 -67, -69, -71, -73, -75, -77, -79, -81, -83, -85, -87, -89, -91, -93,
-95 -97 -99, -101, -103, -105, -107, -109, -111, -113, -115, -117, -119, -121, -123, -125
};
char sawtooth256 [256] __attribute__ ((aligned(256))) = {}
-127 -127 -126, -125, -124, -123, -122, -121, -120, -119, -118, -117, -116, -115, -114, -113,
-112 -111 -110, -109, -108, -107, -106, -105, -104, -103, -102, -101, -100, -99, -98, -97,
-96 -95 -94, -93, -92, -91, -90, -89, -88, -87, -86, -85, -84, -83, -82, -81,
-80 -79, -78, -77, -76, -75, -74, -73, -72, -71, -70, -69, -68, -67, -66, -65,
-64 -63 -62, -61, -60, -59, -58, -57, -56, -55, -54, -53, -52, -51, -50, -49,
-48 -47 -46, -45, -44, -43, -42, -41, -40, -39, -38, -37, -36, -35, -34, -33,
-32 -31 -30, -29, -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, -2, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127
};
#include « avr/pgmspace.h »
table de journal pour 128 seuils de filtre
unsigned char logCutoffs[128] = {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x03,0x04,0x04,0x04,0x04,0x04,0x05,0x05,0x05,0x05,0x06,0x06,0x06,0x06,0x06,0x06,0x07,0x08,0x08,0x08,0x09,0x09,0x0A,0x0A,0x0A,0x0A,0x0B ,0x0C,0x0C,0x0C,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1E,0x20,0x21,0x22,0x23,0x24,0x26,0x28,0x2A,0x2C,0x2E,0x30,0x32,0x34,0x36,0x38,0x3A,0x40,0x42,0x44,0x48,0x4C,0x4F,0x52,0x55,0x58,0x5D,0x61,0x65,0x68,0x6C,0x70,0x76,0x7E,0x85,0x8A,0x90,0x96,0x9D,0xA4 0xAB, 0xB0, 0xBA, 0xC4, 0xCE, 0xD8, 0xE0, 0xE8, 0xF4, 0xFF} ;
volatil unsigned int WAIT_curTime ;
#define WAIT_UNTIL_INTERRUPT() WAIT_curTime = loopSteps ; {while(WAIT_curTime==loopSteps)}
#define SERIAL_OUT 0
attaque, decay sont en 1/64ths par 125e de seconde - c’est à dire. 1 = 0 - > 1 en une demi-seconde
const int DECAY = 3 ;
const int attaque = 4 ;
volatils char * curWave = square256 ;
#define DRAS (sfr, bit) (_SFR_BYTE(sfr) & = ~_BV(bit))
#define sbi (sfr, bit) (_SFR_BYTE(sfr) | = _BV(bit))
C’est censé être la fréquence d’horloge audio - comme
vous pouvez le voir, freq mesurée peut varier un peu de fréquence d’horloge supposée
Je ne suis pas sûr pourquoi
const double refclk = 31372.549 ; = 16MHz / 510
const double refclk = 31376.6 ; mesurée
variables utilisées à l’intérieur de l’interruption service déclarée comme voilatile
ces variables permettent de garder trace de temps - en retard / millis etc. sont
fait inactif en raison d’interruptions sont désactivées.
volatile unsigned char loopSteps = 0 ; une fois par exemple
volatile unsigned int loopStepsHigh = 0 ; une fois par 256 échantillons
informations sur l’état actuel d’un oscillateur simple
struct oscillatorPhase
{
unsigned int phaseStep ;
volume de char ;
unsigned int phaseAccu ;
};
les oscillateurs (8)
struct oscillatorPhase oscillateurs [8] ;
tword_m = pow (2,32) * dfreq/refclk ; calculer le nouveau réglage mot DDS
pour obtenir hz -> réglage mot ne: (pow(2,16) * fréquence) / 31376.6
const unsigned int NOTE_FREQS [25] = {273,289,307,325,344,365,386,409,434,460,487,516,546,579,613,650,688,729,773,819,867,919,974,1032,1093} ;
seuils pour les boutons de détection capacitives
int calibrationThresholds [8] = {0,0,0,0,0,0,0,0} ;
Inline int getNoteKeys (calibrer boolean = false)
{
char PORTD_PINS = 0b11000000 ; (broches 6-7 - éviter les broches 0,1 car elles servent pour port série comms)
char PORTC_PINS = 0b111111 ; (broches analogiques 0-5)
const int MAX_LOOPS = 16 ;
char port_values [MAX_LOOPS * 2] ;
WAIT_UNTIL_INTERRUPT() ;
(volatile) ASM
boucle de lecture port D :
DDDR & = ~(PORTD_PINS = 0x3f) ; Réglez de façon strictement 8-12 au mode d’entrée
« en % [temp], 0x0a""\n\t »
"andi % [temp], 0x3f" « \n\t »
"out 0x0a, % [temp]" "\n\t"
PORTD | = (PORTD_PINS) ; Réglez de façon strictement pullup 8-12 sur
« en % [temp], 0x0b""\n\t »
"ori % [temp], 0xC0" « \n\t »
"out 0x0b, % [temp]" "\n\t"
« à 0 %, 0 x 09""\n\t »
"in 1 %, 0 x 09" "\n\t"
« en %2, 0 x 09""\n\t »
« en %3, 0 x 09""\n\t »
« à 4 %, 0 x 09""\n\t »
"à 5 %, 0 x 09" "\n\t"
« en %6, 0 x 09""\n\t »
« en %7, 0 x 09""\n\t »
« en %8, 0 x 09""\n\t »
« en %9, 0 x 09""\n\t »
« en % 10, 0 x 09""\n\t »
« en % 11, 0 x 09""\n\t »
« en % 12, 0 x 09""\n\t »
« en % 13, 0 x 09""\n\t »
« en % 14, 0 x 09""\n\t »
« en % 15, 0 x 09""\n\t »
:
sorties
« = r » (port_values[0]),
« = r » (port_values[2]),
« = r » (port_values[4]),
« = r » (port_values[6]),
« = r » (port_values[8]),
« = r » (port_values[10]),
« = r » (port_values[12]),
« = r » (port_values[14]),
« = r » (port_values[16]),
« = r » (port_values[18]),
« = r » (port_values[20]),
« = r » (port_values[22]),
« = r » (port_values[24]),
« = r » (port_values[26]),
« = r » (port_values[28]),
« = r » (port_values[30])
: [temp] "d" (0)) ;
WAIT_UNTIL_INTERRUPT() ;
(volatile) ASM
boucle de lecture port C :
DDRC & = ~(PORTC_PINS = 0xc0) ; Réglez de façon strictement 5-7 au mode d’entrée
« en % [temp], 0 x 07""\n\t »
"andi % [temp], 0xc0" « \n\t »
"out 0 x 07, % [temp]" "\n\t"
PORTC | = (PORTC_PINS) ; Réglez de façon strictement pullup 5-7 sur
« en % [temp], 0 x 08""\n\t »
"ori % [temp], 0x3F" « \n\t »
"out 0 x 08, % [temp]" "\n\t"
« à 0 %, 0 x 06""\n\t »
"in 1 %, 0 x 06" "\n\t"
« en %2, 0 x 06""\n\t »
« en %3, 0 x 06""\n\t »
« à 4 %, 0 x 06""\n\t »
"à 5 %, 0 x 06" "\n\t"
« en %6, 0 x 06""\n\t »
« en %7, 0 x 06""\n\t »
« en %8, 0 x 06""\n\t »
« en %9, 0 x 06""\n\t »
« en % 10, 0 x 06""\n\t »
« en % 11, 0 x 06""\n\t »
« en % 12, 0 x 06""\n\t »
« en % 13, 0 x 06""\n\t »
« en % 14, 0 x 06""\n\t »
« en % 15, 0 x 06""\n\t »
:
sorties
« = r » (port_values[1]),
« = r » (port_values[3]),
« = r » (port_values[5]),
« = r » (port_values[7]),
« = r » (port_values[9]),
« = r » (port_values[11]),
« = r » (port_values[13]),
« = r » (port_values[15]),
« = r » (port_values[17]),
« = r » (port_values[19]),
« = r » (port_values[21]),
« = r » (port_values[23]),
« = r » (port_values[25]),
« = r » (port_values[27]),
« = r » (port_values[29]),
« = r » (port_values[31])
: [temp] "d" (0)) ;
PORTC & = ~ (PORTC_PINS) ; pullup hors broches 8-12
PORTD & = ~ (PORTD_PINS) ; pullup hors broches 5-7
DDRC | = (PORTC_PINS) ; décharge
DDDR | = (PORTD_PINS) ; décharge
if(CALIBRATE)
{
pour (int c = 0; c < 8; c ++)
{
pour (d int = 0; d < MAX_LOOPS; d ++)
{
int liveNotes=((int*)port_values) [d] ;
liveNotes & = 0x3fc0 ;
liveNotes >> = 6 ;
Si (liveNotes & (1 << c))
{
Si (calibrationThresholds [c] < = d)
{
calibrationThresholds [c] = j + 1 ;
}
rupture ;
}
}
}
}
int liveNotes = 0 ;
pour (int c = 0; c < 8; c ++)
{
int val = ((int*) port_values) [calibrationThresholds [c] + 1] ;
Val & = 0x3fc0 ;
Val >> = 6 ;
Si ((val & (1 << c)) == 0)
{
liveNotes| = (1 << c) ;
}
}
Return liveNotes ;
}
obtenir un tactile capacitif sur 4 d’entrée et de sortie 3
utilisé pour modulateur de filtre
Inline int getfiltermodulationtime()
{
public static int running_average = 0 ;
public static int running_min = 1024 ;
public static int running_min_inc_count = 0 ;
public static boolean initialise_running_min = true ;
unsigned int delayTime = 0 ;
char PINNUM_OUT = 3 ;
char PINNUM_IN = 4 ;
char PIN_OUT = 1 << PINNUM_OUT ;
char PIN_IN = 1 << PINNUM_IN ;
faire sûrs entrées / sorties sont bonnes
DDRD| = PIN_OUT ;
DDDR & = ~ (PIN_IN) ;
WAIT_UNTIL_INTERRUPT() ;
PORTD| = PIN_OUT ;
(volatile) ASM
"loopstart % =: « « \n\t »
"sbic 0 x 09, % [PINNUM_IN]" "\n\t"
"rjmp outloop % =" « \n\t »
"adiw % [delayTime], 0 x 01" « \n\t »
"IPC %B [delayTime], 0 x 02" "\n\t"
"brne loopstart % =" « \n\t »
"outloop % =: « « \n\t »
: [delayTime] "+ & w » (delayTime)
: [PINNUM_IN] « JE » (PINNUM_IN)) ;
Set tige vers le bas - peut-être ne vous embêtez pas moment, si elle ne semble pas ajouter
beaucoup de précision ?
WAIT_UNTIL_INTERRUPT() ;
PORTD & = ~ PIN_OUT ;
ASM)
"loopstart % =: « « \n\t »
« ITT 0 x 09, % [PINNUM_IN] » "\n\t »
"rjmp outloop % =" « \n\t »
"adiw % [delayTime], 0 x 01" « \n\t »
"IPC %B [delayTime], 0 x 02" "\n\t"
"brne loopstart % =" « \n\t »
"outloop % =: « « \n\t »
: [delayTime] "+ & w » (delayTime)
: [PINNUM_IN] « JE » (PINNUM_IN)) ;
running_average = (running_average-(running_average >> 4)) + (/Delay >> 4) ;
running_min_inc_count ++ ;
if(running_min_inc_count==255)
{
if(initialise_running_min)
{
running_min = running_average ;
running_min_inc_count = 0 ;
initialise_running_min = false ;
} else {}
running_min_inc_count = 0 ;
running_min ++ ;
}
}
if(running_average<running_min)
{
running_min = running_average ;
}
int touchVal = running_average-running_min ;
if(touchVal>15)
{
touchVal-= 15 ;
if(touchVal>99)
{
touchVal = 99 ;
}
} else {}
touchVal = 0 ;
}
Return touchVal ;
}
Téléchargez tactile capacitif sur 5 d’entrée et de sortie 3
utilisé pour la modulation de hauteur
Inline int getpitchbendtime()
{
public static int running_average = 0 ;
public static int running_min = 1024 ;
public static int running_min_inc_count = 0 ;
public static boolean initialise_running_min = true ;
unsigned int delayTime = 0 ;
char PINNUM_OUT = 3 ;
char PINNUM_IN = 5 ;
char PIN_OUT = 1 << PINNUM_OUT ;
char PIN_IN = 1 << PINNUM_IN ;
faire sûrs entrées / sorties sont bonnes
DDRD| = PIN_OUT ;
DDDR & = ~ (PIN_IN) ;
WAIT_UNTIL_INTERRUPT() ;
PORTD| = PIN_OUT ;
(volatile) ASM
"loopstart % =: « « \n\t »
"sbic 0 x 09, % [PINNUM_IN]" "\n\t"
"rjmp outloop % =" « \n\t »
"adiw % [delayTime], 0 x 01" « \n\t »
"IPC %B [delayTime], 0 x 02" "\n\t"
"brne loopstart % =" « \n\t »
"outloop % =: « « \n\t »
: [delayTime] "+ & w » (delayTime)
: [PINNUM_IN] « JE » (PINNUM_IN)) ;
Set tige vers le bas - peut-être ne vous embêtez pas moment, si elle ne semble pas ajouter
beaucoup de précision ?
WAIT_UNTIL_INTERRUPT() ;
PORTD & = ~ PIN_OUT ;
ASM)
"loopstart % =: « « \n\t »
« ITT 0 x 09, % [PINNUM_IN] » "\n\t »
"rjmp outloop % =" « \n\t »
"adiw % [delayTime], 0 x 01" « \n\t »
"IPC %B [delayTime], 0 x 02" "\n\t"
"brne loopstart % =" « \n\t »
"outloop % =: « « \n\t »
: [delayTime] "+ & w » (delayTime)
: [PINNUM_IN] « JE » (PINNUM_IN)) ;
running_average = (running_average-(running_average >> 4)) + (/Delay >> 4) ;
running_min_inc_count ++ ;
if(running_min_inc_count==255)
{
if(initialise_running_min)
{
running_min = running_average ;
running_min_inc_count = 0 ;
initialise_running_min = false ;
} else {}
running_min_inc_count = 0 ;
running_min ++ ;
}
}
if(running_average<running_min)
{
running_min = running_average ;
}
int touchVal = running_average-running_min ;
if(touchVal>15)
{
touchVal-= 15 ;
if(touchVal>99)
{
touchVal = 99 ;
}
} else {}
touchVal = 0 ;
}
Return touchVal ;
}
unsigned int pitchBendTable [201] = {241, 241, 241, 242, 242, 242, 242, 242, 242, 242, 243, 243, 243, 243, 243, 243, 243, 244, 244, 244, 244, 244, 244, 244, 245, 245, 245, 245, 245, 245, 245, 246, 246, 246, 246, 246, 246, 246, 247, 247, 247, 247, 247, 247, 247, 248, 248, 248, 248, 248, 248, 248, 249, 249, 249, 249, 249 , 249, 249, 250, 250, 250, 250, 250, 250, 250, 251, 251, 251, 251, 251, 251, 251, 252, 252, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 256,
256 256, 256, 256, 256, 256, 256, 256, 257, 257, 257, 257, 257, 257, 257, 258, 258, 258, 258, 258, 258, 259, 259, 259, 259, 259, 259, 259, 260, 260, 260, 260, 260, 260, 260, 261, 261, 261, 261, 261, 261, 262, 262, 262, 262, 262, 262, 262, 263, 263, 263, 263, 263, 263, 264, 264, 264, 264, 264, 264, 264, 265 265, 265, 265, 265, 265, 266, 266, 266, 266, 266, 266, 266, 267, 267, 267, 267, 267, 267, 268, 268, 268, 268, 268, 268, 269, 269, 269, 269, 269, 269, 269, 270, 270, 270, 270, 270, 270, 271, 271} ;
void setupNoteFrequencies (int baseNote, int pitchBendVal / * -100 -> 100 * /)
{
oscillateurs [0] .phaseStep = NOTE_FREQS [baseNote] ;
oscillateurs [1] .phaseStep = NOTE_FREQS [baseNote + 2] ;
oscillateurs [2] .phaseStep = NOTE_FREQS [baseNote + 4] ;
oscillateurs [3] .phaseStep = NOTE_FREQS [baseNote + 5] ;
oscillateurs [4] .phaseStep = NOTE_FREQS [baseNote + 7] ;
oscillateurs [5] .phaseStep = NOTE_FREQS [baseNote + 9] ;
oscillateurs [6] .phaseStep = NOTE_FREQS [baseNote + 11] ;
oscillateurs [7] .phaseStep = NOTE_FREQS [baseNote + 12] ;
Si (pitchBendVal < -99)
{
pitchBendVal =-99 ;
} else if(pitchBendVal>99)
{
pitchBendVal = 99 ;
}
Serial.Print("*") ;
Serial.Print(pitchBendVal) ;
unsigned int pitchBendMultiplier = pitchBendTable [pitchBendVal + 100] ;
Serial.Print(":") ;
Serial.Print(pitchBendMultiplier) ;
pour (int c = 0; c < 8; c ++)
{
multiplier 2 nombres 16 bits ensemble et passer 8 sans perte de précision
nécessite l’assembleur vraiment
volatile unsigned char zeroReg = 0 ;
volatile unsigned int multipliedCounter = oscillateurs [c] .phaseStep ;
ASM volatile
(
mult octets élevés ensemble = octet haut
« ldi %A [outVal], 0 » "\n\t »
"mul %B [phaseStep], %B [pitchBend]" "\n\t"
"mov %B [outVal], r0" "\n\t"
ignorer le débordement en r1 (ne doit jamais déborder)
octet de poids faible * octet haut -> les deux octets
"mul %A [phaseStep], %B [pitchBend]" "\n\t"
"Ajouter %A [outVal], r0" "\n\t"
transportent dans l’octet haut
"adc %B [outVal], r1" "\n\t"
haute octets * octet de poids faible -> les deux octets
"mul %B [phaseStep], A [pitchBend]" "\n\t"
"Ajouter %A [outVal], r0" "\n\t"
transportent dans l’octet haut
"adc %B [outVal], r1" "\n\t"
octet de poids faible * octet de poids faible -> rond
"mul %A [phaseStep], A [pitchBend]" "\n\t"
l’adc ci-dessous est d’arrondir basé sur peu élevé de faible * faible :
"adc %A [outVal], r1" "\n\t"
"adc %B [outVal], % [ZERO]" "\n\t"
"clr r1" "\n\t"
: [outVal] "= & d" (multipliedCounter)
: [phaseStep] "d" (oscillateurs [c] .phaseStep), [pitchBend] "d" (pitchBendMultiplier), [ZERO] "d" (zeroReg)
: "r1", "r0"
);
oscillateurs [c] .phaseStep = multipliedCounter ;
}
Serial.Print(":") ;
Serial.Print(NOTE_FREQS[baseNote]) ;
Serial.Print(":") ;
Serial.println(oscillators[0].phaseStep) ;
}
void setup()
{
Serial.Begin(9600) ; se connecter au port série
#ifndef FILTER_LPF_NONE
setFilter (127, 0) ;
#endif
pinMode (sortie 11) ; PIN11 = sortie PWM / fréquence de sortie
setupNoteFrequencies(12,0) ;
pour (int c = 0; c < 8; c ++)
{
oscillateurs [c] .volume = 0 ;
}
Setup_timer2() ;
désactiver les interruptions pour éviter des distorsions de chronométrage
CBI (TIMSK0, TOIE0) ; désactiver le Timer0!!! Delay() n’est actuellement pas disponible
SBI (TIMSK2, TOIE2) ; activez le Timer2 interrompre
étalonner les valeurs de clés non enfoncés
pour (int x = 0; x < 1024; x ++)
{
getNoteKeys(true) ;
étapes d’int = loopSteps ;
WAIT_UNTIL_INTERRUPT() ;
int afterSteps = loopSteps ;
Serial.println(afterSteps-Steps) ;
}
intro de mire
#ifdef TEST_PATTERN_INTRO
int filtValue = 255 ;
byte notes[]={0x1,0x4,0x10,0x80,0x80,0x80,0x1,0x2,0x4,0x8,0x10,0x20,0x40,0x80,0x40,0x20,0x10,0x8,0x4,0x2,0x1,0x1,0x1,0x00,0x00,0x1,0x1,0x1,0x1,0x00,0x00,0x5,0x5,0x5,0x5,0x00,0x00,0x15,0x15,0x15,0x15,0x15,0x00,0x00,0x95,0x95,0x95,0x95,0x95,0x95,0x00};
pour (Remarque int = 0; Notez < sizeof(notes)/sizeof(byte);note++)
{
int noteCount = 0 ;
pour (int c = 0; c < 8; c ++)
{
Si (notes [note] & (1 << c))
{
noteCount += 1 ;
}
}
pour (int c = 0; c < 8; c ++)
{
Si (notes [note] & (1 << c))
{
oscillateurs [c] .volume = 63/noteCount ;
} else
{
oscillateurs [c] .volume = 0 ;
}
}
pour (int c = 0; c < 50; c ++)
{
pourrait ainsi garder étalonnage ici
NB: chaque boucle d’étalonnage = au moins 1 interruption
getNoteKeys(true) ;
#ifndef FILTER_LPF_NONE
setFilter (127-c, 64) ;
#endif
}
}
#else
juste un bip pour indiquer l’étalonnage est réalisé
oscillateurs [0] .volume = 63 ;
pour (int c = 0; c < 20; c ++)
{
WAIT_UNTIL_INTERRUPT() ;
}
oscillateurs [0] .volume = 63 ;
#endif
Serial.println("calibrations:") ;
pour (int c = 0; c < 8; c ++)
{
Serial.Print(c) ;
Serial.Print(":") ;
Serial.println(calibrationThresholds[c]) ;
}
}
void loop()
{
Nous gardons une liste des volumes « raw » - et baissez le volume si un accord se > 64 volume total
Cela doit permettre chording sans réduire le volume des notes seules
int rawVolumes [8] = {0,0,0,0,0,0,0,0} ;
int curNote = 0 ;
unsigned int filterSweep = 64 ;
const int MIN_SWEEP = 64 ;
const int MAX_SWEEP = 127 ;
const int SWEEP_SPEED = 3 ;
int sweepDir = SWEEP_SPEED ;
unsigned int lastStep = loopStepsHigh ;
non signé curStep = loopStepsHigh ;
while(1)
{
lastStep = curStep ;
curStep = loopStepsHigh ;
Remarque : les minuteries ne fonctionnent pas dans ce code (interruptions désactivé / vitesses changé), donc ne pensez même pas à l’appel : delay(), millis / micros etc..
chaque loopstep est à peu près 31250 / seconde
Cette boucle principale est appelée une fois tous les 3 ou 4 échantillons si la sortie série a été désactivé, peut-être plus lentement dans le cas contraire
int liveNotes=getNoteKeys() ;
Nous sommes tout de suite après une interruption (comme loopStep a juste été incrémenté)
donc, nous devrions avoir suffisamment de temps pour faire les contrôles clés capacitive
if(lastStep!=curStep)
{
int totalVolume = 0 ;
pour (int c = 0; c < 8; c ++)
{
Si ((liveNotes & (1 << c)) == 0)
{
rawVolumes [c]-= DECAY*(curStep-lastStep) ;
Si (rawVolumes [c] < 0) rawVolumes [c] = 0 ;
if(SERIAL_OUT)Serial.Print(".") ;
}
d’autre
{
rawVolumes [c] += ATTACK*(curStep-lastStep) ;
Si (rawVolumes [c] > 63) rawVolumes [c] = 63 ;
if(SERIAL_OUT)Serial.Print(c) ;
}
totalVolume += rawVolumes [c] ;
}
WAIT_UNTIL_INTERRUPT() ;
Si (totalVolume < 64)
{
pour (int c = 0; c < 8; c ++)
{
oscillateurs [c] .volume = rawVolumes [c] ;
}
} else
{
volume total réduire trop, pour éviter l’écrêtage
pour (int c = 0; c < 8; c ++)
{
oscillateurs [c] .volume =(rawVolumes[c]*63)/totalVolume ;
}
}
}
if(SERIAL_OUT)Serial.println("") ;
#ifndef FILTER_LPF_NONE
/ * if(liveNotes==0)
{
filterSweep = 64 ;
sweepDir = SWEEP_SPEED ;
}
filterSweep += sweepDir ;
Si (filterSweep > = MAX_SWEEP)
{
filterSweep = MAX_SWEEP ;
sweepDir =-sweepDir ;
}
ElseIf (filterSweep < = MIN_SWEEP)
{
sweepDir =-sweepDir ;
filterSweep = MIN_SWEEP ;
}*/
Serial.println((int)FilterValue) ;
filterSweep=127-(getpitchbendtime() >> 1) ;
WAIT_UNTIL_INTERRUPT() ;
setFilter(150-(getfiltermodulationtime()),220) ;
#endif
WAIT_UNTIL_INTERRUPT() ;
setupNoteFrequencies(12,-getpitchbendtime()) ;
Nous sommes juste après une interruption à nouveau (comme loopStep a juste été incrémenté)
donc nous devrions avoir suffisamment de temps pour vérifier la capacité du pitch bend sans aller sur un autre échantillon, timing est très important ici
ont besoin d’équilibrer en utilisant une résistance assez grande pour obtenir la distance de détection décent avec prend trop de temps d’échantillon
Vérifiez la source de courbure de tangage
}
}
//******************************************************************
installation du TIMER2
prscaler la valeur 1, le mode PWM à phase PWM correct, 16000000/510 = 31372.55 Hz horloge
void Setup_timer2() {}
Diviseur d’horloge TIMER2 pour: 1
SBI (TCCR2B, CS20) ;
CBI (TCCR2B, CS21) ;
CBI (TCCR2B, CS22) ;
TIMER2 PWM Mode de réglage de Phase PWM Correct
CBI (TCCR2A, COM2A0) ; effacer le Match comparer
SBI (TCCR2A, COM2A1) ;
SBI (TCCR2A, WGM20) ; Mode 1 / Phase PWM Correct
CBI (TCCR2A, WGM21) ;
CBI (TCCR2B, WGM22) ;
}
#ifdef FILTER_LPF_BIQUAD
char filtValueA1 = 0, filtValueA2 = 0, filtValueA3 = 0, filtValueB1 = 0, filtValueB2 = 0 ;
volatile unsigned char filtCoeffA1 = 255 ;
volatils char filtCoeffB1 = 127 ;
volatile unsigned char filtCoeffB2 = 255 ;
#endif
#ifdef FILTER_LPF_HACK
filtre passe-bas piraté - 2 pole résonant-
un += f*((in-a) + q*(a-b)
b + = f * (a-b)
int filterA = 0 ;
int filterB = 0 ;
unsigned char filterQ = 0 ;
unsigned char filterF = 255 ;
Inline void setFilterRaw (unsigned char filterF, unsigned char résonance)
{
unsigned char tempReg = 0, tempReg2 = 0 ;
ASM volatile (« ldi % [tempReg], 0xff » « \n\t »
"sub % [tempReg], [filtF]" "\n\t"
"DSL % [tempReg]" "\n\t"
« ldi % [tempReg2], 0 x 04 » « \n\t »
"Ajouter % [tempReg], [tempReg2]" "\n\t"
"sub % [reso], [tempReg]" "\n\t"
"brcc Res_Overflow % =" « \n\t »
« ldi % [reso], 0 x 00 » « \n\t »
"Res_Overflow % =: « « \n\t »
"mov % [filtQ], [reso]" « \n\t »
: [tempReg] "= & d" (tempReg), [tempReg2] "= & d" (tempReg2), [filtQ] "= & d" (filterQ): [reso] "d" (résonance), [filtF] « d » (filterF)) ;
}
Inline setFilter Sub (f unsigned char, unsigned char résonance)
{
if(f>127) f = 127 ;
filterF = logCutoffs [f] ;
setFilterRaw(filterF,resonance) ;
}
#endif
#define HIBYTE(__x) ((char) (((unsigned int) __x) >> 8))
#define LOBYTE(__x) ((char) (((unsigned int) __x) & 0xff))
la boucle principale oscillateur (incrémente le pointeur de la table d’ondes et l’ajouter à des registres de sortie)
13 instructions - devrait prendre 14 cycles du processeur selon la feuille de données
en théorie, selon moi, que cela signifie que chaque oscillateur devrait prendre 1,5 % de cpu
(plus une surcharge constante pour interruption appelle etc..)
Remarque : Ceci a l’habitude de faire tous le stepvolume charge peu après le début, mais ils sont maintenant entrelacées dans la
code, c’est parce que la ldd (charge avec décalage) prend 2 instructions,
versus ld, + 1 (charge avec incrément post) et st, + 1 qui sont 1 instruction - nous pouvons le faire parce que :
//
a) l’étape (qui ne doit pas être stocké à l’arrière) est en mémoire avant le
accumulateur de phase (qui a besoin d’être stockées une fois que l’étape est ajoutée
//
b) la phase assumulator est stocké dans l’octet de poids faible, ordre d’octet élevé, ce qui signifie que nous
peut additionner les premiers octets, puis stocker cet octet incrémentation de l’aiguille,
puis l’octet haut, additionnez les octets de hautes et de stocker incrémenter le pointeur
//
Je pense que c’est le nombre minimum d’opérations possibles de coder cet oscillateur, parce que
1) il y a 6 opérations de chargement requises (pour charger stepHigh/bas, phaseH/L, volume et la valeur de la vague)
2) il y a 2 ajouter les opérations requises pour ajouter à l’accumulateur de phase
3) il y a 2 operations magasin requises pour enregistrer l’accumulateur de phase
4) il est 1 multiplier (2 cycles d’instruction) nécessaire pour faire du volume
5) il y a 2 ajouter les opérations requises pour ajouter à la sortie finale
//
6 + 2 + 2 + 2 + 2 = 14 cycles d’enseignement
#define OSCILLATOR_ASM \
/ * chargement phase étape et volume * / \
« ld %A [tempStep], % un [stepVolume] + "« \n\t » \
« ld %B [tempStep], % un [stepVolume] + "« \n\t » \
« ld [tempVolume], % un [stepVolume] + "« \n\t » \
/ * chargement phase accumulateur - octet haut va droit * / \
/ * dans le tableau de recherche vague (wave est sur la limite de 256 octets * / \
/ * Si nous pouvons le faire sans aucune ajoute * / \
/ * La phase ajoute entre les deux charges, comme charge avec offset est plus lent que
juste une charge normale
*/\
"ld %A [tempPhaseLow], % un [stepVolume]" "\n\t" \
/ * Ajouter phase étape basse * / \
« \n\t"\ « ajouter % [tempPhaseLow], %A [tempStep] »
/ * stocker phase accu faible * / \
"st %a [stepVolume] +, % [tempPhaseLow]" « \n\t » \
/ * chargement phase accumulateur haute * / \
"ld %A [waveBase], % un [stepVolume]" "\n\t" \
/ * Ajouter phase étape haut - avec retenue dans l’ajouter ci-dessus * / \
"adc %A [waveBase], %B [tempStep]" "\n\t"\
/ * stocker phase étape haute * / \
"st %a [stepVolume] +, %A [waveBase]" « \n\t » \
/ * maintenant la recherche de la vague - octet = pointeur de vague, octet de poids faible = offset * / \
« ld % [tempPhaseLow], un [waveBase] » « \n\t » \
/ * maintenant multipliez par volume * / \
"muls % [tempPhaseLow], [tempVolume]" « \n\t » \
/ * r0 contient à présent un échantillon - ajouter à la sortie valeur * / \
"Ajouter %A [outValue], r0" « \n\t » \
"adc %B [outValue], r1" « \n\t » \
/ * aller au prochain oscillateur - stepVolume pointe sur suivant * / \
/ * oscillateur déjà * / \
//******************************************************************
TIMER2 interrompre le Service à 31 372 550 KHz = 32uSec
Il s’agit de la base de temps REFCLOCK pour le générateur DDS
S’en FOUT = (M (REFCLK)) / (2 exp 32)
Duree: ?
{ISR(TIMER2_OVF_vect)}
maintenant mis en place la prochaine valeur
Cette boucle dure environ 172 cycles (214 dont le push/pop) - nous avons 510, donc environ 50 % de la roue de secours va processeur pour des tâches non audio
le filtre passe-bas prend également quelques cycles
int outValue ;
pointeurs :
X = accumulateur de phase oscillateur
Y = étape oscillateur et volume
Z = vague pos - a besoin d’ajouter à la base
int tempStep = 0 ;
char tempPhaseLow = 0, tempVolume = 0 ;
int tempWaveBase = 0 ;
(volatile) ASM
« ldi %A [outValue], 0"« \n\t »
« ldi %B [outValue], 0"« \n\t »
oscillateur 0
Supprimez le code ci-dessous pour vérifier
que les registres ne reçoivent doubles assignés
/ * "lds %A [outValue], 0 x 00" "\n\t"
"lds %B [outValue], 0 x 01" "\n\t"
"lds %A [tempPhaseLow], 0 x 02" "\n\t"
"lds %B [tempPhase], 0 x 03" "\n\t"
"lds %A [tempStep], 0 x 04" "\n\t"
"lds %B [tempStep], 0 x 05" "\n\t"
"lds % [tempVolume], 0 x 06" « \n\t »
"lds % [zéro], 0 x 07" « \n\t »
"lds %A [tempWaveBase], 0 x 08" "\n\t"
"lds %B [tempWaveBase], 0 x 09" "\n\t"
"lds %A [phaseAccu], 0x0a" "\n\t"
"lds %B [phaseAccu], 0x0b" "\n\t"
"lds %A [stepVolume], 0x0c" "\n\t"
"lds %B [stepVolume], 0x0d" "\n\t"
"lds %A [waveBase], 0x0e" "\n\t"
"lds %B [waveBase], 0x0f" "\n\t"*/
OSCILLATOR_ASM
OSCILLATOR_ASM
OSCILLATOR_ASM
OSCILLATOR_ASM
OSCILLATOR_ASM
OSCILLATOR_ASM
OSCILLATOR_ASM
OSCILLATOR_ASM
:
sorties
[tempPhaseLow] "= & d" (tempPhaseLow),
[tempStep] "= & d" (tempStep),
[tempVolume] "= & d" (tempVolume),
[outValue] "= & d" (outValue)
:
entrées
[stepVolume] « y » (& oscillators[0].phaseStep),
[waveBase] « z » (256 * (((unsigned int) curWave) >> 8))
:
autres registres que nous écrase (en faisant des multiplications)
« r1 »
);
à ce stade outValue = valeur de l’oscillateur
Il est actuellement cotisé au maximum à plein volume / 4
certaine marge permettant de filtrage
#ifdef FILTER_LPF_HACK
un passe-bas filtre basé sur celui de MeeBlip (http://meeblip.noisepages.com)
un += f*((in-a) + q*(a-b)
b + = f * (a-b)
outValue >> = 3 ;
commencé à 4700
4686
int tempReg, tempReg2 = 0 ;
unsigned char zeroRegFilt = 0 ;
de-volatilisati
unsigned char filtF = filterF ;
unsigned char filtQ = filterQ ;
(volatile) ASM
"sub %A [outVal], A [filtA]" "\n\t"
"sbc %B [outVal], %B [filtA]" "\n\t"
"brvc No_overflow1 % =" « \n\t »
« ldi %A [outVal], 0b00000001 » "\n\t »
« ldi %B [outVal], 0b10000000 » "\n\t »
"No_overflow1 % =: « « \n\t »
outVal = (in French - filtA)
"mov %A [tempReg], A [filtA]" "\n\t"
"mov %B [tempReg], %B [filtA]" "\n\t"
"sub %A [tempReg], A [filtB]" "\n\t"
"sbc %B [tempReg], %B [filtB]" "\n\t"
"brvc No_overflow3 % =" « \n\t »
« ldi %A [tempReg], 0b00000001 » "\n\t »
« ldi %B [tempReg], 0b10000000 » "\n\t »
"No_overflow3 % =: « « \n\t »
tempReg = (a-b)
« mulsu %B [tempReg], % [filtQ] » "\n\t »
« movw %A [tempReg2], r0 » "\n\t »
tempReg2 = (HIBYTE(a-b)) * Q
"mul %A [tempReg], % [filtQ]" "\n\t"
"Ajouter %A [tempReg2], r1" "\n\t"
"adc %B [tempReg2], % [ZERO]" "\n\t"
« rol r0 » "\n\t »
"brcc No_Round1 % =" « \n\t »
"%A inc [tempReg2]" "\n\t"
"No_Round1 % =: « « \n\t »
à ce point tempReg2 = (a-b) * Q (décalé de façon appropriée et arrondi)
"clc" "\n\t"
"lsl %A [tempReg2]" "\n\t"
« rol %B [tempReg2] » "\n\t »
"clc" "\n\t"
"lsl %A [tempReg2]" "\n\t"
« rol %B [tempReg2] » "\n\t »
tempReg2 = (a-b) * Q * 4
"Ajouter %A [outVal], A [tempReg2]" "\n\t"
"adc %B [outVal], %B [tempReg2]" "\n\t"
"brvc No_overflow4 % =" « \n\t »
« ldi %A [outVal], 0b11111111 » "\n\t »
« ldi %B [outVal], 0b01111111 » "\n\t »
"No_overflow4 % =: « « \n\t »
outVal = ((in-a) + (a-b) * (Q >> 8) * 4) - coupé, etc.
« mulsu %B [outVal], % [filtF] » "\n\t »
« movw %A [tempReg], r0 » "\n\t »
"mul %A [outVal], % [filtF]" "\n\t"
"Ajouter %A [tempReg], r1" "\n\t"
"adc %B [tempReg], % [ZERO]" "\n\t"
« rol r0 » "\n\t »
"brcc No_Round2 % =" « \n\t »
"%A inc [tempReg]" "\n\t"
tempReg = f * ((in-a) + (a-b) * (Q >> 8) * 4)
"No_Round2 % =: « « \n\t »
"Ajouter %A [filtA], A [tempReg]" "\n\t"
"adc %B [filtA], %B [tempReg]" "\n\t"
A = A + f * ((in-a) + (a-b) * (Q >> 8) * 4)
"brvc No_overflow5 % =" « \n\t »
« ldi %A [outVal], 0b11111111 » "\n\t »
« ldi %B [outVal], 0b01111111 » "\n\t »
"No_overflow5 % =: « « \n\t »
maintenant calculer B = f * (a - b)
"mov %A [tempReg], A [filtA]" "\n\t"
"mov %B [tempReg], %B [filtA]" "\n\t"
"sub %A [tempReg], A [filtB]" "\n\t"
"sbc %B [tempReg], %B [filtB]" "\n\t"
"brvc No_overflow6 % =" « \n\t »
« ldi %A [tempReg], 0b00000001 » "\n\t »
« ldi %B [tempReg], 0b10000000 » "\n\t »
"No_overflow6 % =: « « \n\t »
tempReg = (a-b)
« mulsu %B [tempReg], % [filtF] » "\n\t »
« movw %A [tempReg2], r0 » "\n\t »
"mul %A [tempReg], % [filtF]" "\n\t"
"Ajouter %A [tempReg2], r1" "\n\t"
"adc %B [tempReg2], % [ZERO]" "\n\t"
tempReg2 = f*(a-b)
"Ajouter %A [filtB], A [tempReg2]" "\n\t"
"adc %B [filtB], %B [tempReg2]" "\n\t"
"brvc No_overflow7 % =" « \n\t »
« ldi %A [filtB], 0b11111111 » "\n\t »
« ldi %B [filtB], 0b01111111 » "\n\t »
"No_overflow7 % =: « « \n\t »
maintenant b = b+f*(a-b)
"mov %A [outVal], A [filtB]" "\n\t"
"mov %B [outVal], %B [filtB]" "\n\t"
multiplier outval par 4 et clip
"Ajouter %A [outVal], A [filtB]" "\n\t"
"adc %B [outVal], %B [filtB]" "\n\t"
« brbs 3, Overflow_End % = "« \n\t »
"Ajouter %A [outVal], A [filtB]" "\n\t"
"adc %B [outVal], %B [filtB]" "\n\t"
« brbs 3, Overflow_End % = "« \n\t »
"Ajouter %A [outVal], A [filtB]" "\n\t"
"adc %B [outVal], %B [filtB]" "\n\t"
« brbs 3, Overflow_End % = "« \n\t »
"rjmp No_overflow % =" « \n\t »
"Overflow_End % =: « « \n\t »
"brbs 2, Overflow_High % =" « \n\t »
« ldi %A [outVal], 0b00000001 » "\n\t »
« ldi %B [outVal], 0b10000000 » "\n\t »
"rjmp No_overflow % =" « \n\t »
"Overflow_High % =: « « \n\t »
« ldi %A [outVal], 0b11111111 » "\n\t »
« ldi %B [outVal], 0b01111111 » "\n\t »
"No_overflow % =: « « \n\t »
char valOut = ((unsigned int)(outValue)) >> 8 ;
valOut += 128 ;
OCR2A = valOut (octet) ;
"Felix %B [outVal], 0 x 80" "\n\t"
« m 0x00b3, %B [outVal] » "\n\t »
Décommentez les lignes ci-dessous pour voir la répartition du Registre
/*
"lds %A [filtA], 0 x 01" "\n\t"
"lds %B [filtA], 0 x 02" "\n\t"
"lds %A [filtB], 0 x 03" "\n\t"
"lds %B [filtB], 0 x 04" "\n\t"
"lds % [filtQ], 0 x 05" « \n\t »
"lds % [filtF], 0 x 06" « \n\t »
"lds %A [outVal], 0 x 07" "\n\t"
"lds %B [outVal], 0 x 08" "\n\t"
"lds %A [tempReg], 0 x 09" "\n\t"
"lds %B [tempReg], 0x0a" "\n\t"
"lds %A [tempReg2], 0x0b" "\n\t"
"lds %B [tempReg2], 0x0c" "\n\t"
"lds % [zéro], 0x0d" "\n\t"*/
:
sorties / lecture/écriture arguments
[filtA] "+ & w » (filterA),
[filtB] "+ & w » (filterB),
[tempReg] "= & un » (tempReg),
[tempReg2] "= & d" (tempReg2)
:
[filtQ] « a » (filtQ),
[filtF] « a » (filtF),
[outVal] « a » (outValue),
[ZÉRO] "d" (zeroRegFilt)
entrées
: "r1") ;
#endif
sortie se fait dans le code assembleur de filtre si les filtres sont sur
dans le cas contraire nous sortir à la main ici
#ifdef FILTER_LPF_NONE
gain intégral
outValue * = 4 ;
à ce stade, outValue est une version signée de 16 bits de ce que nous voulons, c’est à dire. 0 -> 32767, puis -32768 -> -1 (0xffff)
Nous voulons 0 -> 32767 pour aller à 32768-65535 et -32768 -> -1 à l’aller 0-32767, ensuite, nous ne souhaitons que l’octet haut de la page
prendre l’octet haut de la page, ajouter 128, puis effectuer un cast en unsigned. Le (unsigned int) dans le Voici pour éviter d’avoir à changer (ie.just prend albums octets)
char valOut = ((unsigned int)(outValue)) >> 8 ;
valOut += 128 ;
OCR2A = valOut (octet) ;
#endif
incrémente le compteur de boucle étape (et compteur haute)
ils sont utilisés parce que nous avons arrêter le chronomètre
interruption en cours d’exécution, ne donc aucun autre moyen pour indiquer l’heure
Cette asm n’est probablement pas vraiment nécessaire, mais il enregistre environ 10 instructions
parce que les variables doivent être volatile
ASM)
"inc % [loopSteps]" "\n\t"
« brbc 1, loopend % = "« \n\t »
"%A inc [loopStepsHigh]" "\n\t"
« brbc 1, loopend % = "« \n\t »
« %B inc [loopStepsHigh] » "\n\t »
"loopend % =: « « \n\t »
: [loopSteps] "+" (loopSteps), [loopStepsHigh] "+" (loopStepsHigh):) ;
}