1 (2018-04-11 09:56:32 отредактировано Андрей М)

Тема: Шасси регулятора тэнов на ардуино

Всем добрый день.
Простейший регулятор тэнов из 3-4 дешевых модулей с али. Себе делал для регулировки трехфазного тэна (по этому канала управления - 3, адаптируйте под свою задачу)

это внешний вид блока управления. 2 нагревателя по 3 тэна по 1,5 кВт. Один из нагревателей включен напрямую, через автоматы, другой через автоматы и регулятор

компоненты: Arduino pro mini, LED индикатор трехсегментный, силовой драйвер на moc3063 (тут четырехканальный, выбирайте подходящий) и вольтметр переменного тока для ардуины. Дополнительно потребуется USB-ttl FTDI232 для программирования и блок питания 5 вольт и энкодер с кнопкой или три кнопки для управления.

собственно устройство в сборе.
Описание сборки:
1. распаиваем пины для программирования, как показано на фотографии.
2. распаиваем питание и если предполагается i2c - A4 и A5 на внешний разъем. Я хотел использовать прибор со внешним управлением, но пока нет времени
3. 3 канала 10,11,12. Обратите внимание! общий идет не на GND, а на +5. Эти каналы подключаются к управлению силовой части. (входы драйвера moc3063)
4. Энкодер: направления - 8 и 9. Кнопка  - A6. Общая на GND. Или три кнопки на эти-же контакты для энкодера раскоментируйте
//#define ENCODER // энкодер или кнопки
5. Самое вкусное - припаиваем индикатор, как показано на фотографии
На этом индикаторе 5 ног с одной стороны и 6 с другой. У индикатора ноги нужно немного разогнуть, чтобы они вошли в отверстия ардуно про мини. Сторона с 6 ногами сходит в ряд начиная с отверстия 2.

Далее прикручиваем радиатор с симисторам и подключаем тэны.
Готово.
оно же на макетке:

Для реализации всех идей не хватает времени, не реализована автоматическая подстройка от напряжения... Кто захочет - развивайте дальше.

скетч:

#include <TimerOne.h>
#include <Wire.h> // i2c

// i2c address
//#define I2C_ADDR 8
// количество тэнов
#define mocBase 10 // с какого пина идут MOC-драйвера
#define mocCount  3 // количество тэнов

#define MAX_VAL (mocCount*100) // период Брезенхейма количество тенов * 50 Гц * 2 полупериода
#define MAX_POWER 4500 // максимальная мощность

//#define ENCODER // энкодер или кнопки 
enum {encoder0PinA = 9, encoder0PinB = 8, encoder0Knob = A6}; // 2,4,9
#define ENC_PER_TICK 4
#ifdef ENCODER
#else
enum { KEY_ON_HOLD = 50,  KEY_REP_WAIT = 100,  KEY_REP_PERIOD = 20}; // milliseconds
#endif
// global
//int val = 0;
int powerValue = 0; // <= MAX_VAL
int onoff = 0;

void timerIsr();

// LED driver
uint8_t seg_ports[3] {  6, 5, 2}; //5, 6, 7
enum {SEG_ENABLE = LOW, SEG_LEDS = 8, SEG_COUNT = 3};
uint8_t pins[8] = {A0, A3, A1, A2, 7, 3, 4, 13};//A3, A0, A2, A1, A5, 13, 8, A4
uint8_t BitMap[] = {123, 17, 186, 185, 209, 233, 235, 49, 251, 249, 127, 21, 190, 189, 213, 237, 239, 53, 255, 253};

void segsDigit(int num, int port) {
  for (int i = 0; i < SEG_COUNT; i++) {
    digitalWrite(seg_ports[i], !SEG_ENABLE);
  }
  if (num < 0) return;// lcd off
  for (int i = 0; i < 8; i++) {
    analogWrite(pins[i], bitRead(BitMap[num], i) ? 1023 : 0);
  }
  digitalWrite(seg_ports[port], SEG_ENABLE);
}

void segsInit() {
  int i;
  for (i = 0; i < sizeof(pins); i++) {
    pinMode(pins[i], OUTPUT);
  }
  for (i = 0; i < sizeof(seg_ports); i++) {
    pinMode(seg_ports[i], OUTPUT);
  }
}
//------------------------
// ускорение ADC, точность не очень важна
void fastADC() {
  // set prescale to 16
  _SFR_BYTE(ADCSRA) |= _BV(ADPS2);
  _SFR_BYTE(ADCSRA) &= ~_BV(ADPS1);
  _SFR_BYTE(ADCSRA) &= ~_BV(ADPS0);
}
//------------------------
// Алгоритм равномерного заполнения Брезенхейма
typedef struct bresenham_struct {
  uint16_t size;
  uint16_t value;
  int16_t error;
  uint16_t stepNumber;
} bresenham_struct;

void bresenham_init(struct bresenham_struct *st, uint16_t size) {
  st->size = size;
}

void bresenham_setValue(struct bresenham_struct *st, uint16_t val) {
  st->stepNumber = 0;
  st->value = val;
  st->error = st->size / 2;
}

bool bresenham_getNext(struct bresenham_struct *st) {
  bool result;
  st->error -= st->value;
  if ( st->error < 0 ) {
    st->error += st->size;
    result = true;
  } else {
    result = false;
  }
  if ( ++st->stepNumber >= st->size) {
    st->stepNumber = 0;
    st->error = st->size / 2;
  }
  return result;
}

bresenham_struct bs;
//----------------------------------------------
// encoder
static uint8_t encoderGetVal() {
  int b = digitalRead(encoder0PinB);
  int a = digitalRead(encoder0PinA);
  return (a == 0 ? 2 : 0) + (b == 0 ? 1 : 0);
}
//#else
#ifdef ENCODER
uint8_t encPrev = 0;
uint32_t encPrevMs = 0;
int encClicks = 1;
#else
uint8_t encHold = 0;
uint32_t encNextMs = 0;
#endif
static uint8_t encoderGetCode() {
  uint8_t code;
  uint8_t val = encoderGetVal();
#ifdef ENCODER
  code = (encPrev << 2) | val;
  encPrev = val;
  if (millis() - encPrevMs > 200) {
    encClicks = 1;
  } else {
    if (encClicks <= ENC_PER_TICK + 1) encClicks++;
  }
  encPrevMs = millis();
  if (encClicks <= ENC_PER_TICK && encClicks > 1)
    code = 0;
#else
  code = 0;
  if (val == 2 || val == 1) {
    switch (encHold) {
      case 0: // arm
        encNextMs = millis() + KEY_ON_HOLD;
        encHold = 1;
        break;
      case 1: // first click
        if (encNextMs < millis()) {
          code = val;
          encNextMs = millis() + KEY_REP_WAIT;
          encHold = 2;
        }
        break;
      case 2: // hold clicks
        if (encNextMs < millis()) {
          code = val;
          encNextMs = millis() + KEY_REP_PERIOD;
          encHold = 2;
        }
        break;
    }
  } else {
    code = 0;
    encHold = 0;
  }
#endif
  return code;
}
static uint32_t startMs;
static uint8_t encoderGetKnob() {
  uint8_t knob = 0;
#if encoder0Knob != A6 && encoder0Knob != A7
  knob = digitalRead(encoder0Knob) == 0 ? 1 : 0;
#else
  knob = analogRead(encoder0Knob) > 100 ? 0 : 1;
#endif
  if (knob) {
    // press
    if (startMs == 0) {
      startMs = millis();
    } else if (startMs != 0xffffffff & millis() - startMs > 10) {
      startMs = 0xffffffff;
      return 1;
    }
  } else {
    startMs = 0;
  }
  return 0;
}

static void encoderInit() {
  pinMode(encoder0PinA, INPUT);
  digitalWrite(encoder0PinA, HIGH);       // turn on pullup resistor
  pinMode(encoder0PinB, INPUT);
  digitalWrite(encoder0PinB, HIGH);       // turn on pullup resistor
  pinMode(encoder0Knob, INPUT);
  if (encoder0Knob != A6)
    digitalWrite(encoder0Knob, HIGH);       // turn on pullup resistor
  encoderGetCode();
}

void onEncoderEvent(bool direction) {
  powerValue += direction ? 1 : -1;
  bresenham_setValue(&bs, powerValue);
  if (powerValue > MAX_VAL) powerValue = MAX_VAL;
  else if (powerValue < 0) powerValue = 0;
  Serial.print(4500 / 300 * powerValue);
  Serial.print(" ");
  Serial.print(240.0 / 300 * powerValue);
  Serial.print(" ");
  Serial.print(analogRead(encoder0Knob));
  Serial.print(" ");
  Serial.println(powerValue);

}

void onEncoderKnob() {
  onoff = onoff ? 0 : 1;
}

void encoderCheck() {
  uint8_t code = encoderGetCode();
  if (code == 1 || code == 7 || code == 8 || code == 14) {
    onEncoderEvent(true);
  } else if (code == 2 || code == 4 || code == 11 || code == 13) {
    onEncoderEvent(false);
  } else {
    //Serial.print("+");
  }
  if (encoderGetKnob()) {
    //  Serial.println("knob!!!");
    onEncoderKnob();
  }
}

void receiveEvent(int howMany) {
  //
  //  while (1 < Wire.available()) { // loop through all but the last
  //    char c = Wire.read(); // receive byte as a character
  //    Serial.print(c);         // print the character
  //  }
  for (int i = 0; i < howMany; i++) {
    int x = Wire.read();    // receive byte as an integer
    Serial.println(x);         // print the integer
  }
}

void requestEvent()
{
  if (newDataAvailable)
  {
    for (int c = 0; c < (REG_MAP_SIZE - 1); c++)
    {
      registerMap[c] = registerMapTemp[c];
    }
  }
  newDataAvailable = 0;
  toggleInterrupt();
  //Set the buffer to send all 14 bytes
  Wire.send(registerMap + receivedCommands[0], REG_MAP_SIZE);
}

void setup()
{
  int i;
  for (i = 0; i < mocCount; i++) {
    pinMode(mocBase + i, OUTPUT);
  }
  Serial.begin(57600);
  fastADC();
#if 0
  Serial.print("ADCTEST: ") ;
  start = millis();
  uint32_t x = 0;
  for (i = 0 ; i < 1000 ; i++)
    x += analogRead(A6) ;
  Serial.print(millis() - start) ;
  Serial.print(" msec (1000 calls)") ;
  Serial.print(x / 1000) ;
  Serial.println("val") ;
  delay(1000);
#endif

#ifdef I2C_ADDR
  Wire.begin(I2C_ADDR);                // join i2c bus with address #8
  Wire.onReceive(receiveEvent); // register event
  Wire.onRequest(requestEvent);
#endif

  encoderInit();
  segsInit();
  bresenham_init(&bs, MAX_VAL);
  bresenham_setValue(&bs, 0);
  Timer1.initialize(1000); // 1000 Hz
  Timer1.attachInterrupt( timerIsr ); // attach the service routine here
  Serial.println("Start +");
}


void loop()
{
  encoderCheck();
  uint32_t start ;
  int i ;

}
uint8_t dots[mocCount];
uint8_t pos = 0;
void timerIsr100() {
  int i;
  for (i = 0; i < mocCount; i++) {
    dots[i] = onoff != 0 && bresenham_getNext(&bs) != 0;
    digitalWrite( mocBase + i,  !dots[i] ? 1 : 0);
  }
}


int divi = 0;
int blink0 = 0;
#define BLINK0 200
#define BLINK1 500

int _pow[] = {1, 10, 100};
void timerIsr()
{
  if (++divi > 10) {
    timerIsr100();
    divi = 0;
  }
  segsDigit(onoff == 1 || blink0 > BLINK0 ? ((powerValue / _pow[pos]) % 10) + (dots[pos] * 10) : -1, pos);
  if (++pos > 2) pos = 0;
  if (++blink0 > BLINK1) blink0 = 0;
}
  • 1.jpg
    size: 16.19Кб type: jpg
  • 2.jpg
    size: 96.27Кб type: jpg
  • photo_2018-04-11_08-34-36.jpg
    size: 107.14Кб type: jpg
  • photo_2018-04-11_08-35-31.jpg
    size: 93.3Кб type: jpg
  • 4.jpg
    size: 56.16Кб type: jpg
  • photo_2018-04-11_08-35-31_cr.jpg
    size: 21.63Кб type: jpg
  • photo_2018-04-11_08-35-31_cr.jpg
    size: 21.63Кб type: jpg
  • photo_2018-04-11_08-35-31_cr.jpg
    size: 21.63Кб type: jpg
  • 55.jpg
    size: 21.63Кб type: jpg
  • 55.jpg
    size: 18.75Кб type: jpg

2 (2018-06-11 09:35:13 отредактировано vag377)

Re: Шасси регулятора тэнов на ардуино

схемку б!  а так все классно

и ссылки на комплектующие

3 (2018-06-11 11:00:01 отредактировано Kusnezov Oleg)

Re: Шасси регулятора тэнов на ардуино

vag377 ©:

ссылки на комплектующие

Прямую ссылку в данном случае давать нельзя. Правильно было бы дать ключевые слова поиска на Али. Вообще все детальки обычные, кроме "силового драйвера на MOC...". Но похоже кошки в комнате нет :( , я на Али найти ничего подобного не смог.
Я автору плюс в репутацию поставил, есть за что..., но вот с этим

vag377 ©:

все классно

согласиться не могу, но к теме интереса нет, вот и критика была бы неконструктивной. :)

С уважением, Олег Кузнецов.