Se puede usar dos registros o variables de 8 bit en una variable de 16 bits?

Hola a todos
bueno si leen en el titulo mi duda es la siguiente, ¿se puede guardar dos variables o registros de 8 bits en una variable de 16 bits, uno en el nible bajo y otro en el nible alto?

asi como lo muestro en la imagen:

Captura.PNG

en este caso queria manipular directamente el registro PORTB y PORTD por medio de una variable de 16 bit, se que con el CCS para manipular directamente un registro por medio de una variable es declarandola como puntero, asi que supongo que seria mas sencillo mediante el PROTON BASIC, sea cual sea de estos dos lenguajes, hay alguna manera de manipular dos variables o registros directamente con una sola de 16 bit?, es decir si en mi variable de 16 bit cargo el siguiente valor:

Variable16bit = 1100110011111111

entonces que el valor de los registros sean los siguientes:

PORTB = 11111111 PORTD = 11001100

espero que alguien me pueda dar una mano
saludos
 
Solo si las direcciones fuesen conjuntas creo que seria posible asignando la dirección directamente.
 
La forma más cómoda, en C, es usar uniones, para evitar el trabajo de hacer los desplazamientos:

PHP:
union {
	uint8_t var8[2];
	uint16_t var16;
} variable16;

// ...

variable16.var8[0] = nuevo_valor_PORTD;
variable16.var8[1] = nuevo_valor_PORTD;

*((uint16_t *)PORTD) = variable16.var16;	// depende del compilador si nos deja cambiar el tipo de PORTD

Otra forma es la ya comentada, la de hacer desplazamientos.

El problema está en que no puedes asignar a PORTD un valor de 16 bit, porque el compilador espera solo uno de 8 bit. Lo que necesitas es un puntero a la misma dirección donde está apuntando PORTD, definirla como (uint16_t *) y a partir de ese momento ya puedes escribir en 16 bit.

Pero, además...

Los PIC tienen distintos tamaños en el mapa de memoria. Por ejemplo, en el PIC16F877A, la memoria se compone de 8 Kpalabras, cada una de ellas de 14 bit, por lo que no se puede almacenar 16 bit "de forma continua". El compilador manejará tu variable de 16 bit como dos de 8, siempre, por lo que no obtendrás muchos beneficios.
 
Última edición por un moderador:
Ojo que la unión no funciona de esa forma, tiene que usar un vector. Ejemplo:

PHP:
#include <stdio.h>

union Prueba
{
    uint8_t vector[2];
    uint16_t var_16bits;
};

int main()
{
    union Prueba aux;

    aux.vector[1]=0xab;
    aux.vector[0]=0xcd;
    
    printf("El resultado es: %x",aux.var_16bits);
    return 0;
}

Otra más sencilla todavía es usar punteros en la variable de 16 bits, pero no vale la pena marear al compañero, ya tiene dos opciones útiles.

Acá les dejo la otra opción si les interesa:

https://www.forosdeelectronica.com/posts/978767/
 
Última edición:
¡Oops, perdón! Es cierto... me colé.

La unión es justo eso: la unión de varios campos en el mismo espacio de memoria.

¡Editado!
 
Última edición por un moderador:
Si la memoria no me falla lo más simple para realizar eso es lo siguiente:

#include <main.h>

void main()
{
#define _porta 0x006
#define _portb 0x005
int16 _word;
#byte _word_lb = _word
#byte _word_hb = _word + 1

while(TRUE)
{
_word_lb = _porta;
_word_hb = _portb;
}

}

Creo que una variable de 16bit tiene byte alto y byte bajo.
y una variable de 8bit tiene nibble alto y nibble bajo.

En Proton no se, pero en lenguaje Basic PSI es muy fácil porque el compilador puede manejar bit y byte de forma directa, también todos los registros del micro están integrados:

Dim _Word as Word 'Declara variable de 16bit (2Bytes).
_Word.HB = PORTA 'El byte alto de _Word se carga con el valor del puerto A
_Word.LB = PORTB 'El byte bajo de _Word se carga con el valor del puerto B
 
Última edición:
No mas un poco de terminología! Un nibble son 4 bits, un byte son 8, un word son 16 bits. Así en tu pregunta correctamente debes reemplazar la palabra "nibble" contra "byte"!
 
En realidad el ejemplo de la unión para este caso quedaría así:

union Prueba
{
int8 vector[1];
int16 var_16bits;
};

void main()
{
while(TRUE){

{
union Prueba aux;

aux.vector[1]=0xab;
aux.vector[0]=0xcd;

printf("El resultado es: %Lx",aux.var_16bits);
putc(lf);
putc(cr);
delay_ms(1000);
}

}
 
Con el vector estás apuntando a una dirección no definida, es probable que en este caso en particular no tengas problemas porque implícitamente esa área de memoria está definida por la variable de 16 bits debido a la unión. Pero... es mala práctica usar mal los vectores. ;)
 
Gracias a todos por la ayuda.
Revisaré detalladamente sus recomendaciones, si hay algún problema se los comentare.

Por cierto, ¿esto funciona también en Basic, ya sea Proton Basic, o PICBasic Pro?

Saludos

EDIT:
Quisiera saber un poco más a profundidad esto de UNION.
¿Dónde puedo encontrar un buen documento que detallara este tema?
 
Última edición por un moderador:
Acá tenés algo:

http://www.tutorialspoint.com/cprogramming/c_unions.htm

También ye recomiendo que "consigas" este libro:

EL%20LENGUAJE%20DE%20PROGRAMACION%20EN%20C%20KERNIGHAN%20%26%20RITCHIE.JPG


Sobre el tema del basic, no creo que se pueda implementar este tipo de estructura de datos con memoria compartida, es algo bien de C.

Este sería el mapa de memoria compartida de este ejemplo, todo el bloque implican 16 bits (2 bytes) compartidos:

Mapa de memoria.png
 
Última edición:
Por cierto, ¿esto funciona también en Basic, ya sea Proton Basic, o PICBasic Pro?
En basic no se puede la unión pero hacer eso no es tan rebuscado como en c.
Digamos en pbp solo se pone donde quieras así
Var=var1.highbyte
Var=var1.lowbyte y listo
En código maquina genera unos cuantos ciclos de instrucción.

eso es lo que no me gusta de C, es cierto que tiene mas funciones pero no significa que en codigo maquina se simplifique, en ocaciones termina generando mucho mas codigo XD.
 
Última edición:
Seguramente ese basic tendrá alguna función. Si no la tiene:

Vector= bajo+alto*256

O al revés:

Alto=int(vector/256)
Bajo=vector-alto*256
 
Seguramente ese basic tendrá alguna función.

Estuve revisando el codigo en esamblador que genera PBP y en realidad es el tipico corrimiento (o desplazamiento) "<<" como menciona cosmefulanito en su mensaje #3, que pienso es lo que menos codigo maquina generaria.

y si es basicamente lo que mencionas.
 
Última edición:
Sin dudas lo mejor es la union, el uP no tiene que hacer nada, solo apuntar bien en memoria, por lo tanto una union termina siendo una simple asignación.

muy cierto (y)

bueno una manera de hacer la "union" en basic (yo estoy hablando de basic porque pregunto, sino ni me meto :LOL:) es leyendo o escribiendo directamente al registro con peek o poke. e igual hay que apuntar y tirar en el momento indicado :LOL: pero sigue siendo diferente a lo que es la union de C.
 
yo no multiplcaria por 255

lo que yo haria para unir todo seria con rotar n bits en este caso 8

asi :

int 16bits;

char byte1;
char byte2;

para unirlos es bien facil

16bits=byte1 | byte2<<8;

como se `puede ver se hace muy poco uso del CPU pues uso 1 instruccion logica OR para sumar
y una <<y un rotado de bits en este caso lo movi 8 veces a la izquierda

no use funciones de suma ni multiplicaciones que en ASM se hace largo el codigo robando vitales ciclos de CPU
 
Oh, entendí mal la pregunta, creí que quería apuntar directamente la memoria.

En este caso el bitwise de corrimiento de carro y OR es lo ideal, son operaciones que tienen equivalentes en código máquina y es lo más optimo, además, son símbolos básicos que cualquier lenguaje y compilador interpretará adecuadamente.
 
Oh, entendí mal la pregunta, creí que quería apuntar directamente la memoria.

No está mal lo que planteaste, para mí es una buena solución, pero puede resultar más difícil de verlo en C, en assembler no tanto, ya que se supone que uno está acostumbrado a ese tipo de cosas.

De hecho la unión no es más que eso, pero que te ayuda a evitar el uso de punteros y tener que pensar en direcciones de memoria.
 
Atrás
Arriba