Тема: Шасси регулятора тэнов на ардуино
Всем добрый день.
Простейший регулятор тэнов из 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;
}