AtTiny 13 и АЦП

Здесь принимаются все самые невообразимые вопросы... Главное - не стесняйтесь. Поверьте, у нас поначалу вопросы были еще глупее :)
Аватара пользователя
Ivanoff-iv
Друг Кота
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Re: AtTiny 13 и АЦП

Сообщение Ivanoff-iv »

Итак, приступим:
запускаем протеус и рисуем схему:
Изображение
или собираем такую-же на макетке.
запускаем кодеВижен, запускаем мастер выбираем чип и его частоту, я поставил 9,6МГц и деление на 8 (частота по умолчанию)
:idea: кстати этот делитель выставленный в кодевижене заменяет собой делитель на 8 [не]установленный фьюзом.
потом настраиваем порты порт со светодиодом - на выход, порт с переменником на вход без подтяжки, остальные - вход с подтяжкой.
Изображение
далее настраиваем АЦП:
Изображение
цифры: (следует учитывать, что это не только настройка тини, но и написание предварительного кода)
1 - включение самого блока АЦП
2 - вызвать прерывание по завершению оцифровки
3 - 8битная точность (как она достигается я писал несколькими постами выше)
4 - дописывает в функцию получения значения АЦП остановку процессора тиньки чтоб снизить наводки на блок АЦП
5 - выбор опорного напряжения (если стоит - встроенная опора 1,1в, если нет - внешнее питание)
6 - тактирование (КВАвр сам посчитает делитель) д.ш. рекомендует 50-200кГц
7 - режим запуска преобразования (выбранный режим означает перезапуск АЦП сразу после завершения оцифровки)
(режим "ADC stopped" - означает, что преобразование каждый раз нужно запускать вручную, я бы его назвал "однократный режим")
8 - если включить, то после каждого преобразования АЦП переключается на следующий вход покругу (диапазон входов задается) это чисто софтовая примочка т.е. сам АЦП этого не умеет.
9 - отключение соответствующей ноги от дискретного порта (если поставить галочку, то ни подтяжку ни сигнал в/из порта уже не получить - защитит от ошибочного переключения порта и искажения напряжения на ноге). галочку можно поставить в окошке "1".
_____________
генерируем код, сохраняем и получаем это:
Спойлер

Код: Выделить всё

#include <tiny13a.h>

#include <delay.h>

// Declare your global variables here

// Bandgap Voltage Reference: Off
#define ADC_VREF_TYPE ((0<<REFS0) | (0<<ADLAR))

// ADC interrupt service routine
interrupt [ADC_INT] void adc_isr(void)
{
unsigned int adc_data;
// Read the AD conversion result
adc_data=ADCW;
// Place your code here
}

void main(void)
{
// Declare your local variables here

// Crystal Oscillator division factor: 8
#pragma optsize-
CLKPR=(1<<CLKPCE);
CLKPR=(0<<CLKPCE) | (0<<CLKPS3) | (0<<CLKPS2) | (1<<CLKPS1) | (1<<CLKPS0);
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

// Input/Output Ports initialization
// Port B initialization
// Function: Bit5=In Bit4=Out Bit3=In Bit2=In Bit1=In Bit0=In 
DDRB=(0<<DDB5) | (1<<DDB4) | (0<<DDB3) | (0<<DDB2) | (0<<DDB1) | (0<<DDB0);
// State: Bit5=P Bit4=0 Bit3=P Bit2=T Bit1=P Bit0=P 
PORTB=(1<<PORTB5) | (0<<PORTB4) | (1<<PORTB3) | (0<<PORTB2) | (1<<PORTB1) | (1<<PORTB0);

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=0xFF
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=(0<<COM0A1) | (0<<COM0A0) | (0<<COM0B1) | (0<<COM0B0) | (0<<WGM01) | (0<<WGM00);
TCCR0B=(0<<WGM02) | (0<<CS02) | (0<<CS01) | (0<<CS00);
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=(0<<OCIE0B) | (0<<OCIE0A) | (0<<TOIE0);

// External Interrupt(s) initialization
// INT0: Off
// Interrupt on any change on pins PCINT0-5: Off
GIMSK=(0<<INT0) | (0<<PCIE);
MCUCR=(0<<ISC01) | (0<<ISC00);

// Analog Comparator initialization
// Analog Comparator: Off
// The Analog Comparator's positive input is
// connected to the AIN0 pin
// The Analog Comparator's negative input is
// connected to the AIN1 pin
ACSR=(1<<ACD) | (0<<ACBG) | (0<<ACO) | (0<<ACI) | (0<<ACIE) | (0<<ACIS1) | (0<<ACIS0);
// Digital input buffer on AIN0: On
// Digital input buffer on AIN1: On
DIDR0=(0<<AIN0D) | (0<<AIN1D);

// ADC initialization
// ADC Clock frequency: 150,000 kHz
// ADC Bandgap Voltage Reference: Off
// ADC Auto Trigger Source: Free Running
// Digital input buffers on ADC0: On, ADC1: On, ADC2: On, ADC3: On
DIDR0|=(0<<ADC0D) | (0<<ADC2D) | (0<<ADC3D) | (0<<ADC1D);
ADMUX=ADC_VREF_TYPE;
ADCSRA=(1<<ADEN) | (0<<ADSC) | (1<<ADATE) | (0<<ADIF) | (1<<ADIE) | (0<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
ADCSRB=(0<<ADTS2) | (0<<ADTS1) | (0<<ADTS0);


// Globally enable interrupts
#asm("sei")

while (1)
      {
      // Place your code here
      }
}
дописываем в главный цикл условие для переключения светодиода
Спойлер

Код: Выделить всё

while (1)
      {
      // Place your code here
      if (adc_data>512) {PORTB|=(1<<4);}else{PORTB&=~(1<<4);};
      }
}
и... ловим ошибку - переменная adc_data тут недоступна, можно или условие зажигания светодиода упрятать в прерывание или переменную сделать глобальной (вынести её объявление из прерывания)
я сделал переменную глобальной.
компилирую - компиляция проходит, но не работает...
вспоминаю, что про вход у нас ничего не спрашивали, наверно включен вход 0, а нам нужен 1
лезем в д.ш.: в регистре ADMUX есть соседствующие биты MUX0 и MUX1, которые отвечают за выбор входа
СпойлерИзображение
а квавр к ним ни разу не обратился... непорядок какой! что-ж, допишем сами:
ADMUX=ADC_VREF_TYPE | (inputADC<<MUX0);
и если надо менять вход - создадим переменную, если не надо - задефайним inputADC присвоив ей требуемое значение (в нашем случае 1).
компилим, запускаем - не работает! конечно, после завершения оцифровки АЦП перезапустится, но первый раз его нужно завести вручную
допишем перед главным циклом:
// Start the AD conversion
ADCSRA|=(1<<ADSC);

(вместо этого можно 0 на 1 поменять в соответствующем месте настройки - результат будет тот-же)
компилим - теперь работает!
вот весь полученный код:
Спойлер

Код: Выделить всё

#include <tiny13a.h>

#include <delay.h>

// Declare your global variables here
unsigned int adc_data;

// Bandgap Voltage Reference: Off
#define ADC_VREF_TYPE ((0<<REFS0) | (0<<ADLAR))
//выбор входа
#define inputADC 1

// ADC interrupt service routine
interrupt [ADC_INT] void adc_isr(void)
{
// Read the AD conversion result
adc_data=ADCW;
// Place your code here
}

void main(void)
{
// Declare your local variables here

// Crystal Oscillator division factor: 8
#pragma optsize-
CLKPR=(1<<CLKPCE);
CLKPR=(0<<CLKPCE) | (0<<CLKPS3) | (0<<CLKPS2) | (1<<CLKPS1) | (1<<CLKPS0);
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

// Input/Output Ports initialization
// Port B initialization
// Function: Bit5=In Bit4=Out Bit3=In Bit2=In Bit1=In Bit0=In 
DDRB=(0<<DDB5) | (1<<DDB4) | (0<<DDB3) | (0<<DDB2) | (0<<DDB1) | (0<<DDB0);
// State: Bit5=P Bit4=0 Bit3=P Bit2=T Bit1=P Bit0=P 
PORTB=(1<<PORTB5) | (0<<PORTB4) | (1<<PORTB3) | (0<<PORTB2) | (1<<PORTB1) | (1<<PORTB0);

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=0xFF
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=(0<<COM0A1) | (0<<COM0A0) | (0<<COM0B1) | (0<<COM0B0) | (0<<WGM01) | (0<<WGM00);
TCCR0B=(0<<WGM02) | (0<<CS02) | (0<<CS01) | (0<<CS00);
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=(0<<OCIE0B) | (0<<OCIE0A) | (0<<TOIE0);

// External Interrupt(s) initialization
// INT0: Off
// Interrupt on any change on pins PCINT0-5: Off
GIMSK=(0<<INT0) | (0<<PCIE);
MCUCR=(0<<ISC01) | (0<<ISC00);

// Analog Comparator initialization
// Analog Comparator: Off
// The Analog Comparator's positive input is
// connected to the AIN0 pin
// The Analog Comparator's negative input is
// connected to the AIN1 pin
ACSR=(1<<ACD) | (0<<ACBG) | (0<<ACO) | (0<<ACI) | (0<<ACIE) | (0<<ACIS1) | (0<<ACIS0);
// Digital input buffer on AIN0: On
// Digital input buffer on AIN1: On
DIDR0=(0<<AIN0D) | (0<<AIN1D);

// ADC initialization
// ADC Clock frequency: 150,000 kHz
// ADC Bandgap Voltage Reference: Off
// ADC Auto Trigger Source: Free Running
// Digital input buffers on ADC0: On, ADC1: On, ADC2: On, ADC3: On
DIDR0|=(0<<ADC0D) | (0<<ADC2D) | (0<<ADC3D) | (0<<ADC1D);
ADMUX=ADC_VREF_TYPE | (inputADC<<MUX0);
ADCSRA=(1<<ADEN) | (0<<ADSC) | (1<<ADATE) | (0<<ADIF) | (1<<ADIE) | (0<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
ADCSRB=(0<<ADTS2) | (0<<ADTS1) | (0<<ADTS0);


// Globally enable interrupts
#asm("sei")

// Start the AD conversion
ADCSRA|=(1<<ADSC);

while (1)
      {
      // Place your code here
      if (adc_data>512) {PORTB|=(1<<4);}else{PORTB&=~(1<<4);};
      }
}
Добавлено after 9 minutes 17 seconds:
ПС: сейчас у меня стоит кодевижен версии 3.42. возможно в другой версии настройка АЦП удобнее...
Вложения
2020-09-24_21-02-30.png
(15.47 КБ) 527 скачиваний
2020-09-24_19-38-07.png
(3.85 КБ) 730 скачиваний
2020-09-24_19-30-28.png
(1.94 КБ) 733 скачивания
2020-09-24_19-26-34.png
(5.11 КБ) 753 скачивания
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Аватара пользователя
Ivanoff-iv
Друг Кота
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Re: AtTiny 13 и АЦП

Сообщение Ivanoff-iv »

Есть вариант проще, но медленней (без прерываний):
частоту и порты настраиваешь также
АЦП так:
СпойлерИзображение
и всё, сам квавр создаст функцию получения данных из АЦП, остаётся ею воспользоваться:
добавить в главный цикл строку if (read_adc(1)>512) {PORTB|=(1<<4);}else{PORTB&=~(1<<4);};
(1 - это номер входа)
и всё, всё работает!
весь код:
Спойлер

Код: Выделить всё

#include <tiny13a.h>

#include <delay.h>

// Declare your global variables here

// Bandgap Voltage Reference: Off
#define ADC_VREF_TYPE ((0<<REFS0) | (0<<ADLAR))

// Read the AD conversion result
unsigned int read_adc(unsigned char adc_input)
{
ADMUX=adc_input | ADC_VREF_TYPE;
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// Start the AD conversion
ADCSRA|=(1<<ADSC);
// Wait for the AD conversion to complete
while ((ADCSRA & (1<<ADIF))==0);
ADCSRA|=(1<<ADIF);
return ADCW;
}

void main(void)
{
// Declare your local variables here

// Crystal Oscillator division factor: 8
#pragma optsize-
CLKPR=(1<<CLKPCE);
CLKPR=(0<<CLKPCE) | (0<<CLKPS3) | (0<<CLKPS2) | (1<<CLKPS1) | (1<<CLKPS0);
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

// Input/Output Ports initialization
// Port B initialization
// Function: Bit5=In Bit4=Out Bit3=In Bit2=In Bit1=In Bit0=In 
DDRB=(0<<DDB5) | (1<<DDB4) | (0<<DDB3) | (0<<DDB2) | (0<<DDB1) | (0<<DDB0);
// State: Bit5=P Bit4=0 Bit3=P Bit2=T Bit1=P Bit0=P 
PORTB=(1<<PORTB5) | (0<<PORTB4) | (1<<PORTB3) | (0<<PORTB2) | (1<<PORTB1) | (1<<PORTB0);

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=0xFF
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=(0<<COM0A1) | (0<<COM0A0) | (0<<COM0B1) | (0<<COM0B0) | (0<<WGM01) | (0<<WGM00);
TCCR0B=(0<<WGM02) | (0<<CS02) | (0<<CS01) | (0<<CS00);
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=(0<<OCIE0B) | (0<<OCIE0A) | (0<<TOIE0);

// External Interrupt(s) initialization
// INT0: Off
// Interrupt on any change on pins PCINT0-5: Off
GIMSK=(0<<INT0) | (0<<PCIE);
MCUCR=(0<<ISC01) | (0<<ISC00);

// Analog Comparator initialization
// Analog Comparator: Off
// The Analog Comparator's positive input is
// connected to the AIN0 pin
// The Analog Comparator's negative input is
// connected to the AIN1 pin
ACSR=(1<<ACD) | (0<<ACBG) | (0<<ACO) | (0<<ACI) | (0<<ACIE) | (0<<ACIS1) | (0<<ACIS0);
// Digital input buffer on AIN0: On
// Digital input buffer on AIN1: On
DIDR0=(0<<AIN0D) | (0<<AIN1D);

// ADC initialization
// ADC Clock frequency: 150,000 kHz
// ADC Bandgap Voltage Reference: Off
// ADC Auto Trigger Source: ADC Stopped
// Digital input buffers on ADC0: On, ADC1: On, ADC2: On, ADC3: On
DIDR0|=(0<<ADC0D) | (0<<ADC2D) | (0<<ADC3D) | (0<<ADC1D);
ADMUX=ADC_VREF_TYPE;
ADCSRA=(1<<ADEN) | (0<<ADSC) | (0<<ADATE) | (0<<ADIF) | (0<<ADIE) | (0<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
ADCSRB=(0<<ADTS2) | (0<<ADTS1) | (0<<ADTS0);


while (1)
      {
      // Place your code here
      if (read_adc(1)>512) {PORTB|=(1<<4);}else{PORTB&=~(1<<4);};
      }
}
как я уже писал, этот код медленнее т.к. при вызове функции сначала подключается нужный вход (после этого требуется немного подождать), потом запускается преобразование, в это время АЛУ в цикле ожидает его завершения и другую работу делать не может.

Добавлено after 2 minutes 17 seconds:
ПС: выбор метода зависит от выполняемой контроллером задачи (иногда бывает слишком расточительно ждать результата...)
Вложения
2020-09-25_09-47-20.png
(3.06 КБ) 474 скачивания
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
sharmax
Открыл глаза
Сообщения: 78
Зарегистрирован: Сб янв 28, 2012 21:09:29

Re: AtTiny 13 и АЦП

Сообщение sharmax »

Ivanoff-iv, огромное Вам спасибо. Я пока немного занят (основную работу никто пока не отменял), но в выходные обязательно посижу и вникну.
sharmax
Открыл глаза
Сообщения: 78
Зарегистрирован: Сб янв 28, 2012 21:09:29

Re: AtTiny 13 и АЦП

Сообщение sharmax »

В принципе, все понятно, огромное Вам спасибо за грамотные и самое главное внятные объяснения.
Пара вопросов (пока рассмотрим последний вариант - без прерывания):
1. В регистр ADMUX заносится содержимое переменной ADC_VREF_TYPE, которой, в свою очередь, в самом начале кода придается значение 0b00000000 (заносим 0 в 6 и 5 биты, остальные - равны 0 по результатам инициализации, то есть, по умолчанию. К чему такие сложности? Нельзя ли сразу указать в блоке настройки АЦП: ADMUX = 0b00000000? Зачем вообще используется эта переменная здесь?
Кстати, в моем кодевижине она тоже вводится с непонятной мне целью, причем, в нее изначально заносится 0 (#define ADC_VREF_TYPE 0x00). Потом, уже в блоке инициализации АЦП стоит команда: ADMUX=ADC_VREF_TYPE & 0xff. Т.к. 0xff = 0b11111111, имеем: 0b00000000 & 0b11111111 = 0b00000000. Поскольку в качестве входа АЦП используется ADC1, в ADMUX должно быть: 0b00000001. Так?
2. В главном цикле программы видим: if (read_adc(1)>512) {PORTB|=(1<<4);}else{PORTB&=~(1<<4);};
а) можно ли здесь взамен "read_adc(1)>512" записать "ADCW>512?"
В варианте с прерыванием есть в процедуре обработки прерывания строка: adc_data=ADCW, но во втором варианте я строки "read_adc(1) = ADCW" нигде не нашел. Как компилятор узнает, что под переменной read_adc(1) следует понимать содержимое регистра ADCW? Да и сама переменная read_adc(1) нигде не определена. Компилятор не выдавал ошибки???
б) Запись типа PORTB|=(1<<4);}else{PORTB&=~(1<<4); это не для среднего ума, как у меня. Возможно ли весь главный цикл программы записать следующим образом:
if (ADCW>512) {portb.4=1;} else {portb.4=0} ?
А так больше вопросов нет. Как смогу, сяду за макетку.
Аватара пользователя
Ivanoff-iv
Друг Кота
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Re: AtTiny 13 и АЦП

Сообщение Ivanoff-iv »

2)read_adc(x) это не переменная, это функция (в коде выше она есть) - чтобы в ADCW появился результат измерения нужно проделать все описанные в ней команды
3)PORTB|=(1<<4); равносильно PORTB.4=1;
а PORTB&=~(1<<4); равносильно PORTB.4=0;
т.ч. если вынесешь в этот цикл все команды из функции - то, да, твоя конструкция заработает.
1) про ADMUX напишу завтра
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Аватара пользователя
Ivanoff-iv
Друг Кота
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Re: AtTiny 13 и АЦП

Сообщение Ivanoff-iv »

sharmax писал(а):Запись типа PORTB|=(1<<4);}else{PORTB&=~(1<<4); это не для среднего ума...
да, не для среднего... это основы... :oops:
читать:
Программирование микроконтроллеров ATMEL на языке С (Прокопенко В.С.)
стр. 20-30 - про базовые логические операции
стр. 191-201 - про АЦП (у тинь и мег они похожи) - тут автор применяет цифровую нумерацию битов, хотя правильней вписывать их названия, как делает генератор кода КВАвр (а цифры подставит уже препроцессор, это увеличивает читаемость и переносимость кода)
:idea: и ещё, если внимательно читал про лог. операции, то догадаешься, что (1<<MUX1)|(1<<MUX0) == (3<<MUX0),
я предпочитаю второй вариант - сразу видно, что подключаем 3й вход, также можно настраивать и другие параметры, занимающие более 1го бита.
даташит тини13
стр. 92 - про регистр ADMUX (самому перепечатывать лениво... там на английском, но текст можно скопировать в переводчик)
Пользоваться переведенными д.ш. не рекомендую, т.к. ошибки перевода никто не отменял да и при чтения оригиналов технический инглиш в мозгу закрепится и дальше будет легче.

если чтото будет непонятно после этого - спрашивай, буду объяснять
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
sharmax
Открыл глаза
Сообщения: 78
Зарегистрирован: Сб янв 28, 2012 21:09:29

Re: AtTiny 13 и АЦП

Сообщение sharmax »

Ivanoff-iv, я прошу прощения, сейчас более детально занялся этим вопросом... Пока изучаю под микроскопом вариант без прерываний. Здесь имеется функция
unsigned int read_adc(unsigned char adc_input)
Насколько я понимаю, называется она "read_adc", возвращает она число (результат работы АЦП) типа unsigned int в регистр ADCW, как и должно быть. А вот входным аргументом этой функции является переменная "adc input" типа unsigned char. Но где в тексте остального кода эта переменная определяется??? Чему она равна?! Допустим, она определяется здесь же, при описании функции "read_adc", тогда по всем законам эта переменная должна инициализироваться нулем, т.е, следует считать: adc_input = 0. Но тогда строка ADMUX=adc_input | ADC_VREF_TYPE в регистр ADMUX запишет число: 0b00000000 | 0b00000000 = 0b00000000, последние 2 цифры у которого 00, то есть, в качестве входа АЦП используется 1 ножка - PB5, она же вход RESET. Но выше то мы договаривались входом АЦП использовать вход ADC 1 или PB2!
Выходит, что read_adc должна быть не 0, а 0b00000001??? Или я неправильно рассуждаю?
NStorm
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Re: AtTiny 13 и АЦП

Сообщение NStorm »

Насколько я понимаю, называется она "read_adc", возвращает она число (результат работы АЦП) типа unsigned int в регистр ADCW,
Не В регистр. А ИЗ регистра. Она читает его значение и возвращает его как возвращаемое значение функции (через стек). Дальше по коду где она вызывается, делается что-то вроде unisinged int a = read_adc(...); и соотв. возвращаемое значение запишется в переменную "а".
вот входным аргументом этой функции является переменная "adc input" типа unsigned char. Но где в тексте остального кода эта переменная определяется??? Чему она равна?!
Аргументы функций не определяются отдельно. Они передаются в стеке при вызове функции. Вот когда делаете read_adc(123); то в самой функции adc_input будет равен 123. После выхода из фукнции adc_input "исчезает" отдельно. Если сделаете unsinged int b = 222; потом вызовите a = read_adc(b); то adc_input будет внутри функции равен 222. После выхода из функции adc_input "исчезнет", но b при этом остается неизменным.

Вам бы про основы C почитать. Про функции, аргументы и возвращаемые значения.

Добавлено after 1 minute 12 seconds:
Ну хотя бы вот: https://prog-cpp.ru/c-functions/

Добавлено after 2 minutes 40 seconds:
Но тогда строка ADMUX=adc_input | ADC_VREF_TYPE в регистр ADMUX запишет число: 0b00000000 | 0b00000000 = 0b00000000, последние 2 цифры у которого 00, то есть, в качестве входа АЦП используется 1 ножка - PB5, она же вход RESET. Но выше то мы договаривались входом АЦП использовать вход ADC 1 или PB2!
В коде Ivanoff-iv функция вызывается с аргументом 1:

Код: Выделить всё

 if (read_adc(1)>512) ...
Следовательно, ADMUX=adc_input | ADC_VREF_TYPE будет равен 1, потому что будет это 0b1 | 0 = 1.

Добавлено after 27 seconds:
Выходит, что read_adc должна быть не 0, а 0b00000001??? Или я неправильно рассуждаю?
Выходит что этому она и будет равна )
Ответить

Вернуться в «Теория»