Камин — такая вещь, которая олицетворяет собой необычайное тепло, уют родного дома, конфеты, подарки, зимние вечера, да и вообще приятная штука. Сегодня мы построим настоящий хабракамин — в компьютерном корпусе, на нанотехнологичных светодиодах и «теплых ламповых» технологиях — pic12f683, Hi-Tech PICC в IDE Hi-Tide.
Не так давно я разжился новым домашним компьютером и заботливые китайцы вставили в корпус спереди и сзади светящиеся красным 12-ти сантиметровые вентиляторы. Шума они издавали много, пользы — ноль, потому я живо их демонтировал. Вот только пустующее место и вечно свербящее чувство в одном месте на предмет самоделок не давало мне покоя и в итоге вылилось в идею устройства камина в лицевой части компьютера. Камин должен был бы разгораться в зависимости от количества и продолжительности обращений системы к жесткому диску и постепенно тухнуть при отсутствии оных.
Средства реализации
Микроконтроллер. pic12f683. Пока нам утверждают, что контроллеры за 100+ рублей дешевле и встопицот раз круче контроллеров за 30 рублей, посидим на старых, проверенных и популярных решениях. Что-то более масштабное, нежели восьминожечный контроллер, нам не понадобится. Я остановился на данном «потому что у меня их было», но сама реализация камина должна влезть и в pic12f629 или pic12f675. Какая-либо периферия, окромя двух таймеров и порта ввода-вывода не понадобится.
Светодиоды. Их два, для обеспечения и необходимой яркости в окошке корпуса, и для обеспечения реальности эффекта горения. Я взял 1-канделовые по мощности желтого цвета, потребляют по 20 мА (обязательная ремарка о том, что через МК нельзя проводить более 100 мА).
Программирование МК. Тот, кто знаком с продукцией компании Microchip чуть более, чем понаслышке, наверняка знает, что некоторое время назад Microchip поглотил за деньги компанию Hi-Tech, занимавшуюся разработкой компиляторов под эти самые контроллеры. И не так давно Microchip презентовал общественности свои новые продукты — компиляторы серии XС. По сути, это те же самые объединенные старые PICC, СNN в виде сумбурной мешанины правил старых диалектов. Длинные абзацы все равно никто не читает, потому Вам — конфетку. Пока неприятных и противоречивых ощущений от них больше, чем чувства стандартизации и единственно верного вектора создания своих приложений.
Остаемся на старом и все еще достаточно приятном Hi-Tech PICC 9.60 STD. Инструкции, как достать этот раритет лежат на архивной страничке поглощенной компании.
IDE. Отдельно выделю использование чуть более, чем достаточно, приятной IDE от той же Hi-Tech — Hi-Tide. Эта надстройка над Eclipse характеризуется удобным гуевым волшебником для определения конфигурации и настроек контроллера. Hi-Tide ставится вместе с компилятором (чекбокс на одном из шагов установки) или, для тех, у кого не запустится версия 3.15, можно попробовать 3.13.
Некоторые соглашения о реализации планов
Вот некоторые наброски идей о функционировании создаваемого камина:
1. Оба светодиода должны независимо друг от друга создавать эффект пламени. Совместная их работа дает более приближенный к настоящему пламени свет.
2. Реализацию эффекта пламени разделим на три составляющих — программный ШИМ для задания моментальной яркости свечения от 0 до 255, кадры — этапы смены случайных яркостей свечения и границы этих яркостей в зависимости от общей яркости свечения. Экспериментально я выяснил, что хорошо — это когда нижняя граница может изменяться от 0 до 50 и верхняя — от 30 до 255.
3. Общая яркость свечения изменяется от 0 до 255 и зависит от количества или длительности обращений к диску. Если кадры будут «висеть» на нулевом таймере, то изменение общей яркости — на независимом первом и прерывании по изменению состояния на входе.
4. Для использования программного ШИМа придется использовать высокую тактовую частоту, я взял максимально возможную 20 МГц.
5. Состояние обращений к жесткому диску будем брать непосредственно с положительного контакта светодиода на корпусе. На светодиоде может быть всего два состояния — либо прижатый к земле, либо к +5 вольтам. Такое положение дел поможет избавиться от подтяжек и прочих подсхем обеспечения дискретности состояний на входе.
Железо
Схема устройства используется следующая:
Не вижу необходимости в пояснениях — количество деталей минимально, их выбор описан выше.
Опустим также, как из этого:
Получается это:
Форм-фактор платы в основном определился размером окна и возможностей по ее креплению к корпусу компьютера.
Питание и вход сигнала жесткого диска на плате устройство выполнено в едином стандартном штыревом разъеме, на его обратной части — обыкновенный molex для запайки в текстолит, но с присоединенными проводами на +5 В (красный) и землю (черный) и заглушенными термоусадками остальными двумя контактами. Сигнал входа навсегда припаян к положительной ножке светодиода:
Прошивка
Настройки я предпочитаю сначала сделать в волшебнике Hi-Tide'а, а затем переписать по-новому восполнить не указанными еще в них присвоениями значений в конфигурационные байты.
FUSE-ы отключают watchdog-таймер, предписывают использовать внешний высокочастотный резонатор и внешний же пин перезагрузки программы.
__CONFIG(HS & WDTDIS & PWRTDIS & MCLREN & UNPROTECT & UNPROTECT & BORDIS & IESODIS & FCMDIS);
Настройки периферии следующие:
void initHardware(void)
{
// По переполнению таймера 1 будет вызываться прерывание
PIE1 = 0b00000001;
// Включаем прерывания нулевого таймера и возможность получения прерываний периферии
INTCON = 0b01101000;
// К 0 и 1 контактам подключены светодиоды, прочие - на вход
TRISIO = 0b00111100;
// Таймер 0 используется с минимальным делителем частоты
OPTION = 0b00000000;
// Также как и таймер 1
T1CON = 0b00000001;
// Выключение компараторов
CMCON1 = 0x07;
CMCON0 = 0x07;
CCP1CON = 0x00;
// Выключение АЦП и концигурация всех выводов ка дискретные
ADCON0 = 0x00;
ANSEL = 0x00;
// Включение прерываний по изменению состояния на пине 2
IOC = 0b00000100;
}
В 683 контроллере, как и в некоторых других есть проблема с невозможностью отдельно задавать или принимать значения на конкретных пинах порта ввода-вывода и приходится использовать все значение порта GPIO. Для упрощения вывода я использую следующие функции установки высокого, низкого уровней и результирующего вывода:
volatile uint8 fIoBuffer;
void setIoPinHigh(uint8 aPinNumber)
{
fIoBuffer |= (1 << aPinNumber);
}
void setIoPinLow(uint8 aPinNumber)
{
fIoBuffer &= ~ (1 << aPinNumber);
}
void updateIoBuffer(void)
{
GPIO = GPIO & 0b11111100 | fIoBuffer;
}
Рандомайзер необходим только в рамках генерации одного байта, потому я использовал выпиленные и модифицированные из стандартных модулей функции генератора псевдослучайных последовательностей:
volatile uint32 fRandomSeed;
void srand(void)
{
fRandomSeed = TMR0 ^ TMR1H ^ TMR1L;
}
uint8 randomByte(void)
{
fRandomSeed = fRandomSeed * 1103515245L + 12345;
return fRandomSeed >> 16;
}
По событию переполнения первого таймера должны выполняться две подпрограммы. Первая — программный ШИМ для вывода моментальных яркостей светодиодов. Логика простая: всегда инкрементируется счетчик, если он переполняется, то падает в ноль. Моментальная яркость (fPwmLedValue1 или fPwmLedValue2) принимает значение от 0 до 255, и, если счетчик меньше этого значения, то светодиод горит, если больше, то нет. Чем выше частота прибавления счетчика, тем менее заметно мерцание светодиода, оно в наших глазах сливается в изменение его яркости.
fPwmLedCounter1++;
fPwmLedCounter2++;
if(fPwmLedValue1 > fPwmLedCounter1)
setIoPinHigh(PIN_LED1);
else
setIoPinLow(PIN_LED1);
if(fPwmLedValue2 > fPwmLedCounter2)
setIoPinHigh(PIN_LED2);
else
setIoPinLow(PIN_LED2);
updateIoBuffer();
Второе действие — кадры. Экспериментально я подобрал длину кадра в 0.3 секунды, что, согласно калькулятору, соответствует 2930 событиям переполнения нулевого таймера. Каждый кадр производится вычисление новой моментальной яркости каждого из светодиодов (зависит от установленных границ fPwmHi и fPwmLo) и по возможности, определяемой булевым fCanIncrement, снижение общей яркости камина:
uint8 randPwmValue(void)
{
return fPwmLo + randomByte() % (fPwmHi - fPwmLo);
}
fFrameCounter++;
if(fFrameCounter >= FRAME_DELAY)
{
fPwmLedValue1 = randPwmValue();
fPwmLedValue2 = randPwmValue();
if(!fCanIncrement)
decBrightness();
fFrameCounter = 0;
}
При изменении состояния входа на высокое должно производиться приращение общей яркости огня, перезапуск таймера длительности обращения к жесткому диску, пересчет границ моментальных яркостей и установка флага разрешения инкрементации общей яркости. Пересчет границ происходит по линейному закону:
void calcEdges(void)
{
fPwmLo = (uint8)(0.1953125 * (float)fBrightness);
fPwmHi = (uint8)(0.8828125 * (float)fBrightness + 30);
}
void incBrightness(void)
{
if(fBrightness < 255)
{
fBrightness++;
calcEdges();
}
}
if(GPIO & 0b00000100)
{
fCanIncrement = 1;
incBrightness();
TMR1H = 0;
TMR1L = 0;
}
else
fCanIncrement = 0;
Результаты
Нехитрая программа и нехитрая же схема позволяют добиться неплохих результатов. Даже если видео, снятое на микроволновку, не способно показать действительные результаты работ, то реальная работа устройства заставляет помедитировать, сидя у «огня». Вот видео ночью, днем несколько иначе:
Исходники и схемы — на гитхабе.
Автор: Urvin