desplazamiento - Bitwise gire a la derecha del valor de 4 bits
desplazamiento de bits en c (9)
si uso un int sin signo de 8 bits, eventualmente rotaré el 1 a la MSB
Entonces, use un cambio y reinicialice el bit que desea cuando el valor se pone a cero. C no tiene una operación de rotación de todos modos, así que tendrás que hacer al menos dos turnos. (Y supongo que C ++ tampoco tiene rotaciones).
x >>= 1;
if (! x) x = 0x08;
Simple, corto para escribir, y obvio en lo que hace. Sí, se compilará en una rama (a menos que el procesador tenga una operación de movimiento condicional), pero hasta que tenga la salida del generador de perfiles para decirle que es importante, simplemente perderá más tiempo pensando en eso de lo que esos ciclos de procesador jamás alcanzarán.
Actualmente estoy tratando de controlar un motor paso a paso usando simples pasos completos. Esto significa que actualmente estoy emitiendo una secuencia de valores como este:
1000
0100
0010
0001
Pensé que una forma fácil de hacer esto era simplemente tomar mi valor de 4 bits y, después de cada paso, realizar una rotación correcta. "Código" obviamente no está siguiendo ningún tipo de sintaxis, simplemente está ahí para ilustrar mis pensamientos:
step = 1000;
//Looping
Motor_Out(step)
//Rotate my step variable right by 1 bit
Rotate_Right(step, 1)
Mi problema es que obviamente no hay tipos de datos simples de 4 bits que pueda usar para esto, y si uso un int sin signo de 8 bits, eventualmente rotaré el 1 a la MSB, lo que significa el 4 bits. valor que realmente me interesa, se convertirá en 0000 para unos pocos pasos.
He leído que puedes usar estructuras y campos de bits para resolver esto, pero la mayoría de las cosas que leo de esto me dicen que es una muy mala idea.
Con solo 4 valores posibles utilizarías una tabla con 9 elementos:
unsigned char table_right[] = { [0x1] = 0x8 , [0x2] = 0x1 , [0x4] = 0x2 , [0x8] = 0x4 };
Cuando necesite el siguiente valor, simplemente use el valor actual como índice:
unsigned char current = 0x4; //value is: 0b0100
unsigned char next = table_right[current]; //returns: 0b0010
assert( next == 0x2 );
Haciendo esto en un bucle, recorrerá los cuatro valores posibles.
Convenientemente, pasar un valor no válido devolverá un cero, por lo que puede escribir una función de obtención que también afirma a continuación! = 0. También debe hacer valer un valor <9 antes de pasar el valor a la matriz.
Haría una matriz con los valores que necesita y cargaría el valor correcto de la matriz. Le llevará 4 bytes, será rápido y resolverá sus problemas incluso si comienza a usar un tipo de motor diferente.
for example:
const char values[4]={1,2,4,8};
int current_value = 0;
....
if(++current_value>=4)current_value=0;
motor = values[current_value];
La aritmética para esto es lo suficientemente simple como para que siempre sea más rápido que el enfoque de tabla:
constexpr unsigned rotate_right_4bit ( unsigned value )
{
return ( value >> 1 ) | ( ( value << 3 ) & 15 );
}
Esto se convierte en 5 líneas de ensamblaje x86 sin sucursales:
lea eax, [0+rdi*8]
shr edi
and eax, 15
or eax, edi
ret
O, alternativamente, si realmente desea ver los índices {3, 2, 1, 0}
, entonces puede dividirlos en 2 funciones, una que "incremente" el índice y la otra que realmente calcula el valor:
constexpr unsigned decrement_mod4 ( unsigned index )
{
return ( index - 1 ) & 3;
}
constexpr unsigned project ( unsigned index )
{
return 1u << index;
}
OMI, la forma más fácil es:
const unsigned char steps[ 4 ] = { 0x08, 0x04, 0x02, 0x01 };
int stepsIdx = 0;
...
const unsigned char step = steps[ stepsIdx++ ];
stepsIdx = stepsIdx % ( sizeof( steps ) / sizeof( steps[ 0 ] ) );
Puedes usar 10001000b
y mod 10000b
y puede obtener 01000100b
00100010b
00010001b
10001000b
repetición.
por ejemplo:
char x = 0x88;
Motor_Out(x & 0xf);
Rotate_Right(step, 1);
Simplemente use un int
para mantener el valor. Cuando haga la copia de rotación, mueva el bit menos significativo al bit 4 y luego cámbielo a la derecha en 1:
int rotate(int value)
{
value |= ((value & 1) << 4); // eg 1001 becomes 11001
value >>= 1; // Now value is 1100
return value;
}
Solo necesita dar salida a 1, 2, 4 y 8. Por lo tanto, puede usar un contador para marcar qué bit establecer alto.
Motor_Out(8 >> i);
i = (i + 1) & 3;
Si desea conducir el motor a mitad de pasos, puede usar una matriz para almacenar los números que necesita.
const unsigned char out[] = {0x8, 0xc, 0x4, 0x6, 0x2, 0x3, 0x1, 0x9};
Motor_out(out[i]);
i = (i + 1) & 7;
Y puedes rotar un entero de 4 bits como este.
((i * 0x11) >> 1) & 0xf
Utilice un tipo de datos de 8 bits (como, por ejemplo, uint8_t
). Inicializarlo a cero. Establezca el bit que desea establecer en los cuatro bits inferiores del byte (por ejemplo, value = 0x08
).
Para cada "rotación" tome el LSB (bit menos significativo) y guárdelo. Cambia un paso a la derecha. Sobrescriba el cuarto bit con el bit que guardó.
Algo como esto:
#include <stdio.h>
#include <stdint.h>
uint8_t rotate_one_right(uint8_t value)
{
unsigned saved_bit = value & 1; // Save the LSB
value >>= 1; // Shift right
value |= saved_bit << 3; // Make the saved bit the nibble MSB
return value;
}
int main(void)
{
uint8_t value = 0x08; // Set the high bit in the low nibble
printf("%02hhx/n", value); // Will print 08
value = rotate_one_right(value);
printf("%02hhx/n", value); // Will print 04
value = rotate_one_right(value);
printf("%02hhx/n", value); // Will print 02
value = rotate_one_right(value);
printf("%02hhx/n", value); // Will print 01
value = rotate_one_right(value);
printf("%02hhx/n", value); // Will print 08 again
return 0;
}