搜索
bottom↓
回复: 25

C语言实现串行数据转化为并行数据,有什么好的算法吗?

[复制链接]

出0入13汤圆

发表于 2018-6-14 14:20:20 | 显示全部楼层 |阅读模式
如题,有16个字节的数据,一个数据对应一个IO口,从IO口输出相应的高低电平,总共有16个IO口,并且需要并行从STM32的一个16位的口比如PA口输出,所以首先需要做串行数据转化为并行数据,把这16个8位的数据转为8个16位数据。
我现在的程序如下:

unsigned char in_data[16];
unsigned int out_data[8];


               out_data[0] |= (0x80 & in_data[15])<<8;
               out_data[0] |= (0x80 & in_data[14])<<7;
               out_data[0] |= (0x80 & in_data[13])<<6;
               out_data[0] |= (0x80 & in_data[12])<<5;
               out_data[0] |= (0x80 & in_data[11])<<4;
               out_data[0] |= (0x80 & in_data[10])<<3;
               out_data[0] |= (0x80 & in_data[9])<<2;
               out_data[0] |= (0x80 & in_data[8])<<1;
               out_data[0] |= (0x80 & in_data[7]);
               out_data[0] |= (0x80 & in_data[6])>>1;
               out_data[0] |= (0x80 & in_data[5])>>2;
               out_data[0] |= (0x80 & in_data[4])>>3;
               out_data[0] |= (0x80 & in_data[3])>>4;
               out_data[0] |= (0x80 & in_data[2])>>5;
               out_data[0] |= (0x80 & in_data[1])>>6;
               out_data[0] |= (0x80 & in_data[0])>>7;                           
                          
               out_data[1] |= (0x40 & in_data[15])<<9;            
               out_data[1] |= (0x40 & in_data[14])<<8;   
               out_data[1] |= (0x40 & in_data[13])<<7;
               out_data[1] |= (0x40 & in_data[12])<<6;
               out_data[1] |= (0x40 & in_data[11])<<5;
               out_data[1] |= (0x40 & in_data[10])<<4;
               out_data[1] |= (0x40 & in_data[9])<<3;
               out_data[1] |= (0x40 & in_data[8])<<2;
               out_data[1] |= (0x40 & in_data[7])<<1;
               out_data[1] |= (0x40 & in_data[6]);
               out_data[1] |= (0x40 & in_data[5])>>1;
               out_data[1] |= (0x40 & in_data[4])>>2;
               out_data[1] |= (0x40 & in_data[3])>>3;
               out_data[1] |= (0x40 & in_data[2])>>4;
               out_data[1] |= (0x40 & in_data[1])>>5;
               out_data[1] |= (0x40 & in_data[0])>>6;

               out_data[2] |= (0x20 & in_data[15])<<10;            
               out_data[2] |= (0x20 & in_data[14])<<9;   
               out_data[2] |= (0x20 & in_data[13])<<8;
               out_data[2] |= (0x20 & in_data[12])<<7;
               out_data[2] |= (0x20 & in_data[11])<<6;
               out_data[2] |= (0x20 & in_data[10])<<5;
               out_data[2] |= (0x20 & in_data[9])<<4;
               out_data[2] |= (0x20 & in_data[8])<<3;
               out_data[2] |= (0x20 & in_data[7])<<2;
               out_data[2] |= (0x20 & in_data[6])<<1;
               out_data[2] |= (0x20 & in_data[5]);
               out_data[2] |= (0x20 & in_data[4])>>1;
               out_data[2] |= (0x20 & in_data[3])>>2 ;
               out_data[2] |= (0x20 & in_data[2])>>3 ;
               out_data[2] |= (0x20 & in_data[1])>>4 ;
               out_data[2] |= (0x20 & in_data[0])>>5 ;                          

               out_data[3] |= (0x10 & in_data[15])<<11;            
               out_data[3] |= (0x10 & in_data[14])<<10;   
               out_data[3] |= (0x10 & in_data[13])<<9;
               out_data[3] |= (0x10 & in_data[12])<<8;
               out_data[3] |= (0x10 & in_data[11])<<7;
               out_data[3] |= (0x10 & in_data[10])<<6;
               out_data[3] |= (0x10 & in_data[9])<<5;
               out_data[3] |= (0x10 & in_data[8])<<4;
               out_data[3] |= (0x10 & in_data[7])<<3;
               out_data[3] |= (0x10 & in_data[6])<<2;
               out_data[3] |= (0x10 & in_data[5])<<1;
               out_data[3] |= (0x10 & in_data[4]);
               out_data[3] |= (0x10 & in_data[3])>>1;
               out_data[3] |= (0x10 & in_data[2])>>2;
               out_data[3] |= (0x10 & in_data[1])>>3;
               out_data[3] |= (0x10 & in_data[0])>>4;                           

               out_data[4] |= (0x08 & in_data[15])<<12;            
               out_data[4] |= (0x08 & in_data[14])<<11;   
               out_data[4] |= (0x08 & in_data[13])<<10;
               out_data[4] |= (0x08 & in_data[12])<<9;
               out_data[4] |= (0x08 & in_data[11])<<8;
               out_data[4] |= (0x08 & in_data[10])<<7;
               out_data[4] |= (0x08 & in_data[9])<<6;
               out_data[4] |= (0x08 & in_data[8])<<5;
               out_data[4] |= (0x08 & in_data[7])<<4;
               out_data[4] |= (0x08 & in_data[6])<<3;
               out_data[4] |= (0x08 & in_data[5])<<2;
               out_data[4] |= (0x08 & in_data[4])<<1;
               out_data[4] |= (0x08 & in_data[3]);
               out_data[4] |= (0x08 & in_data[2])>>1;
               out_data[4] |= (0x08 & in_data[1])>>2;
               out_data[4] |= (0x08 & in_data[0])>>3;                           

               out_data[5] |= (0x04 & in_data[15])<<13;            
               out_data[5] |= (0x04 & in_data[14])<<12;   
               out_data[5] |= (0x04 & in_data[13])<<11;
               out_data[5] |= (0x04 & in_data[12])<<10;
               out_data[5] |= (0x04 & in_data[11])<<9;
               out_data[5] |= (0x04 & in_data[10])<<8;
               out_data[5] |= (0x04 & in_data[9])<<7;
               out_data[5] |= (0x04 & in_data[8])<<6;
               out_data[5] |= (0x04 & in_data[7])<<5;
               out_data[5] |= (0x04 & in_data[6])<<4;
               out_data[5] |= (0x04 & in_data[5])<<3;
               out_data[5] |= (0x04 & in_data[4])<<2;
               out_data[5] |= (0x04 & in_data[3])<<1;
               out_data[5] |= (0x04 & in_data[2]);
               out_data[5] |= (0x04 & in_data[1])>>1;
               out_data[5] |= (0x04 & in_data[0])>>2;                           

               out_data[6] |= (0x02 & in_data[15])<<14;            
               out_data[6] |= (0x02 & in_data[14])<<13;   
               out_data[6] |= (0x02 & in_data[13])<<12;
               out_data[6] |= (0x02 & in_data[12])<<11;
               out_data[6] |= (0x02 & in_data[11])<<10;
               out_data[6] |= (0x02 & in_data[10])<<9;
               out_data[6] |= (0x02 & in_data[9])<<8;
               out_data[6] |= (0x02 & in_data[8])<<7;
               out_data[6] |= (0x02 & in_data[7])<<6;
               out_data[6] |= (0x02 & in_data[6])<<5;
               out_data[6] |= (0x02 & in_data[5])<<4;
               out_data[6] |= (0x02 & in_data[4])<<3;
               out_data[6] |= (0x02 & in_data[3])<<2;
               out_data[6] |= (0x02 & in_data[2])<<1;
               out_data[6] |= (0x02 & in_data[1]);
               out_data[6] |= (0x02 & in_data[0])>>1;                           

               out_data[7] |= (0x01 & in_data[15])<<15;
               out_data[7] |= (0x01 & in_data[14])<<14;   
               out_data[7] |= (0x01 & in_data[13])<<13;
               out_data[7] |= (0x01 & in_data[12])<<12;
               out_data[7] |= (0x01 & in_data[11])<<11;
               out_data[7] |= (0x01 & in_data[10])<<10;
               out_data[7] |= (0x01 & in_data[9])<<9;
               out_data[7] |= (0x01 & in_data[8])<<8;
               out_data[7] |= (0x01 & in_data[7])<<7;
               out_data[7] |= (0x01 & in_data[6])<<6;
               out_data[7] |= (0x01 & in_data[5])<<5;
               out_data[7] |= (0x01 & in_data[4])<<4;
               out_data[7] |= (0x01 & in_data[3])<<3;
               out_data[7] |= (0x01 & in_data[2])<<2;
               out_data[7] |= (0x01 & in_data[1])<<1;
               out_data[7] |= (0x01 & in_data[0]);                           


由于有多组这样的数据,转化时占用CPU时间比较多,看一下大家有没什么更好的算法?能压缩这个转化的时间。

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2018-6-14 14:27:40 | 显示全部楼层
楼主不知道用for循环?

出0入0汤圆

发表于 2018-6-14 14:27:57 | 显示全部楼层
根本不需要转换,用DMA每次直接将16个数据搬移到端口对应的位域地址即可。

出0入0汤圆

发表于 2018-6-14 14:33:44 | 显示全部楼层
看楼主这架势,应该是输入端口是杂乱的,没有顺序,所以直接赋值,肯定不行。
我觉得,最快的办法,应该是查表了。
16字节,也就是 128位,你可以考虑如果你资源够大,可以考虑用 8bit查表,也就是16*256=4k 的一个表。或者 4bit查表,也就是32×16=512的一个表。

出0入13汤圆

 楼主| 发表于 2018-6-14 14:44:26 | 显示全部楼层
maxwell_lee 发表于 2018-6-14 14:27
根本不需要转换,用DMA每次直接将16个数据搬移到端口对应的位域地址即可。 ...

学得不深入,我还真不知可以这么操作。但这个PA口16位只是数据线,还有另外一个口是时钟线,需要配合输出,还可以这么操作吗?

出0入13汤圆

 楼主| 发表于 2018-6-14 14:56:33 | 显示全部楼层
maxwell_lee 发表于 2018-6-14 14:27
根本不需要转换,用DMA每次直接将16个数据搬移到端口对应的位域地址即可。 ...

还有,我每位输出都需要控制不同时间的,还可以用DMA吗?

出0入0汤圆

发表于 2018-6-14 15:52:10 | 显示全部楼层
用阵啊,傻孩子

出0入13汤圆

 楼主| 发表于 2018-6-14 16:39:02 | 显示全部楼层
zhonghua_li 发表于 2018-6-14 14:33
看楼主这架势,应该是输入端口是杂乱的,没有顺序,所以直接赋值,肯定不行。
我觉得,最快的办法,应该是 ...

有点道理,只是这个表如何建,如何查,得想想。

出0入13汤圆

 楼主| 发表于 2018-6-14 16:39:32 | 显示全部楼层

什么阵?是不是你的意思也是查表?

出0入8汤圆

发表于 2018-6-14 16:56:35 | 显示全部楼层
4楼说的对,想省时间 只能查表。

出0入42汤圆

发表于 2018-6-14 16:57:34 | 显示全部楼层
maxwell_lee 发表于 2018-6-14 14:27
根本不需要转换,用DMA每次直接将16个数据搬移到端口对应的位域地址即可。 ...

您确定STM32的DMA可以把MEM地址设成位域区?

出0入0汤圆

发表于 2018-6-14 17:24:24 | 显示全部楼层
wshtyr 发表于 2018-6-14 16:57
您确定STM32的DMA可以把MEM地址设成位域区?


STM32F103可以这样操作,实际操作过。其他STM32系不清楚。

出0入0汤圆

发表于 2018-6-14 17:29:06 | 显示全部楼层
zhbc 发表于 2018-6-14 14:44
学得不深入,我还真不知可以这么操作。但这个PA口16位只是数据线,还有另外一个口是时钟线,需要配合输出 ...


我当时是这么做的:位域区就是STM32的GPIO的BSRR/BRR寄存器对应的位,直接设置DMA的目的地址为这个地址,源地址为你要输入的16个数据地址,地址自增。
每次传输你要的16个字即可。至于你说要不同时间控制,我不是太清楚你的需求。
相当于这16个字的缓存就是你对应的GPIO控制缓存,设置一次缓存,然后启动一次DMA传输。

出0入13汤圆

 楼主| 发表于 2018-6-14 18:01:02 | 显示全部楼层
zhonghua_li 发表于 2018-6-14 14:33
看楼主这架势,应该是输入端口是杂乱的,没有顺序,所以直接赋值,肯定不行。
我觉得,最快的办法,应该是 ...

这个表如何建,想不出来。你的8位查表,4位查表是什么意思?
128位建表,表不是2的128次方吗?这个表太大了。
8位查表,查16次,再组合起来,再处理一次?
4位查表,查32次,再组合起来,再处理一次?
这样表小一些?解决全部查表表太大,不查表速度又太慢。查表加再处理折中一下来解决,是这个意思吗?

出0入4汤圆

发表于 2018-6-14 18:17:07 | 显示全部楼层
联合体 位阈

出0入0汤圆

发表于 2018-6-14 18:25:37 | 显示全部楼层
本帖最后由 ilawp 于 2018-6-14 18:27 编辑

理解错误,清除内容

出0入13汤圆

 楼主| 发表于 2018-6-14 18:45:35 来自手机 | 显示全部楼层
ztrx 发表于 2018-6-14 18:17
联合体 位阈

可以试一下,但不一定会快,这只是编译器帮着处理了一下,执行代码不一定会少。

出0入42汤圆

发表于 2018-6-14 19:43:12 | 显示全部楼层
LZ要的是这个效果吗?

  1. #include "stdio.h"
  2. #include "stdint.h"
  3. #include "stdlib.h"

  4. void bit_swap(uint8_t * in, uint16_t * out)
  5. {
  6.     uint32_t * dat_grp = (uint32_t *)in;
  7.     uint32_t val;
  8.     /* Load new Group */
  9.     val = *(dat_grp++);
  10.     out[0]  = (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 28; val >>= 1;
  11.     out[1]  = (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 28; val >>= 1;
  12.     out[2]  = (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 28; val >>= 1;
  13.     out[3]  = (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 28; val >>= 1;
  14.     out[4]  = (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 28; val >>= 1;
  15.     out[5]  = (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 28; val >>= 1;
  16.     out[6]  = (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 28; val >>= 1;
  17.     out[7]  = (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 28;
  18.    
  19.     /* Load new Group */
  20.     val = *(dat_grp++);
  21.     out[0] |= (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 24; val >>= 1;
  22.     out[1] |= (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 24; val >>= 1;
  23.     out[2] |= (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 24; val >>= 1;
  24.     out[3] |= (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 24; val >>= 1;
  25.     out[4] |= (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 24; val >>= 1;
  26.     out[5] |= (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 24; val >>= 1;
  27.     out[6] |= (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 24; val >>= 1;
  28.     out[7] |= (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 24;
  29.    
  30.     /* Load new Group */
  31.     val = *(dat_grp++);
  32.     out[0] |= (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 20; val >>= 1;
  33.     out[1] |= (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 20; val >>= 1;
  34.     out[2] |= (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 20; val >>= 1;
  35.     out[3] |= (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 20; val >>= 1;
  36.     out[4] |= (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 20; val >>= 1;
  37.     out[5] |= (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 20; val >>= 1;
  38.     out[6] |= (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 20; val >>= 1;
  39.     out[7] |= (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 20;
  40.    
  41.     /* Load new Group */
  42.     val = *(dat_grp++);
  43.     out[0] |= (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 16; val >>= 1;
  44.     out[1] |= (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 16; val >>= 1;
  45.     out[2] |= (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 16; val >>= 1;
  46.     out[3] |= (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 16; val >>= 1;
  47.     out[4] |= (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 16; val >>= 1;
  48.     out[5] |= (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 16; val >>= 1;
  49.     out[6] |= (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 16; val >>= 1;
  50.     out[7] |= (((val & 0x01010101) * 0x10204080) & 0xF0000000) >> 16;
  51. }

  52. int main(void)
  53. {
  54.     int i;
  55.     uint8_t input[16] =
  56.     {
  57.         0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
  58.         0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42
  59.     };
  60.     uint16_t output[8];
  61.     bit_swap(input, output);
  62.     /* Dump */
  63.     printf("Input: \n  ");
  64.     for(i = 0; i < 16; i++)
  65.     {
  66.         printf("0x%02X", input[i]);
  67.     }
  68.     printf("\n");
  69.     //
  70.     printf("Output: \n  ");
  71.     for(i = 0; i < 8; i++)
  72.     {
  73.         printf("0x%04X\n  ", output[i]);
  74.     }
  75. }
复制代码


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入42汤圆

发表于 2018-6-14 14:20:21 | 显示全部楼层
https://www.amobbs.com/thread-3703075-1-1.html?_dsign=1d2a8f1e

出0入22汤圆

发表于 2018-6-14 20:38:34 来自手机 | 显示全部楼层
用74hc595?

出0入13汤圆

 楼主| 发表于 2018-6-14 21:36:18 来自手机 | 显示全部楼层
wshtyr 发表于 2018-6-14 19:43
LZ要的是这个效果吗?

就是这种效果吧,明天验证一下。这段程序你是看了那个贴子,自己编出来的?那个贴子我没看到现成的完整程序。

出0入42汤圆

发表于 2018-6-14 21:56:06 | 显示全部楼层
zhbc 发表于 2018-6-14 21:36
就是这种效果吧,明天验证一下。这段程序你是看了那个贴子,自己编出来的?那个贴子我没看到现成的完整程 ...

以前看过,大概是这个思路,那个帖子里应该有更高效的算法

出0入42汤圆

发表于 2018-6-14 21:59:15 | 显示全部楼层
zhbc 发表于 2018-6-14 21:36
就是这种效果吧,明天验证一下。这段程序你是看了那个贴子,自己编出来的?那个贴子我没看到现成的完整程 ...

另外,maxwell_lee的方法对STM32来说也是不错的,还非常好理解,两个循环就转换好了,只需要消耗大约144次Load和Store的时间

出0入0汤圆

发表于 2018-6-15 12:43:55 | 显示全部楼层
zhbc 发表于 2018-6-14 18:45
可以试一下,但不一定会快,这只是编译器帮着处理了一下,执行代码不一定会少。 ...

联合体,本质上,和楼主的方法一样。

出0入0汤圆

发表于 2018-6-15 17:37:22 | 显示全部楼层
可以从硬件上考虑 是否可以找一个16个引脚扩展的芯片更简单也更快稳定

出0入13汤圆

 楼主| 发表于 2018-6-19 16:52:11 | 显示全部楼层
本帖最后由 zhbc 于 2018-6-19 16:53 编辑


https://www.amobbs.com/thread-3703075-1-1.html?_dsign=1d2a8f1e

这个贴子里minux的算法不错。


编辑原因:加上贴子的链接。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-27 09:16

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表