'********************************************************************************************************
'Include "_FuncionesPic16F88.bas" ***************************************************************
'By COS, 08/12/2016 *******************************************************************************
'09/2016, 08/16, 06/16, 09/15, 04/15, 12/14, 10/14, 09/14, 07/14, 06/14, 12/13 **************
'PSI v7.41 ********************************************************************************************
'********************************************************************************************************
'********************************************************************************************************
'INICIALIZACIÓN DE PUNTEROS
'_Address()
'******************************************************************************
'_Address(): Devuelve la dirección de memoria del primer elemento de un vector.
'******************************************************************************
'******************************************************************************
'RESISTENCIAS DE PULLUP PUERTO B:
'_Set_PullUp(Modo)
	'Modo:
		'_PullUp_On, Modo a On
		'_PullUp_Off, Modo a Off
'***********************************************************************
'***********************************************************************
'Pulsación de teclas:
'_Button(_Port As Byte, _Pin As Byte, _Time As Byte, _Activestate As Bit, _Delay As Byte)
	'_Port: direccion del puerto elegido.
	'_Pin: pin del puerto elegido (0 a 7, el pin tiene que ser configurado como entrada digital).
	'_Time: tiempo que la tecla tiene que estar pulsada en mSeg. (0 a 255).
	'_ActiveState: estado que tiene que tener la tecla para ser validada (0 o 1).
	'_Button: devuelve 0 si no hay tecla pulsada y 255 si lo esta.
	'_Delay: si la tecla fue validada y sigue pulsada genera un retraso en mSeg. (0 a 255)..
'***********************************************************************
'***********************************************************************
'INTERRUPCIONES EXTERIORES POR RB0/INT Y RB7:4
'_IntIf: flag de aviso pulso (flanco) interrup. ext. RB0
'_RbIf: flag de aviso interrup. por cambio en RB7:4
'_Set_Int_Ext(Flanco): flanco de disparo de las int. ext. RB0/INT
	'Flanco:
		'_Int_Ext_L_to_H: Interrupción ext. por flanco bajo a alto
		'_Int_Ext_H_to_L: Interrupción ext. por flanco alto a bajo
'***********************************************************************
'***********************************************************************
'FUNCIONES PARA LA GESTION DE LAS INTERRUPCIONES:
'_enable_interrupts(_global), _disable_interrupts(_global)
'***********************************************************************
'_enable_interrupts(_global): Activa interrup. globales y perifericos
'_enable_interrupts(_int_rda): Activa interrupción Usart Rx
'_enable_interrupts(_int_timer0): Activa interrup. TIMER0
'_enable_interrupts(_int_timer1): Activa interrup. TIMER1
'_enable_interrupts(_int_timer2): Activa interrup. TIMER2
'_enable_interrupts(_int_ext) Interrupción Externa por pulso o flanco en RB0/INT
'_enable_interrupts(_int_rb) Interrupción Externa por cambio de estado en los pin RB7:4
'_diable_interrupts(_global): Desactiva interrup. globales y perifericos
'_disable_interrupts(_int_rda): Desactiva interrupción Usart Rx
'_disable_interrupts(_int_timer0): Desactiva interrup. TIMER0
'_disable_interrupts(_int_timer1): Desactiva interrup. TIMER1
'_disable_interrupts(_int_timer2): Desactiva interrup. TIMER2
'_disable_interrupts(_int_ext) Interrupción Externa por pulso o flanco en RB0/INT
'_disable_interrupts(_int_rb) Interrupción Externa por cambio de estado en los pin RB7:4
'***********************************************************************
'***********************************************************************
'USART:
'_clear_error_usart(), _usartif, _error_usart
'***********************************************************************
'_clear_error_usart(): Desbloquea el módulo usart en modo Rx
'_usartif: equivalente al bit de aviso de datos en bufer
'_error_usart: equivale al bit de aviso de bloqueo de la usart en modo Rx
'***********************************************************************
'***********************************************************************
'TIMER0:
'***********************************************************************
'_Set_Timer0(Byte), _Clear_timer0(), _Get_timer0(), _tmr0if
'_SetUp_Timer0().
'***********************************************************************
'_setup_timer0(_mode As Byte, _pdiv As Byte): Configura el Timer0
	'_mode:
		'_tmr0_internal: 'Internal clock (Fosc/4)
		'_tmr0_ext_l_to_h: 'External oscillator
		'_tmr0_ext_h_to_l: 'External oscillator
	'_pdiv: 'Preescaler
		'_tmr0_div2: Divide por 2
		'_tmr0_div4: Divide por 4
		'_tmr0_div8: Divide por 8
		'_tmr0_div16: Divide por 16
		'_tmr0_div32: Divide por 32
		'_tmr0_div64: Divide por 64
		'_tmr0_div128: Divide por 128
		'_tmr0_div256: Divide por 256
'_Set_Timer0(Byte): Recarga el contador del TIMER0
'_Get_Timer0(): Lee el contador del TIMER0
'_Clear_Timer0(): Borra el contador del TIMER0
'_Tmr0If: Etiquea el flag de desborde TIMER0
'***********************************************************************
'***********************************************************************
'TIMER2:
'***********************************************************************
'_setup_timer2(Prescaler, PR2, Postscaler), _tmr2if, _timer2(on/off)
'***********************************************************************
'_setup_timer2(_prediv As Byte, _periodo As Byte, _posdiv As Byte)
	'_Prediv: 'Preescaler
		'_tmr2_disable: Para el Tmr2
		'_tmr2_div1: Divide por 1
		'_tmr2_div4: Divide por 4
		'_tmr2_div16: Divide por 16
	'_Periodo: Carga el registro PR2
	'Formula:
		'PR2 = ((Tiempo Deseado en uSeg. / (4/fosd Mhz)) / (Prescaler * Postscaler)) -1
		'Cuando contador TMR2 = PR2 => TMR2 = 0 y _tmr2if = 1.
	'_posdiv: Postscaler, Valores comprendidos entre 0 y 16
'_set_timer2(Byte): Recarga el contador del TIMER2 (no se usa)
'_get_timer2(): Lee el contador del TIMER2 (Byte) (no se usa)
'_clear_timer2(): Borra el contador del TIMER2 (no se usa)
'_tmr2if: Etiquea el flag de desborde TIMER2
'_timer2(): (_on), (_off), activa o para el timer2
'***********************************************************************
'***********************************************************************
'TIMER1:
'***********************************************************************
'_set_timer1(Word), _clear_timer1(), _get_timer1(), _tmr1if
'_setup_timer1(), _timer1().
'***********************************************************************
'_setup_timer1(_mode As Byte, _pdiv As Byte): Configura el Timer1
	'_mode:
		'_tmr1_osctmr1: 'Oscillator TIMER1, pin T1OSI y T1OSO
		'_tmr1_internal: 'Internal clock (Fosc/4)
		'_tmr1_external: 'External oscillator
		'_tmr1_external_sysnc: 'Synchronize external clock input
	'_pdiv: 'Preescaler
		'_tmr1_div1: Divide por 1
		'_tmr1_div2: Divide por 2
		'_tmr1_div4: Divide por 4
		'_tmr1_div8: Divide por 8
'_set_timer1(word): Recarga el contador del TIMER1
'_get_timer1(): Lee el contador del TIMER1
'_clear_timer1(): Borra el contador del TIMER1
'_tmr1if: Etiquea el flag de desborde TIMER1
'_timer1(): (_on), (_off), activa o para el timer1
'***********************************************************************************
'***********************************************************************************
'GESTIÓN MODULO CCP1:
'_setup_ccp1(), _set_pwm1_duty()
'***********************************************************************************
'Call _Setup_CCP1(modo)
	'Modo:
		'_OFF modulo CCP apagado
		'_ON modulo CCP trabajando como PWM encendido
'Call _Set_Pwm1_Duty(Duty)
	'Duty = duración del pulso alto con respecto al pulso bajo.
'************************************************************************************
'************************************************************************************
'WATCHDOG (WDT):
'Funciones para el control del módulo WDT
'_SeUp_WDT(_mode, _prescaler2)'Configura los prescaler del WDT
'_Set_WDT_On()'Activa el módulo
'_Set_WDT_Off()'Para el módulo
'_Restart_WDT()'Reinicia el contador del WDT
'************************************************************************************
'************************************************************************************
'OSCCON: OSCILLATOR CONTROL REGISTER:
'Call _Setup_Oscillator(_Modo)
	'_Modo:
		'_Osc_31250hz
		'_Osc_125Khz
		'_Osc_250Khz
		'_Osc_500Khz
		'_Osc_1Mhz
		'_Osc_2Mhz
		'_Osc_4Mhz
		'_Osc_8Mhz
'Call _Setup_Oscillator_Mode_Select_Bit(_Selec)
	'_Selec:
		'_Oscillator_mode_define_by_FOSC
		'_T1OSC_System_Clock
		'_Internal_RC_System_Clock
'Call _Setup_Oscillator_Finetune(_Finetune)
	'Finetune:
		'Maximum frequency = 011111
		'......
		'000001 = Center +1
		'Center frequency = 000000
		'111111 = Center -1
		'......
		'Minimum frequency = 100000
'************************************************************************************
'************************************************************************************
'Gestion Usart
'***********************************************************************************
Symbol _usartif = PIR1.RCIF  'Asigna nombre al flag interrupción de la usart
Symbol _error_usart = RCSTA.OERR  'Asigna nombre al flag error buffer usart
'Gestiona el bloqueo de la Usart en modo Rx
Proc _clear_error_usart()
	Dim _papelera As Byte
	If RCSTA.OERR = True Then  'Entraron más datos de los que se extrajeron (bloqueada)
		RCSTA.CREN = 0  'Disable, continua recepción
		_papelera = RCREG  'Vacía buffer usart
		_papelera = RCREG
		RCSTA.CREN = 1  'Enable, Continuous Receive Enable bit*/
	Endif
End Proc                                          
'***************************************************
'***************************************************
'MODULO CCP1
'***************************************************
Const _on = 1
Const _off = 0
'Selecciona el modo de trabajo del modulo CCP1
Proc _setup_ccp1(_mode As Byte)
	If _mode = 0 Then  'CCP1 a Off
		CCP1CON.CCP1M0 = 0
		CCP1CON.CCP1M1 = 0
		CCP1CON.CCP1M2 = 0
		CCP1CON.CCP1M3 = 0
	Endif

	If _mode = 1 Then  'CCP1 en modo Pwm
		CCP1CON.CCP1M0 = 0
		CCP1CON.CCP1M1 = 0
		CCP1CON.CCP1M2 = 1
		CCP1CON.CCP1M3 = 1
	Endif
End Proc                                          
'Carga el duty cycle
Proc _set_pwm1_duty(_duty As Word)
	CCP1CON.CCP1Y = _duty.0
	CCP1CON.CCP1X = _duty.1
	CCPR1L = ShiftRight(_duty, 2)
End Proc                                          
'***************************************************
'***************************************************
'TIMER2
'***************************************************
'Etiquetas y constantes
Symbol _tmr2if = PIR1.TMR2IF  'Etiquea el flag de desbordamiento Timer2
'ConFigura el TIMER2
'Prescale Select Bits (T2CON: T2CKPS1, T2CKPS0)
Const _tmr2_disable = 0x00  'Timer2 a Off
Const _tmr2_div1 = 0  'Prescale Select bits
Const _tmr2_div4 = 1  'Prescale Select bits
Const _tmr2_div16 = 2  'Prescale Select bits
'Postscale Select Bits (T2CON: TOUTPS3, TOUTPS2, TOUTPS1, TOUTPS0)
'Postscale de 0 a 16.
'prediv: (prescaler) _tmr2_disable, _tmr2_div1, _tmr2_div4, _tmr2_div16
'Period: PR2 = ((Tiempo Deseado uSeg / (4/Osc Mhz)) / (Prescaler * Postscaler)) -1
	'Cuando el contador del Tmr2 = PR2 => PIR1.TMR2IF = 1 => Tmr2 = 0 y de nuevo.
	'Tmr2 es un contador de 8bits y PR2 es un registro de 8bits
'_posdiv: (postscaler) valores comprendidos entre 0 1 16.
Proc _setup_timer2(_mode As Byte, _periodo As Byte, _posdiv As Byte)
	T2CON = 0x00  'Timer2 a Off
	T2CON.T2CKPS0 = _mode.0
	T2CON.T2CKPS1 = _mode.1
	PR2 = _periodo  'Desborde TMR2 (TMR2 = PR2)
	T2CON.TOUTPS0 = _posdiv.0  'Asigna postscaler
	T2CON.TOUTPS1 = _posdiv.1  'Asigna postscaler
	T2CON.TOUTPS2 = _posdiv.2  'Asigna postscaler
	T2CON.TOUTPS3 = _posdiv.3  'Asigna postscaler
End Proc                                          
'Borra el registro del TMR2
'Proc _clear_timer2()
		'TMR2 = 0  'Borra el byte
		'PIR1.TMR2IF = 0  'Flash dosborde a cero
'End Proc
'Recarga el registro del TMR
'Proc _set_timer2(_reg As Byte)
		'TMR2 = _reg  'Recarga el byte
		'PIR1.TMR2IF = 0  'Flash dosborde a cero
'End Proc
'Devuelve el registro del Tmr2
'Function _get_timer2() As Byte
		'_get_timer2 = TMR2  'Carga el byte
		'PIR1.TMR2IF = 0  'Flash dosborde a cero
'End Function
'Activa o para el modulo Timer2
Proc _timer2(_on_off As Bit)
	T2CON.TMR2ON = _on_off
End Proc                                          
'***************************************************
'***************************************************
'TIMER1
'***************************************************
'Etiquetas y constantes
Symbol _tmr1if = PIR1.TMR1IF  'Etiquea el flag de desbordamiento Timer1
'Modo de oscilador
Const _tmr1_disable = %00000000  'Timer1 a off
Const _tmr1_internal = %00000000  'Internal clock (Fosc/4)
Const _tmr1_external = %00000110  'External oscillator
Const _tmr1_external_sysnc = %00000010  'Synchronize external clock input
Const _tmr1_osctmr1 = %00001000  'Oscillator TIMER1, pin T1OSI y T1OSO
'Preescale Select Bits (T1CON: T1CKPS1, T1CKPS0)
Const _tmr1_div1 = 0  'Divide por 1
Const _tmr1_div2 = 1  'Divide por 2
Const _tmr1_div4 = 2  'Divide por 4
Const _tmr1_div8 = 3  'Divide por 8
'ConFigura el TIMER1
Proc _setup_timer1(_mode As Byte, _pdiv As Byte)
	T1CON = _mode  'Asigna el tipo de oscilador
	T1CON.T1CKPS1 = _pdiv.1  'Asigna el divisor
	T1CON.T1CKPS0 = _pdiv.0
	T1CON.TMR1ON = 1  'Activa el modulo
End Proc                                          
'Borra el registro del TMR
Proc _clear_timer1()
		TMR1H = 0  'Borra el byte alto
		TMR1L = 0  'Borra el byte bajo
		PIR1.TMR1IF = 0  'Flash dosborde a cero
End Proc                                          
'Recarga el registro del TMR
Proc _set_timer1(_reg As Word)
		TMR1H = _reg.HB  'Recarga el byte alto
		TMR1L = _reg.LB  'Recarga el byte bajo
		PIR1.TMR1IF = 0  'Flash dosborde a cero
End Proc                                          
'Devuelve el registro del TMR
Function _get_timer1() As Word
		_get_timer1.HB = TMR1H  'Carga el byte alto
		_get_timer1.LB = TMR1L  'Carga el byte bajo
End Function                                      
'Activa o para el contador del timer1
Proc _timer1(_on_off As Bit)
	T1CON.TMR1ON = _on_off
End Proc                                          
'***************************************************
'***************************************************
'TIMER0
'***************************************************
'Etiquetas y constantes
Symbol _tmr0if = INTCON.TMR0IF  'Flash dosborde
'Modo de oscilador
Const _tmr0_disable = %00000000  'Timer0 a Off
Const _tmr0_internal = %00000000  'Internal clock (Fosc/4)
Const _tmr0_ext_l_to_h = %00100000  'External oscillator
Const _tmr0_ext_h_to_l = %00110000  'Synchronize external clock input
'RTCC_EXT_L_TO_H or RTCC_EXT_H_TO_L
'Preescale Select Bits (OPTION_REG: PS2, PS1, PS0)
Const _tmr0_div2 = 0  'Divide por 2
Const _tmr0_div4 = 1  'Divide por 4
Const _tmr0_div8 = 2  'Divide por 8
Const _tmr0_div16 = 3  'Divide por 16
Const _tmr0_div32 = 4  'Divide por 32
Const _tmr0_div64 = 5  'Divide por 64
Const _tmr0_div128 = 6  'Divide por 128
Const _tmr0_div256 = 7  'Divide por 256
'ConFigura el TIMER1
Proc _setup_timer0(_mode As Byte, _pdiv As Byte)
	OPTION_REG.T0CS = _mode.5  'Asigna el tipo de oscilador
	OPTION_REG.T0SE = _mode.4  'Asigna la transición para el incremento
	OPTION_REG.PSA = 0  'Prescaler es asignado al TMR0
	OPTION_REG.PS2 = _pdiv.2  'bits de la seleccion del factor de division
	OPTION_REG.PS1 = _pdiv.1  'bits de la seleccion del factor de division
	OPTION_REG.PS0 = _pdiv.0  'bits de la seleccion del factor de division
End Proc                                          
'Borra el registro del TMR
Proc _clear_timer0()
	TMR0 = 0  'Borra el contador del TMR0
	INTCON.TMR0IF = 0  'Flash dosborde a cero
End Proc                                          
'Recarga el registro del TMR
Proc _set_timer0(_reg As Byte)
	TMR0 = _reg  'Asigna valor al contador del TMR0
	INTCON.TMR0IF = 0  'Flash dosborde a cero
End Proc                                          
'Devuelve el registro del TMR
Function _get_timer0() As Byte
	_get_timer0 = TMR0  'Asigna el valor del contador del TMR0
End Function                                      
'***************************************************
'***************************************************
'INTERRUPCIONES:
'***************************************************
Const _global = 1  'Interrupciones globales y perifericos
Const _int_rda = 2  'Interrupción Usart Rx
Const _int_timer0 = 0  'Interrupción TIMER0
Const _int_timer1 = 3  'Interrupción TIMER1
Const _int_timer2 = 4  'Interrupción TIMER2
Const _int_ext = 5  'Interrupción Externa por pulso o flanco en RB0/INT
Const _int_rb = 6  'Interrupción Externa por cambio de estado en los pin RB7:4
'Activa interrupciones seleccionadas
Proc _enable_interrupts(_int As Byte)
	If _int = 1 Then INTCON.PEIE = 1  'Bit habilita interrupciones perifericos
	If _int = 1 Then Enable  'INTCON.GIE habilita las interrupciones globales
	If _int = 2 Then PIE1.RCIE = 1  'Activa la interrup. de la usart en modo rx*/
	If _int = 0 Then INTCON.TMR0IE = 1  'Activa la interrup. TIMER0
	If _int = 3 Then PIE1.TMR1IE = 1  'Activa la interrup. TIMER1
	If _int = 4 Then PIE1.TMR2IE = 1  'Activa la interrup. TIMER2
	If _int = 5 Then INTCON.INTE = 1  'Activa la interrup. EXTERNA RB0/INT
	If _int = 6 Then INTCON.RBIE = 1  'Activa la interrup. por cambio RB7:4
End Proc                                          
'Desactiva las interrupciones seleccionadas
Proc _disable_interrupts(_int As Byte)
	If _int = 1 Then INTCON.PEIE = 0  'Bit de deshabilita interrup. perifericos
	If _int = 1 Then Disable  'INTCON.GIE deshabilita las interrup. globales
	If _int = 2 Then PIE1.RCIE = 0  'Deshabilita interrup. de la usart en modo rx*/
	If _int = 0 Then INTCON.TMR0IE = 0  'Deshabilita la interrup. TIMER0
	If _int = 3 Then PIE1.TMR1IE = 0  'Deshabilita la interrup. TIMER1
	If _int = 4 Then PIE1.TMR2IE = 0  'Deshabilita la interrup. TIMER2
	If _int = 5 Then INTCON.INTE = 0  'Deshabilita la interrup. EXTERNA RB0/INT
	If _int = 6 Then INTCON.RBIE = 0  'Deshabilita la interrup. por cambio RB7:4
End Proc                                          
'******************************************************************************
'******************************************************************************
Symbol _intif = INTCON.INTF  'Asigna  nobre al flag de aviso interrup. ext. RB0
Symbol _rbif = INTCON.RBIF  'Asigna nobre al flag de aviso interrup. RB7:4
Const _int_ext_l_to_h = 1  'Interrupción ext. por flanco bajo a alto
Const _int_ext_h_to_l = 0  'Interrupción ext. por flanco alto a bajo
'Establece el flanco de disparo de las int. ext. RB0/INT
Proc _set_int_ext(_flanco As Bit)
	OPTION_REG.INTEDG = _flanco  '_flanco
End Proc                                          
'******************************************************************************
'******************************************************************************
'Resistencias PullUp:
'Activa o desactiva las resistencias de PullUp del puerto B
Const _pullup_on = 0
Const _pullup_off = 1
Proc _set_pullup(_modo As Bit)
	OPTION_REG.7 = _modo  '_RBPU, Enable/Disable PORTB pullups
End Proc                                          
'******************************************************************************
'******************************************************************************
'WATCHDOG (WDT):
'Funciones para el control del módulo WDT
'_SeUp_WDT(_mode, _prescaler2)'Configura los prescaler del WDT
'_Set_WDT_On()'Activa el módulo
'_Set_WDT_Off()'Para el módulo
'_Restart_WDT()'Reinicia el contador del WDT
'----------------------------------------------------------------------
'_Mode (prescaler):
Const _wdt_div32 = 0  '1,024mSeg (1/31250Hz*32div*1000mSeg)
Const _wdt_div64 = 1  '2,048mSeg
Const _wdt_div128 = 2  '4,096mSeg
Const _wdt_div256 = 3  '8,192mSeg
Const _wdt_div512 = 4  '16,384mSeg
Const _wdt_div1024 = 5  '32,768
Const _wdt_div2048 = 6  '65,536
Const _wdt_div4096 = 7  '131,072
Const _wdt_div8192 = 8  '262.144
Const _wdt_div16394 = 9  '524,608
Const _wdt_div32768 = 10  '1048,576
Const _wdt_div65536 = 11  '2097,152
'_Poscaler:
Const _wdt_nopostscaler = 0  '0.032mSeg (no se usa, queda asignado al Tmr0)
Const _wdt_div2_ps2 = 1  '0,064mSeg
Const _wdt_div4_ps2 = 2  '0,128mSeg
Const _wdt_div8_ps2 = 3  '0,256mseg
Const _wdt_div16_ps2 = 4  '0,512mSeg
Const _wdt_div32_ps2 = 5  '1,024mSeg (1/31250Hz*32div*1000mSeg)
Const _wdt_div64_ps2 = 6  '2,048mSeg
Const _wdt_div128_ps2 = 7  '4,096mSeg
'Configura el prescaler del WDT (reloj 31250Hz)
Proc _setup_wdt(_mode As Byte, _postscaler As Byte)
	'Prescaler del Wdt
	WDTCON.WDTPS0 = _mode.0  'Prescaler Rate Select bits
	WDTCON.WDTPS1 = _mode.1
	WDTCON.WDTPS2 = _mode.2
	WDTCON.WDTPS3 = _mode.3
	'Poscaler compartido con el Tmr0
	If _postscaler > 0 Then
		OPTION_REG.PSA = 1  'Asigna Poscaler al WDT
		OPTION_REG.PS0 = _postscaler.0  'Configura prescaler
		OPTION_REG.PS1 = _postscaler.1
		OPTION_REG.PS2 = _postscaler.2
	Else
		OPTION_REG.PSA = 0  'No postscaler WDT (asigna al Tmr0)
	Endif
End Proc                                          
'Activa el WDT (si se activa el fuse de WDT se ignora)
Proc _set_wdt_on()
	WDTCON.SWDTEN = 1
End Proc                                          
'Para el WDT (si se activa el fuse de WDT se ignora)
Proc _set_wdt_off()
	WDTCON.SWDTEN = 0
End Proc                                          
Proc _restart_wdt()
	ASM:        clrwdt  'Reinicializa el WDT
End Proc                                          
'******************************************************************************
'******************************************************************************
'OSCCON: OSCILLATOR CONTROL REGISTER
'******************************************************************************
Const _osc_31250hz = 0
Const _osc_125khz = 1
Const _osc_250khz = 2
Const _osc_500khz = 3
Const _osc_1mhz = 4
Const _osc_2mhz = 5
Const _osc_4mhz = 6
Const _osc_8mhz = 7
Proc _setup_oscillator(_mode As Byte)  'Internal frecuency clock (INTRC)
	OSCCON.IRCF0 = _mode.0
	OSCCON.IRCF1 = _mode.1
	OSCCON.IRCF2 = _mode.2
End Proc                                          
Const _oscillator_mode_defined_by_fosc = 0  'Oscillator mode defined by FOSC<2:0>
Const _t1osc_system_clock = 1  'T1OSC is used for system clock
Const _internal_rc_system_clock = 2  'Internal RC is used for system clock
Proc _setup_oscillator_mode_select_bit(_select_bit As Byte)
	OSCCON.SCS0 = _select_bit.0
	OSCCON.SCS1 = _select_bit.1
End Proc                                          
'Valores para _finetune:
	'Maximum frequency = 011111
	'......
	'000001 = Center +1
	'Center frequency = 000000
	'111111 = Center -1
	'......
	'Minimum frequency = 100000
Proc _setup_oscillator_finetune(_finetune As Byte)
	OSCTUNE = _finetune
End Proc                                          
'******************************************************************************
'******************************************************************************
'Asignación de direcciones de memoria para trabajar con punteros
'******************************************************************************
'Funcion para asignar dirección de memoria a punteros de forma automática.
'By COS, 11/11.
'Basic del Pic Simulator IDE (PSI).
'*************************************************
'Longitud minima de los vectores 2 bytes.
'Hay que indicar la direccion primera y última de lal Ram del Pic.
'Ejecutar al principio.
'*************************************************
'Dim x(10) As Byte  'Declara vector
'Dim p_x As Word  'Declara puntero
'x(0) = 0xaa  'Clave para la localización de la variable en memoria
'x(1) = 0xaa  'Clave para la localización de la variable en memoria
'p_x = _Address(x)  'Asigna la direccion de la variable y clave de busqueda
'Pic16F628A Ram 0x20 to 0x14f
'Pic16F88 Ram 0x20 to 0x1ef
'Pic16F877A Ram 0x20 to 0x1ef
'-------------------------------------------------
'Devuelve la dirección de un vector.
'Los elementos minimos que puede tener el vector son dos.
Const _p_ram_inicio = 0x020  'Inicio de la memoria ram del Pic16F88
Const _p_ram_fin = 0x1ef  'Fin de la memoria ram del Pic16F88
Function _address(_clave As Byte) As Word
	Dim _dr0_ram As Word  'Dirección byte 0
	Dim _dr1_ram As Word  'Dirección byte 1
	Dim _dt0 As Byte  'Contenido de la dirección byte 0
	Dim _dt1 As Byte  'Contenido de la dirección byte 1
	For _dr0_ram = _p_ram_inicio To _p_ram_fin  'Rutina de busqueda
		_dr1_ram = _dr0_ram + 1
		_dt0 = Pointer(_dr0_ram)  'Asignación del contenido de dirección
		_dt1 = Pointer(_dr1_ram)  'Asignación del contenido de dirección
		If _dt0 = _clave And _dt1 = _clave Then  'Comparación
			_address = _dr0_ram  'Asignación de dirección
			Pointer(_dr0_ram) = 0  'Inicaliza la variable
			Pointer(_dr1_ram) = 0
			Exit  'Sale de la función
		Endif
		If _dt1 <> _clave Then _dr0_ram = _dr1_ram  'Acelera la busqueda
	Next _dr0_ram
End Function                                      
'***********************************************************************************************
'***********************************************************************************************
'Función Button de MikroBasic.
'By COS, 27/11/2016, Basic PSI.
'***********************************************************************************************
'_Port: puerto elegido.
'_Pin: pin del puerto elegido (0 a 7, el pin tiene que ser configurado como entrada digital).
'_Time: tiempo que la tecla tiene que estar pulsada en mSeg. (0 a 255).
'_ActiveState: estado que tiene que tener la tecla para ser validada (0 o 1).
'_Button: devuelve 0 si no hay tecla pulsada y 255 si lo esta.
'_Delay: si la tecla fue validada y sigue pulsada genera un retraso.
Const port_a = 0
Const port_b = 1
'Const port_c = 2
'Const port_d = 3
'Const port_e = 4
Function _button(_port As Byte, _pin As Byte, _time As Byte, _activestate As Bit, _delay As Byte) As Byte
	Dim address As Word  'byte
	Dim _n As Byte
	'Establece la dirección del puerto a usar
	Select Case _port
		Case 0
			address = 05h  'Puerto A
		Case 1
			address = 06h  'Puerto B
		'Case 2
			'address = 07h  'Puerto C
		'Case 3
			'address = 08h  'Puerto D
		'Case 4
			'address = 84h  'Puerto E
	EndSelect
	
	_button = 0  'Reset al estado anterior
	'Lee el estado del pin
	_port = Pointer(address)
	_port = ShiftRight(_port, _pin)
	
	'Comprueba que se cumpla que la tecla este pulsada el tiempo _time
	If _activestate = _port.0 Then
		For _n = _time To 0 Step -1
			_port = Pointer(address)
			_port = ShiftRight(_port, _pin)
			If _activestate = _port.0 Then
				_button = 255
			Else
				_button = 0
				Exit For
			Endif
			WaitUs 1000
		Next _n
	Endif
	'Genera un retraso si la tecla fue validada y sigue pulsada
	If _button > 0 Then
		For _n = 0 To _delay
			_port = Pointer(address)
			_port = ShiftRight(_port, _pin)
			If _activestate = _port.0 Then
				WaitUs 1000
			Else
				Exit For
			Endif
		Next _n
	Endif
End Function                                      