PicManía by RedRaven |
![]()
Búsqueda personalizada
|
TÉCNICAS EN C |
||
|
Esta serie de contenidos titulada Técnicas en C pretende mostrar con ejemplos comentados la forma de implementar ciertos procesos muy usuales durante el uso de los Microcontroladores PIC de las series 16F y 18F. |
|
|
Librería de Funciones "Útiles" |
|
A.- Un poco de Teoría: |
Utilizando una
Librería de Funciones "Útiles" en CCS C |
![]() |
Por lo demás ambas formas de citar al
fichero a incluir son exactamente iguales. 2º.- Otro concepto que tenemos que aplicar es el de la precedencia en C. En este lenguaje, como en todos los estructurados, es fundamental el hecho de tener que declarar cualquier cosa antes de poder usarla. De esta forma solo podremos usar un función en nuestro programa si, y solo si, el compilador conoce la función antes de usarla. Hay que tener en cuenta que el compilador va a recorrer, compilando, nuestro programa de arriba a abajo, siendo la parte superior la que primero se compila y la inferior la última en serlo. Así si en nuestro main() utilizamos una función ésta debe estar colocada antes del main() para que pueda ser compilada, en otro caso el compilador nos lanzará un error indicándonos que dicha función no está declarada. Este caso compilaría perfectamente ya que al utilizar en main() la función miFuncion() ha sido desarrollada antes de llegar allí el compilador y por lo tanto "la conoce" antes de usarla: |
int8 miFuncion(void){ return 100 } void main(void){ int8 n; n = miFuncion(); } |
||
Y sin embargo éste no lo haría ya que al compilar main() el compilador no sabría qué es miFuncion() al estar desarrollada después de ser usada: |
void main(void){ int8 n; n = miFuncion(); } int8 miFuncion(void){ return 100 } |
||
La solución a éste último caso sería o mover miFunción() para colocarla antes del main(), que es lo que teníamos en el ejemplo anterior, o mejor aún: Declararla, colocando su prototipo antes del mismo y podríamos así dejar su desarrollo donde quisiésemos. Esto lo haríamos de la siguiente forma: |
int8 miFuncion(void); void main(void){ int8 n; n = miFuncion(); } int8 miFuncion(void){ return 100 } |
||
Fijaos en que solo he
puesto una línea exactamente igual que la que describe mi función pero sin
desarrollarla, sin poner qué hace la función por dentro, solo qué
parámetros recibe la función y qué devuelve la misma. |
// Cabecera ////////////// int8 miFuncion(void); // Fin de Cabecera //////// // Main /////////////////// void main(void){ int8 n; n = miFuncion(); } // Fin de Main //////////// // Desarrollo ///////////// int8 miFuncion(void){ return 100 } // Fin de Desarrollo ////// |
||
Nos vamos acercando a nuestro objetivo ... |
#include "Lib_utils.h" // Main //////////////////////// void main(void){ int8 n; n = miFuncion(); } // Fin de Main ///////////////// #include "lib_utils.c" |
||
Esta forma de escribirlo es
exactamente igual que la anterior, el compilador va a recorrer las mismas
líneas de código en el mismo orden generando exactamente el mismo código
objeto compilado. La única diferencia entre ellos es que el compilador ha
tenido que unir las distintas líneas de código contenidas en los distintos
ficheros mediante los #include antes de compilar. |
/** \file lib_Utils.h * \brief Este fichero contiene las cabeceras necesarias para * el manejo de la Librería de Utilidades * * * \author (c) 08.2008 by RedPic */ // Prototipos de funciones int8 bin_to_bcd(int8 binary_value); int8 bcd_to_bin(int8 bcd_value); void int8_to_bits_string(int8 val,char* pF); int8 bits_string_to_int8(char* pF); int1 get_bit_in_byte(int8 byte_for_bits, int8 pbit); int8 set_bit_in_byte(int8 byte_for_bits, int1 vbit, int8 pbit); void fill_end_with_char(char c, int8 maxlen,char* pF); int8 str_to_int8(char* pF); void decode_timestamp(char *pF, int8 &day, int8 &mth, int16 &year, int8 &hr, int8 &min, int8 &sec); void encode_timestamp(char *pF, int8 day, int8 mth, int16 year, int8 hr, int8 min, int8 sec); void replace_char(char c, char p, char* pF); int8 ascii_to_hex(char d); int8 hex_to_int8(char* pF); int16 hex_to_int16(char* pF); int32 hex_to_int32(char* pF); void right_trim(char* pF); int1 are_all_char_code_printable(char *pF); void insert_char_in_string_in_position(char *pF, char c, int8 position, int8 len); /////////////////////////////////////////////////////////////////////////////////////////////////// // // end of lib_Utils.h // /////////////////////////////////////////////////////////////////////////////////////////////////// |
||
lib_utils.c |
/** \file lib_utils.c * \brief Este fichero contiene un compendio de funciones de utilidad varia. * * \author (c) 08.2008 by RedPic */ /** \brief Función auxiliar que convierte de \c BIN a \c BCD * * \param binary_value Valor binario a convertir. * \return Valor BCD convertido. */ int8 bin_to_bcd(int8 binary_value){ int8 temp; int8 retval; temp = binary_value; retval = 0; while(1){ if(temp >= 10){ temp -= 10; retval += 0x10; }else{ retval += temp; break; } } return(retval); } /** \brief Función auxiliar que convierte de \c BCD a \c BIN * * \param bcd_value Valor BCD a convertir. * \return Valor Binario convertido. */ int8 bcd_to_bin(int8 bcd_value){ int8 temp; temp = bcd_value; temp >>= 1; temp &= 0x78; return(temp + (temp >> 2) + (bcd_value & 0x0f)); } /** \brief Función que convierte un Byte (de 8 bits) a bits string ASCII. * * Convierte un Byte (de 8 bits) a string ASCII terminado en NULL (\\0). * * \param val Valor del Byte a convertir. * \param[out] pF Puntero a string_null_ended. * * \return void */ void int8_to_bits_string(int8 val,char* pF){ int8 i,j; for(i=0,j=7;i<8;i++,j--){ pF[i]=bit_test(val,j)+'0'; } pF[8]='\0'; } /** \brief Función que convierte un bits string ASCII a un Byte (de 8 bits). * * Convierte un string ASCII terminado en NULL (\\0) a Byte (de 8 bits). * * \param pF Puntero a string_null_ended. * * \return int8 Valor convertido. */ int8 bits_string_to_int8(char* pF){ int8 i,j,ret=0; for(i=0,j=7;i<8;i++,j--){ if(pF[i]=='1'){ bit_set(ret,j); } } return ret; } /** \brief Función que lee el valor de un bit del byte en la posición dada \c pbit. * * Lee un Bit en la posición \c pbit del Byte. * \param byte_for_bits Byte contenedor de los bits. * \param pbit Posición en el Byte del bit a leer. * \return bit leído. */ int1 get_bit_in_byte(int8 byte_for_bits, int8 pbit){ int1 r; r=bit_test(byte_for_bits,pbit); return r; } /** \brief Función que guarda un bit de valor \c vbit en el Byte en la posición dada \c pbit. * * Guarda un bit de valor \c vbit en la posición \c pbit del Byte dado. * \param byte_for_bits Puntero al Byte contenedor de bits. * \param vbit Valor del bit a escribir. * \param pbit Posición en el Byte del bit a escribir. * \return byte con el bit cambiado. */ int8 set_bit_in_byte(int8 byte_for_bits, int1 vbit, int8 pbit){ bit_clear(byte_for_bits,pbit); if(vbit==1) bit_set(byte_for_bits,pbit); return byte_for_bits; } /** \brief Función que rellena con un caracter dado un string a partir de NULL hasta una longitud dada. * * \param c Carácter de relleno. * \param maxlen Longitud máxima del string. * \param[out] pF Puntero a string_null_ended a rellenar. * * \return void */ void fill_end_with_char(char c, int8 maxlen,char* pF){ int8 i; int1 start=0; for(i=0;i<maxlen;i++){ if(start==0){ if(pF[i]=='\0'){ start=1; } } if(start==1){ pf[i]=c; } } pF[maxlen]='\0'; } /** \brief Función que convierte un string numérico decimal ASCII NULL-END a su valor entero (8 bits). * * \param pF Puntero al buffer que contiene el string numérico ASCII. * * \return int8 Valor numérico. */ int8 str_to_int8(char* pF){ int8 ret=0,i,l,m=1; l=strlen(pF)-1; for(i=l;i<255;i--){ if(isdigit(pF[i])){ ret+= m * (pF[i]-'0'); m = m * 10; } else break; } //printf("StrToInt %s (%u)\r\n",pF,ret); return ret; } /** \brief Función decodifica una variable TimeStamp extrayendo sus componentes. * * Acepta una variable TimeStamp y devuelve valores enteros de Año, Mes, Día, Hora, Minuto, y Segundo. * \param pF Puntero a string TimeStamp * \param[out] day Dia * \param[out] mth Mes * \param[out] year Año (4 dígitos, int16) * \param[out] hr Hora * \param[out] min Minuto * \param[out] sec Segundo * \see encode_timestamp() */ void decode_timestamp(char *pF, int8 &day, int8 &mth, int16 &year, int8 &hr, int8 &min, int8 &sec){ char sval[]="00"; sval[2]='\0'; sval[0]=pF[2]; sval[1]=pF[3]; year= 2000+str_to_int8(sval); sval[0]=pF[5]; sval[1]=pF[6]; mth = str_to_int8(sval); sval[0]=pF[8]; sval[1]=pF[9]; day = str_to_int8(sval); sval[0]=pF[11]; sval[1]=pF[12]; hr = str_to_int8(sval); sval[0]=pF[14]; sval[1]=pF[15]; min = str_to_int8(sval); sval[0]=pF[17]; sval[1]=pF[18]; sec = str_to_int8(sval); } /** \brief Función codifica una variable TimeStamp dando sus componentes. * * Acepta variables de valores enteros de Año, Mes, Día, Hora, Minuto, y Segundo y devuelve puntero a variable de tipo Timestamp. * \param[out] pF Puntero a string TimeStamp * \param day Dia * \param mth Mes * \param year Año (4 dígitos, int16) * \param hr Hora * \param min Minuto * \param sec Segundo * \see encode_timestamp() */ void encode_timestamp(char *pF, int8 day, int8 mth, int16 year, int8 hr, int8 min, int8 sec){ sprintf(pF,"%Lu-%2u-%2u_%2u:%2u:%2u\0",year,mth,day,hr,min,sec); replace_char(' ','0',pF); replace_char('_',' ',pF); } /** \brief Reemplaza carácter en string null-terminated. * * \param c Carácter a sustituir. * \param p Carácter nuevo a insertar. * \param[out] pF Puntero a string null-terminated. * * \return void */ void replace_char(char c, char p, char* pF){ int8 i; char x; x=pF[0]; for(i=0;i<255,x!='\0';i++){ x=pf[i]; if(x==c){ pF[i]=p; } } } /** \brief Función que convierte un carácter Hexadecimal ASCII NULL-END a su valor entero de 8 bits. * * \param d Caracter Hexadecimal a convertir. * * \return int8 Valor numérico. */ int8 ascii_to_hex(char d){ int r=0x00; if(isxdigit(d)){ if(isdigit(d)){ r=d-'0'; } if(isalpha(d)){ d=toupper(d); r=10+(d-'A'); } } return(r); } /** \brief Función que convierte un string numérico Hexadecimal ASCII NULL-END a su valor entero de 8 bits. * * \param pF Puntero al buffer que contiene el string numérico ASCII Hexadecimal de 2 digitos (00h a FFh). * * \return int8 Valor numérico. */ int8 hex_to_int8(char* pF){ int8 i,ret; ret=0; for(i=1;i!=255;i--){ ret+=ascii_to_hex(pF[i])*((15*(1-i))+1); } return ret; } /** \brief Función que convierte un string numérico Hexadecimal ASCII NULL-END a su valor entero de 16 bits. * * \param pF Puntero al buffer que contiene el string numérico ASCII Hexadecimal de 4 digitos (0000h a FFFFh). * * \return int16 Valor numérico. */ int16 hex_to_int16(char* pF){ int8 i, p2, p1; int16 ret; p1=hex_to_int8(&pF[2]); p2=hex_to_int8(&pF[0]); ret=make16(p2,p1); //printf("hex_to_int16 recibe: %s p2: %LX p1 %LX valor: %LX (%Lu)\r\n",pF,p2,p1,ret,ret); return ret; } /** \brief Función que convierte un string numérico Hexadecimal ASCII NULL-END a su valor entero de 32 bits. * * \param pF Puntero al buffer que contiene el string numérico ASCII. * * \return int32 Valor numérico. */ int32 hex_to_int32(char* pF){ int32 ret; int16 p1,p2; p1=hex_to_int16(&pF[4]); p2=hex_to_int16(&pF[0]); ret = make32(p2, p1); //printf("hex_to_int32 recibe: %s p2: %LX p1 %LX valor: %LX (%Lu)\r\n",pF,p2,p1,ret,ret); return ret; } /** \brief Función que descarta los espacios en blanco por la derecha de una cadena. * * \param[out] pF Puntero a string_null_ended a procesar. * * \return void */ void right_trim(char* pF){ int8 i,L; for(i=0;i<255;i++){ if(pF[i]=='\0'){ L=i-1; break; } } for(i=L;i>0;i--){ if(pF[i]==' '){ pF[i]='\0'; } else{ break; } } } /** \brief Comprueba si todos los caracteres del string NULL-Terminated son imprimibles ('0'..'9','A'..'Z' ó ' ') y hay al menos uno. * * \param pF Puntero al string a investigar. * * \return int1 1 si todos los carácteres son válidos, 0 en caso contrario. */ int1 are_all_char_code_printable(char *pF){ int1 ret=1; int8 i; for(i=0;i<255;i++){ if(pF[i]=='\0'){ break;} if(!isdigit(pF[i]) && !isupper(pF[i]) && pF[i]!=' ') ret=0; } if(i==0) ret=0; return ret; } /** \brief Función que inserta un caracter en un string. * */ void insert_char_in_string_in_position(char *pF, char c, int8 position, int8 len){ int8 i; char tmp1,tmp2; for(i=0;i<len;i++){ if(i>position){ tmp2=pF[i]; pf[i]=tmp1; tmp1=tmp2; } if(i==position){ tmp1=pF[i]; pF[i]=c; } } } /////////////////////////////////////////////////////////////////////////////////////////////////// // // End of lib_utils // /////////////////////////////////////////////////////////////////////////////////////////////////// |
||
Que es lo que queríamos conseguir, una librería de funciones útiles lista para usar. |
A.- Un poco de Práctica: Un ejemplo. |
Con todo lo descrito
anteriormente he realizado un par de programas main absolutamente idénticos
salvo que cada uno de ellos llama a una función distinta de nuestra librería
de utilidades. |
void main() { printf("\r\nLibrerias de Funciones Main 1\r\n"); printf("By Redpic para Foro TODOPIC\r\n"); printf("Recibe CHAR y convierte a BINARIO\r\n\n"); recFlag=0; // Desactivo el Flag de Recepción enable_interrupts(int_rda); // Habilito la interrpción INT_RDA enable_interrupts(global); // Habilito las interrupciones do { if(recFlag==1){ recFlag=0; int8_to_bits_string(rec,respuesta); printf("Recibido : %c En bits : %s\r\n",rec,respuesta); } } while (TRUE); } |
||
![]() |
Y el otro recibe los mismos caracteres pero los trata como hexadecimales convirtiéndolos a decimal: |
void main() { printf("\r\nLibrerias de Funciones Main 2\r\n"); printf("By Redpic para Foro TODOPIC\r\n"); printf("Recibe HEX y convierte a INT8\r\n\n"); recFlag=0; // Desactivo el Flag de Recepción enable_interrupts(int_rda); // Habilito la interrpción INT_RDA enable_interrupts(global); // Habilito las interrupciones do { if(recFlag==1){ recFlag=0; tmp[1]=toupper(rec); respuesta = hex_to_int8(tmp); printf("Recibido HEX : %c En Decimal : %u\r\n",rec,respuesta); } } while (TRUE); } |
||
![]() |
La diferencia entre ellos se muestra
claramente al comparar entre si los dos códigos ASM generados por el
compilador, en el uno solo ha sido compilada la función void int8_to_bits_string(int8
val,char* pF); y en el otro por el contrario solo lo ha sido la función int8
ascii_to_hex(char d); En el siguiente fichero ZIP tenéis ambos main, la librería completa y los ASM generados para que podáis ver la diferencia entre ambos: Descargar Técnicas en C : Usando librerías de funciones.zip |
Esta página se modificó el 27/12/2008
|