Autor Tema: Array como argumento a función.  (Leído 3416 veces)

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

Desconectado remi04

  • PIC24F
  • *****
  • Mensajes: 657
Array como argumento a función.
« en: 24 de Febrero de 2019, 14:42:27 »
Hola. Tenía entendido que en C no era posible pasar un array como argumento a una función, de hecho creo que lo probé en CCS y me dijo que nanai.. 

  Pero en XC32 si que me está dejando, Un resumen de código (obviando los include, los fuses y configuraciones) de prueba sería este que envía un string por SPI:

Código: C
  1. void sendtxt(char texto[]);   // Prototipo.
  2.  
  3.  
  4.  
  5.  
  6. int main(void) {
  7.                       sendtxt("HOLA, ESTE STRING SE ENVIA POR SPI A TRAVES DE LA FUNCION SENDTXT() \0");      // Añado un NULL "\0" para indicar el fin de cadena a la función.
  8.                       while(1)
  9.                      return(0);
  10.                     }
  11.  
  12. void sendtext(texto[]) {
  13.                                   int i;
  14.                                   for (i=0;i<1000;i++) {
  15.                                                                    SpiChnPutC(1,texto[i]);
  16.                                                                    if (texto[i] == '\0') break;                            
  17.                                                                   }
  18.                                  }

   Cuando se haya enviado el caracter NULL "\0" la iteracción es cortada y la función termina.

  Esto funciona perfectamente, está probado.

  Ahoa viene lo raro, vereis que he puesto un ciclo FOR que cuenta hasta 1000 mientras no se reciba el NULL cuando podría perfectamente poner

Código: C
  1. while(texto[i] != '\0')  {
  2.                                     SpiChnPutC(1,texto[i]);
  3.                                     i++;
  4.                                  }



   Pues bien, puesto así con el while lo que sucede es que se envía la string perfectamente incluyendo el NULL, pero el while no deja de validarse nunca. Pasa el NULL y sigue y sigue y sigue enviando 0xFF,0xFF,0xFF asi infinitamente.

  ¿Por qué?

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Array como argumento a función.
« Respuesta #1 en: 24 de Febrero de 2019, 18:31:25 »
Nunca vas a pasar un array... Lo que siempre vas a pasar es un puntero del array. Es por eso que estas usando texto[ i ] , usar esto es simplemente tomar el puntero base y sumarle i, para luego acceder a los datos.
Hay varias cosas raras en tu programa..
- Como el while(1) que no es un loop infinito, logrando que ocurra el return.
- Tambien esta lo de ponerle el \0 al string cuando de por si ya te lo agrega.
- Segun lo que comentas la i NO se encuentra inicializada luego cuando lo probas con el while... Ya que reemplazas el for por el while. Pero el que no se detenga tal ves sea por otra cosa (optimizacion, etc).
- La funcion SENDTXT tiene otro nombre... SENDTEXT

Mejor definirlo como puntero, aunque decir char texto[] es lo mismo que decir char *texto


Código: C
  1. void sendtxt(const char *);   // Prototipo.
  2.  
  3. int main(void){
  4.  
  5.     sendtxt("HOLA, ESTE STRING SE ENVIA POR SPI A TRAVES DE LA FUNCION SENDTXT()");
  6.     while(1);
  7.     return(0);
  8. }
  9.  
  10. void sendtxt(const char *texto) {
  11.     while(*texto) {
  12.         SpiChnPutC(1,*texto++);
  13.     }
  14. }
« Última modificación: 24 de Febrero de 2019, 18:34:31 por KILLERJC »

Desconectado remi04

  • PIC24F
  • *****
  • Mensajes: 657
Re:Array como argumento a función.
« Respuesta #2 en: 25 de Febrero de 2019, 03:29:57 »
Gracias Killer.  Efectivamente al while(1) le falta el ;, y la función sendtxt está mal escrita, pero no es un copia/pega del código que funciona, más bien un error de transcripción.

 De todas formas creo que ya se lo que pasa gracias a tu respuesta.  La función del SPI envía el dato por que ella si que accede al dato mientras que el while (text) está viendo direcciones de memoria y por eso nunca ve el Null.  Podría ser. Pero sin embargo el while que va dentro del for si que lo ve y cumple el break; 

  Si es problema de optimización u otro (es el xc32 en modo libre) pues entonces sería una “mierda” puesto que si un código que debería funcionar aunque sea sin optimizar no funciona por culpa de optimización pues entonces no sirve.  No se si activar ya la prueba de 30 días a full para ver si es por eso..

 Lo probaré luego.

 Muchísimas gracias.
« Última modificación: 25 de Febrero de 2019, 05:44:37 por remi04 »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Array como argumento a función.
« Respuesta #3 en: 25 de Febrero de 2019, 06:20:03 »
Deberia funcionar lo del while... Tal ves es otro problema... Para saber exactamente cual es el problema. necesitaria el codigo en C completo y el disassembler del mismo... Para determinar donde es que esta equivocado.

Desconectado remi04

  • PIC24F
  • *****
  • Mensajes: 657
Re:Array como argumento a función.
« Respuesta #4 en: 27 de Febrero de 2019, 13:40:24 »
Hola Killer, te adjunto este código completo, lo que hace este programa primero es hacer 10 ecos por UART y luego enviar una frase por SPI.

  Abajo la ultima función que NO está comentada es la que NO funciona.

  La función comentada si que funciona.

En verdad funcionar, funcionan las dos, lo que pasa es que en la primera el WHILE siempre se cumple, aunque reciba el NULL. y el envío de datos continua indefinidamente con 0xff,0xff, etc.....

  En la segunda el IF cumple el break cuando recibe el NULL por lo que esa función si que funciona perfectamente.

 Un saludo.


Código: C
  1. #include <p32xxxx.h>
  2. #define _SUPPRESS_PLIB_WARNING         // Elimina los warning de aviso de que estas librerias dejarán de estar disponible en futuras versiones.
  3. #include <plib.h>                      //Librería de periféricos
  4. #include <stdio.h>
  5.  
  6.  
  7.  
  8.  
  9.  
  10.  
  11.  
  12. #pragma config FNOSC = PRIPLL, POSCMOD = HS, FPLLMUL = MUL_18, FPLLIDIV = DIV_2, FPBDIV = DIV_2, FPLLODIV = DIV_1
  13. #pragma config FWDTEN = OFF
  14.  
  15.  
  16. #define SYSCLK         (72000000)
  17. #define PBCLK          (SYSCLK/2)
  18.  
  19. #define DESIRED_BAUDRATE       (115200)      //The desired BaudRate
  20.  
  21. // Cálculo de BRG en función del baudrate elegido y el PBCLK
  22. #define BAUD_VALUE    ((PBCLK/16/DESIRED_BAUDRATE)-1)
  23.  
  24.  
  25.  
  26. void spi_ini();   // INICIALIZA EL MODULO SPI
  27. void delay_ms(unsigned long);   // implementa función de retardo.
  28. void lcdprint(char texto[]);     // imprime texto via puerto SPI.
  29.  
  30.  
  31.  
  32.  
  33.  
  34.  
  35. int main(void)
  36. {
  37.    unsigned char data = 0;
  38.    SYSTEMConfigPerformance(72000000L);
  39.    OpenUART2(UART_EN, UART_RX_ENABLE | UART_TX_ENABLE, BAUD_VALUE );
  40.    U2MODE = 0b00000000000000001110100000100001;      // AutoBaudRate Habilitado.
  41.  
  42.    spi_ini();
  43.    
  44.    int a = 0;
  45.  
  46.    while(a <=10)        // Recibe diez caracteres y los repite  ( Función Eco para probar el modulo y la comunicación UART)) (Nota: AUTOBAUD ACTIVO, el primer caracter a enviar tiene que ser 0X55).
  47.    {
  48.       while(!DataRdyUART2());   // Espera a que haya un caracter en el buffer de recepción.
  49.       data = (char)ReadUART2(); // lee y carga el caracter en variable.
  50.      
  51.       while(BusyUART2()); /* Wait till the UART transmitter is free. */
  52.       putcUART2(data); /* Write data into Tx. */
  53.       a++;
  54.    }
  55.      
  56.    
  57.    lcdprint("IMPRIME ESTE TEXTO VIA SPI\0");
  58.    
  59.    while(1);
  60.    
  61.    
  62.  
  63.    return 0;
  64. }
  65.  
  66.  
  67.  
  68.  
  69.  
  70.  
  71.  
  72.  
  73. void spi_ini() {
  74.     unsigned int config=SPI_CON_MODE8|SPI_CON_SMP|SPI_CON_ON|SPI_OPEN_MSTEN;  // SPI configuration word
  75.     SpiChnOpen(1, config, 128);    // Canal SPI, configuración y velocidad (Divisor de PBCLC)
  76. }
  77.  
  78.  
  79.  
  80. void delay_ms(unsigned long retardo) {
  81.     unsigned long i = 0;
  82.     for (i=0;i<=retardo;i++);
  83.    
  84.    
  85.    
  86. }
  87.  
  88.  
  89.  
  90.  
  91. void lcdprint(char texto[]) {                                     // Esta función  debería terminar cuando [i] apunte al caracter NULL, pero no lo hace, simplemente no se detiene, la frase sale entera, incluido el NULL
  92.                                                                    // Pero luego sigue enviando 0xFF,0xFF sucesivamente de forma infinita,
  93.     int i;
  94.    
  95.     while(texto[i] != '\0') SpiChnPutC(1,texto[i++]) ;
  96.                              
  97.                                                      
  98.                    
  99. }
  100.    
  101.  /*  
  102.  void lcdprint(char texto[]) {            // Esta función si que funciona perfectamente. El IF vé perfectamente el NULL y se cumple el break;
  103.    
  104.     int i;
  105.   for (i=0;i<1000;i++) {
  106.                         SpiChnPutC(1,texto[i++]) ;
  107.                         if (texto[i] == '\0') break;
  108.                        }                                              
  109.                    
  110. }
  111. */

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Array como argumento a función.
« Respuesta #5 en: 27 de Febrero de 2019, 23:32:30 »
Creo que deberias inicializar en 0 la i, es decir:


Código: C
  1. void lcdprint(char texto[]) {                                     // Esta función  debería terminar cuando [i] apunte al caracter NULL, pero no lo hace, simplemente no se detiene, la frase sale entera, incluido el NULL
  2.                                                                    // Pero luego sigue enviando 0xFF,0xFF sucesivamente de forma infinita,
  3.     int i = 0;
  4.    
  5.     while(texto[i] != '\0') SpiChnPutC(1,texto[i++]) ;
  6.                              
  7.                                                      
  8.                    
  9. }

Si no es eso, entonces lo unico que se me ocurre de ver es el ASM generado para revisar que es lo que esta pasando.

Desconectado remi04

  • PIC24F
  • *****
  • Mensajes: 657
Re:Array como argumento a función.
« Respuesta #6 en: 28 de Febrero de 2019, 14:30:58 »
Hola Killer, efectivamente habia que inicializar i=0;

  Ya funciona.    ¿ Ves? otra tontería que vuelve loco a los menos cautos.

  Ahi lo que ha pasado es que al principio lo planteé con el for, para lo cual no hace falta iniciar el "i" por que ya lo hace el for, pero luego lo quice hacer con el while por que vi que era mejor, pero olvidé iniciar el i.

  De nuevo muchisimas gracias.

   Ya solo queda mirar lo del Baudrate a ver por qué no da lo que debe. Los fuses los he revisado y están configurados para partiendo el cristal que tengo que es de 8 Mhz, de 72 Mhz a la salida y divida entre 2 para el Pbclk.

  Es decir, que debo tener 36 Mhz de pbclk.

  Los cálculos que yo hago por ejemplo para un Baudrate de 115200bps sería:

   UxBRG= 36000000/(16.115200)-1 = (36000000/1845200)-1 = 18 (redondeado).

  Si le pongo ese dato al registro UxBRG el terminal me da frame error.

  Si uso el Autobaudrate y le envío el 0x55, el registro UxBRG se carga con el valor 38. (Eso es algo mas del doble de lo que me está dando a mi la formula). Y entonces ya no tengo frame error, ahora va perfecto.

   Se ocurren dos cosas,  o mi PBCLK va a lo mismo que el clock de cpu (72 Mhz) o el modulo UART no está usando el clock desde el PBCLK.

  Un saludo.



 



Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Array como argumento a función.
« Respuesta #7 en: 28 de Febrero de 2019, 14:44:34 »
Citar
Los fuses los he revisado y están configurados para partiendo el cristal que tengo que es de 8 Mhz, de 72 Mhz a la salida y divida entre 2 para el Pbclk.

Pero no son los FUSES quien determinan el preescaler que afecta al CLK de los perifericos... Sino el registro OSCCON, fijate el registro ese que valores tenes el divisor de los perifericos.

En algo esta mal condigurado.

O esta mal el divisor.
O esta mal la frecuencia de entrada.
O de ultima mal configurado la UART por parte de la funcion debido a que esta mal definida la frecuencia.

Pero si podes enviar aunque sea los valores de los registros para asegurarte. Entonces mejor.

Para que de 38 a 115.200 baudios, es como si tuvieras una frecuencia de 72Mhz de PBCLK
« Última modificación: 28 de Febrero de 2019, 14:51:23 por KILLERJC »

Desconectado remi04

  • PIC24F
  • *****
  • Mensajes: 657
Re:Array como argumento a función.
« Respuesta #8 en: 01 de Marzo de 2019, 08:34:27 »
Hola Killer, he estado mirando el datasheet, el registro OSCCON, concretamente este bit. (PBDIV)

  Pone que por defecto es DIV/8, pero también dice esto:  "On Reset, these bits are set to the value of the FPBDIV Configuration bits (DEVCFG1<13:12>)."

  Es decir, que si no lo configuro desde el main, se quedaría configurado por el FUSE DEVCFC1<13:12>  y eso lo tengo entonces bien.

  De todas formas también he probado al poner en el main: 
Código: C
  1. OSCCONbits.PBDIV = 1;       // PBCLK div/2

  Con el mismo resultado.

  Es como si el modulo UART estuviese tomando el clock de SYSCLK y no de PBCLK.   O bien PBCLK va a lo mismo que SYSCLK.

   Edito:

  He probado por ejemplo el modulo SPI, 
Código: C
  1. while(1) SpiChnPutC(1,0x55);
, que también coge la señal del PBCLK según datasheet, y si le activo el divisor /4, en el osciloscopio (el mio es de 20 Mhz) consigo ver la señal de clock a 18 Mhz.

  En mi programa el SYSCLK está configurado a 72 Mhz, eso me confirma entonces que el PBCLK va a 72 MHZ diga lo que diga el FUSE DEVCFC1<13:12> y diga lo que diga OSCCON <20:19>

 He estado viendo la Silicon Errata y no aparece nada al respecto, solo dice que si se modifica PBCLK al vuelo (mediante el registro OSCCON hay que dejar antes y después 64  NOP para evitar que pueda causar excepciones).

 A ver, por mi, me da igual que PBCLK trabaje a 72 Mhz, teniéndolo en cuenta me basta. Pero me mosquea que tenga que tomar esa decisión forzada y no haber sido capaz de hacer funcionar algo que debería funcionar. Soy así de cabezón. Si algo tiene que funcionar y no funciona soy de los que se come la cabeza hasta que dilucide el por qué. No soy de los que se conformen poniendo las cosas así por que sí, por que "Así me funciona y punto".
« Última modificación: 01 de Marzo de 2019, 09:43:37 por remi04 »