Главная Friday, August 18 2017  
ГлавнаяКонтактыАдминистрированиеПрограммированиеСсылки
UK-flag-ico.png English Version
GERMAN-flag-ico.png Die deutsche Version
лента новостей сайта microsin.ru лента новостей
map.gif карта сайта
нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.

Поделиться:
Кто он-лайн
Сейчас на сайте:
Гостей - 2
Модуль рекламы
Поисковые системы

Пример подключения АЦП MCP3202 к микроконтроллеру AVR Версия для печати
Написал microsin   
27.06.2011

Рассматривается код программного SPI микроконтроллера AVR и подключение через него внешнего 12-битного ADC (АЦП) MCP3202.

MCP3202_CIP_DIP8.jpg MCP3202-CISN-SOIC8.JPG

Аппаратно подключение довольно простое - тип интерфейса SPI, используется 4 сигнала CS, DI, DO и CLK (см. таблицу).

MCP3202.png

 Цоколевка АЦП MCP3202 (аналог ADC0832)

Сигнал MCP3202
Порт AVR
Описание
CS, вход
PB5, выход
Выборка для чипа MCP3202, активный уровень - лог. 0
DI, вход
PB7, выход
Последовательные данные команды для MCP3202
DO, выход
PC7, вход
Последовательные данные результата АЦП MCP3202
CLK, вход
PB6, выход
Такты для бит сигналов DI и DO MCP3202

У АЦП два мультиплексируемых входа CH0 и CH1, которые могут быть выбраны программно. В качестве эталонного напряжения (reference voltage) для АЦП MCP3202 служит напряжение питания VDD/VREF.

Используемый протокол обмена данными максимально прост. Сначала по шине DI идут 4 бита команды, потом по шине DO выдвигаются из АЦП 12 бит данных (каждый бит команды DI и каждый бит данных DO тактируется фронтом сигнала CLK). Данные передаются в порядке, когда самый старший бит идет первым (MSBF, Most Significant Bit First).

MCP3202-SPI-protocol.png

Так как сигналы DI и DO активны в разное время, то для экономии портов они теоретически могут быть запараллелены. Однако в этом случае необходимо очень аккуратно манипулировать сигналами CS и CLK - чтобы не было паразитного зацикливания с выхода DO на вход DI. Биты данных на DO и DI считываются по нарастанию (фронту) сигнала CLK.

tCYC - полное время цикла аналого-цифрового преобразования.
tCSH - минимальное время нахождения сигнала выборки в неактивном (лог. 1) состоянии (500 нс).
tSUCS - минимальное время между спадом сигнала выборки и первым фронтом нарастания сигнала тактов (100 нс).
tSAMPLE - время, за которое делается выборка и запоминание уровня напряжения на аналоговом входе АЦП (CH0 или CH1).
tCONV - время аналого-цифрового преобразования.
tDATA - в течение этого времени выключаются внутренние узлы АЦП.
START - стартовый бит команды, всегда лог. 1
SGL/DIFF - бит, задающий режим работы входов CH0 и CH1. Если лог. 1, то входы одиночные (недифференциальные), если лог. 0, то входы дифференциальные.
ODD/SIGN - бит, задающий номер выбранного входа CH0 или CH1 (когда вход недифференциальный), либо полярность дифференциальных входом (когда вход дифференциальный). Если в недифференциальном режиме значение этого бита равно 0, то выбран как аналоговый вход CH0, если 1, то выбран CH1.
MSBF - бит, задающий порядок передачи бит данных. В самом простейшем случае этот бит должен быть равен 1, что означает - самый старший бит будет идти первым, а самый младший - последним.
HI-Z - высокоимпедансное состояние выхода данных DO (выход чипа MCP3202 отключен).
Don't Care - значение входных данных DI не имеют значения.
Null Bit - пустой нулевой, ничего не значащий бит данных.
B11..B0 - биты данных АЦП (результат аналого-цифрового преобразования).

Для реализации обмена данными использовался программно формируемый интерфейс SPI. За основу взят код для подключения MCP3202 к микроконтроллеру MCS51 (см. [2]). Код испытывался на чипе AVR USB AT90USB162, но он будет работать на любом микроконтроллере семейства AVR компании Atmel, и может быть портирован на другие микроконтроллеры.

[MCP3202.h]

#ifndef _MCP3202_
#define _MCP3202_

#include <avr/io.h>

#define ADC_CS  PB5
#define ADC_CLK PB6
#define ADC_DI  PB7
#define ADC_DO  PC7

//К ножке 2 MCP3202 (канал 0) подключено измеряемое
// напряжение VTARGET
#define CHANNEL0 0

unsigned int ReadMCP3202ADC(unsigned char channel);

#endif  //_MCP3202_

[MCP3202.c

/*
Подпрограмма чтения ADC MCP3202 фирмы Microchip.
Идея взята тут: http://www.sixca.com/micro/mcs51/adc12bit/
*/

#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-buffer.PNG

[Пример использования АЦП MCP3202 - апгрейд программатора AVRISP-MkII]

После изготовления клона AVRISP-MkII (см. [1]) выяснилось, что желательно было бы иметь возможность измерять напряжение питания программируемого микроконтроллера. Так как в микроконтроллере AT90USB162 внутреннего АЦП нету, то возникла идея подключить внешний АЦП.

AVRISP-MKII-full-AVR-USB162MU-MCP3202.PNG

Резисторы R7 и R8 - защитные. R7 уравнивает разность потенциалов между выходом DOUT АЦП и входным портом микроконтроллера, когда у них различается напряжение питания - у АЦП всегда напряжение питания +5 вольт, а у портов ввода/вывода микроконтроллера напряжение может переключаться в зависимости от положения перемычки SJ1 (либо 3.3 вольт, либо 5 вольт). Буфера на операционном усилителе перед входом CH0 нет, так как выходное сопротивление источника питания VTARGET достаточно мало, и не требуется высокая точность измерения напряжения.

MCP3202_in_AVRISP-MkII_IMG_1287.JPG

Использование внешнего АЦП MCP3202 в firmware программатора включается на этапе компиляции, если в makefile задан макрос USE_MCP3202. Если этот макрос задан, то в подпрограмме V2ProtocolParams.c -> V2Params_UpdateParamValues напряжение VTarget считывается с АЦП MCP3202 и записывается в V2Params_GetParamFromTable(PARAM_VTARGET)->ParamValue как число в единицах десятых долей вольта.

После такой доработки в утилите программатора AVRStudio на закладке HW Settings стало правильно измеряться и отображаться напряжение питания программируемого чипа VTarget.

AVRISP-MkII-AVRStudio07.PNG

[Ссылки]

1. AVR-USB162MU: макетирование и изготовление программатора AVRISP-MKII в домашних условиях.
2. Connecting AT89S52 with 12 bit ADC 2 channel.
3. Страница краткого описания АЦП MCP3202.
4Исходный код и скомпилированные прошивки программатора AVRISP-MkII, доработанного подключенным АЦП MCP3202.

Последнее обновление ( 27.06.2011 )
 

Комментарии  

  1. #1 Виталий СПб
    2011-06-2716:08:40 А почему вы не пользуетесь стандартом С99 для обозначения переменных? Ведь uint16_t выглядит понятней, чем unsignet int для 8-ми битной архитектуры.

    В чем прикол k++; ??? Компилятор их вообще соптимизирует. Почему не использовать _NOP(); ? А еще лучше _delay_us(); ?

    Почему бы PORTB тоже не продефайнить скажем как PORT_ADC?

    microsin: Вы во всем правы, Виталий. Однако замечания некритичны. Вы ведь поняли, что такое unsigned int? Поняли. Компилятор понял? Наверное тоже понял. Поэтому тут чистое ИМХО - кому что больше нравится. Я например больше люблю обозначения типов еще короче: s8, s16, s32 (это типы со знаком, signed) и u8, u16, u32 (это для типов unsigned). То же самое можно сказать про PORTx - переименовать его было бы конечно красивее, однако код все равно тупо не переносится с порта B на порт C или на какой-то еще (если нужно поменять используемые ножки портов), поэтому такое скрытие деталей может сыграть злую шутку. Так что делайте как Вам самому больше нравится.

    Насчет k++ : Вы опять правы, наверное лучше было применить что-то типа NOP(). Я не проверял, какой именно ассемблерный код генерит у меня компилятор, однако проверил реальную работоспособнос ть кода, и мне этого показалось достаточным.

Добавить комментарий

:D:lol::-);-)8):-|:-*:oops::sad::cry::o:-?:-x:eek::zzz:P:roll::sigh:

Защитный код
Обновить

< Пред.   След. >

Top of Page
 
microsin © 2017