Hola, estos días retome un código que hice hace un par de veranos y lo logré hacer funcionar, se trata de un decodificador digital para locomotoras, muy básico pero quiero compartirlo con todos.
La idea es la siguiente toman un Pic lo configuran a su gusto y le ponen este código que en resumen hace lo siguiente:
Son tres fases
-detectar el preámbulo, 12 unos lógicos y espera por el 0 si no empieza de nuevo
-detectar los paquetes de datos, detecta 9 bit (si 9) los aloja en una variable y si el noveno bit es 0 empieza otra variable
si es 1 da por terminada la recepción.
-gestión de datos, pues hace lo que indica, de momento lo mas básico, dirección, velocidad y funciones 1 a 4
La detección del bit se hace por "polling" en la entrada del Pic (A5), pero al salir se repregunta, a modo de asegurar el estado de
la entrada
bucle clrwdt
clrf checksum ;borra la variable que contiene el xor de datos DCC recibidos
bcf flagbyte,7 ;pone a 0 el flag
bcf PORTA,4 ;pone a 0 la salida A4 led de error
movlw 0x0c ;carga W con el valor de 1 logicos minimos a detectar en el preambulo
movwf preamble_count ;lo descarga en la variable preamble_count
preamble_detect
clrwdt ;algoritmo contador duracion de un pulso en A5 3a (58uS)es para saber si dura mas o menos---
clrf valor ;pone a 0 la variable que se usara como contador
btfss PORTA,5 ;comprueba el estado de A5
goto preamble_detect ;no sale mientras no se recibe un bit DCC
dpa clrwdt
incf valor,F ;incrementa la variable
btfsc PORTA,5 ;comprueba el estado de A5
goto dpa ;va a la etiqueta no sale del loop hasta que no acabe el pulso
nop ;5 nop = 1uS 20MHZ xtal 5uS 4 MHZ xtal
nop ;retardo para una segunda lectura
nop ;de la entrada
nop ;
nop ;
btfsc PORTA,5 ;comprueba el estado de A5 sale si realmente fue 0 y no falso contacto
goto dpa ;reitera la consulta de estado del bit para asegurar el dato
movf valor,W ;carga la duracion del pulso en W
bcf STATUS,C ;borra el Carry
sublw 0x0e ;0x41 para 20 MHZ resta una W de una constante de tiempo
btfss STATUS,C ;mira si W era mayor o menor que la constante
goto dpe ;
decfsz preamble_count,F ;al ser menor es 1 logico se decrementa la variable de preamble
goto preamble_detect ;se va a detectar otro bit DCC
bsf flagbyte,7 ;pone a 1 un flag para indicar que se alcanzaron los 1 necesarios de preamble ;
goto preamble_detect ;se va a detectar otro bit DCC-------------------------------------
dpe btfss flagbyte,7 ;comprueba el flag
goto bucle ;error se recibio un 0 sin los 1 necesarios preamble no valido
bcf flagbyte,7 ;pone a 0 el flag
data_detect ;rutina para detectar los bites de datos
movlw (dato1) ;carga el valor offset INDF para el registro FSR
movwf FSR ;INDF apunta a la variable dato1
data_detect2
movlw 0x09 ;bits DCC a detectar 8 + 0 o 1 de fin de paquete
movwf data_count ;variable contador de bit 8+1 fin paquete
movlw 0x03 ;numero maximo de bytes a rellenar
addlw (dato1) ;le suma el offset
bcf STATUS,C ;borra el Carry
subwf FSR,W ;lo resta del FSR
btfsc STATUS,C;
goto signal_error2 ;error por exceso de paquetes 1 de final no recibido
data_detect1
clrwdt
clrf valor ;borra la variable
btfss PORTA,5 ;comprueba el estado de A5
goto data_detect1 ;no sale mientras no se recibe un bit DCC
dpa2 clrwdt
incf valor,F ;incrementa la variable
btfsc PORTA,5 ;comprueba el estado de A5
goto dpa2 ;va a la etiqueta
nop ;5 nop = 1uS 20MHZ xtal
nop ;retardo para una segunda lectura
nop ;de la entrada
nop ;
nop ;
btfsc PORTA,5 ;comprueba el estado de A5 sale si realmente fue 0 y no falso contacto
goto dpa2 ;reitera la consulta de estado del bit para asegurar el dato
decfsz data_count,F ;si es 0 pasa al siguiente byte
goto data_detect4 ;va a recibir un bit DCC
goto data_detect3 ;va a rellenar el siguiente byte
data_detect4
movf valor,W ;carga la duracion del pulso en W
rlf INDF,F ;rota a la izquierda para el siguiente bit
bcf STATUS,C ;borra el Carry
sublw 0x0e ;0x41 para 20 MHZ resta una constante de tiempo a W
bcf INDF,0 ;pone a 0 la variable
btfsc STATUS,C ;mira si W era mayor o menor que la constante
bsf INDF,0 ;pone a 1 el bit DCC en la variable
goto data_detect1 ;
data_detect3
movf valor,W ;carga la duracion del pulso en W
bcf STATUS,C ;borra el Carry
sublw 0x0e ;0x41 para 20 MHZ resta una constante de tiempo a W
btfsc STATUS,C ;mira si W era mayor o menor que la constante
goto gestion_datos ;
movf INDF,W ;carga W con el byte recibido
xorwf checksum,F ;hace un xor para hacer el checksum
incf FSR,F ;incrementa el puntero FSR
goto data_detect2 ;
gestion_datos
movlw (dato3) ;carga en W el puntero de la variable que contiene el checksum
movwf FSR ;decrementa el puntero FSR para apuntar al ultimo dato recibido
movf INDF,W ;carga W con el ultimo dato recibido
subwf checksum,W ;resta el checksum del checksum recibido
btfss STATUS,Z ;si es 0 se recibio todo bien
goto signal_error3;se?aliza error
movf dato1,F ;comprueba si es la direccion 0
btfsc STATUS,Z ;si no es 0 continua comprobando la direccion DCC
goto adv ;la direccion 0 la deben atender todos los decodificadores DCC
movf dcc_adr,W ;carga W dcc_adr = direccion addreses del decodificador DCC
subwf dato1,W ;dcc_adr decoder - DCC byte = 0 OK se procesan los datos
btfss STATUS,Z ;si lo es salta y ejecuta el codigo para hacer el tratamiento de los datos recibidos
goto bucle ;la variable dato1 addresses no es la del decodificador entonces vuelve al principio
adv movlw 0x01 ;carga el PCLATH con 1 para asegurar el computed goto correcto
movwf PCLATH ;
swapf dato2,W ;intercambia nibbles
movwf resultado ;deja W en la variable temporal
rrf resultado,F ;rota una posicion a la derecha
movlw 0x07 ;carga W con la mascara para dejar solo los bit 7,6,5 (nibbles intercambiados)
andwf resultado,W ;hace el and y lo deja en W
salto addwf PCL,F ;suma el resultado al PCL para hacer un computed goto
goto control_in ;0 va a la rutina de gestion Decoder Control Instruccion
goto operacion_in;1 va a la rutina de gestion Advanced Operation Instruccion
goto reverse_op ;2 va a la rutina de gestion velocidad y marcha atras
goto forward_op ;3 va a la rutina de gestion velocidad y marcha adelante
goto funcion_0_4 ;4 va a la rutina de gestion activacion de las funciones de la 0 a la 4
goto funcion_5_12;5 va a la rutina de gestion activacion de las funciones de la 5 a la 12
goto f_expansion ;6 va a la rutina de gestion futura s expansiones
goto cv_instruccion ;7 CV Configuracion Variable access Instruccion
goto bucle ;8
goto bucle ;9
goto bucle ;a
goto bucle ;b
goto bucle ;c
goto bucle ;d
goto bucle ;e
goto bucle ;f
control_in
goto bucle
operacion_in
goto bucle
reverse_op
btfsc CCP1CON,P1M1 ;comprueba el cambio de sentido de marcha
goto frenado_auto
bcf flagbyte,5 ;indica la marcha atras
bcf CCP1CON,P1M1 ;pone a 0 el bit del PWM reverse
goto pwm_v ;va a cargar el PWM duty cycle
forward_op
btfss CCP1CON,P1M1 ;comprueba el cambio de sentido de marcha
goto frenado_auto ;va a la secuencia de frenado automatico
bsf flagbyte,5 ;indica la marcha adelante
bsf CCP1CON,P1M1 ;pone a 1 el bit del PWM
pwm_v
movf dato2,W ;carga W con el valor de velocidad
movwf v_general2 ;descarga W para modificar la variable y pasar el bit 4 al bit 0
rlf v_general2,F ;hace 4 rotaciones para pasar el bit 4 al CARRY
rlf v_general2,F ;
rlf v_general2,F ;
rlf v_general2,F ;
swapf v_general2,F ;intercambia nibbles
rlf v_general2,W ;ahora tenemos los bit 4,3,2 mas el bit 0 que antes era el 4
andlw 0x1f ;hace un and para dejar solo los bit de velocidad
movwf CCPR1L ;los descarga en la variable y luego al Duty Cycle del PWM en el bucle principal
rlf CCPR1L,F ;multiplica por 2 el DUTY CYCLE
rlf CCPR1L,F ;multiplica por 2 el DUTY CYCLE
movwf v_general2 ;los descarga en el registro para saber si es 0
bcf STATUS,C ;borra el CARRY
rrf v_general2,F ;desplaza a la derecha para saber si es 0 (valores 0 y 1 STOP)
movf v_general2,F ;si es 0 ejecuta el codigo de parada
btfss STATUS,Z ;
goto bucle
clrf CCPR1L ;pone a 0 el PWM
goto bucle
frenado_auto
movlw 0x80 ;mascara para conmutar el bit 7 PM1 direccion forw/revr
xorwf CCP1CON,W ;carga el bit
movwf CCP1CON ;lo descarga conmutado
clrf CCPR1L ;reduce a 0 el DUTY CYCLE
call delay ;produce un retardo para no invertir el motor demasiado rapido
call delay ;produce un retardo para no invertir el motor demasiado rapido
call delay ;produce un retardo para no invertir el motor demasiado rapido
call delay ;produce un retardo para no invertir el motor demasiado rapido
goto bucle ;
funcion_0_4
bsf PORTB,1 ;pone a 0 la salida 1
btfss dato2,0 ;si el bit de la variable esta a 1 activa bit en el PUEROB
bcf PORTB,1;pone a 1 el bit del PUERTOB Funcion 1
bsf PORTB,2 ;pone a 0 la salida 2
btfss dato2,1 ;si el bit de la variable esta a 1 activa bit en el PUEROB
bcf PORTB,2;pone a 1 el bit del PUERTOB Funcion 2
bsf PORTB,4 ;pone a 0 la salida 4
btfss dato2,2 ;si el bit de la variable esta a 1 activa bit en el PUEROB
bcf PORTB,4;pone a 1 el bit del PUERTOB Funcion 3
bsf PORTB,5 ;pone a 0 la salida 5
btfss dato2,3 ;si el bit de la variable esta a 1 activa bit en el PUEROB
bcf PORTB,5;pone a 1 el bit del PUERTOB Funcion 4
bcf PORTB,6 ;pone a 1 la salida B6 FL en avance
bcf PORTB,7 ;pone a 1 la salida B7 FL en marcha atras
btfss dato2,4 ;si el bit de la variable esta a 1 activa bit en el PUEROB
goto bucle ;si la funcion FL no activada sale
btfss flagbyte,5 ;comprueba la direccion
bsf PORTB,7 ;pone a 0 la salida B7 FL en marcha atras
btfsc flagbyte,5 ;comprueba la direccion
bsf PORTB,6 ;pone a 0 la salida B6 FL en avance
goto bucle
funcion_5_12
goto bucle
f_expansion
goto bucle
cv_instruccion
goto bucle