Проблемы неявного приведения длинного знака со сдвигом битов к 8-битному значению без знака - PullRequest
0 голосов
/ 15 января 2019

У меня проблема с неверными значениями uint8 после передачи функции long со знаком. Вы можете увидеть всплески, где произошло переполнение (?) В значениях необработанных данных на правой оси

enter image description here

Я пишу это для PIC, используя MPLABX 5.0 и компилятор XC8. Упрощенная версия моего кода ниже:

int16_t ADCOutput[6];
signed long ADCOutputAvg[6];
uint8_t USARTRxLSB = 6;

void MOVING_AVERAGE_ADC(void)                                       
{
        READ_ADC();
        for ( int i = 0 ; i < 6 ; ++i)                            
        {
            ADCOutputAvg[i] = (ADCOutputAvg[i]*4) - ADCOutputAvg[i];
            ADCOutputAvg[i] += ADCOutput[i];
            ADCOutputAvg[i] = ADCOutputAvg[i] /4;


        }
SERIAL_WRITE(0x45,(ADCOutputAvg[(USARTRxLSB-1)]>>8), (ADCOutputAvg[(USARTRxLSB-1)]));
}

SERIAL_WRITE - это функция:

    void SERIAL_WRITE(uint8_t Control, uint8_t MSB, uint8_t LSB)
{
    uint8_t Checksum = 0;
    Checksum = NextHeader ^ Control ^ MSB ^ LSB;            
    EUSART1_Write(NextHeader);                          
    EUSART1_Write(Control);                             
    EUSART1_Write(MSB);                                
    EUSART1_Write(LSB);                                 
    EUSART1_Write(Checksum);                                
    if(NextHeader == 0x5A)                              
    {
        NextHeader = 0xA5;                              
    }
    else
    {
        NextHeader = 0x5A;          
    }

}

Мне удалось исправить это, изменив его следующим образом:

int16_t ADCOutput[6];
signed long ADCOutputAvg[6];
uint8_t USARTRxLSB = 6;
int16_t ADCOutputAvgHolder[6];

void MOVING_AVERAGE_ADC(void)                                       
{
        READ_ADC();
        for ( int i = 0 ; i < 6 ; ++i)                            
        {
            ADCOutputAvg[i] = (ADCOutputAvg[i]*4) - ADCOutputAvg[i];
            ADCOutputAvg[i] += ADCOutput[i];
            ADCOutputAvg[i] = ADCOutputAvg[i] /4;
            ADCOutputAvgHolder[i] = (int16_t) ADCOutputAvg[i];

        }
SERIAL_WRITE(0x45,(ADCOutputAvgHolder[(USARTRxLSB-1)]>>8), (ADCOutputAvgHolder[(USARTRxLSB-1)]));
}

Теперь это дает следующий вывод:

enter image description here

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

Вторая версия имеет 32-битное целое число, которое явно преобразуется в int16_t, которое затем сдвигается на восемь бит вправо, а затем неявно преобразуется в uint8_t. Чем отличаются эти методы, которые дают разные результаты?

...