Paso 22: Firmware
Cargar el firmware siguiente a la Junta Directiva:www.Monome.org www.Monome.org www.Monome.org www.Monome.org * * / / / asignaciones de PIN y puerto / / si está utilizando hardware que no sea el escudo unsped, usted querrá pasar por esta parte del código, / / y cambiar los números pin y atmega 168 puertos que usas. Aquí, estamos usando las asignaciones de pines del puerto / entradas / salidas no el esquema número de pin de la placa arduino (e.g. pin digital de arduino 8 = PORTB perno 1) / / sin embargo, en los comentarios, dan las equivalencias entre números de pin digital de arduino y la / / numeración de puerto y la broca del atmega168. IMPORTANTE - usted necesitará fijar los datos de dos variables de registro de dirección para que coincida con su / / asignaciones de pin. byte PORTD_Data_Direction = 0 x 02; //all entradas excepto pin 1 byte (TX) PORTB_Data_Direction = 0xFF; //all salidas byte PORTC_Data_Direction = 0xFC; //A2-A5 son salidas, A0, A1 entradas //Connections a cambio 595 registro //dataPin = A4 = PORTC, bit 4 //clockPin = A2 = PORTC, //latchPin bit 2 = A3 = PORTC, bit 3 #define DATA_PORT_595 (PORTC) byte dataPin595 = 4; byte dataPin595MaskHigh = 1 << dataPin595; byte dataPin595MaskLow = ~ dataPin595MaskHigh; #define CLOCK_PORT_595 (PORTC) byte clockPin595 = 2; byte clockPin595MaskHigh = 1 << clockPin595; byte clockPin595MaskLow = ~ clockPin595MaskHigh; #define LATCH_PORT_595 (PORTC) byte latchPin595 = 3; byte latchPin595MaskHigh = 1 << latchPin595; byte latchPin595MaskLow = ~ latchPin595MaskHigh; Conexiones con el Max7219 (unidades de LED) / / dataIn = pin arduino A5 = PORTC, bit 5 / / carga = arduino perno 11 = PORTB bit 4 / reloj = pin arduino 12 = PORTB, 5 #define LED_DATA_PORT (PORTC) Cuarteto MaxDataPin = 5; byte DataMaskHigh = 1 << MaxDataPin; byte DataMaskLow = ~ DataMaskHigh; bytes de LED_CLOCK_PORT (PORTB) #define MaxClockPin = 5; byte ClockMaskHigh = 1 << MaxClockPin; byte ClockMaskLow = ~ ClockMaskHigh; bytes de LED_LOAD_PORT (PORTB) #define MaxLoadPin = 4; byte LoadMaskHigh = 1 << MaxLoadPin; byte LoadMaskLow = ~ LoadMaskHigh; conexiones para el cambio 165 registro //use para fijar espejado mirrorXLEDs booleano = true; Boolean mirrorYLEDs = false; Boolean mirrorXButtons = false; Boolean mirrorYButtons = false; Pasador de extremo y asignaciones de Puerto / /---/ / Global variables byte byte0, byte1; almacenamiento de entrada byte de datos en serie WaitingForAddress = 1; 1 cuando esperamos el siguiente byte serial a un valor de dirección, dirección de 0 bytes lo contrario = 0 x 00; bytes de basura para mantener la dirección de la función estatal de byte = 0 x 00; bytes de basura para sostener el byte de estado valor x = 0 x 00; bytes de basura para mantener x posición byte y = 0 x 00; bytes de basura para mantener y posición byte z = 0 x 00; bytes de basura para iterar sobre botones / / las siguientes variables se utilizan para almacenar banderas que si hemos recibido un mensaje dado, / / el valor de los datos de ese mensaje. por ejemplo, IntensityChange = 0 no == ningún mensaje de cambio de la intensidad recibida, / / IntensityChange = 1 == un cambio de intensidad mensaje ha sido recibido, y su valor será de IntensityVal / / el código que finalmente actúa sobre el mensaje entrante restablecerá la variable 'Cambiar' a 0 una vez el / / mensaje se ha manejado. byte IntensityChange = 0; byte IntensityVal = 0; byte DisplayTestChange = 0; byte DisplayTestVal = 0; byte ShutdownModeChange = 0; byte ShutdownModeVal = 0; Estas variables se utilizan para manejar los mensajes de ADC y tienda que puertos están habilitados actualmente, / / y cuales no. byte ADCnum; byte ADCstate; byte ADCEnableState [4]; ledmem Byte [8]; memoria para los Estados LED - 64 bits. byte j = 0; variable temporal para botón bucle int i = 0; variable temporal para bucle id de etc. int = 0; almacenamiento temporal para entrante mensaje ID byte firstRun = 1; 1 cuando tenemos todavía recibir un comando de LED, 0 después de eso. para asegurar que nuestro estado led de la memoria se inicializa correctamente cuando recibimos el primer LED mensaje int kButtonUpDefaultDebounceCount = 12; Utilizado en botón contra rebotes int kButtonNewEvent = 1; Utilizado para almacenar si el estado de un botón ha cambiado o no. t bytes = 0; variable temporal utilizada en el procesamiento del botón / * botón matriz de VARIABLES de Estados de botón 1/0, uso 8 bytes (64 bits) para contador de botón debounce, matriz de 8 x 8 * / byte button_current [8]; button_last Byte [8]; button_state Byte [8]; button_debounce_count Byte [8] [8]; button_event Byte [8]; / * FIN de botón matriz de VARIABLES * / / * MAX 7219 instrucciones direcciones * / byte max7219_reg_noop = 0 x 00; definir max7219 registros (leído el documento técnico para explicación) byte max7219_reg_digit0 = 0 x 01; byte max7219_reg_digit1 = 0 x 02; byte max7219_reg_digit2 = 0 x 03; byte max7219_reg_digit3 = 0 x 04; byte max7219_reg_digit4 = 0 x 05; byte max7219_reg_digit5 = 0 x 06; byte max7219_reg_digit6 = 0x07; byte max7219_reg_digit7 = 0x08; byte max7219_reg_decodeMode = 0 x 09; byte max7219_reg_intensity = 0x0a; byte max7219_reg_scanLimit = 0x0b; max7219_reg_shutdown octeto 0x0c; byte max7219_reg_displayTest = 0x0f; / * FINAL de MAX 7219 instrucciones direcciones * / / / putByte - función auxiliar que envía un sólo byte al máximo chip void putByte (datos del octeto) {bytes i = 8; máscara de bytes; while(i > 0) {máscara = 0 x 01 << (i - 1); / / obtener la máscara de bits si (datos y máscara) / comprobar y enviar valor de este bit {LED_DATA_PORT | = DataMaskHigh;} más {LED_DATA_PORT & = DataMaskLow;} / / pulso del reloj de MAX LED_CLOCK_PORT y = ClockMaskLow; / / digitalWrite (reloj BAJA); "garrapata" prepeare poco entrada LED_CLOCK_PORT | = ClockMaskHigh; / / digitalWrite (reloj, alta); binario de la entrada "tock"--i; //maxSingle movimiento de bits menor}} es la función de "fácil" para un //dig solo max7219 es la fila, y seg es la columna llamada empuje y seg se refieren a nombres de pin de tecnología doc void maxSingle (dig byte, byte seg) {LED_LOAD_PORT & = LoadMaskLow; / / digitalWrite (carga, LOW); / / iniciar putByte(dig); / / especificar registro putByte(seg); / / ((data & 0x01) * 256) + datos >> 1); poner datos LED_LOAD_PORT | = LoadMaskHigh; digitalWrite(load,HIGH); } / / buttonInit - función auxiliar que ceros el botón Estados buttonInit(void) vacío {bytes; para (i = 0; i < 8; i ++) {button_current [i] = 0 x 00; button_last [i] = 0 x 00; button_state [i] = 0 x 00; button_event [i] = 0 x 00;}} / / buttonCheck - comprueba el estado de un botón determinado. void buttonCheck (fila de byte, byte índice) {si (((button_current [fila] ^ button_last[row]) & (1 << índice)) & & / / si el estado actual del botón físico es diferente de la ((button_current [fila] ^ button_state[row]) & (1 << índice))) {/ / última estado botón físico y la corriente debounced estado si (button_current [fila] & (1 << índice)) {/ / si el estado actual del botón físico es deprimido button_event [fila] = kButtonNewEvent << índice; / / cola un nuevo evento de botón inmediatamente button_state [fila] | = (1 << índice); y el estado debounced abajo. } else {button_debounce_count [fila] [índice] = kButtonUpDefaultDebounceCount;} / / de lo contrario el botón fue presionado anteriormente y ahora / / ha sido liberado por lo que establecemos nuestro contador debounce. } else if (((button_current [fila] ^ button_last[row]) & (1 << índice)) == 0 & & / si el estado actual del botón físico es el mismo que (button_current [fila] ^ button_state[row]) & (1 << índice)) {/ físico último botón Estado, pero la física actual / estado de botón es diferente de la actual debounce / / estado... Si (button_debounce_count [fila] [índice] > 0 & y--button_debounce_count [fila] [índice] == 0) {/ / si el el contador debounce tiene / / se reduce a 0 (significado el / el botón ha sido para / / kButtonUpDefaultDebounceCount / / iteraciones / / button_event [fila] = kButtonNewEvent << índice; / / cola un evento de cambio de estado de botón si (button_current [fila] & (1 << índice)) {/ / y cambiar los botones debounce estado. button_state [fila] | = (1 << índice);} else {button_state [fila] & = ~ (1 << índice);}}} } void buttonpress () {para (me = 0; i < 8; i ++) {LATCH_PORT_595 & = latchPin595MaskLow; / / conjunto clavija de enganche bajo para las salidas no cambian durante el envío de bits para (j = 0; j < 8; j ++) {CLOCK_PORT_595 & = clockPin595MaskLow;//digitalWrite(clockPin,LOW); si (j == me) {//if corriente igual de índice que valoro, conjunto bajo DATA_PORT_595 y = dataPin595MaskLow;//digitalWrite(A4,LOW);} más {//set el resto de los pines DATA_PORT_595 alta | = dataPin595MaskHigh; //digitalWrite (A4 ALTO); } CLOCK_PORT_595 | = clockPin595MaskHigh;//digitalWrite(clockPin,HIGH); } //set cierre perno alto-envía datos a salidas LATCH_PORT_595 | = latchPin595MaskHigh; //digitalWrite (latchPin, HIGH); Desaceleración se pone aquí para perder un poco de tiempo mientras esperamos el estado de la salida / / pins para resolver. Sin este bucle pérdida de tiempo, una sola pulsación se muestra como / / dos prensas (el botón y su vecino) volátiles int desaceleración = 0; mientras que (desaceleración < 15) {desaceleración ++;} button_last [i] = button_current [i]; para (id = 0; id < 8; id ++) {interruptor (id) {caso 0: t = digitalRead(A0); break; caso 1: t = digitalRead(A1); break; caso 2: t = digitalRead(2); break; case 3: t = digitalRead(3); break; caso 4: t = digitalRead(4); break; caso 5: t = digitalRead(5); break; caso 6: t = digitalRead(6); break; caso 7: t = digitalRead(7); break;} t = (t == 0); //invert t if(t) {button_current [i] | = (1 << id);} else {button_current [i] & = ~ (1 << id);} buttonCheck (i, id); Si (button_event [i] y (1 << id)) {button_event [i] & = ~ (1 << id); //zero el botón evento si (button_state [i] & (1 << id)) {Serial.write(1);} else {Serial.write(byte(0));} si (mirrorXButtons) {id = 7-id;} si (mirrorYButtons) {i = 7-i;} Serial.Write(((ID) << 4) | (i)); //set}}} todos los pines de 595 alto LATCH_PORT_595 & = latchPin595MaskLow; / / configurar pin de cierre baja por lo que las salidas no cambian durante el envío de bits para (j = 0; j < 8; j ++) {CLOCK_PORT_595 & = clockPin595MaskLow;//digitalWrite(clockPin,LOW); DATA_PORT_595 | = dataPin595MaskHigh;//digitalWrite(A4,HIGH); CLOCK_PORT_595 | = clockPin595MaskHigh;//digitalWrite(clockPin,HIGH); } //set cierre perno alto-envía datos a salidas LATCH_PORT_595 | = latchPin595MaskHigh; //digitalWrite (latchPin, HIGH); } ISR(TIMER2_COMPA_vect) {{si (Serial.available()) {si (WaitingForAddress == 1) {byte0 = Serial.read(); dirección = byte0 >> 4; WaitingForAddress = 0; } / / fin si (WaitingForAddress == 1); Si (Serial.available()) {WaitingForAddress = 1; byte1 = Serial.read(); switch(address) {caso 2: estado = byte0 & 15; x = byte1 >> 4; y = byte1 & 15; si (estado == 0) {ledmem [7-y] & = ~ (1 << x);} else {ledmem [7-y] | = (1 << x);} break; caso 3: IntensityChange = 1; IntensityVal = byte1 y 15; rotura; caso 4: DisplayTestChange = 1; DisplayTestVal = byte1 y 15; rotura; caso 5: estado = byte1 & 0x0F; ADCEnableState [(byte1 >> 4) & 0 x 03] = Estado; rotura; caso 6: ShutdownModeChange = 1; ShutdownModeVal = byte1 y 15; rotura; caso 7: Si (firstRun == 1) {para (x = 0; x < 8; x ++) {ledmem [x] = 0;} firstRun = 0;} x = ((byte0 & 15) & 0x7); Este valor de la máscara para no escribir a una dirección no válida. y = byte1; Si (mirrorYLEDs) {y = 7-y;} si (mirrorXLEDs) {x=flipByte(x);} ledmem [x] = y; rotura; caso 8: Si (firstRun == 1) {para (x = 0; x < 8; x ++) {ledmem [x] = 0;} firstRun = 0;} x = ((byte0 & 15) & 0x7); y = byte1; Si (mirrorYLEDs) {x = 7-x;} si (mirrorXLEDs) {y=flipByte(y);} para (z = 0; z < 8; z ++) {si (y & (1 << z)) {ledmem [z] | = 1 << x;} else {ledmem [z] & = ~ (1 << x);}} break; } / / fin switch(address)} / / fin si (Serial.available()} / / fin si (Serial.available();} / / fin mientras que (Serial.available() > 16); } void whoosh(void) {/ / reactivar la interrupción de desbordamiento para / / temporizador 1 - ha necesitado por delay(...) TIMSK0 | = (1 << TOIE0); para (int j = 0; j < 9; j ++) {para (int i = 0; i < 8; i ++) {maxSingle (i + 1, 1 << j);} delay(125);} / / y apagar la interrupción. TIMSK0 & = ~ (1 << TOIE0); } void setup () {DDRD = PORTD_Data_Direction; DDRB = PORTB_Data_Direction; DDR = PORTC_Data_Direction; Serial.Begin(57600); buttonInit(); iniciación de la maxSingle 7219 máximo (max7219_reg_scanLimit, 0x07); maxSingle(max7219_reg_intensity,0x0F); maxSingle (max7219_reg_shutdown, 0 x 01); no en modo de apagado maxSingle (max7219_reg_displayTest, 0 x 00); vaciar los registros, gire todos los LEDs de h para (me = 1; i < = 8; i ++) {maxSingle(i,0); ledmem [i-1] = 0;} (cli); //stop interrupciones //set timer2 interrumpir cada TCCR2A 128us = 0; / ajustar todo registro de TCCR2A a 0 TCCR2B = 0; / / igual para TCCR2B TCNT2 = 0; //initialize valor de contador a 0 / / sistema compara partido registro para incrementos de 7,8 khz OCR2A = 255; / = (16 * 10 ^ 6) / (7812.5 * 8) - 1 (debe ser < 256) / / Activar modo CTC TCCR2A | = (1 << WGM21); Sistema poco CS11 para 8 prescaler TCCR2B | = (1 << CS11); habilitar interrupción de timer compara TIMSK2 | = (1 << OCIE2A); (SEI); interrupciones //allow / / / / configurar el contador de 8 bits 2, salida compara apagada, / / / / normal generación de forma de onda (lo que puede significar) / / TCCR2A = 0; / / contador para ser registrado en 16Mhz/8 = 2 Mhz / / TCCR2B = 1 << CS21; / / / / establecer la máscara de interrupción para que tengamos una interrupción / / / / desbordamiento de timer 2, es decir, después de 256 ciclos de reloj. / / Se ejecuta la rutina de interrupción del timer 2 todos / / / / 128 nosotros. TIMSK2 = 1 << TOIE2; / / / Nota: en mi esfuerzo por tratar de que esto / / / / código para trabajar confiablemente a 115200 baudios / / / / fui sobre deshabilitar sin usar temporizadores que / / / / se establecen por el framework de Arduino. / / El marco establece dos timer 2 y / / / / temporizador 1. Utilizamos el timer 2 para conducir el / / / / serie de interrupción de la lectura, tan sólo podemos / / / / desactivar timer1 y su interrupción. / / / / MUY importante Nota: Si desea usar / / / / ANALOGWRITE / / / / / / desactivar el temporizador 1 se desconecta el temporizador / / / usa para PWM, que es la base de analogWrite. / Si desea utilizar analogWrite, quite / / / / las líneas de abajo. / / / / DESHABILITAR contador PWM / / TIMSK0 & = ~ (1 << TOIE0); / / TCCR1B & = ~ (1 << CS12); TCCR1B & = ~ (1 << CS11); TCCR1B & = ~ (1 << CS10); / / FIN desactivar el PWM contador / / / / / / también, desactivar las interrupciones de temporizador 0 / / / / realmente importante Nota Si usted quiere usar / / / retardo / / / eliminar esta línea y también / / / / 'whoosh', que activa y desactiva entonces / / / / intterupt temporizador 0. Usted querrá / / / / para deshacerse de esas líneas también. TIMSK0 & = ~ (1 << TOIE0); bonito del patrón para asegurarme que el firmware / / subido correctamente. Whoosh(); Asegúrese de apagar las luces. para (int i = 0; i < 8; i ++) {maxSingle(i+1,0);}} void sendADC (int puerto, int valor) {/ / Serial.write ((1 << 4) | ((puerto << 2) y 0x0C) | ((valor >> 8) & 0 x 03)); Serial.Write (valor & 0xFF); } / / //int actual [4]; int anterior [4]; tolerancia de int = 7; void checkADCs() {/ / / / para (int adcCounter = 0; adcCounter < 4; adcCounter ++) / / {/ / / si (ADCEnableState [adcCounter]! = 0) / / {/ / corriente [adcCounter] = analogRead(adcCounter); / / / si (abs(previous[adcCounter]-current[adcCounter]) > tolerancia) / / {/ / anterior [adcCounter] = corriente [adcCounter]; / / sendADC(adcCounter,current[adcCounter]); / /} / / / /} / / / /} / /} byte flipByte (numToFlip bytes) {espejo bytes = 0; para (int j = 0; j < 8; j ++) {copia byte = numToFlip; espejo | = (copia >> j) & 1; si (j < 7) {espejo = espejo << 1;}} vuelta espejo;} void loop () {/ los Estados LED, enviar a la matriz de LED. para (int i = 0; me < 8; i ++) {byte ledmemMirror = 0; si (mirrorXLEDs) {ledmemMirror=flipByte(ledmem[i]);} más {ledmemMirror = ledmem [i];} int y; si (mirrorYLEDs) {y =(7-i) + 1;} más {y = i + 1;} maxSingle(y,ledmemMirror);} si (IntensityChange == 1) {IntensityChange = 0; maxSingle (max7219_reg_intensity, IntensityVal y 15);} si (DisplayTestChange == 1) {DisplayTestChange = 0; maxSingle (max7219_reg_displayTest, DisplayTestVal y 15);} si (ShutdownModeChange == 1) {ShutdownModeChange = 0; maxSingle (max7219_reg_shutdown ShutdownModeVal y 15); } / / comprobar botón presiona buttonpress(); / / comprobar el estado de la ADCs / / checkADCs(); }
Debería ver el LED enciende para arriba de una columna en una hora y un desplazamiento en la pantalla cuando haya terminado el firmware subir:
Si tus leds no están conectados correctamente, les fija ahora antes de pasar al siguiente paso.