Introducción
Placa entrenadora PIC EBASIC |
PIC EBASIC es una placa entrenadora de bajo coste para poder iniciarse en el mundo de los PIC,
reúne una serie de cualidades que nos permitirá practicar con ella a
distintos niveles de dificultad, desde principiantes hasta niveles
avanzados sin perder la cualidad de ser una herramienta de bajo coste.
Esta placa y los ejemplos que acompañan en artículo fueron desarrollados por Carlos "Dogflu66", quien los fue posteando en el foro TODOPIC. Carlos a autorizado la publicación de su trabajo en uControl.
Características
Se ha elegido como base de esta placa al microcontrolador PIC16F88, que mantiene una cierta compatibilidad con el pinour del PIC16F84, pero internamente posee una cantidad y variedad de módulos que lo hace casi único dentro de su categoría.
La placa contiene los siguientes elementos para poder interactuar con ella:
- Display LCD de 16x2 caracteres con su ajuste de contraste.
- Control de la retroiluminacion del LCD para hacer practicas con el modulo CCP del PIC.
- Reloj calendario por I2C, con una batería no recargable de litio y LED indicador.
- Dos pulsadores en placa.
- Dos LED que se pueden controlar mediante el PIC.
- Un resistor ajustable para poder hacer pruebas con el módulo ADC.
- Conexión exterior para el puerto I2C y el Pin RA4 del ADC u otro uso como controlar servomotores, reles, etc.
- Puerto serie para ser usado como RS-232.
- Puerto ICSP que permite programar el PIC directamente en la placa.
- Protección contra inversión de polaridad de la alimentación y medidas básicas contra interferencias.
El circuito
Este es el esquema electrico de la PIC EBASIC:
Circuito de la PIC EBASIC
Fotografías
Aqui ponemos un par de fotografías de la placa terminada:
Ejercicios de programación
Configuracion del PSI
Los ejemplos estan realizados con el entorno de trabajo del PIC SIMULATOR IDE,y compilados con su [BASIC (PSI)|compilador Basic].
Deberemos instalar el PIC SIMULATOR IDE, y configurar su entorno de trabajo como sigue:
- En el menú Options seleccionar el PIC16F88 a utilizar mediante Select MIcrocontroller.
- Elegir la frecuencia del cristal en MHz del microcontrolador, desde Options -> Change Clock Frequency.
- Seleccionar el modo de trabajo del microcontrolador desde Option -> Configuration Bits.
Todo esto queda ya configurado para otras ocasiones, pero de todas formas cada vez que se entra en el PIC SIMULATOR IDE es conveniente el comprobar que Configuration Bits no ha cambiado, ya que es sensible a algunas modificaciones.
Y ya solo resta indicar en que se va a trabajar en [BASIC (PSI)|Basic] o ASM mediante Tools -> BASIC Compiler.
Estamos listos para comenzar. Si surgen dudas sobre en el entorno de programación, puede consultarse el artículo correspondiente en uControl. Y para comprender el [BASIC (PSI)|Basic], puede consultarse la [BASIC (PSI)|guia] sobre este lenguaje de programación.
Escribir "A" en el LCD
Este es el codigo a compilar y cargar en el microcontrolador:
'NOMBRE:16F88_PicEBasic
'MICRO: PIC16F88/8Mhz reloj interno
'Uso del LCD con bus de datos a 4Bit y sin pin de RW
'**********************************************************************
'----------Puertos del LCD---------------------------------------------
Define LCD_BITS = 4 'indicamos que el bus de datos del lcd sera de 4bit
Define LCD_DREG = PORTA 'el bus de datos sera el puerto A
Define LCD_DBIT = 0 'el bus de datos seran los 4 bit menos significativos del puerto A
Define LCD_RSREG = PORTB 'el bit de control RS sera del puerto A
Define LCD_RSBIT = 7 'se usara el RA7 como RS
Define LCD_EREG = PORTB 'el bit de control E sera del puerto A
Define LCD_EBIT = 6 'se usara el RA6 como E
'Define LCD_RWREG = PORTA 'el bit de control RW sera del puerto A (si se suprime el compilador no protesta
'Define LCD_RWBIT = 5 'se usara el RA5 como RW (si se suprime el compilador no protesta)
Define LCD_COMMANDUS = 2000 'Tiempo de espera despues de ejecutar un comand del lcd en uSeg.
Define LCD_DATAUS = 50 'Tiempo de espera despues de enviar un dato al LCD en uSeg.
Define LCD_INITMS = 5 '(50) 'Tiempo de espera despues de inicializar el Display, solo se ejecuta una vez en Seg.
'---------------------------------------------------------------
'Define SIMULATION_WAITMS_VALUE = 1 'suprime los tiempos de espera Waitms, solo activar esta linea en simulacion
'---Definicion de puertos y registros----------------------------
ANSEL = 0x00 'los pin I/O digitales (no analogicos)
OSCCON = 0x7e 'set intrc To 8mhz, se usara reloj interno a 8Mhz
CMCON = 0x07 'comparador a off
TRISA = 0x00 'Puerto A como salidas
TRISB = 0x00 'puerto B como salidas
'---------------------Inicio-------------------------------------
Lcdinit 'inicializa el lcd sin cursor
WaitMs 500 'pausa para estabilizar
main: 'comienza el programa principal
Lcdcmdout LcdClear 'borra el display
WaitMs 1000 'hace una pausa de 1Seg.
Lcdout "A" 'escribe el caracter "A" en el display
WaitMs 1000 'hace una pausa de 1Seg.
Goto main 'impide que termine el programa principal
End 'es conveniente ponerlo siempre segun el manual
El resultado es una letra "A" que parpadea en la primer posición de la primer fila del display LCD. Permanece durante un segundo, desaparece durante otro segundo, y vuelve a comenzar.
Teclas y LEDs
Este ejemplo simplemente lee el estado de las teclas, mostrando en el display LCD el estado de las mismas, a la vez que enciende el LED correspondiente:'************ PIC Entrenadora BASIC (PicEBasic)******************************
'NOMBRE: 16F88_LCD_I/O
'VERSION: 1.0
'MICRO: PIC16f88A
'FECHA/AUTOR: 12/06 - By COS
'DESCRIPCION: MUESTRA EN EL DISPLAY EL ESTADO DE LA TECLA ACTIVANDO EL LED ASOCIADO
'*****************************************************************************
'-------------------tos del LCD-----------------------------------------------
Define LCD_BITS = 4 'indicamos que el bus de datos del lcd sera de 4bit
Define LCD_DREG = PORTA 'el bus de datos sera el puerto A
Define LCD_DBIT = 0 'el bus de datos seran los 4 bit menos significativos del puerto A
Define LCD_RSREG = PORTB 'el bit de control RS sera del puerto B
Define LCD_RSBIT = 7 'se usara el RB7 como RS
Define LCD_EREG = PORTB 'el bit de control E sera del puerto B
Define LCD_EBIT = 6 'se usara el RB6 como E
'Define LCD_RWREG = PORTx 'el bit de control RW sera del puerto x(no se usa)
'Define LCD_RWBIT = n 'se usara el Rxn como RW (no se usa)
'
Define LCD_COMMANDUS = 2000 'Tiempo de espera despues de ejecutar un comand del lcd en uSeg.
Define LCD_DATAUS = 50 'Tiempo de espera despues de enviar un dato al LCD en uSeg.
Define LCD_INITMS = 50 'Tiempo de espera despues de inicializar el Display, solo se ejecuta una vez en mSeg.
'
'*****************DEFINICION DE VARIABLES**************************************
'--------------------Variables Programa----------------------------------------
Dim tecla_s1 As Byte 'guarda el estado de la tecla hasta terminar la maniobra
Dim tecla_s2 As Byte 'guarda el estado de la tecla hasta terminar la maniobra
'
'------------------------ASIGNACIONES------------------------------------------
tecla_s1 = 0
tecla_s2 = 0
'
'********************DEFINICION DE PUERTOS*************************************
'-----ASIGNACION DE I/O y valores de inicio de las salidas---------------------
ANSEL = %00000000 'los pin I/O digitales
CMCON = 0x07 'comparador a off
OSCCON = 0x7e 'set intrc To 8mhz, se usara reloj interno a 8Mhz
TRISA = 0x00 'Puerto A como salidas
TRISB = 0x00 'puerto B como salidas
TRISA.4 = 1 'como entrada (RA4, adc)
TRISA.6 = 1 'como entrada (RA6, tecla S1)
TRISA.5 = 1 'como entrada (RA5, tecla S2)
PORTB.3 = 1 'luz lcd a on (RB3)
PORTA.7 = 1 'led amarillo a off
PORTB.0 = 1 'led verde a off
'
'******************Inicio Programa*********************************************
Lcdinit 'inicializa el lcd sin cursor
WaitMs 1000 'espera 1Seg
Lcdout "16f88_LCD_I/O" 'escribe en el lcd
Lcdcmdout LcdLine2Home 'seleciona la linea dos como proxima para escritura
Lcdout "Pruebas con I/O" 'escribe en el lcd
WaitMs 3000 'espera 3Seg
'------------------Main Programa-----------------------------------------------
main:
If RA6 = 0 Then tecla_s1 = 1 'lee el estado de la tecla S1
If RA5 = 0 Then tecla_s2 = 1 'lee el estado de la tecla S2
Gosub print_lcd 'salto con retorno, rutina que imprime los valores en el lcd
WaitMs 100
If tecla_s1 = 1 Then 'si la tecla S1 fue pulsada
Toggle RA7 'invierte el estado de RA7, led amarillo
tecla_s1 = 0 'tecla queda en reposo
Endif
If tecla_s2 = 1 Then 'si la tecla S2 fue pulsada
Toggle RB0 'Invierte el estado de RB0, led verde
tecla_s2 = 0 'tecla queda en reposo
Endif
WaitMs 100 'hace una pausa de 100mSeg
Goto main
End
'---------------------FIN DEL MAIN---------------------------------------------
'
'*********************Subrrutinas**********************************************
print_lcd: '____________________muestra los datos por el display
Lcdcmdout LcdLine1Clear 'borra la primera linea y cursor al principio
Lcdout " S1 ", #tecla_s1, " -- S2 ", #tecla_s2 'imprime en el lcd
Lcdcmdout LcdLine2Clear 'borra la segunda linea y cursor al principio
Lcdout "----------------" 'muestra los datos en el lcd
REturn
End
DS1307: Un reloj en tu LCD
El siguiente ejemplo muestra como implementar un reloj utilizando el DS1307. Recordemos que los registros de dicho circuito integrado se leen y escriben en formato BCD.
'************ PIC Entrenadora BASIC (PicEBasic)******************************
'NOMBRE: 16F88_LCD_RTC
'VERSION: 1.0
'MICRO: PIC16f88A
'FECHA/AUTOR: 12/06 - By COS
'DESCRIPCION: MUESTRA EN EL DISPLAY LA FECHA Y LA HORA
'para transferir la hora al reloj dejar pulsada la tecla S1
'****************************************************************************
'--------------------Puertos del LCD-----------------------------------------
Define LCD_BITS = 4 'indicamos que el bus de datos del lcd sera de 4bit
Define LCD_DREG = PORTA 'el bus de datos sera el puerto A
Define LCD_DBIT = 0 'el bus de datos seran los 4 bit menos significativos del puerto A
Define LCD_RSREG = PORTB 'el bit de nrol RS sera del puerto B
Define LCD_RSBIT = 7 'se usara el RB7 como RS
Define LCD_EREG = PORTB 'el bit de nrol E sera del puerto B
Define LCD_EBIT = 6 'se usara el RB6 como E
'Define LCD_RWREG = PORTx 'el bit de nrol RW sera del puerto x(no se usa)
'Define LCD_RWBIT = n 'se usara el Rxn como RW (no se usa)
Define LCD_COMMANDUS = 2000 'Tiempo de espera despues de ejecutar un comand del lcd en uSeg.
Define LCD_DATAUS = 50 'Tiempo de espera despues de enviar un dato al LCD en uSeg.
Define LCD_INITMS = 50 'Tiempo de espera despues de inicializar el Display, solo se ejecuta una vez en mSeg.
'
'---------------------Puerto I2C---------------------------------------------
Symbol sda = PORTB.1 'asignamos nombre al pin que hara de SDA del puerto I2C
Symbol scl = PORTB.4 'asignamos nombre al pin que hara de SCL del puerto I2C
'
'***************DEFINICION DE VARIABLES**************************************
'
'------------------Variables Programa----------------------------------------
Dim aux_4h As Byte 'contendra el nibble alto del dato leido por el I2C
Dim aux_4l As Byte 'contendra el nibble bajo del dato leido por el I2C
Dim i As Byte 'variable indice
Dim reg(7) As Byte 'contendra los valores finales de fecha y hora en el sistema decimal
'
'----------------------ASIGNACIONES------------------------------------------
'******************DEFINICION DE PUERTOS*************************************
'-------------ASIGNACION DE I/O y valores de inicio de las salidas-----------
ANSEL = %00000000 'los pin I/O digitales
CMCON = 0x07 'comparador a off
OSCCON = 0x7e 'set intrc To 8mhz, se usara reloj interno a 8Mhz
TRISA = 0x00 'Puerto A como salidas
TRISB = 0x00 'puerto B como salidas
TRISA.4 = 1 'como entrada (RA4, adc)
TRISA.6 = 1 'como entrada (RA6, tecla S1)
TRISA.5 = 1 'como entrada (RA5, tecla S2)
PORTB.3 = 1 'luz lcd a on (RB3)
PORTA.7 = 1 'led amarillo a off
PORTB.0 = 1 'led verde a off
'
'***************Inicio Programa**********************************************
Lcdinit 'inicializa el lcd sin cursor
WaitMs 1000 'espera 1Seg
Lcdout "16f88LCD_RTC/I2C" 'escribe en el lcd
Lcdcmdout LcdLine2Home 'seleciona la linea dos como proxima para escritura
Lcdout "Pruebas con I2C" 'escribe en el lcd
WaitMs 3000 'espera 3Seg
Lcdcmdout LcdClear
'--------------------inicializacion del reloj---------------------------------
'
'------------Aqui escribimos los valores para cargar al RTC-------------------
If RA6 = 0 Then 'si la tecla S1 esta pulsada pasaremos los datos al reloj
I2CWrite sda, scl, 0xd0, 0, 0x00 'segundos, escrito en hex, porque coincide en este caso con BCD del RTC
I2CWrite sda, scl, 0xd0, 1, 0x59 'minutos
I2CWrite sda, scl, 0xd0, 2, 0x23 'horas
I2CWrite sda, scl, 0xd0, 3, 0x01 'dia de la semana
I2CWrite sda, scl, 0xd0, 4, 0x31 'dia del mes
I2CWrite sda, scl, 0xd0, 5, 0x12 'mes
I2CWrite sda, scl, 0xd0, 6, 0x06 'año
I2CWrite sda, scl, 0xd0, 7, 0x10 'salida a 1hz
Endif
'
'-----------------------Main Programa-----------------------------------------
main:
Gosub print_lcd 'actualiza la hora
WaitMs 100 'pausa de 100mSeg.
Goto main
End
'
'--------------------------FIN DEL MAIN----------------------------------------
'
'**********************Subrrutinas*********************************************
'
'lee la hora del RTC, la pasa a decimal y la envia al lcd
print_lcd:
i = 0
While i <= 6 'se repite el codigo comprendido entre while y wend, mientras i sea menor o igual a 6
I2CRead sda, scl, 0xd0, i, reg(i) 'lectura de la direccion de memoria indicada del RTC, formato BCD
aux_4l = reg(i) And %00001111 'eliminamos los bit de configuracion del RTC y dejamos solo el nibble bajo
If i = 0 Then aux_4h = reg(i) And %01110000 'segundos, borrado de bit configuracion y almacena nibble alto
If i = 1 Then aux_4h = reg(i) And %11110000 'minutos, almacena nibble alto
If i = 2 Then aux_4h = reg(i) And %10110000 'horas, borrado de bit configuracion y almacena nibble alto
If i = 3 Then aux_4h = reg(i) And %11110000 'dia_semana, almacena nibble alto
If i = 4 Then aux_4h = reg(i) And %11110000 'dia_mes, almacena nibble alto
If i = 5 Then aux_4h = reg(i) And %11110000 'mes, almacena el nibble alto
If i = 6 Then aux_4h = reg(i) And %11110000 'año, almacena el nibble alto
aux_4h = ShiftRight(aux_4h, 4) 'convierte el nibble alto en bajo
reg(i) = (aux_4h * 10) + aux_4l 'fusiona los nibbles alto y bajo en una sola variable en formato decimal
i = i + 1 'incrementa la variable indice con cada repeticion del bucle While/Wend
Wend 'fin del bucle y salta a While
Lcdcmdout LcdLine1Home 'cursor del lcd a la izquierda en la linea 1
If reg(2) < 10 Then Lcdout "0" 'si horas es inferior a 10 escribe el cero delante
Lcdout #reg(2), ":" 'escribe la hora y el separador
If reg(1) < 10 Then Lcdout "0" 'si minutos es inferior a 10 escribe el cero delante
Lcdout #reg(1), ":" 'escribe los minutos y el separador
If reg(0) < 10 Then Lcdout "0" 'si segundos es inferior a 10 escribe el cerodelante
Lcdout #reg(0) 'escribe los segundos
Lcdcmdout LcdLine2Home 'cursor del lcd a la izquierda en la linea 2
If reg(3) = 1 Then Lcdout "Dom" 'asigna el literal al dia de la semana
If reg(3) = 2 Then Lcdout "Lun"
If reg(3) = 3 Then Lcdout "Mar"
If reg(3) = 4 Then Lcdout "Mie"
If reg(3) = 5 Then Lcdout "Jue"
If reg(3) = 6 Then Lcdout "Vie"
If reg(3) = 7 Then Lcdout "Sab"
Lcdout "/" 'escribe separador
If reg(4) < 10 Then Lcdout "0" 'si dia del mes es inferior a 10 escribe cero
Lcdout #reg(4), "/" 'escribe el dia del mes y el separador
If reg(5) < 10 Then Lcdout "0" 'si mes es inferior a 10 escribe cero
Lcdout #reg(5), "/20" 'escribe el mes, separador y los dos primeros digitos del año de 4 digitos
If reg(6) < 10 Then Lcdout "0" 'si año es inferior a 10 escribe primero el cero
Lcdout #reg(6) 'escribe el año
Return
End
LCD y ADC
Sin usar funciones
El siguiente ejemplo muestra como utilizar el conversor Analógico/Digital del PIC16F88 y como mostrar los resultados por el display LCD. Como siempre, el código esta perfectamente documentado:
'************* PIC Entrenadora BASIC (PicEBasic)******************************
'NOMBRE: 16F88_LCD_ADC
'VERSION: 1.0
'MICRO: PIC16f88A
'FECHA/AUTOR: 12/06 - By COS
'DESCRIPCION: MUESTRA EN EL DISPLAY EL VALOR DE LA ENTRADA
'ANALOGICA CON DOS DECIMALES Y EN VOLTIOS
'*****************************************************************************
'---------------Puertos del LCD-----------------------------------------------
Define LCD_BITS = 4 'indicamos que el bus de datos del lcd sera de 4bit
Define LCD_DREG = PORTA 'el bus de datos sera el puerto A
Define LCD_DBIT = 0 'el bus de datos seran los 4 bit menos significativos del puerto A
Define LCD_RSREG = PORTB 'el bit de control RS sera del puerto B
Define LCD_RSBIT = 7 'se usara el RB7 como RS
Define LCD_EREG = PORTB 'el bit de control E sera del puerto B
Define LCD_EBIT = 6 'se usara el RB6 como E
'Define LCD_RWREG = PORTx 'el bit de control RW sera del puerto x(no se usa)
'Define LCD_RWBIT = n 'se usara el Rxn como RW (no se usa)
Define LCD_COMMANDUS = 2000 'Tiempo de espera despues de ejecutar un comand del lcd en uSeg.
Define LCD_DATAUS = 50 'Tiempo de espera despues de enviar un dato al LCD en uSeg.
Define LCD_INITMS = 50 'Tiempo de espera despues de inicializar el Display, solo se ejecuta una vez en mSeg.
'********************DEFINICION DE VARIABLES**************************************
'----------------Variables del ADC y Rutina division------------------------------
Dim num_1 As Word 'valor del adc y retorna la parte entera
Dim num_2 As Word 'factor de la escala y retorna el primer decimal
Dim num_3 As Word 'segundo decimal
Dim dvdo As Word 'dividendo operacion
Dim dvsor As Word 'divisor operacion
'------------------------Variables Programa----------------------------------------
'
'----------------------------ASIGNACIONES------------------------------------------
'
'************************DEFINICION DE PUERTOS*************************************
'--------ASIGNACION DE I/O y valores de inicion de las salidas---------------------
ANSEL = %00000000 'los pin I/O digitales
Define ADC_SAMPLEUS = 0 'el minimo, configuracion del ADC
Define ADC_CLOCK = 5 '16Tad a 8Mhz = 2uSeg, minimo permitido por el micro 1.5uSeg, configuracion ADC
'
'_______________registros afectados por Define ADC_CLOCK y ADCIN________________
'ANSEL = %00010000 'los pin I/O digitales y RA4 analogico
'ADCON0 = %01100000 'Fosc/16 a 8Mhz (ADCON1.ADCS2=1) =2uSeg (minimo 1.uSeg), channel RA4
'ADCON1 = %01000000 'voltage reference (AVdd/AVss) y seleccion de escala division clock/2 ADCON1.ADCS2=1
'
'_______________________________________________________________________________
CMCON = 0x07 'comparador a off
OSCCON = 0x7e 'set intrc To 8mhz, se usara reloj interno a 8Mhz
TRISA = 0x00 'Puerto A como salidas
TRISB = 0x00 'puerto B como salidas
TRISA.4 = 1 'como entrada (RA4, adc)
TRISA.6 = 1 'como entrada (RA6, tecla S1)
TRISA.5 = 1 'como entrada (RA5, tecla S2)
PORTB.3 = 1 'luz lcd a on (RB3)
PORTA.7 = 1 'led amarillo a off
PORTB.0 = 1 'led verde a off
'
'*******************Inicio Programa*********************************************
Lcdinit 'inicializa el lcd sin cursor
WaitMs 1000 'espera 1Seg
Lcdout "16f88_LCD_ADC" 'escribe en el lcd
Lcdcmdout LcdLine2Home 'seleciona la linea dos como proxima para escritura
Lcdout "Pruebas con ADC" 'escribe en el lcd
WaitMs 3000 'espera 3Seg
'
'-------------------Main Programa-----------------------------------------------
main:
Gosub lee_adc 'salto con retorno, rutina de lectura de la entrada ADC
Gosub division_dos_decimales 'salto con retorno, rutina de conversion de valor adc a voltios
Gosub print_lcd 'salto con retorno, rutina que imprime los valores en el lcd
WaitMs 100 'hace una pausa de 100mSeg
Goto main
End
'----------------------FIN DEL MAIN---------------------------------------------
'
'**********************Subrrutinas**********************************************
'--------------------------------------Subrrutina lectura ADC, division y LCD
lee_adc: '_______________________lee la entrada analogica
Adcin 4, num_1 'lee el valor de la entrada analogica y lo carga en num_1
num_2 = 205 'asigna factor de correccion, para 5V
Return
'
'________Rutina division con dos decimales y conversion a voltios
division_dos_decimales:
dvdo = num_1 'asigna dividendo
dvsor = num_2 'asigna divisor
If dvdo > dvsor Then 'calcula la parte entera
num_1 = dvdo / dvsor
dvdo = dvdo Mod dvsor
Else
num_1 = 0
Endif
dvdo = dvdo * 10
If dvdo > dvsor Then 'extrae el primer decimal
num_2 = dvdo / dvsor
dvdo = dvdo Mod dvsor
Else
num_2 = 0
Endif
dvdo = dvdo * 10
If dvdo > dvsor Then 'extrae el segundo decimal
num_3 = dvdo / dvsor
Else
num_3 = 0
Endif
Return
'
'____________________muestra los datos por el display
print_lcd:
Lcdcmdout LcdLine1Clear 'borra la primera linea y cursor al principio
Lcdout "ENTR. ADC ", #num_1, ".", #num_2, #num_3, "V" 'muestra los datos en el lcd
Lcdcmdout LcdLine2Clear 'borra la segunda linea y cursor al principio
Lcdout "Lectura Pin RA4" 'muestra los datos en el lcd
Return
Usando funciones
Este es el programa modificado. Se han utilizado funciones, que estan disponibles en una de las licencias del PIC SIMULATOR IDE.
'********************************** PIC Entrenadora BASIC (PicEBasic)******************************
'NOMBRE: 16F88_LCD_ADC_Funcion_12
'VERSION: 1.2
'MICRO: PIC16f88A
'FECHA/AUTOR: 12/06, 13/07, 24/2/7 - By COS
'Version: 1.0
'DESCRIPCION: MUESTRA EN EL DISPLAY EL VALOR DE LA ENTRADA ANALOGICA CON DOS DECIMALES Y EN VOLTIOS
'Version: 1.1
'se acelera la rutina del display
'se implementa una rutina tipo funcion para la division
'version: 1.2
'simplificado de la rutina de division
'modificacion de la rutina print_lcd, para hacerla compatible con el nuevo formato salida de datos de la division
'********************************************************************************************
Define SIMULATION_WAITMS_VALUE = 1
'-----------------------------Puertos del LCD-----------------------------------------------
Define LCD_BITS = 4 'indicamos que el bus de datos del lcd sera de 4bit
Define LCD_DREG = PORTA 'el bus de datos sera el puerto A
Define LCD_DBIT = 0 'el bus de datos seran los 4 bit menos significativos del puerto A
Define LCD_RSREG = PORTB 'el bit de control RS sera del puerto B
Define LCD_RSBIT = 7 'se usara el RB7 como RS
Define LCD_EREG = PORTB 'el bit de control E sera del puerto B
Define LCD_EBIT = 6 'se usara el RB6 como E
'Define LCD_RWREG = PORTx 'el bit de control RW sera del puerto x(no se usa)
'Define LCD_RWBIT = n 'se usara el Rxn como RW (no se usa)
Define LCD_COMMANDUS = 2000 'Tiempo de espera despues de ejecutar un comand del lcd en uSeg.
Define LCD_DATAUS = 50 'Tiempo de espera despues de enviar un dato al LCD en uSeg.
Define LCD_INITMS = 1 '50 'Tiempo de espera despues de inicializar el Display, solo se ejecuta una vez en mSeg.
'***********************************************************************************************
Define SIMULATION_WAITMS_VALUE = 1
'**********************************DEFINICION DE VARIABLES**************************************
'------------------------------Variables del ADC y Rutina division------------------------------
Dim entero As Word 'parte entera
Dim decimal As Word 'los dos decimales
Dim division As Long 'almacenara el numero con los dos decimales
Dim adc_4 As Word 'contendra el valor de la entrada del ADC
Dim factor_escala As Word 'contiene el factor de correcion para pasar el valor del ADC a voltios, max. 5V
'--------------------------------------Variables Programa----------------------------------------
'------------------------------------------ASIGNACIONES------------------------------------------
entero = 0
decimal = 0
division = 0
adc_4 = 0
factor_escala = 205 'factor de escala maximo 5V,en este caso
'**************************************DEFINICION DE PUERTOS*************************************
'----------------------ASIGNACION DE I/O y valores de inicio de las salidas---------------------
ANSEL = %00000000 'los pin I/O digitales
Define ADC_SAMPLEUS = 0 'el minimo, configuracion del ADC
Define ADC_CLOCK = 5 '16Tad a 8Mhz = 2uSeg, minimo permitido por el micro 1.5uSeg, configuracion ADC
'_______________registros afectados por Define ADC_CLOCK y ADCIN________________
AN SEL = %00010000 'los pin I/O digitales y RA4 analogico
ADCON0 = %01100000 'Fosc/16 a 8Mhz (ADCON1.ADCS2=1) =2uSeg (minimo 1.uSeg), channel RA4
ADCON1 = %01000000 'voltage reference (AVdd/AVss) y seleccion de escala division clock/2 ADCON1.ADCS2=1
'_______________________________________________________________________________
CMCON = 0x07 'comparador a off
OSCCON = 0x7e 'set intrc To 8mhz, se usara reloj interno a 8Mhz
TRISA = 0x00 'Puerto A como salidas
TRISB = 0x00 'puerto B como salidas
TRISA.4 = 1 'como entrada (RA4, adc)
TRISA.6 = 1 'como entrada (RA6, tecla S1)
TRISA.5 = 1 'como entrada (RA5, tecla S2)
PORTB.3 = 1 'luz lcd a on (RB3)
PORTA.7 = 1 'led amarillo a off
PORTB.0 = 1 'led verde a off
'**************************************Inicio Programa*********************************************
Lcdinit 'inicializa el lcd sin cursor
WaitMs 1000 'espera 1Seg
Lcdout "16f88_LCD_ADC" 'escribe en el lcd
Lcdcmdout LcdLine2Home 'seleciona la linea dos como proxima para escritura
Lcdout "Pruebas con ADC" 'escribe en el lcd
WaitMs 3000 'espera 3Seg
Lcdcmdout LcdClear 'borra el display, y cursor al principio de la primera linea
Lcdout "Lectura Pin RA4" 'muestra los datos en el lcd
'--------------------------------------Main Programa-----------------------------------------------
main:
Gosub lee_adc 'salto con retorno, rutina de lectura de la entrada ADC
division = dvsion_2dcmles(adc_4, factor_escala) 'llama a la funcion dvsion_2dcmles, que retorna un long
Gosub print_lcd 'salto con retorno, rutina muestra los datos por el LCD
WaitMs 100 'hace una pausa de 100mSeg
Goto main
End
'--------------------------------------FIN DEL MAIN---------------------------------------------
'**************************************Subrrutinas**********************************************
'--------------------------------------Subrrutina lectura ADC, division y LCD
'_______________________lee la entrada analogica
lee_adc:
Adcin 4, adc_4 'lee el valor de la entrada analogica y lo guarda en adc_4
Return
'
'____________________muestra los datos por el display
print_lcd:
entero = division.HW 'sede el word alto a entero, parte entera
decimal = division.LW 'sede el word bajo a decimal
Lcdcmdout LcdLine2Home 'selecciona la primera linea y cursor al principio
Lcdout "ENTR. ADC ", #entero, "." 'muestra los datos en el lcd
If decimal < 10 Then Lcdout "0" 'asegura que decimal siempre se escribira con dos digitos
Lcdout #decimal, "V " 'muestra los datos en el lcd
Return
'
'____Rutina funcion division con dos decimales
'____Argumentos de entrada: 2 word, dividendo y divisor, salida: variable tipo long
Function dvsion_2dcmles(dvdo As Word, dvsor As Word) As Long
Dim f_entera As Word 'variable local, contendra la parte entera
Dim f_resto As Word 'varable local, contendra el resto
Dim f_decimal As Word 'contendra la parte decimal
f_entera = dvdo / dvsor 'obtengo la division
f_resto = dvdo Mod dvsor 'obtengo el resto
f_decimal = (f_resto * 100) / dvsor 'calculo los 2 decimales, para obtener 3 decimales multiplicar por 1000
dvsion_2dcmles.HW = f_entera 'almacena la parte entera en el word alto
dvsion_2dcmles.LW = f_decimal 'almacena la parte decimal word bajo
'Recuerda que la parte decimal tiene que ser mostrada en el display con plantilla de dos digitos siempre
End Function
End
Video demostrativo
El siguiente video muestra el programa anterior funcionando:
TIMER1 y las Interrupciones del PIC
'***************** Placa Entrenadora **********************************
'NOMBRE:16F88_PicEBasic_LCD_4Bit_No_RW_Timer1
'MICRO: PIC16F88/8Mhz reloj interno
'Uso del LCD con bus de datos a 4Bit y sin pin de RW
'Activacion del Timer1 por rebose cada 1mSeg.
'implementacion de timer (bases de tiempos)por soft
'refresco del display segun la base de tiempos asignada
'cambio de estado del RA7 de forma ciclica (led intermitente)
'**********************************************************************
'-----------------Puertos del LCD--------------------------------------
Define LCD_BITS = 4 'indicamos que el bus de datos del lcd sera de 4bit
Define LCD_DREG = PORTA 'el bus de datos sera el puerto A
Define LCD_DBIT = 0 'el bus de datos seran los 4 bit menos significativos del puerto A
Define LCD_RSREG = PORTB 'el bit de control RS sera del puerto B
Define LCD_RSBIT = 7 'se usara el RB7 como RS
Define LCD_EREG = PORTB 'el bit de control E sera del puerto B
Define LCD_EBIT = 6 'se usara el RB6 como E
'Define LCD_RWREG = PORTA 'el bit de control RW sera del puerto A (si se suprime el compilador no protesta)
'Define LCD_RWBIT = 5 'se usara el RA5 como RW (si se suprime el compilador no protesta)
Define LCD_COMMANDUS = 2000 'Tiempo de espera despues de ejecutar un comand del lcd en uSeg.
Define LCD_DATAUS = 50 'Tiempo de espera despues de enviar un dato al LCD en uSeg.
Define LCD_INITMS = 5 '(50) 'Tiempo de espera despues de inicializar el Display, solo se ejecuta una vez en mSeg.
'------------------------------------------------------------------------
Define SIMULATION_WAITMS_VALUE = 1 'suprime los tiempos de espera Waitms, solo activar esta linea en simulacion
'---------------declaracion de variables---------------------------------
'******************variables de los timer********************************
Dim timer_base As Byte 'tiempo referencia para los timer por soft del programa
Dim timer_base_tiempo As Byte 'contiene el valor del tiempo del timer_base
Dim timer1_ms As Word 'base de tiempos en ms
Dim timer2_ms As Word 'base de tiempos en ms
Dim timer3_ms As Word 'base de tiempos en ms
Dim timer1_100ms As Byte 'base de tiempos msx100
Dim timer2_100ms As Byte 'base de tiempos msx100
Dim timer3_100ms As Byte 'base de tiempos msx100
Dim timer1_ms_tiempo As Word 'contiene el valor del tiempo del timer1_ms
Dim timer2_ms_tiempo As Word 'contiene el valor del tiempo del timer2_ms
Dim timer3_ms_tiempo As Word 'contiene el valor del tiempo del timer3_ms
Dim timer1_100ms_tiempo As Byte 'contiene el valor del tiempo del timer1_100ms
Dim timer2_100ms_tiempo As Byte 'contiene el valor del tiempo del timer2_100ms
Dim timer3_100ms_tiempo As Byte 'contiene el valor del tiempo del timer3_100ms
'-----------------------Variable General---------------------------------
Dim flag As Byte 'se utiliza para controlar el parpadeo de "A"
'---------asignacion de valores a las variables--------------------------
timer_base = 0
timer1_ms = 0
timer2_ms = 0
timer3_ms = 0
timer1_100ms = 0
timer2_100ms = 0
timer3_100ms = 0
timer_base_tiempo = 100 'cuenta 100mSeg
timer1_ms_tiempo = 5 'cuenta 5 mSeg.
timer2_ms_tiempo = 5
timer3_ms_tiempo = 5
timer1_100ms_tiempo = 1 'cuenta 0.1 Seg.
timer2_100ms_tiempo = 1
timer3_100ms_tiempo = 1
flag = 1 'flag=0 permite que se imprima "A", flag=1 permite que se borre el display
'-------------Definicion de puertos--------------------------------------
ANSEL = 0x00 'los pin I/O digitales (no analogicos)
OSCCON = 0x7e 'set intrc To 8mhz, se usara reloj interno a 8Mhz
CMCON = 0x07 'comparador a off
TRISA = 0x00 'Puerto A como salidas
TRISA.5 = 1 'como entrda, no permite ser usada como salida digital
TRISB = 0x00 'puerto B como salidas
'
'-----------Inicializacion de Interrupciones-----------------------------
T1CON.TMR1CS = 0 'asigna el reloj interno al timer1, se incrementa cada ciclo de instruccion
T1CON.T1CKPS0 = 0 'factor del preescales del timer1, 0
T1CON.T1CKPS1 = 0 'factor del preescales del timer1, 0
TMR1H = 0xf8 'carga el registro del contador para que desborde cada 1mSeg, byte alto
TMR1L = 0x30 'carga el registro del contador para que desborde cada 1mSeg, byte bajo
T1CON.TMR1ON = 1 'habilitacion del TMR1, comienza a incrementarce
'PIE1.TMR1IE = 1 'activa las interrupciones del timer1
INTCON.PEIE = 1 'bit de habilitacion de interrupciones de perifericos
Enable 'INTCON.GIE habilita todas las interrupciones globales
'-----------------Inicio------------------------------------------------
Lcdinit 'inicializa el lcd sin cursor
WaitMs 500 'pausa para estabilizar
Lcdout "Listo" 'muestra en el display
WaitMs 500 'pausa de 0,5Seg
timer1_ms_tiempo = 2
timer2_ms_tiempo = 3
PIE1.TMR1IE = 1 'activa las interrupciones del timer1
'------------------------------------rutinas del Programa----------------------
main: 'comienza el programa principal
If timer1_ms >= timer1_ms_tiempo Then 'refresco el display cada timer1_ms_tiempo
If flag = 1 Then Lcdcmdout LcdClear 'borra el display
If flag = 0 Then Lcdout "A" 'escribe el caracter "A" en el display
flag = flag + 1 'incrementa flag, controla el parpadeo de "A"
If flag > 1 Then flag = 0 'hace reset al flag
timer1_ms = 0 'reinicio el timer1_ms
Endif
If timer2_ms >= timer2_ms_tiempo Then 'cambio de estado el pin RA7 cada timer2_ms_tiempo
Toggle RA7
timer2_ms = 0 'reinicio el timer2_ms
Endif
Goto main 'impide que termine el programa principal
End 'es conveniente ponerlo siempre segun el manual
'-----------------------Interrupciones------------------------------------------
On Interrupt 'Comienzan las rutinas de las interrupciones, desactiva las interrupciones
Save System 'Guarda los valores del sistema para poder reemprender el curso normal del programa
If PIR1.TMR1IF = 1 Then 'comprueba que la interrupcion del timer1 es activa
'********************base de tiempos********************************************
timer_base = timer_base + 1
If timer1_ms < timer1_ms_tiempo Then timer1_ms = timer1_ms + 1
If timer2_ms < timer2_ms_tiempo Then timer2_ms = timer2_ms + 1
If timer3_ms < timer3_ms_tiempo Then timer3_ms = timer3_ms + 1
If timer_base >= timer_base_tiempo Then
If timer1_100ms < timer1_100ms_tiempo Then timer1_100ms = timer1_100ms + 1
If timer2_100ms < timer2_100ms_tiempo Then timer2_100ms = timer2_100ms + 1
If timer3_100ms < timer3_100ms_tiempo Then timer3_100ms = timer3_100ms + 1
timer_base = 0
Endif
'*************************fin base de tiempos**********************************
Endif
TMR1H = 0xf8 'recarga el contador del timer1 para que desborde pasado 1mSeg, byte alto
TMR1L = 0x30 'recarga el contador del timer1 para que desborde pasado 1mSeg, byte bajo
PIR1.TMR1IF = 0 'borra el flag de salto del tmr1
Resume 'activa las interrupciones y retorna al curso normal del programa antes del salto
'
End