TODOPIC
Microcontroladores PIC => Almacén del Assembler => Mensaje iniciado por: groundman en 03 de Junio de 2012, 18:42:22
-
hola.estoy con un proyecto para gestionar las tramas del protocolo MODBUS.
ya tengo realizado la recepcion y almacenamiento en la ram del pic de los datos recibidos.pero necesito relizar el calculo del CRC para saber si los datos-
recibidos son correctos.
para ello queria desarroyar la rutina de comprobacion.pero si alguien tiene alguna ya hecha le agradeceria el tiempo que me ahorraria.
en caso contrario si la desarroyo ya la pondria por aqui.gracias de antemano.
-
bueno.ya esta casi terminado.trabajo me ha costado.me he llevado una alegria cuando he metido los valores de una trama modbus y he visto que los valores
del CRC han coincidido.
es un calculo muy tedioso.desarroyar un programa a partir de un ejemplo en una oja escrita (sin codigo) cuesta un trabajazo.pero os aseguro que la logica
de funcionamiento la tengo bien aprendida.
me he percatado que el CRC se crea despues de cada byte gestionado.y que este se va modificando despues de la gestion del siguiente byte.el calculo del
CRC es infinito si no dejamos de analizar bytes.aunque cuando llegamos al ultimo byte a analizar,el CRC es el ultimo valor que nos da de la gestion de todos
los bytes.
el codigo que he realizado no es muy grande.
no esta terminado del todo.este es infinito.me falta ponerle la finalizacion por localizacion del ultimo byte a leer.
pero se puede probar en un simlador.el CRC es contenido en los registros TEMP_CRCH y TEMP_CRCL.solo hay que poner un break point.despues de haberse guardado los valores del CRC en ellos.la linea tiene la etiqueta CRC1.
los datos a gestionar se cogen a partir de la direccion de memoria 0x20.aunque podemos cambiarlo a la que queramos.
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CALCULO CRC >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
CRC clrf FSR1H ;borra puntero FSR
clrf CONT_CRC ;borra contador de rotaciones
clrf CONT_CRC2 ;borra contador de datos analizados
setf CRCH ;pon a 1 todos los bits del registro alto,cotenedor de CRCs (inicializacion)
setf CRCL ;pon a 1 todos los bits del registro bajo,cotenedor de CRCs (inicializacion)
movlw 0x20 ;valor para primer direccion a leer de la ram.
movwf FSR1L ;selecciona primera posicion de registros de la ram.
CRC1 movff CRCH,TEMP_CRCH ;intercambia registros principales a temporales.
movff CRCL,TEMP_CRCL ;intercambia registros principales a temporales.
;separar los nibles de un registro para introducirlos en el nible bajo de otros dos registros.
movff INDF1,CRCH ;introduce en CRCH valor leido de la ram.
movff INDF1,CRCL ;introduce en CRCH valor leido de la ram.
swapf CRCH,F ;invierte los nibles de CRCH.
movlw 0X0F ;valor para conservar el nible bajo.
andwf CRCH,F ;borra el nible alto.
incf FSR1L ;incrementa indice de direccionamiento de la ram
movf TEMP_CRCH,W ;mueve a W el valor alto del valor leido de la ram
xorwf CRCH,F ;hacer xor con el dato anterior (primera operacion de conversion CRC)
movf TEMP_CRCL,W ;mueve a W el valor bajo del valor leido de la ram
xorwf CRCL,F ;hacer xor con el dato anterior (primera operacion de conversion CRC)
CRC2 call ROTAC ;llamada a rutina de conversiones por rotacion.
btfsc FLAGS,4 ;comprueba si ha habido acarreo en la rotacion.
call SUM ;llamada a rutina de operacion xor 0xA001 si ha habido acarreo.
CARRY_OFF ;borra flag carry
movlw 0X08 ;valor del contage de movimientos de rotacion
xorwf CONT_CRC2,w ;comprueba si ha llegado al valor anterior
btfss STATUS,Z ;si no es asi,
goto CRC2 ;realiza otra rotacion
clrf CONT_CRC2 ;en caso contrario reinicia el contador
goto CRC1 ;vuelve a por el siguiente valor en ram a convertir.
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ROTACIONES >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><
ROTAC incf CONT_CRC ;incrementa contador de CRC (totales)
incf CONT_CRC2 ;incrementa contador de 8 contages
rrcf CRCL,F ;rota CRCL hacia la derecha.
btfsc STATUS,C ;comprueba si ha habido acarreo
CARRY_ON ;si es asi,activa flag de carry.
bcf STATUS,C ;borra flag carry del registro STATUS
rrcf CRCH,F ;rota CRCH hacia la derecha
btfsc STATUS,C ;comprueba si ha habido acarreo al rotar CRCH
bsf CRCL,7 ;si es si,poner a 1 el bit alto de CRCL
;btfss STATUS,C ;comprueba si ha habido acarreo al rotar CRCH
;bcf CRCH,7 ;si no ha habido acarreo,poner a 1 el bit alto de CRCH
return ;retorna
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< SUMA DEL VALOR 0XA001 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
SUM movlw 0xA0 ;carga en w el valor 0xA0
xorwf CRCH,F ;hacer xor con CRCH
movlw 0x01 ;carga en w el valor 0x01
xorwf CRCL,F ;hacer xor con CRCL
return ;return
segun he visto en algunos documentos.hay dos formas de realizar la comprobacion del CRC.una seria la que he desarroyado.
haciendo el calculo insitu.
y otra seria cogiendo los valores de una tabla.segun dicen los documentos,la opcion de las tablas es mas rapida pero ocupa mas espacio
de rom.
y en la gestion de una trama recibida,la velocidad es un tema bastante importante segun el dispositivo que ballamos a controlar.
por el contrario si la velocidad en la gestion de nuestro dispositivo no es importante.podriamos implementar nuesro codigo
en un chip mas varato.
todo depende de para que lo vayamos a utilizar.
en todo caso primero voy a probar con este codigo.y si veo que es muy lento para mis propositos,tendre que optar por el sistema de
tablas.
como dige anteriormente me falta identificar el ultimo valor a gestionar de la ram.podria poner un caracter de control.pero esto no sirve
porque los valores con los que trabajamos estan todos incluidos.
tambien podria ir buscando el CRC.ya que esta al final de la trama a analizar.pero tampoco puedo porque no sabria en que parte
se encuentra.y me he dado cuenta de que los CRC originales habeces coinciden durante la generacion del CRC a comprobar.
lo ideal es aprovechar el dato de direccion y numero de bytes a enviar de la trama a gestionar.
que estan hubiadas en los 2º,3º y 4º,5º de la trama.
pero aqui se nos presenta otro problema.y es que no todos los codigos de funcion del protocolo MODBUS indican estos valores.
solo se me ocurre discriminar el codigo de funcion y optar en consecuencia.
si alguien tiene otra idea le agradeceria su ayuda.
-
y aqui pongo en programa mejorado:
;Libreria para el calculo y comprobacion del CRC de una tabla de datos ubicada a partir de
;la direccion 0x100h de la ram del pic.
;
;Al llamar a este programa,los datos de la ram son analizados byte a byte.y cuando se leen todos los datos-
;incluidos los dos ultimos bytes (CRC) se comprueva si los CRC recividos,son iguales a los CRC calculados.
;Si los datos recibidos y los calculados son iguales.el bit 1 del registro FLAGS_CRC.indicara si los datos
;son validos o no.siendo valor logico 1=datos correctos y 0=no correctos.
;
;********************************* Ejemplo de codigo a poner en programa principal *********************
; TRAMA_NOK
;SD BTFSC FLAGS_CRC,1
; NOP ;aqui saltaria cuando la trama fuera correcta
; GOTO SD
;
;*******************************************************************************************************
CBLOCK CRC_VAR
TEMP_CRCL ;primer valor CRC calculado.
TEMP_CRCH ;segundo valor CRC calculado
CRCL ;primer valor CRC calculado.
CRCH ;segundo valor CRC calculado
CONT_CRC ;contador de CRC (totales)
CONT_CRC2 ;contador de 8 contages
CONT_CRC3 ;contador de CRCs producidos
TEMP_FSR0L ;temporal de indice de ram
TEMP_FSR_ANT ;primer valor CRC recivido.
TEMP_FSR_POST ;segundo valor CRC recivido.
TEST ;registro para testado cruzado de CRCs
FLAGS_CRC ;registro de banderas
ENDC
; Definiciones a poner en el programa principal
; #define CARRY_ON bsf FLAGS_CRC,0
; #define CARRY_OFF bcf FLAGS_CRC,0
; #define TRAMA_OK bsf FLAGS_CRC,1
; #define TRAMA_NOK bcf FLAGS_CRC,1
;CRC_VAR EQU 0X50 o la direccion que queramos para introcir los registros
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CALCULO CRC >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
CRC clrf CONT_CRC ;borra contador de rotaciones
clrf CONT_CRC2 ;borra contador de datos analizados
clrf CONT_CRC3 ;borra contador de CRCs producidos
setf CRCH ;pon a 1 todos los bits del registro alto,cotenedor de CRCs (inicializacion)
setf CRCL ;pon a 1 todos los bits del registro bajo,cotenedor de CRCs (inicializacion)
movlw 0X01 ;valor de direccion del banco 1 de la flash
movwf FSR1H ;selecciona el banco 1 de la eeprom de programa.
clrf FSR1L ;selecciona primera direccion a leer de la ram. (direccion 0100h de la eeprom de programa)
CRC1 movff CRCH,TEMP_CRCH ;intercambia registros principales a temporales.
movff CRCL,TEMP_CRCL ;intercambia registros principales a temporales.
incf CONT_CRC3 ;incrementa contador de CRCs producidos
movf TEMP_FSR0L,W ;carga en w la cantidad de bytes que contiene la trama
xorwf CONT_CRC3,W ;comprueba si coinciden los valores
btfsc STATUS,Z ;si coinciden,
return ;retorna
;separar los nibles de un registro para introducirlos en el nible bajo de otros dos registros.
movff INDF1,CRCH ;introduce en CRCH valor leido de la ram.
movff INDF1,CRCL ;introduce en CRCH valor leido de la ram.
swapf CRCH,F ;invierte los nibles de CRCH.
movlw 0X0F ;valor para conservar el nible bajo.
andwf CRCH,F ;borra el nible alto.
incf FSR1L ;incrementa indice de direccionamiento de la ram
movf TEMP_CRCH,W ;mueve a W el valor alto del valor leido de la ram
xorwf CRCH,F ;hacer xor con el dato anterior (primera operacion de conversion CRC)
movf TEMP_CRCL,W ;mueve a W el valor bajo del valor leido de la ram
xorwf CRCL,F ;hacer xor con el dato anterior (primera operacion de conversion CRC)
;conversiones por rotacion.
CRC2 incf CONT_CRC ;incrementa contador de CRC (totales)
incf CONT_CRC2 ;incrementa contador de 8 contages
rrcf CRCL,F ;rota CRCL hacia la derecha.
btfsc STATUS,C ;comprueba si ha habido acarreo
CARRY_ON ;si es asi,activa flag de carry.
bcf STATUS,C ;borra flag carry del registro STATUS
rrcf CRCH,F ;rota CRCH hacia la derecha
btfsc STATUS,C ;comprueba si ha habido acarreo al rotar CRCH
bsf CRCL,7 ;si es si,poner a 1 el bit alto de CRCL
;btfss STATUS,C ;comprueba si ha habido acarreo al rotar CRCH
;bcf CRCH,7 ;si no ha habido acarreo,poner a 1 el bit alto de CRCH
btfsc FLAGS_CRC,0 ;comprueba si ha habido acarreo en la rotacion.
call SUM ;llamada a rutina de operacion xor 0xA001 si ha habido acarreo.
CARRY_OFF ;borra flag carry
movlw 0X08 ;valor del contage de movimientos de rotacion
xorwf CONT_CRC2,w ;comprueba si ha llegado al valor anterior
bnz CRC2 ;si no es asi realiza otra rotacion
clrf CONT_CRC2 ;en caso contrario reinicia el contador
goto CRC1 ;vuelve a por el siguiente valor en ram a convertir.
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< COMP_CRC >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; compara entre CRC recibido y CRC calculado
COMP_CRC clrf TEST ;borra registro de testado
movf TEMP_CRCH,W ;carga en W el contenido del registro que contiene el primer CRC calculado
cpfseq TEMP_FSR_ANT ;compara si los valores son iguales
incf TEST,F ;incrementa TEST si los valores son diferentes
cpfseq TEMP_FSR_POST ;compara si los valores son iguales al CRC capturado
incf TEST,F ;incrementa TEST si los valores son diferentes
movlw 0x01 ;valor para unica coincidencia detectada
cpfseq TEST ;comparala con registro de testado
return ;si los valores no coinciden retorna
clrf TEST ;borra registro de testado
movf TEMP_CRCL,W ;carga en W el contenido del registro que contiene el primer CRC calculado
cpfseq TEMP_FSR_ANT ;compara si los valores son iguales
incf TEST,F ;incrementa TEST si los valores son diferentes
cpfseq TEMP_FSR_POST ;compara si los valores son iguales al CRC capturado
incf TEST,F ;incrementa TEST si los valores son diferentes
movlw 0x01 ;valor para unica coincidencia detectada
xorwf TEST,W ;comparala con registro de testado
btfsc STATUS,Z ;si los valores coinciden
TRAMA_OK ;activa flag de trama correcta
return ;en caso contrario retorna
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< SUMA DEL VALOR 0XA001 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
SUM movlw 0xA0 ;carga en w el valor 0xA0
xorwf CRCH,F ;hacer xor con CRCH
movlw 0x01 ;carga en w el valor 0x01
xorwf CRCL,F ;hacer xor con CRCL
return ;return
-
hola de nuevo.resulta que se acaba de presentr un problema con esto de la comprovacion CRC de las tramas.
el programa que he realizado arriva parece ser que funciona bien.pero me ocurre algo raro cuando analizo tramas de 8 bytes de longitud.
esto me pasa en el ejemplo MODBUS del proteus.si analizo tramas de 7 bytes o menos,el isis me las acepta.pero a partir de 8 bytes en adelante.
el CRC de las tramas que se envian entre maestro y esclavo,no corresponden a los calculos de mi programa.
por ejemplo:
la trama 01 04 04 00 00 00 00 fb 84 funciona en el isis.y si analizo esta trama con el programa que he hecho.los datos 01 04 04 00 00 00 00 me da un CRC fb84.
que es correctamente el que le pertenece a la trama.
por contra:
la trama 01 04 00 00 00 00 00 00 60 93 que es la que me da el isis. y funciona entre maestro y esclavo, en mi programa me da un CRC 07c4
segun he visto en algunos manuales de MODBUS.este es un CRC16 y usa un polynominal 0xA001.
no estoy muy seguro si el ejemplo del isis utiliza este polynominal.pero si no lo usa seria imposible que los CRC coincidieran los primeros 7 bytes y no apartir del 8 byte.
en todo caso si nadie sabe si el problema es del isis.alguien me podria indicar una aplicacion para el calculo CRC16 con el polynominal 0XA001 ?
gracias.
-
0xA101 o 0xA001? Cuidado con eso....
Algoritmos para calcular CRC5 CRC7 CRC8 CRC16 CRC24 CRC32 (http://www.todopic.com.ar/foros/index.php?topic=25627.msg209548#msg209548)
-
perdon me he equivocado en la respuesta anterior.el que estoy utilizando es 0xA001.esta en la linea SUM del programa que he subido.
he mirado tu enlace.y es muy interesante.lastima que algunas imagenes ya no esten.de todas formas este tema es algo bastante complicado.y no lo digo
por el sistema de calculo.si no porque el calculo es tan tedioso que no es posible hacerlo a mano si no quieres estar eternamente haciendo calculos.
lo que se es que con solo un bit que nos equivoquemos.los CRC de salida nos saldrian errorneos.entonces.porque a mi me salen bien los calculos comparandolos con el ejemplo del isis hasta el byte 7? y no apartir de ahi?
mi problema es saber si mi programa esta bien hecho.y queria compararlo con algun programa fiable.pero es que los que he visto por la web.no me calculan vien
o no se si los estoy usando mal.
no tendrias algo que no estubiera en C.? he visto una aplicacion para android.pero por mas que meto datos.estos no salen como debieran.
este es el enlace. https://play.google.com/store/apps/details?id=an.CrcCal&hl=es_419
-
por fin. :-/ :-/ :-/ un dia para encontrar un programa que funcione.
aqui: http://www.lammertbies.nl/comm/info/crc-calculation.html
calcula el CRC de diferentes sistemas.yo pensaba que el CRC16 solo habia un tipo. y no es asi.menosmal que aqui tambien funciona con el polinomio 0xA001
que es el que usa MODBUS.
asi que he hecho los calculos y resulta que mi programa si funciona.al final el CRC de la trama 01040000000000006093 es 0x074 y no 0x6093
como aparece en la trama.
no se que problema habra en el isis.tendre que profundizar haber si doy en el clavo.
-
:5] :5] :5] mea culpa :5] :5] :5]
media semana perdida.el error era mio no del isis.la trama no era la 010400000000006093 sino 0104060000000000006093.
se me olvido poner el deto 06.ahora si me funciona. :lol:
gracias por todo.ya he modificado los errores de las respuestas anteriores.y he quitado un par de lineas que no hacian falta de mi programa.
por cierto.cuando posteo el codigo,salen unos cuadraditos que desfaratan toda la leyenda.se que es por culpa del break space.por eso puse espacios en
el primer codigo.pero es muy tedioso intercambiar los break por espacios.
hay alguna forma de eliminar esos cuadraditos?
-
Hola.
Pues creo que no hay, al menos no en el foro. Habria que filtrarlo con una aplicación antes de postearlo...
En el enlace que te pase, si descargas el archivo verías que las subrutinas para calculo de CRC estan tanto en C como en ASM...
Me alegro que haya funcionado...
Saludos.
-
gracias.no me di cuenta del enlace.parece que tu codigo es mas compacto que el mio.he intentado adaptarlo al mio.pero entran en cuenta otros valores
del programa principal y no quiero entretenerme mas con mi proyecto.
de todas formas tendria que adaptarle alguna rutina para la lectura de la trama completa.tendria que comprobar si es mas rapido.me interesa la rapidez en la gestion de las tramas.
-
hay un error en las rutinas anteriores.aqui pongo el programa corregido:
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CALCULO CRC >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
CRC clrf CONT_CRC ;borra contador de rotaciones
clrf CONT_CRC2 ;borra contador de datos analizados
clrf CONT_CRC3 ;borra contador de CRCs producidos
setf CRCH ;pon a 1 todos los bits del registro alto,cotenedor de CRCs (inicializacion)
setf CRCL ;pon a 1 todos los bits del registro bajo,cotenedor de CRCs (inicializacion)
movlw 0X06 ;valor de direccion del banco 6 de la flash
movwf FSR1H ;selecciona el banco 1 de la eeprom de programa.
clrf FSR1L ;selecciona primera direccion a leer de la ram. (direccion 0600h de la eeprom de programa)
CRC1 movff CRCH,TEMP_CRCH ;intercambia registros principales a temporales.
movff CRCL,TEMP_CRCL ;intercambia registros principales a temporales.
incf CONT_CRC3,f ;incrementa contador de CRCs producidos
movf N_BYTES,W ;carga en w la cantidad de bytes que contiene la trama
xorwf CONT_CRC3,W ;comprueba si coinciden los valores
btfsc STATUS,Z ;si coinciden,
return ;retorna
;separar los nibles de un registro para introducirlos en el nible bajo de otros dos registros.
movff INDF1,CRCL ;introduce en CRCH valor leido de la ram.
clrf CRCH ;poner a cero el registro CRCH.
incf FSR1L,f ;incrementa indice de direccionamiento de la ram
movf TEMP_CRCH,W ;mueve a W el valor alto del valor leido de la ram
xorwf CRCH,F ;hacer xor con el dato anterior (primera operacion de conversion CRC)
movf TEMP_CRCL,W ;mueve a W el valor bajo del valor leido de la ram
xorwf CRCL,F ;hacer xor con el dato anterior (primera operacion de conversion CRC)
;conversiones por rotacion.
CRC2 incf CONT_CRC,f ;incrementa contador de CRC (totales)
incf CONT_CRC2,f ;incrementa contador de 8 contages
rrcf CRCL,F ;rota CRCL hacia la derecha.
btfsc STATUS,C ;comprueba si ha habido acarreo
CARRY_ON ;si es asi,activa flag de carry.
bcf STATUS,C ;borra flag carry del registro STATUS
rrcf CRCH,F ;rota CRCH hacia la derecha
btfsc STATUS,C ;comprueba si ha habido acarreo al rotar CRCH
bsf CRCL,7 ;si es si,poner a 1 el bit alto de CRCL
btfss STATUS,C ;comprueba si ha habido acarreo al rotar CRCH
bcf CRCH,7 ;si no ha habido acarreo,poner a 0 el bit alto de CRCH
btfsc FLAGS_CRC,0 ;comprueba si ha habido acarreo en la rotacion.
call SUM ;llamada a rutina de operacion xor 0xA001 si ha habido acarreo.
CARRY_OFF ;borra flag carry
movlw 0X08 ;valor del contage de movimientos de rotacion
xorwf CONT_CRC2,w ;comprueba si ha llegado al valor anterior
bnz CRC2 ;si no es asi realiza otra rotacion
clrf CONT_CRC2 ;en caso contrario reinicia el contador
goto CRC1 ;vuelve a por el siguiente valor en ram a convertir.
-
hola.hace ya tiempo hize la anterior rutina pensando en la cantidad de memoria y no en la velocidad del pic.pero ahora que estoy con el 18F87k22
memoria me sobra.pero requiero mas velocidad.y aunque estoy trabajando a 64Mhz,quiero sacarle el maximo rendimiento al pic.
por eso pongo esta rutina pra el calculo del CRC con polinomio 0xA001 con tablas.
la trama a gestionar se pondria a partir de la direccion 0x600.los registros de proposito general en el banco 7.
el numero de bytes de la trama en N_BYTES.
el resultado sera hubicado en los registros CRCL y CRCH.
espero les sea de utilidad.
#define TABLA_CRCsH 0x5000 ;direccion apartir de donde se metera la tabla alta para el calculo del CRC y rutina de redondeo
#define TABLA_CRCsL 0x5200 ;direccion apartir de donde se metera la tabla alta para el calculo del CRC y rutina de redondeo
;************************************************************** CRC **************************************************
;Calculo del crc por el sistema de tabla.
CRC GENERAL_BANK ;banco de registros de trabajo 0x07 en este caso
setf TEMP_CRCH ;inicializa registros para la generacion del CRC
setf TEMP_CRCL ;inicializa registros para la generacion del CRC
decf N_BYTES,F ;resta uno al contador de rotaciones.
movlw 0X06 ;banco de recepcion de trama
movwf FSR1H ;selecciona el banco de la eeprom de programa.
clrf FSR1L ;inicializa direccionamiento indirecto
next_crc movff INDF1,CRCL ;lee el valor de la trama recibida y lo cargas en registro de CRC bajo
movff TEMP_CRCL,INDEX ;carga valor temporal de CRC alto en indice de tabla
movf CRCL,W ;carga en W el contenido del CRC bajo
xorwf INDEX,F ;hacer xor con CRCL y caga indice de tabla en INDEX
movff INDEX,TBLPTRL ;direcciona tabla
movlw HIGH TABLA_CRCsH;direccion alta de tabla
movwf TBLPTRH ;cargalo en registro
call CRC16 ;busca dato en la tabla alta
xorwf TEMP_CRCH,W ;operacion xor de W con el valor leido de la tabla
movwf TEMP_CRCL ;introduce el resultado en el registro temporal del CRC bajo
movff INDEX,TBLPTRL ;direcciona tabla
movlw HIGH TABLA_CRCsL;direccion baja de tabla
movwf TBLPTRH
call CRC16 ;busca dato en la tabla baja
movwf TEMP_CRCH ;inroduce dato seleccionado de la tabla en el registro temporal CRC alto
incf FSR1L,F ;incementa indice de ram
movf N_BYTES,W ;carga en w la cantidad de bytes que contiene la trama
cpfseq FSR1L
goto next_crc ;siguente byte a leer
movff TEMP_CRCH,CRCH ;actualiza registros
movff TEMP_CRCL,CRCL ;actualiza registros
return ;return
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CRC16 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
CRC16 clrf WREG ;dato 0x00
xorwf TBLPTRL,w ;comprueba si el dato indexado es igual a 0x00
btfsc STATUS,Z ;si es asi,
goto TABLA_CRC16 ;salta a tabla para leer el primer valor "0"
bcf STATUS,C ;borra el carry
rlcf TBLPTRL,F ;multiplica por 2
bnc TABLA_CRC16 ;salta a tabla si el valor indexado esta en los primeros 256bytes.en caso contrario,
incf TBLPTRH ,f ;incrementa puntero alto de tabla
TABLA_CRC16 tblrd*+ ;incrementa puntero de tabla antes de su lectura
movf TABLAT,W ;carga el valor leido de la tabla en W
return
ORG TABLA_CRCsH ;0x5000
dt 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81
dt 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0
dt 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01
dt 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41
dt 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81
dt 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0
dt 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01
dt 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
dt 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81
dt 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0
dt 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01
dt 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41
dt 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81
dt 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0
dt 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01
dt 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41
dt 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81
dt 0x40
ORG TABLA_CRCsL ;0x5200
dt 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4
dt 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09
dt 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD
dt 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3
dt 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7
dt 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A
dt 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE
dt 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26
dt 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2
dt 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F
dt 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB
dt 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5
dt 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91
dt 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C
dt 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88
dt 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C
dt 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80
dt 0x40
-
Interesante, entre uno de mis proyectos pendientes esta la decodificacion de tramas de RDS, y muy seguramente esto me ayude..... asi que :
Gracias.
_______________________________________________________________________________________________________________________________
Mi Blog
https://misterelectronico.wordpress.com/entranador-fabricacion-casera/ (https://misterelectronico.wordpress.com/entranador-fabricacion-casera/)
-
yo no se si RDS utiliza el polinomio 0xA001 para el CRC.tampoco se si este polinomio no es exclusivo solo para MODBUS.pero para RDS? :shock:
-
Perdon groundman por responder un poco tarde, pero es que ultimamente ando un poco liado.
Mas bien que se ajuste o no la tu programa a la decodificacion de la trama de RDS, no mi importa tanto lo que me interesa es el proceso que haces para trabajar con el polinomio.
La forma en que comprueba el error con el decodificador de RDS sigue siendo un tanto oscura para mi.
El RDS se envia en bloques de 26 bits, 16 - 10 bits , 16 bits son de datos y 10 correscomponden a la correccion de errores.
En el enlace que justo me acabo de encontrar y que no encontre en su dia el siguiente pdf :
http://www.google.es/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CDIQFjAA&url=http%3A%2F%2Fwww.eecs.qmul.ac.uk%2F~hamed%2Fpapers%2FRDSencoder.pdf&ei=NG7oVML9EYL7UKiLgogO&usg=AFQjCNFpgK8u784LFseyQEzH62Uf6K-S4Q&bvm=bv.86475890,d.d24 (http://www.google.es/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CDIQFjAA&url=http%3A%2F%2Fwww.eecs.qmul.ac.uk%2F~hamed%2Fpapers%2FRDSencoder.pdf&ei=NG7oVML9EYL7UKiLgogO&usg=AFQjCNFpgK8u784LFseyQEzH62Uf6K-S4Q&bvm=bv.86475890,d.d24)
En las paginas 12 y 13 lo explica un poco aunque esta un poco confuso para mi.
Aunque mas adelante pone un ejemplo de como hacerlo, y bueno vere de estudiarlo cuando retome el asunto.
Yo adapte un TDA7330B a una radio y saque las tramas y hize un programa en C para adecuarlas, pero al final me canse y lo deje, pero me gustaria retomarlo y montarle un microcontrolador, al ver tu post me recordo esto.
Un saludo groundmand.
______________________________________________________________________________________________________________________________
Mi Blog
https://misterelectronico.wordpress.com/entranador-fabricacion-casera/ (https://misterelectronico.wordpress.com/entranador-fabricacion-casera/)
-
valla.esta interesante.a mi siempre me han gustado los retos.cuando me hizo falta calcular el CRC del modbus. tuve que hacerlo a mano.no pude encontrar
ningun codigo ya realizado.pero me ayudo los ejemplos de calculo.como los que pone en los pdf que as puesto.pero es tedioso y complicado.
ya hace tiempo que realize ese programa.pero el de las tablas estaba en C y no lo entendia.pero ya que estudie un poco de java.pues me hizo a la idea
si creas un programa de estas caracteristicas sin tablas.puedes crear tus tablas apartir de los valores generados.porque es posible que no encuentres las tablas
para la comprobacion del CRC de las tramas del RDS.
espero que tengas suerte y encuentres algun ejemplo con tablas.es mas facil que generar el CRC sin tablas.
-
Bueno la verdad es que muchas veces lo interesante y que realmente realiza es crear tu propio codigo:
Mirando en las notas de aplicacion de microchip para otra cosa enconter justo esto:
CRC Generating and Checking - Microchip (http://www.google.es/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CCkQFjAA&url=http%3A%2F%2Fww1.microchip.com%2Fdownloads%2Fen%2FAppNotes%2F00730a.pdf&ei=T-7oVOedLobiaujQgPgP&usg=AFQjCNF6Sv-tsNff6MCIHufNX4bf9nrYyA&bvm=bv.86475890,d.d2s)
Y tambien esto:
AN1148, Cyclic Redundancy Check (CRC) - Microchip (http://www.google.es/url?sa=t&rct=j&q=&esrc=s&source=web&cd=2&ved=0CDMQFjAB&url=http%3A%2F%2Fww1.microchip.com%2Fdownloads%2Fen%2FAppNotes%2F01148a.pdf&ei=T-7oVOedLobiaujQgPgP&usg=AFQjCNGI329dVHFwhu0i_-2u40srYghoYw&bvm=bv.86475890,d.d2s)
Bueno ya vere cuando me pongo con esto por ahora tengo otros proyectos en mente.
Saludos groundmand
-
es verdad que en ese datasheet hay un calculo CRC.pero se refiere a un CRC-16 con polinomio 0x8005 P(x) = x16+x15+x2+1
el del MODBUS es 0xA001 P(x) =x15+x13+1
pero sabes que polinomio usa el RDS? estas seguro que es el 0x8005 ?
-
Perdona groundman me desconecte del tema y es que ultimamente estoy bastante liado entre el trabajo y otras cosas:
En RDS cada bloque se transmite es de 26 bits
16 bits datos + 10 bits CRC
Los 10 bits de CR se obtienen del polinomio G(x) = x^10 + x^8 + x^7 + x^5 + x^4 + x^3 + 1
Como lo hace todavia no lo tengo claro, cuando retome el tema lo mirare mas correctamente si bien es verdad que cuando yo lo quise hacer no encontraba informacion al respecto en ese momento, pero ahora ya hay paginas que ponen hasta el programa ya echo.
Este documento de la universidad de Londres me parece muy bueno y trae el programa para hacerlo.
RDS UNIVERSITY COLLEGE LONDON (http://www.google.es/url?sa=t&rct=j&q=&esrc=s&source=web&cd=2&ved=0CCsQFjAB&url=http%3A%2F%2Fwww.eecs.qmul.ac.uk%2F~hamed%2Fpapers%2FRDSencoder.pdf&ei=wBT2VIrPB4nzUtXQgZgP&usg=AFQjCNFpgK8u784LFseyQEzH62Uf6K-S4Q&bvm=bv.87519884,bs.1,d.ZWU)
Y la verdad es que no me voy a comer el coco y cuando lo tenga que hacer lo copio tal cual.
Esta pagina en aleman tiene un programa que tambien lo hace:
RDS (http://www.mikrocontroller.net/topic/330060)
Habia un italiano por ahi controlaba equipos atraves del RDS, puede ser interesante en aplicaciones como obtener la hora, geolocalizacion etc...
Al igual que tu me parece muy interesante hacerse uno mismo los propios programas por que la verdad es que es la forma de disfrutar de esto, pero en este caso no me comere el coco, por que este tema es muy especifico y luego mas tarde tampoco va a tener mucha mas aplicacion en otras cosas.
Un placer charlar contigo groundman .... nos vemos.
______________________________________________________________________________________________________________________
Mi Blog
https://misterelectronico.wordpress.com/entranador-fabricacion-casera/ (https://misterelectronico.wordpress.com/entranador-fabricacion-casera/)
-
es verdad que en ese datasheet hay un calculo CRC.pero se refiere a un CRC-16 con polinomio 0x8005 P(x) = x16+x15+x2+1
el del MODBUS es 0xA001 P(x) =x15+x13+1
pero sabes que polinomio usa el RDS? estas seguro que es el 0x8005 ?
Esto es un poquito viejo, pero me meto ya que quedo ahi nomas
el MODBUS usa 0xA001 como tambien 0x8005, lo que difiere es como se lo transcribe
Reversed: 0xA001 = 1010 0000 0000 0001
Normal: 0x8005 = 1000 0000 0000 0101 <-- miralo de aca
El reversed comienza contando desde x^0 en adelante, mientras que el normal desde el x^15
En otras notaciones algunos omiten el polinomio de mayor tamaño y otros omiten el de menor tamaño, ya que siempre son 1.
-
tienes razon KILLERJC.hace tiempo vi lo de reverse.pero no sabia exactamente lo que queria decir.tampoco se para que sirve elegir entre uno u otro si al final
se obtiene el mismo resultado.o quizas no. :?
-
Como dije son notaciones... son el mismo numero nomas que escrito de otra forma.
Y por ahi como dije algunos autores omiten el bit mas significante o el menos significante ya que estos son siempre 1 (cada loco con su tema xD)