问题是这样子的 协议要求字节低位在左,高位在右,对每个字节做转换处理,逐个交换其高低位,例如11010001,经过0->7,1->6,2->5,3->4对应位的交换,变成10001011。 这里就需要有位操作的知识,参考 位操作运算有什么奇技淫巧?(附源码) 这里我们以8位数据高低位转换为例子: 1#include <stdio.h>: }+ a0 x1 x6 R. ?* Q; @. X2 3unsigned char highAndLowShiftHEX(unsigned char data);9 J/ m6 ?* k' y" n1 s4 C 4void printBin(int n);( G9 k* S7 B! V7 W! F8 X 5 6int main () {6 R4 U+ F# J+ F% q; N3 O% V' O& k 7% W/ ~ l0 O. ]% H5 l+ A 8 highAndLowShiftHEX(209);! v* n5 I" l. H6 h5 z 9 return 0; 10} 11 12unsigned char highAndLowShiftHEX(unsigned char data) ; ^- G( X* b+ m1 h9 C& @ 13{ 0 q% p+ n6 N- ^# Q5 l2 x 14 unsigned char i; 15 unsigned char tmp=0x00; 16 for(i=0;i<8;i++) 17 { 5 T" a6 u; [3 V. x; o 18 tmp=((data>>i)&0x01)|tmp; ! i0 K4 W+ k9 {' ? 19 //printBin(tmp); 20 if(i<7) 2 }! j# [* T# `) o9 E; a 21 tmp=tmp<<1; 22 } 9 r# |" J* ^. K3 G7 h 23 printf("\nafter shift data:"); 24 printBin(tmp); 25 return tmp; 26} 27; A/ T6 L; y$ q# N* ^ 28//由于二进制直观,故写了一个打印二进制的函数 29void printBin(int n) 30{ 31 int len = sizeof(n)*8;//总位数。 32 int i;, F( i2 S7 @6 A5 o- D. Z$ e" N( g; }+ T | 33 if(i == 0)* }5 N" ^0 G9 u% P9 X' \( H6 Y$ y 34 { 35 printf("0"); 36 return;8 _! z0 k8 N, ?* E 37 }9 u9 @" r, m: j \+ T: H- X 38 for(i = len-1; i >= 0; i --)//略去高位0.; r# ^6 @6 w- d3 W 39 { 40 if(n&(1<<i)) break;1 y2 e( |& W' @0 L$ f% F 41 }0 V) o; @6 a. U$ n 420 Z5 n1 r3 J& O/ Z0 e 43 for(;i>=0; i --) 44 printf("%d", (n&(1<<i)) != 0); 45} 熟悉位操作,上述代码实现起来就比较简单。在嵌入式开发中这类问题通常使用蝶式交换法和查表法来实现。 高阶实现?查表法就是将一些值存到内存中,在需要计算的时候查表,但是这种方法会占用额外的存储空间。 所以这里主要介绍一下蝶式交换法,我们以8位数据转换为例。
那么流程图如下:
由此完成了整个位的逆序转换,同样以11010001为例,下面是具体的实现代码: 1#include <stdio.h>2 3unsigned char highAndLowShiftHEX(unsigned char );. s+ s- r& Y: j& I6 f O 4void printBin(int ); 5 6int main () { 7 8 highAndLowShiftHEX(209); 9 return 0;0 R' t7 S! D. v0 K 10} 11 12unsigned char highAndLowShiftHEX(unsigned char data) 13{ 3 ]( `7 [# A6 i. \ 14 data=(data<<4)|(data>>4); 15 data=((data<<2)&0xcc)|((data>>2)&0x33); 16 data=((data<<1)&0xaa)|((data>>1)&0x55); 17 printf(" after shift data=%x \n",data); 18 printBin(data); 19 return data; - q6 X+ n$ {% T, M( l 20}& m- a# Y& d/ }9 d D& S$ Y 21! [8 E4 l. F: q4 k; l 22//由于二进制直观,故写了一个打印二进制的函数' ]: O2 V i$ k% | 23void printBin(int n) 24{ 25 int len = sizeof(n)*8;//总位数。 26 int i; 27 if(i == 0), [3 k4 I7 Y& ?* z% _+ _- q 28 { 29 printf("0");; L8 \9 N$ h5 A 30 return; 31 }% c: D, B9 B5 j9 B, l 32 for(i = len-1; i >= 0; i --)//略去高位0. 33 { 34 if(n&(1<<i)) break; 35 } 36 37 for(;i>=0; i --)/ N& o* y) J, y' L6 o+ Y4 q 38 printf("%d", (n&(1<<i)) != 0); 39}3 j [* O9 s$ k: s 交换字节的高低位并不是一个很常见的问题,遇到该问题时,需要经过仔细的分析,加上对C语言位操作的熟练掌握,就能够很好的解决这一类的问题。 扩展那么我们将其扩展到16位半字数据的高低位转换。 其实原理是跟8位的时候是一样的,采用简单的移位方式对数据的高低位进行转换。熟悉位操作的话代码就相对简单了。 下面是对该思路的具体实现。 1#include <stdio.h>2 3void expandPrintBin(int val2); 4unsigned short HighAndLowSwitchHEX(unsigned short data); 56 [3 B% y K$ B- N& ^. f 6int main () { 7 8 HighAndLowSwitchHEX(38491); 9 return 0; 10}- j0 B" }8 I/ @0 Y; T6 E3 p( a 11/ g* J$ x: t! @ [ 12 x4 \0 m+ o9 f4 L' p. c$ A 13//由于二进制直观,故写了一个扩展的打印二进制的函数 14void expandPrintBin(int val2)3 ?' ?' o" L8 t3 H# |4 |7 F( W 15{2 N- J* T8 N& ]* I2 u) M" z* u 16 int i,k;) j/ Q% {- D/ n1 y. L) e9 ^ 17 unsigned char *p = (unsigned char*)&val2 + 3; //从低位到高位,低端字节计算机& e* |& p5 y' e( N9 S9 U4 w. K; t 18 for( k = 0; k <= 3; k++) `8 ]# A6 F( _# R& { 19 {' B# ]" H. |) ^, p, p+ v 20 int val2 = *(p-k);8 ]; D% e V. \+ ^) d% C' Q 21 for (i = 7; i >= 0; i--)- x& F4 q. I* ~4 Q' C 22 { l% ]- v" I! x& r) B1 l 23 if(val2 & (1 << i)) 24 printf("1"); 25 else+ G! F# k3 ]8 } x5 E 26 printf("0");. i; \ B# Y* s8 N6 S0 S b2 d 27 } 28 printf(" ");+ p# r, ]* c8 h: X4 S 29 } 30} 31unsigned short HighAndLowSwitchHEX(unsigned short data) 32{# A: s) X+ a; d. G 33 unsigned char i = 0; 34 unsigned short temp = 0x0000;0 b. ?, ]) o+ o3 u0 e8 l7 a* s 35 36 for(i = 0; i < 16; i++) 37 {, D! o5 V$ Z. s8 _2 M 38 temp = ((data >> i) & 0x0001) | temp; 39 if(i < 15) 40 {8 `7 q- r; B: h: t5 b$ V% @4 d% d( B' N 41 temp = temp << 1;6 j& T9 d% [5 {, N2 l: ^- w 42 } n4 l) A/ b0 }& ^6 o& g0 H 43 } 44 printf("temp:%x\n\n",temp);2 d$ v o1 k5 _ 45 expandPrintBin(temp);' W1 l: F! o( T4 L* m 46 return temp; K: l7 g: ]# |9 O; ^# ^ 47}' L% \" G1 Q5 G6 g0 d 同样的所谓的蝶式交换法,我引用了字节交换法的例子,我们可以演算一下:
那么流程图如下:
由此完成了整个位的逆序转换,完成了算法的拓展,以1001011001011011为例,下面是具体的实现代码: 1#include <stdio.h>2 t1 a* r0 I! f, ?2 3unsigned short highAndLowShiftHEX(unsigned short data);- {9 H" U9 s1 G: T9 h 4void expandPrintBin(int val2);9 a3 S9 o5 N2 U1 c5 i0 ? 5! S4 Z* i5 \& D 6int main () { 7* u1 I7 ^0 C* u7 T# n; c2 p7 q F 8 highAndLowShiftHEX(38491); 9 return 0; 10} 112 z8 i$ u; B- l9 o) _( ^% _ 12unsigned short highAndLowShiftHEX(unsigned short data)- L- ?. F- j" `* k2 ?8 E! [0 w5 J 13{0 n. v; L. }( a, s- Y 14 data = (data << 8) | (data >> 8); //01011011100101105 Y+ y! D) R2 q- V+ k4 j! @5 ?# q 15 data = ((data << 4) & 0xF0FF) | ((data >> 4) & 0xFF0F); //1011010101101001 16 data = ((data << 2) & 0xCCCC) | ((data >> 2) & 0x3333); //1110010110010110 17 data = ((data << 1) & 0xAAAA) | ((data >>1 ) & 0x5555); //1101101001101001 18 printf(" after shift data=%x \n",data); 19 expandPrintBin(data);" m' Z' a: R3 W+ Z 20 return data; 1 |6 e/ N2 A. \1 I+ Y 21}. a- F. w4 b6 T3 u3 `3 ?, \& V 22& l/ k' B( T0 C+ i( P 23//由于二进制直观,故写了一个扩展的打印二进制的函数 24void expandPrintBin(int val2) 25{1 n$ h2 E, y; J 26 int i,k; 27 unsigned char *p = (unsigned char*)&val2 + 3; //从低位到高位,低端字节计算机4 r4 B/ o. M w- k 28 for( k = 0; k <= 3; k++) 29 { 30 int val2 = *(p-k);% n$ w% [4 h. m. p9 k 31 for (i = 7; i >= 0; i--) D% j( a3 [2 @8 R 32 { 33 if(val2 & (1 << i))5 J& S. @( }, ^8 y1 U! S9 D 34 printf("1");" d* a, P# G2 J1 R. I 35 else 36 printf("0");* ~. x2 l. c+ _) T, _- I+ }7 @) _$ i 37 } 38 printf(" "); 39 } 40} 对于这种交换位的问题,在嵌入式开发中会经常遇到,熟悉掌握位操作还有调试手段很重要。熟练的利用好C语言的移位操作,就能快速的解决此类问题。 总结上面的问题关键还是位操作的灵活妙用,其次是写了两个打印二进制的函数,方便使用,代码可以直接使用,调试不易,欢迎点赞,在看,转发也是厚爱,我们下一期,再见! 1 \" I8 q$ B# U% v0 G |
【LSM6DSV320X评测】使用MEMS Studio训练数据并使用MLC功能进行识别
LSM6DSV320X测评 Linux平台驱动移植与姿态感知应用实现
【我的STM32U5 项目秀】+04-MPU6050在STM32U5上的移植
技术文| 如何使用J-Link烧录SPI Flash
PS2无线遥控手柄与STM32单片机通信
STM32学习笔记11— 温湿度采集实验
Linux入侵过程
C语言——位域的数据结构
C语言printf函数的“安全隐患”
Linux环境变量配置
微信公众号
手机版