Autor Tema: Microcursillo en C  (Leído 178982 veces)

0 Usuarios y 3 Visitantes están viendo este tema.

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
RE: Microcursillo en C
« Respuesta #45 en: 12 de Agosto de 2004, 17:58:00 »
Muy didáctico Modulay. Practicaré con ello en los próximos ejemplos.

Con respecto al problema que tenía con mis comunicaciones serie, ya lo he resuelto. Y no era problema del cristal.

Resulta que tenía conectado al MAX232 la salida DTS del puerto serie para que, una vez adaptada a niveles TTL, me hiciera Reset en el micro a través de la patilla MCLR. De esta manera, cuando lo grababa con el PICDownloader, no tenía que tocar nada; el software hacía reset automáticamente y enviaba el programa.

Pues bien, esta conexión impedía el funcionamiento correcto del puerto serie. Ahora bien, me pregunto porqué. ¿Cuál es el funcionamiento de la señal DTS en una comunicación serie?, ¿porque impide que funcione?

Gracias

Desconectado oshow

  • PIC18
  • ****
  • Mensajes: 321
RE: Microcursillo en C
« Respuesta #46 en: 12 de Agosto de 2004, 18:08:00 »
Hola Modulay, tengo dos preguntas sobre el 2º codigo que has puesto, bueno, mejor un apunte y una pregunta.

El apunte, bueno según lo poco que sé de esto, num1 no es un parámetro de entrada por referencia, sino por valor ( o al menos así me explicaron), si fuese por referencia (como el tercer argumento de la función) si se podría modificar, sin embargo es una "copia del valor" de la variable, por eso lo de "paso por valor".

Bueno, ahora la pregunta, me puedes explicar como funciona realmente el paso del tercer argumento de la función?. Yo personalmente, para modificar una variable dentro de una función, la paso por referencia usando punteros, pero es la primera vez que veo tu forma de hacerlo, pasando la dirección de la variable en la definición de la función, te pongo aquí lo que hago yo habitualmente...

Codigo:

#include <16F877A.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#include "lcd.c"


void suma(int num1,int num2,long int *res)
   {
   // "num1" y "num2" son parámetros de entrada.
   // "res" es de entrada-salida.
   // "num1" es un parámetro de entrada por referencia,ya tiene como referencia
   // a una variable ("numero" del main).Al ser un parámetro de entrada,cuando se produce
   // la llamada al procedimiento,se crea una copia de dicho parámetro y el procedimiento
   // trabaja con dicha copia,y no con el original como cabe pensar.
   // "num2" es un parámetro pasado por valor,ya que tiene como origen un valor
   // constante(23),y no una variable.Al ser sólo de entrada,también se crea una copia en
   // memoria con la que trabajaremos y que será destruída,al igual que "num1",cuando
   // acabe la ejecución de la rutina.
   // Por último nuestro parámetro de entrada-salida.Ni que decir tiene que un parámetro
   // de entrada-salida JAMAS DE LOS JAMASES puede ser pasado por valor.
   // Deberá tener SIEMPRE como origen una variable.
   // Esta vez,al ser un parámetro de entrada-salida,susceptible de ser modificado,el
   // el procedimiento no hace copia ninguna y trabaja con el original.
   *res = num1 + num2;  // Asiganmos a "res" la suma de los otros 2 parámetros
   }


void main()
   {
   // Declarar variables en el programa principal es casi como declararlas globales,
   // por lo que tampoco es lo más óptimo.
   int numero;
   long int resultado;
   lcd_init();
   resultado = 0;  // Esta acción es superflua ya que vamos a modificar su valor en breve.
   // suma() lleva 3 parámetros: uno por valor y dos por referencia.
   suma(numero,23,&resultado);    // Llamada al procedimiento suma()
   // "resultado" ha sido modificado y devuelto por el procedimiento suma()
   printf(lcd_putc,"%lu",resultado);   // La mostramos en el lcd
   for(;
     {}
  }




Saludos.

Desconectado Modulay

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 2651
RE: Microcursillo en C
« Respuesta #47 en: 12 de Agosto de 2004, 18:16:00 »
Cuando te refieres a DTS,supongo que lo harás a RTS(yo lo conozco con ese nombre,no se si será el correcto).En definitiva,el pin 6 del puerto.
Bien,este terminal del puerto serie es de salida y es usado por el pc para avisar al dispositivo que tenga conectado que tiene datos para enviar,y funciona conjuntamente con  el terminal de entrada DSR(pin 7),por el que le entrará la respuesta que proporcione el pic o dispositivo conectado a la solicitud-aviso enviada mediante DTS:

pc tiene datos para enviar y pone DTS a 1 -> pic responde poniendo un 1 en DSR -> pc recibe respuesta y envía los datos.

Es por esto que se suelen puentear los pines 6 y 7 cuando se implementa una puerto para comunicación serie en un circuito,de esa forma,la solicitud de envío de datos formulada por el pc es contestada a sí misma.
De la misma forma tb se puentean los pines 8(CTS) y 4(DTR) para el mismo objetivo,pero esta vez cuando el flujo de datos va en sentido contrario.
En cuanto a que fuera la causa de tu problema,si dices que lo tenías conectado al MCLR del pic,posiblemente te lo estuviera reseteando.
Un saludo

Desconectado Modulay

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 2651
RE: Microcursillo en C
« Respuesta #48 en: 12 de Agosto de 2004, 18:35:00 »
Haciéndolo así consigues lo mismo pero con una pequeña diferencia,oshow.
Yo,al poner "&" delante del parámetro en la cabecera del procedimiento,lo que hago es que dicho procedimiento tome como dato la dirección de memoria del parámetro de origen para trabajar directamente con él,es decir estoy usando sin darme cuenta un puntero.
Al hacerlo como describes,el parámetro en la llamada es una dirección de memoria :
&dato = dirección en memoria de dato
En la cabecera del procedimiento,al poner el * delante del parámetro lo que consigues esta vez es deshacer el cambio y proporcionarle a la rutina el dato en sí mismo,pero con una pega,que se crea una copia en memoria.
De ahí la importancia de poner el dichoso & delante de los parámetros de entrada-salida (PERO SOLO EN LA CABECERA DE LA RUTINA!,NO EN LA LLAMADA!).Ese pequeño detalle te ahorra memoria por cada vez que lo uses,al indicarle al compilador que debe trabajar de forma dinámica con los datos.
En cuanto a lo por valor o por referencia,puede que tengas razón y que me haya embalado un poco con los conceptos.
Lo miraré a ver.Gracias.
Saludotess!!

Desconectado oshow

  • PIC18
  • ****
  • Mensajes: 321
RE: Microcursillo en C
« Respuesta #49 en: 12 de Agosto de 2004, 18:42:00 »
Gracias a tí por la explicación , máquina...

La verdad nunca había trabajado dinámicamente con los datos, me pondré al día y lo intentaré usar más a menudo.

Gracias.

Saludos

Desconectado Modulay

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 2651
RE: Microcursillo en C
« Respuesta #50 en: 12 de Agosto de 2004, 18:45:00 »
Definitivamente sí,tienes razón.
Por valor significa de entrada,se copia el valor del parámetro de origen(sea constante o variable) y se trabaja con dicha copia.
Por referencia implica entrada-salida,uso de un puntero asociado al parámetro y manejo dinámico de dicho parámetro.
Ya está corregido.
Echale un vistazo a lo del Symbol map,probando a tu forma,a la que expuse yo,a la que se te ocurra,observando qué datos se crean en memoria.
Un saludo

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
RE: Microcursillo en C
« Respuesta #51 en: 13 de Agosto de 2004, 00:40:00 »
Sí, era RTS, Modulay.

Pienso que efectivamente me resetea el PIC a la vez que intenta la comunicación, pero hay dos cosas extrañas:
- tengo al principio del programa unas instrucciones para que se encienda un led durante una décima de segundo cuando arranca. Si hago reset a mano veo como efectivamente se enciende. Sin embargo, cuando sospechamos que está reseteándose, no veo encenderse al led en ningún momento.
- ¿porqué funciona perfectamente la comunicación serie cuando grabo el micro con el PicDownloader?

Seguiré investigando

Desconectado Modulay

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 2651
RE: Microcursillo en C
« Respuesta #52 en: 13 de Agosto de 2004, 01:12:00 »
No veo por que ha de encenderse ese led si el micro se mantiene reseteado.Si RTS está a 0 porque el pc no tiene nada para enviar,el reset será permanente ¿no?
¿A qué te refieres con la última pregunta? No termino de entenderla

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
RE: Microcursillo en C
« Respuesta #53 en: 13 de Agosto de 2004, 02:25:00 »
Bien, puede ser que esté siempre reseteado. Pensé que la señal RTS oscilaba; si es continua puede ser una explicación.

Con respecto al segundo tema, me refiero a que cuando grabo el PIC con el Bootloader y el PICDownloader utilizo una comunicación serie con el PC y ahí no falla, aunque tenga conectado el RTS.

Desconectado T0ni0

  • PIC16
  • ***
  • Mensajes: 196
RE: Microcursillo en C
« Respuesta #54 en: 13 de Agosto de 2004, 10:59:00 »
Vamo a ver, en principio instaldo el CCS 3.155 y funcionando, he probado las rutinas anteriores NP pero con el el LCD ... es otro asunto, no he sabido ver en que puerto esta ( yo uso un PICDEM 2 PLUS con un PIC16F876) y al compilar me da error en los set_tris_ me faltará alguna rutina? o inicializar algun parámetro?

Mi siguiente paso va a ser dos entradas analógicas. Por cierto que se pondria en la atención de la interupción de la UART?  

Vale vale poco a poco
- T0ni0 -
30RCF112

Desconectado Modulay

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 2651
RE: Microcursillo en C
« Respuesta #55 en: 13 de Agosto de 2004, 15:23:00 »
Holas,Tonio.
CCS y su librería "lcd.c" asumen por defecto que tienes el lcd conectado al puerto D.
Ya que un 16F876 carece de puerto D vale con añadir esta línea a tu código en la parte de preprocesado:
#define use_portb_lcd TRUE
Con ello le dices al compilador que tienes conectado el lcd al puerto B y dejará de darte ese error al compilar.
Para saber como tienes que tener el conexionado de las líneas de datos y las de control,abre el archivo "lcd.c" (está en PICC-> drivers) y fíjate en las primeras líneas de código.Deberías tener algo así,posiblemente en diferente orden.Dicho orden dependerá de como conectes los pines del lcd al pic:
Codigo:

struct lcd_pin_map {
           BOOLEAN unused;    // RB0  (sin conectar a nada)
           BOOLEAN rs;        // RB1
           BOOLEAN rw;        // RB2
           BOOLEAN enable;    // RB3
           int     data : 4;  // RB4 a RB7
        } lcd;




Así,si en vez de "unused",en la primera línea tienes "rs",dicho pin del lcd irá conectado a RB0.De la misma forma todo lo demás
Ya nos cuentas como te fue.
Saludos

Desconectado T0ni0

  • PIC16
  • ***
  • Mensajes: 196
RE: Microcursillo en C
« Respuesta #56 en: 14 de Agosto de 2004, 04:30:00 »
Haber sobre la LCD, a quien le intertese:

En la PICDEM2 PLUS hay una LCD de 4 bits que solo está conectada al zocalo de 40 pines, está como sigue: E=RA1, R/W=RA2, RS=RA3, RD0:RD3 son los datos.

Como yo utilizo un 16F876 ( si tengo el de 40 pines pero digamos que no me gusta mucho)  de momento voy ha esperar con la LCD y lo voy a printar por la UART.

Más adelante ya lo probare con el grande haber como adapto las rutinas para 4 bits ok gracias por todo.

PD: alguien sabe como puedo depurar con un ICD2?
- T0ni0 -
30RCF112

Desconectado gfp

  • PIC18
  • ****
  • Mensajes: 274
RE: Microcursillo en C
« Respuesta #57 en: 14 de Agosto de 2004, 10:16:00 »
Mira este recorte de código, a mi me funcionó a las mil maravillas. recibe una trama de caracteres hasta el enter.

Espero te ayude.

GFP

#include <16F877.h>
#include <stdlib.h>
#fuses XT, NOPROTECT, PUT, NOWDT, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use delay (clock=4000000)
#use RS232(BAUD=19200, XMIT=PIN_C6, RCV=PIN_C7)
#zero_ram
void main( void )
{
   char string[4];    //Define la cantidad de caracteres a recibir. Ejemplo 125 y el "enter".
   long int x;       //Se define x cono entero
   while(1)         //Loop infinito
   {
   gets(string);      //Guarda caracteres hasta que recibe enter.
   x = atoi32(string);   //Convierte los 3 caracteres ascii recibidos a un numero entero. Ejemplo 1,2,3 quedaría x=123
//Bla-bla-bla
   }
}

Desconectado Modulay

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 2651
RE: Microcursillo en C
« Respuesta #58 en: 14 de Agosto de 2004, 14:37:00 »
Otro buen ejemplo para seguir ampliando este cursillo,gracias gfp.
Se me ocurre tocar otro tema interesante.
Hasta ahora hemos visto que nuestros programas,además del programa principal,también pueden contar con una serie de rutinas para hacerlo mas modular.Estos subprogramas,hasta el momento han sido todos del tipo "void".Pero podemos usar otro tipo de procedimientos llamados funciones.Las funciones tienen como cometido hacer una serie de operaciones para finalmente DEVOLVER un valor,ya sea de tipo entero,caracter,real,booleano...
Una vez está implementada,el manejo de una función es casi el mismo que el que se le da a una variable del mismo tipo,a excepción de que mientras a una variable le podemos asignar un valor con "=",a una función no le podemos asignar nada.Sólo podemos usarla como fuente,no como destino.
Un ejemplo de una función de tipo entero:

Codigo:

////////////////////////////////////// PREPROCESADO ///////////////////////////////////

#include <16F876.h>
#use delay(clock=20000000)
#fuses HS,NOWDT,NOPUT,NOLVP,NOBROWNOUT,NOWRT
#include "lcd.c"

#use fast_io(B)
#use fast_io(C)

////////////////////////////////////// RUTINAS ///////////////////////////////////////

int entrada_activa()
  {
  if(input(PIN_C0))
    {
    // Esto se ejecuta si RC0 está a 1
    return(0);  // Devolvemos un 0
    }else if(input(PIN_C1)) {
    // Esto se ejecuta si RC1 está a 1
    return(1);  // Devolvemos un 1
    }else if(input(PIN_C2)) {
    // RC2 está a 1
    return(2);  // Devolvemos un 2
    }else if(input(PIN_C3)) {
    // RC3 está a 1
    return(3);
    }else if(input(PIN_C4)) {
    // RC4 está a 1
    return(4);
    }else if(input(PIN_C5)) {
    // RC5 está a 1
    return(5);
    }else if(input(PIN_C6)) {
    // RC6 está a 1
    return(6);
    }else if(input(PIN_C7)){
    // RC7 está a uno
    return(7);
    }else {
    // Si entramos aquí es que no se dió ninguno de los casos anteriores (todas a 0)
    return(8);
    }
  }
 
 
////////////////////////////////////// PRINCIPAL //////////////////////////////////////
 

void main()
   {
   int pin_activo;
   set_tris_c(0xff);  // Puerto C configurado como entrada
   lcd_init();
   pin_activo = entrada_activa();  // Asiganmos a "pin" el valor que devuelve entrada_activa()
   while(TRUE) // Bucle infinito
     {
     if(entrada_activa() > 7)  // Usamos directamente el valor que nos retorne la función
       {
       // entrada_activa() devolvió el valor 8
       printf(lcd_putc,"No hay entradas activas");  
       }else {
       // En otro caso...
       printf(lcd_putc,"El pin %u está a 1",entrada_activa());  // Mostramos qué pin está a 1
       }
     }
   }




Como se ve,la clave de una función es la sentencia "return".
No hay que olvidar que el elemento que acompañe a "return" debe ser del mismo tipo que la función.
Otra forma de hacerlo es declarando una variable dentro de la función,modificarla dentro de la función según nos interese,y finalmente devolver dicha variable.Ocupa más memoria,pero nos libra de escribir tantos returns:

Codigo:

////////////////////////////////////// PREPROCESADO ///////////////////////////////////

#include <16F876.h>
#use delay(clock=20000000)
#fuses HS,NOWDT,NOPUT,NOLVP,NOBROWNOUT,NOWRT
#include "lcd.c"

#use fast_io(B)

////////////////////////////////////// RUTINAS ///////////////////////////////////////

BOOLEAN a_mayor_que_b(int a,int b)
  {
  BOOLEAN mayor; // Esta es la variable que vamos a devolver
  mayor = FALSE; // Las variables booleanas es bueno inicializarlas con algún valor
  if(a >= b)
    {
    // "a" es mayor o igual que "b"
    mayor = TRUE;
    }else {
    // "a" es menor que "b"
    // Aquí no necesitamos hacer mayor=FALSE ya que hemos inicializado "mayor" a FALSE
    }
  return(mayor);
  }
 
////////////////////////////////////// PRINCIPAL //////////////////////////////////////
 

void main()
   {
   int a,b;
   a = 50;
   b = 30;
   if(a_mayor_que_b(a,b))
     {
     // La función ha devuelto TRUE
     output_high(PIN_B1);  // Por ejemplo :)
     }else if(!a_mayor_que_b(a,b)) {
     // La función ha devuelto FALSE
     output_high(PIN_B2);
     }
   }




Igual que los subprogramas,las funciones también pueden llevar parámetros,pero únicamente de entrada,nunca de entrada-salida.
Ah,se me olvidaba...Una vez que nos encontramos con un "return",acaba la ejecución de la función y volvemos al punto desde donde fué llamada.
Saludos

Desconectado Duende_Azul

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 902
RE: Microcursillo en C
« Respuesta #59 en: 14 de Agosto de 2004, 17:26:00 »
Una impecable exposición, gracias por este conocimiento, por cierto  ¿eres profesor de C?


 

anything