Hola a todos.
Cuando uso el programa de ejemplo que trae JAL, la conexión anda muy bien. Incluso si la modifico y le voy agregando algunas tareas, la comunicación anda muy bien también. Pero cuando necesito agregarle más trabajo, la PC deja de reconocerme al PIC. Me he dado cuenta de que es por culpa de la función usb_serial_flush(). Si la llamo seguido, no tengo problema; pero si por algún problema el PIC se demora más de lo habitual para llamar a la función antes mencionada, la comunicación falla.
Para ello decidí usar la interrupción por TMR0 usando la librería, pero no he tenido buenos resultados. A fin de evitar problemas, decidí hacer mi propia configuración del TMR0; haciendo una interrupción cada 15useg (emulado en el MPLAB). Adivinen, no funcionó.
Sinceramente, ya no se porqué es la falla. Desde que retomé con este proyecto, me he estado volviendo loco. A continuación, pego el código completo para ver si ustedes ven mi error:
-- ------------------------------------------------------------------------------------------------
--
-- Este programa ha sido generado por jallib.py
-- Plataforma Invernadero.
--
-- ------------------------------------------------------------------------------------------------
-- INICIO DEL PROGRAMA.
-- --------------------
include 18f4550 -- Incluímos la librería para controlar nuestro PIC.
-- Aunque el cristal externo es 20 MHz, la configuración es tal que el reloj de la CPU
-- se deriva de reloj PLL 96 Mhz (div2),
-- por lo tanto, establecer la frecuencia de destino para 20 MHz
pragma target clock 20_000_000
-- FUSIBLES:
-- ---------
pragma target PLLDIV P5 -- divide by 5 - 20MHZ_INPUT
pragma target CPUDIV P1 -- [primary oscillator src: /1][96 mhz pll src: /2]
pragma target USBPLL F48MHZ -- CLOCK_SRC_FROM_96MHZ_PLL_2
pragma target OSC HS_PLL
pragma target FCMEN DISABLED
pragma target IESO DISABLED
pragma target PWRTE DISABLED -- power up timer
pragma target VREGEN ENABLED -- USB voltage regulator
pragma target VOLTAGE MINIMUM -- brown out voltage
pragma target BROWNOUT DISABLED -- no brownout detection
pragma target WDTPS P32K -- watch dog saler setting
pragma target WDT CONTROL -- no watchdog
pragma target CCP2MUX ENABLED -- CCP2 pin C1
pragma target PBADEN DIGITAL -- digital input port<0..4>
pragma target LPT1OSC LOW_POWER -- low power timer 1
pragma target MCLR EXTERNAL -- master reset on RE3
pragma target STVR DISABLED -- reset on stack over/under flow
pragma target LVP DISABLED -- no low-voltage programming
pragma target XINST ENABLED -- extended instruction set
pragma target DEBUG DISABLED -- background debugging
pragma target CP0 DISABLED -- code block 0 not protected
pragma target CP1 DISABLED -- code block 1 not protected
pragma target CP2 DISABLED -- code block 2 not protected
pragma target CP3 DISABLED -- code block 3 not protected
pragma target CPB DISABLED -- bootblock code not write protected
pragma target CPD DISABLED -- eeprom code not write protected
pragma target WRT0 DISABLED -- table writeblock 0 not protected
pragma target WRT1 DISABLED -- table write block 1 not protected
pragma target WRT2 DISABLED -- table write block 2 not protected
pragma target WRT3 DISABLED -- table write block 3 not protected
pragma target WRTB DISABLED -- bootblock not write protected
pragma target WRTD DISABLED -- eeprom not write protected
pragma target WRTC DISABLED -- config not write protected
pragma target EBTR0 DISABLED -- table read block 0 not protected
pragma target EBTR1 DISABLED -- table read block 1 not protected
pragma target EBTR2 DISABLED -- table read block 2 not protected
pragma target EBTR3 DISABLED -- table read block 3 not protected
pragma target EBTRB DISABLED -- boot block not protected
-- ------------------------------------------------------------------------------------------------
-- INCLUIMOS LIBRERÍAS:
-- --------------------
include usb_serial -- Incluímos la librería para emular el puerto serial por USB.
include delay -- Incluímos la librería para las demoras.
-- ------------------------------------------------------------------------------------------------
-- CONFIGURACIÓN GENERAL DEL PIC:
-- ------------------------------
enable_digital_io() -- Por seguridad, configuraremos a los pines análogos
-- como digitales. Luego, cuando inicializemos el ADC,
-- se autoconfigurará analógicas las entradas a utilizar.
INTCON_GIE = false -- Deshabilitamos las interrupciones. Las habilitaremos
-- mas adelante.
portb_direction = output -- Todo el puerto B como salida.
portc_direction = output -- Todo el puerto C como salida.
portd_direction = output -- Todo el puerto D como salida.
pin_a4_direction = output -- Solo el RA4 como salida.
-- ------------------------------------------------------------------------------------------------
-- CONFIGURACIÓN DEL TMR0:
-- -----------------------
var byte tempori = 200
T0CON = 0b11000000 -- Habilitamos el TMR0, 8 Bit, Reloj del PIC; Prescaler 1:2
TMR0L = tempori -- A 48Mhz 15useg
INTCON_TMR0IF = 0 -- Por seguridad, limpiamos la bandera.
INTCON_TMR0IE = 1 -- Habilitamos individualmente la interrupción de TMR0
-- INTCON_GIE = 1 -- Habilitamos las interrupciones.
---------------------------------------------------------------------------------------------------
-- CONFIGURACIÓN DEL ADC:
-------------------------
;const bit ADC_HIGH_RESOLUTION = false
-- we said we want 1 analog channel...
;const byte ADC_NCHANNEL = 1
-- and no voltage reference
;const byte ADC_NVREF = 0
-- now we can include the library
-- note it's now named "adc", not "adc_hardware" anymore
;include adc
-- and run the initialization step
;adc_init()
-- ------------------------------------------------------------------------------------------------
-- VARIABLES:
-- -----------
var byte ch
var byte temp_hongo_1
var byte hum_hongo_1
var byte temp_hongo_2
var byte hum_hongo_2
var byte temp_hongo_3
var byte hum_hongo_3
var byte temp_hongo_4
var byte hum_hongo_4
var byte canal
var byte temperatura
var byte humedad
var word temp
var dword hum
-- ------------------------------------------------------------------------------------------------
-- setup the USB serial library
usb_serial_init()
INTCON_GIE = 1 -- Habilitamos las interrupciones.
-- ------------------------------------------------------------------------------------------------
-- TRATAMIENTO DE LAS INTERRUPCIONES:
-- ----------------------------------
procedure temporizador0() is
pragma interrupt NORMAL
if INTCON_TMR0IF == 1 then
usb_serial_flush()
end if
TMR0L = tempori
INTCON_TMR0IF = 0
end procedure
-- ----------------------------------------------------------------------------
-- PROCEDIMIENTOS Y FUNCIONES TOTALES.
-- -----------------------------------
-- ----------------------------------------------------------------------------
-- PROCEDIMIENTOS PARA EL CAD:
-- ---------------------------
function leer_cad(byte in canal)return byte is
var byte resultado_cad
ADCON0_CHS = canal
ADCON0_ADON = 1
_usec_delay(4) -- 20uS
ADCON0_GO = 1
while ADCON0_GO loop end loop -- Esperamos hasta que la conversión finalice.
resultado_cad = ADRESH
ADCON0_ADON = 0
return resultado_cad
end function
procedure sensar_temperatura() is
temp = BYTE(leer_cad(canal)) -- Iniciamos la conversión
temp = temp * 195 -- Multiplicamos por 195 para pasarlo a tensión
temp = temp / 100 -- Dividimos por 100 para quedarnos con la parte entera. Tamaño máximo 8 bit.
temperatura = BYTE(temp) -- El resultado de 8 bit, lo pasamos a otra variable de tamaño de 8 bit
end procedure
;
;**********************************************************************
;MEDIMOS LA HUMEDAD.
;------------------
;PASOS A SEGUIR.
;
;1- CONFIGURAR EL CANAL A SENSAR.
;2- MEDIR EL ADC DE LA HUMEDAD Y GUARDAMOS EL VALOR EN RAM
; TENEMOS QUE APLICAR LA FÓRMULA SIGUIENTE PARA OBTENER LA HUMEDAD HR = (Vout - 0,8) / 0,031
;3- PARA ELLO, DEVEMOS MULTIPLICAR EL ADC POR 196 PARA PASARLO A TENSIÓN (EN REALIDAD DEBERÍA SER 195 PERO CON ESTE, EL ERROR ES MAS GRANDE).
;4- LUEGO LO VOLVEMOS A MULTIPLICAR POR 1.000 PARA TRABAJAR CON LA SIGUIENTE FÓRMULA HR = (Vout - 800) / 31
;5- APLICAMOS LA FORMULA HR = (Vout - 800) / 31,
;5- EL RESULTADO LO DIVIDIMOS POR 10.000 PARA OBETENER LA HUMEDAD RELATIVA EN 2 DÍGITOS (O 1.000 PARA OBTENER 3 DÍGITOS, ANALIZAMOS MAS ADELANTE ESTO)
;6- LO GUARDAMOS EN LA RAM
;7- TOMAMOS 42 MUESTRAS
;8- HACEMOS EL PROMEDIO, PARA ELLO SUMAMOS LAS 42 MUESTRAS ENTRE SI Y LUEGO LA DIVIDIMOS POR 42
;9- EL RESULTADO DEL PROMEDIO LO GUARDAMOS EN LA RAM humedad
;10- SENSAMOS EL VIENTO.
;**********************************************************************
procedure sensar_humedad() is
hum = BYTE(leer_cad(canal)) -- Iniciamos la conversión
hum = hum * 196 -- Lo pasamos a tensión
hum = hum * 1000 -- Lo multiplicamos por 1000
hum = hum - 800 -- Le restamos 800
hum = hum / 31 -- Lo dividimos por 31
hum = hum / 10000 -- Lo dividimos por 10000 para obtener 3 dígitos
humedad = BYTE(hum) -- El resultado de 8 bit, lo pasamos a otra variable de tamaño de 8 bit
end procedure
-- main loop
forever loop
;
canal = 0 -- Temperatura hongo 1 (AN0).
sensar_temperatura()
-- usb_serial_flush()
temp_hongo_1 = temperatura -- Recuperamos el valor de la temperatura sensado.
-- usb_serial_flush()
;
canal = 1 -- Humedad hongo 1 (AN1).
sensar_humedad()
-- usb_serial_flush()
hum_hongo_1 = humedad -- Recuperasmos el valor de la humedad sensada.
-- usb_serial_flush()
;
canal = 2 -- Temperatura hongo 2 (AN2).
sensar_temperatura()
-- usb_serial_flush()
temp_hongo_2 = temperatura -- Recuperamos el valor de la temperatura sensado.
-- usb_serial_flush()
;
canal = 3 -- Humedad hongo 2 (AN3).
sensar_humedad()
-- usb_serial_flush()
hum_hongo_2 = humedad -- Recuperasmos el valor de la humedad sensada.
-- usb_serial_flush()
;
canal = 4 -- Temperatura hongo 3 (AN4).
sensar_temperatura()
-- usb_serial_flush()
temp_hongo_3 = temperatura -- Recuperamos el valor de la temperatura sensado.
-- usb_serial_flush()
;
canal = 5 -- Humedad hongo 3 (AN5).
sensar_humedad()
-- usb_serial_flush()
hum_hongo_3 = humedad -- Recuperasmos el valor de la humedad sensada.
-- usb_serial_flush()
;
canal = 6 -- Temperatura hongo 4 (AN6).
sensar_temperatura()
-- usb_serial_flush()
temp_hongo_4 = temperatura -- Recuperamos el valor de la temperatura sensado.
-- usb_serial_flush()
;
canal = 7 -- Humedad hongo 4 (AN7).
sensar_humedad()
-- usb_serial_flush()
hum_hongo_4 = humedad -- Recuperasmos el valor de la humedad sensada.
-- usb_serial_flush()
if ( usb_cdc_line_status() != 0x00 ) then
ch = 0
if usb_serial_read(ch) then -- leo el puerto usb
-- usb_serial_flush() -- mantengo viva la conexion usb
case ch of -- manipulación de salidas digitales
"A": pin_b7 = on -- Ventilador encendido
"B": pin_b7 = off -- Ventilador apagado
"C": pin_b6 = on -- Calefación encendido
"D": pin_b6 = off -- Calefacción apagado
"E": pin_b5 = on -- Refrigeración encendido
"F": pin_b5 = off -- Refrigeración apagado
"G": pin_b4 = on -- Luz encendido
"H": pin_b4 = off -- Luz apagado
"I": pin_b3 = on -- Humificador encendido
"J": pin_b3 = off -- Humificador apagado
;
"0": usb_serial_write(temp_hongo_1) -- Mostrar el valor de la tempereatura actual.
"1": usb_serial_write(hum_hongo_1) -- Mostrar el valor de la humedad actual.
"2": usb_serial_write(pin_b7) -- Mostrar el estado del ventilador.
"3": usb_serial_write(pin_b6) -- Mostrar el estado del calefacción.
"4": usb_serial_write(pin_b5) -- Mostrar el estado de la refrigeración.
"5": usb_serial_write(pin_b4) -- Mostrar el estado de la luz.
"6": usb_serial_write(pin_b3) -- Mostrar el estado del humificador.
;
"K": pin_b2 = on -- Vantilador 2 encendido
"L": pin_b2 = off -- Ventilador 2 apagado
"M": pin_d7 = on -- Calefacción 2 encendido
"N": pin_d7 = off -- Calefacción 2 apagado
"O": pin_d6 = on -- Refrigeración 2 encendido
"P": pin_d6 = off -- Refrigeración 2 apagado
"Q": pin_d5 = on -- Luz 2 ecendido
"R": pin_d5 = off -- Luz 2 apagado
"S": pin_d4 = on -- Humificador 2 encendido
"T": pin_d4 = off -- Humificador 2 apagado
;
"7": usb_serial_write(temp_hongo_2) -- Muestra la temperatura del hongo 2
"8": usb_serial_write(hum_hongo_2) -- Muestra la humedad del hongo 2
"9": usb_serial_write(pin_b2) -- Muestra el estado del ventilador 2
":": usb_serial_write(pin_d7) -- Muestra el estado de la calefacción 2
";": usb_serial_write(pin_d6) -- Muestra el estado de la refrigeración 2
"<": usb_serial_write(pin_d5) -- Muestra el estado de la luz 2
"=": usb_serial_write(pin_d4) -- Muestra el estado del humuficador 2
;
"a": pin_c7 = on -- Ventilador 3 encendido
"b": pin_c7 = off -- Ventilador 3 apagado
"c": pin_c6 = on -- Calefacción 3 encendido
"d": pin_c6 = off -- Calefacción 3 apagado
"e": pin_d3 = on -- Refrigeración 3 encendido
"f": pin_d3 = off -- Refrigeración 3 apagado
"g": pin_d2 = on -- Luz 3 encendido
"h": pin_d2 = off -- Luz 3 apagado
"i": pin_c0 = on -- Humificador 3 encendido
"j": pin_c0 = off -- Humificador 3 apagado
;
">": usb_serial_write(temp_hongo_3) -- Muestra la temperatura del hongo 3
"?": usb_serial_write(hum_hongo_3) -- Muestra la humedad del hongo 3
"@": usb_serial_write(pin_c7) -- Muestra el estado del ventilador 3
"(": usb_serial_write(pin_c6) -- Muestra el estado de la calefacción 3
")": usb_serial_write(pin_d3) -- Muestra el estado de la refrigeración 3
"+": usb_serial_write(pin_d2) -- Muestra el estado de la luz 3
"^": usb_serial_write(pin_c0) -- Muestra el estado del humificador 3
;
"k": pin_c1 = on -- Ventilador 4 encendido
"l": pin_c1 = off -- Ventilador 4 apagado
"m": pin_c2 = on -- Calefacción 4 encendido
"n": pin_c2 = off -- Calefacción 4 apagado
"o": pin_d0 = on -- Refrigeración 4 encendido
"p": pin_d0 = off -- Refrigeración 4 apagado
"q": pin_d1 = on -- Luz 4 encendido
"r": pin_d1 = off -- Luz 4 apagado
"s": pin_a4 = on -- Humificador 4 encendido
"t": pin_a4 = off -- Humificador 4 apagado
;
"_": usb_serial_write(temp_hongo_4) -- Muestra la temperatura del hongo 4
"!": usb_serial_write(hum_hongo_4) -- Muestra la humedad del hongo 4
" ": usb_serial_write(pin_c1) -- Muesttra el estado del ventilador 4
"#": usb_serial_write(pin_c2) -- Muestra el estado de la calefacción 4
"$": usb_serial_write(pin_d0) -- Muestra el estado de la refrigeración 4
"%": usb_serial_write(pin_d1) -- Muestra el estado de la luz 4
"&": usb_serial_write(pin_a4) -- Muestra el estado del humificador 4
;
end case
end if
end if
end loop
Como notarán, es una máquina de estado. Aún falta terminar ya que faltan funciones, que no las quiero agregar hasta tanto solucione este problema de comunicación.
Notarán que hay muchas llamadas de la función usb_serial_flush() pero que están comentada (con --) para ver si logro funcionar con la interrupción por TMR0.
Hasta tomé la precaución de activar la interrupción después de inicializar el puerto USB, para que usb_serial_flush() no sea llamado primero.
He utilizado otros tiempos de interrupciones con 2 mseg y 6mseg, pero el resultado es el mismo.
Desde ya, cualquier ayuda se los agradeceré muchísimo.