Autor Tema: Asignar variable de 3bits a puerto  (Leído 3960 veces)

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

Desconectado dogflu66

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 3510
Re:Asignar variable de 3bits a puerto
« Respuesta #15 en: 10 de Octubre de 2015, 09:39:48 »
Según tenga más tiempo seguiré probando las otras implementaciones.
Saludos desde Granada, España.

Desconectado dogflu66

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 3510
Re: Asignar variable de 3bits a puerto
« Respuesta #16 en: 11 de Octubre de 2015, 07:51:42 »
Hola, de que si se puede, claro que si se puede, pero no se si vale el esfuerzo.  :lol: El codigo esta en C18.
Código: C
  1. struct MyPort           // Se define la estructura
  2.   {
  3.         unsigned HIGH:5;
  4.         unsigned LOW:3;
  5.   };
  6.   struct MyPort *pMyPortD;  // se crea un puntero para el tipo de estructura
  7.  
  8. void main() {
  9.  
  10.   TRISB=0xFF;
  11.   TRISD=0x00;          
  12.   ADCON1 = 0x0F;
  13.        
  14.   pMyPortD = (struct MyPort *) &(PORTD);        // se inicializa el puntero con la direccion del puerto D
  15.  
  16.  
  17.   do {
  18.  
  19.     pMyPortD->HIGH = 0x0;        // Turn OFF HIGH LEDs on PORTD
  20.     pMyPortD->LOW = 0x7;        // Turn ON LOW LEDs on PORTD
  21.         Delay10KTCYx(250);                      //  delay
  22.  
  23.     pMyPortD->HIGH = 0x1F;        // Turn ON HIGH LEDs on PORTD
  24.     pMyPortD->LOW = 0x0;        // Turn OFF LOW LEDs on PORTD
  25.         Delay10KTCYx(250);                      // delay
  26.  
  27.   } while(1);
  28. }

En realidad este y el anterior son el mismo, pero se me paso el ejemplo.

Este es el mismo que el anterior pero una versión algo más simplificada. Hace lo mismo mediante el mismo método (en este caso algo más simple) pero se adapta mejor a la función, porque va mejor con la simplicidad de la función.

Código: [Seleccionar]
//Selecciona el Display de 7Segmentos activo e imprime el digito.
//_numero a imprimir, _power = 1 display on
Void _Display(Int16 _numero, int1 _power) {
   struct MyPort {
      unsigned BIT3 : 3;
   }Port = 1;
   struct MyPort *pMyPortA;
   pMyPortA = (struct MyPort *) &(PORTA);
 
   Static Int8 n = 0;
   //Int8 i = 1;
   Int8 _digito = 0;

   If (_numero > 999) _numero = 999; //Acota superior el numero
   //Descompone en digitos para numero >= 100
   If (_numero >= 100) {
      If (n == 2) _digito = _numero / 100;
      else If (n == 1) _digito = ((_numero / 10) % 10);
      else If (n == 0) _digito = _numero % 10;
   }
   else If (_numero >= 10) { //Descompone en digitos para numero >= 10
      If (n == 1) _digito = _numero / 10;
      else If (n == 0) _digito = _numero % 10;
   }
   else If (n == 0) _digito = _numero; //Extrae el digito para numero < 10
   
   If (n == 1) PORTB = _get7seg1(_digito); //Asigna la mascara del digito con punto decimal 
   else PORTB = _get7seg(_digito); //Asigna la mascara del digito sin punto decimal

   //If (_power == 0) i = 0; //Apaga el display
   If (_power == 0) Port.BIT3 = 0;
   pMyPortA -> BIT3 = Port.BIT3 << n;
   //PORTA = (PORTA & 0b11111000) | (i << n); //Selecciona el digito a iluminar.
   if (n < 2) n++; //Proximo digito a iluminar (digitos 0 to 2)
   else n = 0; //Reinicia el ciclo de refresco
}
« Última modificación: 11 de Octubre de 2015, 07:54:45 por dogflu66 »
Saludos desde Granada, España.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Asignar variable de 3bits a puerto
« Respuesta #17 en: 11 de Octubre de 2015, 08:00:00 »
El mio no se si funciona. Para XC8 creo que funcionaria directo. Y para CCS habria que definir PORTx para que funcione, luego cambiarle el puerto en el #define. La verdad es que no lo probe.

Y todo eso si es que funciona xD, nunca probe ese metodo, lo vi y bueno, pense ponerlo aca. Me refiero a este:

Código: C++
  1. #define encender_display(pin)   _display(A,pin,0x07,1,0)
  2.     #define apagar_display()        _display(A,pin,0x07,0,0)
  3.     #define _display(puerto,bit,andvalue,set,ofs) PORT ## puerto = ( PORT ## puerto & ~( andvalue ) )|( set << ( bit + ofst ))

Y luego usarias encender_display(n) y apagar_display() , incluso se podria complicar un poco mas el #define para que directamente solo tome de 0 a 3, y que 0 apague, 1 encienda el 1 y asi. y tener solo una definicion de funcion. Luego en el codigo se reemplaza por una AND + OR y listo.
y n en encender_display(n) toma el valor de 0,1,2, si es que no se agrega un offset.
« Última modificación: 11 de Octubre de 2015, 08:02:54 por KILLERJC »

Desconectado dogflu66

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 3510
Re:Asignar variable de 3bits a puerto
« Respuesta #18 en: 11 de Octubre de 2015, 08:15:32 »
El tuyo también lo voy a experimentar, en el caso de que no consiga ponerlo en marcha lo indico, para así atacarle hasta adaptarlo a la función.

Nota:
   struct MyPort {
      unsigned BIT3 : 3;
   }Port = 1;
   struct MyPort *pMyPortA;
   pMyPortA = (struct MyPort *) &(PORTA);

Tenia curiosidad por saber si el CCS entendería que pMyPortA espera la asignación de una dirección de memoria y realmente es así:

   struct MyPort {
      unsigned BIT3 : 3;
   }Port = 1;
   struct MyPort *pMyPortA;
   pMyPortA = &(PORTA);

Acepta la modificación y no genera avisos.

Incluso esta: struct MyPort *pMyPortA = &(PORTA);

« Última modificación: 11 de Octubre de 2015, 08:22:10 por dogflu66 »
Saludos desde Granada, España.

Desconectado acabello

  • PIC10
  • *
  • Mensajes: 18
Re:Asignar variable de 3bits a puerto
« Respuesta #19 en: 11 de Octubre de 2015, 20:48:11 »
 Una forma mas.

Código: [Seleccionar]
#define display(n) LATAbits.LATA0 =(n & 1); LATAbits.LATA1 = (n & 2)>>1; LATAbits.LATA2 = (n & 4)>>2;

display(0); // Apaga todos
display(1); // Enciende el 1
display(2); // Enciende el 2
display(3); // Enciende el 1 y el 2



Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Asignar variable de 3bits a puerto
« Respuesta #20 en: 12 de Octubre de 2015, 03:08:37 »
Bueno despues de corregir un par de cosas, probe mi forma en XC8

Código: C++
  1. #include "xc.h"
  2.  
  3. #define display(pin)   _display(A,pin,0x07)
  4. #define _display(puerto,bit,andvalue) PORT ## puerto = ( PORT ## puerto & ~( andvalue ) )|( (bit?1:0) << ( bit-1 ))
  5.  
  6. int main() {
  7.    
  8.     TRISB = 0x0F;
  9.     ANSEL = 0;
  10.     ANSELH = 0;
  11.     PORTB = 0;
  12.  
  13.     while(1){
  14.         display(1); //Enciende display 1 (RA0)
  15.         display(2); //Enciende display 2 (RA1)
  16.         display(3); //Enciende display 3 (RA2)
  17.         display(0); //Apaga los displays
  18.     }
  19.    
  20. }

Resultado en ASM

Código: ASM
  1. !        display(1);
  2. 0x7E8: MOVF PORTA, W
  3. 0x7E9: ANDLW 0xF8
  4. 0x7EA: IORLW 0x1
  5. 0x7EB: MOVWF PORTA
  6. !        display(2);
  7. 0x7EC: MOVF PORTA, W
  8. 0x7ED: ANDLW 0xF8
  9. 0x7EE: IORLW 0x2
  10. 0x7EF: MOVWF PORTA
  11. !        display(3);
  12. 0x7F0: MOVF PORTA, W
  13. 0x7F1: ANDLW 0xF8
  14. 0x7F2: IORLW 0x4
  15. 0x7F3: MOVWF PORTA
  16. !        display(0);
  17. 0x7F4: MOVF PORTA, W
  18. 0x7F5: ANDLW 0xF8
  19. 0x7F6: MOVWF PORTA

Es decir el minimo numero de instrucciones posibles para llevar a cabo lo que se debe hacer.
Lo malo es el de no estar limitado a solo 3, pero que seguro dandole vueltas al define se podria hacer.
Y esta realizado para los primeros 3 bits, nada que no se pueda modificar
« Última modificación: 12 de Octubre de 2015, 05:01:46 por KILLERJC »

Desconectado dogflu66

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 3510
Re:Asignar variable de 3bits a puerto
« Respuesta #21 en: 12 de Octubre de 2015, 08:21:44 »
Tengo que dejar el tema unos cuantos días, seguramente el "finde" que viene retomare el tema.
Saludos desde Granada, España.

Desconectado acabello

  • PIC10
  • *
  • Mensajes: 18
Re:Asignar variable de 3bits a puerto
« Respuesta #22 en: 12 de Octubre de 2015, 12:19:38 »

Solo para verificar el codigo que produce genere el asm, pero no se cuantos ciclos dura cada instruccion

Código: C++
  1. #define display(n) LATAbits.LATA0 =(n==1?1:0); LATAbits.LATA1 =(n==2?1:0); LATAbits.LATA2 =(n==3?1:0);
  2.  
  3.         display(1);
  4.         display(2);
  5.         display(3);
  6.         display(0);

Código: ASM
  1. 5(  63): bsf LATAbits, 0, 0      
  2.    6(  63): bcf LATAbits, 1, 0      
  3.    7(  63): bcf LATAbits, 2, 0
  4.        
  5.    8(  64): bcf LATAbits, 0, 0      
  6.    9(  64): bsf LATAbits, 1, 0      
  7.   10(  64): bcf LATAbits, 2, 0
  8.        
  9.   11(  65): bcf LATAbits, 0, 0      
  10.   12(  65): bcf LATAbits, 1, 0      
  11.   13(  65): bsf LATAbits, 2, 0
  12.        
  13.   14(  66): bcf LATAbits, 0, 0      
  14.   15(  66): bcf LATAbits, 1, 0      
  15.   16(  66): bcf LATAbits, 2, 0

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Asignar variable de 3bits a puerto
« Respuesta #23 en: 12 de Octubre de 2015, 18:34:47 »
Citar
Solo para verificar el codigo que produce genere el asm, pero no se cuantos ciclos dura cada instruccion

Duran un ciclo cada una. El problema es la aplicacion. a muchos aplicaciones no les molesta. Solo para que entiendas lo que estas haciendo y los posibles problemas:

Suponete que tenes el puerto en 0x04 (display 3 encendido), es decir 0000 0100 , ejecutando esas instrucciones para encender el segundo display ocurriria esto:

1ra instruccion: 0000 0100
2da instruccion: 0000 0110
3ra instruccion: 0000 0010

Momentaneamente tenes los 2 activos, tal ves 1us o menos segun el clock. En un display en el cual manejas solo los anodos no creo que afecte en nada. no llegarian ni a encender creo.
Tambien tenes que ver que PIC estas trabajando. En tu caso es un PIC18, pero si es un PIC16 hacer eso puede traer otros problemas mas. El PIC18 cuando lee toma el valor del LATx ( este registro no esta conectado con la entrada del pin ) lo modifica en el nucleo y lo guarda.
En un PIC16 ocurre algo similar, nomas que usa el PORTx , ocurre que si haces esto:

bcf PORTAbits, 0, 0       
bsf PORTAbits, 1, 0       
bcf PORTAbits, 2, 0

Y tu diseño tiene una buena capacidad en sus pines vas a tener un error. ejemplo Supongamos que tenes algo conectado con una buena capacidad al pin PORTA,0 , tenes activo ese pin y luego ejecutas el codigo anterior. Ocurriria esto:

Antes de las instruccion:  0000 0001
1ra instruccion: 0000 0001  ( Intenta ponerlo a 0, es decir puso a 0 el tipo D, PERO por la capacidad en el pin la tension no baja rapido, ademas cuando lees,  lees el PIN no el LATCH o valor que le diste de salida )
2da instruccion: El nucleo lee: 0000 0001 (no lee el tipo D, sino el PIN) , modifica 0000 0011 , escribe 0000 0011 (Se perdio el 0 anterior asi que vuelve a 1 en bit de antes)
3ra instruccion: 0000 0011

Por eso mismo tenes que tenerlo en cuenta. Es aplicable si no ocurren estas cosas, por eso mismo los PIC18 ya traen en LATx y usamos el PORTx para leer del pin.
Yo jamas tuve problemas pero por lo que lei en los foros de Microchip en los PIC16 en algunos casos era algo serio. de tal forma que todos los cambios se hacian en una "variable" y luego se pasaba la variable completa al puerto.

Desconectado acabello

  • PIC10
  • *
  • Mensajes: 18
Re:Asignar variable de 3bits a puerto
« Respuesta #24 en: 12 de Octubre de 2015, 19:04:20 »
Interesante, entonces esa seria una buena conclusion, tratar de no modificar bit a bit sino todo el puerto.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Asignar variable de 3bits a puerto
« Respuesta #25 en: 12 de Octubre de 2015, 19:22:04 »
Interesante, entonces esa seria una buena conclusion, tratar de no modificar bit a bit sino todo el puerto.

Tu solucion es totalmente valida.

Y la forma de hacerlo va a  depender de tu aplicacion , el PIC, lo que tengas conectado, etc. yo soy partidario de hacerlo directamente como lo hice, es decir Tomo el valor del puerto ( para no modificar los valores de los anteriores bits), le hago una AND y luego de ser necesario una OR, finalmente al puerto todo junto. En ASM prefiero eso. por esos motivos, pero solo queria remarcar lo que podria ocurrir, solo para que lo tengas en cuenta si es que en algun momento te falla y no sabes que es. Especialmente en los PIC16, el PIC18 solo tendrias que se activan los 2 al mismo tiempo por un muy pequeño momento.

Y esto creo que seria mucho peor
Código: [Seleccionar]
#define data(n) (output_bit(pin_c0, bit_test(n, 0)),output_bit(pin_c1, bit_test(n, 1)),output_bit(pin_c2, bit_test(n, 2)))
Ya que los bit_test devolverian un 1 o un 0, usando 3 instrucciones como minimo, El hacer eso significaria casi 6 instrucciones ASM por cada uno de estos:
output_bit(pin_c2, bit_test(n, 2))
Encima se realizarian todos en distintos tiempos, Se toma el valor del primero y se cambia, luego se toma el valor del otro pin y se cambia, tal ves un tema de velocidad. Pero si no usa #fast_io en CCS se le va a complicar manejar el puerto para hacer lo mismo que en XC8 y hacer:

#define output_c((input_c()&0xF8)|(1<<n))

Peero.. nuevamente depende de la aplicacion y tu necesidad de velocidad y esas cosas. Y todas son validas, no vi el codigo resultante de la estructura. deberia haber realizado una y probado.

EDIT:
Trate de realizar el codigo de la estructura y no funciono para nada. Siempre con errores o terminaba poniendo el dato en cualquier lado.
« Última modificación: 13 de Octubre de 2015, 07:57:12 por KILLERJC »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Asignar variable de 3bits a puerto
« Respuesta #26 en: 13 de Octubre de 2015, 08:10:25 »
El codigo con la estructura no me funciono para nada, asi que tome el ejemplo que usa para modificar los puertos el XC8, y lo modifique:

Código: C
  1. typedef union {
  2.     struct {
  3.         unsigned LOW    :3;
  4.         unsigned HIGH   :5;
  5.     };
  6. } MyPORT_t;
  7. extern volatile MyPORT_t MyPORT @ &PORTB;
  8.  
  9.  
  10. int main() {
  11.    
  12.     TRISB = 0x0F;
  13.     ANSEL = 0;
  14.     ANSELH = 0;
  15.     PORTB = 0;
  16.  
  17.     while(1){
  18.     MyPORT.LOW = 0x7;        // Turn ON LOW LEDs on PORTD
  19.     MyPORT.LOW = 0x0;        // Turn OFF LOW LEDs on PORTD
  20.     MyPORT.LOW = 0x1;
  21.     MyPORT.LOW = 0x2;
  22.     MyPORT.LOW = 0x4;
  23.     }
  24. }

El disasm

Código: ASM
  1. !    MyPORT.LOW = 0x7;        // Turn ON LOW LEDs on PORTD
  2. 0x7EB: MOVLW 0x7
  3. 0x7EC: IORWF PORTB, F
  4. !    MyPORT.LOW = 0x0;        // Turn OFF LOW LEDs on PORTD
  5. 0x7ED: MOVLW 0xF8
  6. 0x7EE: ANDWF PORTB, F
  7. !    MyPORT.LOW = 0x1;
  8. 0x7EF: MOVF PORTB, W
  9. 0x7F0: ANDLW 0xF8
  10. 0x7F1: IORLW 0x1
  11. 0x7F2: MOVWF PORTB
  12. !    MyPORT.LOW = 0x2;
  13. 0x7F3: MOVF PORTB, W
  14. 0x7F4: ANDLW 0xF8
  15. 0x7F5: IORLW 0x2
  16. 0x7F6: MOVWF PORTB
  17. !    MyPORT.LOW = 0x4;
  18. 0x7F7: MOVF PORTB, W
  19. 0x7F8: ANDLW 0xF8
  20. 0x7F9: IORLW 0x4
  21. 0x7FA: MOVWF PORTB

Se puede ver que no siempre hace el mismo codigo, Al principio con PORTB = 0, directamente le pone un 0x7 en una OR al puerto, pero luego en los demas no lo hace y vuelve a hacerlo como el define anterior. Raro...

Igual tal ves esto solo funcione en MPLAB
No creo que sea problema el no leer el puerto para ponerlo en 0 y es aventaja al codigo de los define. Es la unica diferencia, por una sola instruccion al momento de apagar todo. No se si hay otra mas y si va a funcionar obviamente, la desventaja es que no puedo usar el 1 para el primer dispaly, 2 para el segundo, etc.
« Última modificación: 13 de Octubre de 2015, 08:23:19 por KILLERJC »


 

anything