2015-10-08 2 views
1

Первоначально мне нужно отправить и получить серийные данные. Длина пакета составляет 48 бит. Для более коротких пакетов (32 бита), я мог бы сделать что-то вроде этого:Побитовый сдвиг массива символов в AVR C

unsigned long data=0x12345678; 

for(i=0;i<32;i++){ 
    if(data & 0x80000000) 
    setb_MOD; 
    else 
    clrb_MOD; 
    data <<= 1; 
} 

Этот код сборник действительно приятны мне:

 code<<=1; 
    ac: 88 0f   add r24, r24 
    ae: 99 1f   adc r25, r25 
    b0: aa 1f   adc r26, r26 
    b2: bb 1f   adc r27, r27 
    b4: 80 93 63 00  sts 0x0063, r24 
    b8: 90 93 64 00  sts 0x0064, r25 
    bc: a0 93 65 00  sts 0x0065, r26 
    c0: b0 93 66 00  sts 0x0066, r27 

После мне нужно расширить пакет (до 48 бит) I столкнувшись с необходимостью сместить массив:

unsigned char data[6]={0x12,0x34,0x56,0x78,0xAB,0xCD}; 

for(i=0;i<48;i++){ 
    if(data[5] & 0x80) 
    setb_MOD; 
    else 
    clrb_MOD; 
    for(j=5;j>0;j--){ 
    data[j]<<=1; 
    if(data[j-1] & 0x80) 
     data[j]+=1; 
    } 
    data[0] <<= 1; 
} 

compilled код немного зависит от параметров оптимизации, но в целом она делает то, что Я заповедал в C:

 for(j=5;j>0;j--){ 
      code[j]<<=1; 
    a8: 82 91   ld r24, -Z 
    aa: 88 0f   add r24, r24 
    ac: 80 83   st Z, r24 
      if(code[j-1]&0x80) 
    ae: 9e 91   ld r25, -X 
    b0: 97 fd   sbrc r25, 7 
    b2: 13 c0   rjmp .+38  ; 0xda <__vector_2+0x74> 
      clrb_MOD; 
     } 
     else{ 
      setb_MOD; 
     } 
     for(j=5;j>0;j--){ 
    b4: 80 e0   ldi r24, 0x00 ; 0 
    b6: a3 36   cpi r26, 0x63 ; 99 
    b8: b8 07   cpc r27, r24 
    ba: b1 f7   brne .-20  ; 0xa8 <__vector_2+0x42> 
      code[j]<<=1; 
      if(code[j-1]&0x80) 
       code[j]+=1; 
     } 

Как вы можете видеть, нет очевидного (для человека) решения по смещению байта массива после байта.

Я бы хотел пропустить инъекцию встроенного ассемблера, поскольку я не очень разбираюсь в этой технике, и я действительно не понимаю, как мне адресовать переменные C в Asm. Есть ли альтернативы?

ответ

2

Если вы знаете, что ваш вход меньше, чем 64 бита, вы можете сделать что-то подобное (при условии, stdint.h доступен, иначе конвертируют в unsigned long long и т.д.):

union BitShifter 
{ 
    uint64_t u64; 
    uint32_t u32[2]; 
    uint16_t u16[4]; 
    uint8_t u8[8]; 
}; 

union BitShifter MyBitshifter; 

MyBitShifter.u64 <<= 1; 

Компилятор должен использовать лучшую инструкцию для этого (возможно, двух 32-битных сдвигов и некоторой другой логики, чтобы получить бит от одного слова к другому. Конечно, бэкэнд может быть ленивым и делать это как байты ...

В зависимости от соответствия AVR , вам нужно будет исправить свои байты в правильном порядке до правильного исходящего битового порядка.

+0

Я не знал о типе uint64_t. Это немного лишнее, но хорошее решение. Просто протестировал его в компиляторе - все сработало! Благодаря! –

Смежные вопросы