Ing. Oscar Concha Rdz
Programación de micro-controladores PIC con el "MPLAB XC8"
Ing. Oscar Concha Rdz
Noviembre 7, 2016
Ing. Oscar Concha Rdz Abstracto: En este documento se presenta un tutorial del compilador XC8 que pretende proporcionar los conocimientos básicos para comenzar a desarrollar diferentes proyectos con el PIC18F4455 de la empresa “Microchip” y el software de simulación llamado “Proteus” Por otro lado, como en este escrito solo se pueden observar los códigos de programación que se llevan a cabo en el microcontrolador, se han tomado como referencias distintas páginas de internet para instalar y configurar el compilador que se usa en el documento al final de éste Introducción: Un micro-controlador es un circuito integrado que en su interior contiene una unidad central de procesamiento (CPU), unidades de memoria (RAM y ROM) además de puertos de entrada y salida. Básicamente, un micro-controlador ejecuta el programa que ha sido descargado en su memoria para realizar las diferentes tareas que se le a asignado llevar a cabo Actualmente existe una gran diversidad de micro-controladores ubicados en diferentes sectores, tales como: industria automovilística, aplicaciones militares y en el mercado de la comunicación. Algunos ejemplos de ellos los podemos encontrar en teléfonos celulares, computadoras, impresoras, entre otras Los principales recursos específicos que incorporan los micro-controladores son: temporizadores (timers), conversores análogos-digitales (ADC) y digitales-análogos (DAC), comparadores, modulador de anchura de impulsos (PWM) y puertos de comunicación (USART, SPI, I2C)
Ing. Oscar Concha Rdz PRAGMA PIC18F4455 // CONFIG1L #pragma config PLLDIV = 1 #pragma config CPUDIV = OSC1_PLL2 #pragma config USBDIV = 1
// CONFIG1H #pragma config FOSC = HS (Proteus) ó INTOSC_XT (Microcontrolador) #pragma config FCMEN = OFF #pragma config IESO = OFF
// CONFIG2L #pragma config PWRT = OFF #pragma config BOR = OFF #pragma config BORV = 3 #pragma config VREGEN = OFF
// CONFIG2H #pragma config WDT = OFF #pragma config WDTPS = 32768
// CONFIG3H #pragma config CCP2MX = ON #pragma config PBADEN = ON #pragma config LPT1OSC = OFF #pragma config MCLRE = ON
// CONFIG4L #pragma config STVREN = ON #pragma config LVP = ON #pragma config ICPRT = OFF #pragma config XINST = OFF
Ing. Oscar Concha Rdz // CONFIG5L #pragma config CP0 = OFF #pragma config CP1 = OFF #pragma config CP2 = OFF
// CONFIG5H #pragma config CPB = OFF #pragma config CPD = OFF
// CONFIG6L #pragma config WRT0 = OFF #pragma config WRT1 = OFF #pragma config WRT2 = OFF
// CONFIG6H #pragma config WRTC = OFF #pragma config WRTB = OFF #pragma config WRTD = OFF
// CONFIG7L #pragma config EBTR0 = OFF #pragma config EBTR1 = OFF #pragma config EBTR2 = OFF
// CONFIG7H #pragma config EBTRB = OFF
Ing. Oscar Concha Rdz Configuración PORTB Interrupción #include
void interrupt high_priority HIGH () { if (INTCONbits.INT0IF == 1) //INT0 external interrupt occurred { PORTDbits.RD0 = ~PORTDbits.RD0; } INTCONbits.INT0IF = 0; //INT0 cleared in software
if (INTCON3bits.INT1IF == 1) //INT1 external interrupt occurred { PORTDbits.RD1 = ~PORTDbits.RD1; } INTCON3bits.INT1IF = 0; //INT1 cleared in software }
void interrupt low_priority LOW () { if (INTCON3bits.INT2IF == 1) //INT2 external interrupt occurred { PORTDbits.RD2 = ~PORTDbits.RD2; } INTCON3bits.INT2IF = 0; //INT2 cleared in software }
void main(void) { OSCCONbits.IRCF2 = 1; //Internal oscillator frequency select bits (8MHz) OSCCONbits.IRCF1 = 1; OSCCONbits.IRCF0 = 1;
Ing. Oscar Concha Rdz TRISD = 0x00; PORTD = 0x00;
ADCON1bits.PCFG3 = 1; //AD port configuration control bits (AN12 to AN0) digital ADCON1bits.PCFG2 = 1; ADCON1bits.PCFG1 = 1; ADCON1bits.PCFG0 = 1;
RCONbits.IPEN = 1; //Interrupt priority enable bit (priority levels on interrupts)
INTCONbits.GIEH = 1; //Enables all high priority interrupts INTCONbits.GIEL = 1; //Enables all low priority interrupts
INTCON2bits.INTEDG0 = 1; //External interrupt 0 on rising edge INTCON2bits.INTEDG1 = 1; //External interrupt 1 on rising edge INTCON2bits.INTEDG2 = 1; //External interrupt 2 on rising edge
INTCONbits.INT0IE = 1; //INT0 external interrupt enable bit INTCONbits.INT0IF = 0; //INT0 external interrupt flag bit (did not occur)
INTCON3bits.INT1IE = 1; //INT1 external interrupt enable bit INTCON3bits.INT1IP = 1; //INT1 exernal interrupt priority bit (high priority) INTCON3bits.INT1IF = 0; //INT1 external interrupt flag bit (did not occur)
INTCON3bits.INT2IE = 1; //INT2 external interrupt enable bit INTCON3bits.INT2IP = 0; //INT2 exernal interrupt priority bit (low priority) INTCON3bits.INT2IF = 0; //INT2 external interrupt flag bit (did not occur)
while (1) {
} return;
Ing. Oscar Concha Rdz }
Ing. Oscar Concha Rdz Configuración TMR0 Interrupción #include
int msegundo; int segundo;
void interrupt high_priority ISR () { if (INTCONbits.TMR0IF == 1) //TMR0 register has overflowed { msegundo++; if (msegundo > 999) //Overflow time = 0.001 seconds { msegundo = 0; segundo++; if (segundo > 1) { segundo = 0; } if (segundo == 0) { PORTDbits.RD0 = 0; } if (segundo == 1) { PORTDbits.RD0 = 1; } } } TMR0 = 6; INTCONbits.TMR0IF = 0; //TMR0 cleared in software }
Ing. Oscar Concha Rdz void main(void) { OSCCONbits.IRCF2 = 1; //Internal oscillator frequency selecct bits (8MHz) OSCCONbits.IRCF1 = 1; OSCCONbits.IRCF0 = 1;
TRISD = 0x00; PORTD = 0x00;
RCONbits.IPEN = 1; //Interrupt priority enable bit (priority levels on interrupts)
INTCONbits.GIEH = 1; //Enables all high priority interrupts INTCONbits.GIEL = 1; //Enables all low priority interrupts
T0CONbits.T08BIT = 1; //TMR0 8-16 bit control bit (8 bit timer/counter)
T0CONbits.PSA = 0; //TMR0 prescaler assignment bit (TMR0 prescaler is assigned)
T0CONbits.T0PS2 = 0; //TMR0 prescaler select bits (1:8 prescale value) T0CONbits.T0PS1 = 1; T0CONbits.T0PS0 = 0;
T0CONbits.T0CS = 0; //TMR0 clock source select bit
INTCONbits.TMR0IE = 1; //TMR0 overflow intterrupt enable bit (enables overflow interrupt) INTCON2bits.TMR0IP = 1; //TMR0 overflow interrupt priority bit (high priority) INTCONbits.TMR0IF = 0; //TMR0 overflow interrupt flag bit (did not overflow)
TMR0 = 6; //TMR0 = 256 - (overflow time) / (4*Tosc*Prescaler)
T0CONbits.TMR0ON = 1; //Timer0 on control bit while(1) {
Ing. Oscar Concha Rdz
} return; }
Ing. Oscar Concha Rdz Configuración TMR1 y TMR3 Interrupción #include
int msegundo; int segundo;
void interrupt high_priority ISR () { if (PIR1bits.TMR1IF == 1) //TMR1 register has overflowed { msegundo++; if (msegundo > 999) //Overflow time = 0.001 seconds { msegundo = 0; segundo++; if (segundo > 8) { segundo = 0; } if (segundo == 0) { PORTD = 0x00; } if (segundo == 1) { PORTD = 0x01; } if (segundo == 2) { PORTD = 0x02; } if (segundo == 3) {
Ing. Oscar Concha Rdz PORTD = 0x04; } if (segundo == 4) { PORTD = 0x08; } if (segundo == 5) { PORTD = 0x10; } if (segundo == 6) { PORTD = 0x20; } if (segundo == 7) { PORTD = 0x40; } if (segundo == 8) { PORTD = 0x80; } } } TMR1H = 255; TMR1L = 6; PIR1bits.TMR1IF = 0; //TMR1 cleared in software }
void main(void) { OSCCONbits.IRCF2 = 1; //Internal oscillator frequency select bits (8MHz) OSCCONbits.IRCF1 = 1;
Ing. Oscar Concha Rdz OSCCONbits.IRCF0 = 1;
TRISD = 0x00; PORTD = 0x00;
RCONbits.IPEN = 1; //Interrupt priority enable bit (priority levels on interrupts)
INTCONbits.GIEH = 1; //Enables all high priority interrupts INTCONbits.GIEL = 1; //Enables all low priority interrupts
T1CONbits.RD16 = 0; //Mode enable bit (two 8 bit operation)
T1CONbits.T1OSCEN = 1; //TMR1 oscillator enable bit
T1CONbits.T1CKPS1 = 1; //TMR1 prescaler select bits (1:8 prescale value) T1CONbits.T1CKPS0 = 1;
T1CONbits.TMR1CS = 0; //Internal clock (Fosc/4)
T1CONbits.TMR1ON = 1; //TMR1 on bit
PIE1bits.TMR1IE = 1; //TMR1 overflow interrupt enable bit IPR1bits.TMR1IP = 1; //TMR1 overflow interrupt priority bit (high priority) PIR1bits.TMR1IF = 0; //TMR1 overflow interrupt flag bit (did not occur)
//TMR1 = 65536 - (overflow time) / (4*Tosc*Prescaler) // overflow time = 65286 = 11111111 00000110 TMR1H = 255; TMR1L = 6;
while (1) {
Ing. Oscar Concha Rdz } return; }
Ing. Oscar Concha Rdz Configuración ADC Interrupción #include
int ADC = 0;
void interrupt high_priority ISR () { if (PIR1bits.ADIF == 1) //A/D conversion completed { ADC = (ADRESH << 8) + ADRESL; //10bits result PORTC = ADC; //LSB PORTD = ADC >> 8; //MSB } PIR1bits.ADIF = 0; //A/D conversion cleared in software ADCON0bits.GO = 1; //AD conversion status bit (conversion in progress) }
void main(void) { OSCCONbits.IRCF2 = 1; //Internal oscillator frequency selecct bits (8MHz) OSCCONbits.IRCF1 = 1; OSCCONbits.IRCF0 = 1;
TRISC = 0x00; PORTC = 0x00; TRISD = 0x00; PORTD = 0x00;
RCONbits.IPEN = 1; //Interrupt priority enable bit (priority levels on interrupts) INTCONbits.GIEH = 1; //Enables all high priority interrupts INTCONbits.GIEL = 1; //Enables all low priority interrupts
PIE1bits.ADIE = 1; //A/D converter interrupt enable bit
Ing. Oscar Concha Rdz IPR1bits.ADIP = 1; //A/D converter interrupt priority bit (high priority) PIR1bits.ADIF = 0; //A/D converter interrupt flag bit
ADCON2bits.ACQT2 = 1; //Table 2-11 ADCON2bits.ACQT1 = 1; ADCON2bits.ACQT0 = 0;
ADCON2bits.ADCS2 = 1; //Table 2-11 ADCON2bits.ADCS1 = 0; ADCON2bits.ADCS0 = 1;
ADCON2bits.ADFM = 1; //AD result format select bit (right justified)
ADCON1bits.PCFG3 = 1; //AD port configuration control bits (AN0 analog) ADCON1bits.PCFG2 = 1; ADCON1bits.PCFG1 = 1; ADCON1bits.PCFG0 = 0;
ADCON0bits.CHS3 = 0;//Analog channel select bits (AN0) ADCON0bits.CHS2 = 0; ADCON0bits.CHS1 = 0; ADCON0bits.CHS0 = 0;
ADCON1bits.VCFG1 = 0; //Voltage reference (Vss) ADCON1bits.VCFG0 = 0; //Voltage reference (Vdd)
ADCON0bits.ADON = 1; //AD on bit
ADCON0bits.GO = 1; //AD conversion status bit (conversion in progress)
while (1) {
Ing. Oscar Concha Rdz } return; }
Ing. Oscar Concha Rdz Configuración ADC #include
int ADC;
void main(void) { OSCCONbits.IRCF2 = 1; //Internal oscillator frequency select bits (8MHz) OSCCONbits.IRCF1 = 1; OSCCONbits.IRCF0 = 1;
TRISD = 0x00; PORTD = 0x00;
ADCON2bits.ACQT2 = 1; //Table 2-11 ADCON2bits.ACQT1 = 1; ADCON2bits.ACQT0 = 0;
ADCON2bits.ADCS2 = 1; //Table 2-11 ADCON2bits.ADCS1 = 0; ADCON2bits.ADCS0 = 1;
ADCON2bits.ADFM = 1; //AD result format select bit (right justified)
ADCON1bits.PCFG3 = 1; //AD port configuration control bits (AN0 analog) ADCON1bits.PCFG2 = 1; ADCON1bits.PCFG1 = 1; ADCON1bits.PCFG0 = 0;
ADCON0bits.CHS3 = 0; //Analog channel select bits (AN0) ADCON0bits.CHS2 = 0; ADCON0bits.CHS1 = 0; ADCON0bits.CHS0 = 0;
Ing. Oscar Concha Rdz
ADCON1bits.VCFG1 = 0; //Voltage reference (Vss) ADCON1bits.VCFG0 = 0; //Voltage reference (Vdd)
ADCON0bits.ADON = 1; //AD on bit
while (1) { ADCON0bits.GO = 1; //AD conversion status bit (conversion in progress) while (ADCON0bits.nDONE == 1) continue; //Wait until conversion is over ADC = (ADRESH << 8) + ADRESL; //10bits result
if (ADC >= 0 && ADC <= 128) { PORTD = 0x01; } if (ADC >= 129 && ADC <= 256) { PORTD = 0x02; } if (ADC >= 257 && ADC <= 384) { PORTD = 0x04; } if (ADC >= 385 && ADC <= 512) { PORTD = 0x08; } if (ADC >= 513 && ADC <= 640) { PORTD = 0x10; } if (ADC >= 641 && ADC <= 768)
Ing. Oscar Concha Rdz { PORTD = 0x20; } if (ADC >= 769 && ADC <= 896) { PORTD = 0x40; } if (ADC >= 897 && ADC <= 1023) { PORTD = 0x80; } } return; }
Ing. Oscar Concha Rdz Configuración TOUCH #include
int voltage = 0; int touch = 0; int rango = 0;
void main(void) { OSCCONbits.IRCF2 = 1; OSCCONbits.IRCF1 = 1; OSCCONbits.IRCF0 = 1;
TRISD = 0x00; PORTD = 0x00;
ADCON2bits.ACQT2 = 1; //Table 2-11 ADCON2bits.ACQT1 = 1; ADCON2bits.ACQT0 = 0;
ADCON2bits.ADCS2 = 1; //Table 2-11 ADCON2bits.ADCS1 = 0; ADCON2bits.ADCS0 = 1;
ADCON2bits.ADFM = 0; //AD result format select bit (left justified)
ADCON1bits.PCFG3 = 1; //AD port configuration control bits (AN0 analog) ADCON1bits.PCFG2 = 1; ADCON1bits.PCFG1 = 0; ADCON1bits.PCFG0 = 1;
ADCON1bits.VCFG1 = 0; //Voltage reference (Vss) ADCON1bits.VCFG0 = 0; //Voltage reference (Vdd)
Ing. Oscar Concha Rdz
ADCON0bits.ADON = 1; //AD on bit
while (1) { ADCON0bits.CHS3 = 0; //Analog channel select bits (AN0) ADCON0bits.CHS2 = 0; ADCON0bits.CHS1 = 0; ADCON0bits.CHS0 = 0;
ADCON0bits.GO = 1; //AD conversion status bit (conversion in progress) while (ADCON0bits.nDONE == 1) continue; //Wait until conversion is over voltage = ADRESH; //8bit result //PORTD = voltage;
ADCON0bits.CHS3 = 0; //Analog channel select bits (AN1) ADCON0bits.CHS2 = 0; ADCON0bits.CHS1 = 0; ADCON0bits.CHS0 = 1;
ADCON0bits.GO = 1; //AD conversion status bit (conversion in progress) while (ADCON0bits.nDONE == 1) continue; //Wait until conversion is over touch = ADRESH; //8bit result //PORTD = touch;
rango = (voltage * touch) / (voltage + touch);
if (rango >= 7 && rango <= 15) { PORTDbits.RD0 = 1; } else {
Ing. Oscar Concha Rdz PORTDbits.RD0 = 0; } } return; }
Ing. Oscar Concha Rdz Configuración PWM FIJO #include
void main(void) { OSCCONbits.IRCF2 = 1; //Internal oscillator frequency select bits (1MHz) OSCCONbits.IRCF1 = 0; OSCCONbits.IRCF0 = 0;
//16ms (periodo) 8ms (duty cycle) //PR2 = (PWM period / (TMR2prescale *4 * Tosc)) - 1 //CCPR1L:CCP1CON = (PWM duty-cycle/(TMR2prescale * Tosc)) //NOTA: Convertir resultado obtenido entero a valor binario de 10 bits //CCPR1L:CCP1CON = 500 = 01111101 00 //Últimos dos bits al registro CCP1CON (bit 4 y 5) //Primeros ocho bits al registro CCPR1L
TRISCbits.RC2 = 0; //Pin RC2/CCP1 as an output PORTCbits.RC2 = 0;
T2CONbits.T2CKPS1 = 1; //TMR2 clock prescale select bits (prescaler is 16) T2CONbits.T2CKPS0 = 0; T2CONbits.TMR2ON = 1; //TMR2 On bit (TMR2 is on)
PR2 = 0xF9; //Maximo 8 bits
CCPR1L = 0x7D; //10 bits
CCP1CONbits.DC1B1 = 0; CCP1CONbits.DC1B0 = 0;
CCP1CONbits.CCP1M3 = 1; //PWM mode CCP1CONbits.CCP1M2 = 1;
Ing. Oscar Concha Rdz CCP1CONbits.CCP1M1 = 0; CCP1CONbits.CCP1M0 = 0;
while (1) { CCPR1L = 0x7D; } return; }
Ing. Oscar Concha Rdz Configuración PWM Variable #include
int ADC = 0; int i = 0;
void main(void) { OSCCONbits.IRCF2 = 1; //Internal oscillator frequency selecct bits (8MHz) OSCCONbits.IRCF1 = 1; OSCCONbits.IRCF0 = 1;
TRISCbits.RC2 = 0; //Pin RC2/CCP1 as an output PORTCbits.RC2 = 0;
//ADC ADCON2bits.ACQT2 = 1; //Table 2-11 ADCON2bits.ACQT1 = 1; ADCON2bits.ACQT0 = 0; ADCON2bits.ADCS2 = 1; //Table 2-11 ADCON2bits.ADCS1 = 0; ADCON2bits.ADCS0 = 1; ADCON2bits.ADFM = 0; //AD result format select bit (left justified) ADCON1bits.PCFG3 = 1; //AD port configuration control bits (AN0 analog) ADCON1bits.PCFG2 = 1; ADCON1bits.PCFG1 = 1; ADCON1bits.PCFG0 = 0; ADCON0bits.CHS3 = 0;//Analog channel select bits (AN0) ADCON0bits.CHS2 = 0; ADCON0bits.CHS1 = 0; ADCON0bits.CHS0 = 0; ADCON1bits.VCFG1 = 0; //Voltage reference (Vss) ADCON1bits.VCFG0 = 0; //Voltage reference (Vdd)
Ing. Oscar Concha Rdz ADCON0bits.ADON = 1; //AD on bit
//PWM CCP1CONbits.CCP1M3 = 1; //PWM mode CCP1CONbits.CCP1M2 = 1; CCP1CONbits.CCP1M1 = 0; CCP1CONbits.CCP1M0 = 0; PR2 = 0xF9; //500Hz T2CONbits.T2CKPS1 = 1; //TMR2 clock prescale select bits (prescaler is 16) T2CONbits.T2CKPS0 = 0; T2CONbits.TMR2ON = 1; //TMR2 On bit (TMR2 is on)
while (1) { ADCON0bits.GO = 1; //AD conversion status bit (conversion in progress) while (ADCON0bits.nDONE == 1) continue; //Wait until conversion is over ADC = ADRESH; //8bit result
for (i == 0; i < 51; i++) { CCPR1L = ADC; } i = 0; } return; }
Ing. Oscar Concha Rdz
Ing. Oscar Concha Rdz Configuración Compare (50% Duty Cycle) Interrupción #include
void interrupt high_priority ISR () { if (PIR1bits.CCP1IF == 1) //A TMR1 register compare match ocurred { PORTCbits.CCP1 = ~PORTCbits.CCP1; // T = 20ms con 50% duty cycle } CCPR1H = 78; CCPR1L = 32; PIR1bits.CCP1IF = 0; //TMR1 cleared in software }
void main(void) { OSCCONbits.IRCF2 = 1; //Internal oscillator frequency selecct bits (8MHz) OSCCONbits.IRCF1 = 1; OSCCONbits.IRCF0 = 1;
TRISCbits.RC2 = 0; //Pin RC2/CCP1 as an output PORTCbits.RC2 = 0;
RCONbits.IPEN = 1; //Interrupt priority enable bit (priority levels on interrupts) INTCONbits.GIEH = 1; //Enables all high priority interrupts INTCONbits.GIEL = 1; //Enables all low priority interrupts
CCP1CONbits.CCP1M3 = 1; //Compare mode, trigger special event CCP1CONbits.CCP1M2 = 0; CCP1CONbits.CCP1M1 = 1; CCP1CONbits.CCP1M0 = 1;
PIE1bits.CCP1IE = 1; //CCP1 interrupt enable bit
Ing. Oscar Concha Rdz IPR1bits.CCP1IP = 1; //CCP1 interrupt priority bit (high priority) PIR1bits.CCP1IF = 0; //CCP1 interrupt flag bit (No TMR1 register compare match ocurred)
//TCY = 4 / Fosc //CCPR1 = valor deseado / TCY (valor máximo = 65536) //CCPR1 = 4E20 = 10ms/0.5us = 20000 cumple CCPR1H = 78; CCPR1L = 32;
T1CONbits.RD16 = 0; //Mode enable bit (two 8 bit operation) T1CONbits.T1OSCEN = 1; //TMR1 oscillator enable bit T1CONbits.T1CKPS1 = 0; //TMR1 prescaler select bits (1:1 prescale value) T1CONbits.T1CKPS0 = 0; T1CONbits.TMR1CS = 0; //Internal clock (Fosc/4) T1CONbits.TMR1ON = 1; //TMR1 on bit
while (1) {
} return; }
Ing. Oscar Concha Rdz
Ing. Oscar Concha Rdz Configuración Compare (Variable Duty Cycle) Interrupción #include
void interrupt high_priority ISR () { if (PIR1bits.CCP1IF == 1) //A TMR1 register compare match ocurred { if (CCP1CON == 8) { CCP1CON = 9; //CCP1 pin high //CCPR1 = 0x2710 = 5ms CCPR1H = 0x27; CCPR1L = 0x10; } else { CCP1CON = 8; //CCP1 pin low //CCPR1 = 0x7530 = 15ms CCPR1H = 0x75; CCPR1L = 0x30; } } TMR1H = 0; TMR1L = 0; PIR1bits.CCP1IF = 0; //TMR1 cleared in software }
void main(void) { OSCCONbits.IRCF2 = 1; //Internal oscillator frequency select bits (8MHz) OSCCONbits.IRCF1 = 1; OSCCONbits.IRCF0 = 1;
Ing. Oscar Concha Rdz TRISCbits.RC2 = 0; //Pin RC2/CCP1 as an output PORTCbits.RC2 = 0;
RCONbits.IPEN = 1; //Interrupt priority enable bit (priority levels on interrupts) INTCONbits.GIEH = 1; //Enables all high priority interrupts INTCONbits.GIEL = 1; //Enables all low priority interrupts
CCP1CONbits.CCP1M3 = 1; //Initializate CCP1 pin high CCP1CONbits.CCP1M2 = 0; CCP1CONbits.CCP1M1 = 0; CCP1CONbits.CCP1M0 = 1;
PIE1bits.CCP1IE = 1; //CCP1 interrupt enable bit IPR1bits.CCP1IP = 1; //CCP1 interrupt priority bit (high priority) PIR1bits.CCP1IF = 0; //CCP1 interrupt flag bit (No TMR1 register compare match ocurred)
//TCY = 4 / Fosc //CCPR1 = valor deseado / TCY (valor máximo = 65536) //CCPR1 = 15ms/0.5us = 30000 = 0x7530 cumple //CCPR1 = 5ms/0.5us = 10000 = 0x2710 cumple CCPR1H = 0x27; CCPR1L = 0x10;
T1CONbits.RD16 = 0; //Mode enable bit (two 8 bit operation) T1CONbits.T1OSCEN = 1; //TMR1 oscillator enable bit T1CONbits.T1CKPS1 = 0; //TMR1 prescaler select bits (1:1 prescale value) T1CONbits.T1CKPS0 = 0; T1CONbits.TMR1CS = 0; //Internal clock (Fosc/4) T1CONbits.TMR1ON = 1; //TMR1 on bit
while (1) {
Ing. Oscar Concha Rdz } return; }
Ing. Oscar Concha Rdz Configuración Capture Interrupción #include
int captura = 0; unsigned int valor1 = 0; unsigned int valor2 = 0; unsigned int valor3 = 0;
void interrupt high_priority ISR () { if (PIR1bits.CCP1IF == 1) //TMR1 register capture ocurred { captura++;
if (captura == 1) { valor1 = CCPR1L + (CCPR1H * 256); }
if (captura == 2) { valor2 = CCPR1L + (CCPR1H * 256); valor3 = (valor2 - valor1);
PORTD = valor3;
//Tosc = (Fosc/4)^-1 = 0.5us //periodo = (valor3 * Tosc * prescaler)/#rising edge; //frecuencia = 1/periodo
captura = 0; } }
Ing. Oscar Concha Rdz CCPR1H = 0; CCPR1L = 0; PIR1bits.CCP1IF = 0; }
void main(void) { OSCCONbits.IRCF2 = 1; //Internal oscillator frequency selecct bits (8MHz) OSCCONbits.IRCF1 = 1; OSCCONbits.IRCF0 = 1;
TRISCbits.RC2 = 1; //CCP1 input bit
TRISD = 0x00; PORTD = 0x00;
RCONbits.IPEN = 1; //Interrupt priority enable bit (priority levels on interrupts) INTCONbits.GIEH = 1; //Enables all high priority interrupts INTCONbits.GIEL = 1; //Enables all low priority interrupts
PIE1bits.CCP1IE = 1; //Enables the CCP1 interrupt IPR1bits.CCP1IP = 1; //CCP1 interrupt priority bit (high priority) PIR1bits.CCP1IF = 0; //A TMR1 register captured didn't ocurr
//TMR1 T1CONbits.RD16 = 1; //Mode enable bit (one 16 bit operation) T1CONbits.T1OSCEN = 0; //TMR1 oscillator enable bit T1CONbits.T1CKPS1 = 0; //TMR1 prescaler select bits (1:2 prescale value) T1CONbits.T1CKPS0 = 1; T1CONbits.TMR1CS = 0; //Internal clock (Fosc/4)
TMR1H = 0; TMR1L = 0;
Ing. Oscar Concha Rdz
CCP1CONbits.CCP1M3 = 0; //Capture mode, every 4th rising edge CCP1CONbits.CCP1M2 = 1; CCP1CONbits.CCP1M1 = 1; CCP1CONbits.CCP1M0 = 0;
T3CONbits.T3CCP2 = 0; //TMR1 is the capture clock source for CCP1 T3CONbits.T3CCP1 = 1;
T1CONbits.TMR1ON = 1; //TMR1 on bit
while (1) {
} return; }
Ing. Oscar Concha Rdz Configuración EUSART Interrupción #include
char dato;
void interrupt high_priority ISR () { if (PIR1bits.RCIF == 1) //RCREG is full { dato = RCREG; //The received data is sent to character while (!TXSTAbits.TRMT) continue; //Waiting for a whole data frame to be ready for a transmission TXREG = dato + 1; //Write charater to TXREG and start transmission } PIR1bits.RCIF = 0; //USART receive buffer cleared in software }
void main(void) { OSCCONbits.IRCF2 = 1; //Internal oscillator frequency selecct bits (8MHz) OSCCONbits.IRCF1 = 1; OSCCONbits.IRCF0 = 1;
TRISCbits.TRISC6 = 1; //TX pin is input TRISCbits.TRISC7 = 1; //RX pin is input
TXSTAbits.TXEN = 1; //Transmit enable bit RCSTAbits.CREN = 1; //Continous receive enable bit TXSTAbits.SYNC = 0; //EUSART mode select bit (asynchronoous mode) BAUDCONbits.BRG16 = 0; //16-bit baud rate register enable bit TXSTAbits.BRGH = 1; //High baud rate select bit (high speed) RCSTAbits.SPEN = 1; //Serial port enable bit
SPBRG = 8; //SPBRG = Fosc/[16(n+1)] ((Table 20.3)
Ing. Oscar Concha Rdz
PIE1bits.RCIE = 1; //EUSART receive interrrupt enable bit IPR1bits.RCIP = 1; //EUSART receive interrupt priority bit (high priority) PIR1bits.RCIF = 0; //EUSART receive interrupt flag bit (buffer is empty)
RCONbits.IPEN = 1; //Interrupt priority enable bit (priority levels on interrupts) INTCONbits.GIEH = 1; //Enables all high priority interrupts INTCONbits.GIEL = 1; //Enables all low priority interrupts
while (1) {
} return; }
Ing. Oscar Concha Rdz Configuración SPI MAESTRO #include
int datout; // Master prepares to send data/character/number int dato; // Master sends information to slave int recibidos; //Master recives information from slave int dat; //Master shows information on display
void interrupt high_priority ISR () { if (INTCONbits.RBIF == 1) //At least of the RB7:RB4 pins changed state { if (PORTBbits.RB4 == 1) { datout = datout + 1;
if(datout <= 8) { dato = datout; // datout = 0, 1, 2, 3, 4, 5, 6, 7, 8 PORTAbits.RA5 = 0; // Pull SS low to select slave SSPBUF = dato; // Write charater to SSPBUF and start transmission while (!SSPSTATbits.BF); // Waiting for a whole data frame to be ready for a transmission PORTAbits.RA5 = 1; // Pull SS hgh to terminate transfer recibidos = SSPBUF; //The received data from slave is sent to SSPBUF dat = recibidos; //Master recives information from slave }
if (datout >= 9) { datout = 0; // datout = 0; dato = datout; PORTAbits.RA5 = 0;
Ing. Oscar Concha Rdz SSPBUF = dato; while (!SSPSTATbits.BF); PORTAbits.RA5 = 1; recibidos = SSPBUF; dat = recibidos; }
switch (dat) //Master shows information on PORTD { case 0: PORTD = 0; break; case 1: PORTD = 1; break; case 2: PORTD = 2; break; case 3: PORTD = 3; break; case 4: PORTD = 4; break; case 5: PORTD = 5; break; case 6: PORTD = 6; break; case 7: PORTD = 7; break;
Ing. Oscar Concha Rdz case 8: PORTD = 8; break; } } } INTCONbits.RBIF = 0; //RBIF register cleared in software }
void main(void) { OSCCONbits.IRCF2 = 1; //Internal oscillator frequency selecct bits (8MHz) OSCCONbits.IRCF1 = 1; OSCCONbits.IRCF0 = 1;
ADCON1 = 0x0F; //Digital I/O (AN12 to AN0)
TRISBbits.RB4 = 1; //Push botom in pin RB4 (input) PORTBbits.RB4 = 0;
INTCONbits.GIEH = 1; //Enables all high priority interrupts INTCONbits.GIEL = 1; //Enables all low priority interrupts
INTCONbits.RBIE = 1; //Enables the RB port change interrupt INTCON2bits.RBIP = 1; //RB port change interrupt high priority bit INTCONbits.RBIF = 0; //None of the RB7:RB4 pins have changed state
TRISBbits.RB0 = 1; //SDI serial data in TRISBbits.RB1 = 0; //SCK serial clock TRISCbits.RC7 = 0; //SDO serial data out TRISAbits.RA5 = 0; //SS slave select
TRISD = 0x00; //Port D as output
Ing. Oscar Concha Rdz PORTD = 0x00;
SSPSTATbits.SMP = 0; //Input data sampled at middle of data output time SSPSTATbits.CKE = 0; //Transmit occurs on transition from idle to active clock state
SSPCON1 = 0x00; //SPI master mode, clk = Fosc/4 SSPCON1bits.CKP = 1; //Idle state for clock is a high level SSPCON1bits.SSPEN = 1; //Enables serial port SDI, SDO, SCK, SS
while (1) {
} return; }
Ing. Oscar Concha Rdz Configuración SPI ESCLAVO #include
int recibidos; int datout; int dat; int dato;
void main(void) { OSCCONbits.IRCF2 = 1; //Internal oscillator frequency selecct bits (8MHz) OSCCONbits.IRCF1 = 1; OSCCONbits.IRCF0 = 1;
ADCON1 = 0x0F; //Digital I/O (AN12 to AN0)
TRISBbits.RB0 = 1; //SDI serial data in TRISBbits.RB1 = 1; //SCK serial clock TRISCbits.RC7 = 0; //SDO serial data out TRISAbits.RA5 = 1; //SS select slave
TRISD = 0x00; //Port D as output PORTD = 0x00;
SSPSTATbits.SMP = 0; //Input data sampled at middle of data output time SSPSTATbits.CKE = 0; //Transmit occurs on transition from idle to active clock state
SSPCON1 = 0x04; //SPI slave mode, clk = SCK pin, SS pin control enabled SSPCON1bits.CKP = 1; //Idle state for clock is a high level SSPCON1bits.SSPEN = 1; //Enables serial port SDI, SDO, SCK, SS
while (1) {
Ing. Oscar Concha Rdz recibidos = SSPBUF; //The received data from master is sent to SSPBUF
switch (recibidos) //Slave sends information to master { case 0: //If slave recives '0' datout = 1; //The slave sends '1' break; case 1: datout = 2; break; case 2: datout = 3; break; case 3: datout = 4; break; case 4: datout = 5; break; case 5: datout = 6; break; case 6: datout = 7; break; case 7: datout = 8; break; case 8: datout = 0; break; }
Ing. Oscar Concha Rdz dat = recibidos; //Slave recives information from master
switch (dat) //Master shows information on PORTD { case 0: PORTD = 1; break; case 1: PORTD = 2; break; case 2: PORTD = 3; break; case 3: PORTD = 4; break; case 4: PORTD = 5; break; case 5: PORTD = 6; break; case 6: PORTD = 7; break; case 7: PORTD = 8; break; case 8: PORTD = 0; break; }
Ing. Oscar Concha Rdz dato = datout; //datout 1, 2, 3, 4, 5, 6, 7, 8, 0 SSPBUF = dato; // Write charater to SSPBUF and start transmission while (!SSPSTATbits.BF); // Waiting for a whole data frame to be ready for a transmission SSPCON1bits.SSPOV = 0; //Recive overflow indicator bit (no overflow) } return; }
Ing. Oscar Concha Rdz Configuración LCD HEADER FILE #ifndef FLEX_LCD_H #define FLEX_LCD_H
#define LCD_RD7
PORTDbits.RD7
// D7
#define TRISRD7
TRISDbits.TRISD7
#define LCD_RD6
PORTDbits.RD6
#define TRISRD6
TRISDbits.TRISD6
#define LCD_RD5
PORTDbits.RD5
#define TRISRD5
TRISDbits.TRISD5
#define LCD_RD4
PORTDbits.RD4
#define TRISRD4
TRISDbits.TRISD4
#define LCD_EN
PORTEbits.RE2
#define TRISEN
TRISEbits.TRISE2
#define LCD_RS
PORTEbits.RE1
#define TRISRS
TRISEbits.TRISE1
// D6
// D5
// D4
// EN
// RS
//comandos disponibles #define
LCD_FIRST_ROW
128
#define
LCD_SECOND_ROW
#define
LCD_THIRD_ROW
#define
LCD_FOURTH_ROW
#define
LCD_CLEAR
#define
LCD_RETURN_HOME
#define
LCD_CURSOR_OFF
#define
LCD_UNDERLINE_ON
#define
LCD_BLINK_CURSOR_ON
192 148 212 1 2 12 14 15
Ing. Oscar Concha Rdz #define
LCD_MOVE_CURSOR_LEFT 16
#define
LCD_MOVE_CURSOR_RIGHT 20
#define
LCD_TURN_OFF
0
#define
LCD_TURN_ON
8
#define
LCD_SHIFT_LEFT
24
#define
LCD_SHIFT_RIGHT
28
void Lcd_Init(void); void Lcd_Out(unsigned char y, unsigned char x, const char *buffer); void Lcd_Out2(unsigned char y, unsigned char x, char *buffer); void Lcd_Chr_CP(char data); void Lcd_Cmd(unsigned char data);
void Lcd_Init(void){ unsigned char data; TRISRD7 = 0; TRISRD6 = 0; TRISRD5 = 0; TRISRD4 = 0; TRISEN = 0; TRISRS = 0; LCD_RD7 = 0; LCD_RD6 = 0; LCD_RD5 = 0; LCD_RD4 = 0; LCD_EN = 0; LCD_RS = 0; __delay_us(5500); __delay_us(5500); __delay_us(5500); __delay_us(5500); __delay_us(5500); __delay_us(5500);
Ing. Oscar Concha Rdz for(data = 1; data < 4; data ++) { LCD_RD7 = 0;
LCD_RD6 = 0;
LCD_RS = 0;
LCD_RD7 = 0;
LCD_EN = 1;
LCD_RS = 0;
LCD_RD5 = 1; LCD_RD6 = 0;
LCD_RD4 = 1; LCD_RD5 = 1;
LCD_EN = 0; LCD_RD4 = 1;
__delay_us(5); LCD_RD7 = 0;
LCD_RD6 = 0;
LCD_RD5 = 1;
LCD_RD4 = 1;
LCD_EN = 0;
LCD_RS = 0; __delay_us(5500); } LCD_RD7 = 0; LCD_RD6 = 0; LCD_RD5 = 1; LCD_RD4 = 0; LCD_EN = 0; LCD_RS = 0; LCD_RD7 = 0; LCD_RD6 = 0; LCD_RD5 = 1; LCD_RD4 = 0; LCD_EN = 1; LCD_RS = 0; __delay_us(5); LCD_RD7 = 0; LCD_RD6 = 0; LCD_RD5 = 1; LCD_RD4 = 0; LCD_EN = 0; LCD_RS = 0; __delay_us(5500); data = 40; Lcd_Cmd(data); data = 16; Lcd_Cmd(data); data = 1; Lcd_Cmd(data); data = 15; Lcd_Cmd(data); }
void Lcd_Out(unsigned char y, unsigned char x, const char *buffer) { unsigned char data; switch (y) { case 1: data = 128 + x; break; case 2: data = 192 + x; break; case 3: data = 148 + x; break; case 4: data = 212 + x; break; default: break; } Lcd_Cmd(data);
Ing. Oscar Concha Rdz while(*buffer)
// Write data to LCD up to null
{ Lcd_Chr_CP(*buffer); buffer++;
// Increment buffer
} return; }
void Lcd_Out2(unsigned char y, unsigned char x, char *buffer) { unsigned char data; switch (y) { case 1: data = 128 + x; break; case 2: data = 192 + x; break; case 3: data = 148 + x; break; case 4: data = 212 + x; break; default: break; } Lcd_Cmd(data); while(*buffer)
// Write data to LCD up to null
{ Lcd_Chr_CP(*buffer); buffer++;
// Increment buffer
} return; }
void Lcd_Chr_CP(char data){ LCD_EN = 0; LCD_RS = 1; LCD_RD7 = (data & 0b10000000)>>7; LCD_RD6 = (data & 0b01000000)>>6; LCD_RD5 = (data & 0b00100000)>>5; LCD_RD4 = (data & 0b00010000)>>4; _delay(10);
Ing. Oscar Concha Rdz LCD_EN = 1; __delay_us(5); LCD_EN = 0; LCD_RD7 = (data & 0b00001000)>>3; LCD_RD6 = (data & 0b00000100)>>2; LCD_RD5 = (data & 0b00000010)>>1; LCD_RD4 = (data & 0b00000001); _delay(10); LCD_EN = 1; __delay_us(5); LCD_EN = 0; __delay_us(5); __delay_us(5500); }
void Lcd_Cmd(unsigned char data){ LCD_EN = 0; LCD_RS = 0; LCD_RD7 = (data & 0b10000000)>>7; LCD_RD6 = (data & 0b01000000)>>6; LCD_RD5 = (data & 0b00100000)>>5; LCD_RD4 = (data & 0b00010000)>>4; _delay(10); LCD_EN = 1; __delay_us(5); LCD_EN = 0; LCD_RD7 = (data & 0b00001000)>>3; LCD_RD6 = (data & 0b00000100)>>2; LCD_RD5 = (data & 0b00000010)>>1; LCD_RD4 = (data & 0b00000001); _delay(10); LCD_EN = 1; __delay_us(5); LCD_EN = 0; __delay_us(5500);//Delay_5us(); } #endif
Ing. Oscar Concha Rdz PROGRAMA #define _XTAL_FREQ 8000000
#include #include //Uso de la función sprintf, float %f, int %d, char %s, #include "flex_lcd.h"
/*Lcd_Init(); Nos permite inicializar la lcd siempre hay que ejecutar esta función antes de comenzar a usar la lcd
* Lcd_Out(y,x,constante); Con esta escribimos sobre la pantalla en la posición inicial y,x y escribimos una constante.
* Lcd_Out2(y, x, variable); Con esta función hacemos lo mismo que con la anterior solo que aquí podemos agragar una variable.
* Lcd_Cmd() Nos permite ejecutar los siguientes comandos;*/
/*LCD_FIRST_ROW
//Ubica el cursor en el primer renglón
LCD_SECOND_ROW
//Ubica el cursor en el segundo renglón
LCD_THIRD_ROW
//Ubica el cursor en el tercer renglón
LCD_FOURTH_ROW LCD_CLEAR
//Ubica el cursor en el cuarto renglón //Limpia la pantalla
LCD_RETURN_HOME
//Regreso del cursor al inicio
LCD_CURSOR_OFF
//Apaga el cursor
LCD_UNDERLINE_ON
//Selección de subrayado
LCD_BLINK_CURSOR_ON LCD_MOVE_CURSOR_LEFT LCD_MOVE_CURSOR_RIGHT
//Parpadeo del cursor //Cursor se mueve a la izquierda //Cursor se mueve a la derecha
LCD_TURN_OFF
//Apaga el lcd
LCD_TURN_ON
//Enciende el lcd
LCD_SHIFT_LEFT
//Desplazamiento a la izquierda
Ing. Oscar Concha Rdz LCD_SHIFT_RIGHT
//Desplazamiento a la derecha*/
char buffer [16]; int i = 0;
void main(void) { OSCCONbits.IRCF2 = 1; OSCCONbits.IRCF1 = 1; OSCCONbits.IRCF0 = 1;
ADCON1bits.PCFG3 = 1; //AD port configuration control bits (all digital) ADCON1bits.PCFG2 = 1; ADCON1bits.PCFG1 = 1; ADCON1bits.PCFG0 = 1;
Lcd_Init(); //Inicializamos el lcd Lcd_Cmd(LCD_CLEAR); //Limpiamos el lcd Lcd_Cmd(LCD_CURSOR_OFF); //Apagamos el cursor
while (1) { for (i == 0; i <= 50; i++) { sprintf (buffer,"Cuenta %d",i); //Guardamos en el string Buffer1 la palabra Cuenta espacio y el valor de i Lcd_Out2 (1, 1, buffer); //Escribimos en el renglon uno espaco 1 la que contiene buffer1 __delay_ms (98); //Esperamos y repetimos } i = 0;
Lcd_Out (1,1,"Yo soy:
"); //Escribimos en la linea 1 espacio 1 la palabra
Lcd_Out (2,1,"Oscar Concha __delay_ms (98);
"); //Escribimos en la linea 2 espacio 1 la palabra
Ing. Oscar Concha Rdz Lcd_Cmd (LCD_CLEAR); //Limpiamos el cursor __delay_ms (98); } return; }
Ing. Oscar Concha Rdz Control PID Temperatura #define _XTAL_FREQ 4000000
#include #include //Uso de la función sprintf, float %f, int %d, char %s, #include "flex_lcd.h" //Librería LCD
//Variables PID unsigned long valor, controlador; //Variables para lectura de ADC y señal de control al módulo CCP float a,b,c; //Constantes para parámetros de controlador PID float TEMPERATURA_LIMITE; //Referencia de Temperatura float rT,eT,iT,dT,yT,uT,iT0,eT0; //Variables del controlador PID float max,min; //Variables para anti-windup
//Variables LCD char buffer1 [16]; char buffer2 [16]; float tempera = 0;
void PID () { ADCON0bits.GO = 1; //AD conversion status bit (conversion in progress) while (ADCON0bits.nDONE == 1) continue; //Wait until conversion is over valor = (ADRESH << 8) + ADRESL; //Leer ADC de 10bits
yT = (5000.0 * valor) / (1024.0); //Señal de salida y(kT) rT = TEMPERATURA_LIMITE; //Referencia eT = rT - yT; //Calcular señal de error e(kT) iT = b * eT + iT0; //Calcular termino integrativo i(kT) dT = c * (eT - eT0); //Calcular termino derivativo d(kT) uT = iT + a * eT + dT; //Calcular señal de control u(kT)
if (uT >= max)
Ing. Oscar Concha Rdz { uT = max; } else { if (uT <= min) { uT = min; } }
unsigned long uTEntero = (unsigned long) uT; //flotante a entero controlador = uTEntero;
CCPR1L = controlador; iT0 = iT; eT0 = eT; }
void LCD () { sprintf (buffer1," Setpoint %f ",TEMPERATURA_LIMITE); //Guardamos en el string Buffer1 la palabra Setpoint y su valor Lcd_Out2 (1, 0, buffer1); //Escribimos en el renglón uno, columna cero lo que contiene buffer1 tempera = yT/10; sprintf (buffer2,"Tempera %f",tempera); //Guardamos en el string Buffer2 la palabra Tempera y su valor Lcd_Out2 (2, 0, buffer2); //Escribimos en el renglón dos, columna 0 lo que contiene buffer2 }
void main(void) { OSCCONbits.IRCF2 = 1; //Internal oscillator frequency select bits (4MHz) OSCCONbits.IRCF1 = 1; OSCCONbits.IRCF0 = 0;
Ing. Oscar Concha Rdz
min = 0.0; max = 1000.0; iT0 = 0.0; eT0 = 0.0; a = 0.1243; b = 0.0062; c = 0.6215; TEMPERATURA_LIMITE = 600.0; //Set-Point r(kT)= 60°C
//PWM TRISCbits.RC2 = 0; //Pin RC2/CCP1 as an output PORTCbits.RC2 = 0; CCP1CONbits.CCP1M3 = 1; //PWM mode CCP1CONbits.CCP1M2 = 1; CCP1CONbits.CCP1M1 = 0; CCP1CONbits.CCP1M0 = 0; PR2 = 0x7C; //1KHz T2CONbits.T2CKPS1 = 1; //TMR2 clock prescaler select bits (prescaler is 16) T2CONbits.T2CKPS0 = 0; T2CONbits.TMR2ON = 1; //TMR2 On bit (TMR2 is on)
//ADC ADCON2bits.ACQT2 = 1; //Table 2-11 ADCON2bits.ACQT1 = 1; ADCON2bits.ACQT0 = 0; ADCON2bits.ADCS2 = 1; //Table 2-11 ADCON2bits.ADCS1 = 0; ADCON2bits.ADCS0 = 1; ADCON2bits.ADFM = 1; //AD result format select bit (right justified) ADCON1bits.PCFG3 = 1; //AD port configuration control bits (AN0 analog) ADCON1bits.PCFG2 = 1; ADCON1bits.PCFG1 = 1;
Ing. Oscar Concha Rdz ADCON1bits.PCFG0 = 0; ADCON0bits.CHS3 = 0; //Analog channel select bits (AN0) ADCON0bits.CHS2 = 0; ADCON0bits.CHS1 = 0; ADCON0bits.CHS0 = 0; ADCON1bits.VCFG1 = 0; //Voltage reference (Vss) ADCON1bits.VCFG0 = 0; //Voltage reference (Vdd) ADCON0bits.ADON = 1; //AD on bit
//LCD Lcd_Init ( ); //Inicializamos el LCD Lcd_Cmd (LCD_CLEAR); //Limpiamos el LCD Lcd_Cmd (LCD_CURSOR_OFF); //Apagamos el cursor
while (1) { PID ( ); //Llamamos la rutina PID a ejecutar LCD ( ); //Llamamos la rutina LCD a ejecutar __delay_ms (100); //Periodo de muestreo T = 0.1 segundos } return; }
Ing. Oscar Concha Rdz
Ing. Oscar Concha Rdz Referencias: gabrielcg3023 (2013). “Instalación XC8 y MPLAB X”. MKMEKATRONIKA. Recuperado el 7 de noviembre de 2016 de https://mkmekatronika.wordpress.com/page/3/
"PIC18F4455 DATASHEET (PDF) - Microchip Technology” (n.f.). Microchip. Recuperado el 7 de noviembre de 2016 de http://www.alldatasheet.es/datasheetpdf/pdf/93910/MICROCHIP/PIC18F4455.html