Управление оптронами на частоте 2МГц

MuckS
MuckS аватар
Offline
Зарегистрирован: 13.04.2015

Добрового времени суток, друзья!

Я пытаюсь управлять двумя транзисторами, меняющими полярность через 2 оптрона. Но никак не могу разобраться как заставить digitalWrite мне в этом помочь.

Вот код:

int redPin = 13;                  // оптрон прямой полярности на выводе 13
int greenPin = 12;                // оптрон обратной полярности на выводе 12

void setup()                      // запускается один раз при старте скетча
{
  pinMode(redPin, OUTPUT);        // вывод 13 в режиме вывода
  pinMode(greenPin, OUTPUT);      // вывод 12 в режиме вывода
  }

void loop()                       // повторяется постоянно
{
  digitalWrite(redPin, HIGH);     // включаем прямую полярность
  delayMicroseconds(10);                       // пауза
  digitalWrite(redPin, LOW);
  digitalWrite(greenPin, HIGH);   // включаем обратную полярность
  delayMicroseconds(10);                       // пауза
  digitalWrite(greenPin, LOW);
}

Он работае нормально, но минимальное значение для delayMicroseconds = 1 (Это 1 МГЦ), а мне нужно, чтобы выводы открывались последовательно с частотой 2МГц.

Есть дельные мысли как это реализовать?

 

nikolaki
nikolaki аватар
Offline
Зарегистрирован: 14.02.2013
MuckS
MuckS аватар
Offline
Зарегистрирован: 13.04.2015

Извиняй-) Код не большой-) А отредактировать никак-(

Datak
Offline
Зарегистрирован: 09.10.2014

MuckS пишет:

минимальное значение для delayMicroseconds = 1 (Это 1 МГЦ), а мне нужно, чтобы выводы открывались последовательно с частотой 2МГц.

Что-то мне подсказывает, что 2МГц не получится, даже если delayMicroseconds убрать совсем.
digitalWrite - достаточно медленная функция.

Для программного переключения с такой частотой придётся напрямую писать в выходные порты ардуины.

Но правильней, наверное, использовать программно-аппаратный способ - генерировать частоту с помощью одного из ардуиновсуих таймеров.

Подробнее, конечно, можно советовать только зная какие-то подробности решаемой задачи. :)

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

попробуй

#define red   12
#define green 13

void setup(){
  pinMode(red, OUTPUT);
  pinMode(green, OUTPUT);
  
}

void loop(){
  dWrite(red, 1);
  dWrite(red, 0);
  dWrite(green, 1);
  dWrite(green, 0);
}



void dWrite(byte pin, byte val){
  byte bit = digitalPinToBitMask(pin);
  volatile byte *out;
  out = portOutputRegister(digitalPinToPort(pin));
  (val)? *out |= bit : *out &=~bit;
}

кстати какой оптрон?

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

jeka_tm, вы ж вроде не первый год ардуините?  2МГц  это не шутки, -это всего  8 тактов процессора. Программно невозможно с такой скоростью дёргать ногами.  Единственный вариант -это аппаратный таймер, который будет дёргать своей аппаратной ногой. Но  будет проблема дёргать ногами инверсно.

MuckS, нафига вам 2 МГц?

maksim
Offline
Зарегистрирован: 12.02.2012

MuckS пишет:

минимальное значение для delayMicroseconds = 1 (Это 1 МГЦ), а мне нужно, чтобы выводы открывались последовательно с частотой 2МГц.

Вы бы определились для начала какая частота сигнала вам нужна. 

void loop()
{
  digitalWrite(redPin, HIGH);    
  delayMicroseconds(1);
  digitalWrite(redPin, LOW);
  delayMicroseconds(1);
}

в этом случае при delayMicroseconds(1) "теоретическая" (гипотетичекская) частота будут не 1 МГц, а 500 кГц.

jeka_tm пишет:

попробуй

Так вы получите неизвестную и нестабильную частоту.

Такие частоты только на таймере:

void setup() 
{
  pinMode(11, OUTPUT);
  TCCR2A = (1<<WGM21)|(1<<COM2A0);
  TCCR2B = 1<<CS20;
  OCR2A = 2; // 0 - 8МГц, 1 - 4МГц, 2 - 2МГц, 3 - 1МГц, и т.д.
  TIMSK2 = 0;
}

void loop() {
}

Актуально для UNOподобных плат (Atmega88/168/328).
Оптроны подключите к 11 выводу, аналогично диодам на картинке:


 

 

 

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

а мне было просто интересно какая частота получится

к чему такая несерьезность? а вот к чему. я не зря спросил какая оптопара. далеко не каждая сможет с такой частотой работать

например самый распрастраненный PC817/ смотреть последние 2 строчки

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

и еще. я в таймерах нифига не разбираюсь))

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

jeka_tm, а я сам недавно "победил" таймеры.. Раньше всё с завистью смотрел, как Maksim и некоторые другие наши коллеги по форуму с лёгкостью оперируют этими странными регистрами)) И решил, что хватит, пора браться за ум. За пару выходных понял как с ними общаться, сейчас вот активно всем помогаю на них что-то делать -тем самым набираюсь опыта использования )

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

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

 

Datak
Offline
Зарегистрирован: 09.10.2014

dimax пишет:

Программно невозможно с такой скоростью дёргать ногами.

Не, если постараться, то можно. :)



   pinMode( 13, OUTPUT );

   asm( "cli        " );
   asm( "1:         " );
   asm( "sbi 0x05, 5" );
   asm( "nop        " );
   asm( "nop        " );
   asm( "cbi 0x05, 5" );
   asm( "rjmp     1b" );

Вот, 2Мгц на 13 ноге, программно.

Но практически, конечно, никакого смысла в этом нет - ардуина ничем другим заниматься уже не сможет. 

Puhlyaviy
Puhlyaviy аватар
Offline
Зарегистрирован: 22.05.2013

jeka_tm пишет:

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

 


http://playground.arduino.cc/Main/TimerPWMCheatsheet

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

jeka_tm пишет:

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

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

void setup() 
{
  pinMode(11, OUTPUT); 
// назначаем выход, и судя по тому, что никто в скетче этот выход не использует
//делаем вывод, что сигнал будем с ноги 8-битного таймера2 OC2A  
  
  TCCR2A = (1<<WGM21)|(1<<COM2A0);
//155 страница даташита. Первая команда задаёт режим таймера "Сброс по совпадаеню"
// (режим 2) Таймер досчитав до значения указанного в OCR2 сбросится в ноль,
// и начнёт снова считать. Вторая команда даташит стр.153 Таблица 18-2. Вывод OC2A "активируется "
// и инвертируется при достижении таймером значения, указанного в OCR2A
 TCCR2B = 1<<CS20;
 // стр.156 Табл 18-9  Делитель не используем, (=1)  таймер "заводится" на частоте контроллера
  OCR2A = 2; // 0 - 8МГц, 1 - 4МГц, 2 - 2МГц, 3 - 1МГц, и т.д.
 // о нём чуть позже
  TIMSK2 = 0;
// прерывание не используем  стр.157. По идее там и по дефолту ноль. Но перестраховка иногда спасает от глюков

}

void loop() {
}

И немного теории. Если не считать таймером ничего OCR2A=0, значит мы будет работать на частоте контроллера -16 мГц. Но на выходе будет не 16МГц, а 8. Потому, что одним тактом будет устанавливаться на выходе "1" а другим "0". Поэтому имеем максимальную частоту 8Мгц. Теперь самое иентересное, как рассчитывать частоту в зависимости от содержания регистра OCR2A. Это просто, но сразу нужно деать поправку, что в регистре счёт с ноля. А в уме все манипулируют счётом с "1".  Так вот OCR -это фактически делитель частоты.  Т.е. конечная частота = 16000000 /2 / OCR2A (при условии счёта с единицы) Из этого выводим формулу что-б считать с ноля автоматом  16000000/2 / (OCR2A+1)Итого имеем, при OCR2A=1 -4МГц, при OCR2A=2 -2,666666 мГц,при  OCR2A=3 -2мГц, OCR2A=4 -1,6мГц Формулу можно в ёксель вбить,но если используется прескалер (аппартаный делитель) то результат нужно ещё раз поделить на этот делитель)  Значит искомая ошибка была в том, что для 2Мгц нужно ocr2a=3

 

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

Datak, да, здорово, ассемблер компактый язык :)

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

))) ладно пока совсем не припрет видно не разберусь. частично вроде разобрался

MuckS
MuckS аватар
Offline
Зарегистрирован: 13.04.2015

Друзья! Большое спасибо за огромное количество полезной информации - осилю. Применю. Вы интересовались задачей - задача по сути представляет собой аппарат для УВЧ прогревания. 2МГц нужно для оптимального разогрева кожи в собственно дермальном слое. Именно с такой частотой должна сменияться полярность. Ещё раз спасибо. Отвечу что получилось-)

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

проще сделать генератор на лог. элементах)))

MuckS
MuckS аватар
Offline
Зарегистрирован: 13.04.2015

Это и вправду было бы проще, если бы не синхронизация-)

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

в смысле синхронизация? чтобы один выключился другой включился? если да это вообще не проблема. берется элемент с инвертором, например 2И-НЕ, на них и генератор и инвертор для второго транзистора делается

MuckS
MuckS аватар
Offline
Зарегистрирован: 13.04.2015

И всё стабильно даже при нагрзке в 1КОм?

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

сделай на кварце если частота настолько критичная. 1ком должен легко потянуть

так какой оптрон?

MuckS
MuckS аватар
Offline
Зарегистрирован: 13.04.2015

АОТ161а, но по ходу он точно не успевает.

// defines for setting and clearing register bits
#ifndef cbi
  #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
  #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

int redPin = 13;                  // оптрон прямой полярности на выводе 13
int greenPin = 12;                // оптрон обратной полярности на выводе 12

void setup()                      // запускается один раз при старте скетча
{
  pinMode(redPin, OUTPUT);        // вывод 13 в режиме вывода
  pinMode(greenPin, OUTPUT);      // вывод 12 в режиме вывода
}

void loop(){
  while (1) // avoid the overhead of having main go out to loop() every time
  {
    sbi(PORTB,5);       // Set pin 13
    delayMicroseconds(1);
    cbi(PORTB,5);       // Clear pin 13
    sbi(PORTB,4);       // Set pin 12
    delayMicroseconds(1);
    cbi(PORTB,4);       // Clear pin 12
  }
}

Вот такое соорудил, но это не пашет. пп крайней мре диодик вообще не светит-( даж без оптрона-)

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

ага не успевает))) 

что надеешь увидеть?

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

http://arduino.cc/en/Reference/DelayMicroseconds

Caveats and Known Issues

This function works very accurately in the range 3 microseconds and up.
We cannot assure that delayMicroseconds will perform precisely for smaller delay-times.

MuckS
MuckS аватар
Offline
Зарегистрирован: 13.04.2015

Да какт смирился, что надо по-быстрее что-нибудь. Буду комп мучать-) А так на 1МГц светился диодик, на 2 не светится-)