Programacion en C 2da Parte
Click here to load reader
Transcript of Programacion en C 2da Parte
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 está 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 muestra la aplicación de la lógica y las instrucciones de rotación
utilizadas en la conversión de 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 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) Binario BCD (desempaquetado)
O 0x30 011 0000 00000000
1 0x31 011 0001 00000001
2 0x 32 011 0010 00000010
3 0x 33 011 0011 00000011
4 0x 34 011 0100 00000100
5 0x 35 011 0101 00000101
6 0x 36 011 0110 00000110
7 0x 37 011 0111 00000111
8 0x 38 011 1000 0000 1000
9 0x 39 011 1001 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) de 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 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. 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 empaquetado.
Tecla ASCII BCD desempaquetado BCD empaquetado
4 0x34 00000100
7 0x37 00000111 01000111 or 0x47
Escribir Un programa para convertir BCD a ASCII 0x29 y mostrar los bytes en PORTB y PORTC
#include <avr/io.h>
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 <avr/io.h>
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 serie 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 de 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) Si 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 1 0x18 (no tomando en cuenta el acarreo)
Complemento a dos 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, significa 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 <avr/io.h>
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 <avr/io.h>
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 <avr/io.h>
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 en C
Funciones Descripción de la función
int atoi (char * str) Convierte la cadena str a un entero.
long atoi (char * str) Convierte la cadena str a entero largo .
void itoa (int n, char * str) Convierte el número entero n a una cadena de caracteres str.
void ltoa (int n, char * str) Convierte el numero entero largo n a cadena de caracteres str.
float atof (char * 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 en 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 ellos. 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 espacio en una placa de circuito
impreso. Aunque podemos utilizar estándares como I2C, 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 <avr/io.h>
#define serPin 3
int main(void) {
unsigned char conbyte = 0x44;
unsigned char regALSB;
unsigned char x;
regALSB = conbyte;
DDRC |= (1<<serPin);
for(x=0;x<8;x++) {
if(regALSB & 0x01)
PORTC |= (1<<serPin);
else
PORTC &= ~(1<<serPin);
regALSB = regALSB >>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 <avr/io.h>
#define serPin 3
int main(void) {
unsigned char conbyte = 0x44;
unsigned char regALSB;
unsigned char x;
regALSB = conbyte;
DDRC |= (1<<serPin);
for(x=0;x<8;x++) {
if(regALSB & 0x80)
PORTC |= (1<<serPin);
else
PORTC &= ~(1<<serPin);
regALSB = regALSB <<1;
}
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 LSB debe venir primero.
#include <avr/io.h>
#define serPin 3
int maín (void) {
unsigned char x;
unsigned char REGA=0;
DDRC &= ~(1<<serPin); //serPin es una entrada
for(x=0; x<8; x++) //repite para cada bit de REGA
{
REGA = REGA >> 1; //desplaza REGA hacia la derecha un bit
REGA |= (PINC & (1<<serPin))<< (7-serPin); //copia el bit en el pin serPin
} //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 <avr/io.h>
#define serPin 3
int maín (void) {
unsigned char x;
unsigned char REGA=0;
DDRC &= ~(1<<serPin); //serPin es una entrada
for(x=0; x<8; x++) //repite para cada bit de REGA
{
REGA = REGA << 1; //desplaza REGA hacia la izquierda un bit
REGA |= (PINC & (1<<serPin)) >> 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 tener 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 cuando 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 EEPROM 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 <avr/io.h>
int main(void) {
while(EECR & (1<<EEWE)); // 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<<EEMWE);
EECR | = (1<<EEWE) ; //Arranca la escritura en la EEPROM
while(1);
return 0;
}
Escriba un programa en C para leer el contenido de la ubicación 0x005F de EEPROM en el
PORTB.
#include <avr/io.h>
int main(void) {
DDRB = 0xFF;
while(EECR & (1<<EEWE)); // espera a que termine la escritura anterior
EEAR = 0x5f; //Coloca la dirección en el registro de dirección
EECR |= (1<<EERE); //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;
}