Autor Tema: Para que sirven los ".h"???  (Leído 19045 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado Marttyn

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1835
    • IDEAA
Para que sirven los ".h"???
« en: 04 de Febrero de 2008, 14:35:40 »
hola! hace "bastante" que uso CCS y la verdad nunca me habia preguntado esto... pero, cada vez que creo un nuevo proyecto se crean varios archivos, entre ellos el ".c" donde va el programa, y un ".h" donde especifica que tipo de micro es, los fuses y alguna otra cosilla mas...
lo que hago siempre es eliminar ese archivo y poner el codigo en el programa, porque no se que utilidad tiene que este en un archivo separado.
hoy empezando un nuevo proyecto me plantee la pregunta, y asocie el tema con los includes de librerias especificas. por ejemplo, para controlar una memoria serial hay una libreria para eso, y esta bien que este "sola" dentro de un archivo. supongo que el ".h" que se crea podria ser para algo similar, como poder usar el mismo codigo con otro micro solo cambiando la cabecera... pero eso no lo veo posible, ya que en el main se configuran todos los modulos del pic, y estos varian de uno a otro...
entonces solo se que no se nada...  :mrgreen:
alguno podria explicarme un poquillo para que sirve esto o remitirme a donde considere oportuno?
salu2 y Kgracias (mil gracias  :D :D :D :D)!
La gente ve las cosas que existen y se pregunta por qué.
Yo prefiero imaginar lo que no existe y preguntarme por qué no.

Desconectado MGLSOFT

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 7912
Re: Para que sirven los ".h"???
« Respuesta #1 en: 04 de Febrero de 2008, 17:04:15 »
El archivo .h es un archivo de cabecera (header) y es parte de la anatomia del lenguaje C.
Veras que es muy util al momento de depurar, cuando tienes un proyecto grande con muchos archivos y librerias, el archivo .h te ayuda a declarar alli las variables que son globales (tienen alcance desde cualquier funcion, no solo del main() ), recien alli le sacas el jugo a tu archivo de cabecera.

Es exactamente lo mismo que no aprovechar los archivos .inc del assembler y declarar directamente dentro del programa todas tus variables, en el momento de depurar o cambiar de PIC arrancan todos los problemas... :mrgreen: :mrgreen:
Todos los dias aprendo algo nuevo, el ultimo día de mi vida aprenderé a morir....
Mi Abuelo.

Desconectado PalitroqueZ

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5474
    • Electrónica Didacta
Re: Para que sirven los ".h"???
« Respuesta #2 en: 06 de Febrero de 2008, 14:56:13 »
yo creo que es como dice MGLSOFT, que es por cuestiones de convención, porque da igual que le pongas cualquier otra extensión.





La propiedad privada es la mayor garantía de libertad.
Friedrich August von Hayek

Desconectado RICHI777

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1498
Re: Para que sirven los ".h"???
« Respuesta #3 en: 06 de Febrero de 2008, 17:53:06 »
Hola, la función principal del los archivos "H" es instruir al compilador sobre tipos de datos definidos por el usuario ( typedefs ) y el prototipado de funcionesy definicion de macros. En el caso del prototipado, por un lado el compilador puede hacer una verificacion de los tipos parametros que son pasados a una funcion y tambien el retorno de la misma. Es bueno recordar que en versiones primitivas de compilador ( ANSI C ) los prototipos no eran obligatorios y si el compilador no encontraba el prototipo asumia que la funcion era del tipo int Function( void ), si la función no retorna un tipo entero se produce un bug, por demas muy comun. Por eso versiones actuales de compiladores presentan un warning feo cuando falta un prototipo y es mas en C++ ( evolucion de C ) es totalmente obligatorio.
Con respecto al comentario de incluir declaracion de variables globales no es para nada recomendable, ya que si tenemos un H con declaracion tipo "int Pepe", y tenemos dos fuentes distintos que incluyen ese H, la variable Pepe se incluira dos veces, con la cual en el momento del linkeo se producira un error, en C los nombres de las variables deben ser unico, el unico caso es utilizar la palabra static...pero eso es tema para otro post...
Espero haber aportado algo.
Salu2!

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5544
    • Picmania by Redraven
Re: Para que sirven los ".h"???
« Respuesta #4 en: 06 de Febrero de 2008, 18:22:30 »
Uf. Marttyn, voy a ver si puedo ponerte algún caso práctico para que veas su utilidad.

Por ejemplo declarar una función independiente de donde coloques su código, y así poder utilizarla aunque el compilador no ha llegado aún a ella y la haya compilado.

Este primer ejemplo te funcionará porque el compilador encuentra la función antes de llamarla en main()
Código: C#
  1. void mifuncion(void){
  2.    printf("Hola mundo");
  3. }
  4.  
  5. void main(void){
  6.    mifuncion();
  7. }

Pero este te dará error porque el compilador cuando llega a la llamada de mifuncion() no tiene ni idea de que es ni donde está ni que tipo de llamada necesita:
Código: C#
  1. void main(void){
  2.    mifuncion();
  3. }
  4.  
  5. void mifuncion(void){
  6.    printf("Hola mundo");
  7. }

Esto se soluciona declarando la función antes de usarla, así este nuevo ejemplo sí funcionaría:
Código: C#
  1. void mifuncion(void);
  2.  
  3. void main(void){
  4.    mifuncion();
  5. }
  6.  
  7. void mifuncion(void){
  8.    printf("Hola mundo");
  9. }

Ahora imagina que mifuncion() la quieres utilizar, llamar desde muchas otras funciones, o incluso en otros programas y quieres asegurarte que todas tus funciones y programas "conozcan" que mifuncion() existe y cómo se llama.

Entonces guardas la declaración void mifuncion(void); un fichero .h, por ejemplo mifuncion.h y en nuestro ejemplo lo que hacemos es poner el correspondiente include en lugar de la declaración directamente:
Código: C#
  1. #include "mifuncion.h";
  2.  
  3. void main(void){
  4.    mifuncion();
  5. }
  6.  
  7. void mifuncion(void){
  8.    printf("Hola mundo");
  9. }

Estaremos haciendo lo mismo pero tenemos la declaración disponible para cualquier otro programa con tan solo poner el include. Si además colocamos el desarrollo de la función en un fichero .c, por ejemplo mifuncion.c, entonces tendremos el ejemplo absolutamente igual de operativo pero preparado para poder usar mifuncion() donde haga falta:

Código: C#
  1. #include "mifuncion.h";
  2.  
  3. void main(void){
  4.    mifuncion();
  5. }
  6.  
  7. #include "mifuncion.c";

Parece trivial pero exactamente esto es lo que hacemos cuando escribimos una librería, por ejemplo para manejar el LCD o para la EEPROM o ... En el .h ponemos las declaraciones de las funciones que después desarrollaremos en el .c e incluimos ese .h al principio de cada programa donde vayamos a utilizar alguna de las funciones que contiene, y mas abajo podemos poner el include del .c donde se desarrolla su contenido.

Te voy a poner ahora un ejemplo real como la vida misma. Mi librería de utils.h y utils.c donde pongo todo aquello que no se donde poner.

utils.h
Código: C#
  1. /** \file lib_Utils.h
  2.  *  \brief Este fichero contiene las cabeceras necesarias para el manejo de la Libreria de Utilidades
  3.  *
  4.  *
  5.  * \author Diego Márquez
  6.  */
  7.  
  8.  
  9. // Prototipos de funciones
  10.  
  11. int8 bin_to_bcd(int8 binary_value);
  12. int8 bcd_to_bin(int8 bcd_value);
  13. void decode_timestamp(char *pF, int8 &day, int8 &mth, int16 &year, int8 &hr, int8 &min, int8 &sec);
  14. void encode_timestamp(char *pF, int8 day, int8 mth, int16 year, int8 hr, int8 min, int8 sec);
  15. void give_me_greater_timestamp(char *pF);
  16. void timestamp_to_DateTimeShort(char *pF, struct tDateTimeShort * pDTS);
  17. void fill_end_with_char(char c, int8 maxlen,char* pF);
  18. void int8_to_bits_string(int8 val, char* pF);
  19. int8 bits_string_to_int8(char* pF);
  20. int8 str_to_int8(char* pF);
  21. void replace_char(char c, char p, char* pF);
  22. void init_buffer(int16 maxlen, char *buffer);
  23. int8 ascii_to_hex(char d);
  24. int8 hex_to_int8(char* pF);
  25. int16 hex_to_int16(char* pF);
  26. int32 hex_to_int32(char* pF);
  27. int1 are_all_chars_equal_ASCII(char *pF, char Eq);
  28. int1 are_all_chars_equal_ASCII_zero(char *pF);
  29. int32 tDateTimeShort_to_int32(struct tDateTimeShort t);
  30. void right_trim(char* pF);
  31.  
  32. ///////////////////////////////////////////////////////////////////////////////////////////////////
  33. //
  34. // end of lib_Utils.h
  35. //
  36. ///////////////////////////////////////////////////////////////////////////////////////////////////

utils.c
Código: C#
  1. /** \file lib_Utils.c
  2.  * \brief Este fichero contiene un compendio de funciones de utilidad varia.
  3.  *
  4.  * \author Diego Márquez García-Cuervo \n <diego@indalosecurity.com> \n <micropic@garcia-cuervo.com>
  5.  */
  6.  
  7. /** \brief Función auxiliar que convierte de \c BIN a \c BCD
  8.   *
  9.   * \param binary_value Valor binario a convertir.
  10.   * \return Valor BCD convertido.
  11.   */
  12. int8 bin_to_bcd(int8 binary_value){
  13.  
  14.   int8 temp;
  15.   int8 retval;
  16.  
  17.   temp = binary_value;
  18.   retval = 0;
  19.   while(1){
  20.     if(temp >= 10){
  21.       temp -= 10;
  22.       retval += 0x10;
  23.     }else{
  24.       retval += temp;
  25.       break;
  26.     }
  27.   }
  28.   return(retval);
  29. }
  30.  
  31. /** \brief Función auxiliar que convierte de \c BCD a \c BIN
  32.   *
  33.   * \param bcd_value Valor BCD a convertir.
  34.   * \return Valor Binario convertido.
  35.   */
  36. int8 bcd_to_bin(int8 bcd_value){
  37.  
  38.   int8 temp;
  39.  
  40.   temp = bcd_value;
  41.   temp >>= 1;
  42.   temp &= 0x78;
  43.   return(temp + (temp >> 2) + (bcd_value & 0x0f));
  44. }
  45.  
  46. /** \brief Función que obtiene el nombre del día de la semana.
  47.   *
  48.   * Convierte el orden del día de la semana a su correspondiente nombre Lunes=1, Martes=2 ... Domingo=7.
  49.   *
  50.   * \param dow Orden del Día de la semana.
  51.   * \param[out] *pF Puntero a string donde cargar el nombre del día de la semana.
  52.   * \return void
  53.   */
  54. void get_name_day_of_week(int8 dow, char *pF){
  55.  
  56.    strcpy(pF,"\0");
  57.    switch(dow){
  58.       case 1: strcpy(pF,"Lunes");     break;
  59.       case 2: strcpy(pF,"Martes");    break;
  60.       case 3: strcpy(pF,"Miércoles"); break;
  61.       case 4: strcpy(pF,"Jueves");    break;
  62.       case 5: strcpy(pF,"Viernes");   break;
  63.       case 6: strcpy(pF,"Sábado");    break;
  64.       case 7: strcpy(pF,"Domingo");   break;
  65.    }
  66.  
  67. }
  68.  
  69. /** \brief Función que convierte un Byte (de 8 bits) a bits string ASCII.
  70.   *
  71.   * Convierte un Byte (de 8 bits) a string ASCII terminado en NULL (\\0).
  72.   *
  73.   * \param val Valor del Byte a convertir.
  74.   * \param[out] pF  Puntero a string_null_ended.
  75.   *
  76.   * \return void
  77.   */
  78. void int8_to_bits_string(int8 val,char* pF){
  79.  
  80.    int8 i,j;
  81.  
  82.    for(i=0,j=7;i<8;i++,j--){
  83.       pF[i]=bit_test(val,j)+'0';
  84.    }
  85.    pF[8]='\0';
  86. }
  87.  
  88. /** \brief Función que convierte un bits string ASCII a un Byte (de 8 bits).
  89.   *
  90.   * Convierte un string ASCII terminado en NULL (\\0) a Byte (de 8 bits).
  91.   *
  92.   * \param pF Puntero a string_null_ended.
  93.   *
  94.   * \return int8 Valor convertido.
  95.   */
  96. int8 bits_string_to_int8(char* pF){
  97.  
  98.    int8 i,j,ret=0;
  99.  
  100.    for(i=0,j=7;i<8;i++,j--){
  101.       if(pF[i]=='1'){
  102.        bit_set(ret,j);
  103.       }
  104.    }
  105.  
  106.    return ret;
  107. }
  108.  
  109. /** \brief Función que rellena con un caracter dado un string a partir de NULL hasta una longitud dada.
  110.   *
  111.   * \param c Carácter de relleno.
  112.   * \param maxlen Longitud máxima del string.
  113.   * \param[out] pF  Puntero a string_null_ended a rellenar.
  114.   *
  115.   * \return void
  116.   */
  117. void fill_end_with_char(char c, int8 maxlen,char* pF){
  118.  
  119.    int8 i;
  120.    int1 start=0;
  121.  
  122.    for(i=0;i<maxlen;i++){
  123.       if(start==0){
  124.          if(pF[i]=='\0'){
  125.             start=1;
  126.          }
  127.       }
  128.       if(start==1){
  129.          pf[i]=c;
  130.       }
  131.    }
  132.    pF[maxlen]='\0';
  133.  
  134. }
  135.  
  136. /** \brief Función que convierte un string numérico decimal ASCII NULL-END a su valor entero (8 bits).
  137.   *
  138.   * \param pF  Puntero al buffer que contiene el string numérico ASCII.
  139.   *
  140.   * \return int8 Valor numérico.
  141.   */
  142. int8 str_to_int8(char* pF){
  143.  
  144.    int8 ret=0,i,l,m=1;
  145.  
  146.    l=strlen(pF)-1;
  147.    for(i=l;i<255;i--){
  148.       if(isdigit(pF[i])){
  149.          ret+= m * (pF[i]-'0');
  150.          m = m * 10;
  151.       } else break;
  152.    }
  153.    //printf("StrToInt %s (%u)\r\n",pF,ret);
  154.    return ret;
  155. }
  156.  
  157. /** \brief Función decodifica una variable TimeStamp extrayendo sus componentes.
  158.   *
  159.   * Acepta una variable TimeStamp y devuelve valores enteros de Año, Mes, Día, Hora, Minuto, y Segundo.
  160.   * \param pF Puntero a string TimeStamp
  161.   * \param[out] day Dia
  162.   * \param[out] mth Mes
  163.   * \param[out] year Año (4 dígitos, int16)
  164.   * \param[out] hr Hora
  165.   * \param[out] min Minuto
  166.   * \param[out] sec Segundo
  167.   * \see encode_timestamp()
  168.   */
  169. void decode_timestamp(char *pF, int8 &day, int8 &mth, int16 &year, int8 &hr, int8 &min, int8 &sec){
  170.  
  171.    char sval[]="00";
  172.  
  173.    sval[2]='\0';
  174.    sval[0]=pF[2];  sval[1]=pF[3];  year= 2000+str_to_int8(sval);
  175.    sval[0]=pF[5];  sval[1]=pF[6];  mth = str_to_int8(sval);
  176.    sval[0]=pF[8];  sval[1]=pF[9];  day = str_to_int8(sval);
  177.    sval[0]=pF[11]; sval[1]=pF[12]; hr  = str_to_int8(sval);
  178.    sval[0]=pF[14]; sval[1]=pF[15]; min = str_to_int8(sval);
  179.    sval[0]=pF[17]; sval[1]=pF[18]; sec = str_to_int8(sval);
  180. }
  181.  
  182. /** \brief Función codifica una variable TimeStamp dando sus componentes.
  183.   *
  184.   * Acepta variables de valores enteros de Año, Mes, Día, Hora, Minuto, y Segundo y devuelve puntero a variable de tipo Timestamp.
  185.   * \param[out] pF Puntero a string TimeStamp
  186.   * \param day Dia
  187.   * \param mth Mes
  188.   * \param year Año (4 dígitos, int16)
  189.   * \param hr Hora
  190.   * \param min Minuto
  191.   * \param sec Segundo
  192.   * \see encode_timestamp()
  193.   */
  194. void encode_timestamp(char *pF, int8 day, int8 mth, int16 year, int8 hr, int8 min, int8 sec){
  195.  
  196.    sprintf(pF,"%Lu-%2u-%2u_%2u:%2u:%2u\0",year,mth,day,hr,min,sec);
  197.    replace_char(' ','0',pF);
  198.    replace_char('_',' ',pF);
  199. }
  200.  
  201. /** \brief Función que devuelve la mayor fecha posible en formato Timestamp.
  202.   *
  203.   * \param[out] pF Puntero a string TimeStamp
  204.   */
  205. void give_me_greater_timestamp(char *pF){
  206.  
  207.    strcpy(pF,greater_Timestamp);
  208. }
  209.  
  210. /** \brief Función que convierte una variable TimeStamp en una tDateTimeShort.
  211.   *
  212.   * Acepta una variable TimeStamp y devuelve los valores correspondientes de la estructura tDateTimeShort (int8) de Año, Mes, Día, Hora y Minuto.
  213.   * \param pF Puntero a string TimeStamp
  214.   * \param[out] pDTS Puntero a una variable tDateTimeShort
  215.   */
  216. void timestamp_to_DateTimeShort(char *pF, struct tDateTimeShort * pDTS){
  217.  
  218.    char sval[]="00";
  219.  
  220.    // Info Debug
  221.    //printf("\r\ntimestamp_to_DateTimeShort recibe: %s",pf);
  222.  
  223.    sval[2]='\0';
  224.    sval[0]=pF[2];  sval[1]=pF[3];  pDTS->year= str_to_int8(sval);
  225.    sval[0]=pF[5];  sval[1]=pF[6];  pDTS->mth = str_to_int8(sval);
  226.    sval[0]=pF[8];  sval[1]=pF[9];  pDTS->day = str_to_int8(sval);
  227.    sval[0]=pF[11]; sval[1]=pF[12]; pDTS->hr  = str_to_int8(sval);
  228.    sval[0]=pF[14]; sval[1]=pF[15]; pDTS->min = str_to_int8(sval);
  229.  
  230.    // Info Debug
  231.    //printf("\r\ntimestamp_to_DateTimeShort devuelve: %u %u %u %u %u\r\n",pDTS->year,pDTS->mth,pDTS->day,pDTS->hr,pDTS->min);
  232. }
  233.  
  234. /** \brief Reemplaza carácter en string null-terminated.
  235.   *
  236.   * \param c Carácter a sustituir.
  237.   * \param p Carácter nuevo a insertar.
  238.   * \param[out] pF  Puntero a string null-terminated.
  239.   *
  240.   * \return void
  241.   */
  242. void replace_char(char c, char p, char* pF){
  243.  
  244.    int8 i;
  245.    char x;
  246.  
  247.    x=pF[0];
  248.    for(i=0;i<max_len_buffer,x!='\0';i++){
  249.       x=pf[i];
  250.       if(x==c){
  251.          pF[i]=p;
  252.       }
  253.    }
  254. }
  255.  
  256. /** \brief Inicializa un Buffer
  257.   *
  258.   * Esta función inicializa a "\0" todos los bytes de un Buffer.\n
  259.   *
  260.   * \return void
  261.   */
  262. void init_buffer(int16 maxlen, char *buffer){
  263.  
  264.    int16 i;
  265.    for(i=0;i<maxlen;i++){
  266.       buffer[i]='\0';
  267.    }
  268. }
  269.  
  270. /** \brief Función que convierte un carácter Hexadecimal ASCII NULL-END a su valor entero de 8 bits.
  271.   *
  272.   * \param d Caracter Hexadecimal a convertir.
  273.   *
  274.   * \return int8 Valor numérico.
  275.   */
  276. int8 ascii_to_hex(char d){
  277.  
  278.    int r=0x00;
  279.  
  280.    if(isxdigit(d)){
  281.       if(isdigit(d)){
  282.          r=d-'0';
  283.       }
  284.       if(isalpha(d)){
  285.          d=toupper(d);
  286.          r=10+(d-'A');
  287.       }
  288.    }
  289.    return(r);
  290. }
  291.  
  292. /** \brief Función que convierte un string numérico Hexadecimal ASCII NULL-END a su valor entero de 8 bits.
  293.   *
  294.   * \param pF Puntero al buffer que contiene el string numérico ASCII Hexadecimal de 2 digitos (00h a FFh).
  295.   *
  296.   * \return int8 Valor numérico.
  297.   */
  298. int8 hex_to_int8(char* pF){
  299.  
  300.    int8 i,ret;
  301.  
  302.    ret=0;
  303.    for(i=1;i!=255;i--){
  304.       ret+=ascii_to_hex(pF[i])*((15*(1-i))+1);
  305.    }
  306.    //printf("hex_to_int8 recibe: %s valor: %X (%u)\r\n",pF,ret,ret);
  307.    return ret;
  308. }
  309.  
  310. /** \brief Función que convierte un string numérico Hexadecimal ASCII NULL-END a su valor entero de 16 bits.
  311.   *
  312.   * \param pF Puntero al buffer que contiene el string numérico ASCII Hexadecimal de 4 digitos (0000h a FFFFh).
  313.   *
  314.   * \return int16 Valor numérico.
  315.   */
  316. int16 hex_to_int16(char* pF){
  317.  
  318.    int8  i, p2, p1;
  319.    int16 ret;
  320.  
  321.    p1=hex_to_int8(&pF[2]);
  322.    p2=hex_to_int8(&pF[0]);
  323.    ret=make16(p2,p1);
  324.    //printf("hex_to_int16 recibe: %s p2: %LX p1 %LX valor: %LX (%Lu)\r\n",pF,p2,p1,ret,ret);
  325.    return ret;
  326. }
  327. /** \brief Función que convierte un string numérico Hexadecimal ASCII NULL-END a su valor entero de 32 bits.
  328.   *
  329.   * \param pF Puntero al buffer que contiene el string numérico ASCII.
  330.   *
  331.   * \return int32 Valor numérico.
  332.   */
  333. int32 hex_to_int32(char* pF){
  334.  
  335.    int32 ret;
  336.    int16 p1,p2;
  337.  
  338.    p1=hex_to_int16(&pF[4]);
  339.    p2=hex_to_int16(&pF[0]);
  340.    ret = make32(p2, p1);
  341.    //printf("hex_to_int32 recibe: %s p2: %LX p1 %LX valor: %LX (%Lu)\r\n",pF,p2,p1,ret,ret);
  342.    return ret;
  343. }
  344.  
  345. /** \brief Función que comprueba si todos los caracteres del string son iguales a uno dado.
  346.   *
  347.   * \param pF Puntero al string a investigar.
  348.   * \param Eq Caracter a comprobar.
  349.   *
  350.   * \return int1 0 si al menos un caracter es distinto del dado, 1 si todos los caracteres son iguales al dado.
  351.   */
  352. int1 are_all_chars_equal_ASCII(char *pF, char Eq){
  353.  
  354.    int8 ret;
  355.    int8 i,l;
  356.  
  357.    ret=1;
  358.    l=strLen(pF);
  359.    for(i=0;i<l;i++){
  360.       if(pf[i]!=Eq){
  361.          ret=0;
  362.       }
  363.    }
  364.  
  365.    return ret;
  366. }
  367.  
  368. /** \brief Función que comprueba si todos los caracteres del string son '0' (ASCII Cero).
  369.   *
  370.   * \param pF Puntero al string a investigar.
  371.   *
  372.   * \return int1 0 si al menos un caracter es distinto de cero, 1 si todos los caracteres son cero.
  373.   */
  374. int1 are_all_chars_equal_ASCII_zero(char *pF){
  375.  
  376.    int8 ret;
  377.  
  378.    ret = are_all_chars_equal_ASCII(pF,'0');
  379.  
  380.    return ret;
  381. }
  382.  
  383. /** \brief Función que crea un int32 con el contenido de un tDateTimeShort (Se desprecian el componente struct .min)
  384.   *
  385.   * \param t Fecha a convertir.
  386.   *
  387.   * \return int32 valor truncado y convertido.
  388.   */
  389. int32 tDateTimeShort_to_int32(struct tDateTimeShort t){
  390.  
  391.    int32 ret=0;
  392.  
  393.    t.hr = (t.hr * 60) + t.min;
  394.  
  395.    ret=make32(t.year,t.mth,t.day,t.hr);
  396.  
  397.    return ret;
  398. }
  399.  
  400. /** \brief Función que descarta los espacios en blanco por la derecha de una cadena.
  401.   *
  402.   * \param[out] pF  Puntero a string_null_ended a procesar.
  403.   *
  404.   * \return void
  405.   */
  406. void right_trim(char* pF){
  407.  
  408.    int8 i,L;
  409.  
  410.    for(i=0;i<len_string;i++){
  411.       if(pF[i]=='\0'){
  412.             L=i-1;
  413.             break;
  414.       }
  415.    }
  416.    for(i=L;i>0;i--){
  417.       if(pF[i]==' '){
  418.             pF[i]='\0';
  419.       }
  420.       else{
  421.          break;
  422.       }
  423.    }
  424. }
  425.  
  426. ///////////////////////////////////////////////////////////////////////////////////////////////////
  427. //
  428. // End of lib_utils
  429. //
  430. ///////////////////////////////////////////////////////////////////////////////////////////////////

Cualquier programa mio que necesite alguna de las funciones incluidas en utils se podría ver como:

Código: C#
  1. #include <18f1320.h>
  2. #fuses HS,MCLR,PUT,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOCPD,NODEBUG,NOWRT
  3. #use delay(clock=20000000)
  4. #use rs232(baud=115200, xmit=PIN_B1, rcv=PIN_B4)
  5.  
  6. #include "utils.h"
  7.  
  8. #int_rda
  9. void serial_isr() {
  10.  
  11.    if(kbhit()){
  12.       putc(getc());
  13.    }
  14. }
  15.  
  16. void main() {
  17.  
  18.    enable_interrupts(int_rda);
  19.    enable_interrupts(global);
  20.  
  21.    do {
  22.  
  23.    } while (TRUE);
  24. }
  25.  
  26. #include "utils.c"

Ea, esa es una forma de darle uso a los .h

Espero que te sirva.  :mrgreen: :mrgreen: :mrgreen: :mrgreen:
« Última modificación: 06 de Febrero de 2008, 18:29:27 por RedPic »
Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado MGLSOFT

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 7912
Re: Para que sirven los ".h"???
« Respuesta #5 en: 06 de Febrero de 2008, 19:32:12 »
Bien hecho!!

Incluso CCS incluye dentro del archivo de libreria .c el llamado al de encabezados .h
Veamos un ejemplo:

Código: [Seleccionar]
#include <16F876.h>
#fuses HS,NOPROTECT,NOLVP,NOWDT
#use delay(clock=2500000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

#define CAN_DO_DEBUG TRUE

#include <can-mcp2510.c>

#define PIN_LED1  PIN_A1
#define PIN_LED2  PIN_A2
#define PIN_LED3  PIN_A3

Luego veamos una parte del archivo .c

Código: [Seleccionar]
#include <can-mcp2510.h>

//IO pins connected to MCP2510
#ifndef EXT_CAN_CS
   #define EXT_CAN_CS   PIN_B1
   #define EXT_CAN_SI   PIN_C1
   #define EXT_CAN_SO   PIN_C0
   #define EXT_CAN_SCK  PIN_C3
//   #define EXT_CAN_RESET   PIN_B5 //CCS library does not use this pin by default
//   #define EXT_CAN_TX0RTS  PIN_C4 //CCS library does not use this pin by default
//   #define EXT_CAN_TX1RTS  PIN_B4 //CCS library does not use this pin by default
//   #define EXT_CAN_TX2RTS  PIN_C2 //CCS library does not use this pin by default
#endif

#if CAN_DO_DEBUG
 #define can_debug printf
#else
 #define can_debug
#endif

////////////////////////////////////////////////////////////////////////
//
// can_init()
//
// Initializes MCP2510 CAN peripheral.  Sets the RX filter and masks so the
// CAN peripheral will receive all incoming IDs.  Configures both RX buffers
// to only accept valid valid messages (as opposed to all messages, or all
// extended message, or all standard messages).
//
// The constants (CAN_USE_RX_DOUBLE_BUFFER, CAN_ENABLE_DRIVE_HIGH,
// CAN_ENABLE_CAN_CAPTURE, etc) are given a default define in the can-mcp2510.h file.
// These default values can be overwritten in the main code, but most
// applications will be fine with these defaults.
//
//////////////////////////////////////////////////////////////////////////////
void can_init(void) {
   struct struct_RXB0CTRL b_rxb0ctrl;

   mcp2510_init();

   can_set_mode(CAN_OP_CONFIG);   //must be in config mode before params can be set
   can_set_baud();

   b_rxb0ctrl=0;
   b_rxb0ctrl.rxm=CAN_RX_VALID;
   b_rxb0ctrl.bukt=CAN_USE_RX_DOUBLE_BUFFER;
   mcp2510_write(RXB0CTRL, (int)b_rxb0ctrl);
   mcp2510_write(RXB1CTRL, (int)b_rxb0ctrl);

   //if you want to configure the TXnRTS pins, do it here.  default is off

   can_set_id(RX0MASK, CAN_MASK_ACCEPT_ALL, CAN_USE_EXTENDED_ID);  //set mask 0 (RX BUFFER 0)
   can_set_id(RX0FILTER0, 0, CAN_USE_EXTENDED_ID);  //set filter 0 of mask 0 (RX BUFFER 0)
   can_set_id(RX0FILTER1, 0, CAN_USE_EXTENDED_ID);  //set filter 1 of mask 0 (RX BUFFER 0)

   can_set_id(RX1MASK, CAN_MASK_ACCEPT_ALL, CAN_USE_EXTENDED_ID);  //set mask 1 (RX BUFFER 1)
   can_set_id(RX1FILTER2, 0, CAN_USE_EXTENDED_ID);  //set filter 0 of mask 1 (RX BUFFER 1)
   can_set_id(RX1FILTER3, 0, CAN_USE_EXTENDED_ID);  //set filter 1 of mask 1 (RX BUFFER 1)
   can_set_id(RX1FILTER4, 0, CAN_USE_EXTENDED_ID);  //set filter 2 of mask 1 (RX BUFFER 1)
   can_set_id(RX1FILTER5, 0, CAN_USE_EXTENDED_ID);  //set filter 3 of mask 1 (RX BUFFER 1)

   can_set_mode(CAN_OP_NORMAL);
}

////////////////////////////////////////////////////////////////////////
//
// can_set_baud()
//
// Configures the baud rate control registers.  All the defines here
// are defaulted in the can-mcp2510.h file.  These defaults can, and
// probably should, be overwritten in the main code.
//
// Current defaults are set to work with CCS's CAN Prototype board and
// Microchip's MCP250xxx CAN Developers Kit if this PIC is running at 20Mhz.
//
////////////////////////////////////////////////////////////////////////
void can_set_baud(void) {
   struct struct_CNF1 new_CNF1;
   struct struct_CNF2 new_CNF2;
   struct struct_CNF3 new_CNF3;


   new_CNF1.brp=CAN_BRG_PRESCALAR;
   new_CNF1.sjw=CAN_BRG_SYNCH_JUMP_WIDTH;

   new_CNF2.prseg=CAN_BRG_PROPAGATION_TIME;
   new_CNF2.phseg1=CAN_BRG_PHASE_SEGMENT_1;
   new_CNF2.sam=CAN_BRG_SAM;
   new_CNF2.btlmode=CAN_BRG_SEG_2_PHASE_TS;

   new_CNF3.phseg2=CAN_BRG_PHASE_SEGMENT_2;
   new_CNF3.wakfil=CAN_BRG_WAKE_FILTER;

   mcp2510_write(CNF1, (int)new_CNF1);
   mcp2510_write(CNF2, (int)new_CNF2);
   mcp2510_write(CNF3, (int)new_CNF3);
}

void can_set_mode(CAN_OP_MODE mode) {
   struct struct_CANCTRL old_CANCTRL;

   old_CANCTRL=mcp2510_read(CANCTRL);

   old_CANCTRL.reqop=mode;

   mcp2510_write(CANCTRL, (int)old_CANCTRL);

   do {
      old_CANCTRL=mcp2510_read(CANCTRL);
   } while (old_CANCTRL.reqop != mode);
}

Y aqui el archivo .h

Código: [Seleccionar]
#ifndef CAN_ENABLE_CAN_CAPTURE
 #define CAN_ENABLE_CAN_CAPTURE 0
#endif

enum CAN_OP_MODE {CAN_OP_CONFIG=4, CAN_OP_LISTEN=3, CAN_OP_LOOPBACK=2, CAN_OP_SLEEP=1, CAN_OP_NORMAL=0};

//can control
struct struct_CANCTRL {
   int  clkpre:2; //0:1 //clkout pin prescalar
   int1 clken; //2   //clkout pin enable
   int1 void3; //3
   int1 abat;  //4   //abort all pending transmissions
   CAN_OP_MODE reqop:3; //5:7 //request operation mode
};
#define CANCTRL   0x0F  //or 1f, or 2f, or 3f ... or 7f

enum CAN_INT_CODE {CAN_INT_RX1=7, CAN_INT_RX0=6, CAN_INT_TX2=5, CAN_INT_TX1=4, CAN_INT_TX0=3, CAN_INT_WAKEUP=2, CAN_INT_ERROR=1, CAN_INT_NO=0};

//can status register READ-ONLY
struct struct_CANSTAT {
   int1 void0;   //0
   CAN_INT_CODE icode:3;   //1:3   //interrupt code
   int1 void4;   //4
   CAN_OP_MODE opmode:3;   //5:7   //operation mode status
};
#define CANSTAT 0x0E //or 1e, or 2e ... or 7e

sigue pero es muy largo.....

Hasta llegar a los prototipos de funciones...

Código: [Seleccionar]
void  can_init(void);
void  can_set_baud(void);
void  can_set_mode(CAN_OP_MODE mode);
void can_set_id(int addr, int32 id, int1 ext);
int32 can_get_id(int addr, int1 ext);
int   can_putd(int32 id, int * data, int len, int priority, int1 ext, int1 rtr);
int1  can_getd(int32 & id, int * data, int & len, struct rx_stat & stat);

void mcp2510_init();
void mcp2510_command(int command);
void mcp2510_write(int address, int data);
int mcp2510_status(void);
int mcp2510_read(int address);

#endif
Todos los dias aprendo algo nuevo, el ultimo día de mi vida aprenderé a morir....
Mi Abuelo.

Desconectado Geo

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 922
    • Mexchip
Re: Para que sirven los ".h"???
« Respuesta #6 en: 08 de Enero de 2009, 22:13:30 »
Precisamente en este momento me había encontrado con el problema de compilar diferentes unidades, desconocía que CCS no permite enlazar unidades ya compiladas :?.

En su lugar, se incluye el código en el mismo archivo principal con #include archivo.c
La imaginación es el límite.
Visita mi blog, en inglés o en español :).
Mini curso de introducción a VHDL en MEXCHIP :-/

Desconectado Marttyn

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1835
    • IDEAA
Re: Para que sirven los ".h"???
« Respuesta #7 en: 08 de Enero de 2009, 22:29:08 »
Gracias a todos por las respuestas!
Un poco tarde lo se... pero no recibi ningun aviso de que me habian respondido  :(
Recibi un aviso ahora y veo que hay un monton de respuestas y ayuda!
Gracias de nuevo, cada vez que entro en el foro aprendo un monton!  :-/

PS: que son los prototipos?
La gente ve las cosas que existen y se pregunta por qué.
Yo prefiero imaginar lo que no existe y preguntarme por qué no.

Desconectado micro_pepe

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 3206
Re:Para que sirven los ".h"???
« Respuesta #8 en: 19 de Enero de 2017, 19:04:31 »
Tengo una duda a cerca de esto, si tengo dos librerías .h, y quiero que una vea a la otra y la otra a la una, ¿que hay que hacer?

pongamos este ejemplo:
Código: C
  1. #include "libreria_1.h"
  2. #include "libreria_2.h"

Si libreria_2 usa funciones de la 1, no hay problema, pero si la 1 usa funciones de la 2, no las ve, podría darse el caso que se usen librerías en los dos sentidos.

Gracias!!! Un saludo.
Se obtiene más en dos meses interesandose por los demás, que en dos años tratando de que los demás se interesen por ti.

新年快乐     的好奇心的猫死亡

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Para que sirven los ".h"???
« Respuesta #9 en: 19 de Enero de 2017, 19:41:31 »
Es dificil ver la situacion sin un ejemplo un poco mas practico.

Lo unico que se me ocurre sin ver el caso practico es que: Si libreria_2 usa funciones de la 1, entonces en libreria_2.c deberias tener el include a libreria_1.h y viceversa.
En si esos includes son la puerta de los demas archivos para acceder al .c. Por lo cual si estas en libreria_1.c, entonces podrias llegar a tener algo asi:

Código: C
  1. #include "libreria_1.h"
  2. #include "libreria_2.h"

Si estas en libreria_2.c tendrias algo asi:

Código: C
  1. #include "libreria_2.h"
  2. #include "libreria_1.h"

Ambos tienen acceso a la otra.
Si en realidad esos includes estan en otro archivo, digamos main.c es imposible que puedas juntarlos ahi. Ya que incluir 2 include en un archivo externo a los archivos fuentes de las librerias (.c ) No va a hacer que libreria_1.c pueda acceder a libreria_2.c.

Realmente no tengo idea de como puede llegar a ocurrir lo que estas planteando.

Desconectado micro_pepe

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 3206
Re:Para que sirven los ".h"???
« Respuesta #10 en: 20 de Enero de 2017, 13:12:07 »
Realmente no tengo idea de como puede llegar a ocurrir lo que estas planteando.

Es algo que me pasó hace tiempo, pero creo que por una mala organización de los ficheros, encontré este hilo y recordé aquel problema.

Lo que no tengo muy claro, es si en el fichero que hace uso del otro hay que incluir las definiciones de funciones con extern:

fichero_1.h

Código: C
  1. void funcion_1(void);

fichero_2.h
Código: C
  1. extern void funcion_1(void);
  2. void funcion_2(void);

fichero_2.c
Código: C
  1. #include "fichero_2.h"
  2.  
  3. void funcion_2(void){
  4.      ------
  5.      ------
  6.      funcion_1();
  7.      ------
  8. }

Eso me está dando problemas, y lo he resuelto poniendo la cabecera de la función con extern. He probado lo que dices    KILLERJC, de poner el include de la otra librería en el .c, pero da un error. Es una librería con un retardo que hace uso del __delay_ms(), y creo que por ahí vienen los problemas.

No he dicho nada  :5] estaba poniendo el include de la segunda librería en el .h, cuando debe ir en el .c:

Citar
Si estas en libreria_2.c tendrias algo asi:

Código: C

    #include "libreria_2.h"
    #include "libreria_1.h"

Salí a darme una vuelta, a que me diese un poco el fresco, y caí en ello. A veces es mejor cambiar de actividad que emperrarse en encontrar la solución, y luego volver a ello.

Gracias!!! un saludo.
« Última modificación: 20 de Enero de 2017, 16:36:51 por micro_pepe »
Se obtiene más en dos meses interesandose por los demás, que en dos años tratando de que los demás se interesen por ti.

新年快乐     的好奇心的猫死亡

Desconectado Marttyn

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1835
    • IDEAA
Re:Para que sirven los ".h"???
« Respuesta #11 en: 24 de Enero de 2017, 10:14:27 »
Bueno, a mi me paso algo similar, que una libreria se "necesitaba a si misma".
En mi caso es una libreria para leer el voltaje de la bateria segun el voltaje Vdd.
Mi libreria necesita saber el tipo de bateria que se va a usar para los calculos, y los DEFINE de esa libreria estan en la misma libreria.
Por ejemplo:
leer_bateria.h
Código: C
  1. #define BAT_LIPO    3.7
  2. #define BAT_1AA    1.5
  3. #define BAT_2AA    3
  4. #define BAT_3AA    4.5
  5.  
  6. //calculos con la bateria, usando BAT_TYPE
  7. ...
  8. ...

Desde el header de mi proyecto tengo que declarar BAT_TYPE como el tipo de bateria a usar:
Código: C
  1. #define BAT_TYPE    BAT_LIPO

A su vez, la libreria leer_bateria.h buscaba BAT_TYPE para hacer ciertos calculos...
Por lo que si defino BAT_TYPE antes de llamar a la libreria, no encuentra los define de tipos de bateria
Y si defino BAT_TYPE despues de llamar a la libreria, lo que ocurre es que salta un error por que BAT_TYPE no esta declarado.

La solucion fue crear un header solo con los tipos de bateria, e incluirlo en el proyecto al principio, luego puedo crear el define BAT_TYPE, y luego incluir la libreria.
La gente ve las cosas que existen y se pregunta por qué.
Yo prefiero imaginar lo que no existe y preguntarme por qué no.

Desconectado micro_pepe

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 3206
Re:Para que sirven los ".h"???
« Respuesta #12 en: 26 de Enero de 2017, 09:54:11 »
Citar
La solucion fue crear un header solo con los tipos de bateria, e incluirlo en el proyecto al principio, luego puedo crear el define BAT_TYPE, y luego incluir la libreria.

Sí, es una solución posible, gracias!!!
Se obtiene más en dos meses interesandose por los demás, que en dos años tratando de que los demás se interesen por ti.

新年快乐     的好奇心的猫死亡

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5883
    • Picuino
Re:Para que sirven los ".h"???
« Respuesta #13 en: 26 de Enero de 2017, 11:20:40 »
Muy sencillo:
Si quieres que la librería 1 vea la librería 2, añades en el header de la librería 1,  la librería 2.
Para eso sirve añadir headers.

Ahora el problema que tienes es que la librería 2 puede aparecer en varios sitios y estar "Redefinida".
Para evitar eso se suele añadir un pequeño código a las librerías que asegura que sólo se defina una vez:

Código: C
  1. #ifndef  LIBRERIA_2_H
  2. #define LIBRERIA_2_H
  3.  
  4. ... aquí pones todo el código de la librería 2, que sólo se leerá la primera vez.
  5.  
  6. #endif

Un saludo.

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5883
    • Picuino
Re:Para que sirven los ".h"???
« Respuesta #14 en: 26 de Enero de 2017, 12:16:45 »
Marttyn, creo que lo mejor en tu caso es utilizar macros para hacer los cálculos. Una macro es como una función y puedes pasarle el parámetro que quieras después de estar definida. Es más elegante y no cometes errores si cambias el orden de las líneas.

De todas formas debería ver el código para estar seguro.

Un saludo.


 

anything