Define CONF_WORD = 0x2f10
Define CONF_WORD_2 = 0x3ffc
Define CLOCK_FREQUENCY = 8
'***************** Placa Entrenadora (PIC EBadic) ***************************************
'NOMBRE:16F88_Pic_EBasic_LCD_Timer1_ADC_PWM_Servo_12
'Descripcion: Control de un servomotor (Futaba S3003) usando el ADC, Timer1, Interrupciones
'Micro: pic16f88 / 8mhz reloj interno
'version 1.2
'añado base de tiempos, 20 mSeg.
'suprimo "flag2_pwm"
'Version 11
'se fusiona la rutina de division con decimales
'para mostrar el tiempo del duty cycle en pantalla, minimo 0.43mSeg. y maximo 2.26mSeg.
'modificacion del formato de salida de la imformacion por el lcd
'Version: 1.0
'Fecha/Autor: 4/07, By COS
'Uso del LCD con bus de datos a 4Bit y sin pin de RW
'uso del timer1 para controlar el PWM, de periodo 20mSeg.
'lectura de entrada analogica y conversion a tiempo
'conversion de tiempo a valores a cargar en el timer1
'************************************************************************************************
'-------------------------------------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 = 500 '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 = 5 '50 'Tiempo de espera despues de inicializar el Display, solo se ejecuta una vez en mSeg.
'****************************************************************************************************
Define SIMULATION_WAITMS_VALUE = 1 'Ignora los valores de Waitms
'--------------------------------------Reasignacion de nombres---------------------------------------
Symbol led_amarillo = PORTA.7 'led amarillo
Symbol led_verde = PORTB.0 'led verde
Symbol luz_lcd = PORTB.3 'retroiluminacion del lcd
'------------------------------------declaracion de variables---------------------------------------
'-------------------------------Bases de tiempos,variables--------------------------------------
Dim timer1_20ms As Word 'base de tiempos, 20mSeg
Dim timer1_20ms_tiempo As Word 'tiempo a temporizar por la base de tiempos * 20mSeg
'-------------------------------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 factor_escala As Word 'situa la parte entera del numero
Dim reg_timer1 As Word 'valor maximo que puede contener el registro del TMR1
Dim tiempo_ms As Word 'tiempo a on de la señal de control del servo en mSeg.
Dim aux_adc_4 As Word 'auxiliar
Dim adc_4 As Word 'contiene el valor de la entrada ADC
'----------------------------------------variables calculo y control PWM-----------------------------
Dim pwm As Word 'variable de paso
Dim pwm_nop As Word 'variable de paso
Dim aux_pwm As Long 'calculo del tiempo a ON, de la señal de control
Dim aux_pwm_nop As Long 'calculo del tiempo a OFF, de la señal de cotrol
Dim timer_pwm As Word 'valor del tiempo a on, para ser interpretado
Dim timer_pwm_nop As Word 'valor del tiempo a off, para ser interpretado
Dim flag1_pwm As Byte 'variable que determina si ON o a OFF de la señal de control
'------------------------------------asignacion de valores a las variables--------------------------
pwm = 62535
pwm_nop = 28535
aux_pwm = 62535
flag1_pwm = 1
entero = 0
decimal = 0
division = 0
adc_4 = 0
reg_timer1 = 65535 'maximo valor registro de 16 bit del TMR1
factor_escala = 100 'factor de escala para dos decimal
timer1_20ms_tiempo = 2 '40 mSeg.
timer1_20ms = timer1_20ms_tiempo
'------------------------------------Definicion de puertos------------------------------------------
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
OSCTUNE = 2 'factor de correcion del reloj
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, negado
PORTB.0 = 1 'led verde a off, negado
'------------------------------------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
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 1000 'espera 1Seg
Lcdout "LCD_Tmr1_ADC_PWM" 'escribe en el lcd
Lcdcmdout LcdLine2Home 'seleciona la linea dos como proxima para escritura
Lcdout "Servo S3003" 'escribe en el lcd
WaitMs 3000 'espera 3Seg
Lcdcmdout LcdClear 'borra el display
PIE1.TMR1IE = 1 'activa las interrupciones del timer1
'------------------------------------rutinas del Programa----------------------
main: 'comienza el programa principal
If timer1_20ms >= timer1_20ms_tiempo Then
Gosub lee_adc 'salto con retorno a la rutina de lectura del ADC
aux_pwm = ((adc_4 + 240) * 250) / (1023 + 370) 'tiempo a ON de la señal de control del servo
'240 y 370 fijan los valores minimo y valores maximos del duty cycle
aux_pwm_nop = 2000 - aux_pwm 'calculo del tiempo de la señal de control a OFF
aux_pwm_nop = 65535 - ((aux_pwm_nop * 100) / 5) 'valor a cargar en el timer1, OFF
aux_pwm = 65535 - ((aux_pwm * 100) / 5) 'valor a cargar en el timer1, ON
pwm = aux_pwm 'se cambia de long a word, para acelerar la rutina de interrupciones
pwm_nop = aux_pwm_nop 'se cambia de long a word, para acelerar la rutina de interrupciones
Gosub print_lcd 'salto con retorno a la rutina que muestra los dato por el display
tiempo_ms = ((reg_timer1 - pwm) * 5) / 100 'calculo en mSeg.
division = dvsion_dcmles(tiempo_ms, factor_escala) 'llama a la funcion dvsion_dcmles,
'que retorna un Long
Gosub formato_decimales 'extrae e imprime con formato decimal
timer1_20ms = 0
Endif
Goto main 'impide que termine el programa principal
End 'es conveniente ponerlo siempre segun el manual
formato_decimales: '____________________da formato a los decimales y los saca por el lcd
entero = division.HW 'sede el word alto a entero, parte entera
decimal = division.LW 'sede el byte alto del word bajo a decimal_1
Lcdout #entero, "." 'muestra los datos en el lcd
If decimal < 10 Then Lcdout "0" 'mantiene la plantilla de los decimales, quitar para 1 decimal
Lcdout #decimal, " " 'muestra los datos en el lcd
Return
'--------------------------------------Subrrutina lectura ADC
lee_adc: '_______________________lee la entrada analogica
Adcin 4, adc_4 'lee el valor de la entrada analogica y lo carga en adc_4
Return
print_lcd: '____________________muestra los datos por el display
Lcdcmdout LcdLine1Home 'cursor al principio
Lcdout "ADC--TMR1--mSeg." 'magnitudes
Lcdcmdout LcdLine2Home 'selecciona la linea dos del lcd y cursor a inicio
If adc_4 < 1000 Then Lcdout "0" 'para mantener la plantilla
If adc_4 < 100 Then Lcdout "0" 'para mantener la plantilla
If adc_4 < 10 Then Lcdout "0" 'para mantener la plantilla de salida
Lcdout #adc_4, " ", #pwm, " " 'muestra los datos en el lcd
Return
'________Argumentos de entrada dos variables tipo word, dividendo y divisor,
'________argumento de salida una variable tipo Long
Function dvsion_dcmles(dvdo As Word, dvsor As Word) As Long '_Rutina funcion division con decimales
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 Long '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 'Multiplicar 1xx seguido de tantos ceros como decimales
dvsion_dcmles.HW = f_entera 'almacena la parte entera en el word alto
dvsion_dcmles.LW = f_decimal 'almacena la parte decimal word bajo
'Recuerda que la parte decimal tiene que ser mostrada en el display con plantilla
'especial en este caso de dos digitos
End Function
'--------------------------------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
'___________Rutina generadora del PWM, para la entrada de control del servomotor
If flag1_pwm = 1 Then 'controla el tiempo de la señal del servo a OFF
RB4 = 0 'salida del servo a OFF
TMR1H = timer_pwm_nop.HB 'recarga el contador del timer1 para que desborde, tiempo a off
TMR1L = timer_pwm_nop.LB 'recarga el contador del timer1 para que desborde, tiempo a off
flag1_pwm = 0 'permite la alternancia entre señal del servo a ON o a OFF
timer_pwm = pwm 'recarga la rutina con los nuevos valores del potenciometro
timer_pwm_nop = pwm_nop 'recarga la rutina con los nuevos valores del potenciometro
If timer1_20ms < timer1_20ms_tiempo Then timer1_20ms = timer1_20ms + 1
Else
RB4 = 1 'salida de la señal de contol del servo a ON
TMR1H = timer_pwm.HB 'recarga el contador del timer1 para que desborde, tiempo a on
TMR1L = timer_pwm.LB 'recarga el contador del timer1 para que desborde, tiempo a on
flag1_pwm = 1 'permite la alternancia entre señal del servo a ON o a OFF
Endif
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