Как заставить работать микросхему ЦАП?

trukhanov
Offline
Зарегистрирован: 26.03.2018

Коллеги, приветствую!

Сразу прошу прощения за новичковый вопрос. Я никогда не работал с ардуино, более того у меня нет никакого опыта практической работы с электроникой и электротехникой. У меня есть инженерное образование,которое я получил 25 лет назад и ни разу не работал по специальности, поэтому что-то я понимаю, но этого "чего-то" видимо недостаточно, поэтому я прошу вашей консультации.

Расписывать весь проект я не буду, для экономии вашего времени, краткая задача состоит в том, чтобы получить с ардуино два восьмибитных значения и преобразовать их в два значения напряжения. Сразу оговорюсь, чтобы избежать вопросов, эксперимент с ШИМом не удался из-за своеобразной организации контролера, которым мне необходимо управлять. Поэтому я решил выводить в два регистра два восьмибитных числа и на выходе поставить ЦАП. Сначала я собрал так называемую "лестницу сопротивлений" или R-2R  ЦАП на 16-и резисторах - это было рабочее решение, но мне хотелось упростить и избавится от такой кучи деталей, поэтому я поискав в интернете, приобрел микросхему AD7302BNZ, которая представляет из себя два ЦАПа с паралельной 8-битной загрузкой, как мне и надо. Но, мне не удалось заставить ее работать.  Я подозреваю, что я неправильно истолковываю описание ее упраляющих сигналов, поэтому прошу у вас консультации и разъяснения, что именно и на какую ногу мне подавать, чтобы оно заработало.

Вот ссылка на PDF с описанием микросхемы. 

Правильно ли я понял, что:

1. Все управляющие сигналы описаны как low active, а это значит, что мне необходимо подавать на них "0", чтобы они выполнили свою функцию?

2. На ногу CS я подаю постоянный ноль (то есть просто ее могу не подключать), чтобы она всегда была активной.

3. На ноги CLR и PD я подаю постоянный высокий сигнал, чтобы они не работали. 

4. На ногу LDAC я подаю "0" (или не подключаю), так как мне не важна синхронная загрузка в регистры ЦАПов.

5. К ноге REFIN  я ничего не подключаю, к ноге Vdd я подключаю 5V с ардуины, к ногам DGND и AGND подключаю GND ардуины.

6. К ноге WR я по умолчанию подаю "0", а когда мне надо загрузить данные подаю сначала "1". а потом "0", чтобы возник положительный фронт.

Далее весь алгоритм выглядит так:

1. На ногу A/B я сначала подаю "0"

2. Потом в регистр ардуины вывожу нужное мне восьмибитное число.

3. Потом в WR я подаю 1, а за тем 0.

4. На ногу A/B подаю "1" и перехожу к п. 2

В результате на выходах VoutA и VoutB я получаю два нужных мне напряжения.

Видимо я что-то не так понял или сделал, потому что такая схема не работает - на выходах нули.

Буду благодарен за разъяснения.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

"Подать 0" - соединить с землей. Никуда не подключать, это совсем другое, в некоторых случаях совпрадающее с "подать 1"

nik182
Offline
Зарегистрирован: 04.05.2015

Refin подать напряжение, можно как на рис. 27 просто питание. На wr должна быть 1. Ldac и cs -0. На а/в выставляем 0 для первого , 1 для второго канала . На дата выставляем код в прямом коде : 0 это 0 на выходе. Затем на время больше 20 наносекунд на wr надо подать 0. Достаточно digitalwrite(0);digitalwrite(1);
На PD и CLR я б подал 1 от греха подальше.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

trukhanov пишет:

Как заставить работать микросхему ЦАП?

Как всегда: добрым словом и/или пистолетом. 

toxikaciya
Offline
Зарегистрирован: 11.04.2016

ЕвгенийП пишет:

trukhanov пишет:

Как заставить работать микросхему ЦАП?

Как всегда: добрым словом и/или пистолетом. 

Позвать белый дым.

trukhanov
Offline
Зарегистрирован: 26.03.2018

nik182 пишет:
Refin подать напряжение, можно как на рис. 27 просто питание. На wr должна быть 1. Ldac и cs -0. На а/в выставляем 0 для первого , 1 для второго канала . На дата выставляем код в прямом коде : 0 это 0 на выходе. Затем на время больше 20 наносекунд на wr надо подать 0. Достаточно digitalwrite(0);digitalwrite(1); На PD и CLR я б подал 1 от греха подальше.

Благодарю! Попробовал - не работает. Есть подозрение, что дело не в неправильном управлении, а в чем-то еще. Может чип битый? Как проверить работоспособность микросхемы?

Видимо, придется забить на микросхему и вернуться к R-2R ЦАПу, иначе получается проблема затянулась.

В любом случае спасибо, что откликнулись.

nik182
Offline
Зарегистрирован: 04.05.2015

Не может она не работать. Вот только выход у неё очень маломощный. Приходится ОУ ставить что бы хоть на что то нагрузить.

trukhanov
Offline
Зарегистрирован: 26.03.2018

nik182 пишет:

Не может она не работать. Вот только выход у неё очень маломощный. Приходится ОУ ставить что бы хоть на что то нагрузить.

 

Я прошу прощения за уточнение - ОУ - это операционный усилитель? (это я сейчас в яндексе посмотрел :)). 

Если да, то это врядли мой случай - мерял и силу и напряжение - по нулям на обеих ногах. Что-то я не так делаю конкретно. Вроде уже все ноги перемерял - все как и должно быть. А на выходе - нифига.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Опубликуйте схему - иначе долго можно гадать на кофейной гуще.

trukhanov
Offline
Зарегистрирован: 26.03.2018

andriano пишет:

Опубликуйте схему - иначе долго можно гадать на кофейной гуще.

Согласен. Вот так пойдет? Ниже кусок кода, которым я пытаюсь этой схемой управлять.

digitalWrite (A10, 0);

PORTF = leftMotorPower;

digitalWrite (A9, 0);

digitalWrite (A9, 1);

digitalWrite (A10, 1);

PORTF = rightMotorPower;

digitalWrite (A9, 0);

digitalWrite (A9, 1);

Выход VoutB пока в воздухе висит, на макетке и так полное макраме из проводов, тестирую только на одном диоде попеременно подключая VoutA или VoutB. Также мерил мультиметром обе ноги. Ничего нет.

Думаю, лучше мне подробнее рассказать, вдруг что-то важное упускаю. К ардуине подключен USB Host Shield 2.0, к которому подключен джойстик для самолетных симуляторов. Я получаю сигнал от движения рукоятки джойстика, анализирую его и в зависимости от положения джойстика подаю на выход два цифровых сигнала, которые должны превратится в два напряжения и управлять двумя мотор-колесами. Вся эта канитель прекрасно работала на R-2R, а вот с микросхемой непонятка. 

nik182
Offline
Зарегистрирован: 04.05.2015

Вставте, пожалуйста, по правилам форома, полную программу.

trukhanov
Offline
Зарегистрирован: 26.03.2018

nik182 пишет:

Скажите, а что такое A10, A9? Какая плата? И что такое PORTF? К каким ногам ардуины он у вас идёт?

У меня Arduino Mega 2560. PORTF - это пины Analog In с 7-го по 0-вой.

Вот тут есть распиновка Меги с указанием всех портов.

У меня на плате пины Analog In пронумерованы A0 - A15.  Т.е. A10 и A9 -это Analog In 10 и Analog In 9. 

Предварительно я инициализирую все эти пины и порт на вывод:

pinMode (A9, OUTPUT);

pinMode (A10, OUTPUT);

DDRF = B11111111;

trukhanov
Offline
Зарегистрирован: 26.03.2018

nik182 пишет:

Вставте, пожалуйста, по правилам форома, полную программу.

Извините.

#include "urbamobileJoystick.h"

//Описание переменных
//GamePadEventData - это структура, описывающая все параметры джойстика
//leftMotorPower, rightMotorPower - это цифровые значения напряжения, которые надо выводить на колеса
//powerLock - это значение "замка", только после нажатия на него в порт подаются данные
//остальные переменные используются для промежуточных вычислений напряжения в зависимости от параметров джойстика

GamePadEventData	currentStatus, oldStatus;
uint8_t				leftMotorPower = 42, rightMotorPower = 42, oldLeftMotorPower, oldRightMotorPower;
const uint8_t		basePower = 42;
const double		joystickXmax = 0x03FF, joystickYmax = 0x03FF, joystickXcenter = 0x01FF, joystickYcenter = 0x01FF;
uint8_t				powerStepsCount, powerStepsY;
double				coordinateStepY, coordinateStepX;
bool 				powerLock = true;
bool				DAC_Register_AB, DAC_CS, DAC_WR, DAC_LDAC;




//Эта функция получает данные с джойстика
JoystickReportParser::JoystickReportParser(JoystickEvents *evt) :
	joyEvents(evt)
{}

void JoystickReportParser::Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf)
{
	bool match = true;

	// Checking if there are changes in report since the method was last called
	for (uint8_t i=0; i<RPT_GAMEPAD_LEN; i++) {
		if( buf[i] != oldPad[i] ) {
			match = false;
			break;
		}
  }
  	// Calling Game Pad event handler
	if (!match && joyEvents) {
		joyEvents->OnGamePadChanged((const GamePadEventData*)buf);

		for (uint8_t i=0; i<RPT_GAMEPAD_LEN; i++) oldPad[i] = buf[i];
	}
}

//Вот в этой функции все и происходит 
void JoystickEvents::OnGamePadChanged(const GamePadEventData *evt)
{
	
	currentStatus.x			= evt->x;
	currentStatus.y			= evt->y;
	currentStatus.hat		= evt->hat;
	currentStatus.twist 	= evt->twist;
	currentStatus.slider 	= evt->slider;
	currentStatus.buttons_a = evt->buttons_a;
	currentStatus.buttons_b	= evt->buttons_b;
	
	pinMode (A8, OUTPUT);
	pinMode (A9, OUTPUT);
	pinMode (A10, OUTPUT);
	
	
	if (currentStatus.buttons_a == 0x01) {
		if (powerLock) powerLock = false;
		else powerLock = true;
	}	
	
	powerStepsCount = ceil ((256 - basePower) * currentStatus.slider / 255);
	coordinateStepY	= (joystickYmax - joystickYcenter) / powerStepsCount;
	powerStepsY = ceil((256 - basePower) / powerStepsCount);
	
	DDRF = B11111111;
//	DDRK = B11111111;
		
	Serial.print("X: ");
	PrintHex<uint16_t>(evt->x, 0x80);
	Serial.print(" Y: ");
	PrintHex<uint16_t>(evt->y, 0x80);
//	Serial.print(" Hat Switch: ");
//	PrintHex<uint8_t>(evt->hat, 0x80);
//	Serial.print(" Twist: ");
//	PrintHex<uint8_t>(evt->twist, 0x80);
	Serial.print(" Slider: ");
	PrintHex<uint8_t>(evt->slider, 0x80);
    Serial.print(" Buttons A: ");
	PrintHex<uint8_t>(evt->buttons_a, 0x80);
//	Serial.print(" Buttons B: ");
//	PrintHex<uint8_t>(evt->buttons_b, 0x80);

	if (currentStatus.y <= joystickYcenter) { 
		leftMotorPower = rightMotorPower = basePower;
	}
	else {
		leftMotorPower = rightMotorPower = basePower + powerStepsY * ceil((currentStatus.y - joystickYcenter) / coordinateStepY);
	}
	
	if (currentStatus.x < joystickXcenter) {
		coordinateStepX = joystickXcenter / (leftMotorPower - basePower); 
		leftMotorPower = leftMotorPower - ceil ((joystickXcenter - currentStatus.x) / coordinateStepX);
	}
	
	if (currentStatus.x > joystickXcenter) {
		coordinateStepX = (joystickXmax - joystickXcenter) / (rightMotorPower - basePower); 
		rightMotorPower = rightMotorPower - ceil ((currentStatus.x - joystickXcenter) / coordinateStepX);
	} 
	
	if ((oldLeftMotorPower > leftMotorPower) && !powerLock) PORTF = basePower;
	if ((oldRightMotorPower > rightMotorPower) && !powerLock) PORTK = basePower;
	
	if (powerLock) leftMotorPower = rightMotorPower = 0;
	
//	digitalWrite (A8, 0);
	digitalWrite (A10, 0);
	PORTF = leftMotorPower;
	digitalWrite (A9, 0);
	digitalWrite (A9, 1);
	
	digitalWrite (A10, 1);
	PORTF = rightMotorPower;
	digitalWrite (A9, 0);
	digitalWrite (A9, 1);
	
	
//	PORTK = rightMotorPower;
	
	Serial.print(" Left Power ");
	Serial.print(leftMotorPower);
	Serial.print(" Right Power ");
	Serial.print(rightMotorPower);	
	Serial.print(" powerLock ");
	Serial.print(powerLock);
	Serial.print(" Power Steps Count ");
	Serial.print(powerStepsCount);
	Serial.print(" coordinateStepY ");
	Serial.print(coordinateStepY);
	Serial.print(" powerStepsY ");
	Serial.print(powerStepsY);
	Serial.println("");
	
	oldLeftMotorPower = leftMotorPower;
	oldRightMotorPower = rightMotorPower;
	
	oldStatus.x			= currentStatus.x;
	oldStatus.y			= currentStatus.y;
	oldStatus.hat		= currentStatus.hat;
	oldStatus.twist		= currentStatus.twist;
	oldStatus.slider	= currentStatus.slider;
	oldStatus.buttons_a	= currentStatus.buttons_a;
	oldStatus.buttons_b	= currentStatus.buttons_b;
	
}

 

nik182
Offline
Зарегистрирован: 04.05.2015

В программе должен быть main или loop & setup - они где? Я рекомендую проверять м.с. отдельной программой где только к ней обращение.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

trukhanov,  а с чего вы собснно решили что CS можно посадить на землю? Это отнюдь не везде прокатывает, иногда нужен именно перепад уровня что-б чип понял что ему что-то шлют. Так что дёргайте его как нарисовано в даташите.

trukhanov
Offline
Зарегистрирован: 26.03.2018

nik182 пишет:

В программе должен быть main или loop & setup - они где? Я рекомендую проверять м.с. отдельной программой где только к ней обращение.

Тот код, что я процитировал, это библиотека, которая вызывается скетчем, поэтому в ней нету ни main, ни loop, ни setup. Это просто описание вызываемых функций. Именно в этих функциях происходит вся работа программы. В самом скетче, где есть setup и loop ничего интересного кроме вызова этих функций нет, цитировать его смысла нет. Программа совершенно рабочая, я вижу ее действия в терминале (я туда вывожу значения переменных для отладки, это видно в программе), более того, я могу проверить мультиметром значения на пинах - и там тоже все в порядке. Однако, спасибо за совет, я напишу маленький скетчик, который будет что-нибудь писать в порт F. Посмотрим.

Спасибо.

trukhanov
Offline
Зарегистрирован: 26.03.2018

dimax пишет:

trukhanov,  а с чего вы собснно решили что CS можно посадить на землю? Это отнюдь не везде прокатывает, иногда нужен именно перепад уровня что-б чип понял что ему что-то шлют. Так что дёргайте его как нарисовано в даташите.

О! Это толково, спасибо. Вы имеете ввиду Рис. 1 в даташите, с таймингом? 

И можете чуть подробнее про "дергать", а то я путаюсь в инвертных входах. Мне надо сначала "0" потом "1" подать или наоброт?

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

У Вас похоже все наоборот "дергается". WR с черточкой - это not WR то есть управляющий(разрешающий) сигнал - низкий. Стало быть порядок должен быть такой (даже вот не смотрел в даташит, тока по вашим обозначениям, могу ошибиться). Все что должно быть известно до записи по идее должно быть предустановлено до самого сигнала "запись":

1. Выбираете "выход" сигналом А10, где 0 - выход "А", 1 - выход "В".;

2. Выставляете в порт F байт для преобразования, возможно тут тоже нужна пауза;

3. Машете сигналом notWR что надо бы записать байт, для этого: Устанавливаете его в 0 (а у Вас в 1!), выдерживаете время записи в преобразователь из даташита и завершаете запись установкой снова в 1.

Как догадываюсь сигнал CS - управление выходом (разрешение работы этой микросхеме из кучки на шине данных - тогда можно посадить на землю, если других таких нет в вашей железяке), но могу и ошибаться, смотрите в даташите временные диаграммы, когда и куда его надо устанавливать. Они должны быть всяко.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

trukhanov,  на рисунке 10стр. всё ясно видно.  Выбрали вход, опустили CS, опустили WR, подняли WR, подняли CS.

trukhanov
Offline
Зарегистрирован: 26.03.2018

dimax пишет:

trukhanov,  на рисунке 10стр. всё ясно видно.  Выбрали вход, опустили CS, опустили WR, подняли WR, подняли CS.

Коллеги! Огромная благодарность всем, кто принял участие в обсуждении, особенно dimax, так как решение было за ним. Всё работает!