Пример подключения АЦП MCP3202 к микроконтроллеру AVR |
![]() |
Добавил(а) microsin | |||||||||||||||||
Рассматривается код программного SPI микроконтроллера AVR и подключение через него внешнего 12-битного ADC (АЦП) MCP3202.
Аппаратно подключение довольно простое - тип интерфейса SPI, используется 4 сигнала CS, DI, DO и CLK (см. таблицу). Цоколевка АЦП MCP3202 (аналог ADC0832)
У АЦП два мультиплексируемых входа CH0 и CH1, которые могут быть выбраны программно. В качестве эталонного напряжения (reference voltage) для АЦП MCP3202 служит напряжение питания VDD/VREF. Используемый протокол обмена данными максимально прост. Сначала по шине DI идут 4 бита команды, потом по шине DO выдвигаются из АЦП 12 бит данных (каждый бит команды DI и каждый бит данных DO тактируется фронтом сигнала CLK). Данные передаются в порядке, когда самый старший бит идет первым (MSBF, Most Significant Bit First). Так как сигналы DI и DO активны в разное время, то для экономии портов они теоретически могут быть запараллелены. Однако в этом случае необходимо очень аккуратно манипулировать сигналами CS и CLK - чтобы не было паразитного зацикливания с выхода DO на вход DI. Биты данных на DO и DI считываются по нарастанию (фронту) сигнала CLK. tCYC - полное время цикла аналого-цифрового преобразования. Для реализации обмена данными использовался программно формируемый интерфейс SPI. За основу взят код для подключения MCP3202 к микроконтроллеру MCS51 (см. [2]). Код испытывался на чипе AVR USB AT90USB162, но он будет работать на любом микроконтроллере семейства AVR компании Atmel, и может быть портирован на другие микроконтроллеры. [MCP3202.h] /* Подпрограмма чтения ADC MCP3202 фирмы Microchip. #include "MCP3202.h" //---------------------------------------------------------- // Чтение аналоговых данных из ADC MCP3202 через программный // SPI. Подпрограмма не требует предварительной // инициализации портов для работы с ножками SPI. // Режим MCP3202: недифференциальный (Single end, 2 канала), // старший бит идет первым (MSB first). // Входной параметр channel задает канал: 0 канал с ножки 2, // 1 канал с ножки 3. //---------------------------------------------------------- unsigned int ReadMCP3202ADC (unsigned char channel) { unsigned char i,k; unsigned int AdcResult; // 12 бит //настройка DO как входа без pullup DDRC &= ~(1<<ADC_DO); PORTC &= ~(1<<ADC_DO); //остальные ножки как выходы, у CLK начальное состояние 0, // у CS и DI начальное состояние 1. DDRB |= ((1<<ADC_CS)|(1<<ADC_CLK)|(1<<ADC_DI)); PORTB |= ((1<<ADC_CS)|(0<<ADC_CLK)|(1<<ADC_DI)); //ADC_CS=0 активируем выборку чипа PORTB &= ~(1<<ADC_CS); k++;k++; // задержка около 2 мкс #define CMD_BIT_START 0x08 #define CMD_BIT_SGL 0x04 #define CMD_BIT_MSBF 0x01 channel <<= 1; channel |= (CMD_BIT_START | CMD_BIT_SGL | CMD_BIT_MSBF); //////////////////////////////////////////////////// // передаем 4 бита команды, старший бит идет первым for(i=0; i< 4;i++) { PORTB = ((channel & 0x08) != 0) ? PORTB | (1<<ADC_DI) : PORTB & ~(1<<ADC_DI); channel <<= 1; PORTB |= (1 << ADC_CLK); //ADC_CLK=1 k++;k++; // задержка около 2 мкс PORTB &= ~(1 << ADC_CLK); //ADC_CLK=0 } k++;k++; // задержка около 2 мкс PORTB |= (1 << ADC_CLK); //ADC_CLK=1 k++;k++; // задержка около 2 мкс PORTB &= ~(1 << ADC_CLK); //ADC_CLK=0 k++;k++; // задержка около 2 мкс //////////////////////////////////////////////////// // чтение 12 бит результата ADC, старший бит первый AdcResult=0; for(i=0;i<12;i++) { PORTB |= (1 << ADC_CLK); //ADC_CLK=1 k++;k++; // задержка около 2 мкс AdcResult<<=1; if (PINC & (1 << ADC_DO)) AdcResult |= 1; PORTB &= ~(1 << ADC_CLK); //ADC_CLK=0 k++;k++; // задержка около 2 мкс } PORTB |= ((1 << ADC_CS)|(0 << ADC_CLK)|(1 << ADC_DI)); return(AdcResult); } При подключении АЦП к измеряемым цепям нужно иметь в виду, что входы CH0 и CH1 у MCP3202 имеют низкое и нелинейное сопротивление (которое меняется в зависимости от состояния процесса аналого-цифрового преобразования). Поэтому напрямую подключать MCP3202 в большинстве случаев нельзя, нужен буферный усилитель, иначе результат измерения напряжения будет неверным. На рисунке показан пример простой схемы такого буферного усилителя вместе с антиалиазинговым фильтром низкой частоты на операционном усилителе MCP601. [Пример использования АЦП MCP3202 - апгрейд программатора AVRISP-MkII] После изготовления клона AVRISP-MkII (см. [1]) выяснилось, что желательно было бы иметь возможность измерять напряжение питания программируемого микроконтроллера. Так как в микроконтроллере AT90USB162 внутреннего АЦП нету, то возникла идея подключить внешний АЦП. Резисторы R7 и R8 - защитные. R7 уравнивает разность потенциалов между выходом DOUT АЦП и входным портом микроконтроллера, когда у них различается напряжение питания - у АЦП всегда напряжение питания +5 вольт, а у портов ввода/вывода микроконтроллера напряжение может переключаться в зависимости от положения перемычки SJ1 (либо 3.3 вольт, либо 5 вольт). Буфера на операционном усилителе перед входом CH0 нет, так как выходное сопротивление источника питания VTARGET достаточно мало, и не требуется высокая точность измерения напряжения. Использование внешнего АЦП MCP3202 в firmware программатора включается на этапе компиляции, если в makefile задан макрос USE_MCP3202. Если этот макрос задан, то в подпрограмме V2ProtocolParams.c -> V2Params_UpdateParamValues напряжение VTarget считывается с АЦП MCP3202 и записывается в V2Params_GetParamFromTable(PARAM_VTARGET)->ParamValue как число в единицах десятых долей вольта. После такой доработки в утилите программатора AVR Studio на закладке HW Settings стало правильно измеряться и отображаться напряжение питания программируемого чипа VTarget. [Ссылки] 1. AVR-USB162MU: макетирование и изготовление программатора AVRISP-MKII в домашних условиях. |