operadores desplazamiento bitwise c bit-manipulation motordriver

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; }

Demostración en vivo .