C программа останавливает выполнение при присвоении переменной - PullRequest
0 голосов
/ 01 августа 2020

Я не уверен, происходит ли это при назначении переменной специально, но при отладке кода сборки компилятор выполняет RJMP $+0000 там, где он вешает программу.

EDIT: Я добавил включенные библиотеки, если это актуально

#define __DELAY_BACKWARD_COMPATIBLE__
#define F_CPU 8000000UL
#include <avr/io.h>
#include <avr/delay.h>
#include <stdint.h> 

void ReadTemp(uint8_t address){
    
    ADCSRA = ADCSRA | 0b10000111;       //enable ADC, CLK/128 conversion speed
    ADMUX  = ADMUX | 0b01000000;        //Use internal 2.56V Vref and PA0 as input, right-hand justified
        
    ADCSRA |= (1 << ADSC);              //start conversion
        
    while(!(ADCSRA & (1 << ADIF))) {}   // wait until process is finished;

    uint8_t  low_value = ADC & 0x00FF;
// or low_value = ADCL;
    uint8_t high_value = ADC & 0xFF00;   //problem here
...
}

введите описание изображения здесь

Ответы [ 2 ]

6 голосов
/ 01 августа 2020

Я не знаю, что все это делает, но я вижу ошибку в побитовой математике.

uint8_t  low_value = ADC & 0x00FF;
uint8_t high_value = ADC & 0xFF00;   //problem here

low_value и high_value - оба 8-битные (uint8_t ). Я собираюсь бросить здесь go и сказать, что ADC - это 16 бит. Для high_value вы вводите and AD C с 0xFF00, а затем усекаете значение до 8 бит. high_value всегда будет нулем.

Что должно быть сделано:

uint8_t high_value = (ADC & 0xFF00) >> 8;

Это захватит левый байт AD C и сдвинет его вправо на 8 бит, а затем назначит его в хранилище high_value байтов, дающее вам правильное значение.

Как у вас low_value правильно. Фактически, вы можете просто сделать:

uint8_t low_value = ADC;
1 голос
/ 15 августа 2020

Здесь есть что-то неоптимальное:

uint8_t low_value = ADC & 0x00FF;

Вы читаете ADC, 16-битный регистр, реализованный как пара 8-битных регистров. Как показано в разборке, для этого требуются две инструкции in, по одной на байт. И тогда вы просто выбрасываете один из этих байтов. Вы можете подумать, что компилятор достаточно умен, чтобы не читать байт, который он собирается сразу отбросить. К сожалению, он не может этого сделать, поскольку регистры ввода-вывода объявлены как volatile. Компилятор вынужден обращаться к регистру столько раз, сколько это делает исходный код.

Если вам нужен только младший байт, вы должны читать только этот байт:

uint8_t low_value = ADCL;

Затем вы написали :

uint8_t high_value = ADC & 0xFF00;

Как объяснялось в предыдущем ответе, high_value будет равно нулю. Однако компилятору придется снова прочитать два байта, потому что регистр ввода-вывода - volatile. Если вы хотите прочитать старший байт, прочтите ADCH.

Но зачем вам читать эти два байта один за другим? Чтобы собрать их обратно в 16-битную переменную? В таком случае нет необходимости читать их отдельно. Вместо этого просто прочитайте 16-битный регистр самым простым способом:

uint16_t value = ADC;

Долгое время a go, g cc не знал, как обрабатывать 16-битные регистры, и людям приходилось прибегать к чтению байтов один за другим, а затем склеивать их вместе. Вы все еще можете найти в Интернете очень старый пример кода, который делает это. Сегодня нет абсолютно никаких причин продолжать программировать таким образом.

Тогда вы написали:

//problem here

Нет, проблема не в этом. Это не то, что сгенерировало инструкцию rjmp. Проблема, вероятно, кроется сразу после этой строки в коде, который вы решили не публиковать. У вас какая-то ошибка, которая проявляется только при включенной оптимизации. Это типично для кода, который производит неопределенное поведение : работает, как ожидалось, с отключенной оптимизацией, затем делает странные «необъяснимые» вещи, когда вы включаете оптимизацию.

...