Чай, термометри, музикална теория и математика

~ 5 Jun 2013, 02:54

Обичате ли чай?

Чаят е много хубаво питие, но, за да е полезен, трябва да се направи с наистина гореща вода, а поради това има следното много неприятно свойство:

Image
:D

Понеже това не можеше да се остави просто така на произвола на съдбата, реших да си сглобя уред, който ми прави чая. Т.е., в действие влезе един термистор и един 8-крак PIC, който командва нещата.

В процеса на разработка на този проект научих



Ако ви е интересно - нека се потопим!

1. Интерфейсът


Идеята е проста - малка платчица с бутонче, говорителче, диодче, и стърчаща температурна пробка. Слагате пробката в чая, пускате уреда - когато температурата стигне оптималната за пиене, уредът изписуква мелодия и примигва настойчиво (ако случайно пропуснете звъненето). Пиете си чая, уреда се изгася сам след 10 минути.

2. Термистори


Термисторът е полупроводник със съпротивление, което се мени осезаемо с промяна на температурата. В случая ползвах 10К термистор, което ще рече, че съпротивлението му при 25 градуса е 10 kΩ, а за други температури се смята чрез уравнението на Щайнхарт-Харт. За съжаление, последното е прекалено сложно за изчисляване върху рахитични микроконтролери като споменатия PIC, затова обикновено се преизчисляват две точки с известни температури/съпротивления и се интерполира линейно между тях. За малки температурни обхвати това е напълно достатъчно, като за по-големи (примерно 0-100°, както ни е нужно на нас) се прави многосегментна линейна интерполация.

На практика нещата откъм реализация са дори по-прости. За да се измери съпротивлението на термистора, той е вързан в делител на напрежение, като PIC-а чете напрежението и го обръща в 10-битово число. На конкретно 10-битово число отговаря конкретна температура. Прави се lookup табличка - във вид [число→температура], покриваща целия температурен обхват. Реализацията на това е във функцията get_temperature() в кода (виж по-долу).

3. Standby режим (който наистина не харчи батерия)


Поне в началото ми се струваше като интересна главоблъсканица, как да можем да палим и гасим уред от едно бутонче (незадържащо! с ключе е ясно), както и с възможност устройството да се самоизключва. В началото си го представях с една схема, която логически управлява захранването, с възможност контролера сам да си "дръпне шалтера". Но има и доста по-лесен начин, а именно режимът Sleep.
Всички процесори имат начин да си изключват тактовия генератор и по този начин спират изпълнението на инструкции и свеждат консумацията до почти 0. Изключването не е необратимо - някои базови части остават активни, и чрез тях устройството може да бъде събудено - примерно при промяна на състоянието на даден крак на микроконтролера (т.е., следи за промяна на напрежението там, а ние можем да направим тази промяна да се случи при натискане на бутонче). Реално животът на фърмуера протича така - процесорът се включва с поставяне на батерията, и оттам насетне винаги "работи", просто в sleep консумира прекалено малко ток, за да го правим на въпрос (60 nA измерих). Когато потребителят го "включи", всъщност се преминава в активно състояние, а при гасене (дали чрез бутон или по таймер), просто заспива отново, реално продължавайки да "трупа uptime".
За да е ниска консумацията и в активен режим, процесорът работи на 32 kHz, което го прави много, много, много бавен. Средната консумация, която се постига, е под 0.3 mA. Батерийката, която съм сложил (CR2032) ще издържи направата на поне 5000 чая :)

4. Как се оптимизира за място


Програмната памет е наистина малко - 1024 думи - което значи че трябва да се пише наистина стегнат код за да се събере цялата функционалност.
Затова:



В крайна сметка програмата е 1022 думи, имам даже къде да натъпча още функционалност :)

5. Как се издават звуци


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

Другият момент е как да издаваме конкретна мелодия. От учебниците знаем, че Ла от първа октава е 440 Hz, следователно възпроизвеждането й, като код, би могло да стане така:



Ако горния цикъл се изпълни 440 пъти, ще имаме тон "ла" в продължение на 1 секунда.
Лошото е, че няма как да се докарат редовете с delay 1/880s: процесорът работи на 32kHz тактова честота, а PIC ядрото оперира с по инструкция на 4 такта, т.е. около 8000 инст/секунда. Забавянията можем да ги направим само целочислен брой инструкции (контролерът няма PWM изводи, но и да имаше, не биха помогнали особено). Ако целим да докараме "Ла", то най-добрият избор е забавянето да е 9 инструкции (нали ви казах, че процесорът е бавен!). Това е 9/8192 от секундата забавяне (≈1/910), т.е. тонът ще е доста фалшив. Бихме могли да "благословим" полученото като "наше, custom Ла", и да градим тонова стълбица, базирана на него, но тук ще срещнем един фундаментален проблем - честотите на повечето ноти не са цели (или дори рационални числа). Обяснението на това се крие в избора на темпериране на нотите в съвременната музика (известен още като 12-tone equal temperament). Става дума за следното - известно е, че ако удвоим честотата на една нота, получаваме нотата с една октава отгоре. 440→880 Hz за горно Ла - дотук добре. Обаче помежду тях има още 12 полутона (ако сте запомнили "седем" от уроците по музика, това е защото не броите черните клавиши). Респективно честотите растат експоненциално нагоре, т.е. отношението между честотите на два съседни полутона винаги е една и съща константа (затова и equal temperament). От честотата за Ла умножавате по константата C и получавате Ла#. От нея, умножавате пак и получавате следващото - Си. Така 12 пъти и получавате горно Ла. Константата по тази логика излиза дванадесети корен от 2 и е приблизително 1.059463... (може да мислите за нея като за фундаменталната константа на музиката :)). Но поради факта, че тук имаме корен, следва, че даже и да тръгнем от кръгло число (примерно, нека приемем, че "до" е 100 херца), то всички останали тонове без до-тата ще са ирационални числа. Поради което няма как да ги възпроизведем по никакъв начин със забавания от вида X/8192, т.е. всичките ни тонове ще са фалшиви. Положението може да се подобри с повишаване на тактовата честота (пак няма да можем да уцелваме "точните" тонове, но поне ще сме по-близо). Впрочем, подозирам, че причината китайските детски играчки да свирят толкова фалшиво произлиза именно от проблеми от този характер...

Все пак: на 8 килохерца сме, можем ли да направим нещо по въпроса за музиката? Оказва се, че можем да приложим една средновековна инторнираща схема, която идва още от времето на Питагор. Нека приемем, че "до" е 100 херца и искаме да пресметнем "ми". ДоДо#РеРе#→Ми, т.е. четири полутона, честотата на Ми е 100 * C⁴ (където C е фундаменталната константа). Получаваме 125.992.. херца. Това говори ли ни нещо? Нека видим колко е Сол спрямо До. Там са 7 полутона и излиза 149.830... Hz. Лампичка? Да, ми е приблизително 5/4 от честотата на До, а сол е приблизително 3/2. В това няма нищо странно. Когато два тона звучат заедно, ако отношенията на честотите им са дроби от малки цели числа, ефектът е, че звучат хармонично и приятно за ухото (и в следствие до-ми звучи хармонично, до-сол също, до-ми-сол е мажорен акорд и т.н.). Този вид темпериране (всички тонове да се изразяват един от друг с малки, "прости" дроби) се нарича just intonation и е бил основният метод за настройване на инструментите близо 20 века.

Как можем да приложим това интониране при нас? Да речем, че ще реализираме тоновете до, ми и сол. От питагоровата теория, отношението на честотите до-ми трябва да е 5/4, а до-сол да е 3/2. Понеже в кода не работим с честоти, а с интервали на изчакване (реципрочните на честотите), така че ако за до трябват X цикъла закъснение, за ми ще са ⅘ X, а за сол - ⅔ X. След привеждане към НОД, излиза, че до трябва да е 15 цикъла, ми - 12, а сол - 10 цикъла. Свиренето на нотите е внимателно написано на асемблер, защото само така има прецизен контрол над това колко цикъла точно се събират - вижте функциите note6(), note5() и note4().

Една последна хитрост се налага тук - така описаните функции генерират правилни до, ми и сол, но те са твърде басови като честоти и не звучат добре на малките говорителчета, с които разполагах. На пръв поглед няма какво да се направи - за да се вдигнат нотите, трябва да се скъсят циклите, а така няма как да се запазят отношенията. Какво ще стане, ако все пак се опитаме да вдигнем тоновете с една октава? Получават се дължини на циклите, респективно, 7½, 6 и 5. Тук можем да приложим следната хитрост, за да реализираме интервала 7½. От кода горе се вижда, че за един цикъл на синусоидата всъщност има два полуцикъла, всеки по 7½ инструкции. Всъщност може да се реализира с 7 цикъла '1'-ца, и 8 цикъла '0' (или обратно). Каква е разликата? Синусоидата вече не е симетрична около средното положение. Практическият тест, обаче показва, че човешкото ухо не чува разликата. Тази хитрост ми позволи да вдигна нотите с една октава и така имаме перфектни три тона, с които могат да се измислят весели мелодийки :)

Кодът на всичко това се намира в noteplayer.c.

С това фърмуера беше готов и пристъпих към реализацията. Както обикновено, започнах с бредборда:
Image

После бързо го прехвърлих на монтажна платка:
Image

Ето го в действие:
Image

6. Проектиране на печатни платки



От любопитство, а и нали се бях заклел повече да не правя неща на перфборд, рекох да видя как ще изглежда нещото на печатна платка. Проектирането на схемата и платката става, естествено, с CAD софтуер, като аз ползвах CadSoft EAGLE, понеже последният работи под Linux и има напълно функционална безплатна версия. Проектирането става на две фази (в instructables има повече от достатъчно инфо, ако ви потрябва). Първата е разполагането на схемата с елементите. EAGLE и подобните му програми имат голяма библиотека с електронни компоненти, като се почне от стандартните резистори, конденатори, транзистори, интегрални схеми и се стигне до специализирани неща като микроконтролери, 7-сегментни дисплеи и т.н.
Всеки елемент в библиотеката има както означение за схематиката, така и 2D модел за разполагане върху платката. Ето как изглежда проектираната схема във EAGLE:

Image

Да се прехвърлим на платката. В началото всички елементи са "скупчени" отстрани и от вас се очаква да ги подредите:

Image

След подредбата, все още тези тънки линии (airwires, показващи кое с кое е свързано) следва да ги оптимизирате така, че да няма много пресичания. После е прекарването на самите пътечки по платката (routing). Макар и да има автоматичен алгоритъм за рутиране, използването му не е препоръчително, тъй като рядко може да се справи толкова добре, колкото човек. За тази малка схема е окей всъщност (а можете и винаги да откажете някои от избраните от него пътечки и да си ги прекарате ръчно).

В аматьорските проекти, целта на рутирането обикновено е да направите платката еднослойна (т.е. всички пътечки да са само от една страна и да не се пресичат една с друга). Това невинаги е възможно, но ако може и особено ако си правите платките после в домашни условия, "производството" им ще е много по-лесно (а дори при поръчка във фирма, често еднослойните излизат по-евтино). Както и да е, след рутирането стигнах до следният финален дизайн:

Image

Следващата стъпка, ако работите с платкаджийница, е да създадете Gerber файлове от вашия дизайн, след което ги пращате на фирмата и те ги произвеждат. Препоръка за платкаджийница в България не мога да дам, тъй като след известна фурстрация с въпросните Gerber файлове, попаднах на един американски доставчик - OSH Park - на който директно пращате EAGLE-ския .brd файл и те ви го печатат. Тяхната услуга е изключително подходяща за аматьори (те за тази цел съществуват), но имат няколко недостатъка - времето от поръчка до получаване е дълго (около три седмици), и една съществена част от цената всъщност е транспорт от Орегон до тук. Като изключим това, услугата е чудесна и крайната цена за 3 бройки платки ми излезе около 35 лева (OSH Park изискват минимум три бройки да пратят).

Ето как изглежда една бройка:

Страна с елементи:
Image

Обратна страна:
Image

Платката и елементите насипно:
Image

Тук стигаме до един проблем, който е мое недоглеждане при проектирането. В библиотеката с компоненти на EAGLE има десетки хиляди артикула и примерно държач за CR2032 батерия има 5-6 вида. Очевидно съм избрал вариант с три крака, докато реалният компонент, който съм купил е двукраков:

Image

Другият момент е, че краката на EAGLE-ския компонент са по-тънки от реалния. Малко работа с дремела и проблемът е решен:

Image Image

Всичко е наситено, остава говорител и термосондата:

Image

Принципно се продават и капсуловани термистори, които щяха да са по-подходящи. В случая ползвах щедри количества термошлаух:

Image Image

Говорители с нужните характеристики има, но защо да купуваме, след като могат да се рециклират? Старите GSM апарати, които иначе биха отишли в кошчето, са ценен източник на елементи: вибриращи моторчета, подсветки, екранчета, клавиатури и говорители:

Image Image

Наливане на софтуера. Това е минималистична конфигурация за програмиране на PIC:

Image Image

Готовият урОд:

Image Image

И те така. Надявам се пътешествието да ви е харесало!

Благинки:
Сорскод, платки: (EAGLE sch/brd, png, pdf), User manual.

Ако някой иска да си сглоби своя бройка, имам две излишни платки - да се свърже с мен, подарявам ги :)



Коментари:

#1 от LZ1IRQ, изпратено на 5 Jun 2013, 17:26


Най-странното приложение нa микроконтролер (или електроника изобщо), което съм виждал :D Но като се замисля, и аз редовно си пия чая студен, ще е добре да си имам нещо такова.


#2 от Александър, изпратено на 6 Jun 2013, 11:01


Нямам особена представа от обясненията освен, някакви бегли спомени от изчезналите ми знания по гимназиална физика, ама винаги ми е супер забавно да чета за изобретенията ти. Евала.




Име:
За връзка: (Линк към вашия блог/сайт/e-mail; незадължително)
Вашият коментар:

Сметнете израза: тридеcет и девет минус детдет и две = (въведи с цифри)


<<

Valid XHTML 1.0 Strict