Andalucía Makers en el Parque de las Ciencias 2016

Algunos proyectos de Andalucía Makers fueron presentados en el Parque de las Ciencias de Granada, en su día de jornadas de puertas abiertas (mayo 2016).

Granabot 2016

Dibujos de Cristina Urdiales

Robolot 2016

1º, 2º y 3º en la modalidad libre, y 3º velocistas.

EVA, el nuevo proyecto robótico del Politécnico, triunfa en Robolot 2016

Capítulo 9: PWM

Configuramos el módulo CCP1 (PIN_C2) para que genere una señal cuadrada (PWM). En PIN_C2 tenemos conectado un LED. El ciclo de trabajo (duty cycle) de la señal PWM variará de 0% (apagada) a 100% (totalmente encendida), pasando por 4 estados intermedios, de forma que veremos como va cambiando la intensidad luminosa del LED de manera progresiva.

Código fuente: PWM.c

T_PWM = (PR2+1)*prescaler*4*Tosc

Duty cycle (CCPRxx): valor mínimo=0 (0%), valor máximo=PR2 (100%)

El PIC18F2550 tiene dos puertos que pueden generar automáticamente señales PWM: CCP1 (PIN_C2) y CCP2 (PIN_C1).

En nuestro ejemplo, el período de la señal PWM sería:

T_PWM = (255+1) * 16 * 4 *  (1/48MHz) = 341us (2.93KHz)

Duty cycle: CCPR1L = (0 – 255)

Registros para configurar el PWM (para generar el PWM, el PIC18F2550 trabaja con el timer2):

CPxCONbits.CCPxM: configura el módulo CCPx en modo PWM, o en modo Comparación o en modo Mejorado de Captura.
PR2: Similar al valor máximo del duty cycle, para una resolución de 8 bits.
T2CONbits.TMR2ON: Habilita el timer2.
T2CONbits.T2CKPS: Prescaler del timer2. El postscaler del timer2 no se usa en el PWM.
CCPRxL: El valor del duty cycle puede tener una resolución de 8 bits o de 10 bits. Los 8 bits más significativos se almacenan en el resgistro CCPRxL. Los dos bits menos significativos estarían en CPxCONbits.DCxB. En la mayoría de los casos, una resolución de 8 bits (0-255) sería suficiente, por lo que tan solo habría que dar un valor a CCPRxL para cambiar el duty cycle.

ccpxcon

CCPxCON: CCP control register

timer2

T2CON: Timer2 control register

Capítulo 8: Timer 0

Se configura el timer_0 del PIC18F2550 para que salte la interrupción por desbordamiento cada 500ms. Y cada 500ms se invierte el valor del PIN_C6, para que parpadee el LED que tiene conectado.

Código fuente: timer0.c

tiempo = (cont_máx – cont_mín)*Prescaler*4*Tosc

cont_máx = 255+1 (8 bits) ó 65535+1 (16 bits).

cont_mín = TMR0 en el momento del desbordamiento. Si en la subrutina de interrupción no se le da ningún valor, empieza contando desde cero.

En nuestro ejemplo: tiempo = (65535+1 – 18661) * 128 * 4 * (1/48MHz) = 500ms

Registros para configurar la interrupción:

INTCONbits.GIE: Habilita las interrupciones.
INTCONbits.PEIE: Habilita las interrupciones periféricas (todas son periféricas, menos las externas, port B).
INTCONbits.TMR0IE: Habilita la interrupción del timer0.
INTCONbits.TMR0IF: Flag o bandera del timer0, que se pone a uno cuando salta la interrupción por desbordamiento del timer0.

Registros para configurar el timer0:

T0CONbits.TMR0ON: Habilita el timer0.
T0CONbits.T08BIT: Contador de 8 bits (desborda a 255+1) o de 16 bits (desborda a 65535+1), la interrupción salta al reiniciar.
T0CONbits.T0CS: Cuenta los pulsos del reloj interno (48MHz) o de una fuente externa.
T0CONbits.T0SE: Cuenta los flancos de subida o de bajada.
T0CONbits.PSA: Se le asigna un valor al prescaler.
T0CONbits.T0PS: Prescaler.

t0con

T0CON: Timer0 control register

Capítulo 7: Interrupciones externas

Un pulsador en pull-up conectado al PIN_B7 interrumpe el bucle infinito while(1) para encender un LED (PIN_C6) cuando lo pulsamos y apagarlo cuando lo soltamos.

Código fuente: interrupcion_externa.c

En el puerto B tenemos varios tipos de interrupciones externas:

Interrupciones por flanco: INT0 (PIN_B0), INT1 (PIN_B1) y INT2 (PIN_B2). Cada una se puede configurar de manera independiente, es decir, cada una tiene su propio “flag”, que puede saltar en el flanco de subida o en el de bajada, según se quiera.

Interrupciones por nivel: la interrupción saltaría ante cualquier cambio de nivel en cualquiera de los 4 puertos: RB4-RB7. Por eso es importante comprobar dentro de la subrutina de interrupción qué puerto es el que ha cambiado.

Registros a tener en cuenta para configurar interrupciones por nivel:

INTCONbits.GIE: Habilita las interrupciones.
INTCONbits.RBIE: Habilita interrupciones por nivel, RB4-RB7.
INTCONbits.RBIF: Indicador de bandera (flag), se pone a uno cuando salta la interrupción de nivel.

Apuntes detallados de cómo configurar interrupciones externas, tanto las de flanco como las de nivel:

interrupt_port_B.pdf

INTCON: Interrupt control register

intcon2

INTCON2: Interrupt control register 2

intcon3

INTCON3: Interrupt control register 3

Capítulo 6: Entrada analógica

En el PIN_A0 (AN0) tenemos conectado un potenciómetro, de manera que el PIC18F2550 leerá valores analógicos entre 0 y 5V. El programa enciende un LED cuando sobrepasa los 2.5V y lo apaga cuando está por debajo.

Código fuente: entrada_analogica.c

Configurar un puerto como analógico:

TRIS…: Configura el PIN de salida.
ADCON1bits.VCFG: Configura tensiones de referencia. Pueden usarse los 0 y 5V de alimentación, como valores mínimo y máximo, o tensiones Vref- y Vref+, conectadas a PIN_A2 y PIN_A3, respectivamente.
ADCON1bits.PCFG: Configura los puertos que queremos que sean analógicos, y los que serán digitales.
ADCON2bits.ADCS: Configura el tiempo de conversión analógico-digital, según frecuencia de trabajo.
ADCON2bits.ACQT: Configura tiempo de adquisición, para el que hay que tener en cuenta el de conversión.
ADCON2bits.ADFM: El resultado se puede almacenar en 8 bits (resolución 256, dato justificado a la izquierda) o en 10 bits (resolución 1024, dato justificado a la derecha).

Conversión analógico-digital:

ADCON0bits.ADON: Habilita el módulo convertidor analógico-digital.
ADCON0bits.CHS: El PIC18F2550 sólo tiene un módulo convertidor, que es compartido por todos los puertos analógicos. Por lo que antes de lanzar  la conversión, hay que decir de qué puerto se va a leer el valor analógico.
ADCON0bits.GO_DONE: Lanza la conversión analógico-digital del puerto seleccionado anteriormente. Hasta que no se pone a CERO, no se ha finalizado la conversión, y no se debe leer el dato.
ADRESH y ADRESL: Registros donde se carga el resultado. Para justificación a la izquierda (resolución 256), sólo se leería ADRESH.

Apuntes detallados con las tablas de valores para cada uno de los registros, según datasheet:

analog ports.pdf

adcon0

ADCON0: A/D control register 0

adcon1

ADCON1: A/D control register 1

adcon2

ADCON2: A/D control register 2

Capítulo 5: Pulsador

Un pulsador en modo pull-up (PIN_C0) y un LED (PIN_C6) conectados al PIC18F2550. Al pulsar BUTTON (PIN_C0 vale 0) se enciende el LED, al soltar (PIN_C0 vale 1) se apaga el LED.

Hemos incluido un if-else y cómo leer un bit del exterior. Además, hemos usado #define.

Código fuente: Pulsador.c

lat-vs-port

TRISCbits.TRISC0=1;            // PIN_C0 periférico de entrada, BUTTON
if (PORTCbits.RC0==0)…   // si PIN_C0 vale 0, entonces…

Explicación detallada del funcionamiento de los biestables y puertas lógicas al usar: TRIS, LAT, PORT.

TRIS vs LAT vs PORT.pdf

RESUMEN y RECOMENDACIÓN:

TRIS: configura puertos para conectar periféricos de entrada (1) o salida (0).

//TRISx=…   //TRISxxbits.TRISxx=…

LAT: escribe un dato en un puerto de salida.

//LATx=…   //LATxxbits.LATxx=…

PORT: lee un dato de un puerto de entrada.

//PORTx    //PORTxxbits.Rxx