Webcampista.com

mucho más que un foro

Et voila... Mi nueva centralita funcionando...

Dedalo

Mobilis in Mobili
Mi nueva centralita funcionando...

Aqui os envio unas imagenes que hice durante el montaje.
 

Archivos adjuntos

  • 08042010957.jpg
    08042010957.jpg
    35,9 KB · Visitas: 1
  • 12042010958.jpg
    12042010958.jpg
    34,5 KB · Visitas: 1
  • 12042010961.jpg
    12042010961.jpg
    48 KB · Visitas: 1
  • 12042010964.jpg
    12042010964.jpg
    41,8 KB · Visitas: 1
  • 12042010966.jpg
    12042010966.jpg
    34,5 KB · Visitas: 1
  • 12042010968.jpg
    12042010968.jpg
    31,6 KB · Visitas: 1
  • 12042010969.jpg
    12042010969.jpg
    50,4 KB · Visitas: 1
  • 12042010971.jpg
    12042010971.jpg
    56,3 KB · Visitas: 1
  • 12042010973.jpg
    12042010973.jpg
    48,6 KB · Visitas: 1
  • 12042010977.jpg
    12042010977.jpg
    31,4 KB · Visitas: 4
  • 17042010978.jpg
    17042010978.jpg
    51,2 KB · Visitas: 4
  • 17042010979.jpg
    17042010979.jpg
    39,6 KB · Visitas: 5
  • 17042010980.jpg
    17042010980.jpg
    39 KB · Visitas: 4
Joe, que nivel, con pantalla gráfica y to, pero ¿eso está hecho en ensamblador?, pues vaya faena...
Parecen menús como los del movil. ¿está ya comprobada?
 
Efectivamente esta hecho en ensamblador.

El menu principal tiene 5 funciones:
1- 220V
2 - Carga de baterias
3 - Nivel de baterias
4 - vaciado de depositos
5 - Nivel de depositos.

La primera opcion simplemente enciende o apaga el inversor de 220V (solo en caso de no estar conectado a 220V exteriores).

La segunda opcion nos lleva a la pantalla de carga de baterias. En esta pantalla se puede seleccionar manualmente la fuente de carga de cada una de las baterias (Placa solar, alternador del motor o cargador de 220V) o simplemente dejarlo en automatico.

La tercera opcion carga una pantalla que muestra el estado de las baterias, el voltaje de las tres baterias y las intensidades (carga o descarga) de las dos baterias de la vivienda. En la bateria de motor no he puesto ningun shunt para medir la intensidad.

La cuarta opcion carga una ventana desde la que se puede activar o desactivar las valvulas electricas de vaciado de los depositos de aguas grises y negras.

La quinta opcion carga una ventana en la que aparecen los depositos y suy porcentaje de llenado.

Cada pantalla es un grafico de 240 x 64 puntos que hice con paint y que pasé a binario. Los graficos estan almacenados en una 24C256.

El procesador es un ATMEL AT89C51.

Aqui va el esquema completo:

Ver el archivos adjunto Panel AC.pdf

He puesto optoacopladores de sobra para poder ampliar funciones en el futuro. Modificando el programa solo es cuestion de imaginacion aumentar las prestaciones.
 
¿está ya comprobada?

Ya esta todo funcionando excepto los niveles de agua. Fijate que en la fotografia los tres niveles marcan 50%. Si recuerdas monté un invento con un indicador analogico de estilo retro. Este indicador lleva una PAL que permite que la centralita lea en formato serie los datos de los niveles, y sobre la mesa funciona, pero en la AC, con varios metros de cable no funciona, debe ser por los niveles logicos, que son TTL y no se puede estirar las longitudes de los cables mas de un par de metros. La idea es reformar el circuito para crear bucles de intensidad, que soportan mas distancia en los cables que los niveles TTL. Eso es facil de hacer con optoacopladores. Todo a su tiempo...
 
Ya esta todo funcionando excepto los niveles de agua. Fijate que en la fotografia los tres niveles marcan 50%. Si recuerdas monté un invento con un indicador analogico de estilo retro. Este indicador lleva una PAL que permite que la centralita lea en formato serie los datos de los niveles, y sobre la mesa funciona, pero en la AC, con varios metros de cable no funciona, debe ser por los niveles logicos, que son TTL y no se puede estirar las longitudes de los cables mas de un par de metros. La idea es reformar el circuito para crear bucles de intensidad, que soportan mas distancia en los cables que los niveles TTL. Eso es facil de hacer con optoacopladores. Todo a su tiempo...


Los circuitos de intensidad son más complicados que mandar 12V y que lleguen solo 8, aunque te serviría para detectar "cable abierto" o "cable en corto". eso requiere más circuitería.
0mA= circuito abierto, cable desconectado
4mA= cero lógico
20mA= uno lógico
>20mA= cortocircuito.

Los circuitos de intensidad que conozco se usan para niveles analógicos, de 4 a 20mA, te da una gama "infinita" de niveles.

Por cierto, ¿no lo ibas a hacer con un PIC? :D
 
Por cierto, ¿no lo ibas a hacer con un PIC? :D

Pues si, me estoy planteando rehacer de nuevo todo el circuito de niveles. De hecho he estado mirando unos sensores de presion diferencial que tiene farnell de 0 a 10 kPa que son ideales para medir la altura del agua en los depositos. Colocados uno en el fondo de cada deposito tendria 10 Pa de presion por cada cm de altura del agua sobre el nivel del sensor, como son de rango 0-5V tendria un rango analogico de 0 a 1,5V por los 30 Cm que tienen los depositos de altura.
 
¿Y cuanto cuestan? y ya puestos ¿cuanto cuesta la pantalla gráfica?

Aquí quieren hacer un modelo en el que hay que medir niveles, pero en depósitos pequeños, ¿cual es la presión mínima que miden?.
 
Bueno, pues este fin de semana ya he marchado con la centralita nueva. He estado en la albufereta, en Alicante.

Todo funciona al 100%. Solo hay un par de problemas que son errores de software.

Uno de ellos es que la misma tecla del menu principal que nos lleva al menu de vaciado es la tecla de apertura de las aguas grises, por lo que si no te andas listo, la pulsas, cambia el menu y medio segundo despues se pone a vaciar las aguas grises sin previo aviso. La solucion es cambiar de lugar en el menu principal las opciones de niveles de depositos y vaciados, asi al entrar en vaciado, si dejas el dedo pegado mas de medio segundo en lugar de abrir cierras. Es preferible cerrar antes de tiempo que abrir donde no se debe y dejar un charco debajo de la AC.

El segundo error es que cuando estas vaciando hay que volver al menu principal para ver como va el nivel de los depositos. Se me ocurre que se puede programar una de las teclas libres de la pantalla de vaciado para pasar a ver los niveles y viceversa, es decir, una tecla libre de la pantalla de niveles para ir al menu de vaciado.

Vamos, que con unos retoques de software se queda de lujo...
 
Sobre los sensores de presion, he encontrado algunos en Farnell y en RS, desde unos pocos euros hasta varios cientos. Para la precision que necesitamos en los depositos es suficiente con uno de los mas baratos. Yo he pensado en poner este:

Honeywell | Control de Procesos Industriales | Sensores y Transductores | Sensores de Presión | Sensores Piezoresistivos |SCC15ASMT

o este otro, un poco mas caro:

Honeywell | Control de Procesos Industriales | Sensores y Transductores | Sensores de Presión | Sensores Piezoresistivos |24PCEFA6G

El primer sensor es de 0 a 15 PSI, es decir, que su rango es de 0 a +/- 10 metros de nivel de agua.

El segundo es de 0 a 0,5 PSI, o lo que es lo mismo, entre 0 y +/- 30 cm de nivel de agua. Ideal para un deposito de la AC.

Sobre los indicadores graficos, yo he utilizado uno que tenia en casa de experimentos anteriores, creo que me costó unos 50 euros hace ya un par de años, pero los he visto ya en color y de una resolucion parecida entre los 30 y 50 euros.
 
Gracias, no me queda claro que el segundo sea para líquidos ¿o es eso del LPPC?

30cm sigue siendo demasiado para lo que busco, tendremos que ver si es suficiente.

¿y como pasas el BMP a la pantalla?, no me ha quedado muy claro, ¿o lo haces a mano "uno cero cero uno...."?
 
LPPC (Libras por pulgada cuadrada) es la traduccion a español de PSI, (Pound by Square Inch).

Las especificaciones dicen literalmente:

Media (P1&P2): Limited only to those media which not attack polietherimide, silicon and fluorosilicone seal.

Que se puede traducir por: limitado solo a los ambientes que no ataquen... los elementos de las juntas internas. Supongo que el agua no atacará a esas siliconas ni al silicio. En todo caso se puede inventar algo para interponer una membrana entre el agua y el sensor, asi se deja una camara de aire del lado del sensor sin afectar a la presion.
 
¿y como pasas el BMP a la pantalla?, no me ha quedado muy claro, ¿o lo haces a mano "uno cero cero uno...."?

Para pasar los BMP a la pantalla grafica me hice un programa en el PC que pasa un grafico BMP monocromo a bytes en el mismo formato que los necesita el display grafico, es decir, de cada byte solo son utiles los primeros 6 bits, cada pantalla esta compuesta por 64 lineas, cada una de ellas utiliza 40 bytes (40 x 6 bits), en total 2560 bytes.

El programa me graba un archivo en formato intel.hex que utilizo directamente para grabar la memoria EEPROM

Podria haber comprimido mas la imagen utilizando los 8 bits, pero como dispongo de memoria de sobra asi simplifico el programa en assembler que copia bloques desde la memoria EEPROM a la RAM del display.

El programa (en Delphi):
Ver el archivos adjunto Graficos.rar
 
He comentado lo de los sensores en el agua y alguno ya los conoce, cree que si dará problemas si entra agua, aunque como no son caros, se puede probar,

El problema lo tenemos en el rango, para lo que nosotros queremos (que es algo más de un vaso de agua) no llega a ser preciso.

¿sabes si delphi funciona todavía en Windows 7? aunque me pase al CBuilder, también de Borland, igual de rápido para diseñar cosas, pero en C++ lo que pasa es me quede en la versión 5... allá por el ¿98?
 
Supongo que funcionará. Yo lo utilizo porque me he dedicado en los ultimos años a hacer programas de gestion y es mas eficiente que C++ para esa aplicacion.

Para este tipo de programas me gusta mas C que Pascal, pero es lo que tengo instalado y para una cosita rapida como esta me sirve, ademas no tengo ahora ningun C actualizado, pues el ultimo C que utilicé fué el Borland C++ V 4.5 para Windows 3.11
 
Mi nueva centralita funcionando...

Aqui os envio unas imagenes que hice durante el montaje.


La madre que te matriculo!!!!!!!!!!!!!!!

Hace dias que me rondava la idea de buscar info sobre como manejar un LCD gráfico, pero me daba pereca porque pensaba que era muy complejo, pero viendo esto...... y en esamblador........ ya me estas pasando las subrutinas....... y explica explica......

¿ y si fuera en color ?

con el 16f877 puedo manejarlo sin problemas?????

Al final mi mujer me pide el divorcioo por vuestra culpa :toothy7::toothy7::toothy7:
 
Cada pantalla es un grafico de 240 x 64 puntos que hice con paint y que pasé a binario. Los graficos estan almacenados en una 24C256.

Con el paint?????

y ya esta?????

la de cosas que se me estan ocurriendo????
 
Para pasar los BMP a la pantalla grafica me hice un programa en el PC que pasa un grafico BMP monocromo a bytes en el mismo formato que los necesita el display grafico, es decir, de cada byte solo son utiles los primeros 6 bits, cada pantalla esta compuesta por 64 lineas, cada una de ellas utiliza 40 bytes (40 x 6 bits), en total 2560 bytes.

El programa me graba un archivo en formato intel.hex que utilizo directamente para grabar la memoria EEPROM

Podria haber comprimido mas la imagen utilizando los 8 bits, pero como dispongo de memoria de sobra asi simplifico el programa en assembler que copia bloques desde la memoria EEPROM a la RAM del display.

El programa (en Delphi):
Ver el archivos adjunto 29262

AHHHHH!!!!!! este es el secreto......

Aunque no me he enterado muy bien del tema.....

Si quisiera usar una de color??? es posible que encuentre algun programita ya hecho al estilo del de toni pero para color????

Y si en vez de programarlo en ensablador lo quiero hacer usando el CCS A que formato tengo que grabar la imagen???

Si Oscar, CCS, Digamos que tras mucho esfuerzo, horas y horas probando programar, he conseguido completar el curri del curso, osea C básico, funciones y punteros. Y con el titular de sistemas microprogramables, que no tenia muchas granas de explicar cosas, le obligue a que por lo menos hiciera una intro al CCS.
 
Ya verás como con el C todo la parte de programación va más rápido. Te recomiendo que te vayas guardando las funciones (ya comprobadas) que hagan cosas especiales, importantes o simplemente repetitivas, luego será copiar y pegar, funcionando a la primera.

Los punteros en C son muy potentes y también muy jodi..os, sobre todo cuando te equivocas y no sabes porque...
 
Antes de empezar ningun programa te tienes que empollar la hoja de caracteristicas del display, y segun vayas leyendo te daras cuenta de la forma mas facil de meterle los datos. Si es de color, probablemente tenga por cada punto una zona de memoria de 1, 2 ó 3 bytes para colocar en ella el color de ese pixel. Tambien puede ser que sea como los TFT, es decir, que en realidad esta compuesto de lineas y puntos como si fuese monocromo, pero luego en las lineas pares, los puntos pares son rojos y los impares verdes y en las lineas impares los puntos se alternan verdas y azules. Todo depende de la arquitectura del display.

Mira el codigo de esa centralita (Aun sin terminar)

Código:
$MOD51
$TITLE(FRONTAL)
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Puertos
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
LCD_D  EQU P0    ; Datos display LCD
LCD_ILUM BIT P2.3   ; Alimentacion display LCD
LCD_WR  BIT P2.4   ; señal RW display LCD
LCD_RD  BIT P2.5   ; señal RD display LCD
LCD_CE  BIT P2.6   ; señal CE display LCD
LCD_RS  BIT P2.7   ; señal RS display LCD
I2C_SDA  BIT P2.0   ; Datos bus I2C
I2C_SCL  BIT P2.1   ; Reloj bus I2C
BAT0  BIT P1.0
BAT1  BIT P1.1
BAT2  BIT P1.2
ANEGRAS  BIT P1.3
CNEGRAS  BIT P1.4
AGRISES  BIT P1.5
LIBRE  BIT P1.6
RLCONV  BIT P1.7
KL0  BIT P0.0
KL1  BIT P0.1
KL2  BIT P0.2
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; RAM
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
BTECLAS  DATA 20h
BOPTOA  DATA 21h
BOPTOB  DATA 22h
BANDERAS DATA 23h
I2C_Flags DATA 24h   ;Banderas I2C.
BAux1  DATA 25h
BAux2  DATA 26h
BMotor  DATA 27h
TECLA_1I BIT BTECLAS.7
TECLA_2I BIT BTECLAS.6
TECLA_3I BIT BTECLAS.5
TECLA_1D BIT BTECLAS.4
TECLA_2D BIT BTECLAS.3
TECLA_3D BIT BTECLAS.2
CHG_V  BIT BOPTOA.7
CHG_A  BIT BOPTOA.6
CNV_ERR  BIT BOPTOA.5
CNV_ON  BIT BOPTOA.4
OPTO_5  BIT BOPTOA.3
OPTO_6  BIT BOPTOA.2
OPTO_7  BIT BOPTOB.7
OPTO_8  BIT BOPTOB.6
OPTO_9  BIT BOPTOB.5
OPTO_A  BIT BOPTOB.4
OPTO_B  BIT BOPTOB.3
OPTO_C  BIT BOPTOB.2
T_VAR  BIT BANDERAS.0
O_VAR  BIT BANDERAS.1
CONV_ON  BIT BANDERAS.2

I2C_Ack  BIT I2C_Flags.0   ;ACK I2C.
I2C_Err  BIT I2C_Flags.1   ;Error bus I2C.
I2C_Busy BIT I2C_Flags.2   ;Bus I2C ocupado.
TapagadoL DATA 30h
TapagadoH DATA 31h
I2C_BitCnt DATA 33h   ;Contador de bits I2C
I2C_SlvAdr DATA 34h   ;Direccion de chip I2C
GRAlto  DATA 35h
GRBajo  DATA 36h
Nivel_Aux1 DATA 37h
Nivel_Aux2 DATA 38h
Nivel_Motor DATA 39h
Nivel_Limpia DATA 3Ah
Nivel_Gris DATA 3Bh
Nivel_Negra DATA 3Ch
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Constantes
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CTE_TEMPH EQU HIGH(-2000)   ; Constante para 1 mS
CTE_TEMPL EQU LOW(-2000)
EEPROM  EQU 0A4h   ; Direccion I2C de la memoria
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; REGISTROS
; R0=POINTER
; R1=POINTER EN IRQ
; R2=CMD 2 LCD
; R3=CMD 1 LCD
; R4=
; R5=
; R6=CONTADOR generico
; R7=CONTADOR IRQ
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Vectores
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 ORG 0000h
 SJMP INICIO
 ORG 000Bh
 LJMP T0_ISR
 ORG 00023h
 LJMP UART_ISR
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Inicio del procesador
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 ORG 0030h
INICIO:
 CLR EA    ; Deshabilitamos Interrupciones
 MOV R6,#60h   ; Primero limpiamos la RAM
 MOV R0,#20h
LIMPIA_RAM:
 MOV @R0,#0
 INC R0
 DJNZ R6,LIMPIA_RAM
INICIO1:
 MOV TapagadoH,#60  ; Tiempo de apagado 15 Segundos
 MOV TMOD,#01h   ; T0 en modo 1 y T1 en modo 2
 SETB TF0   ; Fuerza IRQ T0
 MOV IP,#02h   ; Fija la prioridad para la IRQ de T0
 MOV IE,#82h   ; Habilita IRQ UART, IRQ T0 e IRQ General
 CALL LCD_INIT   ; Iniciamos LCD
 MOV GRAlto,#00h
 MOV GRBajo,#00h
 CALL LCD_GRAFICO
 CALL SEGUNDO
 CALL SEGUNDO
 CALL SEGUNDO
 CALL SEGUNDO
 CALL SEGUNDO
 CALL LCD_BORRAR
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Ajustar valores iniciales
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 MOV BAux1,#00h
 MOV BAux2,#00h
 MOV BMotor,#00h
 CLR CONV_ON
 MOV NIVEL_Aux1,#0A7h
 MOV NIVEL_Aux2,#0A3h
 MOV NIVEL_Motor,#0B2h
 MOV Nivel_Limpia,#50h
 MOV Nivel_Gris,#50h
 MOV Nivel_Negra,#50h
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Menu principal
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MENU0:
 CALL LCD_BORRARTXT
 MOV GRAlto,#0Ah
 MOV GRBajo,#00h
 CALL LCD_GRAFICO

 JB CONV_ON,MENU0_C
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 MOV R2,#20h    ; TEST
 MOV R3,#00h
 MOV DPTR,#TXT_NO
 CALL LCD_TEXTO
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 MOV R2,#01h
 MOV R3,#00h
 CALL LCD_POSICION
 MOV A,#82h
 CALL LCD_BYTE
 MOV A,#83h
 CALL LCD_BYTE
 MOV R2,#01h
 MOV R3,#01h
 CALL LCD_POSICION
 MOV A,#92h
 CALL LCD_BYTE
 MOV A,#93h
 CALL LCD_BYTE
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 JMP MENU0_D    ; TEST
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MENU0_C:
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 MOV R2,#20h    ; TEST
 MOV R3,#00h
 MOV DPTR,#TXT_OK
 CALL LCD_TEXTO
MENU0_D:
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 CLR T_VAR
MENU0_1:
 JNB T_VAR,MENU0_1
 CLR T_VAR
 JB Tecla_1I,O_T220V
 JB Tecla_2I,O_CARGAB
 JB Tecla_3I,O_NIVELB
 JB Tecla_2D,O_VACIAR
 JB Tecla_3D,O_NIVELA
 SJMP MENU0_1

O_T220V:
 JNB Tecla_1D,O_T220V1
 JMP TEST
O_T220V1:
 CALL T220V
 JMP MENU0
O_CARGAB:
 CALL CARGAB
 JMP MENU0
O_NIVELB:
 CALL NIVELB
 JMP MENU0
O_VACIAR:
 CALL VACIAR
 JMP MENU0
O_NIVELA:
 CALL NIVELA
 JMP MENU0
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Tratamiento tecla 220V
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
T220V:
 CPL CONV_ON
 JB CONV_ON,T220V1
 SETB RLCONV
 SJMP T220V2
T220V1:
 CLR RLCONV
T220V2:
 JB Tecla_1I,T220V2
 RET
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Menu carga de baterias
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CARGAB:
 CALL LCD_BORRARTXT
 MOV GRAlto,#14h
 MOV GRBajo,#00h
 CALL LCD_GRAFICO
 MOV DPTR,#TXT_C_Placa
 JB BAux1.0,CARGAB_1
 MOV DPTR,#TXT_C_ALT
 JB BAux1.1,CARGAB_1
 MOV DPTR,#TXT_C_220
 JB BAux1.2,CARGAB_1
 MOV DPTR,#TXT_C_Auto
CARGAB_1:
 JB BAux1.3,CARGAB_2
 MOV R2,#02h
 MOV R3,#02h
 CALL LCD_TEXTO
CARGAB_2:
 MOV DPTR,#TXT_C_Placa
 JB BAux2.0,CARGAB_3
 MOV DPTR,#TXT_C_ALT
 JB BAux2.1,CARGAB_3
 MOV DPTR,#TXT_C_220
 JB BAux2.2,CARGAB_3
 MOV DPTR,#TXT_C_Auto
CARGAB_3:
 JB BAux2.3,CARGAB_4
 MOV R2,#02h
 MOV R3,#05h
 CALL LCD_TEXTO
CARGAB_4:
 MOV DPTR,#TXT_C_Placa
 JB BMotor.0,CARGAB_5
 MOV DPTR,#TXT_C_ALT
 JB BMotor.1,CARGAB_5
 MOV DPTR,#TXT_C_220
 JB BMotor.2,CARGAB_5
 MOV DPTR,#TXT_C_Auto
CARGAB_5:
 JB BMotor.3,CARGAB_6
 MOV R2,#22h
 MOV R3,#04h
 CALL LCD_TEXTO
CARGAB_6:
 CLR T_VAR
CARGAB_7:
 JNB T_VAR,CARGAB_7
 CLR T_VAR
 JB Tecla_1I,CARGA_AUX1
 JB Tecla_2I,CARGA_AUX
 JB Tecla_3I,CARGA_AUX2
 JB Tecla_2D,CARGA_Motor
 JNB Tecla_1D,CARGAB_7
 RET
CARGA_AUX1:
 JNB BAux1.0,CARGA_AUX1_1 ; Estamos a Placa
 MOV BAux1,#02h   ; Pasamos a Alt
 JMP CARGAB
CARGA_AUX1_1:
 JNB BAux1.1,CARGA_AUX1_2 ; Estamos en Alt
 MOV BAux1,#04h   ; Pasamos a 220
 CLR BAux2.2
 CLR BMotor.2
 JMP CARGAB
CARGA_AUX1_2:
 JNB BAux1.2,CARGA_AUX1_3 ; Estamos en 220
 MOV BAux1,#08h   ; Pasamos a No
 JMP CARGAB
CARGA_AUX1_3:
 JNB BAux1.3,CARGA_AUX1_4 ; Estamos en No
 MOV BAux1,#00h   ; Pasamos a Auto
 JMP CARGAB
CARGA_AUX1_4:
 MOV BAux1,#01h   ; Pasamos a Placa
 CLR BAux2.0
 CLR BMotor.0
 JMP CARGAB
CARGA_AUX:
 JNB BAux1.3,CARGA_AUX_1  ; Estamos en No
 MOV BAux1,#00h   ; Pasamos a Auto
 MOV BAux2,#00h   ; Pasamos a Auto
 JMP CARGAB
CARGA_AUX_1:
 MOV BAux1,#08h   ; Pasamos a No
 MOV BAux2,#08h   ; Pasamos a No
 JMP CARGAB
CARGA_AUX2:
 JNB BAux2.0,CARGA_AUX2_1 ; Estamos a Placa
 MOV BAux2,#02h   ; Pasamos a Alt
 JMP CARGAB
CARGA_AUX2_1:
 JNB BAux2.1,CARGA_AUX2_2 ; Estamos en Alt
 MOV BAux2,#04h   ; Pasamos a 220
 CLR BAux1.2
 CLR BMotor.2
 JMP CARGAB
CARGA_AUX2_2:
 JNB BAux2.2,CARGA_AUX2_3 ; Estamos en 220
 MOV BAux2,#08h   ; Pasamos a No
 JMP CARGAB
CARGA_AUX2_3:
 JNB BAux2.3,CARGA_AUX2_4 ; Estamos en No
 MOV BAux2,#00h   ; Pasamos a Auto
 JMP CARGAB
CARGA_AUX2_4:
 MOV BAux2,#01h   ; Pasamos a Placa
 CLR BAux1.0
 CLR BMotor.0
 JMP CARGAB

CARGA_Motor:
 JNB BMotor.0,CARGA_Motor_1 ; Estamos a Placa
 MOV BMotor,#02h   ; Pasamos a Alt
 JMP CARGAB
CARGA_Motor_1:
 JNB BMotor.1,CARGA_Motor_2 ; Estamos en Alt
 MOV BMotor,#04h   ; Pasamos a 220
 CLR BAux2.2
 CLR BAUX1.2
 JMP CARGAB
CARGA_Motor_2:
 JNB BMotor.2,CARGA_Motor_3 ; Estamos en 220
 MOV BMotor,#08h   ; Pasamos a No
 JMP CARGAB
CARGA_Motor_3:
 JNB BMotor.3,CARGA_Motor_4 ; Estamos en No
 MOV BMotor,#00h   ; Pasamos a Auto
 JMP CARGAB
CARGA_Motor_4:
 MOV BMotor,#01h   ; Pasamos a Placa
 CLR BAux2.0
 CLR BAUX1.0
 JMP CARGAB
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Niveles de las baterias
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
NIVELB:
 CALL LCD_BORRARTXT
 MOV GRAlto,#14h
 MOV GRBajo,#00h
 CALL LCD_GRAFICO
 MOV R2,#01h
 MOV R3,#02h
 CALL LCD_POSICION
 MOV A,NIVEL_Aux1
 CALL NivelB_OUT
 MOV R2,#01h
 MOV R3,#05h
 CALL LCD_POSICION
 MOV A,NIVEL_Aux2
 CALL NivelB_OUT
 MOV R2,#22h
 MOV R3,#04h
 CALL LCD_POSICION
 MOV A,NIVEL_Motor
 CALL NivelB_OUT
 CALL SEGUNDO
 CLR T_VAR
NIVELB_1:
 JNB T_VAR,NIVELB_1
 CLR T_VAR
 JNB Tecla_1D,NIVELB_1
 RET
NIVELB_OUT:
 PUSH ACC
 JNB ACC.7,NIVELB_OUT_1  ; El bit 7 del valor es el "1" inicial
 MOV A,#'1'
 CALL LCD_CHAR
 POP ACC
 CLR ACC.7   ; Si estaba puesto lo eliminamos del valor
 SJMP NIVELB_OUT_2  ; y el resto son los digitos restantes
NIVELB_OUT_1:
 MOV A,#'0'
 CALL LCD_CHAR
 POP ACC
 ADD A,#020h   ; Si no añadimos 2 al nybble alto
NIVELB_OUT_2:
 PUSH ACC
 SWAP A
 ANL A,#0Fh
 ADD A,#'0'
 CALL LCD_CHAR
 MOV A,#','
 CALL LCD_CHAR
 POP ACC
 ANL A,#0Fh
 ADD A,#'0'
 CALL LCD_CHAR
 MOV A,#' '
 CALL LCD_CHAR
 MOV A,#'V'
 JMP LCD_CHAR
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Menu 4
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
VACIAR:
 CALL LCD_BORRARTXT
 MOV GRAlto,#1Eh
 MOV GRBajo,#00h
 CALL LCD_GRAFICO
 JB AGRISES,VACIAR_1
 MOV DPTR,#TXT_ABIERTO
 MOV R2,#20h
 MOV R3,#03h
 CALL LCD_TEXTO
VACIAR_1:

 JB Tecla_2I,ABRE_NEGRAS
 JB Tecla_3I,CIERRA_NEGRAS
 JB Tecla_2D,ABRE_GRISES
 JB Tecla_3D,CIERRA_GRISES
 JNB Tecla_1D,VACIAR_1
 RET
ABRE_NEGRAS:
 CALL LCD_BORRARTXT
 MOV DPTR,#TXT_ABRIENDO
 MOV R2,#00h
 MOV R3,#03h
 CALL LCD_TEXTO
 SETB CNEGRAS
 CLR ANEGRAS
ABRE_NEGRAS_1:
 JB Tecla_2I,ABRE_NEGRAS_1
 SETB ANEGRAS
 JMP VACIAR
CIERRA_NEGRAS:
 CALL LCD_BORRARTXT
 MOV DPTR,#TXT_CERRANDO
 MOV R2,#00h
 MOV R3,#07h
 CALL LCD_TEXTO
 SETB ANEGRAS
 CLR CNEGRAS
CIERRA_NEGRAS_1:
 JB Tecla_3I,CIERRA_NEGRAS_1
 SETB CNEGRAS
 JMP VACIAR
ABRE_GRISES:
 CLR AGRISES
 CLR RLCONV
 CLR T_VAR
ABRE_GRISES_1:
 JNB T_VAR,ABRE_GRISES_1
 JMP VACIAR
CIERRA_GRISES:
 SETB AGRISES
 JB CONV_ON,CIERRA_GRISES_1
 SETB RLCONV
 SJMP CIERRA_GRISES_2
CIERRA_GRISES_1:
 CLR RLCONV
CIERRA_GRISES_2:
 CLR T_VAR
CIERRA_GRISES_3:
 JNB T_VAR,CIERRA_GRISES_3
 JMP VACIAR
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Menu 6
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
NIVELA:
 CALL LCD_BORRARTXT
 MOV GRAlto,#28h
 MOV GRBajo,#00h
 CALL LCD_GRAFICO

 MOV R2,#03h
 MOV R3,#03h
 CALL LCD_POSICION
 MOV A,NIVEL_Limpia
 CALL NivelA_OUT
 MOV R2,#10h
 MOV R3,#03h
 CALL LCD_POSICION
 MOV A,NIVEL_Gris
 CALL NivelA_OUT
 MOV R2,#1Bh
 MOV R3,#03h
 CALL LCD_POSICION
 MOV A,NIVEL_Negra
 CALL NivelA_OUT
 
 CALL SEGUNDO
 CLR T_VAR
NIVELA_1:
 JNB T_VAR,NIVELA_1
 CLR T_VAR
 JNB Tecla_1D,NIVELA_1
 RET
NIVELA_OUT:
 PUSH ACC
 SWAP A
 ANL A,#0Fh
 ADD A,#'0'
 CALL LCD_CHAR
 POP ACC
 ANL A,#0Fh
 ADD A,#'0'
 CALL LCD_CHAR
 MOV A,#' '
 CALL LCD_CHAR
 MOV A,#'%'
 JMP LCD_CHAR
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Rutinas lectura niveles
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

NIV_DECO:
 JB ACC.3,NIV_DECO1  ; No esta lleno, saltamos 0xxx (0000)
 XRL A,#99h
 RET    ; Esta lleno, salimos 99%=ok 92..98= error sensor
NIV_DECO1:
 JB ACC.2,NIV_DECO2  ; No esta al 75%, saltamos 10xx (1000)
 XRL A,#7Dh
 RET    ; Esta al 75%=ok 74,77,76= error sensor
NIV_DECO2:
 JB ACC.1,NIV_DECO3  ; No esta al 50%, saltamos 110x (1100)
 XRL A,#5Ch
 RET    ; Esta al 50%=ok 51=error sensor
NIV_DECO3:
 JB ACC.0,NIV_DECO4  ; No esta al 25%, saltamos 1110
 MOV A,#25h
 RET
NIV_DECO4:    ; Esta vacio 1111
 MOV A,#00h
 RET
 
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Rutinas LCD
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
LCD_INIT:
 CLR LCD_ILUM   ; Iluminacion LCD
 MOV R2,#00h
 MOV R3,#00h
 MOV A,#40h   ; Inicio RAM texto
 CALL LCD_TXCMD
 MOV R2,#00h
 MOV R3,#02h
 MOV A,#42h   ; Inicio RAM Graficos
 CALL LCD_TXCMD
 MOV R2,#28h
 MOV R3,#00h
 MOV A,#41h   ; Anchura texto
 CALL LCD_TXCMD
 MOV R2,#28h
 MOV R3,#00h
 MOV A,#43h   ; Anchura graficos
 CALL LCD_TXCMD

 MOV R2,#03h
 MOV R3,#03h
 MOV A,#22h   ; RAM Caracteres de usuario
 CALL LCD_TXCMD   ; 0001 1Hxx xxxx xlll
 CALL LCD_CARGAUDG
 MOV A,#80h   ; Modo
 CALL LCD_TXC
 MOV A,#9Ch   ; Display
 CALL LCD_TXC
 MOV R2,#00h
 MOV R3,#00h
 MOV A,#21h   ; Cursor en 0,0
 CALL LCD_TXCMD
LCD_BORRARTXT:
 MOV R2,#00h
 MOV R3,#00h
 MOV A,#24h   ; Pointer en 0000h
 CALL LCD_TXCMD
 MOV A,#0B0h   ; Inicio datos
 CALL LCD_TXC
 MOV R2,#00h   ; Contador para 512 bytes
 MOV R3,#02h
 SJMP LCD_BORRAR1
LCD_BORRAR:
 MOV R2,#00h
 MOV R3,#00h
 MOV A,#24h   ; Pointer en 0000h
 CALL LCD_TXCMD
 MOV A,#0B0h   ; Inicio datos
 CALL LCD_TXC
 MOV R2,#00h   ; Contador para 8 Kbytes
 MOV R3,#20h
LCD_BORRAR1:
 MOV A,#00h
 CALL LCD_TXD
 DJNZ R2,LCD_BORRAR1  ; Repetimos hasta el final
 DJNZ R3,LCD_BORRAR1
 MOV A,#0B2h
 SJMP LCD_TXC   ; Fin de datos
LCD_LIBRE:
 PUSH ACC
LCD_LIBRE1:
 SETB LCD_RS   ; Leemos Status
 CLR LCD_CE
 CLR LCD_RD
 MOV A,LCD_D
 SETB LCD_RD
 SETB LCD_CE
 JNB ACC.0,LCD_LIBRE1  ; Si no esta listo esperamos
 JNB ACC.1,LCD_LIBRE1  ; Si no esta listo esperamos
 POP ACC
 RET
LCD_TXD:
 CALL LCD_LIBRE
 CLR LCD_RS   ; Modo de datos
 MOV LCD_D,A   ; Dato al puerto
 CLR LCD_CE
 CLR LCD_WR
 SETB LCD_WR
 SETB LCD_CE
 MOV LCD_D,#0FFh   ; Reponemos puerto
 RET
LCD_CHAR:
 CLR CY
 SUBB A,#20h
LCD_BYTE:
 CALL LCD_TXD
 MOV A,#0C0h
 SJMP LCD_TXC
LCD_POSICION:
 MOV A,R3   ; Valor Y
 RL A
 RL A
 RL A    ; Multiplicado x 8
 XCH A,R2
 ADD A,R2   ; Se suma al valor X
 XCH A,R2
 RL A
 RL A    ; Multiplicado por 20h
 XCH A,R2
 ADD A,R2   ; Se suma al valor X
 MOV R2,A
 CLR A
 ADDC A,#00h
 MOV R3,A
 MOV A,#24h
LCD_TXCMD:
 PUSH ACC
 MOV A,R2
 CALL LCD_TXD
 MOV A,R3
 CALL LCD_TXD
 POP ACC
LCD_TXC:
 CALL LCD_LIBRE
 MOV LCD_D,A   ; Comando al puerto
 CLR LCD_CE
 CLR LCD_WR
 SETB LCD_WR
 SETB LCD_CE
 MOV LCD_D,#0FFh   ; Reponemos puerto
 RET
LCD_TEXTO:
 CALL LCD_POSICION
 MOV A,#0B0h   ; Inicio datos
 CALL LCD_TXC
LCD_TEXTO1:
 CLR A
 MOVC A,@A+DPTR
 JZ LCD_TEXTO2
 CLR CY
 SUBB A,#20h
 CALL LCD_TXD
 INC DPTR
 SJMP LCD_TEXTO1
LCD_TEXTO2:
 MOV A,#0B2h
 JMP LCD_TXC   ; Fin de datos
LCD_GRAFICO:
 MOV R2,#00h
 MOV R3,#02h
 MOV A,#24h   ; Pointer en 0200
 CALL LCD_TXCMD
 MOV A,#0B0h   ; Inicio datos
 CALL LCD_TXC
 MOV A,#EEPROM   ; Direccion de escritura en EEPROM
 CALL I2C_CALL   ; Llama al periferico
 JNB I2C_ACK,LCD_ERR  ; Si error salimos
 MOV A,GRAlto
 CALL I2C_TX   ; Se envia direccion alta
 JNB I2C_ACK,LCD_ERR  ; Si error salimos
 MOV A,GRBajo
 CALL I2C_TX   ; Se envia direccion baja
 JNB I2C_ACK,LCD_ERR  ; Si error salimos
 CALL I2C_START   ; Empezamos la lectura
 MOV A,#EEPROM   ; Direccion de escritura en EEPROM
 SETB ACC.0   ; ya es lectura
 CALL I2C_CALL   ; Llama al periferico
 MOV R6,#00h   ; COntador para 0780h bytes
 MOV R5,#0Ah
LCD_CARGA_RAM:
 CLR I2C_ACK   ; Ponemos ACK
 CALL I2C_RX   ; Traemos un byte
 CALL LCD_TXD   ; y lo enviamos al LCD
 DJNZ R6,LCD_CARGA_RAM
 DJNZ R5,LCD_CARGA_RAM  ; Repetimos hasta terminar
 SETB I2C_ACK   ; Borramos ACK (ultimo byte)
 CALL I2C_RX   ; Traemos el ultimo byte
 MOV A,#0B2h
 JMP LCD_TXC   ; Fin de datos

LCD_ERR:
 CALL I2C_STOP   ; Cierra bus
 CALL LCD_BORRAR   ; Mensaje de error
 MOV R2,#10h
 MOV R3,#04h
 MOV DPTR,#TXT_NoEEPROM
 CALL LCD_TEXTO
 JMP SEGUNDO
LCD_CARGAUDG:
 MOV R2,#00h
 MOV R3,#1Ch
 MOV A,#24h   ; Pointer en 1C00
 CALL LCD_TXCMD
 MOV A,#0B0h   ; Inicio datos
 CALL LCD_TXC
 MOV A,#EEPROM   ; Direccion de escritura en EEPROM
 CALL I2C_CALL   ; Llama al periferico
 JNB I2C_ACK,LCD_ERR  ; Si error salimos
 MOV A,# 7Ch
 CALL I2C_TX   ; Se envia direccion alta
 JNB I2C_ACK,LCD_ERR  ; Si error salimos
 CLR A
 CALL I2C_TX   ; Se envia direccion baja
 JNB I2C_ACK,LCD_ERR  ; Si error salimos
 CALL I2C_START   ; Empezamos la lectura
 MOV A,#EEPROM   ; Direccion de escritura en EEPROM
 SETB ACC.0   ; ya es lectura
 CALL I2C_CALL   ; Llama al periferico
 MOV R6,#00h   ; COntador para 0400h bytes
 MOV R5,#04h
 JMP LCD_CARGA_RAM  ; Terminamos la carga en RAM
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Utiles I2C
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Pone SCL Alto y espera SCL libre
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I2C_SCLH:
 SETB I2C_SCL   ; Pone SCL alto
 JNB I2C_SCL,$   ; Espera SCL alto
 RET
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; I2C_START Inicia una transferencia
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I2C_START:
 CLR I2C_ERR   ; Borramos el estado de error
 SETB I2C_SDA   ; Liberamos SDA y SCL
 CALL I2C_SCLH
 JNB I2C_SCL,I2C_FAULT  ; Comprobamos bus libre
 JNB I2C_SDA,I2C_FAULT  ; Comprobamos bus libre
 CLR I2C_SDA   ; Iniciamos un START
; CALL I2C_BITDLY
 CLR I2C_SCL
; CALL I2C_BITDLY
 RET
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; I2C_FAULT pone la bandera de error
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I2C_FAULT:
 SETB I2C_ERR   ; Señalamos error de bus
 RET    ; y salimos
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; I2C_CALL llama a un periferico
; ACC = Direccion
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I2C_CALL:
 SETB I2C_ACK   ; Ponemos ACK
 CLR I2C_ERR   ; Borramos el estado de error
 CALL I2C_START
 JNB I2C_ERR,I2C_TX
 RET
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; I2C_TX envia un byte por el bus
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I2C_TX:
 MOV I2C_BitCnt,#08h   ; 8 bits
I2C_TX1:
 RLC A    ; bit en CY
 MOV I2C_SDA,C   ; bit en SDA
 CALL I2C_SCLH   ; Pulso en CLK
; CALL I2C_BITDLY
 CLR I2C_SCL
; CALL I2C_BITDLY
 DJNZ I2C_BitCnt,I2C_TX1  ; Repite hasta 8 bits
 SETB I2C_SDA   ; Liberamos SDA
 CALL I2C_SCLH
; CALL I2C_BITDLY
 JNB I2C_SDA,I2C_TX2  ; Verifica ACK
 CLR I2C_ACK   ; Ajusta bandera ACK
I2C_TX2:
 CLR I2C_SCL   ; Finaliza ACK
; CALL I2C_BITDLY
 RET
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; I2C_RX recibe un byte del bus
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I2C_RX:
 SETB I2C_SDA   ; Liberamos SDA
 MOV I2C_BitCnt,#08h  ; 8 bits
I2C_RX1:
 CALL I2C_SCLH
; CALL I2C_BITDLY
 MOV C,I2C_SDA   ; Tomamos un bit
 RLC A    ; Al acumulador
 CLR I2C_SCL   ; Bajamos SCL
; CALL I2C_BITDLY
 DJNZ I2C_BitCnt,I2C_RX1  ; Repetimos para 8 bits
 JNB I2C_ACK,I2C_RX2
 SETB I2C_SDA   ; Si es ultimo enviamos NACK
 SJMP I2C_RX3
I2C_RX2:
 CLR I2C_SDA   ; Si no es ultimo enviamos ACK
I2C_RX3:
 CALL I2C_SCLH
; CALL I2C_BITDLY
 CLR I2C_SCL
 SETB I2C_SDA
; CALL I2C_BITDLY
 RET
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; I2C_BITDLY Retardo de bit. (No usado a esta frecuencia)
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I2C_BITDLY:
; NOP
; RET
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; I2C_STOP Termina bus I2C
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I2C_STOP:
 CLR I2C_SDA   ; SDA bajo
 CALL I2C_SCLH   ; SCL alto
; CALL I2C_BITDLY
 SETB I2C_SDA   ; SDA alto (stop).
; CALL I2C_BITDLY
 RET
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Rutinas de tiempo
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SEGUNDO:
 MOV R6,#10
 SJMP DECIMA1
DECIMA:
 MOV R6,#1
DECIMA1:
; JNB T_VAR,DECIMA2
; RET
DECIMA2:
 MOV R7,#100
DECIMA3:
 MOV A,R7
 JNZ DECIMA3
 DJNZ R6,DECIMA1
 RET
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Rutina de servicio UART
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
UART_ISR:
 PUSH PSW
 PUSH ACC
 SJMP FIN_IRQ
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Rutina de servicio de Timer1
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Reactivar el timer
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
T0_ISR:
 CLR TR0    ; Timer 0 apagado
 MOV TH0,#CTE_TEMPH  ; Cargamos timer 0
 MOV TL0,#CTE_TEMPL  ; Para 1 ms de espera
 SETB TR0   ; Activamos de nuevo Timer 0
 PUSH PSW   ; Salvamos el contexto
 PUSH ACC
;==============================================================================;
; Buscar variaciones en las teclas
;==============================================================================;
 MOV A,P0
 PUSH ACC
LEE_TECLA:
 MOV P0,#0FFh
 MOV P3,#0FFh
 CLR KL0
 SETB KL1
 SETB KL2
 MOV A,P3   ; Leemos fila de teclas
 CPL A    ; Logica positiva
 ANL A,#0FCh   ; Aislamos bits utiles
 XCH A,BTECLAS   ; Salvamos estado teclas
 XRL A,BTECLAS   ; Comparamos con estado anterior
 JZ LEE_TECLA1
 MOV TapagadoH,#60  ; Reponemos tiempo de apagado
 CLR LCD_ILUM   ; Iluminamos el LCD
 SETB T_VAR   ; Señalamos tecla alterada
LEE_TECLA1:
 SETB KL0
 CLR KL1
 MOV A,P3   ; Leemos fila de teclas
 CPL A    ; Logica positiva
 ANL A,#0FCh   ; Aislamos bits utiles
 XCH A,BOPTOA   ; Salvamos estado teclas
 XRL A,BOPTOA   ; Comparamos con estado anterior
 JZ LEE_TECLA2
 SETB O_VAR   ; Señalamos tecla alterada
LEE_TECLA2:
 SETB KL1
 CLR KL2
 MOV A,P3   ; Leemos fila de teclas
 CPL A    ; Logica positiva
 ANL A,#0FCh   ; Aislamos bits utiles
 XCH A,BOPTOB   ; Salvamos estado teclas
 XRL A,BOPTOB   ; Comparamos con estado anterior
 JZ LEE_TECLA3
 SETB O_VAR   ; Señalamos tecla alterada
LEE_TECLA3:
 POP ACC
 MOV P0,A
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Contadores de tiempo
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TIEMPOS:
 DEC R7    ; Contador de mS
 DJNZ TapagadoL,FIN_IRQ
 MOV TapagadoL,#250
TIEMPOS1:
 DJNZ TapagadoH,FIN_IRQ  ; Contador para el apagado.
 SETB LCD_ILUM   ; Cortamos la alimentacion
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Restauramos contexto y volvemos
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FIN_IRQ:
 POP ACC
 POP PSW
 RETI
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Constantes en memoria
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TXT_ABRIENDO:
 DB 'Abriendo',0
TXT_CERRANDO:
 DB 'Cerrando',0
TXT_ABIERTO:
 DB 'Abierto',0
TXT_CERRADO:
 DB 'Cerrado',0
TXT_OK:
 DB 'OK',0
TXT_NO:
 DB 'No',0
TXT_C_Auto:
 DB 'Auto',0
TXT_C_Placa:
 DB 'Placa',0
TXT_C_220:
 DB '220V',0
TXT_C_ALT:
 DB 'Alter.',0
TXT_TEST:
 DB 'Test',0
TXT_TECLA:
 DB 'Tecla',0
TXT_OPTO:
 DB 'Opto',0
TXT_NOEEPROM:
 DB 'EEPROM no responde',0
 
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Test (solo durante programacion
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TEST:
 CALL LCD_BORRAR
TEST0:
 CALL DECIMA
 CALL LCD_BORRARTXT
 MOV DPTR,#TXT_TEST
 MOV R2,#12h
 MOV R3,#00h
 CALL LCD_TEXTO
 JNB Tecla_1I,TEST_1
 MOV DPTR,#TXT_TECLA
 MOV R2,#00h
 MOV R3,#02h
 CALL LCD_TEXTO
 MOV A,#' '
 CALL LCD_CHAR
 MOV A,#'1'
 CALL LCD_CHAR
TEST_1:
 JNB Tecla_2I,TEST_2
 MOV DPTR,#TXT_TECLA
 MOV R2,#00h
 MOV R3,#03h
 CALL LCD_TEXTO
 MOV A,#' '
 CALL LCD_CHAR
 MOV A,#'2'
 CALL LCD_CHAR
TEST_2:
 JNB Tecla_3I,TEST_3
 MOV DPTR,#TXT_TECLA
 MOV R2,#00h
 MOV R3,#04h
 CALL LCD_TEXTO
 MOV A,#' '
 CALL LCD_CHAR
 MOV A,#'3'
 CALL LCD_CHAR
TEST_3:
 JNB Tecla_1D,TEST_4
 MOV DPTR,#TXT_TECLA
 MOV R2,#00h
 MOV R3,#05h
 CALL LCD_TEXTO
 MOV A,#' '
 CALL LCD_CHAR
 MOV A,#'4'
 CALL LCD_CHAR
TEST_4:
 JNB Tecla_2D,TEST_5
 MOV DPTR,#TXT_TECLA
 MOV R2,#00h
 MOV R3,#06h
 CALL LCD_TEXTO
 MOV A,#' '
 CALL LCD_CHAR
 MOV A,#'5'
 CALL LCD_CHAR
TEST_5:
 JNB Tecla_3D,TEST_6
 MOV DPTR,#TXT_TECLA
 MOV R2,#00h
 MOV R3,#07h
 CALL LCD_TEXTO
 MOV A,#' '
 CALL LCD_CHAR
 MOV A,#'6'
 CALL LCD_CHAR
TEST_6:
 JNB CHG_V,TEST_7
 MOV DPTR,#TXT_OPTO
 MOV R2,#10h
 MOV R3,#02h
 CALL LCD_TEXTO
 MOV A,#' '
 CALL LCD_CHAR
 MOV A,#'1'
 CALL LCD_CHAR
TEST_7:
 JNB CHG_A,TEST_8
 MOV DPTR,#TXT_OPTO
 MOV R2,#10h
 MOV R3,#03h
 CALL LCD_TEXTO
 MOV A,#' '
 CALL LCD_CHAR
 MOV A,#'2'
 CALL LCD_CHAR
TEST_8:
 JNB CNV_ERR,TEST_9
 MOV DPTR,#TXT_OPTO
 MOV R2,#10h
 MOV R3,#04h
 CALL LCD_TEXTO
 MOV A,#' '
 CALL LCD_CHAR
 MOV A,#'3'
 CALL LCD_CHAR
TEST_9:
 JNB CNV_ON,TEST_10
 MOV DPTR,#TXT_OPTO
 MOV R2,#10h
 MOV R3,#05h
 CALL LCD_TEXTO
 MOV A,#' '
 CALL LCD_CHAR
 MOV A,#'4'
 CALL LCD_CHAR
TEST_10:
 JNB Opto_5,TEST_11
 MOV DPTR,#TXT_OPTO
 MOV R2,#10h
 MOV R3,#06h
 CALL LCD_TEXTO
 MOV A,#' '
 CALL LCD_CHAR
 MOV A,#'5'
 CALL LCD_CHAR
TEST_11:
 JNB Opto_6,TEST_12
 MOV DPTR,#TXT_OPTO
 MOV R2,#10h
 MOV R3,#07h
 CALL LCD_TEXTO
 MOV A,#' '
 CALL LCD_CHAR
 MOV A,#'6'
 CALL LCD_CHAR
TEST_12:
 JNB Opto_7,TEST_13
 MOV DPTR,#TXT_OPTO
 MOV R2,#20h
 MOV R3,#02h
 CALL LCD_TEXTO
 MOV A,#' '
 CALL LCD_CHAR
 MOV A,#'7'
 CALL LCD_CHAR
TEST_13:
 JNB Opto_8,TEST_14
 MOV DPTR,#TXT_OPTO
 MOV R2,#20h
 MOV R3,#03h
 CALL LCD_TEXTO
 MOV A,#' '
 CALL LCD_CHAR
 MOV A,#'8'
 CALL LCD_CHAR
TEST_14:
 JNB Opto_9,TEST_15
 MOV DPTR,#TXT_OPTO
 MOV R2,#20h
 MOV R3,#04h
 CALL LCD_TEXTO
 MOV A,#' '
 CALL LCD_CHAR
 MOV A,#'9'
 CALL LCD_CHAR
TEST_15:
 JNB Opto_A,TEST_16
 MOV DPTR,#TXT_OPTO
 MOV R2,#20h
 MOV R3,#05h
 CALL LCD_TEXTO
 MOV A,#' '
 CALL LCD_CHAR
 MOV A,#'A'
 CALL LCD_CHAR
TEST_16:
 JNB Opto_B,TEST_17
 MOV DPTR,#TXT_OPTO
 MOV R2,#20h
 MOV R3,#06h
 CALL LCD_TEXTO
 MOV A,#' '
 CALL LCD_CHAR
 MOV A,#'B'
 CALL LCD_CHAR
TEST_17:
 JNB Opto_C,TEST_18
 MOV DPTR,#TXT_OPTO
 MOV R2,#20h
 MOV R3,#07h
 CALL LCD_TEXTO
 MOV A,#' '
 CALL LCD_CHAR
 MOV A,#'C'
 CALL LCD_CHAR
TEST_18:
 
 
 JMP TEST0
 END
 
Joerrrrr pedazo código...... hasta la hora el más largo que he visto..... aunque creo que te lo superaré con lo de scalextric, jejejejejeje

Muchas gracias por la info, ahora me pongo a analizarlo y sacar conclusiones y ideas.
 
Arriba
© 2004-2024 Webcampista.com