bassam sandoussi hadik equipo de diagnÓstico para...

218
Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA VEHÍCULOS (OBD-II) TRABAJO DE FIN DE GRADO Esteban del Castillo Pérez Ingenieria electrónica industrial y automática Tarragona 2019

Upload: others

Post on 01-Sep-2020

1 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Bassam Sandoussi Hadik

EQUIPO DE DIAGNÓSTICO PARA VEHÍCULOS (OBD-II)

TRABAJO DE FIN DE GRADO

Esteban del Castillo Pérez

Ingenieria electrónica industrial y automática

Tarragona

2019

Page 2: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

1

Page 3: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

2

ÍNDICE

1. Introducción al proyecto .............................................................................................................. 4

1.1 Objetivo ............................................................................................................................. 4

1.2 Motivación ........................................................................................................................ 4

2. Introducción al sistema OBD2 .................................................................................................... 5

2.1 Historia de la electrónica en el automóvil ............................................................................ 5

2.2 ¿Que es el sistema OBD2? ..................................................................................................... 9

2.3 Historia del sistema OBD2 .................................................................................................... 9

3. El sistema OBD2 ......................................................................................................................... 12

3.1 Protocolos del sistema OBD2 .............................................................................................. 12

3.1.1 SAE J1850 PWM ............................................................................................................ 13

3.1.2 SAE J1850 VPW ............................................................................................................. 17

3.1.3 ISO 9141-2 ...................................................................................................................... 20

3.1.4 ISO 14230 ....................................................................................................................... 26

3.1.5 ISO 15765-1 .................................................................................................................... 28

3.2 Servicios del sistema OBD2 ................................................................................................. 40

4. Desarrollo del hardware ............................................................................................................ 48

4.1 Interfaz hardware del ISO 9141-2 ...................................................................................... 48

4.1.1 Uso de la UART .............................................................................................................. 48

4.1.2 El MC33290 .................................................................................................................... 50

4.1.3 Circuito de la interfaz ..................................................................................................... 53

4.2 Interfaz hardware del ISO 15765-4 .................................................................................... 54

4.2.1 EL MCP2515 .................................................................................................................. 54

4.2.2 Circuito de la interfaz del ISO 15765-4 ......................................................................... 68

4.3 Interfaz hardware entre el microcontrolador y el ordenador .......................................... 69

4.3.1 Descripción de la interfaz ............................................................................................... 69

4.3.2 Circuito de la interfaz ..................................................................................................... 70

4.4 El microcontrolador PIC18F4550 ....................................................................................... 71

4.4.1 Componentes externos del PIC18f4550 ......................................................................... 72

4.4.2 Configuración del oscilador ........................................................................................... 73

4.4.3 Periféricos del microcontrolador ................................................................................... 76

4.4.4 Circuito del microcontrolador ........................................................................................ 85

4.5 Circuito de alimentación ...................................................................................................... 85

4.5.1 Módulo Mini-360 ............................................................................................................ 85

Page 4: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

3

4.5.2 Circuito del módulo ........................................................................................................ 86

4.6 Circuito completo ................................................................................................................. 87

5. Protocolo de comunicación entre el dispositivo OBD2 y el ordenador .................................. 90

6. Desarrollo del software .............................................................................................................. 95

6.1 Objetivo del software ........................................................................................................... 95

6.2 Proceso de desarrollo del software................................................................................ 96

6.3 Descripción del software ................................................................................................ 98

6.3.1 Funciones generales ....................................................................................................... 99

6.3.2 Funciones del ISO 9141-2 ........................................................................................... 101

6.3.3 Funciones del ISO15765-4 .......................................................................................... 107

6.3.4 Funciones main() y initProtocol() ............................................................................... 115

7. Aplicación de escritorio ........................................................................................................... 117

7.1 Desarrollo de la aplicación ................................................................................................ 117

7.2 Descripción de la aplicación .............................................................................................. 120

8. Construcción y test del prototipo ............................................................................................ 130

8.1 Construcción del prototipo ................................................................................................ 130

8.2 Test del prototipo ............................................................................................................... 130

9. Conclusiones ............................................................................................................................. 140

10. Webgrafía ................................................................................................................................ 142

11. ANEXO 1: Código del microcontrolador PIC18F4550 ...................................................... 143

12. ANEXO 2: Código de la aplicación de escritorio ................................................................ 190

Page 5: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Introducción al proyecto

4

1. Introducción al proyecto

1.1 Objetivo

Son dos los objetivos principales de este proyecto. De una parte, desarrollar un dispositivo

capaz de establecer una comunicación con el sistema OBD2 de un vehículo. De otra,

desarrollar una aplicación software capaz de hacer uso de manera eficiente y amigable de

esa comunicación. El propósito último es facilitar a un usuario no experto la interacción con

el sistema de control de un vehículo. Para poder cumplir estos objetivos se deberán

desarrollar los siguientes puntos:

• Entender la evolución de la electrónica en los automóviles desde sus inicios hasta el

día de hoy.

• Estudiar en profundidad el sistema OBD2.

• Obtener y estudiar la información necesaria para poder implantar los distintos

protocolos con los que se puede comunicar con el sistema OBD2 de un vehículo.

• Diseñar el hardware y el software para implementar los protocolos ISO 9141-2 y ISO

15765-1.

• Diseñar la aplicación de escritorio que permita interactuar de forma amigable con el

sistema OBD2 del vehículo.

1.2 Motivación

Actualmente vivimos en un mundo donde la tecnología se esta expandiendo en todos los

aspectos de nuestra vida. Un claro ejemplo son los vehículos que utilizamos en nuestro día

a día. Desde hace unas décadas observamos la tendencia de añadir cada vez más sistemas

electrónicos dentro de la arquitectura de los automóviles; esto ha permitido mejorar la

seguridad, la eficiencia y el confort. Dentro de estos sistemas se encuentran los encargados

de reducir las emisiones del vehículo y mantenerlas por debajo de los límites legales. Para

poder asegurar el correcto funcionamiento de los sistemas antipolución, los ingenieros

diseñaron el sistema OBD2 el cual permitia monitorizarlos y gobernarlos en cualquier

momento.

Aunque pocos sepan de la existencia de este sistema, los conductores interactuamos con el

frecuentemente ya que es este el que nos avisa cuando hay una avería.

Ante la gran importancia del OBD2 dentro de la industria del automóvil, surge el interés

personal en profundizar en el conocimiento del sistema OBD2 y por esta razón, he decidido

realizar este proyecto.

Page 6: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Introducción al sistema OBD2

5

2. Introducción al sistema OBD2

2.1 Historia de la electrónica en el automóvil

Si nos fijamos en cómo han evolucionado los automóviles desde su primera aparición

observamos grandes diferencias en general. Pero es en un aspecto muy concreto del

automóvil donde se destaca notablemente esta evolución, este es la incorporación de

sistemas electrónicos.

Figura 1: Interior de un coche de los años 60.

Figura 2: Interior de un coche actual.

Con el paso de los años se ha ido incrementando la importancia de los sistemas electrónicos

en los coches. La tendencia inicial en este proceso de cambio era la de sustituir los sistemas

mecánicos presentes en el coche por sistemas electrónicos. Esto ha permitido numerosos

beneficios tanto por parte de los fabricantes como para el consumidor final. Estos cambios

podían simplemente sustituir interruptores mecánicos por transistores. Un ejemplo de estos

cambios seria la sustitución del encendido por ruptor por un encendido con transistores. Este

Page 7: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Introducción al sistema OBD2

6

simple cambio mejoró la fiabilidad de este sistema ya que los interruptores mecánicos

estaban sometidos a altas tensiones que producían arcos y por lo tanto, con el tiempo los

interruptores se dañaban por la erosión y dejaban de funcionar. Este es solo un ejemplo de

los beneficios que ha aportado la inclusión de sistemas electrónicos en los coches.

La incorporación de la electrónica en los coches empezó a principios de los años 70, época

en la que la electrónica en sí no estaba tan desarrollada como la conocemos actualmente. Por

eso, al principio de la electrónica en el automóvil observamos sistemas electrónicos simples,

como el comentado anteriormente. Además, los costes de fabricación de los componentes

electrónicos eran elevados por lo que solo los coches de gamma alta llevaban incorporados

estos sistemas.

Con la evolución de la electrónica, se abarataron los costes de los componentes electrónicos

y se empezó a introducir más la electrónica en los coches. Por la diferencia de costes, los

fabricantes empezaron a preferir utilizar sistemas electrónicos frente a los tradicionales

sistemas mecánicos con lo que se abarató el preció de los coches. Por lo tanto, podemos decir

que la electrónica ha sido clave para disminuir los precios de los coches y hacerlos más

accesibles para el ciudadano medio.

Pero no ha sido hasta la aparición de la electrónica digital cuando realmente se ha producido

una revolución en la industria del automóvil. La electrónica digital permite diseñar sistemas

de control más complejos que los que permite la electrónica analógica.

Cuando hablamos de sistemas digitales no referimos principalmente al microcontrolador.

Este pequeño dispositivo ha revolucionado casi todos los aspectos de nuestra vida,

incluyendo el coche. Un microcontrolador nos permite tratar unos datos de entrada, que

pueden proceder de sensores, y actuar en base a esos datos sobre unas salidas, como pueden

ser los actuadores. Este dispositivo es programable, es decir, mediante un lenguaje de

programación podemos definir cual debe ser el comportamiento del dispositivo y cómo debe

tratar la información.

Figura 3: Ejemplo de microcontrolador.

Con el avance de los procesos de fabricación de la electrónica digital, la complejidad y

funcionalidad de los microcontroladores ha ido aumentando con el tiempo y esto ha

permitido diseñar y incorporar sistemas electrónicos verdaderamente útiles. El precio de

estos sistemas también ha ido disminuyendo la cual cosa ha supuesto una reducción en el

precio de los vehículos.

Muchos son los sistemas electrónicos que se han ido incorporando a lo largo de los años.

Estos sistemas forman parte de todas y cada una de las partes que conforman el automóvil:

sistema de propulsión, sistemas de seguridad, sistemas de confort…

Un coche moderno puede llevar entre 25 a 35 microcontroladores, y si son de lujo pueden

llevar entre 60 y 120.

Page 8: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Introducción al sistema OBD2

7

A continuación se presenta una lista de los principales sistemas electrónicos presentes

actualmente en los coches:

1. Seguridad

• Antibloqueo de ruedas.

Anti patinaje.

• Control dinámico de la trayectoria.

• Suspensión pilotada.

• Dirección asistida.

• Iluminación de xenón.

• Iluminación dinámica.

• Regulación de la limpieza.

• Indicador de mantenimiento.

• Vigilancia de la presión de los neumáticos. placa-ecu-con-lupa-guanaca

• Airbags y pretensores.

2. Confort

• Regulación adaptativa de la velocidad.

• Climatización automática.

• Memorización del puesto de conducción.

• Control de acceso sin llave.

• Cierre centralizado.

• Automatismo de limpieza e iluminación.

• Ayuda de aparcamiento.

3. Comunicación

• Audio.

• Vídeo.

• Ordenador de a bordo.

• Mandos vocales.

• Telefonía móvil.

• Navegación.

• Pantalla centralizada.

• Visualización en el parabrisas.

4. Grupo moto propulsor

• Gestión motor gasolina con regulación de inyección, encendido, riqueza y

devolución.

• Regulación electrónica diésel con regulación del caudal y del comienzo de inyección.

• Gestión motor diésel con rampa común.

• Gestión electrónica de la caja de velocidades (automática, manual robotizada, por

correa).

• Gestión electrónica de la refrigeración motor.

Page 9: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Introducción al sistema OBD2

8

• Gestión electrónica de la sobrealimentación.

• Motorización híbrida.

En la siguiente figura se muestra el momento en el que aparece cada sistema.

Figura 4: Diagrama temporal de la aparición de los sistemas electrónicos más comunes en

los coches.

Analizando el diagrama anterior se puede observar que a medida que avanza el tiempo

aparecen sistemas más complejos. Esto va acorde con lo comentado anteriormente, los

avances en la electrónica han permitido la aparición de sistemas más complejos.

Es evidente que la electrónica ha mejorado notablemente el mundo del automóvil, de otra

forma su evolución dentro de esta industria no habría sido la misma. Estos sistemas han

mejorado desde la seguridad hasta la comodidad. La electrónica ha permitido implementar

sistemas de seguridad activa (ESP, ABS…) y de seguridad pasiva (Airbag, ) que han hecho

que actualmente la peligrosidad de conducir un coche sea 200 veces menor que en 1960.

Además, con la sustitución del carburador por la inyección electrónica la eficiencia de los

vehículos se ha visto mejorada. Estas son algunas de las mejoras que ha llevado la electrónica

al automóvil.

Page 10: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Introducción al sistema OBD2

9

2.2 ¿Que es el sistema OBD2?

Desde hace unas décadas, la electrónica del automóvil está constituida por un conjunto de

sistemas electrónicos independientes (cada uno con una función) distribuidos por distintas

zonas del coche. Estos sistemas están conectados a través de un bus de comunicaciones

permitiendo así el intercambio de información.

Figura 5: Diagrama del sistema de comunicación interno de un coche.

Como se ha mencionado en el apartado anterior, estos sistemas están basados en un

microcontrolador. Un sistema microcontrolador básico consta de sensores, un

microcontrolador y actuadores. Estos sensores miden una determinada variable y

proporcionan su valor al microcontrolador. Dentro del automóvil, estos sensores suelen ser

de temperatura, de velocidad (angular/lineal), de presión, de luz, de oxigeno, de CO2… Hay

multitud de datos en tiempo real sobre los parámetros que envuelven el conjunto de sistemas

del vehículo. Estos datos son necesarios para que los propios sistemas funcionen

correctamente, y por lo tanto, para que el coche funcione correctamente. Sin embargo, estos

datos también podrían ser útiles para las personas ya que a partir de ellos se puede llegar a

conocer el estado del vehículo, es decir, se puede hacer una diagnosis.

De aquí surge la idea de incorporar un sistema que permita extraer del vehículo esta

información para que así sea tratada y con ella realizar un diagnosis de los distintos sistemas

del coche. Este sistema es el sistema OBD (On board diagnostics) el cual es el precursor del

OBD2.

2.3 Historia del sistema OBD2

Anterior a la incorporación del sistema OBD en los coches los especialistas solo tenían una

forma para detectar y diagnosticar una avería. Los mecánicos utilizaban todos sus sentidos

para averiguar cual era la avería: intentaban escuchar ruidos extraños, percibir olores

extraños etc.

Page 11: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Introducción al sistema OBD2

10

Con el avance de la tecnología, aparecen los indicadores analógicos (medidores) los cuales

permitían obtener algunas mediciones como puede ser la temperatura del motor o la presión

del aceite.

Pero no ha sido hasta la aparición del sistema OBD en el 1968 cuando realmente se podía

detectar y diagnosticar una avería sin la necesidad de abrir el capó del vehículo. El sistema

OBD ha permitido realizar diagnósticos utilizando únicamente los datos obtenidos del

conjunto de sensores integrados en el vehículo.

Con la integración de la electrónica en los vehículos, el número de sensores en un coche se

ha ido incrementando con el tiempo. En la actualidad un vehículo moderno puede llegar a

tener hasta 50 sensores, muchos más si se trata de un coche de lujo. Estos proporcionan a los

propios sistemas del vehículo la información necesaria para poder funcionar. Algunos de

estos sensores son: flujo de aire de entrada (sensores MAF), sensor de concentración de O2

(sonda lambda), sensor de presión de combustible etc.

El sistema OBD tiene acceso a toda esta información, por lo que se ha convertido en un

excelente aliado para el diagnóstico de los vehículos.

El motivo que realmente llevó a la implementación del sistema OBD a tan gran escala, no

ha sido principalmente la facilidad que da para el diagnostico de los vehículos, sino que se

trata de un tema de índole ecológica.

En los años 80, se produjo un despertar de conciencia mundial en torno a los temas

ecológicos y ambientales. La población se empezó a preocupar por la contaminación

ambiental que ocasionaban los vehículos de combustión. Este preocupación se veía

fortalecida por temas como el deterioro de la capa de ozono así como el calentamiento global.

Ante este movimiento social, el gobierno del estado del california (EEUU ) se vio obligado

a implementar una serie de regulaciones que afectaban a las emisiones de los vehículos

fabricados a partir del año 1968. Estas regulaciones se extendieron por todo el país en 1968.

Con el objetivo de asegurar el cumplimiento de estas regulaciones, el congreso aprobó el

Clean Air Act (Acta Anti polución) en 1970 y creo la EPA (Enviromental Protection

Agency). La EPA promovió una serie de estándares en la emisión de gases.

Para asegurar el cumplimiento de estas regulaciones, los fabricantes empezaron a añadir

sistemas de control y reducción de emisiones como puede ser el convertidor catalítico,

introducido en el año 1970. Cuando estos sistemas de control empezaron a incorporar

electrónica, los fabricantes de coches emperezaron a integrar el sistema OBD para poder

monitorear estos sistemas de control y asegurar su correcto funcionamiento. Es esta la razón

principal por la que los vehículos empezaron a integrar el sistema OBD.

Tan necesaria fue la implementación del sistema OBD para asegurar el correcto

funcionamiento de los sistemas de control y reducción de emisiones que un organismo del

gobierno de california (CARB, Californian Air Resources Board) sacó en el los años 80 una

ley que obligaba a los fabricantes a integrar el sistema OBD en sus vehículos.

El sistema OBD no solo permitía monitorear los datos obtenidos de los sensores integrados

en los sistemas de control y reducción de emisiones sino que también realizaba

continuamente un autodiagnóstico a partir de los datos de los sensores. Si el sistema

detectaba que había una magnitud que se salía de su rango normal, lo indicaba a través de

un registro mediante un código de avería (DTC, diagnostic trouble codes). Mediante los

códigos DTC se codificaba la información relacionada con la avería: el sistema donde se ha

producido, el sensor que la ha detectado… Además, cuando el sistema OBD detectaba una

avería, este lo indicaba a través de la luz MIL en el cuadro de instrumentos(Figura 6).

Page 12: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Introducción al sistema OBD2

11

Figura 6: Coche con la luz MIL encendida.

Cuando se producía una avería, el propietario del vehículo se percataba mediante la luz

MIL y llevaba el coche a un taller. El técnico especialista obtenía información especifica

del problema a través del registro de averías y mediante esta información podía llegar a la

pieza averiada para repararla o sustituirla.

Esto permitió, entre otras cosas, asegurar el funcionamiento continuo de los sistemas de

control y reducción de emisiones y por ende, mantener las emisiones por debajo de los

limites que marcaba la ley.

Pero la primera versión del sistema OBD no era todo ventajas, también había ciertos

inconvenientes que eran principalmente fruto de lo poco desarrollada que estaba esta

tecnología entonces. Uno de los inconvenientes es que cada fabricante codificaba las averías

de forma distinta, por lo que los talleres debían conocer los códigos de cada fabricante.

También había un problema con el conector utilizado para acceder al sistema OBD y es que

cada fabricante utilizaba uno distinto. Esto requería a los talleres disponer de una

herramienta de enlace para cada fabricante.

Otro inconveniente es que esta versión del OBD solo monitorizaba algunos sistemas

relacionados con la emisión de gases.

Con el paso de los años, los problemas anteriormente mencionado fueron desapareciendo

gracias a la aparición de distintos estándares. En 1988 la SAE (Society of Automotive

Engineers) definió un conector estándar OBD y un conjunto de códigos de avería.

El sistema OBD-2 empezó a sustituir completamente el OBD cuando la segunda versión

pasó a ser obligada para los vehículos fabricados a partir del 1996.

En el caso de Europa, el OBD-2 se conoció como el EOBD y paso a ser obligatorio a partir

del 2001.

A parte de la ventaja que supone ser un sistema estandarizado, el OBD-2 era mucho más

efectivo que el OBD ya que abarcaba más sistemas y detectaba tanto fallos eléctricos como

químicos o mecánicos.

Page 13: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

12

3. El sistema OBD2

3.1 Protocolos del sistema OBD2

Dentro de la arquitectura de un automóvil actual el sistema OBD2 se comunica con los

distintos sistemas del vehículo, y al mismo tiempo puede establecer una conexión con un

equipo de test externo. En términos simplificados, esta comunicación entre dos puntos

permite lo siguiente:

• El sistema OBD2 puede realizar un autodiagnóstico completo de todos los sistemas

de los cuales dispone información (sistemas con los que se comunica)

• Mediante un equipo externo podemos conectarnos al sistema OBD2 y obtener datos

en tiempo real de todos los sistemas a los que está conectado el OBD2. Además, se

puede ver cualquier avería detectada por la auto diagnosis.

Actualmente el sistema OBD2 que incorporan los fabricantes a sus vehículos no está

limitado a la obtención de datos sino que también permite realizar ajustes para modificar

algunas funcionalidades del vehículo. También permite llevar un determinado sistema al

modo de prueba en el cual se realiza una serie de testeos para comprobar su funcionamiento.

El sistema OBD2 permite incluso acceder a los parámetros del motor y ajustarlos para

modificar el comportamiento del vehículo. Aunque los fabricantes incorporan aplicaciones

propias, lo hacen sin alterar lo esencial de este sistema por lo que se mantiene estandarizado.

Como el objetivo de este proyecto es el diseño de un equipo de test, nos interesa saber cómo

el sistema OBD2 se comunica con los equipos externos, es decir, debemos estudiar los

protocolos involucrados.

No todos los fabricantes utilizan el mismo protocolo en sus vehículos ya que existen distintos

protocolos dentro del estándar. Los protocolos que hay para la comunicación entre el equipo

de test y el sistema OBD2 son los siguientes:

• SAE J1850 PWM

• SAE J1850 VPW

• ISO 9141-2

• ISO 14230-1

• ISO 15765-1

En los siguiente apartados se explicará cada uno de los protocolos siguiendo el modelo

OSI.

Page 14: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

13

3.1.1 SAE J1850 PWM

Este estándar fue definido por la SAE (Sociedad de Ingenieros de Automoción) en 1994.

Actualmente solo es utilizado por la marca Ford por lo que no es un estándar muy común

dentro de la industria del automóvil. Este protocolo permite una tasa de transferencia de

hasta 41,6 Kbps.

3.1.1.1 Capa Física

La capa física de este estándar se rige por el protocolo SAE J1850.

Topología de red

En el estándar SAE J1850 PWM se define un sistema de comunicación multipunto ya que

se pueden conectar varias ECUs (Electronic control units) y el equipo de test externo. Todos

los nodos de este sistema están conectados a un mismo medio a través del cual se comunican,

por lo tanto, la topología de red es BUS.

El siguiente diagrama muestra cómo es la conexión física:

Figura 7: Topología de red tipo BUS.

Medio de transmisión

En este sistema de comunicación los nodos se conectan a 2 hilos que son los que forman el

BUS. Son dos hilos ya que el señal que se transmite es un señal diferencial.

El medio físico de transmisión consiste en un par trenzado.

Codificación

Este estándar utiliza la técnica PWM (pulse-width modulation) para generar la señal eléctrica

que codifica la información a transmitir.

Page 15: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

14

La técnica PWM consiste en generar una onda cuadrada de periodo constante y cicle de

trabajo variable. El ciclo de trabajo es la relación entre el tiempo en estado alto y el periodo

de la señal:

𝐷 =𝑇𝑜𝑛

𝑇 (1)

Por lo tanto, al variar el ciclo de trabajo y mantener el mismo periodo estamos variando el

tiempo en estado alto del señal.

Figura 8: Señales cuadradas con distintos ciclos de trabajo.

Este estándar codifica el estado lógico de un bit mediante el ciclo de trabajo de la señal

cuadrada que se transmite. Cada ciclo de trabajo corresponde a un nivel lógico concreto. Un

ciclo de trabajo alto corresponde a un 1 y un ciclo de trabajo bajo corresponde a un 0.

En cada periodo de la señal PWM se transmite un bit. El tiempo de bit es el periodo de la

señal y por lo tanto, la tasa de bits es la frecuencia de la misma. En este caso al tener una

tasa de bits de 41,6 kbps sabemos que la frecuencia de la señal cuadrado es de 41,6 kHz.

En este bus el nivel lógico dominante es el 0.

Sincronismo de bit

En este sistema de comunicación no hay presente una señal de reloj que sincronice los nodos

que se están comunicando, por lo tanto, se trata de una comunicación asíncrona. El nodo

receptor conoce el tiempo de bit por lo que puede identificar cuando se ha dejado de

transmitir la información de un bit y se ha pasado a transmitir el siguiente bit.

Page 16: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

15

Serie/ paralelo

Tal y como se ha mencionado, los nodos de este sistema utilizan una señal diferencial para

transmitir la información. Como solo hay una única señal, solo se puede transmitir la

información de un bit a la vez, por lo tanto, se trata de una comunicación serie.

Pines y conector

Este sistema de comunicación requiere de un conector que suministre alimentación al equipo

de test y también que lo conecte al bus. Por lo tanto, debe tener los siguientes pines:

• BUS +

• BUS –

• 12 v

• Tierra

El conector del protocolo SAE J1850 PWM viene definido por el estándar SAE J1962. En

la siguiente figura se muestra la forma del conector así como la posición de cada uno de los

pines.

Figura 9: Conector estándar del sistema obd2.

Este mismo conector es utilizado por los otros protocolos y por eso tiene más pines de los

mencionados.

Page 17: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

16

3.1.1.2 Capa enlace

La estructura de la trama se puede observar en la siguiente figura:

Figura 10: Formato de trama del SAE J1850 PWM

A continuación se explicará la función de cada uno de los campos que forman la trama.

• SOF (Start Of Frame): indica el inicio de una trama. El SOF consiste en un pulso

de 200 us de ancho.

• Header: Tiene un tamaño de 3 bytes y contiene la siguiente información (en orden):

- Prioridad (3 bits)

- Longitud de cabecera (1 bit)

- IFR (In frame response) (1 bit)

- Modo de direccion (1 bit)

- Tipo de mensaje (2 bits)

- Direccion nodo destino (1 byte)

- Dirección nodo origen (1 byte)

• Datos: Máximo 7 bytes.

• CRC (Cyclic Redundance Check): 1 byte, esta información sirve para detectar

errores en la trama.

• EOF (End Of Frame): indica el final de la trama.

Page 18: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

17

El valor de algunos campos de la trama ya están definidos por el propio estándar tal y como

se puede observar en la siguiente tabla:

Tabla 1: Valores estándar de algunos campos de la trama.

ECU addr es la dirección de la ECU con la que el tester se está comunicando

3.1.2 SAE J1850 VPW

3.1.2.1 Capa Física

La capa física de este estándar se rige por el protocolo SAE J1850.

Topología de red

Al igual que el SAE J1850 VPW este protocolo también tiene una topología de red tipo BUS.

Todos los nodos de este sistema de comunicación están conectados al bus que es el medio

físico a través del cual se transmite la información.

Medio de transmisión

En este caso el bus lo forma un único hilo ya que la señal que se transmite esta referida a

masa. El medio físico que constituye el bus es un cable unipolar con aislamiento.

Codificación de bit

En el protocolo SAE J1850 VPW el bus puede estar en dos estados distintos: estado activo

y estado pasivo. Los símbolos empleados para codificar los bits son distintos según el estado

en el que esté el bus.

Si el bus está en estado activo el nivel lógico 0 se transmite manteniendo el bus a un potencial

alto (de 4,25 V a 20 V) durante un tiempo de 128 us y el nivel lógico 1 se transmite

manteniendo el bus a un potencial alto durante un tiempo de 64 us.

Si el bus está en estado pasivo el nivel lógico 0 se transmite manteniendo el bus a un

potencial bajo (menos de 4,25 V) durante un tiempo de 64 us y el nivel lógico 1 se transmite

manteniendo el bus a un potencial bajo durante un tiempo de 128 us.

Page 19: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

18

El bus utiliza una resistencia de pull-down la cual lleva el bus a un nivel de tensión bajo. Los

nodos conectados disponen de un driver que puede llevar la tensión del bus a un nivel alto.

Un nivel de tensión alto domina sobre uno bajo por lo que el nivel lógico dominante es el 0

(tanto si el bus es activo como pasivo).

En la siguiente figura se ilustra como se codifican los bits en el bus:

Figura 11: Codificación de los niveles lógicos.

Sincronismo de bit

La comunicación es asíncrona ya que, al igual que con el anterior protocolo, no se dispone

de un seña de reloj que sincronice los nodos.

Serie/ paralelo

La información se transmite bit a bit ya que el bus solo esta formado por un único hilo. Por

lo tanto, se trata de una comunicación serial.

Pines y conector

Este sistema de comunicación requiere de un conector que subministre alimentación al

equipo de test y también que lo conecte al bus. Por lo tanto, debe tener los siguientes pines:

• BUS +

• 12 v

• Tierra

El conector del protocolo SAE J1850 VPW viene definido por el estándar SAE J1962. En la

siguiente figura se muestra la forma del conector así como la posición de los pines:

Page 20: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

19

Figura 12: Conector estándar del sistema obd2.

Este mismo conector es utilizado por los otros protocolos y por eso tiene más pines de los

mencionados.

3.1.2.2 Capa enlace

La capa de enlace de este protocolo es la misma que la del SAE J1850 PWM. La única

diferencia se encuentra en el valor que toman algunos campos.

Para este proyecto se aplica la siguiente tabla:

Tabla 2: Valores estándar de algunos campos de la trama.

ECU addr es la dirección de la ECU con la que el tester se esta comunicando

Page 21: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

20

3.1.3 ISO 9141-2

Este protocolo está basado en la norma RS232 la cual es muy conocida dentro del mundo de

la informática ya que históricamente se ha empleado en muchos dispositivos. Algunas de

estos dispositivos han sido impresoras, módems, Ordenadores, cámaras PTZ (pan-tilt-

zoom)…

Dentro de la industria del automóvil, este protocolo es muy popular entre los fabricantes

europeos (Sobre todo el grupo VAG) y asiáticos. El ISO9141 permite una velocidad de

transferencia de 10400 baudios.

3.1.3.1 Capa Fisica

Topología de red

Al igual que en los anteriores protocolos, la topología de red del ISO9141 es del tipo BUS.

Las distintas ECU’s y el equipo de test se conectan a un bus formado por un solo hilo. Este

hilo recibe el nombre de línea K. Este estándar también define otro hilo denominado línea

L. La función de la línea L no es la de transmitir la información sino que sirve solamente

para inicializar la comunicación entre el tester y una de las ECU’s. Habitualmente se suele

utilizar la propia línea k para realizar la inicialización por lo que la línea L queda en desuso

y pocos fabricantes la implementan.

En la siguiente figura se puede ver como están conectados los distintos nodos en el bus

(tester + ECUs):

Figura 13: Conexión del equipo de test al bus.

La forma en la que están conectados los nodos permite que todos puedan comunicarse con

todos pero, como el bus esta formado por una única línea, solo se puede transmitir

información en un sentido a la vez. Es decir, el modo de envió de información es semidúplex

(bidireccional pero no simultaneo).

Page 22: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

21

Cuando el tester requiere obtener un determinado dato del vehículo (velocidad, temperatura

refrigerante, carga del motor…) este debe transmitir una trama a la ECU correspondiente.

Después de un tiempo de la transmisión de la trama, la ECU responde con otra trama con los

datos que se han pedidos.

El flujo de información es siempre el siguiente: primero el tester envía una trama de request

(para pedir un dato) y un tiempo después, le ECU responde con otra trama (o tramas) de

respuesta. Es decir, quien inicia la comunicación siempre es el tester y la ECU solo responde

a las peticiones hechas por el tester.

Medio de transmisión

El bus lo constituye un solo hilo por lo que el medio de transmisión es un conductor

unipolar con aislamiento.

Codificación de bit

La forma en la que se codifican los bits en este protocolo es muy sencilla ya que no se utiliza

ningún tipo de modulación. El valor del bit que se está transmitiendo depende directamente

del nivel de tensión del bus. Si el bus esta a un potencial alto (70 - 100 % de Vbat) el bit

significa que se esta transmitiendo un 1 lógico, en cambio, si esta a un potencial bajo (0 –

30 % Vbat) significa que se esta transmitiendo un 0 lógico. El nivel lógico del bus cuando

esta inactivo (ningún nodo esta transmitiendo ) es 1.

El bus es llevado a un potencial alto mediante una resistencia pull-up. Cada nodo conectado

al bus dispone de un driver (tipo open-collector) que le permite conectar el bus a tierra, con

lo que se consigue llevarlo a un potencial bajo. El esquema se muestra en la siguiente figura:

Figura 14: Driver tipo open-collector.

El nivel de tensión dominante es el bajo, por lo tanto, el nivel lógico dominante es el 0.

Sincronismo de bit

Este estándar establece una comunicación asíncrona.

Page 23: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

22

Serie/paralelo

La información se transmite bit a bit, es decir, es una comunicación serial.

Influencia del RS232

Tal y como se ha mencionado anteriormente, este protocolo nace del RS232. Esto implica

que el ISO 9141 comparte algunos aspectos con el RS232.

Cuando se quiere transmitir una trama con el ISO 9141 esta no se transmite de forma seguida

sino que cada byte de la trama se envía por separado y encapsulado en otra trama.

Esta trama tiene la siguiente forma:

Figura 15: Trama del RS-232.

En primer lugar se transmite el bit de Start (un 0), posteriormente se transmiten el byte de

data y finalmente se transmite el bit de stop (un 1). Esta configuración recibe el nombre de

8N1 (sin bit de paridad y 1 bit de stop). Los bits del byte de data se envían empezando por

el bit de menos peso (LSB).

Pines y conector

Este sistema de comunicación requiere de un conector que subministre alimentación al

equipo de test y también que lo conecte al bus. Suponiendo que la línea L no se utiliza, se

requieren los siguientes pines:

• Línea k

• 12 v

• Tierra

Page 24: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

23

El conector del protocolo ISO 9141-2 viene definido por el estándar SAE J1962. En la

siguiente figura se muestra la forma del conector así como la posición de los pines:

Figura 16: Conector estándar del sistema obd2.

Este mismo conector es utilizado por los otros protocolos y por eso tiene más pines de los

mencionados.

3.1.3.2 Capa Enlace

En este apartado se describirá la trama con la que trabaja el estándar ISO 9141-2.

Figura 17: Formato de trama del ISO 9141-2

• Campos del Header (cabecera)

o Priority/Type: indica el tipo de trama (1 byte).

o Target adress: indica la dirección del nodo destino (1 byte)

o Source adress: indica la dirección del nodo origen (1 byte)

• Data bytes: datos que se quieren transmitir (hasta 7 bytes)

• Checksum: El checksum sirve para la detección de errores (1 byte)

Page 25: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

24

El valor que toman los bytes de la cabecera dependen de si la trama se envía del tester a la

ECU o de la ECU al tester. La siguiente tabla muestra los valores para cada caso:

Tabla 3: Valores que toman algunos campos.

La trama anteriormente descrita solo permite transmitir un máximo de 7 bytes. Pueden haber

casos en los que se requiera transmitir más de 7 bytes, sobre todo si se trata de una trama

respuesta de la ECU. Por ejemplo, cuando pedimos el número VIN (Vehicle identification

number) del vehículo la ECU debe transmitir un total de 24 bytes de datos (tamaño típico

del número VIN).

En estos casos la ECU simplemente envía tantas tramas como sean necesarias para transmitir

los n bytes de datos.

Proceso de inicialización

Antes de poder intercambia información con una determinada ECU, el tester debe

inicializarla. El proceso de inicialización esta descrito dentro del estándar y es el siguiente:

En primer lugar el tester debe transmitir a través de la línea k el byte 0x33 a una velocidad

de 5 baudios. La señal transmitida se debería ver de la siguiente forma:

Figura 18: Transmisión del byte 0x33

Como la tasa de bits es muy pequeña, el tiempo de transmisión de este byte es de 2 segundos.

Después de un tiempo conocido como W1 (entre 20 y 300 ms) la ECU responde con el byte

0x55 a una velocidad de 10,4 kbps. A partir de ahora la comunicación se debe realizar a

10400 baudios. Posteriormente el vehículo espera un tiempo W2 (entre 5 y 20 ms) para que

el tester pueda reconfigurar los baudios. Pasado el tiempo W2 la ECU transmite los bytes

0x08 y 0x08 o 0x94 y 0x94 (según el vehículo) con una separación entre ellos de un tiempo

W3 (entre 0 y 20 ms), estos bytes se conocen como Key Bytes. Para confirmar la recepción

de estos dos últimos bytes, el tester debe invertir y transmitir el Key Byte #2 después de un

tiempo W4 (entre 25 y 50 ms). Finalmente la ECU responde con el byte 0x33 invertido,

Page 26: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

25

llegado a este punto la ECU se encuentra correctamente inicializada y se puede empezar a

enviar las tramas de request transcurrido tras la espera de un tiempo P3 (entre 55 y 5000 ms).

Cabe destacar que si la ECU no recibe ninguna trama en el transcurso de 5 segundos esta se

pone al estado previo a su inicialización, es decir, deja de aceptar peticiones. Para evitar esto

el tester debe estar continuamente enviando tramas durante el tiempo que queremos

mantener la sesión. Hay que tener en cuenta que una vez recibida la respuesta de una petición

no se puede enviar una nueva petición inmediatamente después, se debe esperar un tiempo

P3 (entre 55 y 5000 ms) antes de enviar una nueva petición.

En la siguiente figura se puede apreciar el proceso de inicialización de la ECU:

Figura 19: Representación del proceso de inicialización.

Los tiempos W1, W2, W3, W4 Y P3 son los descritos anteriormente.

Hay otros tiempos que se deben respetar para asegurar una comunicación satisfactoria. Estos

tiempos se reúnen en la siguiente tabla:

Parámetro Tiempo

Min

Tiempo

Max

Descripción

P1 0 ms 20 ms Tiempo entre bytes enviados desde

la ECU al tester

P4 5 ms 20 ms Tiempo entre bytes enviados desde

el tester a la ECU

Tabla 4: Tabla de tiempos que se deben respetar.

Page 27: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

26

3.1.4 ISO 14230

Este protocolo es muy parecido al ISO 9141-2 ya que comparten la misma capa física, las

únicas diferencias se encuentran en la capa enlace. El ISO 14230 es comúnmente utilizado

entre los fabricantes asiáticos y permite una velocidad de transferencia de 10,4 kbps (igual

que ISO 9141-2). Se suele conocer también con el nombre KWP2000 (keyword protocol

2000).

3.1.4.1 Capa Física

La capa física de este protocolo es la misma que la del ISO 9141-2.

3.1.4.2 Capa Enlace

La trama con la que trabaja este protocolo es la misma que en el caso del ISO 9141-2. La diferencia

radica en los valores que toman los campos de cabecera. Estos se describen en la siguiente tabla:

Tabla 5: Valores que toman algunos campos.

Tal y como se puede ver, cambian los campos target adress y source adress de ambas tramas (ECU

a tester y tester a ECU). Pero la diferencia principal radica en el campo Priority/Type. Mientras que

en el ISO 9141-2 este campo tomaba un valor fijo (0x68 o 0x48) en este caso los 6 bits de menos

peso representan el tamaño del campo de bits, es decir, podemos indicar dentro de este campo

cuantos bytes de datos se enviarán. Este pequeño cambio supone una mejora muy significativa ya

que con el ISO 9141-2 el nodo receptor no podía conocer cuantos bytes iba a recibir, por lo que se

complicaba un poco la recepción de las tramas.

Proceso de inicialización

En el caso de este protocolo disponemos de dos métodos de inicialización de las ECUs. Estos

métodos reciben el nombre de KWP 5-baud init y KWP fast init.

• KWP 5-baud init: Este procedimiento es idéntico al que se emplea en el ISO 9141-

2. La única diferencia radica en los Key Bytes recibidos desde la ECU, en este caso

son los byes 0x8F y 0xE9.

Page 28: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

27

• KWP fast init: Este procedimiento solo es soportado por el protocolo KWP2000.

En este caso la comunicación referente a la inicialización se realiza completamente

a 10400 baudios por lo que resulta un método más rápido que los anteriores. El

procedimiento se explica en el siguiente apartado.

KWP fast init

Esta inicialización empieza con el tester transmitiendo un patrón de “wake-up” seguido de

una petición de inicio de comunicación. El patrón de “wake-up” consiste en llevar el bus a

un nivel bajo durante 25 ms y después llevarlo a un nivel alto durante otros 25 ms. Una vez

enviada la petición de inicio de comunicación la ECU debería transmitir una respuesta de

inicio de comunicación.

La trama para la petición del inicio de comunicación es la siguiente:

<0xC1>< 0x33><0xF1><0x81><0x66>

Esta trama sigue el formato anteriormente descrito por lo que se puede desglosar de la

siguiente forma:

• 0xC1: Es el campo de priority/type. Los 6 bits de menos peso representan la longitud

del campo de datos, por lo tanto, esta trama contiene 1 byte de datos

• 0x33: Este byte es la dirección del nodo destino(ECU)

• 0xF1: Este byte es la dirección del nodo origen(Tester)

• 0x81: Es el byte de datos. El valor 0x81 es el ID para la petición de inicio de

comunicación

• 0x66: es el campo de checksum.

La trama con la que responde la ECU es la siguiente:

<0x83><0xF1><0x10><0xC1><0x8F><0xE9><0xBD>

En este caso se puede desglosar de la siguiente forma:

• 0x83: Esta trama contiene 3 bytes de datos.

• 0xF1: Este byte es la direccion del nodo destino(Tester)

• 0x10: Este byte es la direccion del nodo origen (ECU)

Page 29: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

28

• 0xC1: Es el primer byte del campo de datos. El valor 0xC1 es el ID para la respuesta

de inicio de comunicación.

• 0x8F, 0xE9: Estos bytes son los key bytes.

• 0xBD: Este byte es el checksum de la trama.

Una vez recibida esta trama podemos dar por acabado el proceso de inicialización. A partir

de este momento el tester puede proceder a la petición de datos.

3.1.5 ISO 15765-1

El protocolo ISO 15765-1 empezó a implantarse en el año 2003 y actualmente es el protocolo

mas extendido por las ventajas que ofrece frente a los otros estándares. Este protocolo se

puede encontrar principalmente en los modelos de vehículos más modernos ya que a partir

del 2008 su implantación empezó a ser obligatoria en los EEUU.

El principal motivo del éxito de este protocolo es que utiliza el bus CAN para establecer la

comunicación entre los nodos del sistema. Las ventajas que ofrece el bus CAN son

numerosas y por eso no solo se utiliza en la industria del automóvil sino que es la opción por

excelencia en muchos ámbitos de la industria. Sus ventajas se verán a lo largo de los

siguientes capítulos.

Para poder explicar mejor el protocolo ISO 15765-1, primero se explicará en detalle el

protocolo CAN BUS ya que este es la base del ISO 15765-1.

3.1.5.1 BUS CAN

Este protocolo empezó a ser desarrollado por la empresa Robert Bosch GmbH (BOSCH) en

1983 y fue finalmente presentado en el 1986. En 1993 el protocolo CAN fue estandarizado

por la ISO bajo el nombre ISO 11898.

El motivo que llevó a BOSCH a desarrollar este protocolo fue la inmensa cantidad de cables

que eran necesarios para poder conectar los distintos sistemas electrónicos de los que

disponía un coche. Previamente al bus CAN, los distintos sistemas electrónicos del vehículo

se comunicaban entre ellos mediante una conexión punto a punto. Esta forma de conectar la

electrónica de los vehículos requería una gran cantidad de cables y esto representaba una

serie de inconvenientes: mayor costo en materiales, vehículo más pesado, mayor consumo

etc.

Por estos inconvenientes BOSCH decidió desarrollar el bus CAN. Este sistema de

comunicación tipo bus permitía interconectar todos los sistemas electrónicos del coche con

solo 2 cables.

Page 30: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

29

Figura 20: Coche sin BUS CAN y coche con BUS CAN.

En la figura 20 se ilustra el número de conexiones necesarias para conectar las distintas

ECUs utilizando un sistema de comunicación punto a punto (parte de la izquierda) y

utilizando el bus CAN (parte de la derecha). Tal y como se puede ver, las diferencias son

significativas.

A parte de la ventaja evidente que supone el uso del bus CAN, hay otras más que han hecho

que este protocolo sea de los más utilizados en la industria del automóvil. Estas ventajas de

explican en detalle en los siguientes párrafos:

• Velocidad: Las tasas de bits de este protocolo son mucho mayores que las que

ofrecen los protocolos tradicionales.

• Flexibilidad: Al tratarse de un bus formado por solo dos cables su instalación es

considerablemente más fácil que otros protocolos. Por la misma razón, añadir más

componentes al sistema requiere de un esfuerzo menor. Se pueden conectar hasta

110 nodos en el bus por lo que los fabricantes suelen tener margen para añadir más

nodos al sistema.

• Fiabilidad: Como el bus CAN trabaja con señales diferenciales, es menos

susceptible a las EMI’s (Electromagnética interferentes). Por esta misma razón es un

protocolo muy utilizado en la industria. Por otra parte, al disponer de menos piezas

(menos cables, menos conectores etc.) hay menos elementos que pueden fallar con

lo cual su fiabilidad es mayor. Además, el fallo de un nodo no afecta al

funcionamiento del bus.

• Costos: menos elementos significa menos costes, por lo tanto, el bus CAN es más

económico que otros protocolos tradicionales.

• Espacio: Al reducir el número de cables dentro del vehículo hay más espacio

disponible para incorporar otros sistemas y por lo tanto, otras funcionalidades.

• Normalización: Al ser un estándar, las ECU’s de distintos fabricantes que estén

preparadas para este protocolo son completamente compatibles y pueden

intercambiar información entre sí.

Page 31: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

30

• Sistema multimaestro: Todos los nodos en un bus CAN tienen el papel de master,

es decir, pueden transmitir a través del bus cuando quieran (siempre que no haya otro

nodo transmitiendo en ese momento). Esto permite definir dentro del mismo bus

distintos subsistemas de comunicación.

• Acceso al bus: Aplica la metodología CSMA/CD-A para gestionar los accesos al

BUS. Esto permite detectar y solucionar las colisiones de una forma simple y

efectiva.

3.1.5.1.1 Capa física

Topología de red

Tal y como se ha mencionado, este estándar define una tipología de red tipo bus. Los nodos

del sistema de comunicación se conectan a 2 hilos (CAN high y CAN low) que son las líneas

que constituyen el bus. A través de estas dos líneas se transmite un señal diferencial que es

la que lleva la información codificada.

El bus permite una comunicación de todos con todos, pero como el medio de transmisión es

compartido, solo un nodo puede estar transmitiendo en un instante de tiempo dado.

Medio de transmisión

Los distintos nodos del sistema se conectan mediante un par de cables trenzados con una

impedancia característica de 120 Ohm’s. Los cables pueden estar apantallados o sin

apantallar. El uso de un par trenzado es uno de los aspectos que da a este protocolo

inmunidad frente a las EMI’s. En caso de trabajar en un ambiento ruidoso (con alta actividad

electromagnética) las señales inducidas en cada uno de los cables del par se cancelan por lo

que la señal diferencial se mantiene intacta.

Figura 21: Ventajas del par trenzado frente a un cable unipolar.

Codificación de bit:

El bus CAN utiliza un señal diferencial para codificar los bits de información. Este bus tiene

dos estados definidos: estado dominante y estado recesivo. En cada estado las líneas CAN

High y CAN Low tienen un potencial determinado.

Page 32: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

31

Estos potenciales depende del tipo de CAN que se este utilizando ya que hay dos variantes

denominadas CAN de alta velocidad (o ISO 11898-2) y CAN de baja velocidad(o ISO

11898-3). Tal y como su nombre indica, la diferencia radica en la tasa de bits con la que

trabaja cada versión. En el caso del CAN de alta velocidad se permite una tasas de bits de

hasta 1 Mbps. En el caso del CAN de baja velocidad se permite una tasa de bits de hasta 125

kbps.

La siguiente tabla muestra los potenciales de las líneas según el estado del bus en el caso del

CAN de alta velocidad:

Señal Estado

Recesivo

Estado

Dominante

CAN High 2,5 V 3,5 V

CAN Low 2,5 V 1,5 V

Vdiff 0 2 V

Tabla 6: Potenciales del bus según el estado.

En el estado recesivo las dos líneas están al mismo potencial por lo que la tensión diferencial

es de 0 V (caso ideal). En el caso del estado dominante la línea CAN High esta a 3,5 V y la

línea CAN Low esta a 1,5 V, entonces la tensión diferencial es de 2 V.

La siguiente tabla muestra los potenciales de las líneas según el estado del bus en el caso del

CAN de baja velocidad:

Señal Estado

Recesivo

Estado

Dominante

CAN High 0 V 3,6 V

CAN Low 5 V 1,4 V

Vdiff - 5 V 2,2 V

Tabla 7: Potenciales del bus según el estado.

En el caso del estado recesivo la línea CAN High esta a 0 V y la línea CAN Low esta a 5 V

por lo que la tensión diferencial es de -5 V. En el caso del estado dominante la línea CAN

High esta a 3,6 V y la línea CAN Low esta a 1,4 V, entonces la tensión diferencial es de 2,2

V.

Mediante estos dos estados se codifican los niveles lógicos de los bits que se transmiten. El

1 lógico está asociado al estado recesivo y el 0 lógico esta asociado al estado dominante.

Cuando el bus está en reposo este se mantiene en estado recesivo, es decir, transmitiendo un

1.

Page 33: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

32

Driver del BUS

El circuito a través del cual los nodos establecen el estado del bus se puede modelar de la

siguiente forma:

Figura 22: Modelo del driver del BUS.

RL es la resistencia que se debe conectar entre los terminales CAN High y CAN Low de cada

extremo del bus para evitar rebotes de la señal que se transmite. El valor de esta resistencia

suele ser de 120 Ohm’s

Circuito en estado recesivo y en estado dominante:

Figura 23: Circuito del driver en los dos estados del BUS.

Page 34: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

33

Para poner el bus en estado recesivo los dos transistores se ponen en corte. En este caso la

corriente que fluye entre Vcc y tierra es muy pequeña (despreciable) y la tensión Vod(tensión

diferencial del bus) es 0 V.

Para poner el bus en estado dominante los dos transistores se ponen en conducción. En este

caso si hay corriente a través de la resistencia y por lo tanto, hay una caída de tensión entre

los nodos sus nodos. Esta caída de tensión es justamente la tensión diferencial del bus y tiene

un valor de 2,5 V.

Sincronismo de bit

Este estándar define un sistema de comunicación asíncrono por lo que los nodos deben

conocer el tiempo de bit. Aunque todos los nodos compartan un mismo tiempo de bit, cada

nodo dispone de una frecuencia de reloj por lo que en la práctica cada nodo puede transmitir

o muestrear a una velocidad distinta, es decir, pueden estar desincronizados.

Para evitar la desincronización de los nodos, el bus CAN utiliza un sistema tipo PLL (Phase-

Locked Loop) el cual permite sincronizar los nodos del bus a través de los flancos producidos

en la señal transmitido. Para mantener los nodos sincronizados las tramas de deben contener

1’s y 0’s de forma regular. Como no se puede asegurar que dentro de las tramas no haya una

considerable cantidad de bits consecutivos de igual valor, el bus CAN recurre a una técnica

denominada bit stuffing para asegurar la existencia de flancos durante la transmisión de

datos. Esta técnica consiste en añadir después de cada 5 bits iguales un bit opuesto.

Tiempo de bit

Como se ha mencionado al principio del apartado, una de las características que dan

popularidad al bus CAN es su fiabilidad. Muchos aspectos de su diseño se han pensado

teniendo en mente asegurar que la información llegue del nodo origen al nodo destino con

total éxito. Un buen ejemplo de ello son los mecanismos de sincronización utilizados. Aparte

de la técnica del bit stuffing, cada nodo del bus CAN puede adaptar su tiempo de bit de

acuerdo a una serie de circunstancias (retardos de propagación, retardos en los propios

nodos) y así, asegurar la correcta recepción de los bits.

El estándar CAN divide el tiempo de bit en los siguientes segmentos:

Figura 24: Segmentos del tiempo de bit del BUS CAN.

Page 35: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

34

• Segmento de sincronización: Este segmento de tiempo es el primero del tiempo de

bit. Se utiliza para sincronizar los nodos en el bus. Se espera que los flancos se

produzcan dentro de este segmento. Tiene una durada de 1 TQ (Time Quanta).

• Segmento de propagación: Este segmento tiene la función de compensar por los

retardos físicos entre nodos. El tiempo de propagación se define como el doble de la

suma del tiempo de propagación del señal dentro del bus y los retardos asociados al

propio nodo. Tiene una durada de entre 1 y 8 TQ.

• Segmento de fase 1 y segmento de fase 2: Estos dos segmentos se utilizan para

compensar por el error en la sincronización de los flancos. Se puede alargar el

segmento de fase 1 o bien acortar el segmento de fase 2 para ajustar el punto de

muestreo. El segmento de fase 1 tiene una duración de entre 1 y 8 TQ y el segmento

de fase 2 tiene una duración de entre 2 y 8 TQ.

Mediante la variación de la duración de estos segmentos el controlador CAN sitúa el punto

de muestreo en el momento ideal para que la lectura sea correcta.

3.1.5.1.2 Capa Enlace

El protocolo CAN define los siguientes tipos de tramas:

• Trama de datos estándar/extendida: Esta trama permite enviar datos a uno o más

nodos del BUS.

• Trama remota: Esta trama permite pedir datos a otro nodo.

• Trama de error: Mediante esta trama se indica al nodo emisor que la recepción no

ha sido correcta para que se vuelva a repetir la transmisión.

• Trama de sobrecarga: Esta trama permite a un nodo indicar a los otros nodos del

BUS que no está preparado para recibir.

Dentro del ISO 15765-1 solo se utilizan tramas de datos ya que mediante este tipo de tramas

ya se implementan todo un conjunto de subtramas. A continuación se explicará la trama de

datos y sus dos versiones.

Page 36: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

35

Trama de datos estándar

Los campos de esta trama se pueden observar en la siguiente figura.

Figura 25: Trama de datos estándar.

• SOF(Start Of Frame): Campo de 1 bit y valor 0. Sirve para indicar el inicio de la

trama.

• ID: Este campo es el identificador de la trama. Tiene una longitud de 11 bits. Cuando

un nodo recibe una trama la filtra y solo la acepta si el identificador cumple unas

determinadas condiciones.

• RTR(Remote Transmisión Request): Campo de 1 bit y valor 0.

• IDE: Este campo tiene una longitud de 1 bit e indica si se trata de una trama estándar

o extendida. En este caso su valor debe ser 0 (trama estándar).

• R0: Bit reservado, su valor está fijado a 0.

• DLC(Data Length Code): Campo de 4 bits que indica el tamaño del campo de datos.

• Campo de datos: Datos a enviar. Longitud máxima de 8 bytes.

• CRC(Cyclic Redundance Check): Campo de 15 bits. El CRC permite detectar

errores en la trama.

• Ack: Bit de acknowledge. Cuando el nodo emisor llega a este campo pone un 1 en

el bus y si algún nodo ha recibido la trama este pone un 0. Como el bit dominante es

el 0, el nodo emisor verá un 0 en el bus y supondrá que se ha recibido la trama. Si el

nodo emisor ve un 1 significa que ningún nodo ha recibido la trama.

• Ack delimiter: bit de valor 1.

• EOF(End Of Frame): Campo de 7 bits y valor 0x7F. Sirve para indicar el fin de la

trama.

Trama de datos extendida

Esta trama es muy similar a la anterior ya que, como su nombre indica, es simplemente una

extensión de la trama estándar. La diferencia es que en este caso el identificador de la trama

tiene 29 bits.

Figura 26: Campos de la trama de datos extendida.

Page 37: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

36

Las diferencias en la forma de la trama son:

• El campo IDE toma el valor 1 en vez de 0.

• Entre los campos IDE y R0 se añade otro campo de 18 bits que son los 18 bits de

menos peso del identificador. Los 11 bits de más peso del identificador se sitúan en

el campo ID.

3.1.5.2 Capa Enlace

El protocolo ISO 15765-1 utiliza el BUS CAN para enviar las tramas. Las tramas del ISO

15765-1 se envían dentro del campo de datos de las tramas CAN. El estándar fija la longitud

del campo de datos de las tramas CAN en 8 bytes (la máxima posible), esto permite que las

tramas ISO 15765-1 puedan tener una longitud de hasta 8 bytes. Como la longitud de las

tramas ISO 15765-1 puede ser inferior a 8 bytes, podemos encontrarnos con bytes nulos

dentro del campo de datos de las tramas CAN.

El estándar ISO 15765-1 define varios tipos de tramas, estas se explican a continuación:

Single Frame

Esta trama se utiliza cuando uno de los nodos quiere transmitir datos que caben

perfectamente dentro de una única trama. En estos casos los datos a enviar deben tener una

longitud inferior o igual a los 7 bytes. Los campos de esta trama se muestran en la siguiente

figura:

Figura 27: Campos de la trama Single Frame.

El primer byte de la trama se utiliza para identificar el tipo de trama y la longitud del campo

de datos. Los 4 bits de más peso del primer byte indican el tipo de trama, en este caso su

valor debe ser 0x0. Los 4 bits de menos peso indican la longitud del campo de datos, dentro

del rango permisible su valor máximo es 7. Los siguientes n bytes forman parte del campo

de datos de la trama First Frame. Los bytes no utilizados del campo de datos de la trama

CAN se deben llenar con ceros.

No se admite que se envíe este tipo de trama con una longitud del campo de datos igual a 0

ya que este valor se reserva al mismo protocolo.

First Frame

Este tipo de trama se utiliza cuando un nodo quiere enviar datos que no caben dentro de una

Single Frame, es decir, datos de longitud superior a 7 bytes. Mediante esta trama el nodo

emisor hace saber al nodo receptor que este deberá recibir más de una trama. Dentro de esta

misma trama se envían los primeros 6 bytes del total de bytes que se desean enviar.

Page 38: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

37

El formato de la trama es el siguiente:

Figura 28: Campos de la trama First Frame

En este caso la longitud de la trama es siempre de 8 bytes. Como en el caso anterior, los 4

bits de más peso del primer byte indican el tipo de trama, en este caso debe ser 1. Los 4 bits

de menos peso del primer byte y el segundo byte indican el número de bytes que se quieren

enviar. En este caso el valor de este campo (FF_DL) debe ser superior a 7. Los siguientes 6

bytes forman parte de los datos que se quieren enviar.

Consecutive Frame

Como en el caso anterior, la longitud de la trama es siempre de 8 bytes. Este tipo de trama

se utiliza conjuntamente con el tipo anterior para enviar datos de longitud superior a 7 bytes.

Las tramas Consecutive Frame son las que se envían después de la trama First Frame para

enviar los bytes restantes. Este tipo de trama permite enviar 6 bytes de datos. El formato de

la trama es el siguiente:

Figura 29: Campos de la trama Consecutive Frame.

Los 4 bits de más peso son el identificador de la trama y en este caso su valor es 2. Los 4

bits de menos peso indican el número de Consecutive Frame. Los siguientes 6 bytes

corresponden a los datos.

Como el nodo emisor debe enviar los datos en un número entero de Consecutive Frames se

puede dar el caso de que no se requiera utilizar todos los 6 bytes de la última Consecutive

Frame, en este caso los bytes sobrantes se llenan con el valor nulo.

Flow Control

Este tipo de trama solo interviene cuando se quieren enviar diversas tramas. La trama Flow

Control la utiliza el nodo receptor para indicar al nodo emisor las circunstancias en las que

se quieren recibir las tramas. La longitud de esta trama es siempre de 3 bytes.

Page 39: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

38

El formato de la trama es el siguiente:

Figura 30: Campos de la trama Flow Control

Los 4 bits de más peso del primer byte son el identificador de la trama, en este caso su valor

es 3. Los 4 bits de menos peso corresponden al parámetro FS(Flow Status). El segundo byte

corresponde al parámetro BS(Block Size) y el tercer byte corresponde al parámetro Stmin.

En la siguiente tabla se explica el significado de cada parámetro:

Parámetro Definición

FS Indica al nodo emisor si se debe proceder

con la transmisión o no. Un 0 indica al

emisor que puede continuar con la

transmisión. Un 1 indica que el emisor debe

reintentar la transmisión pasado un cierto

tiempo. Un 2 indica al emisor que el

receptor está ocupado y debe abortar la

transmisión.

BS Este parámetro indica el número de

Consecutive Frames que se pueden enviar

antes que el emisor deba pausar la

transmisión y esperar al siguiente Flow

Control. Si su valor es 0 significa que el

receptor dispone de los recursos suficientes

para recibir las tramas (memoria) y el

emisor puede enviar las tramas que quiera.

Stmin Este parámetro indica el tiempo mínimo

entre el envió de las Consecutive Frames.

Tabla 8: Parámetros de la trama Flow Control.

A continuación se explicará las tramas que se intercambian según la longitud de los datos

que se quieren enviar:

Envió de 7 o menos bytes de datos

En este caso el emisor solo debe enviar una trama tipo Single Frame.

Page 40: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

39

Envió de más de 7 bytes

Figura 31: Intercambio de tramas múltiples.

En primer lugar el nodo emisor debe enviar una trama tipo First Frame con los primeros 6

bytes de datos. Cuando el receptor recibe la First Frame este debe responder con una trama

tipo Flow Control. Una vez el nodo emisor recibe la trama de Flow Control el nodo emisor

debe empezar a transmitir las Consecutive Frames con el resto de bytes de datos. Este

intercambio solo se da si los parámetros FS y BS de la trama Flow Control tienen el valor 0,

en otro caso el intercambio sería distinto. Dentro de este proyecto solo los parámetros FS y

BS se ajustarán a 0 ya que el escáner OBD2 no tendrá otra tarea más que la de comunicarse

con el vehículo, además se espera que las respuestas tengan un tamaño muy inferior a la

memoria disponible en el microcontrolador.

Page 41: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

40

3.2 Servicios del sistema OBD2

En los apartados anteriores se han explicado los distintos protocolos con los que un equipo

de test puede comunicarse con el sistema OBD2 de un vehículo. Este apartado se centrará

en los datos que se deben enviar para obtener los parámetros deseados así como el formato

de los datos de respuesta.

El estándar SAE J1979 se refiere a los datos que se pueden obtener del vehículo como PIDs

(Parameter IDs). Estos PIDs están divididos en servicios según el tipo de parámetro.

En todos los protocolos, el campo de datos de una trama request debe tener el siguiente

formato:

<Service><PID>

Y el campo de datos de la trama de respuesta presenta el siguiente formato:

<0x40 + Service><PID><byte/s del PID>

En muchos casos el valor de respuesta de un determinado PID se fragmenta en un conjunto

de bytes y para obtenerlo se debe realizar una operación aritmética. En otros casos la

información se codifica en uno o varios bits y para obtenerla se deben realizar operaciones

a nivel bit. En todo caso el estándar OBD2 especifica como tratar los datos recibidos para

cada PID.

Tal y como se verá mas adelante, algunos servicios no disponen de PIDs. En estos casos se

omite el campo <PID> de las tramas.

A continuación se explicará en detalle los distintos servicios y PIDs que define el estándar.

El estándar SAE J1979 define los siguientes servicios:

• Servicio 1: Este servicio permite obtener el valor en tiempo real de los sensores del

vehículo. Ejemplo de estos datos son la temperatura del refrigerante o la carga del

motor.

• Servicio 2: A través de este servicio se pueden obtener el valor que tenían los

sensores en el momento en el que se ha producido un fallo. Ofrece los mismos PIDs

que el servicio 1 pero a diferencia del primero, este servicio no da valores en tiempo

real

• Servicio3: Este servicio permite obtener el código de las fallas detectadas (DTC) por

las ECUs.

• Servicio 4: Mediante este servicio se pueden borrar de la memoria las fallas

detectadas. También borra los datos del servicio 2.

Page 42: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

41

• Servicio 5: Este modo permite obtener los resultados de las pruebas realizadas a los

sensores de oxigeno del vehículo.

• Servicio 6: Este servicio permite obtener el resultado de todas las pruebas de abordo.

• Servicio 7: Este servicio permite obtener los DTCs pendientes de la memoria de las

ECUs.

• Servicio 8: Mediante este modo se puede realizar una prueba a los actuadores.

• Servicio 9: Este servicio permite obtener información legal del vehículo. Un ejemplo

es el VIN (Vehicle Identification Number)

Servicio 1

Algunos de los PIDs de este servicio se muestran en la siguiente tabla:

Mode (hex) PID

(hex)

Data bytes

returned

Description Min value Max

value

Units Formula

01 00 4 PIDs supported [01 - 20] Bit encoded [A7..D0]

== [PID 0x01..PID

0x20] See below.

01 01 4 Monitor status since

DTCs cleared. (Includes

malfunction indicator

lamp (MIL) status and

number of DTCs.)

Bit encoded. See below.

01 02 2 Freeze DTC

01 03 2 Fuel system status Bit encoded. See below.

01 04 1 Calculated engine load

value

0 100 % A*100/255

01 05 1 Engine coolant temperature -40 215 °C A-40

01 06 1 Short term fuel % trim—

Bank 1 -100

Subtra

cting

Fuel

(Rich

Conditi

on)

99.22

Adding

Fuel

(Lean

Conditi

on)

% (A-128) * 100/128

01 07 1 Long term fuel % trim—

Bank 1 -100

Subtra

cting

Fuel

(Rich

Conditi

on)

99.22

Adding

Fuel

(Lean

Conditi

on)

% (A-128) * 100/128

01 08 1 Short term fuel % trim—

Bank 2 -100

Subtra

cting

Fuel

(Rich

Conditi

on)

99.22

Adding

Fuel

(Lean

Conditi

on)

% (A-128) * 100/128

Page 43: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

42

01 09 1 Long term fuel % trim—

Bank 2 -100

Subtra

cting

Fuel

(Rich

Conditi

on)

99.22

Adding

Fuel

(Lean

Conditi

on)

% (A-128) * 100/128

01 0A 1 Fuel pressure 0 765 kPa A*3

01 0B 1 Intake manifold

absolute pressure

0 255 kPa

(absol

ute)

A

01 0C 2 Engine RPM 0 16,383.7

5

rpm ((A*256)+B)/4

01 0D 1 Vehicle speed 0 255 km/h A

01 0E 1 Timing advance -64 63.5 °

relative

to #1

cylinde

r

A/2 - 64

01 0F 1 Intake air temperature -40 215 °C A-40

01 10 2 MAF air flow rate 0 655.35 grams/s

ec

((A*256)+B) / 100

01 11 1 Throttle position 0 100 % A*100/255

01 12 1 Commanded secondary air

status

Bit encoded. See below.

01 13 1 Oxygen sensors present [A0..A3] == Bank 1,

Sensors 1-4. [A4..A7] ==

Bank 2...

01 14 2 Bank 1, Sensor 1:

Oxygen sensor

voltage, Short

term fuel trim

0

-100(lean)

1.275

99.2(rich

)

Volts

%

A/200

(B-128) * 100/128 (if B==0xFF,

sensor is not used in trim calc)

Tabla 9: Primeros 20 PIDs del servicio 1.

Servicio 2

Para este servicio se aplica la misma tabla que la del servicio 1.

Servicio 3

Este servicio no dispone de PIDs.

Dentro del campo de datos de la respuesta a este servicio se encuentran los DTCs

almacenados en memoria. Por cada DTC detectado, la ECU manda dos bytes con los cuales

se codifica la información de la falla. Un DTC esta compuesto por un conjunto de 5

caracteres y el valor de estos caracteres se codifica utilizando un determinado conjunto de

bits. La obtención de los DTCs a partir de sus bytes se debe realizar siguiendo estas tablas:

Page 44: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

43

Tabla 10: Tabla de obtención del primer carácter.

Tabla 11: Tabla de obtención del segundo carácter.

Tabla 12: Tabla de obtención del tercer carácter.

Page 45: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

44

Los caracteres cuarto y quinto se definen de la misma manera que el tercero, pero utilizando

los bits B7..B4 y B3..B0.

Servicio 4

Este servicio tampoco dispone de PIDs.

Servicio 5

Algunos de los PIDs de este servicio se encuentran en la siguiente tabla:

PID

(hexadecimal)

Bytes de

datos

devuelto

Descripción Valor

mín.

Valor

máx.

Unidades Fórmula

0100 OBD Monitor IDs apoyado ($01 –

$20)

0101

O2 Sensor Monitor Banco 1

Sensor 1

0.00

1,275

Voltios Rich 0,005 a voltaje del umbral

del sensor de inclinación

0102

O2 Sensor Monitor Banco 1

Sensor 2

0.00

1,275

Voltios Rich 0,005 a voltaje del umbral

del sensor de inclinación

0103

O2 Sensor Monitor Banco 1

Sensor 3

0.00

1,275

Voltios Rich 0,005 a voltaje del umbral

del sensor de inclinación

0104

Sensor de O2 Sensor Monitor

Banco 1 4

0.00

1,275

Voltios Rich 0,005 a voltaje del umbral

del sensor de inclinación

0105

O2 Sensor Monitor banco 2 Sensor

1

0.00

1,275

Voltios Rich 0,005 a voltaje del umbral

del sensor de inclinación

0106

O2 Sensor Monitor banco 2 Sensor

2

0.00

1,275

Voltios Rich 0,005 a voltaje del umbral

del sensor de inclinación

0107

O2 Sensor Monitor banco 2 Sensor

3

0.00

1,275

Voltios Rich 0,005 a voltaje del umbral

del sensor de inclinación

0108

Sensor de O2 Sensor Monitor

banco 2 4

0.00

1,275

Voltios Rich 0,005 a voltaje del umbral

del sensor de inclinación

0109

Sensor de O2 Sensor Monitor

Banco 3 1

0.00

1,275

Voltios Rich 0,005 a voltaje del umbral

del sensor de inclinación

010A

Sensor de O2 Sensor Monitor

Banco 3 2

0.00

1,275

Voltios Rich 0,005 a voltaje del umbral

del sensor de inclinación

010B

Sensor de O2 Sensor Monitor

Banco 3 3

0.00

1,275

Voltios Rich 0,005 a voltaje del umbral

del sensor de inclinación

Page 46: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

45

010C

Sensor de O2 Sensor Monitor

Banco 3 4

0.00

1,275

Voltios Rich 0,005 a voltaje del umbral

del sensor de inclinación

010D

Sensor de O2 Sensor Monitor

Banco 4 1

0.00

1,275

Voltios Rich 0,005 a voltaje del umbral

del sensor de inclinación

010E

Sensor de O2 Sensor Monitor

Banco 4 2

0.00

1,275

Voltios Rich 0,005 a voltaje del umbral

del sensor de inclinación

010F

Sensor de O2 Sensor Monitor

Banco 4 3

0.00

1,275

Voltios Rich 0,005 a voltaje del umbral

del sensor de inclinación

Tabla 13: Algunos PIDs del servicio 5.

Servicio 6

Los PIDs de este servicio no están definidos por el estándar sino que cada fabricante

implementa unos PIDs en particular.

Servicio 7

Este funcionamiento de este servicio es equivalente al del servicio 3.

Servicio 8

Al igual que con el servicio 6, el fabricante es quien determina los PIDs de este servicio.

Servicio 9

Los PIDs de este servicio se muestran en la siguiente tabla:

PID

(hexadecimal)

Bytes de datos devuelto Descripción Valor

mín.

Valor

máx.

Unidades Fórmula

00

4

9 el modo compatible PIDs

(01 a 20)

Bit codificado. [A7...D0]

= [PID $01..

PID $20] Vea a

continuación

01

1

VIN mensaje Conde en el PID 02.

Sólo para ISO 9141-2, ISO

14230- 4 y SAE J1850.

Generalmente el valor

será 5.

02

17-20

Número de identificación del

vehículo (VIN)

17-char VIN,

codificación ASCII e

izquierda-rellenado con

caracteres nulos (0 x 00)

si necesario.

Page 47: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

46

03

1

Conde de mensaje de ID de

calibración para el PID 04. Sólo

para ISO 9141-2, ISO 14230-4 y

SAE J1850.

Será un múltiplo de 4 (4

mensajes son necesarios

para cada ID).

04

16

ID de calibración

Hasta 16 caracteres

ASCII. bytes de datos no

utilizados serán

reportados como bytes

nulos (0 x 00).

05

1

Número de verificación de

calibración (CVN) mensaje

cuenta por PID 06. Sólo para

ISO 9141-2, ISO 14230-4 y SAE

J1850.

06

4

Número de verificación de

calibración (CVN)

Izquierda-rellenado con

caracteres nulos (datos en

bruto0 x 00).

Generalmente aparece

como cadena

hexadecimal.

07

1

Conde de mensaje por PID de

seguimiento del rendimiento en

uso08 y 0B. Sólo para ISO 9141-

2, ISO 14230- 4 y SAE J1850.

8

10

8 si dieciséis 16 valores

están obligados a

informar, 9 18 18 valores

están obligados a

informar, y 10 si veinte 20

valores deben ser

registrados (un mensaje

informes dos valores,

cada uno que consiste en

dos bytes).

08

4

Seguimiento para los vehículos

de ignición de chispa del

rendimiento en uso

4 o 5 mensajes, cada

uno conteniendo 4 bytes

(dos valores). Vea a

continuación

09 1 ECU nombre mensaje no cuentan

para PID 0A

Tabla 14: PIDs del servicio 9.

Ejemplo práctico: Obtención de las revoluciones del motor.

Las revoluciones del motor están asociadas al PID 0xC del servicio 1, por lo tanto, el equipo

de test envia los siguientes bytes a la ECU del vehículo:

<0x1><0xC>

Tras un tiempo acotado, el tester recibe los siguientes bytes:

<0x40 + 0x1><0xC><0x14><0x3>

Page 48: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

El sistema OBD2

47

Los bytes que nos interesan son 0x14 y 0x3. Según la tabla 9, la fórmula que debemos

aplicar a estos valores para obtener las revoluciones del motor es la siguiente:

𝑛 =256 × 𝐴 + 𝐵

4 (2)

Realizamos los cálculos indicados:

𝑛 =256 × 20 + 3

4= 𝟏𝟐𝟖𝟎 𝒓𝒑𝒎 (𝟑)

Así es como se obtendría la velocidad de giro del motor.

Page 49: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

48

4. Desarrollo del hardware

En este apartado se explicará todo el proceso de diseño seguido para desarrollar el hardware

necesario. La idea de la que se parte para el diseño del hardware es que permita a un

microcontrolador conectarse a los buses de los protocolos deseados, en este caso ISO 9141-

2 y ISO 15765-4. Al mismo tiempo se debe diseñar un hardware que permita al dispositivo

comunicarse con un ordenador. En primer lugar se explicará en detalle el hardware necesario

para implementar cada uno de los protocolo y seguidamente se explicará el circuito del

microcontrolador que será el que manejará los demás circuitos.

4.1 Interfaz hardware del ISO 9141-2

4.1.1 Uso de la UART

Tal y como se ha especificado en el apartado del ISO 9141-2, este protocolo implementa una

capa física que es similar a la del protocolo RS-232. En el caso del RS-232, el hardware que

implementa las funciones de la capa física se denomina UART (Universal Asíncronos

Receiver-Transmitir).

La UART es un periférico imprescindible dentro de los microcontroladores por su

practicidad y simplicidad a la hora de establecer comunicación entre dos dispositivos. Este

dispositivo se permite establecer una comunicación punto a punto y full-dúplex (se puede

dar en ambos sentidos simultáneamente). Las líneas de comunicación a través de las que se

comunican los dos dispositivos se pueden visualizar en el siguiente diagrama:

Figura 32: Conexión entre dos dispositivos a través de la UART.

Tal y como se puede ver, cada uno de los dispositivos presenta un módulo UART. La líneas

que conectan los dos nodos son 2 y en cada una de la líneas la información fluye en un

sentido (nodo A a nodo B y nodo B a nodo A), esto permite que la comunicación sea full-

dúplex.

En cada una de las línea hay conectado el pin TX de un nodo y el pin RX de otro nodo. El

nodo que tiene su pin TX conectado a la línea la gobierna para transmitir la señal eléctrica

que codifica la información mientras que el nodo que tiene el pin RX conectado recibe la

señal. Es decir, dentro de una línea un nodo transmite mientras que el otro recibe.

Page 50: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

49

Los estados lógicos 1 y 0 se codifican utilizando el potencial eléctrico de la línea: un

potencial alto (habitualmente 5 V) equivale a un 1 lógico y un potencial bajo (habitualmente

0 V) equivale a un 0 lógico.

Como se puede deducir a partir de la figura, este dispositivo establece una comunicación

serie asíncrona permitiendo una tasa de bits de hasta 921,6 Kbps.

La trama de datos con la que trabaja habitualmente este hardware es la siguiente:

Figura 33: Formato de trama de la UART.

La configuración de este paquete de datos recibe el nombre de 8N1 y esta constituido por 1

bit de start + 8 bits de datos + 1 bit de stop. El número de bits de datos que se transmiten en

cada paquete es de 1 byte por lo que la unidad de datos de este protocolo es de 1 byte.

Tal y como se puede ver, hay muchas similitudes entre la forma en la que se comunica una

UART y la capa física del ISO 9141-2, aunque también hay diferencias.

En la siguiente tabla se comparan los dos protocolos y se enumeran la similitudes y

diferencias:

Similitudes Diferencias

→ En ambos se establece una

comunicación serie asíncrona.

→ Ambos no utilizan ninguna modulación.

Es decir, codifican los bits directamente con

el nivel de tensión.

→ El paquete de datos o trama es igual en

ambos casos.

→ Mediante la UART se establece una

comunicación punto a punto mientras que

en el caso del ISO 9141-2 se trata de un bus

(comunicación multinodo).

→ Los niveles de tensión utilizados son

distintos. ISO 9141-2 utiliza 12 V y 0 V,

UART utiliza 5 V y 0 V.

→ La comunicación mediante la UART es

full-dúplex mientras que con ISO 9141-2 no

lo es.

Tabla 15: Comparación entre el ISO 9141-2 y la UART.

Page 51: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

50

A partir de la tabla anterior se deduce que las diferencias se encuentran básicamente en el

medio físico. Por lo tanto, solucionando estas diferencias podemos utilizar la UART de un

microcontrolador para conectarnos al bus de un sistema de comunicación basado en ISO

9141-2.

4.1.2 El MC33290

En el mercado existen multitud de circuitos integrados que funcionan de interfaz entre un

microcontrolador y una línea k (bus del ISO 9141-2). Un claro ejemplo es el MC33290.

El MCP33290 es un circuito integrado fabricado por la empresa NXP y sirve de interfaz

entre las ECUs del vehículo y el microcontrolador del equipo de test. Este integrado ha sido

diseñado para ser usado dentro de la industria del automóvil por lo que satisface nuestras

necesidades.

Pines del circuito integrado

Figura 34: Pinout del MC33290

Descripción de los pines

Número Nombre Definición

1 VBB Alimentación de 12 V (de la batería del coche).

2 NC No se debe conectar.

3 GND Tierra.

4 ISO Conexión al bus.

5 TX Entrada digital para la señal a transmitir.

6 RX Salida digital para la señal recibida

7 VDD Alimentación de 5 V.

8 CEN Entrada digital para habilitar el integrado. 1 para activo y 0 para

inactivo.

Tabla 16: Descripción de los pines del MC33290.

Page 52: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

51

Circuito recomendado para conectar el circuito integrado

Figura 35: Circuito recomendado del MC33290.

En el esquema anterior hay más componentes de los que son necesarios para el

funcionamiento del circuito integrado ya que se han añadido protecciones contra las ESD

(electrostatic discharge). En este caso se va a omitir el uso de estos componentes ya que la

versión que se desarrolla en este proyecto se trata de un prototipo. Si se quiere lanzar una

versión comercial estos componentes son imprescindibles para cumplir con los estándares.

Los componentes que se omiten son: R1, C1, C2, C3, D1, D2 y D3.

Se dejará solamente la resistencia R2 que es la resistencia de pull-up que lleva el bus a un

potencial alto (12 V). Sin esta resistencia no se podría transmitir correctamente la

información.

Funcionamiento del integrado

El funcionamiento del MC33290 es equivalente al funcionamiento del siguiente circuito:

Figura 36: Circuito equivalente al MC33290.

R1

D1

D2 C1

C2

D3

C3 R2

Page 53: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

52

La idea de esta circuito es que el pin TX de la UART permita gobernar el estado del bus

mientras que el pin RX permita leer su estado. En el caso del pin RX la solución es muy

sencilla, mediante un simple divisor de tensión adaptamos la señal del bus a los niveles de

tensión del microcontrolador (5V y 0V) y la llevamos al pin RX. Entre el divisor de tensión

y el bus se debe conectar un seguidor de tensión para evitar efectos de carga. En el caso de

del pin TX el esquema algo más complejo. Como se ha explicado anteriormente, el estándar

ISO 9141-2 especifica que los niveles de tensión se deben obtener mediante una resistencia

de pull-up i un driver de colector abierto. Si implementamos esta solución y conectamos el

pin RX del MCU a la base del transistor tendremos los siguientes casos:

• Si el pin RX está a 1 entonces el transistor conducirá y conectará el bus a masa.

• Si el pin RX está a el transistor no conducirá y la resistencia de pull-up llevará el bus

a 12 V.

Con esta solución podríamos gobernar el bus pero la señal que se transmitiría desde el pin

RX se invertiría. Por esta razón se debe añadir un inversor entre el pin RX y la puerta del

driver tal y como se observa en la figura anterior.

Mediante este integrado podremos transmitir y recibir bytes con las ECUs del coche de la

misma forma que se haría con otro microcontrolador. Hay que tener en cuanta que entre el

microcontrolador y el vehículo hay un bus que impide que haya más de un emisor en un

instante de tiempo dado, esto hace que la UART pierda su bidireccionalidad. Otra cosa que

hay que tener en cuenta es que los pines TX y RX de la UART están conectados de forma

lógica al bus, es decir, lo que se transmite a través de TX llega a RX por lo que tendremos

una eco que habrá que tratar por software.

Con el circuito anteriormente mostrado tenemos todo el hardware necesario para establecer

una conexión con el sistema OBD2 de los vehículos que implementen el protocolo ISO

9141-2.

Page 54: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

53

4.1.3 Circuito de la interfaz

Figura 37: Circuito de la Interfaz ISO 9141-2.

R2 es una resistencia de 500 Ohm’s que el fabricante recomienda conectar para llevar la

linea k a un potencial alto.

Page 55: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

54

4.2 Interfaz hardware del ISO 15765-4

Para poder establecer comunicación con vehículos que implementen el protocolo ISO

15765-4 necesitamos un controlador CAN. El microcontrolador que se utilizará en este

proyecto no dispone de CAN, por lo tanto, debemos utilizar un controlador externo. El

circuito integrado que se va a utilizar será el MCP2515.

4.2.1 EL MCP2515

El MCP2515 es un integrado desarrollado por la empresa Microchip. Este modulo se trata

de un controlador CAN que implementa la versión 2.0B del protocolo. También dispone de

comunicación SPI la cual permite un fácil enlace con un microcontrolador.

Este circuito integrado puede conectarse a un bus CAN y actuar como un nodo más del bus,

es decir, una vez conectado al bus puede enviar y recibir tramas.

El modulo dispone de una memoria RAM estructurada en registros que puede almacenar la

siguiente información:

• La configuración del chip así como los parámetros de la comunicación CAN (tipo de

identificador, tiempo de bit etc.).

• Los campos de las tramas a enviar o de las tramas recibidas.

El microcontrolador puede acceder a estos registros mediante SPI y realizar operaciones de

lectura o escritura controlando así el circuito integrado y el BUS CAN.

La siguiente figura muestra como quedaría conectado el MCP2515 entre el microcontrolador

y el bus CAN.

Figura 38: Conexión del MCP2515 al BUS CAN.

Page 56: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

55

Observamos en la figura anterior que hay otro componente entre el MCP2515 y el bus CAN.

Este componente es el transciever y tiene la función de adaptar los niveles de tensión del

MCP2515 a los del bus CAN. Por lo tanto, es un componente imprescindible y se debe incluir

en el circuito.

Pines del MCP2515

Figura 39: Pinout del MCP2515.

Descripción de los pines

Número

pin

Nombre

pin

Definición

1 TXCAN Salida digital del señal a transmitir a través del bus CAN

2 RXCAN Entrada digital del señal recibido a través del bus CAN

8 OSC1 Entrada oscilador

9 OSC2 Salida oscilador

10 VSS Massa

20 VDD Alimentación positiva

18 /CS Pin de Chip Select del SPI

17 SO Salida del SPI

16 SI Entrada del SPI

Tabla 17: Descripción de los pines del MCP2515.

4.2.1.1 Componentes externos del MCP2515

4.2.1.1.1 Circuito oscilador

El integrado MCP2515 requiere de un oscilador externo que proporcione el señal de reloj.

El circuito oscilador puede estar basado en un oscilador de cristal o bien un resonador con

resistencias. En este caso se ha decidido utilizar un oscilador de cristal ya que proporciona

una salida más estable. La frecuencia del oscilador será de 16 MHz. Esta frecuencia es la

mínima que nos va a permitir llegar a la velocidad de transferencia máxima del sistema

OBD2(500 Kbps).

Page 57: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

56

Esquema de conexión del oscilador

Figura 40: Circuito oscilador del MCP2515.

Tal y como se puede observar, se requiere 2 condensadores adicionales para el correcto

funcionamiento del oscilador. El valor de estos condensadores debe ser de 15 pF, según

recomienda el propio fabricante.

4.2.1.1.2 El transceiver

El transceiver que se utiliza es el TJA1050. Este integrado ha sido desarrollado por la marca

NXP. Permite una tasa de bits de hasta 1 Mbaud, la cual es superior a la máxima que se

empleará (500 Kbps).

Pines del TJA1050

Figura 41: Pines del TJA1050.

Page 58: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

57

Descripción de los pines

Número

pin

Nombre pin Descripción del pin

1 TXD Entrada digital. El señal de este pin se transmite al BUS.

2 GND Tierra.

3 VCC Alimentación positiva (5 V).

4 RXD Salida digital. El señal del bus se transmite a través de este pin

5 Vref Salida de la tensión de referencia.

6 CANL Conexión a la linea CANL del bus.

7 CANH Conexión a la linea CANH del bus.

8 S Entrada digital. Habilita el integrado si está a nivel alto.

Tabla 19: Descripción de los pines del TJA1050.

Esquema de conexión del TJA1050

Figura 42: Conexión del transceiver entre el controlador CAN y el BUS CAN.

El condensador de 100 nF sirve para filtrar el posible ruido de la alimentación.

Page 59: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

58

4.2.1.2 Comunicación SPI

El MCP2515 dispone de una interfaz SPI con la que se puede comunicar con un

microcontrolador. Las instrucciones que soporta el MC2515 son las siguientes:

• Reset Instruction: Esta instrucción permite reinicializar los valores de los registros

del integrado.

• Read Instruction: Esta instrucción permite leer el valor de un registro.

• Write Instruction: Esta instrucción permite escribir en un registro.

• Bit Modify Instruction: Esta instrucción permite modificar los bits de un registro

A continuación se explicaran el intercambio de datos que se produce con cada una de las

instrucciones.

Reset Instruction

Para esta instrucción solo se debe enviar el byte 0xC0.

Read Instruction

Figura 43: Diagrama de la instrucción Read.

En primer lugar el microcontrolador debe enviar el byte que identifica la instrucción, en este

caso es 0x03. Seguidamente el MCU debe enviar la dirección del byte que se quiere leer.

Finalmente el MCP2515 devuelve el valor que se encuentra en la dirección previamente

enviada.

Page 60: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

59

Write Instruction

Figura 44: Diagrama de la instrucción Write.

En primer lugar el microcontrolador envía el byte asociado a la instrucción, el cual es 0x02.

Posteriormente se envía la dirección del registro a modificar y finalmente se envía el nuevo

valor que se le quiere asignar.

Bit Modify Instruction

Figura 45: Diagrama de la instrucción Bit Modify.

En primer lugar se envía el byte de la instrucción, en este caso es 0x05. Posteriormente se

debe enviar la dirección del byte a modificar. Seguidamente se tiene que enviar la máscara

de bits con la que se indica los bits se quieren modificar. Finalmente se envía el byte con el

nuevo valor de los bits que se desean modificar. Solo se modifican los bits indicados en la

máscara de bits, los demás mantienen su valor.

Este circuito integrado dispone de más instrucciones pero solo se utilizan las descritas

anteriormente. Mediante estas instrucciones se pueden aprovechar todas las funciones que

presenta este circuito integrado.

Page 61: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

60

4.2.1.3 Modos de operación

El circuito integrado MCP2515 dispone de distintos modos de operación. Estos se explican

a continuación:

Configuration mode

Este modo es el único que permite modificar la configuración del integrado. Es

imprescindible pasar por este modo antes de utilizar otro ya que se deben inicializar los

registros de configuración para asegurar el correcto funcionamiento del integrado. Este

modo permite modificar los siguientes registros:

Registro Definición

CNF1, CNF2, CNF3

TXRTSCTRL

Filter registers Registros para configurar el filtro

aplicado a las tramas recibidas Mask registers

Tabla 19: Registros del MCP2515 para configurar el modo de funcionamiento.

Sleep mode

el integrado dispone de un modo de bajo consumo. Este modo es muy útil para aplicaciones

portátiles (alimentación con batería) ya que permite reducir el consumo del dispositivo

cuando este no es utilizado. Una vez entrado en este modo el microcontrolador puede

devolverlo a su modo normal a través del SPI.

Listen-Only Mode

Este modo permite escuchar las tramas que se envían a través del bus sin que los otros nodos

se percaten de su presencia (no actúa sobre el bit de ACK). Este modo es muy útil si se quiere

realizar un análisis de las tramas que envía un nodo a través del bus. Cuando se activa el

modo Listen-Only se deshabilita la opción de transmitir tramas a través del bus.

Loopback Mode

Dentro de este modo el integrado no tiene que estar conectado al bus ya que lo que se hace

es redirigir las tramas enviadas al buffer de entrada, es decir, las tramas que se envían las

vuelve a recibir el mismo integrado. El objetivo de este modo es poder probar algunas de las

funcionalidades del integrado sin la necesidad de conectarlo a un bus CAN.

Page 62: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

61

Normal Mode

Este modo es el modo de operación estándar. Dentro de este modo el MC2515 puede

transmitir y recibir tramas a través del bus CAN.

Los bits que permiten cambiar el modo de funcionamiento del integrado son los 3 bits de

mayor peso del registro CANCTRL. El modo que corresponde a cada combinación binaria

se encuentra en la siguiente tabla:

REQOP2 REQOP1 REQOP0 Modo de operación

0 0 0 Normal Mode

0 0 1 Sleep Mode

0 1 0 Loopback Mode

0 1 1 Listen-Only Mode

1 0 0 Configuration Mode

Tabla 20: Bits para configurar el modo de funcionamiento.

4.2.1.4 Transmisión y recepción de mensajes

4.2.1.4.1 Configuración del tiempo de bit

Como el bus CAN implementa un sistema de comunicación asíncrona, se tiene que

configurar el tiempo de bit del MCP2515 para que este sea compatible con el resto de nodos

del bus. Tal y como se ha especificado en su correspondiente apartado 3.1.5, ISO 15765-4

dispone de 4 variantes según la longitud del identificador y la tasa de bits, estas variantes

son:

• ISO 15765-4 CAN (11 bit ID,500 Kbaud)

• ISO 15765-4 CAN (29 bit ID,500 Kbaud)

• ISO 15765-4 CAN (11 bit ID,250 Kbaud)

• ISO 15765-4 CAN (29 bit ID,250 Kbaud)

Por lo tanto, la configuración que le demos al integrado debe permitir que este se comunique

a 250 kbps y 500 kbps.

El tiempo de bit dentro del estándar CAN se divide en 4 segmentos: SyncSeg, PropSeg,

PhaseSeg1 y PhaseSeg2. La duración de cada segmento esta compuesta por un número

entero de veces un parámetro denominado Time Quanta. El propio fabricante recomienda

cuantos Time Quanta debe durar cada segmento.

En el caso del primer segmento la duración se fija a 1 Tq. Para los segmentos tres y cuatro

se recomienda una duración entre 1 y 8 Tq. En el caso del ultimo se segmento se debe ajustar

una duración entre 2 y 8 Tq.

Page 63: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

62

En la siguiente tabla se muestra la duración elegida en función de Tq de cada uno de los

segmentos:

Segmento Tq

SyncSeg 1

PropSeg 2

Phase Segment 1 7

Phase Segment 2 6

Tabla 21: Duración de los segmentos del tiempo de bit.

Ahora podemos expresar el tiempo de bit en función de Time Quanta:

𝑡𝑏𝑖𝑡 = 𝑇𝑄 + 2 · 𝑇𝑄 + 7 · 𝑇𝑄 + 6 · 𝑇𝑄 = 16 · 𝑇𝑄 (3)

Finalmente solo queda definir el parametro Time Quanta para que el tiempo de bit sea el

deseado. Queremos que el MC2515 pueda transmitir a 250 kbps y 500 kbps, entonces

debemos calcular el valor de Time Quanta para cada caso. El valor de Time Quanta se puede

calcular a partir de la siguiente formula:

𝑇𝑄 =2𝐵𝑅𝑃

𝐹𝑜𝑠𝑐 (4)

Tal y como se puede observar en la formula 3, el valor de Time Quanta depende de la

frecuencia del oscilador y del valor de BRP. Mientras que el la frecuencia de oscilador es un

parametro fijo, BRP es el valor de un registro que se puede ajustar para obtener el Time

Quanta deseado. Entonces debemos aislar BRP para poder obtener el valor que debe tomar.

𝐵𝑅𝑃 =𝑇𝑄 · 𝐹𝑜𝑠𝑐

2 (5)

Tasa de bits de 250 kbps

En este caso el tiempo de bit debe tener el siguiente valor:

𝑡𝑏𝑖𝑡 =1

𝑓𝑏𝑖𝑡=

1

250 · 103= 0.04 · 10−4𝑠 (6)

Ahora podemos calcular el valor de Time Quanta:

Page 64: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

63

𝑡𝑏𝑖𝑡 = 16 · 𝑇𝑄 → 𝑇𝑄 =𝑡𝑏𝑖𝑡

16=

0.04 · 10−4

16= 0.0025 · 10−4𝑠 (7)

Finalmente podemos calcular el valor de BRP para fijar el tiempo de bit deseado:

Fosc = 16 MHz

𝐵𝑅𝑃 =0.0025 · 10−4 · 16 · 106

2= 2 (8)

Tasa de bits de 500 kbps

Realizando las mismas operaciones que en el caso anterior:

𝑡𝑏𝑖𝑡 =1

𝑓𝑏𝑖𝑡=

1

500 · 103= 0.02 · 10−4𝑠 (9)

𝑡𝑏𝑖𝑡 = 16 · 𝑇𝑄 → 𝑇𝑄 =𝑡𝑏𝑖𝑡

16=

0.02 · 10−4

16= 0.00125 · 10−4𝑠 (10)

𝐵𝑅𝑃 =0.00125 · 10−4 · 16 · 106

2= 1 (11)

Ahora ya tenemos los valores de BRP para cada uno de los casos. Utilizando las

instrucciones anteriormente descritas podremos asignar un 1 o un 2 al registro BRP según si

queremos transmitir a 500 kbps o a 250 kbps.

4.2.1.4.2 Transmisión de mensajes

El MCP2515 dispone de 3 buffers de transmisión pero en nuestro caso solo se utilizará uno

de ellos. Los buffers de transmisión se pueden configurar mediante un total de 14 registros

mapeados en la memoria SRAM. Los registros asociados al buffer que se utilizará son:

• TXB0CTRL: este registro indica las condiciones bajo las que se enviaran los

mensajes y el estado de las transmisiones.

• TXB0SIDH, TXB0SIDL, TXB0EID8 y TXB0EID0: son los registros que

contienen el identificador de los mensajes. En caso de enviar tramas estándar

(identificador de 11 bits) solo se deben utilizar los 2 primeros registro. Si por lo

contrario se envían tramas extendidas (identificador de 29 bits) se deben emplear

todos los registros.

Page 65: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

64

• TXB0DLC: este registro contiene la longitud del campo de datos.

• TXB0D0, TXB0D1, TXB0D2,…, TXB0D7: Estos registros contienen los bytes de

datos.

A continuación se explicaran con mas detalles algunos de los anteriores registros:

Registro TXB0CTRL

Los bits que forman este registro son los siguientes:

Figura 46: Bits del registro TXB0CTRL

• ABTF: Bit de solo lectura. Sirve para monitorizar el estado de la transmisión. Si

toma el valor 1 significa que el mensaje que se ha abortado, en caso de tomar el valor

0 indicaría que la transmisión se ha completado con éxito.

• MLOA: Bit de solo lectura. Al igual que en el caso anterior, sirve para ver el estado

de la transmisión. Si toma el valor 1 significa que el nodo ha perdido el arbitrio y

debe reintentar la transmisión.

• TXERR: Bit de solo lectura. Este bit indica si se ha detectado un error en el bus. Si

vale 1 significa que se ha detectado un error.

• TXREQ: Bit de lectura y escritura. Mediante este bit podemos iniciar la transmisión

de una trama y al mismo tiempo podemos ver su estado. Asignamos un 1 a este bit

se inicia la transmisión de una trama y cunado esta es finalmente enviada el valor del

bit vuelve a 0.

• TXP[1:0]: Bits de lectura y escritura. Mediante estos bits se puede configurar la

prioridad del mensaje. Esta prioridad no afecta a la prioridad del mensaje dentro del

bus sino que se utiliza para resolver conflictos internos como por ejemplo cuando se

pide iniciar la transmisión de mas de un buffer a la vez. Como solo se utilizara un

buffer el valor de estos bits no nos afectan.

Page 66: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

65

Registro TXB0SIDH

Figura 47: Bits del registro TXB0SIDH

Este registro contiene el byte de mas peso del identificador.

Registro TXB0SIDL

Figura 48: Bits del registro TXB0SIDL

Este registro contiene los 3 bits de menos peso del identificador de 11 bits o bien los bits 18,

19 y 20 del identificador de 29 bits.

También contiene el bit EXIDE. Este bit de lectura y escritura permite definir el tipo de

identificador de los mensajes. Si vale 1 se transmitirán mensajes con identificador extendido,

si vale 0 se transmitirán mensajes con identificador estándar.

Registros TXB0EID8 y TXB0EID0

Estos registros contienen los 16 bits de menos peso del identificador extendido. Solo se

utilizan cuando el bit EXIDE vale 1.

Proceso de transmisión de una trama

Teniendo en cuenta los registros que intervienen en la transmisión de los mensajes, podemos

seguir el siguiente procedimiento cada vez que se quiera enviar una trama a través del bus

CAN:

• Escribir la información de los campos de la trama a enviar a los registros

correspondientes. Esta información es el identificador, los bytes de datos y el número

de bytes de datos.

• Poner a 1 el bit T0REQ y esperar a que vuelva a valer 0. Esto nos indica que la

transmisión ha finalizado.

• Si uno de los bits T0ERR o MLOA se pone a 1 antes de que finalice la transmisión

significa que se ha producido un error y el controlador debe reintentar la transmisión.

Si el error persiste debemos abortar la transmisión poniendo un 0 en el bit T0REQ.

Con la información proporcionado en este apartado se pueden enviar tramas a través del bus

CAN.

Page 67: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

66

4.2.1.4.3 Recepción de mensajes

Configuración del filtro del buffer de recepción

Al igual que en la transmisión de mensajes, el MCP2515 dispone de varios buffers de

recepción. Cada buffer de recepción dispone de un filtro y una mascara que permiten aceptar

solo mensajes con un cierto identificador. Para esta aplicación solo se utilizará uno de los

buffers de recepción.

Los registros asociados al buffer de recepción son los siguientes:

• RXB0CTRL: Este registro contiene los bits asociados al estado del buffer de

recepción.

• RXB0SIDH, RXB0SIDL, RXB0EID8, RXB0EID8, RXB0DLC, RXB0D0,

RXB0D1, RXB0D2,…, RXB0D7: Estos registros contienen el valor de los campos

del mensaje recibido. Son registros equivalentes a los del buffer de transmisión pero

en este caso su valor depende de los mensajes recibidos.

• RXF0SIDH, RXF0SIDL, RXF0EID8, RXF0EID0, RXM0SIDH, RXM0SIDL,

RXM0EID8, RXM0EID0: Estos registros están asociados al filtro y la máscara del

buffer. Su función se explica más adelante.

Como se ha comentado anteriormente, el filtro y la mascara permiten descartar mensajes del

bus para que lleguen al microcontrolador solo un tipo de mensajes. Los registros para

configurar el filtro y la mascara son los siguientes: RXF0SIDH, RXF0SIDL, RXF0EID8,

RXF0EID0, RXM0SIDH, RXM0SIDL, RXM0EID8 y RXM0EID0.

En primer lugar se debe configurar el tipo de identificador al que queremos aplicar el filtro

y la máscara. Esto se realiza a través del bit EXIDE del registro RXF0SIDL. Si queremos

recibir tramas estándar tenemos que asignar un 1 al bit EXIDE, y en caso de querer recibir

tramas extendidas se tiene que asignar un 0.

Seguidamente se deben configurar los bits de la máscara. Mediante la máscara se puede

elegir los bits del identificador a los que se aplicará el filtro.

Si se ha configurado el buffer para recibir tramas estándar debemos asignar un valor solo a

los registros RXM0SIDH y RXM0SIDL, si se ha configurado para recibir tramas extendida

también se tendrá que asignar un valor a RXM0EID8 y RXM0EID0.

Ahora solo queda configurar los bits del filtro. El filtro solo se aplica a los bits que se han

indicado en la máscara, es decir, para que un mensaje sea aceptado todos los bits indicados

a la máscara deberán tener el valor indicado en el filtro.

Al igual que con la máscara, si se ha configurado el buffer para recibir tramas estándar

debemos asignar un valor solo a los registros RXF0SIDH y RXF0SIDL, si se ha configurado

para recibir tramas extendida también se tendrá que asignar un valor a RXF0EID8 y

RXF0EID0.

Page 68: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

67

Figura 49: Funcionamiento de la mascara de bits.

Para que el filtro sea aplicado no es suficiente con asignarle un valor, además, se debe activar

a través del registro RXB0CTRL. Dentro de este registro los bits asociados a la activación

del filtro son los bits RXM1 y RXM0. Para que el filtro esté activo se debe asignar un 0 a

ambos bits.

Proceso de recepción de mensajes

Cuando se transmite un mensaje a través del bus el MCP2515 lo recibe y seguidamente

aplica los filtros al identificador, si este cumple las condiciones del filtro se guarda en el

buffer de recepción y se pone a 1 el bit RX0IF del registro CANINTF. Entonces utilizando

el método de polling el microcontrolador puede percatarse de la recepción de un mensaje

para así obtener su contenido el cual está en los registros anteriormente mencionados.

Page 69: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

68

4.2.2 Circuito de la interfaz del ISO 15765-4

Figura 50: Circuito de la interfaz ISO 15765-4.

A continuación se recuerda la función de algunos de los componentes:

• R3: Esta resistencia de 120 Ohms es necesaria para evitar que se produzcan rebotes

en el BUS CAN.

• C5: Este condensador de 100 nF sirve para filtrar posibles ruidos en la

alimentación.

Page 70: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

69

4.3 Interfaz hardware entre el microcontrolador y el ordenador

4.3.1 Descripción de la interfaz

Con el fin de comunicarse con el equipo de test y poder gobernarlo desde otro dispositivo

(un ordenador por ejemplo) se debe establecer un sistema de comunicación a través del cual

se mande la información necesaria. Este sistema nos va a permitir:

• Mandar comandos al dispositivo para conectarse o desconectarse con el vehículo.

• Mandar comandos al dispositivo para modificar algunos parámetros.

• Enviar peticiones el vehículo.

• Recibir las respuestas mandadas por el vehículo.

Este sistema de comunicación debe ser un sistema punto a punto ya que nos interesa

controlar el equipo de test desde un solo dispositivo. Una solución barata y fácil de

implementar seria una comunicación mediante UART. Utilizando una UART solo

tendremos que diseñar la capa de enlace de nuestro sistema ya que la capa física ya está

implementada.

El único inconveniente que tenemos con esta solución es que actualmente no hay

ordenadores que dispongan de módulos UART para conectar periféricos externos. Una

solución seria utilizar un módulo bluetooth que disponga de UART para hacer de puente

entre la UART del equipo de test y el ordenador. El siguiente diagrama representa cómo

sería la conexión entre el equipo de test y el ordenador:

Figura 51: Diagrama de conexión entre el MCU, el HC-06 y el ordenador.

El módulo bluetooth que se utilizara es el HC-06. Cuando el ordenador se conecta al módulo

bluetooth, se crea un puerto serie (en el ordenador) a través del cual un programa puede

intercambiar bytes con el módulo.

Page 71: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

70

Cuando el módulo recibe un byte del ordenador, este byte es transmitido al microcontrolador

a través de la UART. Por otra parte, si el modulo recibe un byte del microcontrolador, este

byte es transmitido al ordenador. Es decir, todo lo que envía el ordenador se transmite al

microcontrolador y todo lo que envía el microcontrolador se transmite al ordenador.

Esto permite emular una conexión por puerto serie entre el microcontrolador y el

ordenador:

Figura 52: Conexión equivalente entre el escáner OBD2 y el ordenador.

4.3.2 Circuito de la interfaz

Figura 53: Circuito de la interfaz Bluetooth.

Page 72: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

71

4.4 El microcontrolador PIC18F4550

El microcontrolador es el cerebro del dispositivo objeto de este proyecto. Un

microcontrolador es un circuito integrado programable que dispone de una memoria en la

que se puede almacena un programa, esta memoria se denomina memoria de programa. Un

programa consiste en un conjunto de instrucciones que son interpretadas por el

microcontrolador. Estas instrucciones suelen indicar al microcontrolador que realice una

cierta operación con uno o varios datos (operaciones aritméticas, operaciones booleanas

etc.). Dentro del microcontrolador hay otra memoria denominada memoria de datos que es

la que contiene las variables del programa. Esta memoria de datos suele ser del tipo SRAM.

Además de las memorias, el microcontrolador dispone de una serie de periféricos que

realizan unas determinadas funciones. Los periféricos que podemos encontrar habitualmente

dentro de los microcontroladores son: UART, SPI, I2C, PWM, ADC, DAC etc.

Mediante un programa podemos configurar y operar estos periféricos ya que dentro de la

memoria de datos se reservan espacios de memoria o registros para cada uno de estos

dispositivos. Modificando los valor de estos registros podemos configurar estos periféricos

para que funcionen de una determinada forma. En caso de tratarse de periféricos de

entrada/salida (Entradas/salidas digitales, ADC, DAC etc.) podemos obtener o mandar los

datos realizando una lectura o escritura a los registros correspondientes.

Dentro de este proyecto el microcontrolador será el encargado de implantar los dos

protocolos OBD2 elegidos (ISO9141-2 y ISO 15765-4). Esto supone que tendrá que utilizar

el hardware anteriormente descrito más otros módulos que llevará integrados dentro del

propio silicio. Además, tendrá que integrar otro protocolo de comunicación que será el que

permitirá mandarle ordenes desde un ordenador. Estas ordenes permitirán hacer peticiones

al sistema OBD2 de un automóvil o bien modificar la configuración del propio dispositivo.

En el mercado existe una gran variedad de microcontroladores, esto permite al desarrollador

elegir el más adecuado a su proyecto. Para este proyecto se ha decidido utilizar

microcontrolador PIC18F4550. Este microcontrolador es desarrollado y fabricado por la

empresa Microchip Technology inc. la cual se encuentra en el top de empresas fabricantes

de semiconductores.

El PIC18F4550 es un microcontrolador de 8 bits con arquitectura RISC (Reduced Instruction

Set Computer). Como su propio fabricante indica, el diseño de este microcontrolador es apto

para que sea utilizado dentro de la industria del automóvil con lo cual es una opción acertada

para este proyecto.

Page 73: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

72

A continuación se mostraran algunas de las características de este dispositivo, esto incluye

su memoria, los periféricos de los que dispone, sus características eléctricas etc.

Característica Valor

Tipo de memoria de programa Flash

Tamaño memoria de programa 32 KB

Velocidad máxima CPU (MIPS) 12

Tipo memoria de datos SRAM

Tamaño memoria de datos 2048 Bytes

Tamaño memoria EEPROM 256 Bytes

Periféricos de comunicación 1 UART, 1 SPI, 1 I2C, 1 USB

Conversor ADC 13 canales y 10 bits

Rango de temperatura -40 a 85 °C

Tensión de alimentación 2 a 5,5 V

Tabla 22: Algunas características del PIC18F4550.

Estas son solo algunas de las características de este microcontrolador. Toda la información

acerca de este dispositivo se encuentra en la hoja de datos proporcionada por el fabricante.

Este apartado se explicará el hardware que se ha tenido que añadir para que el

microcontrolador funcione correctamente. Además, se explicará la configuración aplicada a

los periféricos que se han utilizado.

4.4.1 Componentes externos del PIC18f4550

4.4.1.1 Circuito oscilador.

El oscilador que se utilizará es un oscilador de cristal de 4 MHz.

Figura 54: Oscilador de cristal de 4 MHz.

El siguiente esquema indica como se debe conectar el oscilador de cristal al

microcontrolador:

Figura 55: Esquema de conexión del oscilador.

Los componentes C1 y C2 son condensadores cerámicos de 22 pF.

Page 74: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

73

4.4.1.2 Circuito de reset del microcontrolador

Es necesario disponer de un mecanismo de reset para reiniciar el microcontrolador y llevarlo

a un estado conocido. Hay diversos mecanismos a través de los cuales se puede realizar un

reset del microcontrolador, el más habitual es utilizando un pin denominado MCLR.

El microcontrolador PIC18F4550 permite reset por hardware a través del pin MCLR por lo

que será el mecanismo usado en este dispositivo. Para poder hacer un reset a través de este

pin se debe añadir el siguiente circuito:

Figura 56: Circuito de reset del PIC18F4550.

Cuando el pin MCLR se encuentra en un potencial alto (5 V), el PC (program counter) se

incrementa con cada flanco del señal de reloj de la CPU con lo cual el MCU está ejecutando

el programa. En cambio cuando esta en un potencial bajo (0 V) el PC se reinicia a 0 (o a la

dirección de inicio del programa) y se mantiene en ese valor con lo que se paraliza la

ejecución del programa.

Si se aprieta el pulsador del circuito anterior, el contador del programa vuelve a la primera

instrucción y se mantiene durante el tiempo que se esta apretando el pulsador. Una vez se

deja de pulsar el PC vuelve a correr con lo que se vuelve a ejecutar el programa pero desde

la primera instrucción. Así es como se consigue realizar un reset del microcontrolador.

El Condensador C2 tiene la función de filtrar los efectos de los rebotes producidos al

accionar el polsador. Su valor típico es de 100 nF.

4.4.2 Configuración del oscilador

Una de las primeras cosas que se deben configurar dentro del microcontrolador es su señal

de reloj. Esta consiste en una señal cuadrada y tiene la función de marcar el ritmo de

ejecución de las instrucciones. En el caso de este microcontrolador, se ejecuta una

instrucción cada 4 flancos de la señal de reloj. Por lo tanto la frecuencia de ejecución de las

instrucciones depende directamente del señal de reloj utilizado, la expresión que los

relaciona es la siguiente:

𝑓𝑐𝑦𝑐 =𝑓𝑜𝑠𝑐

4 (12)

Page 75: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

74

Esta frecuencia de reloj suele proveer de un circuito externo aunque hay microcontroladores,

como es el caso, que disponen de un oscilador interno que proporciona este señal.

Para este proyecto se ha decidido utilizar un oscilador externo ya que se requiere de precisión

y estos suelen ser mas precisos que los internos.

El oscilador utilizado en este proyecto es un oscilador de cristal de cuarzo del tipo XT (X-

Tall). Hay otro tipo de osciladores como los HS (High Speed) que permiten frecuencias

mayores. Para este proyecto es suficiente con un oscilador del tipo XT.

El PIC18F4550 permite conectar varias fuentes de reloj aunque solo una de ellas puede ser

utilizada por la CPU. Además, en cada fuente de reloj permite conectar diversos tipos de

osciladores.

El siguiente diagrama muestra la conexión interna de las distintas fuentes de reloj de las que

dispone el MCU.

Figura 57: Clock Diagram del PIC18F4550.

En este caso queremos conectar el oscilador a la fuente primaria. Tal y como se puede

observar, la señal del oscilador puede seguir diversos caminos hasta llegar a la CPU. Entre

Page 76: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

75

uno de estos caminos se encuentra un componente denominado PLL. Este dispositivo es

capaz de obtener un señal de reloj de 96 MHz a partir de uno de 4 MHz. Para que la CPU

pueda utilizar este camino, el multiplexor indicado en la figura debe estar configurado para

que conecte su salida con la entrada 1. Además del PLL, este camino dispone de una serie

de multiplexores y divisores. La función de estos componentes es la de adaptar las señales

de entrada y salida del PLL. Como se ha mencionado la señal de entrada del PLL debe ser

de 4 MHz, si esta señal tiene otra frecuencia el dispositivo no funcionara correctamente.

El bloque divisor situado a la entrada del PLL multiplica la señal del oscilador por una serie

de ganancias, estas son 1/1, 1/2, 1/3, 1/4, 1/5, 1/6, 1/10 y 1/12. Mediante el multiplexor

conectado al divisor podemos elegir que señal de las obtenidas por el divisor queremos

conectar a la entrada del PLL.

A la salida del PLL tenemos una configuración parecida a la que hay en la entrada. Un bloque

divide la frecuencia de la señal de salida del PLL y obtiene una serie de señales cuyas

frecuencias son 48, 32, 24 y 16 MHz. Mediante otro multiplexor podemos elegir cuál señal

utilizar como señal de reloj de la CPU.

En este caso se dispone de un oscilador de cristal de 4 MHz y queremos hacer funcionar la

CPU a 48 MHz. Teniendo en cuenta los elementos anteriormente descritos y las variables

que influyen, para obtener la frecuencia de 48 MHz debemos utilizar la configuración

descrita a continuación.

La siguiente tabla muestra los registros de configuración del dispositivo, entro los cuales se

encuentran los relacionados con la configuración de la señal de reloj.

Tabla 23: Registros de configuración del PIC18F4550.

Los registros que debemos modificar son CONFIG1L y CONFIG1H. Los valores que se

tiene que asignar a estos registros son los siguientes.

Page 77: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

76

CONFIG1L

Figura 58: Bits del registro CONFIG1L.

El valor de este registro debe ser de 0x20.

CONFIG1H

Figura 59: Bits del registro CONFIG1H.

El valor de este registro debe ser de 0x3.

4.4.3 Periféricos del microcontrolador

En este apartado se explica con detalle la configuración de los periféricos del

microcontrolador PIC18F4550 utilizados para este proyecto. Estos periféricos son: UART,

SPI, Timer 0 y Timer 3.

4.4.3.1 El módulo UART

Como se ha explicado en apartados anteriores, la UART es un módulo que permite que dos

dispositivos establezcan una comunicación punto a punto y full-dúplex. Para este proyecto

la UART se utilizará para establecer comunicación con vehículos que dispongan del

protocolo ISO9141-2.

En el caso del PIC18F4550, el pin RX de la UART corresponde al pin 26 del MCU y el pin

TX corresponde al pin 25.

A continuación se explicará la configuración que se debe aplicar para que la UART funcione

correctamente.

Los registros asociados al modulo UART son los siguientes:

• TXSTA: Permite controlar y ver el estado de las transmisiones.

• RCSTA: La misma función que el anterior pero para las recepciones.

• BAUDCON: Permite configurar la tasa de bits.

Page 78: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

77

Debemos asignar el valor correcto a estos registros para que la UART trabaje con la

configuración 8N1 y tenga una tasa de bits de 10,4 kbps.

Registro TXSTA

Este registro dispone de los siguientes bits:

Figura 60: Bits del registro TXSTA.

• CSRC: Este bit solo se aplica si la UART trabaja en modo síncrono, como no es el

caso no importa su valor.

• TX9: Este bit permite habilitar la transmisión de 9 bits. Queremos que la UART

transmita 1 byte por lo que se debe asignar un 0 a este bit.

• TXEN: Mediante este bit se habilita la transmisión. Su valor debe ser 1.

• SYNC: Este bit permite elegir el modo síncrono o asíncrono de la UART. En este

caso queremos el modo asíncrono y por eso se debe asignar un 0.

• BRGH: Este bit permite elegir entre el modo rápido o el modo lento de la UART.

Como queremos transmitir a 10,4 kbps y esta es una tasa de bits lenta, se debe elegir

el modo lento y para ello se tiene que asignar un 0 a este bit.

• TRMT: Mediante este bit podemos saber el estado de una transmisión, si esta a 0

significa que todavía se esta transmitiendo un byte, en caso contrario, el buffer de

transmisión esta vacío.

• TX9D: Este bit solo se aplica en la transmisión de 9 bits.

Registro RCSTA

Este registro dispone de los siguientes bits:

Figura 61: Bits del registro RCSTA.

• SPEN: Sirve para habilitar el puerto serie. Su valor debe ser 1.

Page 79: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

78

• RX9: Este bit activa la recepción de 9 bits. Como en el caso de la transmisión

queremos recibir solo 8 bits de datos por lo que se le debe asignar un 0.

• SREN: Este bit no se aplica en el modo asíncrono.

• CREN: Este bit habilita la recepción de datos por lo que debe valer un 1.

• ADDEN: Este bit no se aplica en el modo de 8 bits.

• FERR: Indica que se ha producido un error en la trama.

• OERR: Cuando se sobrescribe el buffer de recepción antes de que sea leído se pone

a 1 este bit.

• RX9D: Este bit no se aplica en el modo de 9 bits.

Registro BAUDCON

Este registro dispone de los siguientes bits:

Figura 62: Bits del registro BAUDCON.

Los bits que debemos inicializar para ajustar la tasa de bits son los siguientes:

• BRG16: Este bit permite determinar la longitud del BRG(baud rate generator) la cual

puede ser de 8 o 16 bits. Cuanto mayor sea la longitud del BRG menor podrá ser la

tasa de bits. Como el microcontrolador funcionara a una frecuencia relativamente

alta (48 MHz) y la tasa de bits que se requiere es baja, conviene tener un BRG mayor.

Por lo tanto, debemos elegir la opción de 16 bits asignando un 1 a este bit.

Configuración de la tasa de bits.

La tasa de bits con la que transmite y recibe la UART depende de un valor n de 16 bits

almacenado en los registros SPBRGH y SPBRG. La expresión que relaciona este valor con

la tasa de bits es la siguiente:

𝑏𝑎𝑢𝑑𝑖𝑜𝑠 =𝐹𝑜𝑠𝑐

4(𝑛 + 1)→ 𝑛 =

𝐹𝑜𝑠𝑐 − 4 · 𝑏𝑎𝑢𝑑𝑖𝑜𝑠

4 · 𝑏𝑎𝑢𝑑𝑖𝑜𝑠 (13)

Si se quiere una tasa de bits de 10,4 kbps:

Page 80: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

79

𝑛 =48 · 106 − 4 · 10400

4 · 10400= 1152 (14)

Los registros SPBRGH y SPBRG deben tener los valores 4 y 128, respectivamente

Transmisión de datos

Una vez configurado correctamente el modulo UART, el procedimiento a seguir para enviar

1 byte al otro nodo es el siguiente:

• Para iniciar la transmisión se debe escribir en el registro TXREG el byte que se desea

enviar.

• Una vez iniciada la transmisión se debe esperar a que termine. Cuando la transmisión

finaliza se pone a 1 el bit TXIF por lo que realizando polling sobre este bit el MCU

puede saber cuando a terminado la transmisión.

• Finalmente se tiene que poner un 0 al bit TXIF para dejarlo preparado para la

siguiente transmisión.

Recepción de datos

Para la recepción de datos se debe seguir el siguiente procedimiento:

• El MCU debe esperar a que se reciba un byte y para ello debe realizar polling sobre

el bit RCIF. Este bit se pone a 1 cuando se recibe un byte.

• Una vez recibido el byte se debe leer a través del registro RCREG.

• Finalmente se debe volver a poner un 0 al bit RCIF para dejarlo preparado para la

siguiente recepción.

4.4.3.2 El módulo SPI

Para que el microcontrolador pueda comunicarse con el integrado MCP2515 y establecer

una conexión con vehículos que implementen el protocolo ISO 15765-4 se debe utilizar el

modulo SPI en modo master. En este apartado se explicará todo lo relacionado con la

configuración de este módulo así como las conexiones que se deben realizar entre el

PIC18F4550 y el MCP2515.

Este microcontrolador dispone de un módulo denominado MSSP (Master Síncronos Serial

Port) el cual implementa los protocolos SPI (Master/Slave) y I2C (Master/Slave), aunque no

puede funcionar con los dos a la vez. Por lo tanto, en primer lugar se debe configurar para

que funcione como SPI o I2C. Los registros asociados con en modo SPI del MSSP son los

siguientes:

• SSPCON1: es el registro de control del SPI.

Page 81: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

80

• SSPSTAT: es el registro de estado.

• SSPBUF: es el buffer de transmisión/recepción.

Registro SSPSTAT

Figura 63: Bits del registro SSPSTAT.

• SMP: Mediante este bit se elige el momento en el que se muestrea la señal del pin

SDI. En este caso queremos que se muestre en el medio del tiempo de bit y para ello

el bit SMP debe valer 0.

• El bit CKE junto al bit CKP (registro SSPCON1) permiten elegir el modo con el debe

funcionar el SPI. Existen 4 modos de funcionamiento: Modo 0.0, Modo 1.1, Modo

0.1 y Modo 1.0. Estos modos se diferencian en el estado de reposo de la señal de

reloj y en que flanco (ascendente o descendente) se envían los bits. La siguiente

figura muestra la configuración de cada modo:

Figura 64: Señal de SCK para los diferentes modos del SPI.

En la siguiente figura se encuentran los valores de CKP y CKE para cada uno de los

modos:

Tabla 24: Valores de CKP y CKE para cada uno de los modos.

Page 82: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

81

El integrado MCP2515 esta preparado para que funcione con modo 1,1 por lo que debemos

configurar el PIC para que funcione en este mismo modo. Tal y como se puede observar en

la figura, para el modo 1,1 los bits CKP y CKE deben valer 1 y 0 respectivamente.

• BF: Este bit indica el estado del buffer. Si vale 1 significa que se ha finalizado la

recepción y el buffer SSPBUF esta lleno, en caso contrario, la recepción no ha

finalizado todavía.

Registro SSPCON1

Figura 65: Bits del registro SSPCON1.

• WCOL: Este bit indica cuando se produce una colisión en el buffer SSPBUF, es

decir, cuando este registro es modificado durante una transmisión.

• SSPEN: Mediante este bit se activa el MSSP. Para activarlo el bit debe valer 1.

• SSPM3:SSPM0: Mediante estos bits se puede configurar el modo y la frecuencia de

funcionamiento del MSSP. La siguiente figura muestra el modo de funcionamiento

para cada caso:

Figura 66: Valores de SSPM3:SSPM0 para cada modo y frecuencia del SPI.

Queremos que funcione como SPI en modo master y a una frecuencia de FOSC/16 por lo

que los bits SSPM3:SSPM0 deben valer 0001.

Configuración de los pines del modulo MSSP

Para que este módulo pueda funcionar como SPI, los pines del MCU asociados al modulo

deben estar configurados de una forma concreta.

La configuración a aplicar es la siguiente:

Page 83: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

82

• SDI: Se debe inicializar como entrada digital (TRISB<0> = 1).

• SDO: Se debe inicializar como salida digital(TRISC<7> = 0).

• SCK: También se debe inicializar como salida(TRISB<1> = 0).

• CS: Este pin debe ser una salida digital. Tal y como se puede observar en la figura,

este pin no esta definido sino que puede ser cualquier pin que pueda funcionar como

salida digital. En este caso se ha utilizado el pin RB2

Transmisión de bytes:

Para poder enviar un byte a través del modulo SPI se debe seguir el siguiente procedimiento:

• En primer lugar se debe poner el pin CS en un potencial bajo, esto indica al otro nodo

que se ha inicializado una transmisión.

• Posteriormente se debe escribir el byte a enviar en el registro SSPBUF. Esto inicia

automáticamente la transmisión.

• El MCU debe esperar a que finalice la transmisión realizando polling al bit BF.

Cuando este bit valga 1 se debe dar la transmisión por finalizada. Este paso se puede

realizar por cada byte que se quiera enviar.

• Finalmente se debe poner el pin CS en un potencial alto para indicar que la

transmisión ha finalizado.

Recepción de bytes

En este caso el procedimiento es muy parecido al anterior:

• En primer lugar se debe poner el pin CS en un potencial bajo.

• Posteriormente se debe escribir cualquier cosa en el registro SSPBUF. Esto inicia

automáticamente la recepción del byte.

• El MCU debe esperar a que finalice la recepción de la misma forma que en el caso

anterior. Una vez finalizada la recepción se debe leer el registro SSPBUF para

guardar el byte recibido en otro espacio de memoria. Este paso se puede realizar para

cada uno de los bytes que se quieren recibir.

• Finalmente se debe poner el pin CS en un potencial alto para indicar que la recepción

ha finalizado.

Page 84: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

83

4.4.3.3 El Timer 0

El microcontrolador PIC18F4550 dispone de varios módulos timer como es el TIMER0. Un

módulo timer consiste básicamente en un contador que se incrementa cuando se produce un

flanco de una señal cuadrada. El uso principal que se le da a los timers es como base de

tiempo para el MCU.

En este caso el TIMER0 se utilizara para generar una interrupción de tiempo cada 1 ms así

se obtiene una basa de tiempo para los retardos.

Los registros asociados al TIMER0 son los siguientes:

• T0CON: Permite configurar el timer

• TMR0: Este registro es el contador del timer.

Registro T0CON

Figura 67: Bits del registro T0CON.

• TMR0ON: Este bit activa o desactiva el timer. Para activarlo debe estar a 1.

• T08BIT: Este bit determina la longitud del contador del timer, es decir, del registro

TMR0. Si este bit esta a 1 el tamaño de TMR0 es de 8 bits, en caso contrario es de

16 bits. Queremos un contador de 8 bits por lo que este bit debe valer 1.

• TOCS: Este bit permite elegir la señal del timer la cual puede ser externa (a través

del pin T0CKI) o interna (Fcyc). En este caso se utilizara la interna por lo que este

bit debe valer 0.

• T0SE: Este bit permite elegir entre incrementará el contador en cada flanco

ascendente o en cada flanco descendente.

• PSA: Este MCU dispone de un prescaler que divide la señal de reloj de la CPU y

obtiene otra señal que se puede utilizar para el timer 0. Para que la señal del timer 0

sea la de la salida del prescaler el bit PSA debe valer 0.

• T0PS2:T0PS0: Estos bits permiten elegir la ganancia del prescaler. En este caso

queremos una ganancia de 1/128 por lo que debemos asignar a T0PS2:T0PS0 los

valores 1100. Aplicando esta ganancia y considerando que Fcyc = 12 MHz tenemos

que el TIMER0 funcionará a 93750 Hz

Page 85: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

84

4.4.3.4 El Timer 3

Como se ha dicho en el apartado anterior, el PIC18f4550 dispone de varios timers. Para este

proyecto se necesita más de un timer por lo que debemos configurar otro a parte del

TIMER0. Este segundo timer es el TIMER3 y su función va a ser la de generar el tiempo de

bit para una UART por software (explicada más adelante). Aunque la UART por software

transmitirá a una baja tasa de bits (9600 baudios), la resolución que ofrece el TIMER0 no es

suficiente para generar el tiempo de bit. Por esta razón se debe configurar otro timer que

trabaje a una frecuencia mayor.

El TIMER3 es un timer de 16 bits el cual dispone de los siguientes registros:

• T3CON: Registro de configuración del timer.

• TMR3H: byte de mas peso del contador del TMR3.

• TMR3L: byte de menos peso del contador del TMR3.

Registro T3CON

Figura 68: Bits del registro T3CON.

• RD16: Mediante este bit se configura el modo de lectura/escritura del contador del

timer, el cual es de 16 bits. En el primer modo las operaciones de lectura/escritura

del contador se realizan mediante los registros TMR3L y TMR3H por separado. En

el segundo modo al realizar una operación sobre el registro TRM3L se guarda el byte

de más peso del contador en ese instante en el registro TMR3H. En caso se

configurará el segundo modo ya que permite evitar errores de lectura/escritura, para

ello el bit debe valer 1.

• T3CKPS1:T3CKPS0: Estos bits permiten elegir la ganancia del prescaler de

entrada del TIMER3. En este caso se asigna a T3CKPS1:T3CKPS0 de 0b10 con lo

que se obtiene una ganancia de 1/4. Esto supone que el TIMER3 trabajara a una

frecuencia de 3 MHz.

• TMR3CS: Mediante este bit se elige la fuente de la señal del TIMER3. Queremos

que esta sea Fcyc por lo que se debe asignar un 0 a este bit.

• TM3ON: Este bit permite activar o desactivar el timer, para activarlo se le debe

asignar un 1.

Page 86: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

85

4.4.4 Circuito del microcontrolador

Figura 69: Circuito del MCU PIC18F4550.

Como los módulos SPI y UART comparten el pin RC7, se debe añadir la resistencia R1 de

1k Ohm para aislar las señales y que los módulos no interfieran entre ellos. Añadir esta

resistencia no implica que se puedan utilizar a la vez, esto solo permite que un módulo pueda

estar activo sin que el otro (inactivo) afecta a sus señales.

4.5 Circuito de alimentación

4.5.1 Módulo Mini-360

Como se puede ver en los apartados anteriores muchos de los componentes que se utilizan

requieren una tensión de +5 V, sin embargo, el conector OBD2 solamente ofrece una tensión

de +12 V. Por esta razón se debe añadir un circuito que convierta los +12 V a +5V. La

solución que se implantará consiste en utilizar un convertidor buck realimentado que permita

bajar la tensión a +5 V. El uso de un convertidor buck realimentado permite que se mantenga

una salida de +5V aunque se produzcan variaciones en la tensión de entrada.

Figura 70: Módulo Mini-360

Page 87: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

86

El módulo que se utilizará dispone del convertidor Buck MP1584. Este módulo ya viene con

todos los componentes necesarios para que funcione el convertidor. La tensión de salida se

ajusta mediante un potenciómetro.

Características del módulo:

Característica

Tensión de entrada 4.75 – 23 V

Tensión de salida 1 – 17 V

Corriente de salida máxima 3 A de pico y 1.8 A en régimen permanente

Eficiencia 96 %

Regulación de carga +/- 0.5%

Regulación de linea +/- 2.5%

Tabla 25: Características del convertidor Buck.

4.5.2 Circuito del módulo

Figura 71: Circuito del módulo Mini-360

Tal y como se puede ver en el esquema anterior, simplemente se deben conectar los +12 V

a la entrada y se obtienen los +5 V que se necesitan.

Page 88: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

87

4.6 Circuito completo

Page 89: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

88

Page 90: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del hardware

89

BOM (Bill Of Materials)

ID Designator Type Value Quantity

1 U2 Connector OBD2 Male connector 1

2 U3 IC MC33290 1

3 R2 Resistor 500R 1

4 U4 IC MCP2515 1

5 U5 IC TJA1050 1

6 R3 Resistor 120R 1

7 C3,C4 Capacitor 15pF 2

8 X2,X3 Oscillator 16 MHz 2

9 C5 Capacitor 100nF 1

10 U6 Module buck mini 360 1

11 HC-1 Module hc-06 1

12 U7 IC PIC18F4550- I/PT 1

13 R4,R1 Resistor 1k 2

14 KEY2 Switch - 1

15 C6,C7 Capacitor 22pF 2

Tabla 26: BOM del circuito

Page 91: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Protocolo de comunicación entre el dispositivo OBD2 y el ordenador

90

5. Protocolo de comunicación entre el dispositivo OBD2 y el ordenador

En el apartado 4.3 se ha definido el hardware que se utilizará para enviar la información

entre los dos nodos. En este apartado se explicarán el formato de las tramas que se

intercambiaran los nodos, es decir, se definirá la capa de enlace.

Para esta aplicación vamos a implementar los siguientes tipos de trama:

• Trama de request: A través de esta trama el ordenador puede pedir un PID de un

determinado servicio.

• Trama de respuesta: A través de esta trama el equipo de test envía la respuesta del

vehículo al ordenador.

• Trama de comando: A través de esta trama el ordenador puede enviar un

comando al equipo de test.

• Trama de confirmación de comanda: Mediante esta trama el equipo de test

confirma la realización de una comanda.

• Trama de respuesta negativa: A través de esta trama el equipo de test indica al

ordenador que se ha producido un error.

Trama de request

Campos de la trama y longitud:

<0x2><service><PID><checksum>

• 0x2: Es el byte que identifica la trama.

• Service: Este byte indica el servicio al cual pertenece el PID.

• PID: como su nombre indica, es el PID del cual se quiere conocer su valor. Los

limites de este campo no están definidos.

• Checksum: es el checksum de la trama. El tamaño es de un byte.

Trama de respuesta

Campos de la trama y longitud:

<0x1><service><PID><dataLen><data><checksum>

Page 92: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Protocolo de comunicación entre el dispositivo OBD2 y el ordenador

91

• 0x1: Es el byte que identifica la trama.

• Service: Este byte indica el servicio al cual pertenece el PID.

• PID: como su nombre indica, es el PID del cual se quiere conocer su valor. Los

limites de este campo no están definidos.

• dataLen: Este byte indica la longitud del campo de datos.

• data: Dentro de este campo se encuentra la respuesta del vehículo. La longitud está

limitada por el valor máximo de dataLen, que es 255.

• Checksum: es el checksum de la trama. El tamaño es de un byte.

Trama de comanda

Campos de la trama y longitud:

<0x3><command><paramsLen><params><checksum>

• 0x3: Es el byte que identifica la trama.

• Command: Es el byte que indica la comanda a realizar.

• paramsLen: este byte indica la longitud del campo params.

• Params: Son los bytes de los parámetros relativos a la comanda. Su longitud no

esta definida.

• Checksum: es el checksum de la trama. El tamaño es de un byte.

Trama de error

Campos de la trama y longitud:

<0x4><errorCode><checksum>

• 0x4: Es el byte que identifica la trama.

• errorCode: Este byte indica el código del error.

• Checksum: es el checksum de la trama. El tamaño es de un byte.

Page 93: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Protocolo de comunicación entre el dispositivo OBD2 y el ordenador

92

Trama de confirmación de comanda

Campos de la trama y longitud:

<0x5><command><paramsLen><params><checksum>

• 0x5: Es el byte que identifica la trama.

• Command: Es el byte que indica la comanda a realizar.

• paramsLen: este byte indica la longitud del campo params.

• Params: Son los bytes de los parámetros relativos a la comanda. Su longitud no

esta definida.

• Checksum: es el checksum de la trama. El tamaño es de un byte.

Flujo de tramas entre el dispositivo obd2 y el ordenador

Dentro de este sistema de comunicación formado por el dispositivo OBD2 y el ordenador,

el nodo que toma el papel de master es el ordenador. El dispositivo OBD2 nunca puede

iniciar la comunicación, está siempre es iniciada por el ordenador y el dispositivo OBD2

simplemente responde.

Las tramas que puede utilizar el ordenador para iniciar la comunicación son la trama de

request y la trama de comanda. Ante esta petición, el dispositivo OBD2 puede responder con

las siguientes tramas: trama de respuesta, trama de error y trama de confirmación de

comanda.

En las siguientes figuras se puede ver los distintos intercambios que pueden haber:

Figura 72: Envío de una trama request y recepción de una trama respuesta

Page 94: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Protocolo de comunicación entre el dispositivo OBD2 y el ordenador

93

Figura 73: Envío de una trama request y recepción de una trama error.

Figura 74: Envío de una trama comanda y recepción de una confirmación.

Page 95: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Protocolo de comunicación entre el dispositivo OBD2 y el ordenador

94

Figura 75: Envío de una trama comanda y recepción de una trama error.

Page 96: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del software

95

6. Desarrollo del software

En este apartado se explicara todo lo relacionado con el proceso de desarrollo del software

así como el software en sí.

El programa que se grabará en el microcontrolador está escrito en embedded C y se ha

utilizado el entorno de desarrollo MPLAB X IDE v5.10 para su elaboración. También se ha

utilizado el programa el mismo programa para grabar el código al MCU a través del

programador PICKIT3.

6.1 Objetivo del software

El primer paso en el desarrollo del software es determinar cuáles serán sus funcionalidades.

Para este proyecto, el código elaborado debe implementar las siguientes funcionalidades:

• Inicializar y configurar todos los periféricos que se deben utilizar para el proyecto.

Ejemplos de estos periféricos son la UART o el SPI.

• El programa debe implementar los protocolos ISO 9141-2 e ISO 15765-4. Esto

implica desarrollar el software para implementar y gestionar las distintas capas del

protocolo. Para las capas físicas se deben elaborar los drivers que permitan

gestionar el hardware estas capas, en el caso de del ISO 15765-4 se deben diseñar

todo un conjunto de funciones para controlar el integrado MCP2515.

• También se debe implementar el protocolo de comunicaciones entre el escáner

OBD2 y el ordenador. Para esta parte se debe desarrollar una UART por software

ya que el PIC18F4550 solo dispone de 1 UART, la cual es utilizada para el ISO

9141-2.

• Por último el programa debe ser capaz de gestionar todos los protocolos

implementados para que el usuario pueda utilizarlos desde el ordenador. Esta parte

seria la interfaz entre los protocolos del sistema OBD2 y el protocolo de

comunicación entre el escáner OBD2 y el ordenador.

En resumen el programa debe gestionar las comunicaciones entre el ordenador y el escáner

OBD2 y entre el escáner OBD2 y el vehículo, tal y como se muestra en la siguiente figura.

Figura 76: Interacción entre el ordenador, el escáner OBD2 y el vehículo.

Page 97: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del software

96

6.2 Proceso de desarrollo del software

En este apartado se explicará el procedimiento seguido para desarrollar el software y las

herramientas utilizadas durante el proceso.

En primer lugar se debe preparar el entorno de desarrollo del software, este es el MPLAB X

IDE v5.10. Este programa informático permite escribir código en C, C++ y ASM

(Ensamblador) aunque solo se utilizará para programar en C.

Figura 77: Entorno de desarrollo del MPLAB.

Descargada e instalada la herramienta, se debe proceder a instalar el compilador adecuado

al microcontrolador que se quiere utilizar. El compilador es el encargado de traducir el

programa escrito en C a lenguaje máquina que es el que entiende el microcontrolador. Existe

un compilador para cada arquitectura de MCU, en este caso necesitamos un compilador para

microcontroladores de 8 bits. El compilador que finalmente se ha instalado es el XC8 v2.0.

Una vez preparado el entorno de desarrollo (MPLAB v5.10 + XC8 v2.0) se debe crear y

configurar un proyecto. El procedimiento a seguir es muy intuitivo gracias a su entorno

grafico.

Creado el proyecto ya podemos añadir los ficheros en los que se escribirá el código de

nuestro programa.

Page 98: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del software

97

A partir de aquí empieza el proceso de desarrollo del software. Podemos representar este

proceso mediante el siguiente diagrama:

Figura 78: Diagrama del proceso de desarrollo del software.

El programa MPLAB también incluye una herramienta de simulación mediante la cual

podemos realizar una primera revisión del código. Una vez asegurado que el código tenga

el comportamiento deseado se debe proceder a programar el microcontrolador mediante el

PICKIT3 y el programa informático.

Page 99: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del software

98

Figura 79: Dispositivo programador PICKIT3.

Este dispositivo debe estar conectado al ordenador y al microcontrolador. La conexión al

ordenador se realiza mediante un puerto USB y la conexión al microcontrolador se realizar

a través de los pines VPP, VDD, VSS, PGD, PGC de ambos dispositivos (MCU y PICKIT3).

En primer lugar se debe realizar la programación en modo debug, este modo permite grabar

y ejecutar el programa teniendo control del MCU desde el MPLAB. En este modo se puede

pausar la ejecución del código, reanudarla, pausarla en un punto concreto indicado mediante

breakpoints, ver la memoria de datos etc.

Este modo permite realizar una revisión más exhaustiva del programa escrito. Finalizada la

revisión en modo debug se puede proceder a grabar el código en el modo normal. Si en el

modo debug se observa algún problema se debe reiniciar el proceso para poder corregirlo.

Con esto se da por acabado el proceso de desarrollo del software.

El proceso descrito en este apartado es muy generalista ya que este puede variar según el

proyecto del que se trate.

6.3 Descripción del software

Las funciones desarrolladas se pueden dividir en las siguientes categorías:

• Funciones generales: para el manejo de los periféricos utilizados (UART, SPI,

TIMERS etc.) y otras funciones que no están directamente relacionadas con la

implantación de los protocoles OBD2.

• Funciones del ISO 9141-2: funciones que en conjunto implementan dicho

protocolo.

• Funciones del ISO 15765-4: ídem. Se incluye además el driver del MCP2515.

• Funciones del protocolo propio: Implementan el protocolo entre el equipo de test

y el ordenador.

Page 100: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del software

99

• Función main() y initProtocol(): gestionan las tramas recibidas desde el ordenador.

Las estructuras de datos a las que se hacen referencia se encuentran dentro del archivo

Types.h(ver en anexos).

6.3.1 Funciones generales

long pow(char baseNumber, char exponentNumber)

Esta función realiza la operación baseNumberexponentNumber y la devuelve el resultado.

void setPinMode(uchar* port, uchar pin, uchar mode)

Esta función permite configurar un determinado pin como entrada o salida digital (siempre

que sea un pin de entrada/salida).

void setPin(uchar* port, uchar pin)

Esta función pone a 1 una determinada salida digital.

void resetPin(uchar* port, uchar pin)

Esta función pone a 0 una determinada salida digital.

uchar readPin(uchar* port, uchar pin)

Esta función devuelve el estado (1 o 0) de una determinada entrada digital.

void initTMR0()

Esta función inicializa el TIMER0 de acuerdo a las especificaciones determinadas en el

apartado 4.4.3.3.

void initSPIMaster()

ídem para el modulo SPI.

uchar transferSPI(uchar byteToSend)

Mediante esta función se puede realizar una transferencia a través del SPI. byteToSend es el

byte a enviar y el byte recibido lo devuelve la función.

void wait(uint delay)

Esta función permite realizar retardos. El retardo se indica en ms a través de la variable delay.

void initTMR3()

Page 101: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del software

100

Esta función inicializa el TIMER3.

void initSoftwareUART()

Esta función inicializa una UART por software. Los pines TX y RX de esta UART están

fijados a RD2 y RD1 respectivamente. La tasa de bits a la que transmite y recibe esta UART

es de 9600 baudios.

sendByteSoftwareUART(uchar byteToSend)

Esta función envía un byte a través de la UART por software.

uchar receiveByteSoftwareUART(uchar* receivedByte)

Mediante esta función se puede recibir un byte a través de la UART por software. La función

devuelve un 1 o un 0 según se ha recibido el byte a tiempo o bien se ha producido un timeout.

En caso de recibir el byte, se guarda a la dirección apuntada por receivedByte.

uchar reverseByte(uchar x)

Esta función permite invertir el orden de los bits de un byte. El byte a invertir debe estar en

la variable x y el resultado es devuelto por la función.

void initUart()

Esta función inicializa el modulo UART del MCU.

void closeUart()

Esta función desactiva el modulo UART. Esta función es necesaria ya que como se ha

mencionado anteriormente, los módulos UART y SPI comparten pines y para utilizar uno el

otro debe estar desactivado.

void setUartBaud(uint baud)

Mediante esta función se puede configurar los baudios de la UART.

void flushRxBufferUart()

Esta función sirve para vaciar el buffer de entrada del modulo UART.

void sendByteUart(uchar byteToSend)

Esta función permite enviar un byte a través de la UART.

sendBytesUart(uchar dataLen, uchar* bytesToSend)

Esta función utiliza la función anterior para enviar un conjunto de bytes. bytesToSend es un

puntero que apunta al primer byte del array y dataLen es una variable que indica el tamaño

del array.

Page 102: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del software

101

uchar receiveByteUart(uchar* byteReceived)

Mediante esta función se puede recibir un byte a través de la UART. Su funcionamiento es

parecido al de la función receiveByteSoftwareUART().

uchar receiveBytesUart(dataFrame* bytesToReceive)

Mediante esta función se pueden recibir un conjunto de bytes a través de la UART. Esta

función se basa en la función anterior. bytesToReceive es un puntero que apunta a una

estructura de datos del tipo dataFrame. Esta estructura contiene las variables uchar dataLen

y uchar data[120]. La variable dataLen indica el número de bytes a recibir y se debe asignar

antes de llamar a la función. Los bytes recibidos se guardan en el array data[].

6.3.2 Funciones del ISO 9141-2

void sendByte5baud(uchar byteToSend, uchar* trisPort, uchar* latPort, uchar TXPin)

Esta función toma el control del pin TX de la UART y transmite un byte a una velocidad de

5 baudios. Esta función es necesaria para realizar la inicialización de la ECU de un vehículo

con ISO 9141-2. El modulo UART del PIC no permite velocidades de transmisión tan bajas

y por esta razón se ha tenido que recurrir a una solución por software. Antes de realizar la

transmisión, esta función debe desactivar la UART utilizando la función closeUart().

void sendFrameISO9141(frameFieldsISO9141 frameFields)

Mediante esta función se puede enviar una trama a la ECU del vehículo. frameFields es una

estructura de datos del tipo frameFieldsISO9141. Esta estructura de datos contiene el valor

de los campos de la trama que se desea enviar.

En primer lugar se guardan en un array los campos priority, target, source y data.

Posteriormente la función calcula el checksum y lo añade a la primera posición libre del

array. Finalmente se envía cada un de los bytes del array (solo los bytes de la trama) dejando

un retardo de 10 ms entre transmisión y transmisión (especificación del protocolo ISO 9141-

2).

void sendFrameISO9141(frameFieldsISO9141 frameFields) {

uchar txBuffer[11];

uchar checksum = 0;

txBuffer[0] = frameFields.priority; // First byte of ISO9141 frame is format byte

txBuffer[1] = frameFields.target; // Second byte is target adress

txBuffer[2] = frameFields.source; // Third byte is source adress

// Next lines add data bytes to frame

for(uchar i = 0; i < frameFields.dataLen; i++) txBuffer[3 + i] = frameFields.data[i];

// Checksum of frame is computed

for(uchar i = 0; i < (3 + frameFields.dataLen); i++) checksum += txBuffer[i];

txBuffer[3 + frameFields.dataLen] = checksum; // Add checksum of frame

// Finally the built frame is sended

}

}

Page 103: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del software

102

uchar initISO9141()

Esta función realiza el procedimiento de inicialización descrito en el apartado 3.1.3.2. La

función devuelve 1 si se ha podido inicializar la ECU o 0 si se ha producido algún error. El

siguiente diagrama muestra lo que hace esta función:

Page 104: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del software

103

Figura 80: Inicialización del protocolo ISO 9141-2.

uchar receiveSingleFrameISO9141(frameFieldsISO9141* frameFields)

Page 105: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del software

104

Mediante esta función se puede recibir una trama enviada por el vehículo. Los campos de la

trama se guardan en la estructura de datos que apunta el puntero frameFields. Antes de llamar

a esta función, se debe guardar en la estructura de datos el número de bytes que se espera

que tenga el campo de datos de la trama enviada por el vehículo. La función devuelve un 1

o un 0 según si se ha recibido correctamente la trama o se ha producido algún error.

Lo primero que realiza esta función es recibir los bytes de la trama. Si por alguna razón no

se reciben los bytes esperados la función termina y devuelve un 0 indicando que ha habido

un error. Si se reciben todos los bytes la función procede a calcular el checksum para

compararlo con el enviado dentro de la trama. Si el checksum calculado coincide con el

checksum recibido se guardan los campos de la trama dentro de la estructura de datos y la

función devuelve un 1, si no coinciden los checksum la función termina y devuelve un 0.

uchar receiveMultipleFramesISO9141(frameFieldsISO9141* framesFields, uchar

framesToReceive)

Esta función permite recibir múltiples tramas enviadas por el vehículo y está basada en la

función anterior. El uso de esta función es imprescindible cuando la respuesta del PID pedido

no cabe en una única trama y el vehículo debe responder con un numero determinado de

tramas. frameFields es un puntero a un array del tipo frameFieldsISO9141 y

framesToReceive es una variable que indica el numero de tramas que se espera recibir.

La función devuelve un 1 o un 0 según si se ha recibido correctamente la trama o se ha

producido algún error.

uchar getResponseLengthISO9141(OBD2Request requestedPID, uchar* dataLength)

uchar receiveSingleFrameISO9141(frameFieldsISO9141* frameFields) {

uchar rxBuffer[11];

uchar checksum = 0;

for(uchar i = 0; i < (frameFields->dataLen + 4); i++) {

if(!receiveByteUart(rxBuffer + i)) return 5;

}

for(uchar i = 0; i < (frameFields->dataLen + 3); i++) checksum += rxBuffer[i];

if(checksum != rxBuffer[frameFields->dataLen + 3]) return 0;

frameFields->priority = rxBuffer[0];

frameFields->target = rxBuffer[1];

frameFields->source = rxBuffer[2];

for(uchar i = 3; i < (frameFields->dataLen + 3); i++) {

frameFields->data[i - 3] = rxBuffer[i];

}

return 1;

}

Page 106: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del software

105

Como se ha explicado en el apartado 3.1.3.2, la trama del ISO9141-2 no incluye un campo

que indica el tamaño del campo de datos. La función receiveSingleFrameISO9141() requiere

saber el número de bytes del campo de datos por lo que se debe implementar otra función

que proporcione este valor. Tal y como se puede ver en el apartado 3.2 cada PID tiene una

respuesta acotada por lo que solo debemos integrar esa información en otra función. Esta

función también debe indicar el tipo de respuesta, es decir, si es única o múltiple para saber

cuál función utilizar.

La variable requestedPID es una estructura de datos del tipo OBD2Request que contiene el

PID del cual se requiere saber la longitud de la respuesta y el servicio al cual pertenece el

PID. El tipo de respuesta es devuelto por la misma función y la longitud se almacena al byte

apuntado por dataLength. El valor almacenado en dataLenght se debe interpretar de forma

diferente según se trate de una respuesta simple o múltiple: si es una respuesta simple

dataLenght indica el número de bytes de datos, en cambio si se trata de una respuesta

multiple el valor de dataLenght indica el número de tramas a recibir.

uchar sendOBD2RequestISO9141(OBD2Request requestedPID, OBD2Response*

respondedData)

Page 107: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del software

106

Esta función utiliza las funciones descritas hasta ahora (ISO9141-2) para mandar una trama

request, recibir la respuesta y guardar los datos de la respuesta. El PID pedido y el servicio

al cual pertenece se indica a través de la estructura de datos requestedPID. Los datos de

respuesta así como su longitud se guardan a la estructura de datos apuntada por

respondedData. La función devuelve un 1 o un 0 según si se ha recibido correctamente la

trama o se ha producido algún error. El siguiente diagrama muestra el comportamiento de

esta función:

Figura 81: Diagrama de la función sendOBD2RequestISO9141().

En primer lugar se envia la trama con el PID y el servicio al cual pertenece mediante la

función sendFrameISO9141(). Seguidamente se obtiene el tipo de respuesta y su longitud

mediante la función getResponseLenghtISO9141(). Si la respuesta es única se recibe

Page 108: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del software

107

mediante la función receiveSingleFrameISO9141(), si la respuesta es múltiple se recibe

mediante la función receiveMultipleFramesISO9141(). Si se recibe correctamente la

respuesta esta es guardada a la estructura de datos respondedData, la función devuelve un 1

y termina. Si se produce un error o el PID no es soportado (no se dispone del tamaño de su

respuesta) la función devuelve un 0 y termina.

6.3.3 Funciones del ISO15765-4

void initMCP2515()

Esta funcion inicializa el pin CS para el MCP2515. Este pin es el RB2.

void startCOMMCP2515()

Esta función pone el pin CS a un estado bajo para indicar al MCP2515 que se quiere realizar

una transferencia a través del SPI.

void stopCOMMCP2515()

Esta función devuelve el pin CS a un estado alto indicando al MCP2515 que se ha finalizado

la transferencia.

uchar readRegisterMCP2515(uchar regAdress)

Esta función implementa la instrucción READ explicada en el apartado del MCP2515. La

variable regAdress contiene la dirección del registro a leer y el valor de este registro es

devuelto por la función.

void writeRegisterMCP2515(uchar regAdress, uchar value)

Esta función implementa la instrucción WRITE del MCP2515. La variable regAdress

contiene la dirección del registro a escribir y value es el valor que se le quiere asignar.

void bitModifyMCP2515(uchar regAdress, uchar mask, uchar value)

Esta función implementa la función BIT MODIFY del MCP2515.regAdress es la dirección

del registro, mask es la mascara de bits y value contiene el nuevo valor de los bits a

modificar.

uchar setModeMCP2515(uchar mode)

Mediante esta función se puede cambiar el modo de funcionamiento del MCP2515. La

variable mode contiene el modo a configurar. La función devuelve 1 o 0 según si se ha

podido configurar el modo deseado o ha habido un error.

void initCAN(uchar baudRate)

Page 109: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del software

108

Esta función inicializa el controlador CAN del MCP2515. Lo que se configura con esta

función es básicamente la tasa de bits. Solo se permiten velocidades de 250 kbps y 500 kbps

ya que son las tasas que define el estándar ISO15765-4.

uchar sendCANFrameBuffer0(CANDataFrame dataFrame)

Esta función permite enviar una trama CAN a través del MCP2515. dataFrame es una

estructura de datos del tipo CANDataFrame que contiene los campos de la trama a enviar.

Mediante una variable de la estructura dataFrame se puede elegir si enviar una trama estándar

o una trama extendida. La tasa de bits a la que se envía la trama la determina la función

anterior. La función devuelve un 1 o un 0 según si se ha podido enviar la trama o bien se ha

producido algún error (en el MCP2515, en el bus etc.). Diagrama de flujo de la función:

Figura 82: Diagrama de la función sendCANFrameBuffer0

void configRX0BufferMCP2515(uchar IdType, ulong bufferFilter, ulong bufferMask)

Page 110: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del software

109

Esta función permite configurar el buffer de recepción 0 para que solo acepte tramas con un

determinado Id (o unos determinados Ids). La variable IdType indica el tipo de tramas que

se debe aceptar, puede tomar uno de los siguientes valores: CAN_STANDARD_FRAME

(tramas con id de 11 bits) y CAN_EXTENDED_FRAME (tramas con id de 29 bits).

bufferFilter contiene el filtro del buffer y bufferMask contiene la mascara de bits del filtro,

el funcionamiento del filtro esta explicado con más detalle en el apartado 4.2.1.4.3.

void emptyRX0BufferMCP2515()

Esta función permite vaciar el buffer de recepción del MCP2515.

uchar receiveRX0BufferMCP2515(CANDataFrame* dataFrame)

Mediante esta función se puede recibir una trama CAN. Los campos de la trama se guardan

a la estructura apuntada por el puntero dataFrame. La función devuelve 1 o 0 según si se ha

recibido una trama o no (se ha producido un timeout). Diagrama de la función:

Figura 83: Diagrama de la función receiveRX0BufferMCP2515().

Page 111: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del software

110

En primer lugar se entra dentro de un bucle del cual se sale si se recibe una trama o bien si

se produce un timeout. En caso de que salga porque se ha producido un timeout, la función

devuelve un 0 y termina. Si se recibe la trama, los campos de esta se guardan a la

estructura dataFrame, la función devuelve un 1 y termina.

uchar sendSingleFrameISOTP(dataFrame dataToSend)

Esta función permite enviar una trama del tipo single frame. dataToSend contiene el campo

de datos de la trama a enviar. La función devuelve 1 o 0 según si se ha enviado la trama o si

se ha producido un error.

uchar sendFlowControlFrameISOTP(uchar flowStatus, uchar blockSize, uchar

separationTime)

Esta función permite enviar una trama del tipo flow control. Como se ha explicado en el

apartado 3.1.5.2, esta trama permite indicar los parámetros Flow Status, Block Size y

Separation Time. La función devuelve 1 o 0 según si se ha enviado la trama o si se ha

producido un error.

uchar receiveResponseISOTP(dataFrame* dataReceived)

Esta función permite recibir la respuesta del vehículo, tanto si es simple como múltiple. El

campo de datos de la trama recibida se guarda en la estructura de datos apuntada por

dataReceived. El diagrama de esta función es el siguiente(siguiente hoja):

Page 112: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del software

111

Figura 84: Diagrama de la función receiveResponseISOTP.

Page 113: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del software

112

En primer lugar se llama a la función receiveRX0BufferMCP2515(), si esta función

devuelve un 1 significa que se ha recibido una trama; en cambio, si devuelve un 0 significa

que no se ha recibido nada, en este caso la función receiveResponseISOTP() devuelve un 0

y termina. Si se ha recibido una trama la función comprueba cuál tipo de trama es, en caso

de ser una trama tipo SINGLE_FRAME se guardan los campos de la trama a la estructura

dataReceived y la función termina. En caso de tratarse de una FIRST_FRAME se guardan

los campos de la trama a la estructura dataReceived y se procede a recibir las siguientes

tramas, el número de tramas a recibir se obtiene mediante la función nFramesToReceive().

En primer lugar se debe responder con una trama del tipo FLOW_CONTROL mediante la

función sendFlowControlFrameISOTP(), una vez enviada esta trama se empezarán a recibir

las tramas del tipo CONSECUTIVE_FRAMES. Cada vez que se recibe una trama mediante

la función receiveConsecutiveFrameISOTP() se añaden los datos recibidos a la estructura

dataReceived. Recibidas todas las tramas la función devuelve un 1 y finaliza. Si durante la

recepción de alguna de las tramas se produce un error, la función devuelve un 0 y termina.

uchar sendOBD2RequestISO15765_4(OBD2Request request, OBD2Response*

response)

Esta función es equivalente a la función sendOBD2RequestISO9141() pero para el protocolo

ISO 15765-4. Esta función se encarga de enviar una trama con el PID indicado en la

estructura de datos request y de recibir la trama de respuesta (o tramas), los datos de la cual

se guardan en la estructura de datos response. La función devuelve un 1 o un 0 según si se

ha recibido una respuesta o no. Código de la función:

En primer lugar se prepara el campo de datos de la trama a enviar añadiendo el PID y el

service al que pertenece el PID de la estructura request. Posteriormente se envía la trama

mediante la función y se llama a la función sendSingleFrameISOTP() y se llama a la función

uchar sendOBD2RequestISO15765_4(OBD2Request request, OBD2Response* response) {

dataFrame dataToSend;

dataFrame dataReceived;

dataToSend.dataLen = 1 + request.PIDLength;

dataToSend.data[0] = request.service;

for(uchar i = 1; i < dataToSend.dataLen; i++) dataToSend.data[i] = request.PID[i-1];

if(!sendSingleFrameISOTP(dataToSend)) return 0;

if(!receiveResponseISOTP(&dataReceived)) return 0;

response->service = request.service;

response->PIDLength = request.PIDLength;

for(uchar i = 0; i < request.PIDLength; i++) response->PID[i] = request.PID[i];

response->dataLen = dataReceived.dataLen - request.PIDLength - 1;

for(uchar i = 0; i < response->dataLen; i++) response->data[i] =

dataReceived.data[request.PIDLength + 1 + i];

return 1;

}

Page 114: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del software

113

receiveResponseISOTP(). Si se produce un error en el envió o la recepción de la trama la

función devuelve un 0 y finaliza. Si se recibe correctamente la respuesta, se guardan los

datos recibidos a la estructura response. Llegado a este punto la función devuelve un 1 y

finaliza.

4.3.1 Funciones del protocolo propio:

void sendResponseFrame(responseFrame response)

Mediante esta función se puede enviar una trama de respuesta al ordenador a través de la

UART por software y el módulo Bluetooth. Los campos de la trama se obtienen de la

estructura de datos response.

void sendErrorFrame(negativeResponseFrame negativeResponse)

Esta función envía una trama de error al ordenador. Los campos de la trama se encuentran

en la estructura negativeResponse.

void sendCommandConfirmation(commandFrame command)

Esta función envía una trama de confirmación de comanda. Los campos de la trama se

encuentran en la estructura command.

uchar receiveFrame(uchar* frameReceivedId, requestFrame* request,

commandFrame* command)

Mediante este función se puede recibir una trama del tipo request o command. El tipo de

trama recibida se indica a través del byte frameReceivedId. Si se trata de una trama tipo

request se guardan sus campos en la estructura de datos request, en cambio si se trata de una

trama tipo command se guardan sus campos en la estructura de datos command. La función

devuelve 1 o 0 según si se ha recibido una trama o se ha producido un error. El diagrama de

la función es el siguiente:

Page 115: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del software

114

Figura 85: Diagrama de la función receiveFrame()

Page 116: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del software

115

En primer lugar la función intenta recibir el primer byte de la trama mediante la función

receiveByteSoftwareUART(), este byte indica el tipo de trama que se esta recibiendo. Si no

se recibe ningún byte la función devuelve un 0 y termina. A continuación se procede a recibir

los bytes de la trama indicada por el primer byte recibido. Si se reciben todos los bytes de la

trama y el checksum es correcto, se guardan los campos de la trama que nos interesan a la

estructura de datos correspondiente, se indica el tipo de trama mediante la variable

frameReceivedId y se finaliza la función devolviendo un 1. Si no se reciben todos los bytes

o hay un error en el checksum la función devuelve un 0 y termina.

6.3.4 Funciones main() y initProtocol()

uchar initProtocol(uchar protocol):

Esta función se encarga de comprobar si el protocolo introducido por el usuario es el que

implementa el vehículo. La variable protocol indica el protocolo que ha elegido el usuario.

Si se ha podido comunicar con el vehículo mediante el protocolo elegido la función devuelve

un 1, en caso contrario devuelve un 0. Si el protocolo es el correcto el programa puede

empezar a enviar peticiones ya que la función también inicializa el protocolo (solo con ISO

9141-2 ya que con ISO 15765-4 no hace falta).

void main():

Esta función se encarga de inicializar todos los módulos llamando a las funciones

correspondientes. Además, dentro de esta función se encuentra el código que recibe las

tramas enviadas desde la aplicación, las procesa y envia las respuestas. El código gestiona

tramas de request y tramas de comanda, las comandas implementadas en esta versión son

solo las de conectar al vehículo y desconectarse. El diagrama de la función es el siguiente:

Page 117: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Desarrollo del software

116

Figura 86: Diagrama de la función main().

Page 118: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Aplicación de escritorio

117

7. Aplicación de escritorio

En este apartado se explicarán las diferentes funcionalidades de la aplicación de escritorio

desarrollada para poder comunicarse con el escáner OBD2. Esta aplicación permitirá

controlar el dispositivo OBD2 desde el ordenador y dispondrá de una interfaz gráfica que

facilitará el uso por parte del usuario. Las funcionalidades principales de esta aplicación son:

• Conectarse al escáner OBD2 a través del puerto serie creado.

• Gestionar las diferentes tramas del protocolo diseñado para la comunicación con el

escáner OBD2. Esto permitirá que se puedan enviar comandos al dispositivo y

realizar peticiones al vehículo.

• La aplicación permiten almacenar los datos obtenidos en distintos formatos para así

facilitar su posterior manejo e interpretación. De esta forma todos los datos obtenidos

durante una sesión no se pierden.

Las funcionalidades de la aplicación se explicarán más en detalle en los próximos apartados.

7.1 Desarrollo de la aplicación

La aplicación de escritorio del dispositivo OBD2 ha sido completamente desarrollada

mediante el lenguaje de programación Python. Python es un lenguaje de programación

interpretado que ha adquirido mucha popularidad durante los últimos años, sobre todo dentro

de la comunidad educativa. La razón principal por la que se ha hecho tan popular es la

facilidad en su uso ya que dispone de una sintaxis muy parecida al lenguaje humano. Otra

punto positivo es toda la comunidad que hay detrás de este lenguaje, esto permite disponer

de multitud de librerías que facilitan significativamente el proceso de desarrollo del software.

Otra característica que lo hace interesante es que es un lenguaje orientado a objetos.

Para escribir el código de la aplicación se ha utilizado el editor de código Notepad++ v 7.5.4.

Esta herramienta es muy simple y permite escribir en diferentes lenguajes de programación.

Figura 87: Entorno de desarrollo del Notepad++.

Page 119: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Aplicación de escritorio

118

Para poder ejecutar un código escrito en Python se debe disponer de interprete de Python.

Para este proyecto se ha utilizado la versión 3.7.4. El interprete de Python no dispone de una

interfaz gráfica sino que se maneja desde una línea de comandos como la que ofrece el

programa informático Git. Para poder ejecutar un script de Python mediante la línea de

comandos de Git simplemente se debe ir al directorio donde esta el archivo y seguidamente

ejecutar la comanda mostrada en la siguiente figura:

Figura 88: Línea de comandos de Git.

Si el nombre del archivo es correcto y se dispone del interprete de Python, el código se

empezará a ejecutar después de apretar la tecla intro.

Tal y como se ha comentado anteriormente, el Python dispone de un gran número de librerías

que facilitan el desarrollo de aplicaciones. Un gran ejemplo es PyQt la cual es la librería

gráfica que se utilizará para el desarrollo de la interfaz gráfica.

El PyQt permite añadir ventanas de distintos tipos a nuestra aplicación. Dentro de estas

ventanas se pueden añadir distintos elementos de entrada o salida como pueden ser botones,

listas de selección, cuadros de texto etc.

Para el diseño de la interfaz gráfica en sí se ha utilizado el programa QtDesigner. Este

herramienta permite diseñar cada una de las ventanas de nuestra interfaz gráfica.

Figura 89: Entorno del QtDesigner.

Page 120: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Aplicación de escritorio

119

Tal y como se puede ver a la figura anterior, el QtDesigner permite diseñar de forma gráfica

las ventanas de nuestra aplicación, podemos incluir todos los elementos que deseemos

simplemente arrastrándolos a la ventana que se esta diseñando.

Una vez completado el diseño de las distintas ventanas de la interfaz gráfica podemos

generar los archivos que contendrán la información de estas ventanas, el formato de estos

archivos es .ui. Como se verá más adelante, estos archivos se deberán añadir al código de la

aplicación.

En el código se deberá añadir una clase para cada una de las ventanas de la aplicación. Estas

clases deben ser heredadas de otras clases que incluye la librería PyQt. La clase padre de

cada clase añadida depende del tipo de ventana, por ejemplo, para una ventana principal

(Main Window) se debe crear una clase heredada de la clase QmainWindow.

Una vez creada la clase, se debe asociar al archivo de la ventana generado mediante el

QtDesigner.

El fragmento de código anterior corresponde a una clase asociada a una ventana del tipo

dialogo. Tal y como se puede ver, la clase debe ser heredada de la clase Qdialog.

editProfile.ui es el archivo generado mediante el QtDesigner y contiene la información

gráfica de la ventana. La asociación de este archivo a la clase se realiza mediante la función

uic.loadUi() dentro del constructor de la clase.

Creadas las clases para cada una de las ventanas podemos proceder a crear objetos de estas

clases. Los objetos creados permitirán gestionar las ventanas de la aplicación mediante los

distintos métodos de las clases a las que pertenecen. Estos métodos permiten mostrar/ocultar

la ventana, ver/modificar las propiedades de los distintos elementos de la ventana etc.,es

decir, a partir de estos objetos podemos interactuar con la interfaz gráfica desde el código.

Una vez creados los objetos para cada una de las ventanas debemos empezar a elaborar el

código que dará vida a la interfaz gráfica.

class editProfileDialogClass(QDialog):

def __init__(self):

super().__init__()

uic.loadUi("editProfile.ui", self)

Page 121: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Aplicación de escritorio

120

7.2 Descripción de la aplicación

En este aparatado se explicará en detalle las distintas funcionalidades de la aplicación. Este

apartado también puede servir de manual del usuario de la aplicación.

Conexión al escáner OBD2

Antes de conectarse al dispositivo OBD2 debemos asegurarnos de que esté correctamente

conectado al conector OBD2 del vehículo. Además, el ordenador debe estar conectado al

dispositivo OBD2 mediante Bluetooth. Asegurado lo anterior podemos proceder a

conectarnos al escáner OBD2 mediante la aplicación.

Ir a File > Open Connection y se abrirá la siguiente ventana:

Figura 90: Ventana de conexión.

Esta ventana nos permite introducir la información necesaria para establecer conexión con

el vehículo. Esta información es el protocolo OBD2 del vehículo y el puerto COM al que

está conectado el escáner OBD2. Además podemos introducir otra información como el

fabricante del vehículo o la matrícula, estos datos no son obligatorios pero se recomienda

introducirlos para tener la identidad del vehículo en los archivos generados.

Una vez introducidos los datos se debe hacer clic al botón Connect(1) saldrá una ventana

que nos indicará si se ha realizado la conexión con éxito o no. Si se ha podido conectar con

el vehículo, la aplicación desbloqueará todas sus funciones para que el usuario pueda

proceder a utilizarlas.

1

Page 122: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Aplicación de escritorio

121

Obtención de datos en tiempo real

Una vez conectado al vehículo, el programa habilita las pestañas que permiten navegar a

través de sus distintas herramientas. La primera pestaña de la aplicación recibe el nombre de

“Live Data Meter”. Esta pestaña permite obtener datos en tiempo real del vehículo. El

contenido de la pestaña se puede ver en la siguiente figura:

Figura 91: Pestaña Live Data Meter.

Tal y como se puede observar, esta pestaña incluye 4 listas de selección con lo que se permite

obtener simultáneamente el valor de 4 sensores. El dato elegido en cada lista de selección se

muestra en el cuadro de texto que hay justo abajo. Los datos seleccionados también se

pueden observar de forma gráfica mediante las barras de progreso.

Figura 92: Sección de la pestaña Live Data Meter

Barra de progreso

Cuadro de texto

Lista de selección

1 2

Page 123: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Aplicación de escritorio

122

En esta versión del programa se permite obtener los siguientes datos del vehículo:

• Velocity(km/h): velocidad del vehículo en km/h.

• Engine Speed(rpm): revoluciones del motor en rpm.

• Throttle Position(%): porcentaje accionado del pedal acelerador.

• Engine Load(%): porcentaje de carga del motor.

• Coolant Temperature(°C): temperatura del líquido refrigerante.

• Absolute Intake Manifold Pressure(kPa): presión de aire en la admisión.

• Intake Manifold Temperature(°C): temperatura del aire en la admisión.

• Mass Air Flow(g/s): flujo másico de aire en g/s.

Aunque se elijan los parámetros deseados, el programa no empezará a obtener los datos hasta

hacer clic en el botón Read(1), una vez apretado este botón el programa empezará a obtener

los datos seleccionados. Si se desea pausar la obtención de los datos simplemente se debe

volver a hacer clic en el mismo botón.

Como se puede observar en la figura 91, al lado del botón Read hay otro botón con el nombre

Clean. Este botón permite borrar el valor que hay en los cuadros de texto y en las barras de

progreso.

Obtención de los DTCs del vehículo

La siguiente pestaña de la aplicación recibe el nombre Trouble Codes. Esta pestaña permite

obtener los DTCs del vehículo. El contenido de la pestaña se puede observar en la siguiente

figura:

Page 124: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Aplicación de escritorio

123

Figura 93: Pestaña Trouble Codes.

Dentro de esta pestaña tenemos el botón Read(1) el cual da el orden de leer los DTCs del

vehículo y mostrarlos en pantalla. Los DTCs obtenidos se organizan en la pestaña según la

categoría a la que pertenecen. La categorías disponibles son:

• Powertrain: en esta categoría se muestran los fallos relacionados con el tren motriz:

motor, transmisión etc.

• Body Systems: en esta categoría se muestran los fallos relacionados con los sistemas

situados dentro del compartimiento de los pasajeros: sistemas de seguridad, de

conforte etc.

• Chassis Systems: en esta categoría se muestran los fallos relacionados con los

sistemas situados fuera del compartimiento de los pasajeros: sistema de frenado,

dirección asistida, suspensión hidráulica etc.

• Network Systems: en esta categoría se muestran los fallos relacionados con los

sistemas de comunicación de los diferentes módulos del vehículo.

El botón Clear(2) situado al lado del botón Read(1) permite borrar los fallos almacenados

dentro de la ECU del vehículo. Una vez enviada la orden de borrar los DTCs al vehículo, el

programa vuelve a pedir los DTCs almacenados para que el usuario pueda comprobar si

realmente se han borrado.

1 2 3

Page 125: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Aplicación de escritorio

124

El botón Export to text(3) file situado a la parte inferior-derecha de la pestaña permite

generar un documento de texto con los DTCs obtenidos. Además de los DTCs, el archivo

generado contiene la siguiente información:

• Fecha de creación del documento.

• Fabricante del vehículo.

• Modelo del vehículo.

• Matrícula del vehículo(en el nombre del archivo).

El fabricante, el modelo y la matricula son los introducidos por el usuario en el momento de

conectarse. Esta información es de gran ayuda para poder identificar el vehículo al cual

pertenece el archivo, por eso se recomienda proporcionar la información al programa.

Obtención del Freeze Frame

La pestaña Freeze Frames permite obtener el cuadro de datos congelados disponible en el

vehículo. Además, se muestra el DTC al cual pertenece el Freeze Frame.

Figura 94: Pestaña Freeze Frame.

Para solicitar el Freeze Frame al vehículo se debe hacer clic sobre el botón Read(1). Una vez

recibidos los datos estos se mostraran en la pestaña.

1 2

Page 126: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Aplicación de escritorio

125

El botón Export to text file(2) situado a la parte inferior-derecha permite generar un archivo

con el Freeze Frame obtenido. En el archivo también se incluye información para identificar

el vehículo. Esta información es la misma que se incluye en el archivo generado desde la

pestaña Trouble Codes.

Obtención de la información del vehículo

Esta pestaña permite obtener información especifica del vehículo como el estándar OBD

implementado o el VIN.

Figura 95: Pestaña Vehicle Info

Para enviar una petición de los datos al vehículo se debe hacer clic sobre el botón Read(1).

Una vez se obtengan los datos se muestran en su lugar correspondiente.

El botón Copy to Clipboard(2) permite copiar al portapapeles los datos mostrados en la

pestaña.

Dentro de esta pestaña también se muestra la matrícula y el protocolo de comunicación del

vehículo. Estos datos no proceden del vehículo directamente sino que son los introducidos

por el usuario.

1 2

Page 127: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Aplicación de escritorio

126

Herramientas de decodificación de los DTCs

La pestaña Search DTC Codes dispone de dos herramientas que permiten obtener la

información codificada en los DTCs.

Figura 96: pestaña Search DTC Codes.

Tal y como se puede observar a la figura anterior, dentro de esta pestaña se dispone de dos

herramientas: DTC Decoder y DTC Searcher.

La herramienta DTC Decoder permite decodificar los DTC dentro de la misma aplicación.

Introduciendo el DTC dentro de las casillas y haciendo clic sobre el botón (1) se obtiene el

significado de cada carácter del DTC.

La herramienta DTC Searcher también permite decodificar DTCs pero en este caso se utiliza

una página web de terceros para obtener la información. Al introducir los DTCs dentro de

los cuadros de texto y hacer clic sobre el botón (2) se abre una página web que contiene la

información de los DTC. Lógicamente se requiere de conexión internet para poder utilizar

esta herramienta. Mediante esta herramienta se pueden decodificar hasta 3 DTC a la vez.

La ventaja que presenta la herramienta DTC Searcher frente a la primera es que la

información proporcionada es mucho más completa.

1 2

Page 128: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Aplicación de escritorio

127

Herramienta de gráficos

La pestaña Plotting Tool permite obtener un dato del vehículo de forma periódica durante

un tiempo determinado. La pestaña también permite guardar los datos obtenidos en un

archivo excel.

Figura 97: Pestaña Plotting Tool

En primer lugar se deben seleccionar los parámetros que se quieran muestrear mediante las

listas de selección, la aplicación permite seleccionar hasta 3 parámetros diferentes.

También se debe seleccionar el tiempo de muestreo mediante la lista de selección.

Figura 98: Sección de la pestaña Plotting Tool.

Selección del tiempo

de muestreo

Selección de los parámetros

1 2 3

Page 129: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Aplicación de escritorio

128

Una vez finalizada la configuración se puede proceder a obtener les datos mediante el botón

Get Data(1). La barra de progreso indica el porcentaje de muestras obtenidas respecto a las

que se deben obtener. Cuando termina la obtención de datos se activa el botón Export to

Excel(3) mediante el cual podemos generar un archivo excel con los datos obtenidos. En el

archivo excel también se incluyen datos de identificación del vehículo como la matrícula o

el fabricante.

El botón Clean Data(2) permite eliminar los datos obtenidos.

Depurador de las comunicación con el dispositivo OBD2

La pestaña Interpreter Log permite visualizar todas las tramas que son intercambiadas entre

el escáner OBD2 y el programa. Esta herramienta es muy útil para poder detectar y

solucionar errores en la comunicación.

Figura 99: Pestaña Interpreter Log.

Mediante el botón Pause(1) se puede activar/desactivar el log de las tramas. El botón Clear

Log(2) permite borrar las tramas registradas hasta el momento.

1 2

Page 130: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Aplicación de escritorio

129

Desconexión del escáner OBD2

Para desconectarse del escáner OBD2 simplemente se debe ir a File > Close Connection.

Page 131: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Construcción y test del prototipo

130

8. Construcción y test del prototipo

8.1 Construcción del prototipo

El prototipo del proyecto se ha realizado sobre una protoboard. Algunas partes del circuito

se han añadido como módulos que se comercializan, es un ejemplo la interfaz del ISO

15765-4.

Para su elaboración simplemente se ha seguido el esquema mostrado en el apartado 4.6.

Figura 100: Prototipo del dispositivo OBD2.

8.2 Test del prototipo

En este apartado realizaremos un test del producto final mediante la aplicación de escritorio.

El objetivo es verificar que el dispositivo OBD2 es capaz de conectarse a un vehículo y

obtener los datos que pidamos. Además, mediante este test también se va a comprobar que

la aplicación funcione correctamente y permita acceder a los distintos servicios del sistema

OBD2 (Datos actuales, DTC, Información del vehículo etc.)

El test se realizará con un vehículo que implementa el protocolo ISO 9141-2.

Para empezar el test en primer lugar debemos conectar el dispositivo al vehículo mediante

el conector OBD2 y poner la llave del vehículo en la posición de contacto.

También se debemos asociar el dispositivo OBD al ordenador mediante una conexión

Bluetooth. Una vez conectado se abrirá un puerto serie, debemos apuntar el número para

introducirlo a la aplicación más adelante.

Page 132: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Construcción y test del prototipo

131

A continuación ejecutamos la aplicación y abrimos el diálogo de conexión:

Figura 101: Dialogo de conexión.

Una vez introducidos los datos damos clic al botón Connect.

Tal y como se puede ver en la siguiente figura, el dispositivo OBD2 se ha conectado

correctamente al vehículo y la aplicación a desbloqueado todas sus funcionalidades:

Figura 102: Conexión al vehículo realizada.

Page 133: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Construcción y test del prototipo

132

Obtención de datos actuales

A continuación obtendremos datos del vehículo en tiempo real

Figura 103: Datos en tiempo real.

Tal y como se puede ver en la figura anterior, la aplicación nos proporciona correctamente

los datos en tiempo real de los parámetros elegidos. Se puede verificar que algunos datos

son correctos a través del cuadro de instrumentos del vehículo.

Obtención de los DTCs

A continuación comprobaremos que el dispositivo pueda obtener correctamente los códigos

de falla del vehículo. Para ello debemos provocar que se produzca un fallo en el vehículo.

Una forma fácil de generar un DTC es desconectar el sensor MAF y circular con el vehículo

hasta que aparezca el DTC. Cuando la luz MIL se encienda significa que el sistema OBD2

ha detectado la falla y ha generado un DTC.

Figura 104: Luz MIL encendida.

Page 134: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Construcción y test del prototipo

133

Ahora ya podemos leer los DTCs mediante la aplicación:

Figura 105: Obtención de las DTCs del vehículo.

Tal y como se puede ver en la figura anterior se ha encontrado 1 DTC. Este DTC es el

P0102 y pertenece a la categoría Powertrain (tren de transmisión). Podemos decodificar

este DTC mediante la ventana Search DTC Codes.

Page 135: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Construcción y test del prototipo

134

Figura 106: Decodificación del DTC P0102.

Mediante la herramienta DTC Decoder podemos ver que el DTC es genérico (es estándar).

Vemos además que el DTC hace referencia a un elemento relacionado con la medición del

aire lo cual es lógico ya que el DTC se ha producido por la desconexión del sensor MAF.

Para obtener más información usamos la herramienta DTC Searcher.

Figura 107: Página web www.dtcsearch.com

Comprobamos que efectivamente la aplicación nos redirige a una página web donde

encontramos información sobre el DTC introducido.

Por ultimo intentaremos guardar un listado de los DTCs encontrados en un fichero de texto.

Para ello debemos dar clic en el botón Export to text file.

Page 136: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Construcción y test del prototipo

135

Figura 108: Fichero de DTCs generado

Tal y como se puede ver en la figura anterior, la aplicación genera correctamente el fichero

con los DTCs encontrados. Se añade además datos del vehículo y otra información como la

fecha de creación del fichero.

Borrado de DTC

Ahora comprobaremos que el dispositivo OBD2 borra correctamente los DTCs del

Vehículo. Para ello nos situaremos a la pestaña Trouble Codes y haremos clic sobre el botón

Clear.

Figura 109: Borrado de los DTCs.

Tal y como se puede ver en la figura anterior, el dispositivo ha borrado correctamente el

DTC que había almacenado en la ECU.

Page 137: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Construcción y test del prototipo

136

Observamos también que la luz MIL se apaga una vez borrado el DTC.

Figura 110: Luz MIL apagada.

Información del vehículo

A continuación comprobaremos que el dispositivo OBD permita obtener datos del servicio

9. Para ello nos situaremos a la pestaña Vehicle Info y daremos clic al botón Read.

Figura 111: Información del vehículo.

Tal y como se puede ver en la figura anterior, la aplicación nos ha proporcionado el número

de bastidor del vehículo.

Aunque no pertenezca al servicio 9, la aplicación también nos proporciona correctamente la

versión del OBD implementada.

Page 138: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Construcción y test del prototipo

137

Generación de gráficas

Ahora comprobaremos que la aplicación permita muestrear uno o varios parámetros del

vehículo y generar un archivo Excel con los datos para crear gráficas.

Nos situamos en la pestaña Plotting Tool, elegimos los parámetros y el tiempo de muestreo

y damos clic al botón Get Data.

Figura 112: Muestreo de los parámetros Engine Speed y Velocity.

Una vez terminado el proceso, generamos el fichero Excel mediante el botón Export to

Excel.

Figura 113: Fichero Excel generado.

Page 139: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Construcción y test del prototipo

138

Tal y como se puede observar en la figura anterior, la aplicación genera correctamente el

archivo Excel con los datos obtenidos.

Con los datos anteriores obtenemos la siguiente gráfica:

Gráfica 1: Revoluciones del motor y velocidad del coche.

Observamos que hay tramos de la gráfica donde la velocidad del motor y del vehículo son

proporcionales mientras que en otros no. Esto es porque en algunos tramos hay una marcha

engranada y en otros no o bien se está cambiando de marcha.

Por lo tanto, la aplicación permite obtener gráficas con los parámetros del vehículo

correctamente.

Log de la comunicación

Finalmente comprobaremos que la aplicación registra correctamente todas las tramas

intercambiadas.

Para ello nos situamos en la pestaña Interpreter LOG.

0

10

20

30

40

50

60

0 2 4 6 8

10

12

14

16

18

20

22

24

26

28

30

32

34

36

38

40

42

44

46

48

Revoluciones del motor y velocidad del coche

Engine Speed(rpm) / 100 Velocity(km/h)

Page 140: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Construcción y test del prototipo

139

Figura 114: Log de la aplicación

Tal y como se puede ver, la aplicación registra correctamente las tramas intercambiadas entre

el ordenador y el dispositivo OBD2.

A partir del test realizado podemos concluir que el dispositivo OBD2 y la aplicación de

escritorio funcionan según las especificaciones del proyecto.

Page 141: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Conclusiones

140

9. Conclusiones

Sobre el producto final

El objetivo de este proyecto era el de diseñar un dispositivo que fuera capaz de comunicarse

con el sistema OBD2 de los vehículos que implementen el protocolo ISO 9141-2 o ISO

15765-4. Finalizado el proyecto podemos concluir que el objetivo se ha cumplido

satisfactoriamente.

Tal y como se puede ver en el apartado 8, el dispositivo diseñado permite conectarse con el

sistema OBD2 de un vehículo que implementa el protocolo ISO 9141-2. El dispositivo

también se ha probado con un emulador del protocolo ISO 15765-4 y ha respondido

correctamente a las distintas pruebas realizadas.

Mediante este dispositivo se ha podido acceder a los servicios 1, 2, 3, 4 y 9 del sistema OBD2

del vehículo con el que se ha realizado el test. Esto ha permitido obtener datos en tiempo

real, graficar estos datos, ver los códigos de falla almacenados, borra los códigos de falla etc.

Es decir, el producto diseñado es práctico y sus prestaciones son comparables a las que

ofrecen algunos escáner OBD2 comerciales.

Sobre el sistema OBD2

A partir del estudio de la historia del sistema OBD2 vemos que este sistema no surge

simplemente por la necesidad de disponer de algo que nos proporcione las lecturas de los

distintos sensores del vehículo sino que tiene todo un trasfondo medioambiental. Gracias al

sistema OBD2 se asegura el correcto funcionamiento de los sistemas anti polución y por lo

tanto, gracias al sistema OBD2 podemos respirar un aire más limpio.

Habiendo trabajado con los protocolos ISO 9141-2 y ISO 15765-4 podemos ver porqué

desde el año 2008 los fabricantes están obligados a utilizar el ISO 15765-4. El ISO 9141-2

tiene unas especificaciones que limitan sus prestaciones: baja velocidad de transmisión (10,4

kbps), requiere una inicialización que dura 2 s, el bus no está muy protegido contra las EMIs,

el manejo de las tramas es más caótico… El ISO 15765-4 en cambio está basado en el BUS

CAN el cual permite tasas de transmisión de hasta 1 Mbps, aunque el estándar ISO 15765-4

solo admite tasas de 250 kbps y 500 kbps. Además, el BUS CAN está protegido contra las

EMIs lo cual lo hace ideal para usarlo dentro de la industria del automóvil.

Mejoras del diseño

Para una futura revisión del diseño de este proyecto se pretenderá introducir las siguientes

mejoras:

• En la versión actual del diseño, se utiliza un circuito integrado que implementa el

protocolo CAN ya que el microcontrolador utilizado no dispone de un módulo CAN.

Utilizando el microcontrolador con un módulo CAN integrado abarataría el coste del

producto.

• Como el PIC18F4550 solo dispone de 1 UART y esta se utiliza para implementar el

ISO 9141-2, se ha tenido que implementar una UART por software para comunicarse

Page 142: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Conclusiones

141

con el módulo Bluetooth. Esta UART por software transmite a 9600 baudios por lo

que es el cuello de botella de todo el sistema de comunicación. La solución sería

buscar otro MCU que disponga de 2 o más módulos UART, así podríamos reducir el

tiempo de transmisión entre el dispositivo OBD2 y el ordenador.

• Muchos escáner OBD2 disponen de un conjunto de LEDs a través de los cuales el

usuario puede saber el estado del dispositivo. En una versión futura se añadirán estos

LEDs para así mejorar la experiencia del usuario.

• Otra funcionalidad que se pretende añadir es la de poder leer el voltaje de la batería

mediante el conversor AD del MCU y proporcionar esta información al usuario. Esto

permitiría saber el estado de la batería y del alternador cuando esté cargando la

batería.

• Por último, para mejorar la estética del producto se diseñará una PCB donde irán

soldados todos los componentes.

Page 143: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Webgrafía

142

10. Webgrafía

OBD2 EXPLAINED - A SIMPLE INTRO, https://www.csselectronics.com/screen/page/simple-

intro-obd2-explained/language/en

OBD-II Reader, https://github.com/arashn/obdii-reader/wiki

OBD9141, https://github.com/iwanders/OBD9141

OBD-II, http://blog.perquin.com/blog/category/odbii/

K-line Communication Description, https://obdclearinghouse.com/Files/viewFile?fileID=1380

El OBDII Completo, https://es.wikibooks.org/wiki/El_OBDII_Completo#Parte_III_-_Los_PIDs

OBD-II PIDs, http://obdcon.sourceforge.net/2010/06/obd-ii-pids/

Protocolos de conexión OBD2, https://obd2-elm327.es/protocolos-conexion-obd2

Introducción a CAN, http://www.ni.com/es-es/innovations/white-papers/06/controller-area-

network--can--overview.html

Línea K, https://es.wikipedia.org/wiki/L%C3%ADnea_K

Acerca de los Códigos de falla o DTC, http://www.cise.com/portal/notas-tecnicas/item/228-

acerca-de-los-c%C3%B3digos-de-falla-o-dtc.html

SAE J1850 Description, http://www.interfacebus.com/Automotive_SAE_J1850_Bus.html

Class B Data Communications Network Interface,

https://www.sae.org/standards/content/j1850_201510/

ISO 15765-4 CAN, https://hackaday.com/tag/iso-15765-4-can/

CAN-TP Protocol, http://www.piembsystech.com/protocol/automotive-protocols/can-tp-

protocol/

ISO 15765-2, http://canbushack.com/iso-15765-2/

OBD2 to RS232 Interpreter, https://www.elmelectronics.com/wp-

content/uploads/2016/07/ELM327DS.pdf

SAEJ1979, http://212.113.105.12/library/BOOKS/CAR/OBDII/saeJ1979_2006-08-25Ballot.pdf

Page 144: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

143

11. ANEXO 1: Código del microcontrolador PIC18F4550

BT_Interface.h

#include "Types.h"

void sendResponseFrame(responseFrame response);

void sendErrorFrame(negativeResponseFrame negativeResponse);

void sendCommandConfirmation(commandFrame command);

uchar receiveFrame(uchar* frameReceivedId, requestFrame* request, commandFrame*

command);

ISO15765_4.h

#include "Types.h"

uchar nFramesToReceive(uchar dataLen);

uchar sendFlowControlFrameISOTP(uchar flowStatus, uchar blockSize, uchar

separationTime);

uchar sendSingleFrameISOTP(dataFrame dataToSend);

uchar receiveConsecutiveFrameISOTP(uchar* sequenceNumber, uchar data[7]);

uchar receiveResponseISOTP(dataFrame* dataReceived);

uchar sendOBD2RequestISO15765_4(OBD2Request request, OBD2Response* response);

ISO9141_2.h

#include "Types.h"

void sendByte5baud(uchar byteToSend, uchar* trisPort, uchar* latPort, uchar TXPin);

uchar initISO9141();

void sendFrameISO9141(frameFieldsISO9141 frameFields);

uchar receiveSingleFrameISO9141(frameFieldsISO9141* frameFields);

uchar receiveMultipleFramesISO9141(frameFieldsISO9141* framesFields, uchar

framesToReceive);

uchar getVINLengthISO9141(uchar* framesToReceive);

uchar getDTCBytesISO9141(uchar* bytesToReceive);

uchar nFramesToReceive2(uchar dataLen);

uchar getResponseLengthISO9141(OBD2Request requestedPID, uchar* dataLength);

uchar sendOBD2RequestISO9141(OBD2Request requestedPID, OBD2Response* respondedData);

MCP2515.h

#include "Types.h"

void initMCP2515();

void startCOMMCP2515();

void stopCOMMCP2515();

uchar readRegisterMCP2515(uchar regAdress);

void writeRegisterMCP2515(uchar regAdress, uchar value);

void bitModifyMCP2515(uchar regAdress, uchar mask, uchar value);

void resetMCP2515(void);

uchar setModeMCP2515(uchar mode);

void initCAN(uchar baudRate);

uchar sendCANFrameBuffer0(CANDataFrame dataFrame);

void configRX0BufferMCP2515(uchar IdType, ulong bufferFilter, ulong bufferMask);

void emptyRX0BufferMCP2515();

uchar receiveRX0BufferMCP2515(CANDataFrame* dataFrame);

Page 145: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

144

Macros.h

#define FOSC 48000000

#define TRISA_ADRESS 0xF92

#define TRISB_ADRESS 0xF93

#define TRISC_ADRESS 0xF94

#define TRISD_ADRESS 0xF95

#define TRISE_ADRESS 0xF96

#define PORTA_ADRESS 0xF80

#define PORTB_ADRESS 0xF81

#define PORTC_ADRESS 0xF82

#define PORTD_ADRESS 0xF83

#define PORTE_ADRESS 0xF84

#define CAN_RX_TIMEOUT 500

#define RX_TIMEOUT 1000

#define initByteISO9141 0x33

#define SINGLE_FRAME_RESPONSE 0

#define MULTIPLE_FRAMES_RESPONSE 1

#define PID_NOT_SUPPORTED 2

#define PRIORITY_FIELD_ISO9141 0x68

#define TARGET_FIELD_ISO9141 0x6A

#define SOURCE_FIELD_ISO9141 0xF1

#define INPUT 1

#define OUTPUT 0

#define nop(); asm("nop");

// MCP2515 control registers

#define BFPCTRL 0X0C

#define TXRTSCTRL 0x0D

#define CANSTAT 0xE

#define CANCTRL 0xF

#define TEC 0x1C

#define REC 0x1D

#define CNF3 0x28

#define CNF2 0x29

#define CNF1 0x2A

#define CANINTE 0x2B

#define CANINTF 0x2C

#define EFLG 0x2D

#define TXB0CTRL 0x30

#define TXB1CTRL 0x40

#define TXB2CTRL 0x50

#define RXB0CTRL 0x60

#define RXB1CTRL 0x70

// MCP2515 modes

#define MCP2515_CONFIG_MODE 0

#define MCP2515_NORMAL_MODE 1

#define MCP2515_SLEEP_MODE 2

#define MCP2515_LISTEN_ONLY_MODE 3

#define MCP2515_LOOPBACK_MODE 4

// MCP2515 TX BUFFER 1 (CONTROL AND DATA)

Page 146: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

145

#define TXB0CTRL 0x40

#define TXB0SIDH 0x41

#define TXB0SIDL 0x42

#define TXB0EID8 0x43

#define TXB0EID0 0x44

#define TXB0DLC 0x45

#define TXB0D0 0x46

// MCP2515 RX BUFFER 0 (CONTROL AND DATA)

#define RXB0CTRL 0x60

#define RXB0SIDH 0x61

#define RXB0SIDL 0x62

#define RXB0EID8 0x63

#define RXB0EID0 0x64

#define RXB0DLC 0x65

#define RXB0D0 0x66

// MCP2515 RX BUFFER 0 FILTER AND MASK

#define RXF0SIDH 0x00

#define RXF0SIDL 0x01

#define RXF0EID8 0x02

#define RXF0EID0 0x03

#define RXM0SIDH 0x20

#define RXM0SIDL 0x21

#define RXM0EID8 0x22

#define RXM0EID0 0x23

// MCP2515 BAUD RATE OPTIONS

#define CAN_SPEED_250KBPS 0

#define CAN_SPEED_500KBPS 1

// MCP2515 FRAME ID TYPES

#define CAN_EXTENDED_FRAME 0

#define CAN_STANDARD_FRAME 1

// MCP2515 REMOTE REQUEST

#define CAN_FRAME_IS_RTR 0x40

#define CAN_FRAME_IS_NOT_RTR 0x00

// MCP2515 MESSAGE PRIORITIES

#define HIGHEST_MESSAGE_PRIORITY 3

#define HIGH_INTERMEDIATE_MESSAGE_PRIORITY 2

#define LOW_INTERMEDIATE_MESSAGE_PRIORITY 1

#define LOWEST_MESSAGE_PRIORITY 0

// BT COM

#define responseFrameId 1

#define requestFrameId 2

#define commandFrameId 3

#define negativeResponseFrameId 4

#define commandConfirmationFrameId 5

// ISO-TP FRAMES

#define SINGLE_FRAME 0

#define FIRST_FRAME 1

#define CONSECUTIVE_FRAME 2

#define FLOW_CONTROL 3

//PROTOCOLS

#define ISO9141_2 0

#define ISO14230_1 1

#define SAEJ1850PWM 2

#define SAEJ1850VPW 3

#define ISO15765_1_11bit_250KB 4

Page 147: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

146

#define ISO15765_1_11bit_500KB 5

#define ISO15765_1_29bit_250KB 6

#define ISO15765_1_29bit_500KB 7

Math.h

#include "Types.h"

long pow(char baseNumber, char exponentNumber);

SW_UART.h

#include "Types.h"

uchar reverseByte(uchar x);

void initSoftwareUART();

void sendByteSoftwareUART(uchar byteToSend);

uchar receiveByteSoftwareUART(uchar* receivedByte);

void sendBytesSoftwareUART(dataFrame dataToSend);

uchar receiveBytesSoftwareUART(dataFrame* dataToReceive);

Time.h

#include "Types.h"

void wait(uint delay);

void delay19200baud();

void delay9600baud();

Types.h

typedef unsigned char uchar;

typedef unsigned int uint;

typedef unsigned long ulong;

typedef struct {

uchar cmdLen;

uchar dataLen;

uchar dest;

uchar src;

uchar cmd[10];

} requestFieldsISO9141;

typedef struct {

uchar cmdLen;

uchar dest;

uchar src;

uchar cmd[10];

uchar data[10];

uchar dataLen;

} responseFieldsISO9141;

typedef struct {

uchar idType;

ulong messageId;

uchar RTR;

Page 148: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

147

uchar DLC;

uchar data[8];

} CANDataFrame;

typedef struct {

uint dataLen;

uchar data[120];

} dataFrame;

typedef struct {

uchar service;

uchar PIDLength;

uchar PID[5];

} OBD2Request;

typedef struct {

uchar service;

uchar PIDLength;

uchar PID[5];

uint dataLen;

uchar data[100];

} OBD2Response;

uchar frameType;

typedef struct {

uchar idType;

ulong messageId;

uchar RTR;

uchar DLC;

uchar data[8];

} CANDataFrame;

typedef struct {

uint dataLen;

uchar data[100];

} dataFrame;

typedef struct {

uchar service;

uchar PIDLength;

uchar PID[5];

} OBD2Request;

typedef struct {

uchar mode;

uchar PID;

} PIDInfo;

Page 149: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

148

typedef struct {

uchar priority;

uchar source;

uchar target;

uchar dataLen;

uchar data[7];

} frameFieldsISO9141;

typedef struct {

uchar data[7][10];

uchar dataLength;

uchar responseType;

} OBD2ResponseISO9141;

typedef struct {

uchar service;

uchar PIDLength;

uchar PID[5];

uint dataLen;

uchar data[100];

} OBD2Response;

typedef struct {

uchar service;

uchar PIDLength;

uchar PID[10];

uchar dataLen;

uchar data[100];

} responseFrame;

typedef struct {

uchar service;

uchar PIDLength;

uchar PID[10];

} requestFrame;

typedef struct {

uchar command;

uchar paramsLen;

uchar params[10];

} commandFrame;

typedef struct {

uchar errorCode;

} negativeResponseFrame;

Page 150: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

149

IO.h

#include "Types.h"

void setPinMode(uchar* port, uchar pin, uchar mode);

void setPin(uchar* port, uchar pin);

void resetPin(uchar* port, uchar pin);

uchar readPin(uchar* port, uchar pin);

SPI_Master.h

#include "Types.h"

void initSPIMaster();

void closeSPIMaster();

uchar transferSPI(uchar byteToSend);

TIMER0.h

#include "Types.h"

void initTMR0();

TIMER3.h

#include "Types.h"

void initTMR3();

USART.h

#include "Types.h"

void sendByteUart(uchar byteToSend);

void sendBytesUart(uchar dataLen, uchar* bytesToSend);

uchar receiveByteUart(uchar* byteReceived);

uchar receiveBytesUart(dataFrame* bytesToReceive);

void flushRxBufferUart();

void initUart();

void closeUart();

void setUartBaud(uint baud);

BT_Interface.c

#include "BT_Interface.h"

#include "Types.h"

#include "Macros.h"

#include "SW_UART.h"

#include <xc.h>

void sendResponseFrame(responseFrame response) {

dataFrame txBuffer;

uchar chksum = 0;

txBuffer.data[0] = responseFrameId;

txBuffer.data[1] = response.service;

txBuffer.data[2] = response.PIDLength;

for(uchar i = 0; i < response.PIDLength; i++) {

Page 151: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

150

txBuffer.data[3 + i] = response.PID[i];

}

txBuffer.data[3 + response.PIDLength] = response.dataLen;

for(uchar i = 0; i < response.dataLen; i++) {

txBuffer.data[4 + response.PIDLength + i] = response.data[i];

}

for(uchar i = 0; i < (4 + response.PIDLength + response.dataLen); i++) {

chksum += txBuffer.data[i];

}

txBuffer.data[4 + response.PIDLength + response.dataLen] = chksum;

txBuffer.dataLen = 5 + response.PIDLength + response.dataLen;

sendBytesSoftwareUART(txBuffer);

}

void sendErrorFrame(negativeResponseFrame negativeResponse) {

dataFrame txBuffer;

uchar chksum = 0;

txBuffer.data[0] = negativeResponseFrameId;

txBuffer.data[1] = negativeResponse.errorCode;

chksum = txBuffer.data[0] + txBuffer.data[1];

txBuffer.data[2] = chksum;

txBuffer.dataLen = 3; // On a Error Frame thera are always 3 bytes(id + errorCode +

chksum)

sendBytesSoftwareUART(txBuffer);

}

void sendCommandConfirmation(commandFrame command) {

dataFrame txBuffer;

uchar chksum = 0;

txBuffer.data[0] = commandConfirmationFrameId;

txBuffer.data[1] = command.command;

txBuffer.data[2] = command.paramsLen;

for(uchar i = 0; i < command.paramsLen; i++) {

txBuffer.data[3 + i] = command.params[i];

}

for(uchar i = 0; i < (3 + command.paramsLen); i++) {

chksum += txBuffer.data[i];

}

Page 152: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

151

txBuffer.data[3 + command.paramsLen] = chksum;

txBuffer.dataLen = 4 + command.paramsLen;

sendBytesSoftwareUART(txBuffer);

}

uchar receiveFrame(uchar* frameReceivedId, requestFrame* request, commandFrame*

command) {

uchar receivedChksum;

uchar computedChksum = 0;

if(receiveByteSoftwareUART(frameReceivedId)) {

switch(*frameReceivedId) {

case requestFrameId:

if(!receiveByteSoftwareUART(&request->service)) return 0;

if(!receiveByteSoftwareUART(&request->PIDLength)) return 0;

for(uchar i = 0; i < request->PIDLength; i++) {

if(!receiveByteSoftwareUART(&request->PID[i])) return 0;

}

if(!receiveByteSoftwareUART(&receivedChksum)) return 0;

computedChksum += requestFrameId;

computedChksum += request->service;

computedChksum += request->PIDLength;

for(uchar i = 0; i < request->PIDLength; i++) {

computedChksum += request->PID[i];

}

if(receivedChksum != computedChksum) return 0;

return 1;

break;

case commandFrameId:

if(!receiveByteSoftwareUART(&command->command)) return 0;

if(!receiveByteSoftwareUART(&command->paramsLen)) return 0;

for(uchar i = 0; i < command->paramsLen; i++) {

if(!receiveByteSoftwareUART(&command->params[i])) return 0;

}

if(!receiveByteSoftwareUART(&receivedChksum)) return 0;

computedChksum += commandFrameId;

computedChksum += command->command;

computedChksum += command->paramsLen;

for(uchar i = 0; i < command->paramsLen; i++) {

Page 153: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

152

computedChksum += command->params[i];

}

if(receivedChksum != computedChksum) return 0;

return 1;

break;

default:

//Unidentified receieved frame

return 0;

}

} else return 0;

}

ISO15765_4.c

#include "ISO15765_4.h"

#include "Types.h"

#include "Macros.h"

#include "MCP2515.h"

#include <xc.h>

uchar nFramesToReceive(uchar dataLen) {

uchar n = 1;

while(n*7 < dataLen) n++; // each received frame contains 7 bytes of data.

return n;

}

uchar sendFlowControlFrameISOTP(uchar flowStatus, uchar blockSize, uchar

separationTime) {

CANDataFrame frameToSend;

frameToSend.idType = frameType;

frameToSend.messageId = 0x7E0;

frameToSend.RTR = CAN_FRAME_IS_NOT_RTR;

frameToSend.DLC = 8;

frameToSend.data[0] = (FLOW_CONTROL << 4) | (flowStatus & 0x0F);

frameToSend.data[1] = blockSize;

frameToSend.data[2] = separationTime;

frameToSend.data[3] = 0xAA;

frameToSend.data[4] = 0xAA;

frameToSend.data[5] = 0xAA;

frameToSend.data[6] = 0xAA;

frameToSend.data[7] = 0xAA;

return sendCANFrameBuffer0(frameToSend);

}

uchar sendSingleFrameISOTP(dataFrame dataToSend) {

CANDataFrame frameToSend;

Page 154: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

153

frameToSend.idType = frameType;

frameToSend.messageId = 0x7DF;

frameToSend.RTR = CAN_FRAME_IS_NOT_RTR;

frameToSend.DLC = 8;

frameToSend.data[0] = (SINGLE_FRAME << 4) | (dataToSend.dataLen & 0x0F);

for(uchar i = 0; i < dataToSend.dataLen; i++) {

frameToSend.data[i + 1] = dataToSend.data[i];

}

for(uchar i = (dataToSend.dataLen + 1); i < 8; i++) {

frameToSend.data[i] = 0xAA;

}

return sendCANFrameBuffer0(frameToSend);

}

uchar receiveConsecutiveFrameISOTP(uchar* sequenceNumber, uchar data[7]) {

CANDataFrame frameToReceive;

if(!receiveRX0BufferMCP2515(&frameToReceive)) return 0;

if(((frameToReceive.data[0] & 0xF0) >> 4) != CONSECUTIVE_FRAME) return 0;

*sequenceNumber = frameToReceive.data[0] & 0x0F;

for(uchar i = 0; i < 7; i++) {

data[i] = frameToReceive.data[i + 1];

}

return 1;

}

uchar receiveResponseISOTP(dataFrame* dataReceived) {

CANDataFrame frameToReceive;

uchar nConsecutiveFrames;

uchar rxBuffer[7];

uchar sequenceNumber;

if(!receiveRX0BufferMCP2515(&frameToReceive)) return 0;

switch((frameToReceive.data[0] & 0xF0) >> 4) {

case SINGLE_FRAME:

dataReceived->dataLen = frameToReceive.data[0] & 0x0F;

for(uchar i = 0; i < dataReceived->dataLen; i++) {

dataReceived->data[i] = frameToReceive.data[i + 1];

}

return 1;

Page 155: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

154

break;

case FIRST_FRAME:

dataReceived->dataLen = ((frameToReceive.data[0] & 0x0F) << 8) |

frameToReceive.data[1];

for(uchar i = 0; i < 6; i++) {

dataReceived->data[i] = frameToReceive.data[i + 2];

}

nConsecutiveFrames = nFramesToReceive(dataReceived->dataLen - 6);

if(!sendFlowControlFrameISOTP(0, 0, 5)) return 0; // 0, 0 and 5 are FS, BS

and STmin parameters.

for(uchar i = 0; i < nConsecutiveFrames; i++) {

if(!receiveConsecutiveFrameISOTP(&sequenceNumber, rxBuffer)) return 0;

for(uchar j = 0; j < 7; j++) {

dataReceived->data[6 + i*7 + j] = rxBuffer[j];

}

}

return 1;

break;

default:

// Unidentified response type.

return 0;

break;

}

}

uchar sendOBD2RequestISO15765_4(OBD2Request request, OBD2Response* response) {

dataFrame dataToSend;

dataFrame dataReceived;

dataToSend.dataLen = 1 + request.PIDLength;

dataToSend.data[0] = request.service;

for(uchar i = 1; i < dataToSend.dataLen; i++) {

dataToSend.data[i] = request.PID[i - 1];

}

if(!sendSingleFrameISOTP(dataToSend)) return 0;

if(!receiveResponseISOTP(&dataReceived)) return 0;

response->service = request.service;

response->PIDLength = request.PIDLength;

Page 156: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

155

for(uchar i = 0; i < request.PIDLength; i++) {

response->PID[i] = request.PID[i];

}

response->dataLen = dataReceived.dataLen - request.PIDLength - 1;

for(uchar i = 0; i < response->dataLen; i++) {

response->data[i] = dataReceived.data[request.PIDLength + 1 + i];

}

return 1;

}

ISO9141_2.h

#include "ISO9141_2.h"

#include "Macros.h"

#include "Types.h"

#include "USART.h"

#include "math.h"

#include "IO.h"

#include "Time.h"

#include <xc.h>

void sendByte5baud(uchar byteToSend, uchar* trisPort, uchar* latPort, uchar TXPin) {

uchar bitMask;

setPinMode(trisPort, TXPin, OUTPUT); // Set pin TX as an output

setPin(latPort, TXPin); // Set pin TX

wait(1000); // Wait till k-line gets high

resetPin(latPort, TXPin);

wait(200);

//Now the transmission starts

for(uchar i = 0; i < 8; i++) {

bitMask = pow(2, i);

if(byteToSend & bitMask) setPin(latPort, TXPin); else resetPin(latPort, TXPin);

wait(200); // Tbit is 200 ms

}

setPin(latPort, TXPin);

wait(200);

}

uchar initISO9141() {

uchar byteReceived;

dataFrame keyBytes;

keyBytes.dataLen = 2;

Page 157: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

156

closeUart(); // Disable hardware UART so we can work with a software UART in the

same pins

sendByte5baud(initByteISO9141, TRISC_ADRESS, PORTC_ADRESS, 6); // Send

initialization byte 0x33 at 5 Baud

initUart();

setUartBaud(10400);

if(!receiveByteUart(&byteReceived)) return 0;

if(byteReceived != 0x55) return 0; // If first car response is invalid then return 0

(valid response is 0x55)

if(!receiveBytesUart(&keyBytes)) return 0;

if((keyBytes.data[0] != 0x08 && keyBytes.data[0] != 0x94) || (keyBytes.data[1] !=

0x08 && keyBytes.data[1] != 0x94) || keyBytes.data[0] != keyBytes.data[1]) return 0; //

If key bytes are invalid then retorn 0, vali keybytes are 08 08 or 94 94

wait(30); // This delay is a protocol spec

sendByteUart(~keyBytes.data[0]); // Send keyByte #2 inverted

receiveByteUart(&byteReceived); // receive echo..

if(!receiveByteUart(&byteReceived)) return 0;

if(byteReceived != 0xCC) return 0;

return 1; // If reached here means that initilitzation has been succesfull, so 1 is

returned

}

void sendFrameISO9141(frameFieldsISO9141 frameFields) {

uchar txBuffer[11]; // Length of TX buffer is setted considering that a maximum of

7 bytes of data can be sended with a single frame

uchar checksum = 0;

txBuffer[0] = frameFields.priority; // First byte of ISO9141 frame is format byte

txBuffer[1] = frameFields.target; // Second byte is target adress

txBuffer[2] = frameFields.source; // Third byte is source adress

// Next lines add data bytes to frame

for(uchar i = 0; i < frameFields.dataLen; i++) {

txBuffer[3 + i] = frameFields.data[i];

}

// Checksum of frame is computed

for(uchar i = 0; i < (3 + frameFields.dataLen); i++) {

checksum += txBuffer[i];

}

txBuffer[3 + frameFields.dataLen] = checksum; // Add checksum of frame

// Finally the built frame is sended

for(uchar i = 0; i < (4 + frameFields.dataLen); i++) {

Page 158: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

157

sendByteUart(txBuffer[i]);

wait(10); // Wait 10 ms between sended bytes as ISO9141 specifies

flushRxBufferUart(); // each byte that is sended produces an echo that is

received through UART, so it has to be cleared

}

}

uchar receiveSingleFrameISO9141(frameFieldsISO9141* frameFields) {

uchar rxBuffer[11];

uchar checksum = 0;

for(uchar i = 0; i < (frameFields->dataLen + 4); i++) {

if(!receiveByteUart(rxBuffer + i)) return 5;

}

for(uchar i = 0; i < (frameFields->dataLen + 3); i++) {

checksum += rxBuffer[i];

}

if(checksum != rxBuffer[frameFields->dataLen + 3]) return 0;

frameFields->priority = rxBuffer[0];

frameFields->target = rxBuffer[1];

frameFields->source = rxBuffer[2];

for(uchar i = 3; i < (frameFields->dataLen + 3); i++) {

frameFields->data[i - 3] = rxBuffer[i];

}

return 1;

}

uchar receiveMultipleFramesISO9141(frameFieldsISO9141* framesFields, uchar

framesToReceive) {

uchar rxBuffer[110];

uchar checksum = 0;

for(uchar i = 0; i < (framesToReceive*11); i++) {

if(!receiveByteUart(rxBuffer + i)) return 0;

}

for(uchar frame = 0; frame < framesToReceive; frame++) {

for(uchar i = (frame*11); i < (frame*11 + 10); i++) {

checksum += rxBuffer[i];

}

if(checksum != rxBuffer[frame*11 + 10]) return 0;

Page 159: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

158

checksum = 0;

}

for(uchar frame = 0; frame < framesToReceive; frame++) {

(framesFields + frame)->priority = rxBuffer[frame*11];

(framesFields + frame)->target = rxBuffer[frame*11 + 1];

(framesFields + frame)->source = rxBuffer[frame*11 + 2];

(framesFields + frame)->dataLen = 7;

for(uchar i = 0; i < 7; i++) {

(framesFields + frame)->data[i] = rxBuffer[frame*11 + 3 + i];

}

}

return 1;

}

uchar getVINLengthISO9141(uchar* framesToReceive) {

frameFieldsISO9141 frameToSend;

frameFieldsISO9141 frameReceived;

frameToSend.priority = PRIORITY_FIELD_ISO9141;

frameToSend.target = TARGET_FIELD_ISO9141;

frameToSend.source = SOURCE_FIELD_ISO9141;

frameToSend.dataLen = 2;

frameToSend.data[0] = 9;

frameToSend.data[1] = 1;

frameReceived.dataLen = 3;

sendFrameISO9141(frameToSend);

if(!receiveSingleFrameISO9141(&frameReceived)) return 0;

*framesToReceive = frameReceived.data[2];

return 1;

}

uchar getDTCBytesISO9141(uchar* bytesToReceive) {

frameFieldsISO9141 frameToSend;

frameFieldsISO9141 frameReceived;

frameToSend.priority = PRIORITY_FIELD_ISO9141;

frameToSend.target = TARGET_FIELD_ISO9141;

frameToSend.source = SOURCE_FIELD_ISO9141;

frameToSend.dataLen = 2;

frameToSend.data[0] = 1;

frameToSend.data[1] = 1;

frameReceived.dataLen = 6;

sendFrameISO9141(frameToSend);

if(!receiveSingleFrameISO9141(&frameReceived)) return 0;

Page 160: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

159

*bytesToReceive = (frameReceived.data[2] & 0x7F)*2;

return 1;

}

uchar nFramesToReceive2(uchar dataLen) {

uchar n = 1;

while(n*6 < dataLen) n++; // each received frames contains 6 bytes of data.

return n;

}

uchar getResponseLengthISO9141(OBD2Request requestedPID, uchar* dataLength) {

uchar queryResult;

uint PID = 0;

uchar aux;

for(uchar i = 0; i < requestedPID.PIDLength; i++) {

PID |= requestedPID.PID[i] << i*8;

}

if((requestedPID.service == 1) || (requestedPID.service == 2)) {

switch(PID) {

case 0x0:

*dataLength = 4;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x1:

*dataLength = 4;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x2:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x3:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x4:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x5:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x6:

Page 161: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

160

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x7:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x8:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x9:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0xA:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0xB:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0xC:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0xD:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0xE:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0xF:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x10:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x11:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x12:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

Page 162: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

161

case 0x13:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x14:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x15:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x16:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x17:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x18:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x19:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x1A:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x1B:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x1C:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x1D:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x1E:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x1F:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

Page 163: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

162

case 0x20:

*dataLength = 4;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x21:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x22:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x23:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x24:

*dataLength = 4;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x25:

*dataLength = 4;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x26:

*dataLength = 4;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x27:

*dataLength = 4;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x28:

*dataLength = 4;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x29:

*dataLength = 4;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x2A:

*dataLength = 4;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x2B:

*dataLength = 4;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x2C:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

Page 164: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

163

break;

case 0x2D:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x2E:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x2F:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x30:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x31:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x32:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x33:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x34:

*dataLength = 4;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x35:

*dataLength = 4;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x36:

*dataLength = 4;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x37:

*dataLength = 4;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x38:

*dataLength = 4;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x39:

*dataLength = 4;

Page 165: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

164

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x3A:

*dataLength = 4;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x3B:

*dataLength = 4;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x3C:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x3D:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x3E:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x3F:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x40:

*dataLength = 4;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x41:

*dataLength = 4;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x42:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x43:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x44:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x45:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x46:

Page 166: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

165

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x47:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x48:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x49:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x4A:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x4B:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x4C:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x4D:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x4E:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x4F:

*dataLength = 4;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x50:

*dataLength = 4;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x51:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x52:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

Page 167: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

166

case 0x53:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x54:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x55:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x56:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x57:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x58:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x59:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x5A:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x5B:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x5C:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x5D:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x5E:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x5F:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

Page 168: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

167

case 0x60:

*dataLength = 4;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x61:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x62:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x63:

*dataLength = 2;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x64:

*dataLength = 5;

queryResult = SINGLE_FRAME_RESPONSE;

break;

default:

queryResult = PID_NOT_SUPPORTED;

break;

}

} else if(requestedPID.service == 3) {

// In this case we don't know length of response so we have to request it

if(getDTCBytesISO9141(&aux)) queryResult = MULTIPLE_FRAMES_RESPONSE; else

queryResult = PID_NOT_SUPPORTED;

*dataLength = nFramesToReceive2(aux);

} else if(requestedPID.service == 4) {

*dataLength = 0;

queryResult = SINGLE_FRAME_RESPONSE;

} else if(requestedPID.service == 5) {

} else if(requestedPID.service == 6) {

} else if(requestedPID.service == 7) {

} else if(requestedPID.service == 8) {

} else if(requestedPID.service == 9) {

switch(PID) {

case 0x0:

*dataLength = 4;

queryResult = SINGLE_FRAME_RESPONSE;

Page 169: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

168

case 0x01:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

break;

case 0x02:

// In this case we don't know length of response so we have to request it

if(getVINLengthISO9141(dataLength)) queryResult = MULTIPLE_FRAMES_RESPONSE;

else queryResult = PID_NOT_SUPPORTED;

break;

case 0x03:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

case 0x04:

if(getVINLengthISO9141(dataLength)) queryResult = MULTIPLE_FRAMES_RESPONSE;

else queryResult = PID_NOT_SUPPORTED;

case 0x05:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

case 0x06:

if(getVINLengthISO9141(dataLength)) queryResult = MULTIPLE_FRAMES_RESPONSE;

else queryResult = PID_NOT_SUPPORTED;

case 0x07:

*dataLength = 1;

queryResult = SINGLE_FRAME_RESPONSE;

case 0x0A:

if(getVINLengthISO9141(dataLength)) queryResult = MULTIPLE_FRAMES_RESPONSE;

else queryResult = PID_NOT_SUPPORTED;

default:

queryResult = PID_NOT_SUPPORTED;

break;

}

} else if(requestedPID.service == 10) {

} else if(requestedPID.service == 11) {

} else queryResult = PID_NOT_SUPPORTED;

return queryResult;

}

uchar sendOBD2RequestISO9141(OBD2Request requestedPID, OBD2Response* respondedData) {

uchar aux1;

frameFieldsISO9141 requestFrame;

frameFieldsISO9141 responseFrames[10];

uchar responseType;

uchar aux = 0;

uchar dataa[100];

Page 170: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

169

uchar ji = 0;

// Value of fields are assigned on the following lines

requestFrame.priority = PRIORITY_FIELD_ISO9141;

requestFrame.target = TARGET_FIELD_ISO9141;

requestFrame.source = SOURCE_FIELD_ISO9141;

requestFrame.dataLen = requestedPID.PIDLength + 1; // Data length is pid length + 1

byte of service

requestFrame.data[0] = requestedPID.service; // First data byte is always service

// Now we have to add the PID to data field

for(uchar i = 0; i < requestedPID.PIDLength; i++) {

requestFrame.data[i + 1] = requestedPID.PID[i];

}

responseType = getResponseLengthISO9141(requestedPID, &aux1); // ????Data length

and response type is obtained form another function

sendFrameISO9141(requestFrame); // Built frame with PID request is sended

switch(responseType) {

// If response is delivered with a single frame we have to call

receiveSingleFrameISO9141

case SINGLE_FRAME_RESPONSE:

responseFrames[0].dataLen = aux1 + 1 + requestedPID.PIDLength;

if(!receiveSingleFrameISO9141(responseFrames)) return 0; // if response not

received or not valid abort

for(uchar i = 0; i < aux1; i++) {

respondedData->data[i] = responseFrames[0].data[i + 1 +

requestedPID.PIDLength]; // copy data bytes from responded frame to output struct

respondedData

}

respondedData->service = requestedPID.service;

respondedData->PIDLength = requestedPID.PIDLength;

for(uchar i = 0; i < requestedPID.PIDLength; i++) respondedData->PID[i] =

requestedPID.PID[i];

respondedData->dataLen = aux1;

return 1; // request done with success

break;

// If response is delivered with multiple frames we have to call

receiveMultipleFramesISO9141

case MULTIPLE_FRAMES_RESPONSE:

if(!receiveMultipleFramesISO9141(responseFrames, aux1)) return 0; // if frame

not received or not valid abort

if(requestedPID.service != 3) {

for(uchar i = 0; i < aux1; i++) {

for(uchar j = 3; j < 7; j++) {

Page 171: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

170

respondedData->data[aux] = responseFrames[i].data[j]; // Copy data

bytes from received frame to output struct respondedData

aux++;

}

}

} else {

for(uchar i = 0; i < aux1; i++) {

for(uchar j = 1; j < 7; j++) {

respondedData->data[aux] = responseFrames[i].data[j]; // Copy data

bytes from received frame to output struct respondedData

aux++;

}

}

}

respondedData->dataLen = aux;

respondedData->service = requestedPID.service;

respondedData->PIDLength = requestedPID.PIDLength;

for(uchar i = 0; i < requestedPID.PIDLength; i++) respondedData->PID[i] =

requestedPID.PID[i];

return 1; // request done with success

break;

// If data length is not known then PID is not supprted

case PID_NOT_SUPPORTED:

return 0;

break;

}

}

MCP2515.c

#include "MCP2515.h"

#include "Types.h"

#include "Macros.h"

#include "SPI_Master.h"

#include "Time.h"

#include <xc.h>

extern volatile uint tics;

void initMCP2515() {

TRISBbits.RB2 = 0; // Set pin connected to /CS of MCP2515 as an output

PORTBbits.RB2 = 1; // MCP2515 not selected

}

Page 172: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

171

void startCOMMCP2515() {

PORTBbits.RB2 = 0;

}

void stopCOMMCP2515() {

PORTBbits.RB2 = 1;

}

uchar readRegisterMCP2515(uchar regAdress) {

uchar regValue;

startCOMMCP2515();

transferSPI(0x03); // First byte to send is instruction ID, 0x03 is to read a

register (dummy data received)

transferSPI(regAdress); // Second byte is register adress (dummy data received)

regValue = transferSPI(0); // Received byte is value of register (dummy data

sended)

stopCOMMCP2515();

return regValue;

}

void writeRegisterMCP2515(uchar regAdress, uchar value) {

startCOMMCP2515(); // Set MCP2515 /CS low

transferSPI(0x02); // First byte to send is instruction ID, 0x02 is to write a

register (dummy data received)

transferSPI(regAdress); // Second byte is register adress (dummy data received)

transferSPI(value); // Received byte is value of register (dummy data sended)

stopCOMMCP2515(); // Set MCP2515 /CS HIGH

return;

}

void bitModifyMCP2515(uchar regAdress, uchar mask, uchar value) {

startCOMMCP2515(); // Set MCP2515 /CS low

transferSPI(0x05); // First byte to send is instruction ID, 0x02 is to write a

register (dummy data received)

transferSPI(regAdress); // Second byte is register adress (dummy data received)

transferSPI(mask); // Third byte the bit mask (dummy data received)

transferSPI(value); // Fourth byte is the value to set to those bits that are going

to be modified

stopCOMMCP2515(); // Set MCP2515 /CS HIGH

return;

}

void resetMCP2515(void) {

Page 173: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

172

startCOMMCP2515(); // Set MCP2515 /CS low

transferSPI(0xC0); // First byte to send is instruction ID, 0xC0 is to reset

MCP2515

stopCOMMCP2515(); // Set MCP2515 /CS HIGH

return;

}

uchar setModeMCP2515(uchar mode) {

uchar value;

uchar readingAttempts = 0;

// Value will have a value according to selected mode

switch(mode) {

case MCP2515_CONFIG_MODE:

value = 0x80;

break;

case MCP2515_NORMAL_MODE:

value = 0x00;

break;

case MCP2515_SLEEP_MODE:

value = 0x20;

break;

case MCP2515_LISTEN_ONLY_MODE:

value = 0x60;

break;

case MCP2515_LOOPBACK_MODE:

value = 0x40;

break;

default:

value = 0x80;

}

bitModifyMCP2515(CANCTRL, 0xE0, value); // Modify mode bits to set desired mode

while(1) {

if(readingAttempts == 10) return 0; // if after 10 attempts mode isn't set then 0

is returned

wait(200); // Give time to MCP2515 to change his mode

if((readRegisterMCP2515(CANSTAT) & 0xE0) == value) return 1; // if mode is

correctly set return 1

readingAttempts++;

}

}

void initCAN(uchar baudRate) {

Page 174: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

173

setModeMCP2515(MCP2515_CONFIG_MODE); // First we have to put MCP2515 in donfig mode

bitModifyMCP2515(CNF2, 0x07, 0x01); // PropSeg is 2 time quanta

bitModifyMCP2515(CNF2, 0x38, 0x30); // PS1 segment is 7 time quanta

bitModifyMCP2515(CNF2, 0x80, 0x80); // BTLMODE bit = 1 so we can manually set PS2

time quanta

bitModifyMCP2515(CNF3, 0x07, 0x05); // PS2 segment is 6 time quanta

bitModifyMCP2515(CNF1, 0xC0, 0x00); // SJW segment is 1 time quanta

// Baud rate will be set according to baudRate parameter

switch(baudRate) {

case CAN_SPEED_250KBPS:

bitModifyMCP2515(CNF1, 0x3F, 0x01);

break;

case CAN_SPEED_500KBPS:

bitModifyMCP2515(CNF1, 0x3F, 0x00);

break;

default:

bitModifyMCP2515(CNF1, 0x3F, 0x01); // Default speed is 250KBPS

}

setModeMCP2515(MCP2515_NORMAL_MODE); // To end initialitzation normal mode has to

be set

}

uchar sendCANFrameBuffer0(CANDataFrame dataFrame) {

uchar TXB0CTRL_;

uchar TXB0SIDL_;

uchar TXB0SIDH_;

uchar TXB0EID8_;

uchar TXB0EID0_;

bitModifyMCP2515(TXB0CTRL, 0x03, HIGHEST_MESSAGE_PRIORITY); // Give buffer 0

highest priority

// Set id type and id of data frame to transmit

switch(dataFrame.idType) {

case CAN_STANDARD_FRAME:

TXB0SIDH_ = dataFrame.messageId >> 3;

TXB0SIDL_ = dataFrame.messageId << 5;

writeRegisterMCP2515(TXB0SIDH, TXB0SIDH_);

writeRegisterMCP2515(TXB0SIDL, TXB0SIDL_);

break;

case CAN_EXTENDED_FRAME:

TXB0SIDH_ = dataFrame.messageId >> 21;

TXB0SIDL_ = ((dataFrame.messageId >> 13) & 0x00E0) | ((dataFrame.messageId >> 16)

& 0x0003) | 0x0008;

TXB0EID8_ = dataFrame.messageId >> 8;

TXB0EID0_ = dataFrame.messageId;

writeRegisterMCP2515(TXB0SIDH, TXB0SIDH_);

writeRegisterMCP2515(TXB0SIDL, TXB0SIDL_);

writeRegisterMCP2515(TXB0EID8, TXB0EID8_);

writeRegisterMCP2515(TXB0EID0, TXB0EID0_);

break;

}

Page 175: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

174

bitModifyMCP2515(TXB0DLC, 0x40, 0x40); // RTR bit

bitModifyMCP2515(TXB0DLC, 0x0F, dataFrame.DLC); // DLC field

// Write n bytes in TX buffer0

for(uchar i = 0; i < dataFrame.DLC; i++) {

writeRegisterMCP2515(TXB0D0 + i, dataFrame.data[i]);

}

bitModifyMCP2515(TXB0CTRL, 0x08, 0x08); // Start transmission

// Now we have to wait until transmission has been completed

while(1) {

wait(10); // Check transmission bits every 10 ms

TXB0CTRL_ = readRegisterMCP2515(TXB0CTRL);

if(!(TXB0CTRL_ & 0x08)) return 1; // Message succesfully transmited, return 1

if(TXB0CTRL_ & 0x10) {

bitModifyMCP2515(TXB0CTRL, 0x08, 0x00); // Abort transmission

return 0; // Message not transmited, return 0

}

}

}

void configRX0BufferMCP2515(uchar IdType, ulong bufferFilter, ulong bufferMask) {

uchar RXF0SIDH_;

uchar RXF0SIDL_;

uchar RXF0EID8_;

uchar RXF0EID0_;

uchar RXM0SIDH_;

uchar RXM0SIDL_;

uchar RXM0EID8_;

uchar RXM0EID0_;

setModeMCP2515(MCP2515_CONFIG_MODE);

switch(IdType) {

case CAN_EXTENDED_FRAME:

writeRegisterMCP2515(RXB0CTRL, 0x40); // Only receive extended frames

// Write filter value

RXF0SIDH_ = bufferFilter >> 21;

RXF0SIDL_ = ((bufferFilter >> 13) & 0xE0) | 0x08 | ((bufferFilter >> 16) &

0x03);

RXF0EID8_ = bufferFilter >> 8;

RXF0EID0_ = bufferFilter;

writeRegisterMCP2515(RXF0SIDH, RXF0SIDH_);

writeRegisterMCP2515(RXF0SIDL, RXF0SIDL_);

writeRegisterMCP2515(RXF0EID8, RXF0EID8_);

writeRegisterMCP2515(RXF0EID0, RXF0EID0_);

// Write filter mask

RXM0SIDH_ = bufferMask >> 21;

RXM0SIDL_ = ((bufferMask >> 13) & 0xE0) | ((bufferMask >> 16) & 0x03);

Page 176: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

175

RXM0EID8_ = bufferMask >> 8;

RXM0EID0_ = bufferMask;

writeRegisterMCP2515(RXM0SIDH, RXM0SIDH_);

writeRegisterMCP2515(RXM0SIDL, RXM0SIDL_);

writeRegisterMCP2515(RXM0EID8, RXM0EID8_);

writeRegisterMCP2515(RXM0EID0, RXM0EID0_);

break;

case CAN_STANDARD_FRAME:

writeRegisterMCP2515(RXB0CTRL, 0x20); // Only receive standard frames

// Write filter value

RXF0SIDH_ = bufferFilter >> 3;

RXF0SIDL_ = bufferFilter << 5;

writeRegisterMCP2515(RXF0SIDH, RXF0SIDH_);

writeRegisterMCP2515(RXF0SIDL, RXF0SIDL_);

// Write filter mask

RXM0SIDH_ = bufferMask >> 3;

RXM0SIDL_ = bufferMask << 5;

writeRegisterMCP2515(RXM0SIDH, RXM0SIDH_);

writeRegisterMCP2515(RXM0SIDL, RXM0SIDL_);

break;

default:

writeRegisterMCP2515(RXB0CTRL, 0x20); // Only receive standard frames

// Write filter value

RXF0SIDH_ = bufferFilter >> 3;

RXF0SIDL_ = bufferFilter << 5;

writeRegisterMCP2515(RXF0SIDH, RXF0SIDH_);

writeRegisterMCP2515(RXF0SIDL, RXF0SIDL_);

// Write filter mask

RXM0SIDH_ = bufferMask >> 3;

RXM0SIDL_ = bufferMask << 5;

writeRegisterMCP2515(RXM0SIDH, RXM0SIDH_);

writeRegisterMCP2515(RXM0SIDL, RXM0SIDL_);

}

setModeMCP2515(MCP2515_NORMAL_MODE);

}

void emptyRX0BufferMCP2515() {

bitModifyMCP2515(CANINTF, 0x01, 0);

}

uchar receiveRX0BufferMCP2515(CANDataFrame* dataFrame) { // THIS FUNCTION WAITS FOR RX0

FLAG TO SET

uchar CANINTF_;

uchar RXB0SIDL_;

uchar RXB0SIDH_;

uchar RXB0EID8_;

uchar RXB0EID0_;

Page 177: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

176

CANINTF_ = readRegisterMCP2515(CANINTF);

tics = 0;

while(!(CANINTF_ & 0x01) && (tics < CAN_RX_TIMEOUT)) { // Falta el timeout

CANINTF_ = readRegisterMCP2515(CANINTF);

}

if(CANINTF_ & 0x01) {

RXB0SIDL_ = readRegisterMCP2515(RXB0SIDL);

if(RXB0SIDL_ & 0x08) {

// Extended frame received

dataFrame->idType = CAN_EXTENDED_FRAME;

RXB0SIDH_ = readRegisterMCP2515(RXB0SIDH);

RXB0EID8_ = readRegisterMCP2515(RXB0EID8);

RXB0EID0_ = readRegisterMCP2515(RXB0EID0);

dataFrame->messageId = (RXB0SIDH_ << 21) | ((RXB0SIDL_ & 0xE0) << 13) |

(RXB0EID8_ << 8) | RXB0EID0_;

} else {

// Standard frame received

dataFrame->idType = CAN_STANDARD_FRAME;

RXB0SIDH_ = readRegisterMCP2515(RXB0SIDH);

dataFrame->messageId = (RXB0SIDH_ << 3) | (RXB0SIDL_ >> 5);

}

dataFrame->RTR = readRegisterMCP2515(RXB0DLC) & 0x40;

dataFrame->DLC = readRegisterMCP2515(RXB0DLC) & 0x0F;

for(uchar i = 0; i < dataFrame->DLC; i++) {

dataFrame->data[i] = readRegisterMCP2515(RXB0D0 + i);

}

emptyRX0BufferMCP2515();

return 1;

} else return 0;

}

math.c

#include "math.h"

#include "Types.h"

#include "Macros.h"

#include <xc.h>

Page 178: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

177

long pow(char baseNumber, char exponentNumber) {

long result = 1;

for(char i = 0; i < exponentNumber; i++) result *= baseNumber;

return result;

};

SW_UART.h

#include "SW_UART.h"

#include "Types.h"

#include "Macros.h"

#include "Time.h"

#include <xc.h>

extern volatile uint tics;

uchar reverseByte(uchar x) {

// a simple table is used to obatin reversed byte

static const uchar table[] = {

0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,

0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,

0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,

0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,

0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,

0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,

0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,

0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,

0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,

0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,

0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,

0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,

0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,

0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,

0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,

0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,

0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,

0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,

0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,

0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,

0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,

0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,

0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,

0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,

0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,

0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,

0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,

0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,

0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,

0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,

0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,

0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,

};

return table[x];

}

void initSoftwareUART() {

Page 179: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

178

TRISDbits.TRISD2 = 0; // Set TX pin as an output

TRISDbits.TRISD1 = 1; // Set RX pin as an input

PORTDbits.RD2 = 1; // Set TX pin high

wait(1000); // delay to ensure that node 2 sees bus high

}

void sendByteSoftwareUART(uchar byteToSend) {

uchar bitmask = 1;

// Start Bit

PORTDbits.RD2 = 0;

delay9600baud();

// 8-bit data

for(uchar i = 0; i < 8; i++) {

if(byteToSend & bitmask) PORTDbits.RD2 = 1; else PORTDbits.RD2 = 0;

delay9600baud();

bitmask = bitmask << 1;

}

// Stop Bit

PORTDbits.RD2 = 1;

delay9600baud();

}

uchar receiveByteSoftwareUART(uchar* receivedByte) {

uint sampledBits = 0;

tics = 0;

while(PORTDbits.RD1 && (tics < 5000));

if(PORTDbits.RD1) return 0;

delay19200baud();

for(uchar i = 0; i < 10; i++) {

sampledBits = sampledBits << 1;

if(PORTDbits.RD1) sampledBits++;

delay9600baud();

}

if(((sampledBits & 0x0200) == 0) && ((sampledBits & 0x0001) > 0)) {

*receivedByte = (sampledBits >> 1) & 0x00FF;

*receivedByte = reverseByte(*receivedByte); // reverse bytes as it's received

MSBF

return 1;

} else return 0;

}

void sendBytesSoftwareUART(dataFrame dataToSend) {

for(uchar i = 0; i < dataToSend.dataLen; i++) {

sendByteSoftwareUART(dataToSend.data[i]);

Page 180: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

179

wait(5);

}

}

uchar receiveBytesSoftwareUART(dataFrame* dataToReceive) {

uchar i = 0;

while(1) {

if(i == 100) break; // Max data to receive is 100 bytes

if(receiveByteSoftwareUART(&dataToReceive->data[i])) i++; else break;

}

dataToReceive->dataLen = i;

if(dataToReceive->dataLen) return 1; else return 0;

}

Time.c

#include "Time.h"

#include "Types.h"

#include "Macros.h"

#include <xc.h>

volatile uint tics;

void wait(uint delay) {

tics = 0;

while(tics < delay);

}

void delay19200baud() {

uint TMR3Count;

TMR3H = 0;

TMR3L = 0;

do {

TMR3Count = TMR3L & 0x00FF;

TMR3Count |= (TMR3H << 8) & 0xFF00;

} while (TMR3Count < 156);

}

void delay9600baud() {

uint TMR3Count;

TMR3H = 0;

TMR3L = 0;

do {

TMR3Count = TMR3L & 0x00FF;

TMR3Count |= (TMR3H << 8) & 0xFF00;

Page 181: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

180

} while (TMR3Count < 312);

}

IO.c

#include "IO.h"

#include "Types.h"

#include "math.h"

#include "Macros.h"

#include <xc.h>

void setPinMode(uchar* port, uchar pin, uchar mode) {

uchar bitMask = pow(2, pin);

if(mode) {

*port = *port | bitMask;

} else {

bitMask = ~bitMask;

*port = *port & bitMask;

}

}

void setPin(uchar* port, uchar pin) {

uchar bitMask = pow(2, pin);

*port = *port | bitMask;

}

void resetPin(uchar* port, uchar pin) {

uchar bitMask = ~pow(2, pin);

*port = *port & bitMask;

}

uchar readPin(uchar* port, uchar pin) {

uchar bitMask = pow(2, pin);

uchar pinValue;

if(*port & bitMask) pinValue = 1; else pinValue = 0;

return pinValue;

}

SPI_Master.h

#include "SPI_Master.h"

#include "Types.h"

#include "Macros.h"

Page 182: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

181

#include <xc.h>

void initSPIMaster() {

// Master mode, clk = FOSC/16, in this case 1 MHz (FOSC = 16 MHz)

SSPCON1bits.SSPM3 = 0;

SSPCON1bits.SSPM2 = 0;

SSPCON1bits.SSPM1 = 0;

SSPCON1bits.SSPM0 = 1;

ADCON0 = 0; //

// Set all analog inputs as digital pins

ADCON1bits.PCFG3 = 1;

ADCON1bits.PCFG2 = 1;

ADCON1bits.PCFG1 = 1;

ADCON1bits.PCFG0 = 1;

TRISBbits.RB0 = 1; // Set SDI pin as input

TRISCbits.RC7 = 0; // Set SDO pin as output

TRISBbits.RB1 = 0; // Set SCL pin as output

SMP = 0; // SDI sample is done in the middle of time bit

BF = 0; // Clear buffer full bit

PIR1bits.SSPIF = 0; // Clear interrupt flag of SPI

// Mode 1,1 is utilized in this case (CKP = 0, CKE = 1)

SSPCON1bits.CKP = 1;

SSPSTATbits.CKE = 0;

SSPCON1bits.SSPEN = 1; // Enable serial port

}

void closeSPIMaster() {

SSPCON1bits.SSPEN = 0; // Disable MSSP

}

uchar transferSPI(uchar byteToSend) {

PIR1bits.SSPIF = 0; // Clear interrupt flag of SPI

SSPBUF = byteToSend; // Start transfer of data

while(!PIR1bits.SSPIF); // Wait until byte has been shifted

return SSPBUF; // return received data, might be dummy data

}

TIMER0.c

#include "TIMER0.h"

#include "Types.h"

#include "Macros.h"

#include <xc.h>

void initTMR0() {

T08BIT = 1;

T0CS = 0;

PSA = 0;

Page 183: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

182

T0PS2 = 1;

T0PS1 = 1;

T0PS0 = 0;

TMR0 = 0xA2;

INTCONbits.TMR0IF = 0;

INTCONbits.TMR0IE = 1;

ei();

TMR0ON = 1;

}

TIMER3.c

#include "TIMER3.h"

#include <xc.h>

void initTMR3() {

T3CONbits.RD16 = 1;

T3CONbits.T3CKPS1 = 1;

T3CONbits.T3CKPS0 = 0;

T3CONbits.TMR3CS = 0;

T3CONbits.TMR3ON = 1;

}

USART.c

#include "Macros.h"

#include "USART.h"

#include "Types.h"

#include "time.h"

#include "IO.h"

#include <xc.h>

extern volatile uint tics;

void sendByteUart(uchar byteToSend) {

TXREG = byteToSend;

nop(); // one instruction cycle delay

while(!TXIF);

}

void sendBytesUart(uchar dataLen, uchar* bytesToSend) {

uchar byteToSend;

for(uchar i = 0; i < dataLen; i++) {

byteToSend = *(bytesToSend + i);

sendByteUart(byteToSend);

wait(10);

}

}

uchar receiveByteUart(uchar* byteReceived) {

tics = 0;

Page 184: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

183

while(!RCIF && (tics < RX_TIMEOUT)); // Wait until a byte is available to read(tics

< RX_TIMEOUT)

if(RCIF) {

*byteReceived = RCREG;

RCIF = 0;

return 1;

} else return 0;

}

uchar receiveBytesUart(dataFrame* bytesToReceive) {

char byteReceived;

for(uchar i = 0; i < bytesToReceive->dataLen; i++) {

if(!receiveByteUart(&byteReceived)) return 0;

bytesToReceive->data[i] = byteReceived;

}

return 1;

}

void flushRxBufferUart() {

uchar byteReceived;

tics = 0;

while(!RCIF && tics < RX_TIMEOUT); // Wait until a byte is available to read

if(RCIF) {

byteReceived = RCREG;

RCIF = 0;

}

}

void initUart() {

setPinMode(TRISC_ADRESS, 6, INPUT); // Configure RC6/TX/CK pin as an input

setPinMode(TRISC_ADRESS, 7, INPUT); // Configure RC7/RX/DT/SDO pin as an input

SYNC = 0; // Asynchronous mode selected

SPEN = 1; // Serial port enabled

BRGH = 1; // High speed mode

BRG16 = 1; // 16-bit BRG

TXEN = 1; // Enable transmission

CREN = 1; // Enable reception

}

void closeUart() {

SPEN = 0; // Disable serial port

TXEN = 0; // Disable transmission

Page 185: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

184

CREN = 0; // Disable reception

}

void setUartBaud(uint baud) {

uint n;

n = FOSC / (4*baud) - 1;

SPBRGH = (n & 0xFF00) >> 8;

SPBRG = n & 0x00FF;

}

main.c

#pragma config PLLDIV = 1 // PLL Prescaler Selection bits (No prescale (4 MHz

oscillator input drives PLL directly))

#pragma config CPUDIV = OSC1_PLL2// System Clock Postscaler Selection bits ([Primary

Oscillator Src: /4][96 MHz PLL Src: /6])

#pragma config USBDIV = 2 // USB Clock Selection bit (used in Full-Speed USB mode

only; UCFG:FSEN = 1) (USB clock source comes from the 96 MHz PLL divided by 2)

// CONFIG1H

#pragma config FOSC = XTPLL_XT // Oscillator Selection bits (XT oscillator, PLL

enabled (XTPLL))

#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock

Monitor disabled)

#pragma config IESO = OFF // Internal/External Oscillator Switchover bit

(Oscillator Switchover mode disabled)

// CONFIG2L

#pragma config PWRT = OFF // Power-up Timer Enable bit (PWRT disabled)

#pragma config BOR = OFF // Brown-out Reset Enable bits (Brown-out Reset

disabled in hardware and software)

#pragma config BORV = 3 // Brown-out Reset Voltage bits (Minimum setting 2.05V)

#pragma config VREGEN = OFF // USB Voltage Regulator Enable bit (USB voltage

regulator disabled)

// CONFIG2H

#pragma config WDT = OFF // Watchdog Timer Enable bit (WDT disabled (control is

placed on the SWDTEN bit))

#pragma config WDTPS = 32768 // Watchdog Timer Postscale Select bits (1:32768)

// CONFIG3H

#pragma config CCP2MX = OFF // CCP2 MUX bit (CCP2 input/output is multiplexed with

RC1)

#pragma config PBADEN = OFF // PORTB A/D Enable bit (PORTB<4:0> pins are configured

as digital I/O on Reset)

#pragma config LPT1OSC = OFF // Low-Power Timer 1 Oscillator Enable bit (Timer1

configured for higher power operation)

#pragma config MCLRE = OFF // MCLR Pin Enable bit (RE3 input pin enabled; MCLR pin

disabled)

// CONFIG4L

#pragma config STVREN = OFF // Stack Full/Underflow Reset Enable bit (Stack

full/underflow will cause Reset)

#pragma config LVP = OFF // Single-Supply ICSP Enable bit (Single-Supply ICSP

disabled)

#pragma config ICPRT = OFF // Dedicated In-Circuit Debug/Programming Port (ICPORT)

Enable bit (ICPORT disabled)

Page 186: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

185

#pragma config XINST = OFF // Extended Instruction Set Enable bit (Instruction set

extension and Indexed Addressing mode disabled (Legacy mode))

// CONFIG5L

#pragma config CP0 = OFF // Code Protection bit (Block 0 (000800-001FFFh) is not

code-protected)

#pragma config CP1 = OFF // Code Protection bit (Block 1 (002000-003FFFh) is not

code-protected)

#pragma config CP2 = OFF // Code Protection bit (Block 2 (004000-005FFFh) is not

code-protected)

#pragma config CP3 = OFF // Code Protection bit (Block 3 (006000-007FFFh) is not

code-protected)

// CONFIG5H

#pragma config CPB = OFF // Boot Block Code Protection bit (Boot block (000000-

0007FFh) is not code-protected)

#pragma config CPD = OFF // Data EEPROM Code Protection bit (Data EEPROM is not

code-protected)

// CONFIG6L

#pragma config WRT0 = OFF // Write Protection bit (Block 0 (000800-001FFFh) is

not write-protected)

#pragma config WRT1 = OFF // Write Protection bit (Block 1 (002000-003FFFh) is

not write-protected)

#pragma config WRT2 = OFF // Write Protection bit (Block 2 (004000-005FFFh) is

not write-protected)

#pragma config WRT3 = OFF // Write Protection bit (Block 3 (006000-007FFFh) is

not write-protected)

// CONFIG6H

#pragma config WRTC = OFF // Configuration Register Write Protection bit

(Configuration registers (300000-3000FFh) are not write-protected)

#pragma config WRTB = OFF // Boot Block Write Protection bit (Boot block (000000-

0007FFh) is not write-protected)

#pragma config WRTD = OFF // Data EEPROM Write Protection bit (Data EEPROM is not

write-protected)

// CONFIG7L

#pragma config EBTR0 = OFF // Table Read Protection bit (Block 0 (000800-001FFFh)

is not protected from table reads executed in other blocks)

#pragma config EBTR1 = OFF // Table Read Protection bit (Block 1 (002000-003FFFh)

is not protected from table reads executed in other blocks)

#pragma config EBTR2 = OFF // Table Read Protection bit (Block 2 (004000-005FFFh)

is not protected from table reads executed in other blocks)

#pragma config EBTR3 = OFF // Table Read Protection bit (Block 3 (006000-007FFFh)

is not protected from table reads executed in other blocks)

// CONFIG7H

#pragma config EBTRB = OFF // Boot Block Table Read Protection bit (Boot block

(000000-0007FFh) is not protected from table reads executed in other blocks)

// #pragma config statements should precede project file includes.

// Use project enums instead of #define for ON and OFF.

#include <xc.h>

#include "Src/Types.h"

#include "Src/Macros.h"

#include "Src/USART.h"

#include "Src/SPI_Master.h"

#include "Src/MCP2515.h"

#include "Src/SW_UART.h"

#include "Src/ISO9141_2.h"

#include "Src/ISO15765_4.h"

#include "Src/BT_Interface.h"

Page 187: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

186

#include "Src/TIMER0.h"

#include "Src/TIMER3.h"

volatile uint tics = 0;

void interrupt ISR() {

di();

if(INTCONbits.TMR0IF) {

tics++;

INTCONbits.TMR0IF = 0;

TMR0 = 0xA2;

}

ei();

}

uchar initProtocol(uchar protocol) {

OBD2Request testRequest;

OBD2Response testResponse;

testRequest.service = 1;

testRequest.PIDLength = 1;

testRequest.PID[0] = 0xC;

switch(protocol) {

case SAEJ1850PWM:

return 0;

break;

case SAEJ1850VPW:

return 0;

break;

case ISO9141_2:

closeSPIMaster();

if(!initISO9141()) return 0;

break;

case ISO14230_1:

return 0;

break;

case ISO15765_1_11bit_250KB:

closeUart();

initSPIMaster();

initCAN(CAN_SPEED_250KBPS);

frameType = CAN_STANDARD_FRAME;

Page 188: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

187

configRX0BufferMCP2515(frameType, 0x7E8, 0xFFF);

if(!sendOBD2RequestISO15765_4(testRequest, &testResponse)) return 0;

break;

case ISO15765_1_11bit_500KB:

closeUart();

initSPIMaster();

initCAN(CAN_SPEED_500KBPS);

frameType = CAN_STANDARD_FRAME;

configRX0BufferMCP2515(frameType, 0x7E8, 0xFFF);

if(!sendOBD2RequestISO15765_4(testRequest, &testResponse)) return 0;

break;

case ISO15765_1_29bit_250KB:

closeUart();

initSPIMaster();

initCAN(CAN_SPEED_250KBPS);

frameType = CAN_EXTENDED_FRAME;

configRX0BufferMCP2515(frameType, 0x7E8, 0xFFF);

if(!sendOBD2RequestISO15765_4(testRequest, &testResponse)) return 0;

break;

case ISO15765_1_29bit_500KB:

closeUart();

initSPIMaster();

initCAN(CAN_SPEED_500KBPS);

frameType = CAN_EXTENDED_FRAME;

configRX0BufferMCP2515(frameType, 0x7E8, 0xFFF);

if(!sendOBD2RequestISO15765_4(testRequest, &testResponse)) return 0;

break;

default:

return 0;

}

return 1;

}

void main(void) {

INTCON2bits.nRBPU = 1;

// Init modules

initTMR0();

initTMR3();

initSoftwareUART();

initMCP2515();

requestFrame btRequest;

responseFrame btResponse;

commandFrame command;

negativeResponseFrame errorFrame;

uchar frameReceivedId;

uchar connectedToCar = 0;

Page 189: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

188

uchar connectedProtocol;

OBD2Request obd2Request;

OBD2Response obd2Response;

OBD2ResponseISO9141 obd2ResponseISO9141;

uchar requestState;

while(1) {

while(1) {

// Wait for a frame from computer.

if(receiveFrame(&frameReceivedId, &btRequest, &command)) break;

}

if(frameReceivedId == requestFrameId) {

if(connectedToCar) {

obd2Request.service = btRequest.service;

obd2Request.PIDLength = btRequest.PIDLength;

for(uchar i = 0; i < btRequest.PIDLength; i++) obd2Request.PID[i] =

btRequest.PID[i];

switch(connectedProtocol) {

case SAEJ1850PWM:

break;

case SAEJ1850VPW:

break;

case ISO9141_2:

requestState = sendOBD2RequestISO9141(obd2Request, &obd2Response);

break;

case ISO14230_1:

break;

case ISO15765_1_11bit_250KB:

requestState = sendOBD2RequestISO15765_4(obd2Request, &obd2Response);

break;

case ISO15765_1_11bit_500KB:

requestState = sendOBD2RequestISO15765_4(obd2Request, &obd2Response);

break;

case ISO15765_1_29bit_250KB:

requestState = sendOBD2RequestISO15765_4(obd2Request, &obd2Response);

break;

case ISO15765_1_29bit_500KB:

Page 190: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

189

requestState = sendOBD2RequestISO15765_4(obd2Request, &obd2Response);

break;

}

if(requestState == 1) {

btResponse.service = obd2Response.service;

btResponse.PIDLength = obd2Response.PIDLength;

for(uchar i = 0; i < obd2Response.PIDLength; i++) btResponse.PID[i] =

obd2Response.PID[i];

btResponse.dataLen = obd2Response.dataLen;

for(uchar i = 0; i < obd2Response.dataLen; i++) btResponse.data[i] =

obd2Response.data[i];

sendResponseFrame(btResponse);

} else {

errorFrame.errorCode = 0x11; // This error code means no response from

car

sendErrorFrame(errorFrame);

}

nop();

} else {

errorFrame.errorCode = 0x12; // This error code means not connected to car

sendErrorFrame(errorFrame);

}

} else if(frameReceivedId == commandFrameId) {

switch(command.command) {

case 1:

if(initProtocol(command.params[0])) {

connectedToCar = 1;

connectedProtocol = command.params[0];

sendCommandConfirmation(command);

} else {

connectedToCar = 0;

errorFrame.errorCode = 0x18; // This error code means no response

from car

sendErrorFrame(errorFrame);

}

break;

case 2:

connectedToCar = 0; // disconnected

closeSPIMaster(); // disable SPI

closeUart(); // disable Uart

sendCommandConfirmation(command);

Page 191: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

190

break;

case 3:

break;

default:

errorFrame.errorCode = 0x52; // This error code means command not

supported

sendErrorFrame(errorFrame);

break;

}

} else {

errorFrame.errorCode = 0x77; // This error code means frame not identified

sendErrorFrame(errorFrame);

}

}

}

12. ANEXO 2: Código de la aplicación de escritorio

import sys

import serial

import serial.tools.list_ports

import pyperclip

from PyQt5 import uic

from PyQt5.QtWidgets import *

from PyQt5.QtCore import *

from PyQt5.QtGui import QPainter, QColor, QPen

from time import sleep

import time, threading

import struct

import math

import numpy as np

import random

import webbrowser

import xlwt

from xlwt import Workbook

import datetime

interpreterSerial = serial.Serial()

PID = []

data = []

command = []

params = []

errorCode = []

receivedFrameType = 0

requestsQueue = []

minVelocity = 255

Page 192: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

191

maxVelocity = 0

liveDataEnabled = False

service1Enable = 0

engineSpeed = 3500

carVelocity = 180

throttlePosition = 100

engineLoad = 0

coolerTemp = 0

absPressureAirIntake = 0

tempAirIntake = 0

MAF = 0

DTCs = []

carManufacturer = "NA"

carModel = "NA"

licensePlate = "NA"

obd2Protocol = "NA"

progressBarValues = [0,0,0,0]

plotterPbValue = 0

plotTitle1 = ''

plotTitle2 = ''

plotTitle3 = ''

plotting1 = []

plotting2 = []

plotting3 = []

plottingLen = 20

startPlotting = 0

interpreterLog = True

def clamp(n):

if n < 0:

return 0

else:

return n

def sendCommandFrame(command, params = []):

#This function sends a command frame as described on the project documentation

global interpreterLog

chksum = 0

paramsLen = len(params)

byteToSend = bytearray()

i = 0

if interpreterLog == True:

arrayLog = []

del arrayLog[:]

arrayLog.append(3)

arrayLog.append(command)

arrayLog.append(paramsLen)

arrayLog.append(params)

textLog = str(arrayLog)

formatedTextLog1 = textLog.replace("[", "")

formatedTextLog2 = formatedTextLog1.replace("]", "")

formatedTextLog3 = formatedTextLog2.replace(",", " ")

item = QListWidgetItem(formatedTextLog3)

item.setBackground(QColor(239,239,239))

Page 193: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

192

GUI.framesList.addItem(item)

GUI.framesList.addItem(item)

chksum = 3 + command + paramsLen

for x in params:

chksum = chksum + x

interpreterSerial.write(b'\x03')

sleep(0.01)

byteToSend.append(command)

interpreterSerial.write(bytes(byteToSend))

del byteToSend[0]

sleep(0.01)

byteToSend.append(paramsLen)

interpreterSerial.write(bytes(byteToSend))

del byteToSend[0]

sleep(0.01)

while i < paramsLen:

byteToSend.append(params[i])

interpreterSerial.write(bytes(byteToSend))

del byteToSend[0]

sleep(0.01)

i = i + 1

byteToSend.append(chksum)

interpreterSerial.write(bytes(byteToSend))

del byteToSend[0]

interpreterSerial.reset_output_buffer()

def sendRequestFrame(service, PID = []):

#This function sends a request frame as described on the project documentation

global interpreterLog

chksum = 0

byteToSend = bytearray()

PIDLen = len(PID)

i = 0

if interpreterLog == True:

arrayLog = []

del arrayLog[:]

arrayLog.append(2)

arrayLog.append(service)

arrayLog.append(PIDLen)

arrayLog.append(PID)

textLog = str(arrayLog)

formatedTextLog1 = textLog.replace("[", "")

formatedTextLog2 = formatedTextLog1.replace("]", "")

formatedTextLog3 = formatedTextLog2.replace(",", " ")

item = QListWidgetItem(formatedTextLog3)

item.setBackground(QColor(239,239,239))

GUI.framesList.addItem(item)

chksum = 2 + service + PIDLen

for x in PID:

chksum = chksum + x

interpreterSerial.write(b'\x02')

Page 194: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

193

sleep(0.01)

byteToSend.append(service)

interpreterSerial.write(bytes(byteToSend))

del byteToSend[0]

sleep(0.01)

byteToSend.append(PIDLen)

interpreterSerial.write(bytes(byteToSend))

del byteToSend[0]

sleep(0.01)

while i < PIDLen:

byteToSend.append(PID[i])

interpreterSerial.write(bytes(byteToSend))

del byteToSend[0]

sleep(0.01)

i = i + 1

byteToSend.append(chksum)

interpreterSerial.write(bytes(byteToSend))

del byteToSend[0]

interpreterSerial.reset_output_buffer()

def receiveFrame():

#This function received a frame. This frame can be a response frame, a command

confirmation frame or an error frame

global PID

global data

global command

global params

global errorCode

global receiveFrameType

global interpreterLog

i = 0

computedChksum = 0

receivedByte = interpreterSerial.read()

receivedInt = list(receivedByte)

if receivedInt[0] == 1:

#in this case a response frame is received

computedChksum += 1

receivedByte = interpreterSerial.read()

receivedInt = list(receivedByte)

service = receivedInt[0]

computedChksum += service

receivedByte = interpreterSerial.read()

receivedInt = list(receivedByte)

PIDLen = receivedInt[0]

computedChksum += PIDLen

while i < PIDLen:

receivedByte = interpreterSerial.read()

receivedInt = list(receivedByte)

PID.append(receivedInt[0])

computedChksum += receivedInt[0]

i = i + 1

receivedByte = interpreterSerial.read()

Page 195: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

194

receivedInt = list(receivedByte)

dataLen = receivedInt[0]

computedChksum += dataLen

i = 0

while i < dataLen:

receivedByte = interpreterSerial.read()

receivedInt = list(receivedByte)

data.append(receivedInt[0])

computedChksum += receivedInt[0]

i = i + 1

receivedByte = interpreterSerial.read()

receivedInt = list(receivedByte)

receivedChksum = receivedInt[0]

computedChksum &= 0xFF

if computedChksum == receivedChksum:

if interpreterLog == True:

arrayLog = []

del arrayLog[:]

arrayLog.append(1)

arrayLog.append(service)

arrayLog.append(PIDLen)

arrayLog.append(PID)

arrayLog.append(dataLen)

arrayLog.append(data)

textLog = str(arrayLog)

formatedTextLog1 = textLog.replace("[", "")

formatedTextLog2 = formatedTextLog1.replace("]", "")

formatedTextLog3 = formatedTextLog2.replace(",", " ")

item = QListWidgetItem(formatedTextLog3)

item.setBackground(QColor(232,232,232))

GUI.framesList.addItem(item)

receiveFrameType = 1

return 1

else:

return 0

elif receivedInt[0] == 4:

#in this case an error frame is received

receivedByte = interpreterSerial.read()

receivedInt = list(receivedByte)

errorCode = receivedInt[0]

receivedByte = interpreterSerial.read()

receivedInt = list(receivedByte)

receivedChksum = receivedInt[0]

computedChksum = 4 + errorCode

computedChksum &= 0xFF

if computedChksum == receivedChksum:

receiveFrameType = 4

Page 196: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

195

if interpreterLog == True:

arrayLog = []

del arrayLog[:]

arrayLog.append(4)

arrayLog.append(errorCode)

textLog = str(arrayLog)

formatedTextLog1 = textLog.replace("[", "")

formatedTextLog2 = formatedTextLog1.replace("]", "")

formatedTextLog3 = formatedTextLog2.replace(",", " ")

item = QListWidgetItem(formatedTextLog3)

item.setBackground(QColor(232,232,232))

GUI.framesList.addItem(item)

return 0

else:

return 0

elif receivedInt[0] == 5:

computedChksum += 5

receivedByte = interpreterSerial.read()

receivedInt = list(receivedByte)

command = receivedInt[0]

computedChksum += command

receivedByte = interpreterSerial.read()

receivedInt = list(receivedByte)

paramsLen = receivedInt[0]

computedChksum += paramsLen

while i < paramsLen:

receivedByte = interpreterSerial.read()

receivedInt = list(receivedByte)

params.append(receivedInt[0])

computedChksum += receivedInt[0]

i = i + 1

receivedByte = interpreterSerial.read()

receivedInt = list(receivedByte)

receivedChksum = receivedInt[0]

computedChksum &= 0xFF

if computedChksum == receivedChksum:

receiveFrameType = 5

if interpreterLog == True:

arrayLog = []

del arrayLog[:]

arrayLog.append(5)

arrayLog.append(command)

arrayLog.append(paramsLen)

arrayLog.append(params)

textLog = str(arrayLog)

formatedTextLog1 = textLog.replace("[", "")

formatedTextLog2 = formatedTextLog1.replace("]", "")

formatedTextLog3 = formatedTextLog2.replace(",", " ")

item = QListWidgetItem(formatedTextLog3)

Page 197: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

196

item.setBackground(QColor(232,232,232))

GUI.framesList.addItem(item)

interpreterSerial.reset_input_buffer()

return 1

else:

interpreterSerial.reset_input_buffer()

return 0

else:

return 0

class mainWindowObj(QMainWindow):

def __init__(self):

super().__init__()

uic.loadUi("firstgui.ui", self)

#Set callback functions of buttons

self.actionOpenConnection.triggered.connect(openConnectionDialogObj.show)

self.actionCloseConnection.triggered.connect(self.disconnectFromInterpreter)

self.actionEditProfile.triggered.connect(editProfileDialogObj.show)

self.readVehicleInfo.clicked.connect(self.getVehicleInformation)

self.copyToClipboard.clicked.connect(self.copyVehicleInformationToClipboard)

self.searchDTCButton.clicked.connect(self.searchOnBrowser)

self.clearDTCButton.clicked.connect(self.clearDTCs)

self.actionAboutXpressCarScanner.triggered.connect(aboutUsDialogObj.show)

self.clearLogButton.clicked.connect(self.clearLog)

self.pauseStartLogButton.clicked.connect(self.pauseStartLog)

self.showPlottingToolInfoButton.clicked.connect(self.showPlottingToolInfo)

self.showInterpreterLogInfoButton.clicked.connect(self.showInterpreterLogInfo)

self.readDTCsButton.clicked.connect(self.getDTCs)

self.powertrainList.itemActivated.connect(self.powertrainListClicked)

self.bodySystemsList.itemActivated.connect(self.bodySystemsListClicked)

self.chassisSystemsList.itemActivated.connect(self.chassisSystemsListClicked)

self.networkList.itemActivated.connect(self.networkListClicked)

self.exportFFButton.clicked.connect(self.exportFreezeFrame)

self.readStopLiveDataButton.clicked.connect(self.enDisLiveData)

self.cleanLiveDataButton.clicked.connect(self.cleanLiveData)

self.decodeDTCButton.clicked.connect(self.decodeDTC)

self.exportDTCsButton.clicked.connect(self.exportDTCs)

self.startPlotting.clicked.connect(self.startp)

self.savePlottingButton.clicked.connect(self.savePlotting)

self.cleanPlotterButton.clicked.connect(self.cleanPlotterData)

self.readFFButton.clicked.connect(self.getFreezeFrame)

self.showFFInfoButton.clicked.connect(self.showFFInfo)

self.plottingThObj.plottingEnded.connect(self.plottingEndedFunc)

self.infoSearchDTC.clicked.connect(self.showSearchDTCInfo)

self.infoInterpreterSettings.clicked.connect(self.showInterpreterSettingsInfo)

self.infoVehicleInfo.clicked.connect(self.showVehicleInfoInfo)

self.infoTroubleCodes.clicked.connect(self.showTroubleCodesInfo)

self.infoLiveDataMeter.clicked.connect(self.showLiveDataMeterInfo)

#define initial state of some items

self.mainWidget.setEnabled(False)

self.currentDataTab.setEnabled(False)

self.storedDTCTab.setEnabled(False)

self.freezeFramesTab.setEnabled(False)

self.vehicleInfoTab.setEnabled(False)

self.interpreterSettingsTab.setEnabled(False)

Page 198: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

197

self.plottingTab.setEnabled(False)

self.logTab.setEnabled(False)

#Start app threads

self.updatePbObj = progressBarTh()

self.updatePbObj.start()

self.updatePbObj.mySignal.connect(self.updatePb)

self.plottingThObj = plottingThClass()

self.plottingThObj.start()

self.liveDataMeterThObj = liveDataMeterTh()

self.liveDataMeterThObj.start()

def getFreezeFrame(self):

getDTCFreezeFrame()

getEngineSpeedFreezeFrame()

getEngineLoadFreezeFrame()

getCoolerTempFreezeFrame()

getTempAirIntakeFreezeFrame()

getMAFFreezeFrame()

getThrottlePositionFreezeFrame()

getAbsPressureAirIntakeFreezeFrame()

def exportDTCs(self):

#This function saves DTCs in a txt file

global licensePlate

global carManufacturer

global carModel

if licensePlate == 'NA':

fileName = "Unknown Car - DTCs.txt"

else:

fileName = licensePlate + " - DTCs.txt"

textFile = open(fileName, "w+")

x = datetime.datetime.now()

textFile.write(x.strftime("%c") + "\n\n")

textFile.write("FILE GENERATED WITH XPRESS CAR SCANNER \n\n")

textFile.write("________________________________________" + "\n\n")

textFile.write("MANUFACTURER: " + carManufacturer + "\n")

textFile.write("CAR MODEL: " + carModel + "\n")

textFile.write("________________________________________" + "\n\n")

textFile.write("POWERTRAIN DTCs:\n")

for i in range(self.powertrainList.count()):

textFile.write(str(self.powertrainList.item(i).text()) + "\n")

textFile.write("\nBODYSYSTEMS DTCs:\n")

for i in range(self.bodySystemsList.count()):

textFile.write(str(self.bodySystemsList.item(i).text()) + "\n")

textFile.write("\nCHASSIS SYSTEMS DTCs:\n")

for i in range(self.chassisSystemsList.count()):

textFile.write(str(self.chassisSystemsList.item(i).text()) + "\n")

textFile.write("\nNETWORK DTCs:\n")

for i in range(self.networkList.count()):

textFile.write(str(self.networkList.item(i).text()) + "\n")

Page 199: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

198

textFile.close()

notificationObj.setText("File created succesfully")

notificationObj.exec_()

def exportFreezeFrame(self):

#This function exports Freeze Fram in a txt file

global licensePlate

global carManufacturer

global carModel

DTC = self.DTCFF.text()

throttlePosition = self.throttlePositionFF.text()

engineSpeed = self.engineSpeedFF.text()

engineLoad = self.engineLoadFF.text()

intakeManifoldPressure = self.intakeManifoldPressureFF.text()

MAF = self.MAFFF.text()

coolerTemp = self.coolantTempFF.text()

intakeTemp = self.intakeTempFF.text()

if licensePlate == 'NA':

fileName = "Unknown Car - DTCs.txt"

else:

fileName = licensePlate + " - DTCs.txt"

textFile = open(fileName, "w+")

x = datetime.datetime.now()

textFile.write(x.strftime("%c") + "\n\n")

textFile.write("FILE GENERATED WITH XPRESS CAR SCANNER \n\n")

textFile.write("________________________________________" + "\n\n")

textFile.write("MANUFACTURER: " + carManufacturer + "\n")

textFile.write("CAR MODEL: " + carModel + "\n")

textFile.write("________________________________________" + "\n\n")

textFile.write("Freeze Frame for DTC: " + DTC + '\n\n')

textFile.write("Throttle Position: " + throttlePosition + ' %\n')

textFile.write("Engine Speed: " + engineSpeed + ' rpm\n')

textFile.write("Engine Load: " + engineLoad + ' %\n')

textFile.write("Intake Manifold Temperature: " + intakeTemp + ' ° C\n')

textFile.write("MAF(Mass Air Flow): " + MAF + ' g/s\n')

textFile.write("Coolant Temperature: " + coolerTemp + ' ° C\n')

textFile.write("Intake Manifold Pressure: " + intakeManifoldPressure + '

kPa\n')

textFile.close()

notificationObj.setText("File created succesfully")

notificationObj.exec_()

def powertrainListClicked(self, item):

pyperclip.copy(item.text())

def bodySystemsListClicked(self, item):

pyperclip.copy(item.text())

def chassisSystemsListClicked(self, item):

pyperclip.copy(item.text())

def networkListClicked(self, item):

Page 200: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

199

pyperclip.copy(item.text())

def getDTCs(self):

#This function gets, decodes and shows DTCs of the vehicle.

global DTCs

oneDTC = []

getDTC()

i = 0

self.powertrainList.clear()

self.bodySystemsList.clear()

self.chassisSystemsList.clear()

self.networkList.clear()

unifiedDTCs = []

if len(DTCs) > 0:

nDTCs = int(len(DTCs)/2)

while i < nDTCs:

unifiedDTCs.append(256*DTCs[i*2] + DTCs[i*2 + 1])

i = i + 1

for x in unifiedDTCs:

del oneDTC[:]

if ((x & 0xC000) >> 14) == 0:

oneDTC.append('P')

elif ((x & 0xC000) >> 14) == 1:

ondDTC.append('C')

elif ((x & 0xC000) >> 14) == 2:

ondDTC.append('B')

elif ((x & 0xC000) >> 14) == 3:

ondDTC.append('U')

oneDTC.append(hex((x & 0x3000) >> 12)[2:])

oneDTC.append(hex((x & 0x0F00) >> 8)[2:])

oneDTC.append(hex((x & 0x00F0) >> 4)[2:])

oneDTC.append(hex(x & 0x000F)[2:])

item = QListWidgetItem(''.join(oneDTC))

if oneDTC[0] == 'P':

self.powertrainList.addItem(item)

elif oneDTC[0] == 'C':

self.bodySystemsList.addItem(item)

elif oneDTC[0] == 'B':

self.chassisSystemsList.addItem(item)

elif oneDTC[0] == 'U':

self.networkList.addItem(item)

notificationObj.setText(str(nDTCs) + " DTCs Found. Check the DTC

Searcher to know more about this codes.")

notificationObj.exec_()

else:

notificationObj.setText("0 DTCs found!")

notificationObj.exec_()

def pauseStartLog(self):

global interpreterLog

if interpreterLog == True:

interpreterLog = False

Page 201: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

200

self.pauseStartLogButton.setText("Start")

else:

interpreterLog = True

self.pauseStartLogButton.setText("Pause")

def clearLog(self):

self.framesList.clear()

def cleanPlotterData(self):

self.savePlottingButton.setEnabled(False)

def plottingEndedFunc(self):

global plotterPbValue

plotterPbValue = 0

self.savePlottingButton.setEnabled(True)

notificationObj.setText("Data obtained succesfully! Now you can save it in

an excel file.")

notificationObj.exec_()

def savePlotting(self):

#this function saves obtained data in a excel file.

global licensePlate

global plottingLen

global plotting1

global plotTitle1

global plotting2

global plotTitle2

global plotting3

global plotTitle3

global carManufacturer

global carModel

wb = Workbook()

sheet1 = wb.add_sheet('Sheet 1')

sheet1.write(3, 1, 'Data obtained with XPRESS CAR SCANNER')

sheet1.write(5, 1, 'Manufacturer:')

sheet1.write(5, 2, carManufacturer)

sheet1.write(6, 1, 'Model:')

sheet1.write(6, 2, carModel)

sheet1.write(7, 1, 'License Plate:')

sheet1.write(7, 2, licensePlate)

sheet1.write(10, 1, 'Time(s)')

sheet1.write(10, 2, plotTitle1)

sheet1.write(10, 3, plotTitle2)

sheet1.write(10, 4, plotTitle3)

x = datetime.datetime.now()

sheet1.write(1, 4, x.strftime("%c"))

i = 0

while i < plottingLen:

sheet1.write(11 + i, 1, i*0.5)

i = i + 1

i = 0

while i < plottingLen:

sheet1.write(11 + i, 2, plotting1[i])

i = i + 1

i = 0

Page 202: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

201

while i < plottingLen:

sheet1.write(11 + i, 3, plotting2[i])

i = i + 1

i = 0

while i < plottingLen:

sheet1.write(11 + i, 4, plotting3[i])

i = i + 1

if licensePlate == '':

wb.save('Unknown Car - sampled PIDs.xls')

else:

wb.save(licensePlate+' - sampled PIDs.xls')

notificationObj.setText("Excel file created succesfully! Now you can use

Excel to make a graph from the data.")

notificationObj.exec_()

def copyDTC(self):

pyperclip.copy(self.powertrainList.selectedItems())

def showFFInfo(self):

notificationObj.setText("In this tab you can get the freeze frame of the

last registered DTC.")

notificationObj.exec_()

def showInterpreterLogInfo(self):

notificationObj.setText("In this tab you can see all the frames that have

been exchanged between PC and obd2 interpreter.")

notificationObj.exec_()

def showSearchDTCInfo(self):

notificationObj.setText("This tab contains tools to extract information

from DTC codes.")

notificationObj.exec_()

def showInterpreterSettingsInfo(self):

notificationObj.setText("This tab allows you to change some parameters from

the obd2 interpreter.")

notificationObj.exec_()

def showVehicleInfoInfo(self):

notificationObj.setText("From this tab you can obtain some information

about the car.")

notificationObj.exec_()

def showPlottingToolInfo(self):

notificationObj.setText("From this tab you can sample up to 3 different

parameters. The data obtained can be used with excel to make a graphical

representation.")

notificationObj.exec_()

def showTroubleCodesInfo(self):

notificationObj.setText("From this tab you can extract stored DTCs in the

car's ECU.")

notificationObj.exec_()

def showLiveDataMeterInfo(self):

notificationObj.setText("From this tab you can obtain some real time data

about the car.")

notificationObj.exec_()

def enDisLiveData(self):

Page 203: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

202

global liveDataEnabled

if liveDataEnabled == True:

liveDataEnabled = False

self.readStopLiveDataButton.setText("Read")

self.cleanLiveDataButton.setEnabled(True)

else:

liveDataEnabled = True

self.readStopLiveDataButton.setText("Stop")

self.cleanLiveDataButton.setEnabled(False)

def cleanLiveData(self):

self.label1.setText('0,00');

self.label2.setText('0,00');

self.label3.setText('0,00');

self.label4.setText('0,00');

self.label5.setText('')

self.label6.setText('')

self.label7.setText('')

self.label8.setText('')

self.label1.setStyleSheet("color: black")

self.label5.setStyleSheet("color: black")

self.label2.setStyleSheet("color: black")

self.label6.setStyleSheet("color: black")

self.label3.setStyleSheet("color: black")

self.label7.setStyleSheet("color: black")

self.label4.setStyleSheet("color: black")

self.label8.setStyleSheet("color: black")

progressBarValues[0] = 0

progressBarValues[1] = 0

progressBarValues[2] = 0

progressBarValues[3] = 0

def getVehicleInformation(self):

self.lpLabel.setText(licensePlate)

self.comProtocolLabel.setText(obd2Protocol)

getVIN()

getOBDStandard()

def disconnectFromInterpreter(self):

self.mainWidget.setEnabled(False)

self.currentDataTab.setEnabled(False)

self.storedDTCTab.setEnabled(False)

self.freezeFramesTab.setEnabled(False)

self.vehicleInfoTab.setEnabled(False)

self.interpreterSettingsTab.setEnabled(False)

self.plottingTab.setEnabled(False)

self.logTab.setEnabled(False)

self.actionOpenConnection.setEnabled(True)

self.actionCloseConnection.setEnabled(False)

self.statusLabel.setStyleSheet("background-color: red;");

self.protocolLabel.setText("NA");

sendCommandFrame(2, [])

interpreterSerial.close()

def updateProgressBars(self, values, ranges):

Page 204: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

203

self.pb1.setRange(0, ranges[0])

self.pb2.setRange(0, ranges[1])

self.pb3.setRange(0, ranges[2])

self.pb4.setRange(0, ranges[3])

self.pb1.setValue(values[0])

self.pb2.setValue(values[1])

self.pb3.setValue(values[2])

self.pb4.setValue(values[3])

def copyVehicleInformationToClipboard(self):

lp = self.lpLabel.text()

comProtocol = self.comProtocolLabel.text()

carVin = self.vinLabel.text()

obdStandard = self.obdLabel.text()

pyperclip.copy("License plate: " + lp + "\n" + "Comunication protocol: " +

comProtocol + '\n' + 'OBD Standard: ' + obdStandard + '\n' + 'VIN(Vehicle

Identification number): ' + carVin + '\n')

def clearDTCs(self):

clearDTCsRequest()

self.getDTCs()

def searchOnBrowser(self):

DTCCodes = []

if self.search1.text() != '':

DTCCodes.append(self.search1.text())

if self.search2.text() != '':

DTCCodes.append(self.search2.text())

if self.search3.text() != '':

DTCCodes.append(self.search3.text())

if len(DTCCodes) > 0:

if len(DTCCodes) == 1:

webbrowser.open('http://www.dtcsearch.com/' + DTCCodes[0] +

'/', new=2)

if len(DTCCodes) == 2:

webbrowser.open('http://www.dtcsearch.com/' + DTCCodes[0] + '+'

+ DTCCodes[1] + '/', new=2)

if len(DTCCodes) == 3:

webbrowser.open('http://www.dtcsearch.com/' + DTCCodes[0] + '+'

+ DTCCodes[1] + '+' + DTCCodes[2] + '/', new=2)

def decodeDTC(self):

#This function decodes DTCs

firstChar = self.dtc1.text()

secondChar = self.dtc2.text()

thirdChar = self.dtc3.text()

fourthChar = self.dtc4.text() + self.dtc5.text()

if firstChar == 'B':

domain = "Body"

elif firstChar == 'C':

domain = "Chassis"

elif firstChar == 'P':

domain = "Powertrain"

elif firstChar == 'U':

Page 205: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

204

domain = "Network"

else:

domain = "Unknown"

if secondChar == '0':

property = "Generic"

elif firstChar == '1':

property = "Specific"

else:

property = "Unknown"

if thirdChar == '1':

faultLocation = "Fuel & Air Metering"

elif thirdChar == '2':

faultLocation = "Injectors"

elif thirdChar == '3':

faultLocation = "Ignition System"

elif thirdChar == '4':

faultLocation = "Auxiliary Emission Control"

elif thirdChar == '5':

faultLocation = "Vehicle Speed & Idle"

elif thirdChar == '6':

faultLocation = "Computer Output Circuit"

elif thirdChar == '7':

faultLocation = "Transmission"

elif thirdChar == '8':

faultLocation = "Transmission"

else:

faultLocation = "Unknown"

self.dtcLab1.setText(domain)

self.dtcLab2.setText(property)

self.dtcLab3.setText(faultLocation)

def updatePb(self):

global progressBarValues

global plotterPbValue

self.progressBar1.setValue(progressBarValues[0])

self.progressBar2.setValue(progressBarValues[1])

self.progressBar3.setValue(progressBarValues[2])

self.progressBar4.setValue(progressBarValues[3])

self.plotterPb.setValue(plotterPbValue)

def startp(self):

global startPlotting

startPlotting = 1

def __del__(self):

if interpreterSerial.is_open:

interpreterSerial.close()

class progressBarTh(QThread):

#This thread sends a signal to another function that updates the progress Bars

values

mySignal = pyqtSignal()

def __init__(self):

QThread.__init__(self)

Page 206: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

205

def __del__(self):

self.wait()

def run(self):

while 1:

self.mySignal.emit()

sleep(0.2)

class liveDataMeterTh(QThread):

#This thread gets data desired from the vehicle when mode 1 is active

def __init__(self):

QThread.__init__(self)

def __del__(self):

self.wait()

def run(self):

global liveDataEnabled

global progressBarValues

global carVelocity

global throttlePosition

global engineSpeed

global engineLoad

global coolerTemp

global absPressureAirIntake

global tempAirIntake

global MAF

while 1:

if liveDataEnabled == True:

pidSelections = []

queryResults = []

units = []

color = []

max = []

pidSelections.append(GUI.comboBox1.currentIndex())

pidSelections.append(GUI.comboBox2.currentIndex())

pidSelections.append(GUI.comboBox3.currentIndex())

pidSelections.append(GUI.comboBox4.currentIndex())

i = 0

while i < 4:

if pidSelections[i] == 0:

queryResults.append(0.00)

units.append('')

color.append("black")

max.append(100)

elif pidSelections[i] == 1:

sleep(0.05)

getVelocity()

queryResults.append(carVelocity)

units.append('m/s')

color.append("red")

max.append(300)

elif pidSelections[i] == 2:

sleep(0.05)

getEngineSpeed()

queryResults.append(engineSpeed)

Page 207: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

206

units.append('rpm')

color.append("green")

max.append(16000)

elif pidSelections[i] == 3:

sleep(0.05)

getThrottlePosition()

queryResults.append(throttlePosition)

units.append('%')

color.append("yellow")

max.append(100)

elif pidSelections[i] == 4:

sleep(0.05)

getEngineLoad()

queryResults.append(engineLoad)

units.append('%')

color.append("yellow")

max.append(100)

elif pidSelections[i] == 5:

sleep(0.05)

getCoolerTemp()

queryResults.append(coolerTemp)

units.append('°C')

color.append("yellow")

max.append(215)

elif pidSelections[i] == 6:

sleep(0.05)

getAbsPressureAirIntake()

queryResults.append(absPressureAirIntake)

units.append('kPa')

color.append("yellow")

max.append(255)

elif pidSelections[i] == 7:

sleep(0.05)

getTempAirIntake()

queryResults.append(tempAirIntake)

units.append('°C')

color.append("yellow")

max.append(215)

elif pidSelections[i] == 8:

sleep(0.05)

getMAF()

queryResults.append(MAF)

units.append('g/s')

color.append("yellow")

max.append(655)

i = i + 1

GUI.label1.setText(str(queryResults[0]));

GUI.label2.setText(str(queryResults[1]));

GUI.label3.setText(str(queryResults[2]));

GUI.label4.setText(str(queryResults[3]));

progressBarValues[0] = clamp((queryResults[0]/max[0])*100)

progressBarValues[1] = clamp((queryResults[1]/max[1])*100)

progressBarValues[2] = clamp((queryResults[2]/max[2])*100)

progressBarValues[3] = clamp((queryResults[3]/max[3])*100)

GUI.label5.setText(units[0])

GUI.label6.setText(units[1])

GUI.label7.setText(units[2])

GUI.label8.setText(units[3])

GUI.label1.setStyleSheet("color: " + color[0])

GUI.label5.setStyleSheet("color: " + color[0])

Page 208: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

207

GUI.label2.setStyleSheet("color: " + color[1])

GUI.label6.setStyleSheet("color: " + color[1])

GUI.label3.setStyleSheet("color: " + color[2])

GUI.label7.setStyleSheet("color: " + color[2])

GUI.label4.setStyleSheet("color: " + color[3])

GUI.label8.setStyleSheet("color: " + color[3])

sleep(0.2)

class plottingThClass(QThread):

#The job of this thread is to sample desired data periodically during n seconds.

plottingEnded = pyqtSignal()

def __init__(self):

QThread.__init__(self)

def __del__(self):

self.wait()

def run(self):

global carVelocity

global throttlePosition

global engineSpeed

global engineLoad

global coolerTemp

global absPressureAirIntake

global tempAirIntake

global MAF

global startPlotting

global plotting1

global plotting2

global plotting3

global plottingLen

global plotTitle1

global plotTitle2

global plotTitle3

global plotterPbValue

while 1:

if startPlotting == 1:

i = 0

j = 0

del plotting1[:]

del plotting2[:]

del plotting3[:]

params = []

del params[:]

params.append(GUI.paramSel1.currentIndex())

params.append(GUI.paramSel2.currentIndex())

params.append(GUI.paramSel3.currentIndex())

plotTitle1 = GUI.paramSel1.currentText()

plotTitle2 = GUI.paramSel2.currentText()

plotTitle3 = GUI.paramSel3.currentText()

plottingLen = int(GUI.plottingTime.currentText())

Page 209: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

208

while i < plottingLen:

plotterPbValue = ((i+1)/plottingLen)*100

j = 0

while j < 3:

sleep(0.05)

if params[j] == 0:

receivedData = 0

elif params[j] == 1:

getVelocity()

receivedData = carVelocity

elif params[j] == 2:

getEngineSpeed()

receivedData = engineSpeed

elif params[j] == 3:

getThrottlePosition()

receivedData = throttlePosition

elif params[j] == 4:

getEngineLoad()

receivedData = engineLoad

elif params[j] == 5:

getCoolerTemp()

receivedData = coolerTemp

elif params[j] == 6:

getAbsPressureAirIntake()

receivedData = absPressureAirIntake

elif params[j] == 7:

getTempAirIntake()

receivedData = tempAirIntake

elif params[j] == 8:

getMAF()

receivedData = MAF

if j == 0:

plotting1.append(receivedData)

elif j == 1:

plotting2.append(receivedData)

elif j == 2:

plotting3.append(receivedData)

j = j + 1

i = i + 1

startPlotting = 0

self.plottingEnded.emit()

class openConnectionDialogClass(QDialog):

def __init__(self):

super().__init__()

uic.loadUi("connectWindow.ui", self)

self.refreshPorts.clicked.connect(self.refreshPortsList)

self.connectButton.clicked.connect(self.connectToInterpreter)

self.cancelButton.clicked.connect(self.close)

def closeDialog(self):

self.close()

Page 210: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

209

def refreshPortsList(self):

comlist = serial.tools.list_ports.comports()

connected = []

for element in comlist:

connected.append(element.device)

self.portComboBox.clear()

self.portComboBox.addItems(connected)

def connectToInterpreter(self):

#this function sends a request to the OBD2 scaner to connect to a vehicle

with a specific protocol.

global carManufacturer

global carModel

global licensePlate

global obd2Protocol

protocolSelection = self.protocolComboBox.currentText()

if protocolSelection == 'ISO 9141-2':

protocolSelectionIndex = 0

elif protocolSelection == 'ISO 15765-4 CAN (11 bit, 500kb)':

protocolSelectionIndex = 5

elif protocolSelection == 'ISO 15765-4 CAN (29 bit, 500kb)':

protocolSelectionIndex = 7

elif protocolSelection == 'ISO 15765-4 CAN (11 bit, 250kb)':

protocolSelectionIndex = 4

elif protocolSelection == 'ISO 15765-4 CAN (29 bit, 250kb)':

protocolSelectionIndex = 6

interpreterCOMPort = self.portComboBox.currentText()

if interpreterCOMPort == "":

notificationObj.setText("Select a COM port of obd2 interpreter in

order to establish communication.")

notificationObj.exec_()

return

interpreterSerial.baudrate = 9600

interpreterSerial.port = interpreterCOMPort

interpreterSerial.timeout = None

interpreterSerial.open()

if interpreterSerial.is_open == False:

notificationObj.setText("XPRESS CAR SCANNER has not been able to open

desired port. It might be already opened.")

notificationObj.exec_()

return

params = []

params.append(protocolSelectionIndex)

sendCommandFrame(1, params)

if receiveFrame() == 1:

#if connected enable all the functionalities of the app

GUI.actionOpenConnection.setEnabled(False)

GUI.actionCloseConnection.setEnabled(True)

GUI.mainWidget.setEnabled(True)

GUI.currentDataTab.setEnabled(True)

GUI.storedDTCTab.setEnabled(True)

GUI.freezeFramesTab.setEnabled(True)

GUI.vehicleInfoTab.setEnabled(True)

GUI.interpreterSettingsTab.setEnabled(True)

GUI.plottingTab.setEnabled(True)

Page 211: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

210

GUI.logTab.setEnabled(True)

GUI.statusLabel.setStyleSheet("background-color: green;");

GUI.protocolLabel.setText(self.protocolComboBox.currentText());

carManufacturer = self.manufacturerInput.text()

carModel = self.modelInput.text()

licensePlate = self.licensePlateInput.text()

obd2Protocol = protocolSelection

self.close()

else:

self.close()

notificationObj.setText("Car does not respond, check selected

protocol and make sure key is in ignition position.")

notificationObj.exec_()

interpreterSerial.close()

class editProfileDialogClass(QDialog):

def __init__(self):

super().__init__()

uic.loadUi("editProfile.ui", self)

self.updateButton.clicked.connect(self.updateProfile)

self.cancelButton.clicked.connect(self.closeDialog)

def updateProfile(self):

global carManufacturer

global carModel

global licensePlate

carManufacturer = self.manufacturerInput.text()

carModel = self.modelInput.text()

licensePlate = self.licensePlateInput.text()

self.close()

def closeDialog(self):

self.close()

class aboutUsDialogClass(QDialog):

def __init__(self):

super().__init__()

uic.loadUi("aboutUs.ui", self)

self.okButton.clicked.connect(self.closeDialog)

def closeDialog(self):

self.close()

def getVIN():

global data

global receiveFrameType

global PID

i = 0

sendRequestFrame(9, [2])

if receiveFrame() == 1:

if receiveFrameType == 1:

while 1:

if data[0] == 0:

del data[0]

else:

Page 212: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

211

break;

GUI.vinLabel.setText(''.join(chr(x) for x in data))

dataLen = len(data)

del data[:]

del PID[:]

else:

print(receiveFrameType)

del data[:]

del PID[:]

def getVelocity():

global data

global receiveFrameType

global carVelocity

global PID

i = 0

sendRequestFrame(1, [0xD])

if receiveFrame() == 1:

if receiveFrameType == 1:

if len(data) == 1:

carVelocity = data[0]

del data[:]

del PID[:]

def getEngineSpeed():

global data

global receiveFrameType

global engineSpeed

global PID

i = 0

sendRequestFrame(1, [0xC])

if receiveFrame() == 1:

if receiveFrameType == 1:

if len(data) == 2:

engineSpeed = round((data[0]*256 + data[1])/4, 2)

del data[:]

del PID[:]

def getThrottlePosition():

global data

global receiveFrameType

global throttlePosition

global PID

i = 0

sendRequestFrame(1, [0x11])

if receiveFrame() == 1:

if receiveFrameType == 1:

if len(data) == 1:

Page 213: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

212

throttlePosition = round((data[0]*100)/255, 2)

del data[:]

del PID[:]

def getEngineLoad():

global data

global receiveFrameType

global engineLoad

global PID

i = 0

sendRequestFrame(1, [0x4])

if receiveFrame() == 1:

if receiveFrameType == 1:

if len(data) == 1:

engineLoad = round(data[0]/2.55, 2)

del data[:]

del PID[:]

def getCoolerTemp():

global data

global receiveFrameType

global coolerTemp

global PID

i = 0

sendRequestFrame(1, [0x5])

if receiveFrame() == 1:

if receiveFrameType == 1:

if len(data) == 1:

coolerTemp = data[0] - 40

del data[:]

del PID[:]

def getAbsPressureAirIntake():

global data

global receiveFrameType

global absPressureAirIntake

global PID

i = 0

sendRequestFrame(1, [0xB])

if receiveFrame() == 1:

if receiveFrameType == 1:

if len(data) == 1:

absPressureAirIntake = data[0]

del data[:]

del PID[:]

def getTempAirIntake():

global data

global receiveFrameType

Page 214: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

213

global tempAirIntake

global PID

i = 0

sendRequestFrame(1, [0xF])

if receiveFrame() == 1:

if receiveFrameType == 1:

if len(data) == 1:

tempAirIntake = data[0] - 40

del data[:]

del PID[:]

def getMAF():

global data

global receiveFrameType

global MAF

global PID

i = 0

sendRequestFrame(1, [0x10])

if receiveFrame() == 1:

if receiveFrameType == 1:

if len(data) == 2:

MAF = round((256*data[0] + data[1])/100, 2)

del data[:]

del PID[:]

def getOBDStandard():

global data

global receiveFrameType

global PID

i = 0

sendRequestFrame(1, [0x1C])

if receiveFrame() == 1:

if receiveFrameType == 1:

if len(data) == 1:

#data obtained is decoded to obtain the obd standard of the

vehicle

if data[0] == 0x01:

obdStandard = "OBD-II as defined by the CARB"

elif data[0] == 0x02:

obdStandard = "OBD as defined by the EPA"

elif data[0] == 0x03:

obdStandard = "OBD and OBD-II"

elif data[0] == 0x04:

obdStandard = "OBD-I"

elif data[0] == 0x05:

obdStandard = "Not meant to comply with any OBD standard"

elif data[0] == 0x06:

obdStandard = "EOBD (Europe)"

elif data[0] == 0x07:

obdStandard = "EOBD and OBD-II"

elif data[0] == 0x08:

obdStandard = "EOBD and OBD"

elif data[0] == 0x09:

obdStandard = "EOBD, OBD and OBD II"

Page 215: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

214

elif data[0] == 0x0A:

obdStandard = "JOBD (Japan)"

elif data[0] == 0x0B:

obdStandard = "JOBD and OBD II"

elif data[0] == 0x0C:

obdStandard = "JOBD and EOBD"

elif data[0] == 0x0D:

obdStandard = "JOBD, EOBD, and OBD II"

GUI.obdLabel.setText(obdStandard)

del data[:]

del PID[:]

def getDTC():

global data

global receiveFrameType

global DTCs

global PID

found = False

del DTCs[:]

i = 0

sendRequestFrame(3, [])

if receiveFrame() == 1:

if receiveFrameType == 1:

for x in data:

DTCs.append(x)

while found == False:

if DTCs[len(DTCs) - 1] == 0:

DTCs.pop()

else:

found = True

del data[:]

del PID[:]

def clearDTCsRequest():

global data

global PID

sendRequestFrame(4, [])

receiveFrame()

del data[:]

del PID[:]

def getDTCFreezeFrame():

global data

global receiveFrameType

global PID

dtcStr = []

i = 0

sendRequestFrame(2, [0x2])

if receiveFrame() == 1:

if receiveFrameType == 1:

if len(data) == 2:

Page 216: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

215

#DTC is decoded and stored

dtcInt = 256*data[0] + data[0]

if ((dtcInt & 0xC000) >> 14) == 0:

dtcStr.append('P')

elif ((dtcInt & 0xC000) >> 14) == 1:

dtcStr.append('C')

elif ((dtcInt & 0xC000) >> 14) == 2:

dtcStr.append('B')

elif ((dtcInt & 0xC000) >> 14) == 3:

dtcStr.append('U')

dtcStr.append(hex((dtcInt & 0x3000) >> 12)[2:])

dtcStr.append(hex((dtcInt & 0x0F00) >> 8)[2:])

dtcStr.append(hex((dtcInt & 0x00F0) >> 4)[2:])

dtcStr.append(hex(dtcInt & 0x000F)[2:])

GUI.DTCFF.setText(''.join(dtcStr))

del data[:]

del PID[:]

def getEngineSpeedFreezeFrame():

global data

global receiveFrameType

global PID

i = 0

sendRequestFrame(2, [0xC])

if receiveFrame() == 1:

if receiveFrameType == 1:

if len(data) == 2:

GUI.engineSpeedFF.setText(str(int((data[0]*256 + data[1])/4)))

del data[:]

del PID[:]

def getEngineLoadFreezeFrame():

global data

global receiveFrameType

global PID

i = 0

sendRequestFrame(2, [0x4])

if receiveFrame() == 1:

if receiveFrameType == 1:

if len(data) == 1:

GUI.engineLoadFF.setText(str(int(data[0]/2.55)))

del data[:]

del PID[:]

def getCoolerTempFreezeFrame():

global data

global receiveFrameType

global PID

i = 0

sendRequestFrame(2, [0x5])

Page 217: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

216

if receiveFrame() == 1:

if receiveFrameType == 1:

if len(data) == 1:

GUI.coolantTempFF.setText(str(data[0] - 40))

del data[:]

del PID[:]

def getTempAirIntakeFreezeFrame():

global data

global receiveFrameType

global PID

i = 0

sendRequestFrame(2, [0xF])

if receiveFrame() == 1:

if receiveFrameType == 1:

if len(data) == 1:

GUI.intakeTempFF.setText(str(data[0] - 40))

del data[:]

del PID[:]

def getMAFFreezeFrame():

global data

global receiveFrameType

global PID

i = 0

sendRequestFrame(2, [0x10])

if receiveFrame() == 1:

if receiveFrameType == 1:

if len(data) == 2:

GUI.MAFFF.setText(str(int((256*data[0] + data[1])/100)))

del data[:]

del PID[:]

def getThrottlePositionFreezeFrame():

global data

global receiveFrameType

global PID

i = 0

sendRequestFrame(2, [0x11])

if receiveFrame() == 1:

if receiveFrameType == 1:

if len(data) == 1:

GUI.throttlePositionFF.setText(str(round((data[0]*100)/255,

2)))

del data[:]

del PID[:]

def getAbsPressureAirIntakeFreezeFrame():

global data

Page 218: Bassam Sandoussi Hadik EQUIPO DE DIAGNÓSTICO PARA …deeea.urv.cat/public/PROPOSTES/pub/pdf/2606pub.pdf · 2020. 2. 11. · Introducción al proyecto 4 1. Introducción al proyecto

Anexos

217

global receiveFrameType

global PID

i = 0

sendRequestFrame(2, [0xB])

if receiveFrame() == 1:

if receiveFrameType == 1:

if len(data) == 1:

GUI.intakeManifoldPressureFF.setText(str(data[0]))

del data[:]

del PID[:]

#Objects are created and main window is shown

app = QApplication(sys.argv)

notificationObj = QMessageBox()

editProfileDialogObj = editProfileDialogClass()

openConnectionDialogObj = openConnectionDialogClass()

aboutUsDialogObj = aboutUsDialogClass()

GUI = mainWindowObj()

GUI.show()

sys.exit(app.exec_())