Hola a todos!
Soy nuevo en el foro, así que primero me presentaré.
Me gusta la electrónica desde que era un enanillo, y hace unos años decidí involucrarme más aprendiendo sobre electrónica digital. En programación de PIC no soy ningún experto, sino más bien un aprendiz, pero hasta ahora mis modestos proyectos me habían funcionado a la primera o si acaso con pequeñas depuraciones sin mucha importancia.
Mi proyecto es el siguiente:
Soy técnico de sonido, y tengo en mi estudio multitud de aparatos MIDI. Existe un software llamado TOTAL RECALL, pero los que lo conozcan sabrán la poca facilidad que se tiene para implementar hojas de nuevos dispositivos (tanto por el soft en sí como por la poca información que dan las marcas sobre sus dispositivos con puertos MIDI).
Lo que quiero hacer, es poder enviar órdenes MIDI desde un 16F84, pero no cualquier orden: el comando de cambio de programa (y próximamente el de cambio de controlador, pero eso es otro cantar).
Sé que el 16F84 no es el más indicado por no tener puerto serie, pero, es para mí el más valorado, sobre todo por la multitud de veces que lo he usado. Tengo también 16f876, pero no quiero emplearlo.
Bien, después de mi cabezonería con este micro, diré que he escrito una rutina que hace las veces de puerto serie correctamente configurado para trabajar a 31,25kbaudios (es decir, una orden durará 32uS).
Sé que el midi utiliza un bit start (siempre cero), los ocho de mensaje, y un bit-stop. Conozco la sintaxis MIDI porque es parte de mi trabajo, aunque no el más frecuente (pero hay que saber programar MIDI). Aunque eso no quita que se me haya podido pasar algún detalle... claro.
El problema es: cargué mi programa al 16F84, sobre la protoboard, con cristal de 4Mhz y el cable MIDI a mi aparato (concretamente usé un TC Electronics G-Major en primer lugar), y funcionó, cambió de programa. Volví a dar la orden y volvió a cambiar, pero a otro programa distinto (dando la misma orden el PIC). Después de eso no volvió a funcionar.
El pic no está dañado (comprobado como veinte veces), el cable tampoco y la unidad tampoco (probado con otros dispositivos MIDI y funciona perfectamente).
He probado de todo y nada, no he vuelto a conseguir (ni siquiera con el mismo código y montaje) que me haga caso, no detecta órdenes MIDI cuando se las doy con el PIC.
El protocolo MIDI recibe órdenes en binario natural (los 1 son 1 y los 0 son 0, al contrario que el RS-232). Por lo que mi montaje fue de RA0 ---> RX del MIDI. Y así funcionó, y no ha vuelto a hacerlo.
He probado con inversor 7404, con inversión por mi firmware, con un 2N2222, tal como todos recomiendan, etc.
Y NADA DE NADA.
Alguien puede decirme algo? Estoy completamente ofuscado.
Mi código:
ESPERA CLRF MEMORIA ;
CLRW ; PUESTO DE PRUEBA: CANAL2 (INTERFAZ), MIDI=1
MOVLW b'11000001' ; Esto luego habra que sacarlo de la EEPROM, pero de momento
CLRF MEMORIA ; lo cargo manualmente desde aqui.
MOVWF MEMORIA ;
CALL MIDI_S ; Llama a la rutina de envio (se envia el byte cargado en MEMORIA)
CALL DELAY_BOTON ; Todo este tiempo de espera es porque a algunos aparatos MIDI
CALL DELAY_BOTON ; les cuesta tiempo la orden de cambio de programa (por ejemplo,
CALL DELAY_BOTON ; behringer tiene un tiempo enorme para esto, asi como TC lo tiene
CALL DELAY_BOTON ; muy bajo).
CALL DELAY_BOTON
CALL DELAY_BOTON
CALL DELAY_BOTON
CALL DELAY_BOTON
CLRW
MOVLW b'11000110' ; PUESTO DE PRUEBA CANAL 7 (INTERFAZ), MIDI=6
CLRF MEMORIA
MOVWF MEMORIA
CALL MIDI_S ;Hace otra transmision diferente (otro numero de programa)
CALL DELAY_BOTON
CALL DELAY_BOTON
CALL DELAY_BOTON
CALL DELAY_BOTON
CALL DELAY_BOTON
CALL DELAY_BOTON
CALL DELAY_BOTON
CALL DELAY_BOTON
GOTO ESPERA
;
; FIN DE CODIGO PARA PROBAR
;
;============================================
; DELAY
;============================================
;
; Produce una demora de 260 ms.
;============================================
DELAY_BOTON CLRW
CLRF CONTADOR2
CLRF CONTADOR
MOVLW h'FF' ; Coloca el valor 255 en el contador.
MOVWF CONTADOR2
RESTA2 DECFSZ CONTADOR2,F ; Resta y salta si = 0.
GOTO NO_FIN ; Si no ha terminado sigue.
GOTO SI_FIN ; Si ha terminado, va al return de rutina.
NO_FIN MOVLW h'FF' ; Coloca el valor 255 en el contador.
MOVWF CONTADOR
RESTA NOP
DECFSZ CONTADOR,F ; Resta y salta si = 0.
GOTO RESTA ; Repite el bucle hasta terminar la cuenta.
GOTO RESTA2
SI_FIN RETURN ; Termina la subrutina de delay.
;============================================
; FIN RUTINA DELAYS
;============================================
;================================================
; Manera de hacer un envio:
;================================================
;
; Se pone en W el byte a enviar y se hace
; una llamada CALL MIDI_S, que envia el byte
; por RA0 con sincronia.
;
;================================================
;================================================
; RUTINA PRINCIPAL |
;================================================
; |
; EnvÌa por transmision serie el contenido |
; del registro MEMORIA, un banco temporal al |
; que se ha de copiar previamente el valor |
; binario a enviar almacenado en la eeprom. |
; Ello con la temporizacion necesaria para |
; la comprension por dispositivos MIDI. |
; |
;================================================
MIDI_S MOVWF MEMORIA ; Coloca el valor de W en el registro memoria para trabajar
BANCO0 ; Cambia a banco0 para hacer cambios en el estado de RA0
BCF PORTA,0 ; Pone RA0 a nivel bajo, por si estubiera alto de antes.
CALL DELAY_BOTON ; He introducido esto, por si el tiempo de cero no fuera suficiente, ya que si viene de un uno, no hay 32uS de diferencia.
CLRF CARRY ; Borra el contenido que hubiera en el registro CARRY.
MOVLW d'9' ; Carga el contador de envios realizados con el valor 8.
MOVWF CARRY
CORRER DECFSZ CARRY ; Decrementa el contador de bits enviados y salta si = 0.
GOTO SIGUE ; Aun no ha enviado ocho bits, por lo que sigue enviando.
GOTO TERMINA ; Ya ha enviado ocho veces, asi que termina.
SIGUE NOP ; Ya que en el goto del que procedemos lleva un anticipo en este caso
BTFSC MEMORIA,7 ; Si el bit actual es cero va a PON_CERO
GOTO PON_UNO ; pero si es uno, no salta y va a PON_UNO.
GOTO PON_CERO
PON_UNO NOP Ya que en el goto del que procedemos lleva un anticipo en este caso.
CLRF CONTADOR ; Borra por si hubiera algo de antes.
;===============DELAY=============
MOVLW d'6' ; Coloca el valor 5 en el contador.
MOVWF CONTADOR
BUCLE DECFSZ CONTADOR,F ; resta y salta si = 0.
GOTO BUCLE ; repite el bucle hasta terminar la cuenta.
NOP
;===============DELAY=============
BSF PORTA,0 ; Pone un 1 en RA0.
RLF MEMORIA,F ; Rota el contenido del byte MEMORIA hacia la izquierda, y lo almacena en el propio registro.
GOTO CORRER ; Repite la tarea para enviar el siguiente bit en caso de que proceda.
PON_CERO CLRF CONTADOR ; Borra por si hubiera algo de antes.
;===============DELAY=============
MOVLW d'6' ; Coloca el valor 5 en el contador.
MOVwF CONTADOR
BUCLE_ DECFSZ CONTADOR,F ; resta y salta si = 0.
GOTO BUCLE_ ; repite el bucle hasta terminar la cuenta.
NOP ; En caso de continua o falta de sincronia, puede probarse a ser cambiado por "BCF PORTA,0" a ver si mejora.
;===============DELAY=============
BCF PORTA,0 ; Pone un 0 en RA0.
RLF MEMORIA,F ; Rota el contenido del byte MEMORIA hacia la izquierda, y lo almacena en el propio registro.
GOTO CORRER ; Repite la tarea para enviar el siguiente bit en caso de que proceda.
;===============DELAY FINAL=======
; Ahora ponemos un delay para que si el ultimo bit enviado es uno no se corte antes de tiempo.
TERMINA MOVLW d'8' ; Coloca el valor 5 en el contador.
MOVWF CONTADOR
BUCLE1 DECFSZ CONTADOR,F ; resta y salta si = 0.
GOTO BUCLE1 ; repite el bucle hasta terminar la cuenta.
BSF PORTA,0 ; Envia el STOP BIT, que siempre es 1.
;====================
; DELAY PARA STOP-BIT
;====================
MOVLW d'10' ; Coloca el valor 5 en el contador.
MOVwF CONTADOR
BUCLE__ DECFSZ CONTADOR,F ; resta y salta si = 0.
GOTO BUCLE__ ; repite el bucle hasta terminar la cuenta.
NOP
BCF PORTA,0 ; Termina el STOP-BIT, asi que volvemos a dejar RA0 en estado bajo.
;====================
; DELAY PARA STOP-BIT
;====================
NOP
CLRF MEMORIA ; Borra el registro temporal MEMORIA.
RETURN ; Vuelve al programa, donde esperara una nueva orden de envio.
;================================================
; FIN DE LA RUTINA
;================================================
END ; Fin del programa.