Проблемы неявного приведения длинного знака со сдвигом битов к 8-битному значению без знака
У меня проблема с неверными значениями uint8 после передачи функции long со знаком. Вы можете увидеть пики, где произошло переполнение (?) В значениях необработанных данных на правой оси
Я пишу это для 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)]));
}
Теперь это дает следующий вывод:
Проблема в том, что я не понимаю, как она это исправила. В первом случае у меня есть 32-разрядное целое число со знаком (которое составляет максимум 16 бит; оно должно было войти в 32-битное из-за умножения на него, но позже это отменяется делением), которое сдвигается в битах на восемь справа и затем неявно приведен в uint8_t.
Вторая версия имеет 32-битное целое число, которое явно преобразуется в int16_t, который затем сдвигается на восемь бит вправо, а затем неявно преобразуется в uint8_t. Чем отличаются эти методы, которые дают разные результаты?