Запустил ЦАП на Atmega32, но не простой, а работающий в троичной системе счисления (3бита 27ступенек, 4бита 81ступенька). Минусы- мощный ОУ с тремя дополнительнами резисторами, порядка 30мА общий ток весовых резисторов и их настройка, больше время установления, больше памяти и психологический фактор. Плюсы- меньше резисторов для одного бита, легкость сдвига уровня и регулировки коэффициента преобразования (у меня TDA2030, можно SSM2211S, последний даже с выключением). Для прямой загрузки DDR и PORT прогу помогли составить. Стабильно работает малоразрядный вариант. Для табличного метода памяти жалко. Проблема даже не в переводе двоички в троичку, а в циклах и вложениях и возможности наращивать разрядность. Нужна помощь в программировании, я только учусь, в одиночку будет ну очень долго. В итоге хотелось бы получить генератор трегольников, прямоугольников, синуса и шума. Предвижу вопрос по гармоникам на синусе и отвечаю, RC цепь в обратке ОУ превращает схему в интегратор со всеми вытекающими. На казусе в цап подробности. Спасибо.
не могу понять скрытый кайф происходящего... т.к. невозможно одновременно вести вывд в два разных порта ввода-вывода (DDR и PORT), то в момент смены значения такого ЦАП обязательно будут всплески приличной длительности. подбор резисторов для R-2R не прост, и тут ничем не проще. хранение и обработка "троичной" информации тоже представляет проблему как на уровне понимания, так и языка Си.
однако, вопрос автору: в чем, собственно, ваша проблема?
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
Вы правы, запись в DDR и PORT друг за другом, а не одновременно. Для хранения готовых значений действительно надо в 2 р больше места, поэтому я и обратился на форум, чтобы не хранить, а программно генерить. Всплески длительностью в один такт подавляются кондером в обратке ОУ. Работает, не работает, для меня как бы вопрос решенный. Проблем нет, если не считать то, что я недавно начал изучать программирование. Естественно сам я рано или поздно одолею эти циклы и вложения. Наверняка это будет в 100 раз дольше чем вместе с опытным программистом AVR. Если Вы в состоянии помочь, буду очень рад.
Компания MEAN WELL пополнила ассортимент своей широкой линейки светодиодных драйверов новым семейством XLC для внутреннего освещения. Главное отличие – поддержка широкого спектра проводных и беспроводных технологий диммирования. Новинки представлены в MEANWELL.market моделями с мощностями 25 Вт, 40 Вт и 60 Вт. В линейке есть модели, работающие как в режиме стабилизации тока (СС), так и в режиме стабилизации напряжения (CV) значением 12, 24 и 48 В.
Естественно сам я рано или поздно одолею эти циклы и вложения. Наверняка это будет в 100 раз дольше чем вместе с опытным программистом AVR. Если Вы в состоянии помочь, буду очень рад.
помочь-то я в состоянии (надеюсь), однако вы сформулируйте проблему вашу, ибо просто взять и написать за вас что-то я однозначно не способен
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
ARV, чтоб я Вам не написал лишнего и не обидел, напомню только, что мы будем колдовать вокруг троичной системы счисления и инвертирующего усилка на ОУ, превращаемого в интегратор заменой резистора обратки на кондер. И на всякий случай: моя самооцека как программиста- чуть выше плинтуса. Скажите, если Вам нужна готовая таблица 5в1 десятичка+троичка+двоичка+состояния пинов+состояния портов. У нас есть выбор. Первый. С резистором в обратке. Подобно R-2R методу одному состоянию пинов соответствует одно конкретное напряжение на выходе. Каждое новое значение надо программно генерить (либо брать из удвоенной таблицы). Для ступенчато уменьшающегося напряжения надо организовать цикл 0-1-2 младшего разряда внутри такого же цикла следующего разряда, который тоже внутри следующего и т.д. Если троичка перед Вами то там видно, каждый разряд постарше моргает в три раза медленнее ближайшего помладше. Сами циклы пишем на 8 переменных с тремя возможными значениями 0-1-2. Эти с Нулевой по Седьмую переменные после каждого изменения ныряют в подпрограмму которая в Восьмой и Девятой переменных готовит значения для записи в DDR и PORT соответственно. С Нулевой по Седьмую переменные закреплены каждая за соответствующим разрядом (пином) и соответствующими битами в Восьмой и Девятой переменных. Подпрограмма: -при значении переменной=0 присваивает пину направление=вывод и значение=0(DDR в 1, PORT в 0), но не пишет сразу а сохраняет в Восьмой переменной для DDR и в Девятой для PORT, в битах соответствующих переменным с Нулевой по Седьмую. -при значении переменной=1 присваивает пину направление-ввод и значение=0(DDR в 0, PORT в 0), но не пишет сразу а сохраняет в Восьмой переменной для DDR и в Девятой для PORT, в битах соответствующих переменным с Нулевой по Седьмую. -при значении переменной=2 присваивает пину направление-вывод и значение=1(DDR в 1, PORT в 1), но не пишет сразу а сохраняет в Восьмой переменной для DDR и в Девятой для PORT, в битах соответствующих переменным с Нулевой по Седьмую. Теперь временной интервал. По истечении пишем из Восьмой переменной в DDR, а из Девятой переменной в PORT. Почти так же просто как двоичный счетчик считающий в плюс, только в троичке.
Второй. Более перспективный метод с кондером в обратке ОУ. Как в любом накопителе надо следить за переполнением или опустошением, т.е. используем большую петлю обратной связи. За то огромный выигрыш в линейности. Выставили пинами нужную скорость и ждем когдаааааааа конденсатор зарядится до сработки компаратора. А как клацнет выставляем отрицательную скорость, т.е. разряжаем. Тут надо решить, либо по быстрому неконтролируемый но гарантированный разряд максимальным током, либо сразу завязаться на АЦП, либо второй уровень сработки компаратора городить, либо еще проще отдаться простому входному гистерезису. В самом крутом варианте с АЦП легче генерировать синус, экспоненту, успевай только скорости менять, но не будет почти мгновенного изменения, как без интегрирующего кондера.
Первый вариант подробнее продумал, кроме побитных операций. На второй еще надо время (линейное изменение во втором варианте я считаю у нас с Вами уже есть).
Последний раз редактировалось majorka65 Пт апр 30, 2010 14:22:38, всего редактировалось 1 раз.
че-то я вас не очень понял: когда вижу много букафф, у меня пропадает желание их читать
я наивно полагал себе, что надо сделать всего-навсего функцию, которая будет поразрядно переводить число в троичную систему самым простым способом и затем для каждого из разрядов формировать пару битов для управления регистрами DDR и PORT. вы написали что-то страшное, вникать во что я даже опасаюсь...
Код:
void convert(unsigned char d){ unsigned char ddr=0, port=0; // это то, что будете выводится в регистры порта ЦАП unsigned char tribit; // это значение одного "троичного разряда" числа unsigned char mask = 1; // это маска для управления пинами порта
// преобразование в троичную систему ведем тупым, но простым и понятным способом while(d > 0){ tribit = d % 3; // находим очередной троичный разряд d /= 3; // исходное число уменьшаем в 3 раза, т.е. готовим более старшие разряды switch(tribit){ case 1: // если разряд == 1, то и ddr и port равны 0 break; case 2: port |= mask; // если разряд == 2, то в port устанавливаем единичку // а затем и ddr тоже в единичку, как при tribit == 0 case 0: ddr |= mask; // если разряд == 0, то d ddr устанавливаем единичку } mask <<= 1; // переходим к следующему разряду ЦАП } // выводим в регистры подготовленные значения PORTB = port; DDRB = ddr; }
если я нигде не ошибся в уровнях вашего троичного ЦАП, то теперь с помощью этой функции вы можете формировать какие угодно сигналы, например, вот треугольная пила:
вам остается адаптировать эту функцию для себя: обеспечить корректную обработку входных значений для преобразования, т.к. я не предусматривал случая, когда выводится число 255, для которого ваших троичных разрядов не хватает ну, еще можно помозговать над алгоритмом перевода в троичную систему - деление слишком ресурсоемкая операция, я применил ее лишь потому, что алгоритм при этом весьма нагляден
в общем, остальное уж вы сами доделайте - я ведь всего лишь помогаю вам...
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
switch(tribit){ case 1: // если разряд == 1, вход в Z состояние port &=(~mask); ddr &=(~mask); break; case 2: // если разряд == 2, то выводим единичку port |= mask; ddr |= mask; break; case 0: // если разряд == 0, то выводим ноль port &=(~mask); ddr |= mask; break; }
вы поняли меня неправильно! функцию, которая выводит на резисторы вашего ЦАП я уже сделал - не надо больше никакой самодеятельности! что вам надо сделать самостоятельно, я тоже написал. попробуйте вникнуть в написанное и улучшить его. но портить-то зачем?!
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
Генератор синуса без ступенек stepless sinus generator, sin wave generator. Тот же 4bit 81step ternary DAC, но вместо резистора в обратке ОУ конденсатор (получился интегратор).
уважаемый, ну что же вы так... надо хоть немножко о языке Си почитать, что ли... и еще совет: бросьте вы использовать этот мастер кода CVAVR, пишите руками сами... иначе так и не научитесь понимать, что происходит.
вот что у вас должно быть (сравните с тем, что есть и найдите три отличия):
Код:
#include <mega32.h> #include <delay.h>
static void convert(unsigned char d){ unsigned char ddr=0, port=0; // это то, что будете выводится в регистры порта ЦАП unsigned char tribit; // это значение одного "троичного разряда" числа unsigned char mask = 1; // это маска для управления пинами порта
// преобразование в троичную систему ведем тупым, но простым и понятным способом while(d > 0){ tribit = d % 3; // находим очередной троичный разряд d /= 3; // исходное число уменьшаем в 3 раза, т.е. готовим более старшие разряды switch(tribit){ case 1: // если разряд == 1, то и ddr и port равны 0 break; case 2: port |= mask; // если разряд == 2, то в port устанавливаем единичку // а затем и ddr тоже в единичку, как при tribit == 0 case 0: ddr |= mask; // если разряд == 0, то d ddr устанавливаем единичку } mask <<= 1; // переходим к следующему разряду ЦАП } // выводим в регистры подготовленные значения PORTB = port; DDRB = ddr; }
void main(void){ unsigned char i;
while (1){ for(i=1; i<240; i++){ delay_us(100); convert(i); } for(i=240; i > 0; i--){ delay_us(100); convert(i); } } }
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
Мне очень стыдно просить попить, чтобы поесть, чтобы переночевать. Я, правда, пытаюсь понять. Хочу просить Вашего, ARV, разрешения воложить под Вашим ником Ваше произведение на форуме kazus, с любыми Вашими условиями и оговорками.
Прога от ARV заработала в проте. Что-то я неправильно сделал, вместо одной восходящей и одной нисходящей несколько неравных восходящих частей и симметрично вершинам столько же неравных вниз. Само преобразование двоички в троичку выполняется правильно.
Хочу просить Вашего, ARV, разрешения воложить под Вашим ником Ваше произведение на форуме kazus, с любыми Вашими условиями и оговорками.
под моим ником ничего выкладывать не надо! можете выкладывать все, что угодно под своим ником. можете, если хотите, сослаться на эту тему (правила интернет-вежливости подразумевают указание ссылки на первоисточник) или на меня - но от своего имени
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 13
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения