kostya_unix

Инициализация DS18B20

43 posts in this topic

kostya_unix    1

Здравствуйте форумчане. При изучении датчика DS18B20 и разбора протокола 1-wire столкнулся с такой проблемой. В функции инициализации ( в частности определения присутствия  датчика на шине), при выставлении временных задержек (по даташиту: PORTC (к которому подключен вывод датчика DQ)  490 мкс импульс сброса (PORTC = 0),  переводим PORTC на вход, ожидаем 68 мкс для того, что бы шина успела подтянутся к 1 (через сопротивление 4,7 кОм, "ловим" импульс присутствия датчика, т.е. он должен "просадить" шину в ноль. И эту просадку (ноль) должна зафиксировать ранее созданная переменная для последующей обработки (присутствует датчик или нет.

Собственно с этого вопросы и начались. Если все установлено как пишется в уроках ( потенциал сопротивления между плюсом о шиной данных датчика 4,7 кОм,  временные интервалы тайм пласта инициализации (по даташиту), то переменная не фиксирует ответ (просадку к 0) от датчика, НО если увеличить сопротивление с 4,7 кОм до 6,8 кОм и вместо ожидания 68 мкс установить ассемблеровскую вставку NOP, тогда датчик определяется (отвечает просадкой к 0) и программно датчик виден (если вывод DQ на "горячую" вынуть из макетной платы, в программе срабатывает условие if(); 

В чем причина такого никак не могу взять в толк. Работаю в AVR_studio на C, м.к. ATmega 16, грешил на неисправность датчика, но потом купил второй такой же(предварительно проверив его на исправность в магазине).

Буду признателен за помощь и конструктивную критику.

PS: прошелся по все 30 страницам заголовков форума, именно про такую проблему так и не нашел.

Это код функции инициализации:

  

unsigned char OK_Flag;

void DS18B20_init(void)
{ 
    DDRB |= (1<<PB0);    // просадили шину на 0
    PORTB &= ~(1<<PB0);
       
    _delay_ms(500);
    
    PORTB &= ~(1<<PB0);
    DDRB &= ~(1<<PB0); // 0 перевели порт на вход для приема сигнала с датчика
    
    //_delay_us(68); //делаем задержку для "подъема" логической еденицы(через сопротивление)
    
    asm volatile ("nop");
 
    OK_Flag = (PINB &(1<<PB0));
    
    _delay_us(422);
   
    return OK_Flag; //возвращаем значение переменно в программу
    
}

int main(void)
{
    set_port_led();

    while(1)
    {
       DS18B20_init();
        if (!(OK_Flag == 0))
        { 
          PORTA &= ~(1<<PA0); //если датчик отвечает(исправен),зеленый свет выключен. 
        }
          else
            { 
              PORTA |= (1<<PA0);
            }
        
    }
}

 

Share this post


Link to post
Share on other sites
kostya_unix    1
7 часов назад, snn_krs сказал:

Может быть микросекунд ?

Да. Спасибо. Исправил (_delay_us(68);). Но пока все по прежнему. Сегодня постараюсь приобрести новый м.к и заменить. Может в порыве вдохновения подпалил подтягивающие сопротивления внутри него....

Share this post


Link to post
Share on other sites

Приглашаем на вебинар «Создание беспроводных устройств на системах-на-кристалле семейства SimpleLink компании TI»

Компания Компэл, совместно с Texas Instruments приглашают 26 июня принять участие в вебинаре, где инженер по применению беспроводных технологий компании TI расскажет, как на новых беспроводных системах можно реализовать несколько полезнейших в повседневной жизни функций для ваших устройств. С развитием элементной базы TI становится возможной реализация более удобных, функциональных и безопасных систем, недоступных ранее. Вебинар проводит инженер по применению беспроводных технологий в TI Мари Хернес(будет дублированный перевод).

Подробнее...

kostya_unix    1

Еще раз всем здравствуйте.

Продолжаю бороться с инициализацией DS18B20.

Купил вчера два новых м.к. ATmega16 и ATmega8. Пробовал как один так и другой и все безрезультатно. Верней не то, что бы совсем безрезультатно (так же как описывал проблему в самом начале( при _delay_us(68); не видит датчик, а если использую asm volatile ("nop"); тогда датчик определяется)).

Пробовал на частотах от 1 до 8 мГц. Питание подвал как от блока питания, так и непосредственно с USB_программатора.

Осталось попробовать ECLIPSE под Linux, может, что то с AVRStudio?  Не могу никак взять в толк......

Share this post


Link to post
Share on other sites
Alex    590

Код покажите. Трудно помочь, ориентируясь на одни лишь догадки.

Share this post


Link to post
Share on other sites

Видео вебинара «Уникальный подход MORNSUN к разработке DC/DC-преобразователей. Что на выходе?»

На сайте КОМПЭЛ доступны материалы вебинара, посвященные последнему поколению DC/DC преобразователей с фиксированным входом R3 от MORNSUN. Вы можете посмотреть видеозапись, ознакомиться с презентацией и ответами на вопросы.

Подробнее...

IMXO    1498

зачем это

Цитата

void DS18B20_init(void)
{
....
....
return OK_Flag; //возвращаем значение переменно в программу    
}

????

Цитата

Функция типа void

применение ключевого слова void является явное объявление функций, которые не возвращают значений.  такие функции не могут применяться в выражениях, и указание ключевого слова void предотвращает их случайное использование не по назначению.

 

Share this post


Link to post
Share on other sites
kostya_unix    1

Спасибо всем за участие.

Вот код программы (функцию немного изменил ( для чистоты эксперимента)).

#define F_CPU 8000000UL  // указываем частоту
#include <avr/io.h>
#include <util/delay.h>

void set_port_led(void)
{  
	DDRD = 0b00000001;
	PORTD =0b00000000;
	
}

void DS18B20_init(void)
{ 
   	DDRC |= (1<<PC0);    // просадили шину на 0
	PORTC &= ~(1<<PC0);
			
	_delay_us(490); // время просадки на 0
		
	
	DDRC &= ~(1<<PC0); // 0 перевели порт на вход для приема сигнала с датчика
  	
	//_delay_us(68); //делаем задержку для "подъема" логической еденицы(через сопротивление)
	               //и ожидаем сигнал присутствия датчика (датчик просаживает на 0 шину
				   //данных.
	
	asm volatile ("nop");
		
	if (!(PINC &(1<<PC0)) == 0) // если не равен нулю
	{
      PORTD |= (1<<PD0); //красный светодиод горит (датчик отсутствует)
	   } 
	     else
	       {
             PORTD &= ~(1<<PD0); //не горит
	           }
		
	_delay_us(422);
		
}

int main(void)
{
	set_port_led();
		
    while(1)
    {
		DS18B20_init();
					
    }
}

 

Share this post


Link to post
Share on other sites
Armenn    229
On ‎19‎.‎02‎.‎2019 at 9:49 AM, kostya_unix said:

для того, что бы шина успела подтянутся к 1

По скольким проводам подключаете датчик? Два или три?

Share this post


Link to post
Share on other sites
kostya_unix    1
Только что, Armenn сказал:

По скольким проводам подключаете датчик? Два или три?

По трем проводам. Красный на плюс, черный минус, желтый передача данных (подтянут через сопротивление к питанию). Датчик в герметичном корпусе.

Share this post


Link to post
Share on other sites
kostya_unix    1
41 минуту назад, Armenn сказал:

Без сопротивления 4,7к что происходит?

Здравствуйте Armenn. Спасибо за соучастие в решении моей проблемы! 

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

НО в моих  попытках докопаться до истины, появились сдвиги. 

Как и писал ранее, переписал код инициализации датчика в eclipse, и все заработало так как и должно. И с сопротивлением 4,7к и с "правильным" использованием _delay_us(); (asm "nop" не использовал). Вот как то так.....

Сейчас пытаюсь понять почему в AVR_studio прошивка не работала так как надо (может быть оптимизация кода в studio имеет место быть?).

Буду дальше изучать как DS18D20, так и протокол 1-wire.

Еще раз спасибо большое всем, кто помогал мне.

Edited by kostya_unix

Share this post


Link to post
Share on other sites
kostya_unix    1

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

Итак вот что узнал.....

Т.к. все подключенные к шине устройства имеют выходы с открытым стоком,  то для формирования логической 1 на шине используется подтягивающее сопротивление (4,7 кОм)

Для инициализации всех подключенных ведомых устройств (датчиков), м.к. сначала формирует импульс сброса, логический ноль на шине данных, не менее 480 мкс, для того что бы после формирования положительного перепада датчики смогли ответить импульсом присутствия.

После импульса сброса от м.к. временем нарастания единицы можно пренебречь (1 мкс.) в моем коде это было ошибочно обозначено как:  _delay_us(68); //делаем задержку для "подъема" логической единицы(через сопротивление) и ожидаем сигнал присутствия датчика (датчик просаживает на 0 шину данных).

Когда датчик определил положительный перепад (от ноля к единице), он ожидает от 15 до 60 мкс и затем формирует импульс присутствия устанавливая на шине данных логический ноль на время от 60 до 240 мкс.

Так что импульс присутствия может начаться, самое позднее через 60 мкс от завершения импульса сброса и может закончится, самое ранее, через (15+60) = 75 мкс от завершения импульса сброса м.к.

Для считывания импульса присутствия от датчика, выбираем среднее значение (60~70) = 68 мкс.

Общее время импульса присутствия датчика не менее 480 мкс (68 мкс+412 мкс)  

Share this post


Link to post
Share on other sites
kostya_unix    1

Всем здравствуйте. На днях вывел первые показания температуры с DS18B20 на LED_индикатор (пока правда без знака + или -). Долго шел к этому результату, не забрасывал изучение. Советовался только с вами форумчанами (больше нескем было). Спасибо большое всем кто помогал, кто участвовал в обсуждении моего вопроса.

По возможности буду и дальше информировать о дальнейшем ходе изучения. Продолжение будет в изучении определения знака температуры., считывания ROM кода датчика( с выводом на дисплей) ну и так далее.

Share this post


Link to post
Share on other sites
kostya_unix    1

Здравствуйте всем. Вчера разобрался с расчетом отрицательной температуры..... Это окажется полезным особенно начинающим в разборе этих расчетах. 

И так..... Для начинающих (как я) формулы в примерах не всегда понятны (хотя работают на 100%), по причине несовершенного владения битовыми сдвигами.

И что бы было более понятно и наглядно:

T_L = dt_readbyte(); // считываем младшие 8 бит ( из 16 передаваемых датчиком значений температуры)

T_H = dt_readbyte(): // считываем старшие 8 бит.

для положительной температуры:   temperatura = (((T_H<<8) | T_L) / 16) ;

для отрицательной температуры:    temperatura = ((65536 - temperatura)/16); // 65536 это максимально возможное значение 16 бит информации с датчика, и из этого                                                                                                                                                                // максимального значения мы вычитаем реальные значения датчика в промежуток времени.

Пример: с датчика в момент времени мы получили значение (при условии, что мы определили знак температуры ( if (!((T_H & 128) ==0)); т.е. температура отрицательная)

FECCh и если перевести в десятичное значение: 65228, тогда при этом решении (65536 - 65228) мы получаем 308 и разделив его на 16 (т.е сдвинув в право на 4 (>>4) , мы и получаем искомое значение отрицательной температуры.

Ну вот как то так......

Если что-то не так в моем комментарии прошу более опытных пользователей меня поправить. Думаю, что от этого выиграют все. 

Share this post


Link to post
Share on other sites
ARV    762
Posted (edited)

В вашем подходе много чего не так. Есть вещи несущественные, а есть принципиальные. Код не показан целиком, так что частично буду гадать.

1. Побайтное чтение температуры настораживает: разве вы не считываете все 9 байтов scratchpad-ОЗУ датчика? Разве вы не считаете CRC этих 9-и байт?

2. Метод станных манипуляций с байтами (сдвиги и т.п.) совершенно лишний: датчик выдает температуру в формате int16_t, т.е. 16-битное целочисленное значение в долях градуса. А вот величина доли зависит от режима работы датчика, и в 12-битном варианте составляет 1/16 градуса. То есть считанные 2 байта представляют собой обычное число int, которое надо разделить на 16, чтобы получить температуру сразу со знаком в градусах. Только делать это можно лишь в случае, если CRC всех 9 байтов встроенной блокнотной памяти корректна.

Edited by ARV

Share this post


Link to post
Share on other sites
kostya_unix    1
22 часа назад, ARV сказал:

В вашем подходе много чего не так. Есть вещи несущественные, а есть принципиальные. Код не показан целиком, так что частично буду гадать.

1. Побайтное чтение температуры настораживает: разве вы не считываете все 9 байтов scratchpad-ОЗУ датчика? Разве вы не считаете CRC этих 9-и байт?

2. Метод станных манипуляций с байтами (сдвиги и т.п.) совершенно лишний: датчик выдает температуру в формате int16_t, т.е. 16-битное целочисленное значение в долях градуса. А вот величина доли зависит от режима работы датчика, и в 12-битном варианте составляет 1/16 градуса. То есть считанные 2 байта представляют собой обычное число int, которое надо разделить на 16, чтобы получить температуру сразу со знаком в градусах. Только делать это можно лишь в случае, если CRC всех 9 байтов встроенной блокнотной памяти корректна.

Вы знаете, я еще не очень хорошо разбираюсь во всех командах датчика ( изучаю самостоятельно). Датчик у меня один. Я подаю команду на преобразование температуры (0x44). Собственно с этими данными и работаю. Если Вас не затруднит, подскажите пожалуйста как считать все 9 байт с датчика. Я так понимаю, что без массива тут не обойтись? Заранее благодарен.

Привожу функцию с помощью которой общаюсь с датчиком.

 

signed int dt_check(void)
{
		DS18B20_reset();  // презагружаем (сброс\присутствие) датчик.
		  			  
		dt_sendbyte(204); // (0xCC) (skip rom) пропускаем идентификацию, т.к. датчик один
		dt_sendbyte(68); // (0x44) измерить температуру
		
		_delay_ms(750);    // такая задержка нужна для 12-ти битного ПРЕОБРАЗОВАНИЯ (это максимальная задержка)
				
		DS18B20_reset();   // презагружаем (сброс\присутствие) датчик. Инициализация нужна для того, что бы
		                   // датчик понял, что ему сейчас будет послана команда.
		
		dt_sendbyte(204); // (0xCC) (skip rom) пропускаем идентификацию 
		dt_sendbyte(190); // (0xBE) (convert t) отправляем команду на чтение показаний с датчика
		
		T_L = dt_readbyte(); // читаем младший байт регистра температуры
		T_H = dt_readbyte(); // читаем старший байт регистра температуры
		
		tt = (((T_H<<8)|T_L)*10); // общий результат полученого значения (кода) с датчика
	
		// вывод знака при положительной и отрецательной температуре
		    if ((T_H & 128) ==0)
		    {
				// положительная температура
				znack = 32;// знак пробел при положительной температуре
			} 
		    else
            { // отрицательная температура
				tt = (65536-tt); // формула расчета отрицательной температуры
				znack = 45;// знак минус
							
		    }
					
	return tt;
}

 

Share this post


Link to post
Share on other sites
ARV    762
2 часа назад, kostya_unix сказал:

как считать все 9 байт с датчика

Да как угодно. Размется, с массивом удобно: сделал цикл с чтением в массив, и все. Но можно и без массива (аж 9 байт ОЗУ скономите) - так, как вы, байт а байтом читать разными командами. Но это не красиво...

Share this post


Link to post
Share on other sites
Starichok    1423
8 часов назад, ARV сказал:

Но можно и без массива (аж 9 байт ОЗУ скономите)

а массив, по-твоему, занимает НОЛЬ байт?

Share this post


Link to post
Share on other sites
Alex    590

Дак и речь то об том, что БЕЗ МАССИВА сэкономят.

PS: @Starichok , что то ты сдавать стал :)

Share this post


Link to post
Share on other sites
ARV    762

@Starichok, своих надо знать в лицо :) я на таких простых темах никогда не ошибаюсь.

Share this post


Link to post
Share on other sites
Starichok    1423

видимо, ночью я неправильно понял смысл сказанного...

но что-то и с утра мне плохо соображается.

если без массива, то куда будут помещены прочитанные 9 байт? в чем тут экономия?

зы. вчера довелось быть на дне рождения. может, поэтому плохо соображается...

Share this post


Link to post
Share on other sites
kostya_unix    1
1 час назад, Starichok сказал:

видимо, ночью я неправильно понял смысл сказанного...

но что-то и с утра мне плохо соображается.

если без массива, то куда будут помещены прочитанные 9 байт? в чем тут экономия?

зы. вчера довелось быть на дне рождения. может, поэтому плохо соображается...

Здоровья вам (после вчерашнего).

Share this post


Link to post
Share on other sites
kostya_unix    1

Большое спасибо всем, кто участвует в решении моего вопроса.

Сразу оговорюсь, что изучаю микроконтроллеры самостоятельно, не имея предварительных навыков программирования, но имея много "прыти" и желания.

У меня вопрос возник (как во время чтения даташит_а на датчик, так и во время просмотров кодов работы с датчиком на сайтах)....

В даташит_е есть такие строки:

Если DS18B20 включен с внешним питанием, ведущий может контролировать конвертирование температуры (после команды [0х44]) по состоянию шины. На шине будет присутствовать логический «0» когда происходит температурное преобразование. И логическая «1», когда конвертирование выполнено.

 То есть, можно ли пренебречь паузой в _delay_ms(750); (так как по умолчанию разрядность выставлена в 12 бит) и пользоваться только проверкой завершения конвертации?

Share this post


Link to post
Share on other sites
Starichok    1423

дело в том, что при отработке паузы с помощью _delay_ms(750) МК больше НИЧЕГО в это время делать не может. это пустая трата процессорного времени.

точнее, МК во время отработки паузы может обрабатывать прерывания.

можно делать такую проверку. а можно и не делать.

например, у меня полный приборный цикл равен 1 секунде. но я точно знаю (и ты это знаешь), что 1 секунду преобразование температуры гарантированно закончится.

поэтому я без проверки считываю новую температуру и запускаю новую конвертацию.

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

вариантов тут несколько.

1. тупо делать задержку с помощью delay.

2. тупо сидеть в цикле и по кругу проверять на завершение конвертации. этот вариант потребует те же самые 700-750 мс бесполезной потери времени.

3. делать, как я - 1 раз в секунду без проверки считывать новую температуру и запускать новую конвертацию.

может, чья-то фантазия придумает еще другие способы...

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Сообщения

    • что касается цифр. я всего лишь озвучил показания мультиметра. а что касается "набора текста",поясняю, не понятна причина колебаний  постоянного напряжения на выходе усилителя  и насколько это критично  
    • У меня тоже так в одном канале. Звона нет. Напряжение правда меньше где-то 60-100 мв. С подбором полевиков не заморачивался оставил так. Может ему интегратор добавить и не думать о напряжении на выходе. 
    • да ладно,все норм будет - ты же знаешь)) не пришли еще мс , да и нет смысла для софтбокса делать его дороже. 
    • Доброго времени суток. В процессе экспериментов с лампочками возник такой вот вопрос. Практикуется ли использование двойных триодов для построения двух последовательных каскадов ? На первый взгляд, имеется некоторая межанодная ёмкость, а т.к. каскады работают в противофазе, то получится, что-то наподобие эффекта миллера.
    • НОВЫЙ ВЫПУСК ЖУРНАЛА ДЛЯ РАЗРАБОТЧИКОВ "НОВОСТИ ЭЛЕКТРОНИКИ" №6'19 В шестом номере «Новостей электроники» - об обработке, передаче и защите сигнала в промышленных, лабораторных и бытовых системах Индустрии 4.0 и интернета вещей ( IoT ). Микросхемы цифрового входа; система на кристалле для обработки биомедицинских сигналов; статья о TBU – защитных устройствах для линий питания. Во второй части номера, посвященной преобразованию питания - о преимуществах модульных DC / DC над дискретными решениями, о применении алюминиевых электролитических конденсаторов, о гетероструктурных HEMT -транзисторах.

      Содержание номера:
      1. Статья "Промышленные цифровые входы и выходы. Руководство по проектированию. Часть 1. Цифровые входы".
      Цифровые входы в промышленных модулях входов/выходов необходимы для приема сигналов от дискретных датчиков или переключателей, используемых в промышленном производстве. В статье рассказано об одноканальной и многоканальных ИС цифрового входа производства Maxim. Подробнее>>
      2. Статья "Страж дверей и окон: сенсорный узел с батарейным питанием и возможностью беспроводной передачи данных".
      Батарейка ААА, сверхмаломощный повышающий преобразователь, цифровые датчики на основе эффекта Холла - три основные составляющие части типовой разработки Texas Instruments для систем безопасности жилых зданий и производственных помещений. Подробнее>>
      3. Статья "MAX30003 – персональный кардиолог от Maxim".
      Компания Maxim Integrated представила MAX30003 – аналоговую одноканальную малопотребляющую ИС, разработанную специально для измерения биоэлектрических потенциалов в портативных приложениях. Подробнее>>
      4. Статья "TBU от Bourns – уникальная защита для современной аппаратуры связи".
      Модули блокировки переходных процессов (TBU) производства Bourns разъединяют цепь нагрузки за время порядка 1 мкс и включаются последовательно с нагрузкой после элемента первичной защиты. Подробнее>>
      5. Статья "Всегда ли выгодна схема DC/DC-преобразователя на дискретных компонентах?".
      Статья рассказывает о преимуществе интегрального решения DC / DC над дискретным на примере сравнения дискретной двухтактной схемы с самовозбуждением и модульных DC/DC-преобразователей поколения R3 компании Mornsun. Подробнее>>
      6. Статья "Конденсаторы Panasonic. Часть 1. Алюминий". 
      Статья рассматривает номенклатуру алюминиевых электролитов известнейшей компании Panasonic. Подробнее>>
      7. Статья "Снизить потери энергии: гетероструктурные полевые транзисторы CoolGaN™ от Infineon".
      Применение гетероструктурных полевых транзисторов (HFET) CoolGaN™ от Infineon позволяет достичь КПД преобразователей в 99% и плотности энергии 24 Вт/дюйм 3 для выпрямителей и 160 Вт/дюйм 3 для резонансных LLC-преобразователей. Подробнее>>

      БЛОК РЕДАКЦИЯ РЕКОМЕНДУЕТ:
      Опорное решение: компоненты для защиты RS-485
      Компания Bourns анонсировала новую (4-ю) версию демонстрационной платы для тестирования защиты низковольтных слаботочных цепей от токовых перегрузок и импульсных перенапряжений, в частности, для защиты интерфейса RS-485.
      R3 – новое поколение DC/DC-преобразователей Mornsun: параметры выше – стоимость ниже
      При разработке изделий электронной техники порой возникает ситуация, когда часть схемы или какие-то отдельные компоненты требуют дополнительного напряжения, не имеющего с основным питанием гальванической связи. Характерный пример: питание микросхем оптоизолированных интерфейсов. Также часто требуется получение дополнительных уровней напряжения, отличающихся от основного питания, например, получение из однополярного напряжения биполярного для операционных усилителей. Для решения этих задач разработчики в большинстве случаев применяют...
      Вебинар «Создание беспроводных устройств на системах-на-кристалле семейства SimpleLink компании TI»
      Компания Компэл, совместно с Texas Instruments приглашают 26 июня принять участие в вебинаре, где инженер по применению беспроводных технологий компании TI расскажет, как на новых беспроводных системах можно реализовать несколько полезнейших в повседневной жизни функций для ваших устройств. Вебинар проводит инженер по применению беспроводных технологий в TI Мари Хернес(будет дублированный перевод).
      Литиевые батарейки Fanso для промышленного применения: устойчивость к высоким температурам.
      Надежные литиевые ХИТ производства Fanso для широкого круга применений соответствуют требованиям современного рынка и способны работать в самых жестких условиях. ЛХИТ превосходят по плотности энергии и номинальному напряжению другие элементы автономного питания: 2,9…3,6 В против 1,2…1,5 В.

       
    • Игорь, теперь на этом хочешь шишек набить? У Китафончика в теме ИИП на нормальном ШИМ- контроллере. Зачем тебе это недоразумение?