Здравствуйте. Столкнулся с непонятной работой комманд установки значеной в регистрах. Attiny85 + SSD1306(i2C) + USBAsp
Проверял в 2х IDE - ArduinoIDE и Visual Studio Code+PlatformIO
ADMUX |= (1<<REFS0);
После попытке установки бита экран SSD1306(i2C) гаснет. Осцилографом вижу импульсы на SCK но на SDA 0 вольт. Проблема только с этим битом, причём команды
ADMUX &= 0b00101111; // Очиcтить REFS0(6) REFS1(7) REFS2(4)
ADMUX |= 0b10010000; // Установить REFS0(6)=0 REFS1(7)=1 REFS2(4)=1 что означает Internal 2.56V Voltage Reference without external bypass capacitor
или ADMUX = 0b01000000;
работают нормально.
ADCSRA |= (1<<ADPS2)|(0<<ADPS1)|(1<<ADPS0);
Команда вообще ничего не делает, в регистре все 0. Причем
ADCSRA &= 0b11111000; // Очичтить ADPS2(2) ADPS1(1) ADPS0(0)
ADCSRA |= 0b00000101; // Установить ADPS2(2)=1 ADPS1(1)=1 ADPS0(0)=0 что означает division factor between the system clock frequency and the input clock to the ADC = 64
работает нормально. Сстояния регистров вывожу на экран. Весь код тут
#include <Tiny4kOLED.h>
void setup() {
// Setup OLED //
oled.begin(); // Send the initialization sequence to the oled. This leaves the display turned off
oled.enableChargePump(); // The default is off, but most boards need this.
oled.setRotation(1); // The default orientation is not the most commonly used.
oled.clear(); //
oled.switchFrame(); // Clear ALL the memory before turning on the display
oled.clear(); //
oled.on(); // Turn on the display
oled.setFont(FONT8X16);
oled.switchRenderFrame(); // Switch the half of RAM that we are writing to, to be the half that is non currently displayed
// Настройка ADC
ADCSRA |= (1<<ADEN); // Включить ADC
//!!!Команда ADMUX |= (1<<REFS2)|(1<<REFS1)|(1<<REFS0); Вызывает ошибку экрана поэтому устанавливаем биты так!!!
ADMUX &= 0b00101111; // Очичтить REFS0(6) REFS1(7) REFS2(4)
ADMUX |= 0b10010000; // Установить REFS0(6)=0 REFS1(7)=1 REFS2(4)=1 что означает Internal 2.56V Voltage Reference without external bypass capacitor
ADMUX |= (0<<MUX3)|(0<<MUX2)|(1<<MUX1)|(0<<MUX0); // Подключаем пин ADC2(PB4) к ADC
//!!!Команда ADCSRA |= (1<<ADPS2)|(0<<ADPS1)|(1<<ADPS0); ничего не делает поэтому устанавливаем биты так!!!
ADCSRA &= 0b11111000; // Очичтить ADPS2(2) ADPS1(1) ADPS0(0)
ADCSRA |= 0b00000101; // Установить ADPS2(2)=1 ADPS1(1)=1 ADPS0(0)=0 что означает division factor between the system clock frequency and the input clock to the ADC = 64
ADMUX |= (1<<REFS0);
}
void read_reg(char port) {
oled.setCursor(0, 0);
for (int8_t i=7; i>=0; i--) {
oled.print(bitRead(port, i));
}
oled.setCursor(0, 2);
oled.print(F("0h"));
oled.print(port, HEX);
}
void updateDisplay() {
oled.setCursor(64+24, 0);
oled.fillToEOL(0x00);
oled.setCursor(64+24, 2);
oled.fillToEOL(0x00);
read_reg(ADCSRA);
oled.switchFrame();
}
void loop() {
updateDisplay();
}
Смущает, но я же устанавливаю значения которые подключают внутренний ИОН к компаратору, как я понял этот пин остается свободным. И почему тогда команда ADMUX = 0b10010000; работает нормально, и экран отраматывает и замеры напряжения?
Спасибо я баран получается там просто ошибка… ADMUX |= (1<<REFS2)|(1<<REFS1)|(0<<REFS0); должно быть… там эти биты не по порядку идут, поэтому запутался
А как понять почему ADCSRA |= (1<<ADPS2)|(0<<ADPS1)|(1<<ADPS0); не работает? а
Спасибо работает. А не работало оно т.к. по уполчанию (ну или так в ядре прописано) после включения платы в ADCSRA 0x10000110, в эта штука ADCSRA |= (1<<ADPS2)|(0<<ADPS1)|(1<<ADPS0); не может делать из единиц нули.
А подскажите я правильно понимаю что чем больше предделитель частоты ADC в REFS2 REFS1 REFS0, тем медленнее будет выполняться цикл преобразования, просто на практике он одинаковый что с делителем 2 что со 128 занимает 4us
do { ADCSRA |= (1<<ADSC); }
while ((ADCSRA & (1 << ADIF)) == 0);
V_capture = (ADCL|ADCH << 8);
А чем меньше, тем более результат будет совпадать с ценой овса в прошлом году. Делитель АЦП должен обеспечивать правильную частоту его работы, так что там не особо много свободы каким его делать. Надеюсь, Вы его считаете, а не ставите от фонаря.
Честно говоря не считал. В даташите написано для измерения с точностью 10бит, частота на которой работает АЦП должна быть 50-200 кГц. Я оставил 64 как по умолчанию, это получается 125кгц, с вольтметром замеры совпадают.
Частота считается как t2-t1, только вот она не меняется с изменением делителя, пока не пойму почему.
В ардуино IDE стоит 16, в PlatformIO поставил тоже 16, но все замеры после компиляции и загрузки из него стали в 2 раза дольше, так что думаю что 8. Настройки есть на скриншотах. Как узнать реальную частоты работы сейчас погуглю.
Вы считаете, что здесь написан цикл ожидания пока измерит? Боюсь Вас огорчить, но это не так. Если Вы хотите использовать именно ADIF, то там нужна не &, а ^ Вообще, это вот так делается:
//
// Запуск измерения
// Проверка, что измерение ещё не закончилось
// Проверка, что измерение уже закончилось
//
static inline void adcStartConversion(void) { ADCSRA |= bitMask(ADSC); }
static inline bool adcConversionInProgress(void) { return ADCSRA & bitMask(ADSC); }
// так тоже можно static inline bool adcConversionInProgress(void) { return ADCSRA ^ bitMask(ADIF); }
static inline bool adcReady(void) { return ! adcConversionInProgress(); }
И вообще, если Вы намеряли 4uS – ищите ошибки ибо это бредовый бред. При частоте 125 кГц, время второго и последующих измерений - 104uS. Это элементарно посчитать: 13 тактов умножаем на время одного такта: 13 * 1/125000 = 0,000104
Если 8МГц, то делитель 64 - правильный, если 16 - то нужен 128
Вообще, у меня делитесь всегда сам считается по F_CPU (просто ищется минимальный, для которого частота АЦП будет в пределах 50-200 кГц Могу показать как.