Este es un antiguo ejemplo para controlar la iluminacion del LCD, empleando las bases de tiempos.
Ahora lo he modificado para que haga la misma funcion pero empleando el modulo CCP.
pasamos de tener 20 puntos de resolucion a tener 1024 puntos, contando el cero, utilizando el modulo interno del pic CCP.
la frecuencia que genera el modulo a 8Mhz de reloj y con la configuracion correspondiente es de 488Hz, que corresponde tambien con la realidad segun me indica mi frecuencimetro.
La puesta en marcha de este modulo desde el Basic es realmente sencilla, tan solo se inicializa el modulo con la declaracion "PWMON 1, 1", el primer parametro es el modulo a controlar, y el segundo nos indica el modo de funcionamiento que lo podemos ver en la tabla del manual. y con la segunda declaracion "PWMDUTY 1, duty" controlamos duty de la salida del modulo.
El programa:
'***************** Placa Entrenadora (PIC EBadic) ***************************************
'NOMBRE: 16F88_Pic_EBasic_LCD_Timer1_ADC_PWM_12
'MICRO: PIC16F88/8Mhz reloj interno
'Fecha/Autor: 1/07, 6/07 By COS, PSI v7.41
'Version: 1.2
'se elimina el control del PWM por bases de tiempos y se controla mediante el modulo CCP1
'Version: 1.1
'Se cambian los Lcdcmdout LcdClear por Lcdcmdout LcdLinexHome en la subrutina del display, print_lcd
'este cambio acelera la escritura en el display
'Se convierte en subrutina el calculo del PWM segun el valor leido del ADC, calculo_pwm
'Se cambian el orden de los saltos en las lineas acotadas por el timer3_100ms, en el main, esto hace que el valor
'leido de la entrada analogica se actualice con los valores del PWM en el mismo ciclo
'Version: 1.0
'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
'lectura de entrada analogica y conversion a voltaje con dos decimales
'Implementacion de PWM con periodo de 20mseg. para el control de la luz del lcd por medio de la entrada adc
'*********************************************************************************************
Define CONF_WORD = 0x2f50 'Configuración de bits (fuses)
Define CONF_WORD_2 = 0x3ffc 'Configuración de bits (fuses)
Define CLOCK_FREQUENCY = 8 'Frecuencia del reloj en Mhz
'Define SIMULATION_WAITMS_VALUE = 1 'Hace que se ignoren los tiempos de los WaitMs
'Puertos del LCD-------------------------------------
Define LCD_BITS = 4 'Indicamos que el bus de datos del lcd sera de 4bit
Define LCD_DREG = PORTA 'Bus de datos sera el puerto A
Define LCD_DBIT = 0 'Bus de datos seran los 4 bit menos significativos del puerto A
Define LCD_RSREG = PORTB 'Bit de control RS sera del puerto B
Define LCD_RSBIT = 7 'RB7 como RS
Define LCD_EREG = PORTB 'Bit de control E sera del puerto B
Define LCD_EBIT = 6 'RB6 como E
Define LCD_COMMANDUS = 2000 'Tiempo de espera despues de ejecutar un comando 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.
'------------------------------------Definicion de puertos------------------------------------------
ANSEL = 0x00 'los pin I/O digitales
Define ADC_SAMPLEUS = 10 '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 (RA7), negado
PORTB.0 = 1 'led verde a off (RB0), negado
'------------------------------------Inicializacion del TMR1 ---------------------------------
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
'------------------------------------------------------------------------------------------------------
Lcdinit 'inicializa el lcd sin cursor
'Asignación de nombres --------------------------------------------------------------------
Symbol led_amarillo = PORTA.7 'led amarillo
Symbol led_verde = PORTB.0 'led verde
Symbol luz_lcd = PORTB.3 'iluminacion del lcd
'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
'-------------------------------Variables del ADC y Rutina division-------------------
Dim adc_4 As Word 'contiene el valor de la entrada ADC
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 generales-----------------------------------------
Dim flag_1 As Byte 'determina si la luz del lcd estara a on o a off
Dim duty As Word 'contiene el tiempo a on de la iluminacion del lcd a 10bit
Dim resto_periodo As Word 'contine el tiempo a off de la iluminacion del lcd
'-------------------------------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 = 1 '100 'cuenta 100mSeg
timer1_ms_tiempo = 1 'cuenta 1mSeg.
timer2_ms_tiempo = 19 'cuenta 19mSeg
timer3_ms_tiempo = 5 'cuenta 5mSeg
timer1_100ms_tiempo = 10 'cuenta 1 Seg.
timer2_100ms_tiempo = 20 'temporiza 2Seg
timer3_100ms_tiempo = 1 'temporiza 0.1seg
flag_1 = 0
adc_4 = 0
resto_periodo = 0
duty = 0
'-------------------------------------------------------------------------------------------------------------
Enable 'INTCON.GIE habilita todas las interrupciones globales
WaitMs 1000 'espera 1Seg, las interrupciones alargan este tiempo
Lcdout "LCD_Tmr1_ADC_PWM" 'escribe en el lcd
Lcdcmdout LcdLine2Home 'seleciona la linea dos como proxima para escritura
Lcdout "Pruebas con CCP" 'escribe en el lcd
WaitMs 3000 'espera 3Seg, las iterrupciones hacen este tiempo mas largo
Lcdcmdout LcdClear 'borra el display
PWMon 1, 1 'activa el modulo CCP1, a 10bit, 488Hz y duty cycle 0
'------------------------------------Rutinas Principal----------------------
main: 'comienza el programa principal
If timer1_100ms >= timer1_100ms_tiempo Then 'cambio de estado el pin RA7 cada timer1_100ms_tiempo
Toggle led_amarillo 'invierte el valor del pin
timer1_100ms = 0 'reinicio el timer1_100ms
Endif
If timer2_100ms >= timer2_100ms_tiempo Then 'cambio de estado el pin RB0 cada timer2_100ms_tiempo
Toggle led_verde 'invierte el valor del pin
timer2_100ms = 0 'reinicio el timer2_100ms
Endif
If timer3_100ms >= timer3_100ms_tiempo Then 'permite que se ejecute las rutinas solo una vez cada timer3_100ms_tiempo
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 calculo_pwm 'salto con retorno, rutina de calculo de tiempos del PWM
Gosub print_lcd 'salto con retorno, rutina que imprime los valores en el lcd
timer3_100ms = 0 'reset a la base de tiempos
Endif
PWMduty 1, duty 'mantiene el duty cycle del modulo ccp
Goto main 'impide que termine el programa principal
End 'Fin main
'--------------------------------------Subrutina lectura ADC, division y LCD
lee_adc: '_______________________lee la entrada analogica
Adcin 4, adc_4 'lee el valor de la entrada analogica y lo carga en adc_4
num_1 = adc_4 'sede el valor del adc para ser procesado
num_2 = 205 'asigna factor de correccion, para 5V
Return
division_dos_decimales: '________Rutina division con dos decimales y conversion a voltios
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
print_lcd: '____________________muestra los datos por el display
Lcdcmdout LcdLine1Home 'cursor al principio, de la primera linea
Lcdout "ADC ", #adc_4, " ", #num_1, ".", #num_2, #num_3, "V", " " 'muestra los datos en el lcd
Lcdcmdout LcdLine2Home 'cursor al principio de la segunda linea
Lcdout "On ", #duty, " Off ", #resto_periodo, " " 'muestra los datos en el lcd
Return
calculo_pwm: '__________control de los tiempos del PWM segun el valor de adc_4
duty = adc_4 'controla el tiempo del PWM en estado alto
resto_periodo = 1023 - duty 'nos indica el tiempo del PWM en estado bajo
'___________________________________________________
Return
'--------------------------------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
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
'___base de tiempos
timer_base = timer_base + 1 'contador general
If timer1_ms < timer1_ms_tiempo Then timer1_ms = timer1_ms + 1 'contador
If timer2_ms < timer2_ms_tiempo Then timer2_ms = timer2_ms + 1 'contador
If timer3_ms < timer3_ms_tiempo Then timer3_ms = timer3_ms + 1 'contador
If timer_base >= timer_base_tiempo Then 'limita el tiempo de ejecucion, cada timer_base_tiempo
If timer1_100ms < timer1_100ms_tiempo Then timer1_100ms = timer1_100ms + 1 'contador
If timer2_100ms < timer2_100ms_tiempo Then timer2_100ms = timer2_100ms + 1 'contador
If timer3_100ms < timer3_100ms_tiempo Then timer3_100ms = timer3_100ms + 1 'contador
timer_base = 0 'reset a la base de tiempos
Endif
'__fin base de tiempos
PIR1.TMR1IF = 0 'borra el flag de salto del tmr1
Endif
Resume 'activa las interrupciones y retorna al curso normal del programa antes del salto