PROGRAMAS CONVERSION EN C Muchos microcontroladores más nuevos tienen un reloj en tiempo real (RTC), donde se guardan la fecha y hora, incluso cuando el equipo e stá apagado. Muy a menudo la RTC ofrece la fecha y hora en BCD empaquetado. Para visualizarlos, sin embargo, hay que convertirlos a ASCII. En esta sección se m uestra la aplicación de la lógica y las instrucciones de rotación utilizadas en la conversión de BCD BCD y ASCII.
Números ASCII En los teclados ASCII, cuando el "0" es presionado, la computadora proporciona el valor "0011 0000" (0x30). Similarmente proporciona proporciona el 0x31 (0011 0001) para la tecla "1", y así sucesivamente, como se muestra a continuación:
Código ASCII de los dígitos 0-9 Tecla ASCII (hex) 0x30 O 1 0x31 2 0x 32 3 0x 33 4 0x 34 5 0x 35 6 0x 36 7 0x 37 8 0x 38 9 0x 39
Binario 011 0000 011 0001 011 0010 011 0011 011 0100 011 0101 011 0110 011 0111 011 1000 011 1001
BCD (desempaquetado) 00000000 00000001 00000010 00000011 00000100 00000101 00000110 00000111 0000 1000 0000 1001
Conversión de BCD empaquetado a ASCii El RTC ofrece la hora del día (hora, minuto, segundo) y la fecha (año, mes, día) d e forma continua, independientemente de si la alimentación está encendida o apagada. Estos datos se proporcionan en BCD empaquetado. Para convertir de BCD empaquetado a ASCII, primero debe convertir a BCD desempaquetado. Entonces, el BCD desempaquetado desempaquetado se etiqueta con 011 0000 (0x30). Lo siguiente muestra la conversión de BCD empaquetado a ASCII. BCD empaquetado
BCD desempaquetado
ASCII
0x29
0x02, 0x09
0x32, 0x39
00101001
00000010,00001001
00110010,00111001
Converslon ASCII a BCD empaquetado Para convertir ASCII a BCD empaquetado, primero debe convertir a BCD desempaquetado (para deshacerse del 3), y luego combinar los números para hacer BCD empaquetado. empaquetado. Por ejemplo, 4 y 7 en el teclado da 0x34 y 0x37, respectivamente. El objetivo es producir 0x 47 o "01000111", que está en BCD e mpaquetado.
Tecla
ASCII
BCD desempaquetado
4
0x34
00000100
7
0x37
00000111
BCD empaquetado 01000111 or 0x47
Escribir Un programa para convertir BCD a ASCII 0x29 y mostrar los bytes en PORTB y PORTC #include
int main (void) { unsigned char x, y; unsigned char mybyte=0x29; DDRB = DDRC = 0xFF; // Puertos B y C como salidas x = mybyte & 0x0F; //enmascara los 4 bits superiores PORTB = x | 0x30; //forma un ASCII y = mybyte & 0xF0; // enmascara los 4 bits inferiores y = y >> 4; // desplaza los 4 bits inferiores PORTC = y | 0x30; // forma un ASCII while(1); return 0; } Escribir un programa en C para convertir dígitos ASCII '4' y '7' a BCD empaquetados y mostrarlos en PORTB. #include int main (void) { unsigned char bcdbyte; unsigned char w='4'; unsigned char z = '7'; DDRB = 0xFF; // Puerto B como salida w =w & 0x0F; //enmascara los 4 bits superiores para eliminar el 3 w = w << 4; //desplaza los 4 bits superiores para crear digito BCD z = z & 0x0F; //enmascara los 4 bits superiores para eliminar el 3 bcdbyte = w | z; //combina para hacer el BCD empaquetado PORTB = bcdbyte; while(1); return 0; }
Suma de comprobación de byte en ROM Para asegurar la integridad de los datos, cada sistema debe realizar el cálculo de suma de comprobación. Al transmitir datos de un dispositivo a otro, o al guardar y restaurar los datos a un dispositivo de almacenamiento se debe realizar el cálculo de la suma de comprobación para asegurar la integridad de los datos. La suma de comprobación detectara cualquier alteración de los datos. Para asegurar la integridad de los datos, el proceso de suma de comprobación utiliza lo que se llama control de suma de comprobación de un byte. La suma de comprobación de un byte es un byte adicional que se fija en el extremo de una serie de bytes de datos. Para calcular el byte de suma de comprobación de una se rie de bytes de datos, los pasos siguientes pueden ser tomados:
1. Sume todos los bytes juntos y no tome en cuenta el acarreo. 2. Tome el complemento a 2 d e la suma total. Este es el byte de suma de comprobación, que se convierte en el último byte de la serie. Para realizar la operación de suma de comprobación, se suman todos los bytes, incluyendo el byte de suma de comprobación. El resultado debe ser cero. Si no es cero, uno o más bytes de datos han sido cambiados (dañado). Ejemplo : Supongamos que disponemos de 4 bytes de datos hexadecimales: 0x25, 0x62, 0x52H y 0x3F. (a) Determinar el byte de suma de comprobación, (b) realizar la operación de suma de verificación para garantizar la integridad de los datos, y (c) S i el segundo byte, 0x62, se ha cambiado a 0x22, muestre cómo la suma de comprobación detecta el error. Solución: (a) Encuentre el byte de suma de comprobación. 0x25 +
0x62
+
0x3f
+
0x52
Suma total Complemento a dos
1 0x18 (no tomando en cuenta el acarreo) 0xE8
(b) Realizamos la suma de comprobación para detectar la integridad de los datos 0x25 +
0x62
+
0x3f
+
0x52
+
0xE8 2 0x00(no tomando en cuenta el acarreo) (c) Si el segundo byte 0x62 es cambiado por 0x22, muestre como la suma de comprobación detecta el error. 0x25
+
0x22
+
0x3f
+
0x52
+
0xE8 1 0xC0 (no tomando en cuenta el acarreo da 0x C0, s ignifica que la data esta corrupta)
Escriba un programa C de para calcular la suma de comprobación de bytes de los datos correspondientes al ejemplo anterior. #include int main(void) unsigned char mydata[] ={ 0x2 5, 0x62, 0x3F, 0x52} ; unsigned char sum = 0; unsigned char X; unsigned char chksumbyte; DDRD=DDRB=DDRC = 0xFF; //Port D , Port B y Port C son salidas for(x=0; x<4; x++) { PORTD mydata[x] ; //enviar cada byte al PORTA sum = sum + mydata[ xl ; //sumarlos juntos PORTB = sum; //enviar la suma al PORTB } chksumbyte = ~sum + 1; //Complemento a dos PORTC = chksumbyte; // enviar la suma de comprobación al PortC while(1); return 0; } Escriba un programa en C para realizar el paso de chequeo del ejemplo anterior. Si el datos bueno, envía carácter ASCII 'G' al PORTD. En caso contrario, enviar 'B' a PORTD. #include int main(void) unsigned char mydata[] ={ 0x2 5, 0x62, 0x3F, 0x52,0xE8} ; unsigned char checksum = 0; unsigned char X; DDRA = 0xFF; //PortD salidas for(x=0; x<5; x++) checksum=checksum + mydata[x] ; if (checksum == 0) PORTD = 'G'; else PORTD = 'B'; while(1); return 0; } Cambie uno o dos valores de la matriz mydata y simular el programa para ver los resultados.
Conversión de Binario (hex) a decimal y ASCII en C La función printf es parte de la biblioteca estandar l/O en C y puede hacer muchas cosas, incluyendo la conversión de datos binarios (hex) a decimal, o viceversa. Pero printf toma mucho espacio en la memoria y aumenta el hex sustancialmente. Por esta razón, en los sistemas basados en el microcontrolador AVR, es mejor saber cómo escribir nuestra propia función de conversión en vez de usar printf Una de las conversiones más ampliamente utilizadas es la conversión binario a decimal. En dispositivos tales como ADCs (analógico-a-digital), los datos se proporcionan al microcontrolador en binario. En algunos RTCs, la hora y la fecha también se proporcionan en binario. Con el fin de mostrar datos binarios, tenemos que convertirlo a decimal y luego a ASCII. Debido a que el formato hexadecimal es una manera conveniente de representar datos binarios, se refieren a los datos binarios como hexadecimal, datos binarios 00-0xFF convertido a decimal nos da 000 a 255. Una forma de hacerlo es dividimos por 10 y guardamos el resto. Por ejemplo, 11111101 o 0xFD es 253 en decimal. La siguiente es una versión de un algoritmo para la conversión de hex (binario) a decimal:
Hex
Cociente
Resto
FD/OA
19
3 (digito bajo) LSD
19/0A
2
5 (digito medio) 2 (digito alto) (MSD)
Escribir un programa C para convertir 11111101 (hex FD) a decimal y mostrar los dígitos en PORTB, PORTC, y PORTD. #include int main(void) unsigned char x, binbyte, d1, d2, d3; DDRB = DDRC = DDRD =0xFF; //Ports B, C, y D salidas binbyte = 0xFD; // byte binario (hex) x = binbyte / 10; //divide por 10 d1= binbyte % 10; //obtiene el resto de la division (LSD) d2 = x % 10; // digito medio d3 = x/10; // digito mas significativo (MSD) PORTB d1; PORTC d2; PORTD d3; while(1); Return 0; }
Muchos compiladores tienen algunas funciones predefinidas para convertir tipos de datos. En la siguiente Tabla se puede ver algunas de ellas. Para utilizar estas funciones, el archivo stdlib.h deben ser incluido. Tenga en cuenta que estas funciones pueden variar en diferentes compiladores. TabIa: Funciones de conversión de tipos de datos e n C
Funciones int atoi (char * str) long atoi (char * str) void itoa (int n, char * str) void ltoa (int n, char * str) float atof (char * str)
Descripción de la función Convierte la cadena str a un entero. Convierte la cadena str a entero largo . Convierte el número entero n a una cadena de caracteres str. Convierte el numero entero largo n a cadena de caracteres str. Convierte los caracteres de la cadena str a un valor flotante.
SERIALlZACION DE DATOS EN C
Serializar datos es una forma de enviar un byte de datos un bit a la vez a través de un único pin de un microcontrolador. Hay dos maneras de transferir un byte de datos e n serie: l. Usando el puerto serie. En el uso del puerto serie, el programador tiene un control muy limitado sobre la secuencia de transferencia de datos. Los detalles del puerto serie del AVR y la transferencia de datos se discuten mas adelante. 2. El segundo método de serialización de datos es la transferencia de datos un bit de una vez y controlar la secuencia de datos y espacios entre e llos. En muchas nuevas generaciones de dispositivos tales como LCD, ADC, y EEPROM, las versiones serie están llegando a ser popular debido a que ocupan menos e spacio en una placa de circuito 2
impreso. Aunque podemos utilizar estándares como I C, SPI y CAN, no todos los dispositivos son compatibles con dichas normas. Por esta razón tenemos que estar familiarizado con la serialización de datos utilizando el lenguaje C. Examine los siguientes cuatro ejemplos para ver cómo la serialización de datos se hace en C.
Escribir un programa para enviar el valor 0x44 en serie, un bit a la vez a través PORTC, pin 3. El LSB debería ir en primer lugar. #include #define serPin 3 int main(void) { unsigned char conbyte = 0x44; unsigned char regALSB; unsigned char x; regALSB = conbyte; DDRC |= (1<>1; } while(1); return 0; } Escriba un programa en C para enviar el valor 0x44 serialmente un bit a la vez vía PORTC, pin3. El bit MSB debe ir en primer lugar. #include #define serPin 3 int main(void) { unsigned char conbyte = 0x44; unsigned char regALSB; unsigned char x; regALSB = conbyte; DDRC |= (1<
Escriba un programa C para obtener a un byte de datos en serie un bit a la vez a través de PORTC, pin 3. El LSB debe venir primero. #include #define serPin 3 int maín (void) { unsigned char x; unsigned char REGA=0; DDRC &= ~(1<> 1;
//desplaza REGA hacia la derecha un bit
REGA |= (PINC & (1<
//del PORTC al MSB de REGA.
while(1); return 0; } Escriba un programa C para obtener a un byte de datos en serie un bit a la vez a través de PORTC, pin 3. El MSB debe venir primero. #include #define serPin 3 int maín (void) { unsigned char x; unsigned char REGA=0; DDRC &= ~(1<
//desplaza REGA hacia la izquierda un bit
REGA |= (PINC & (1<> serPin; //copia el bit en el pin serPin }
//del PORTC al LSB de REGA.
while(1); return 0; }
Para adaptarlos a la realidad estos programas deberían te ner unos retardos para la lectura o escritura del pin.
ASIGNACIÓN DE MEMORIA EN C Usando el espacio de programa (código) para datos predefinidos fijos es una opción muy utilizada en el AVR y en los microcontroladores. Veremos cómo utilizar los programas en lenguaje C para acceder a los datos almacenados en la memoria ROM.
Espacio de datos en Flash, RAM y EEPROM del AVR En el AVR tenemos tres espacios en que se almacenan los datos. Son los siguientes: 1. Los bytes del espacio en SRAM de 64K tienen un rango de dirección de 0000-0xFFFF. Como hemos visto en antes, muchos de los chips de AVR tienen menos de 64K bytes para la SRAM. 2. El espacio de programas (código). Este espacio en la ROM Flash del chip se utiliza para almacenamiento de los programas(opcodes) y por lo tanto esta directamente bajo el control del contador programa (PC). 3. El espacio de EEPROM. Este espacio puede guardar los datos c uando el equipo está apagado. Es por eso que utilizamos EEPROM para guardar variables que no debe perderse cuando el equipo está apagado. Por ejemplo, el punto de ajuste de temperatura de un sistema de enfriamiento debe ser cambiado por los usuarios y no se puede almacenar en el espacio de programa. Asimismo, se deben guardar cuando el equipo está apagado, por lo que se le coloca en la EEPROM. Además, cuando no hay suficiente espacio de código, podemos colocar las variables permanentes en EEPROM para ahorrar espacio de código.
Tamaño (Bytes) de memoria para algunos miembros de la familia ATmega Flash SRAM EEPROM 8K
256
256
16K
1K
512
32K
2K
1K
64K
4K
2K
128K
8K
4K
Vamos a mostrar cómo leer o escribir desde y hacia la EE PROM mediante programación C. Se debe tomar en cuenta que los diferentes compiladores de C tienen sus funciones incorporadas o directivas para acceder a cada tipo de memoria. En CodeVision, para definir una variable const en la memoria Flash, sólo tiene que poner la directiva Flash antes de ella. Además, para definir una variable en la memoria EEPROM, puede poner la directiva eeprom delante : Flash unsigned char myNum [] = "Hola"; // usar espacio código Flash eeprom unsigned char = 7;// utilizar el espacio EEPROM Escriba un programa en C para almacenar 'G' en la ubicación de EEPROM 0x005F. #include int main(void) { while(EECR & (1<
// espera a que termine la escritura anterior
EEAR = 0x5f;
//Coloca la direccion en el registro de direccion
EEDR = 'G';
//Coloca el dato en el registro de datos
EECR |= (1<
//Arranca la escritura en la EEPROM
Escriba un programa en C para leer el contenido de la ubicación 0x005F de EEPROM en el PORTB. #include int main(void) { DDRB = 0xFF; while(EECR & (1<
// espera a que termine la escritura anterior
EEAR = 0x5f;
//Coloca la dirección en el registro de dirección
EECR |= (1<
//Inicia la lectura de la EEPROM escribiendo en EERE
PORTB= EEDR ;
//Mueve el dato desde el registro de datos al puerto B
while(1); return 0; }