PROGRAMACIÓN EN LENGUAJE C El WinAvr dispone de un compilador compatible con el ANSI C, adicionalmente dispone de librerías específicas para el manejo de los diferentes recursos. Se presenta una plantilla genérica para un programa escrito para el compilador C de WinAVR //***************************************************************************** // // Titulo : // Autor : // Fecha : 2007-03-29 // Version : 1.0 // Target MCU : Atmel AVR series // // //***************************************************************************** // ------------------------------------------------------------------------------------------------------------//************************* Inclusión de Librerías ******************************* // ------------------------------------------------------------------------------------------------------------#include
#include #include #include #include #include "lcd_lib.h" // ------------------------------------------------------------------------------------------------------------//*********************** Definiciones de Variables Globales ******************* // ------------------------------------------------------------------------------------------------------------// ------------------------------------------------------------------------------------------------------------// ************************* Definiciones y Macros ***************************** // ------------------------------------------------------------------------------------------------------------// ------------------------------------------------------------------------------------------------------------// ************************ Rutinas de Interrupción **************************** // -------------------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------------------// ************************* Declaración de Funciones ************************** // -------------------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------------------// **************************** Cuerpo del Programa **************************** // ------------------------------------------------------------------------------------------------------------int main( void ) { // ------------------------------------------------------------------------------------------------------------// ********************** DECLARACIÓN DE VARIABLES ********************** // -------------------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------------------// ************** CONFIGURACIÓN DE LOS PUERTOS DE E/S ******************* // -------------------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------------------// ********************* INICIALIZACIÓN DE REGISTROS ********************** // -------------------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------------------// ****************** HABILITACIÓN DE INTERRUPCIONES ******************** // -------------------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------------------// ************** INICIALIZACIÓN DE FUNCIONES Y VARIABLES *************** // -------------------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------------------// ******************** CICLO PRINCIPAL DE EJECUCIÓN ********************** // ------------------------------------------------------------------------------------------------------------while (1) { } //Fin while
return 0; } // ------------------------------------------------------------------------------------------------------------//********************* DEFINICIÓN DE FUNCIONES ************************** // ------------------------------------------------------------------------------------------------------------// __________________________________________________________________________
WinAVR dispone de una serie de librerías que pueden incluirse dentro del programa de la cual se dispone la respectiva documentación, algunas son del estándar C y otras propias del WinAVR. Como ejemplo • • • • • • • • • • • • • • • •
: Allocate space in the stack : Diagnostics : Character Operations : System Errors : Integer Type conversions : Mathematics : Non-local goto : Standard Integer Types : Standard IO facilities : General utilities : Strings : Bootloader Support Utilities : EEPROM handling : Fuse Support : Interrupts : AVR device-specific IO definitions
• • • • • • •
: Lockbit Support : Program Space Utilities : Power Reduction Management : Special function registers : Power Management and Sleep Modes : avr-libc version macros : Watchdog timer handling
Variables Globales: Las variables comunes, sólo son accesibles desde la función donde se encuentra definida, si se requiere que la variable sea accesible desde cualquier parte del programa, es necesario declararla como global. Para esto simplemente se define antes de la función main(). Ej. Volatile int var_1, var_2; Es aconsejable aunque no obligatorio definir las variables globales como volactiles para indicarle al compilador que no sobreescriba sobre esta posición de memoria.
Definiciones y Macros: Mediante ciertas directivas se puede asignar a algún símbolo definido por el programador una determinada expresión. Ejemplos: #define
s1
2
#define
larger( x, y)
( (x)>(y) ? (x) : (y))
#define
_BV(bit)
(1 << (bit))
#define
set_bit(value, bit)
(value=((value) | _BV(bit)))
Rutinas de Interrupción: Son funciones cuyo cuerpo definen lo que se debe ejecutar en el momento que se presente una determinada interrupción.
Ej. ISR(TIMER0_OVF_vect) { PORTA=PORTA ^ 0x02; } No es necesario hacer un salto explícito a esta función, ni ejecutar alguna instrucción de retorno. El nombre de los diferentes vectores de interrupción se definen en la librería . /* External Interrupt Request 0 */ INT0_vect /* External Interrupt Request 1 */ INT1_vect /* External Interrupt Request 2 */ INT2_vect /* Timer/Counter0 Overflow */ TIMER0_OVF_vect /* Timer/Counter0 Compare Match */ TIMER0_COMP_vect /* Timer/Counter1 Overflow */ TIMER1_OVF_vect /* Timer/Counter1 Capture Event */ TIMER1_CAPT_vect /* Timer/Counter1 Compare Match A */ TIMER1_COMPA_vect /* Timer/Counter1 Compare Match B */ TIMER1_COMPB_vect /* Timer/Counter2 Overflow */ TIMER2_OVF_vect /* Timer/Counter2 Compare Match */ TIMER2_COMP_vect
/* Serial Transfer Complete */ SPI_STC_vect /* USART, Rx Complete */ USART_RXC_vect /* USART Data Register Empty */ USART_UDRE_vect /* USART, Tx Complete */ USART_TXC_vect /* ADC Conversion Complete */ ADC_vect /* EEPROM Ready */ EE_RDY_vect /* Analog Comparator */ ANA_COMP_vect /* 2-wire Serial Interface */ TWI_vect /* Store Program Memory Ready */ SPM_RDY_vect
Declaración de Funciones: En este campo debe colocarse la declaración de las funciones a emplear con el prototipo de la función. Ej. int mi_funcion(int var1, int var2, float var3);
Cuerpo del Programa: El cuerpo del programa siempre empieza con la función main() y desde donde el programa empieza su ejecución.
Declaración de Variables: Las variables que se definan aquí tienen un ámbito local, no son accesibles desde las funciones.
Configuración de los puertos: // configura PORTA como salida PORTA=0; DDRA = 0xFF; // configura PORTB como salida PORTB=0; DDRB = 0xFF; // configura PORTC como entrada PORTC=0; DDRC = 0x00; // configura PORTD as entrada PORTD=0; DDRD = 0x00;
Inicialización de Registros: Se establecen los valores de los registros de propósito específico de acuerdo con las configuraciones de los diferentes recursos. TCNT1=0xA2B7; En el archivo cabecera de cada dispositivo se tienen asignados los nombres de los registros. #define TCNT1 _SFR_IO16(0x2C) #define TCNT1L _SFR_IO8(0x2C) #define TCNT1H _SFR_IO8(0x2D)
Habilitación de Interrupciones: Habilitación de los diferentes bits de interrupción
Ej. TIMSK=(1<
Inicialización de funciones y variables Se debe establecer el estado inicial de las distintas variables y ejecutar las funciones de inicialización requeridas. Ej. LCDinit();
INTRODUCCIÓN AL LENGUAJE C PARA EL COMPILADOR WINAVR
Tipos de datos básicos: char Define variables de 8 bits, empleado especialmente para representación de caracteres. Enteros: El Ansi C implementa los tipos int y long int, para datos enteros de 16 y 32 bits. Int (-32768 a 32767) Unsigned int (0 a 65535) La librería #include implementa otros tipos adicionales: Int8_t Int16_t Int32_t Int64_t
uint8_t uint16_t uint32_t uint64_t
float y double son punto flotante de 32 bits.
Operadores
Operador condicional expresson1 ? expression2 : expression3 Si expresión1 es verdadera entonces se usa la expresion2, de lo contrario la expresión3. (x)>(y) ? (x) : (y)
Ejercicios 1. Evaluar las siguientes expresiones: (a) 5 / 2 + 20 % 6 (b) 4 * 6 / 2 - 15 / 2 (c) 5 * 15 / 2 / (4 - 2) (d) 8 = = 16 || 7 != 4 && 4 < 1 (e) (4 * 3 < 6 || 3 > 5 - 2) && 3 + 2 < 12 2. Escriba la línea de código en C que corresponda con las siguientes sentencias: (a) Si el residuo de A dividido B es diferente de 0 y A es mayor o igual que B o B es menor de 100 (b) Y= (AB+(C+D)’)((AB)’+C’)
Estructuras de Control If - Else if (expression1) { -------; ..-------; } else if (expression2) { --------; --------; } else if (expression3) { ---------; ---------; }else { ---------; ---------; }
Ejemplo: If (opcion= = 1) { Y=A+B; }else if (opcion= =2) { Y=A-B; } else if (opcion= =3) { Y= A*B; }else { Y=A/B; } Cuando se tiene una sóla sentecia entre un para de llaves, no es obligación colocar éstas. If (opcion= = 1) Y=A+B; else if (opcion= =2) Y=A-B; else if (opcion= =3) Y= A*B; else Y=A/B; Switch switch (expression ) { case constant expression1: -----------; -----------; Break; case constant expression2: -----------; -----------; Break; default constant expression2: -----------; -----------; Break; }
Ejemplo: switch (opcion) { case 1:
}
Y=A+B; Break; case 2: Y=A-B; Break; case 3: Y=A*B; Break; default 3: Y=A/B; Break;
While while(expression) { ---------; ---------; }
do - While do { ------------; ..------------; } while(expression);
Ejemplo; while ( i < 128) { PORTB = 2*i; i++; }
Cual sería el resultado obtenido en cada grupo de instrucciones: (a)
(b)
x=100; y=0;
x=100; y=0;
while ( x < 50) { y= 2*x; x++; }
do {
y= ¿?
y= ¿?
y= 2*x; x++; } while ( x < 50);
For for(expresson1; expression2; expresson3) { --------------; --------------; }
for(i=0;i<=10;i++) { Var=2*i-1; }
Break y Continue Estas instrucciones permiten interrumpir una instrucción cíclica. En el caso de la instrucción break , ésta hace que el bucle más interno que la contenga finalice inmediatamente sin tener en cuenta la condición. La instrucción continue por su parte, finaliza la iteración actual sin salir del ciclo. Ejemplo:
for (i=0; i<100;i++) { if(i==10) continue; sprintf(s_num,"%d\r",i); // Pasa al string s_num el valor numérico LCDclr(); LCDGotoXY(0,0); lcd_puts(s_num,16); _delay_ms(500); } En este caso no se visualiza el valor 10 sino que es saltado.
for (i=0; i<100;i++) { if(i==10) break; sprintf(s_num,"%d\r",i); // Pasa al string s_num el valor numérico LCDclr(); LCDGotoXY(0,0); lcd_puts(s_num,16); _delay_ms(500); } En este caso sólo se visualizan los números del 0 al 9 y termina el ciclo.
PUERTOS DE E/S Cada Puerto tiene asociado tres registros DDRx Para configurar la dirección del puerto. 1 configura como salida 0 Configura como entrada PORTx Se emplea para enviar información por el puerto. En caso que un determinado pin se configure como entrada, y por medio del registro PORTx se coloque en 1, se habilita la correspondiente resistencia de pull-up.
Se recomienda que los pines que no se utilicen se les habiliten esta resistencia. PINx Lee el estado del puerto x Ej. DDRB = 0x1F; DDRB = ( 1 << DDB0 ) | ( 1 << DDB1 ) | ( 1 << DDB2 ) | ( 1 << DDB3 ) | ( 1 << DDB4 ); PORTB = 0x04; PORTB = PORTB | 0x04; PORTB |= ( 1<
Equivalente a la instrucción anterior. Pone los pines 4 y 5 en alto sin alterar los demás.
PORTB &= ~( (1<
Pone los pines 4 y 5 en 0 sin alterar los demás.
Formas de examinar un pin. if ( PINC & (1<
Será verdadero si el pin 1 está en alto.
/* action */
}
if ( !(PINB & (1<
Será verdadero si el pin 1 está en bajo.
/* action */
}
Para simplificar la escritura pueden definirse ciertas macros #define _BV( bit )
(1 << (bit))
#define E0 ((variable) & _BV(0)) #define set_E0 (variable | = _BV(0)) #define clr_E0 (variable &= ~_BV(0))
Test sobre el bit 0
INICIALIZACIÓN DE REGISTROS PARA LOS DIFERENTES RECURSOS Timer 0 como temporizador TCCR0=(1<
//Escala 1024 //Inicializa el temporizador
Timer 0 como contador TCCR0=(1<
//Contador por flanco de subida
Timer 0 como comparador OCR0=128; TCCR0=(1<
Timer 1 como temporizador TCCR1B=(1<
//Escala 64 //Inicializa el temporizador
Timer 1 como contador TCCR1B=(1<
//Contador por flanco de subida
Timer 1 como comparador OCR1A=256; TCCR1A=(1<
//Salida cambia de estado //Escala 8 cambio cada 256us (OCR1A)
Timer 1 como PWM fase correcta de 10 bits OCR1A=256; TCCR1A=(1<
//Escala 8 periodo 2048 ciclos con 8M = 2048us
Timer 2 como temporizador TCCR2=(1<
//Escala 1024 //Inicializa el temporizador
Timer 2 como comparador OCR2=128; TCCR2=(1<
//Salida cambia de estado
Timer 2 como PWM OCR2=128; TCCR2=(1<
//Salida cambia de estado
Timer 2 como contador con oscilador externo TCCR2=(1<
EJEMPLO DE INICIALIZACIÓN DE INTERRUPCIONES Desbordamiento del TMR0 ISR(TIMER0_OVF_vect) { TCNT0=T0_INI; frac++; if(frac>=10) { segundos++; frac=0; PORTA=PORTA ^(1<<2); } } TIMSK= (1<
//Habilita interrupción por desbordamiento TMR0 Desbordamiento del TMR1
ISR(TIMER1_OVF_vect) { TCNT1=T1_INI;
}
frac++; if(frac>=10) { segundos++; frac=0; PORTA=PORTA ^(1<<2); }
TIMSK= (1<
//Habilita interrupción por desbordamiento TMR1
Desbordamiento del TMR2 ISR(TIMER2_OVF_vect) { TCNT2=T2_INI;
}
frac++; if(frac>=10) { segundos++; frac=0; PORTA=PORTA ^(1<<2); }
TIMSK= (1<
//Habilita interrupción por desbordamiento TMR2