Таймер для ванной комнаты

Хочу представить свой проект таймера для вентиляции ванной комнаты.
ТЗ
1. Включение/выключение вентилятора по заданным интервалам.
2. Минимальный размер.
3. Минимальная цена.

Ну что же приступим. Итак в качестве времезадающего элемента решено использовать МК STM8S003F3P6. Для такой задачи это перебор, ну у него есть два очевидных плюса:
1. Цена — я их купил 50шт по цене 3грн 25коп ~ 0,4$.
2. Размер — корпус TSSOP20. Очень мелкий но я пока без проблем с такими размерами справляюсь ЛУТ-ом.
В качестве коммутатора — симистор BT134-600 — слишком мощный и большой но он был у меня в наличии (нагло нарушил 2 и 3 условие ТЗ)
Для питания решено использовать схему питания с гасящим конденсатором — дешево и сердито. Схема предназначена для автономной работы без соединений с другими устройствами поэтому гальваническая развязка не нужна.

Предупреждение — схема находиться под высоким напряжением. При ее наладке и использовании необходимо тщательно соблюдать все правила безопасности. Я как автор схемы не несу ответственности за последствия вызванные нарушением правил безопасности.




Схема устройства:

Немного теории по управлению симистором.
Симистор – полупроводниковый элемент, предназначенный для коммутации нагрузки в сети переменного тока. Имеет три вывода: два силовых и управляющий. Открытие симистора производится током через управляющий электрод. При этом различают четыре рабочих зоны симистора.

Полярность напряжение на управляющем электроде указано относительно вывода МТ1.
При этом рабочими зонами являются «1+», «1-», «3-». Зону «3+» использовать запрещено, это может вывести симистор из строя. Для предотвращения этого используют специальные схемы. Также производители освоили выпуск так называемых трех-квадратных симисторов.
Для наших целей проще использовать зоны «1-» и «3-». Это значит что открываться симистор будет под действием отрицательного напряжения на управляющем электроде.
Для выбранного симистора BT134-600 токи управления по зонам:


Как видно из таблицы, для включения симистора на полный период необходимо подать через управляющий электрод ток не менее 11 мА. При этом максимальный необходимый ток для открытия симистора в выбранных рабочих зонах 25-50 мА. Я выбрал значение управляющего тока 25 мА.
Для подачи отрицательного напряжения на управляющий электрод есть одна хитрость. Если внимательно посмотреть на схему, то можно заметить что общим по питанию сделан положительный электрод. А это позволяет простим открытием выходного транзистора порта контролера подавать отрицательное напряжение на управляющий электрод относительно электрода МТ1.

Полезный документик:Десять золотых правил при использовании симисторов.
От DIHALT :
«Десять золотых правил при использовании симисторов» но на русском
А также «Преимущества трёх-квадрантных триаков (симисторов)»

Программа:

#include "iostm8s003f3.h"
#include <stdint.h>
#include <intrinsics.h>

//macro definition
#define led_on()    PB_ODR_ODR5 = 0
#define led_off()   PB_ODR_ODR5 = 1
#define togle_led() PB_ODR_ODR5 = ~PB_ODR_ODR5
#define fan_on()    PD_ODR &= ~(1<<2 | 1<<3)
#define fan_off()   PD_ODR |= 1<<2 | 1<<3


//User definition
#define T_ON 5*60
#define T_OFF 20*60


//function prototypes
void sysinit(void);
__interrupt __root  void TIM4_OVR(void);


//Global variables
uint8_t on = 1;
volatile uint16_t time = 0;


void main(void)
{
    sysinit();
    fan_on();
    TIM4_CR1_CEN = 1;
    while(1)
    {
        __disable_interrupt();
        if ((on == 1) && (time >= T_ON))
        {
            fan_off();
            time = 0;
            on = 0;
        } else if ((on == 0) && (time >= T_OFF))
        {
            fan_on();
            time = 0;
            on = 1;
        }
        IWDG_KR = 0xAA;     //reset IWDG
        __enable_interrupt();
    }
}

void sysinit(void)
{
    //Disable CLK for unused peripherials
    CLK_PCKENR1 = 0x10;
    CLK_PCKENR2 = 0x00;

    //  Config system clock to use 128kHz LSI
    CLK_ICKR_LSIEN = 1;
    while (!CLK_ICKR_LSIRDY);
    CLK_SWR = 0xD2;
    while(!CLK_SWCR_SWIF);
    CLK_SWCR_SWEN = 1;
    CLK_SWCR_SWIF = 0;

    // TIM4 config
    TIM4_PSCR = 0x07;
    TIM4_ARR = 250;
    TIM4_IER_UIE = 1;
    fan_off();
    led_off();

    //GPIO config
    PD_DDR |= 1<<2 | 1<<3;  //PD3 and PD4 open drain
    PB_DDR_DDR5 = 1;        //PB5 open drain

    //config IWDG
    IWDG_KR = 0xCC;     //Start IWDG
    IWDG_KR = 0x55;     //unlock config registers
    IWDG_PR = 3;        //set prescaler divider to 32
    IWDG_RLR = 19;     // Delay at 10ms
    IWDG_KR = 0xAA;     //Refresh IWDG config

    __enable_interrupt();
}


#pragma vector=TIM4_OVR_UIF_vector
__interrupt __root void TIM4_OVR(void)
{
    volatile static uint8_t  cnt = 0;

    if (cnt < 4)
    {
        cnt++;
    }else
    {
        cnt = 0;
        time++;
        togle_led();
    }
    TIM4_SR_UIF = 0;
}

Программа простая. Из граблей на которые можно наступать долго. Контролер при инициализации переключается на тактирование от внутреннего низкочастотного генератора LSI, а по умолчанию этот генератор запрещено использовать для тактирования ядра. Поэтому сначала необходимо, с помощю програми ST Visual Programmer разрешить использование LSI для ядра.

При анализе моей программы пользователем Anatol80 вылезли проблемы с атомарностью доступа к некоторым переменным. Атомарность понятие очень серьезное и об этом есть много умных статей. Но несмотря на прочитанные мною статьи, и даже некоторое понимание проблемы атомарного доступа у меня очень мало опыта правильно анализировать программу и самое главное видеть проблемы с атомарностю. Итак благодаря Anatol80 проблема атомарного доступа была решена, плюс Anatol80 сформулировал ряд правил которые я с его позволения переношу в топик:

  1. Любые переменные, как-то использующиеся в прерывании — делай их volatile.
  2. Многобайтная переменная ИЗМЕНЯЕТСЯ в прерывании — делай атомарность везде в теле программы где она только есть.

  3. Многобайтная переменная СЧИТЫВАЕТСЯ в прерывании — делай атомарность везде в теле программы где она будет ИЗМЕНЯТЬСЯ.
  4. «Старайся, чтобы при выходе из твоей функции глобальное состояние разрешения прерываний было таким же, как и при входе в нее». То есть: если в Вашей функции надо манипулировать разрешением прерываний, то надо сохранить текущее состояние прерываний, затем запретить прерывание затем спокойно сделать критическое дело и восстановить старое значение бита разрешения прерываний. Особенно это важно для отлаженных общеупотребительных библиотеках программиста, которые он будет использовать тысячу раз в нескольких проектах (например, работа с EEPROM, ADC,… ). Вот почему: Вы не ожидаете подляны от своей старой надёжной функции, которая не раз доказывала свою железобетонность. Когда Вы ее вызывали из места, где прерывания разрешены. Но вот Вашу самописную функцию чтения EEPROM или ADC Вы (или Ваш последователь) вызовет из некого критического места, где прерывания были запрещены. И если в ней вдруг встретится явное enable_interrupt — пиши пропало критической секции.


Если возникнут вопросы — отвечу в комментариях.

Несколько слов о программировании этих камешков. В общем интерфейс SWIM требует три цепи — RESET, SWIM, GND. Как показала практика — хватает двух SWIM, GND. Поэтому я всегда делаю мелкий пятачок для цепи SWIM, и очень редко для GND (как правило я использую земляные полигоны, поэтому вопрос «где земля» не возникает). В качестве программатора использую плату STM8L-DISCOVERY.
Очень важно
Ни в коем случае не подключайте программатор при подключенном питании схемы от сети. Программировать только при питании схемы от программатора — иначе .....!!! Я не виноват!


П.С.
Я из Украины — поэтому русский знаю не так хорошо как хочется. А значит есть ошибки которые не уловили системы проверки орфографии и правописания. Большая просьба о найденных ошибках писать в личку — обещаю исправить!

Для тех кто не использует Altium Designer в папке проекта есть pdf для ЛУТ.

Исправлено:
— переменные cnt и time объявлены volatile;
— доступ к двухбайтовой переменной time, в main, сделан атомарным.
Благодаря пользователю Anatol80

— в схему добавлен разрядный резистор R2
Благодаря пользователю John

Косметические изменения в программе:
— Переменная «cnt» перенесена в обработчик прерывания, так как она только там и используется.
— Названия макросов теперь выглядят как вызов функций. Более информативно.
  • +9
  • 29 июля 2013, 23:16
  • bdpcvit
  • 2

Комментарии (78)

RSS свернуть / развернуть
решено использовать МК STM8S003F3P6

Я тоже на них перешел. Милое дело. По цене — половина Tiny13, но зато 20 ног при тех же размерах. По фаршу — Mega8.
Единствееное что не очень хорошо — такты уже просто так не посчитаешь, а значит и V-USB скорее всего просто не портируешь.
+3
А также в 2 раза ниже нагрузочная способность ножек. А можно ещё вспомнить такие някши, как tn261:
Peripheral Features
– One 8/10-bit High Speed Timer/Counter with Prescaler
• 3 High Frequency PWM Outputs with Separate Output Compare Registers
• Programmable Dead Time Generator
– 10-bit ADC
• 11 Single-Ended Channels
• 16 Differential ADC Channel Pairs
• 15 Differential ADC Channel Pairs with Programmable Gain (1x, 8x, 20x, 32x)

Но кому это всё надо, главное чтобы фарша много.
0
А также в 2 раза ниже нагрузочная способность ножек.
Ну в это ограничение пока не еще упирался.

А можно ещё вспомнить такие някши, как tn261
Вспомнить можно, безпроблемно купить — нельзя. Ни в одном из магазинов где я закупаюсь их нет.
Цена на digikey в 3.5 раза дороже.
Так зачем и за что платить больше?

Но кому это всё надо, главное чтобы фарша много.
Может у кого-то и есть цель использовать весь фарш что есть или создать себе препятствия там где их нет.

Мне больше импонирует мысль что в этом самом «бедном» контроллере в линейке STM8 есть все, что мне нужно в 80% случаев.

Именно поэтому я и купил их 60 штук и мне совершенно не жалко совать их в проекты, где используется меньше 10% их возможностей, так как альтернативы, с точки зрения цены, я им не вижу.

Кстати, вот одна из разработок на нем:

Регулятор мощности (3 алгоритма — фазовый, пропуск полуволн, пропуск целых волн) + таймер (+ в перспективе терморегулятор — эта часть не закончена — не распаян усилитель термопары и не написан соответствующий код).
Прошивка (чистый С) без оптимизации — 1.9К, что, с моей точки зрения, довольно оптимально.

Хотя, конечно, если искусственно задаться целью сделать проект при минимуме доступного фарша, то можно сделать и так.
+2
беcпроблемно купить — нельзя
Таки можно купить и в Украине. Но таки в 3 раза дороже STM8S003F3P6.
0
Ну в это ограничение пока не еще упирался.
Дёргать мелкие полевички, управлять светодиодной матрицей. Очень типовые и очень распространённые задачи. Нагрузочная способность ножек AVR-ок — огромный плюс.
Вспомнить можно, безпроблемно купить — нельзя.
Да, x61 довольно дорогие. Но по соотношению возможности/цена для целого ряда задач всяким STM8 до них ещё как до луны пешком…
0
Дёргать мелкие полевички,
Мелкие полевички требуют таких мизерных токов для управления, что им нагрузочная способность выходов мк пофиг.
управлять светодиодной матрицей
Там авр-ки тоже очень быстро упираются.
Но по соотношению возможности/цена для целого ряда задач всяким STM8 до них ещё как до луны пешком…
Огласите весь список, пожалуйста.
+2
Мелкие полевички требуют таких мизерных токов для управления.
Зависит от Qg и частоты коммутации.
Там авр-ки тоже очень быстро упираются.
Но это, скажем, 6 семисегментинчков против 3 с приличной яркостью. Или матричка 8x8 без дополнительных ключей. Вполне полезно.
0
Но это, скажем, 6 семисегментинчков против 3 с приличной яркостью.
Ну на статическую индикацию ног получается впритык даже для 2-х сегментов.
А при динамической практически все-равно сколько сегментов.
В моем регуляторе что выше 3 сегмента 0.56" индикатора + 6 светодиодов индикации состояния, заведенных как 4-й сегмент. С яркостью никаких проблем нет.
0
Имел ввиду не сегментов, а семисегментных разрядов.
0
Зависит от Qg и частоты коммутации.
Я в курсе. Только там, где нужна действительно высокая частота коммутации с МК вообще не сильно сунешься. Особенно с авр.
Вполне полезно.
Кому?
0
Lifelover, хочу напомнить, что тут вы не хозяин топика, и запретить комменты, когда вам не удобно, не получится. А то ведь мы можем начать проходится по вашим часикам, почему вы из не на этой самой тини сделали, и зачем отклоняетесь от своих мировозрений и примеяете 32 битную арифметику, без которой можно обойтись.
0
Да, приебаться к путсякам вы мастера.
-3
Ребята — давайте жить дружно. Я при выборе камня руководствовался ценой. Я согласен что для такой задачи надо использовать Attiny4 или какой то PIC10. Но у меня их нет, да и стоят они дороже (в розничной продаже). В результате, при правильном инженерном выборе домашняя экономика дает хороший пинок под зад, поэтому я немного уступил как инженер но выиграл по цене прибора. Сам прибор от этого только выиграл, а мое инженерное эго не сильно то и пострадало.
Прибор простой, программа легко переносится на другие камни — поэтому я с большим удовольствием помогу всем кто пожелает сделать прибор на другом контролере — только без холивара.
0
Тссс. А то про 555 таймер вспомнят ещё :)
+1
Ну если брать розничные цены, то PIC10F200 и ATTINY13 для такой задачи подходят не хуже и не дороже.
Но STM8S003 полсотни «для всего» закупить можно, а у этих область применения куда более ограничена.
+2
Сравнил цены у нас:
STM8S003F3P6 в розницу (от одной штуки) стоит 3.5грн ($0.43), от 48шт — 3.18грн ($0.39), от 170 — 2.94грн ($0.36)
TINY13 — 1шт — 6грн ($0.74), >26шт — 5.77грн ($0.71), >90шт — 5.56грн ($0.69)
PIC10F200 — 1шт — 3.25грн ($0.40), >52шт — 2.89грн ($0.36), >187шт — 2.67грн ($0.33)

Таким образом, конкретно для этой задачи при проэктировании серии лучше всего, наверное, подошел бы шестиногий PIC10F200. Не сильно знаком с PIC (не знаю сколько в среднем флэша жрет отдельная комманда), но его 384 байта флэша для этой задачи должно быть за глаза.

А вот TINY13 здесь не вариант — совершенно нет преимуществ перед STM8S003F3P6 и PIC10F200.

А вообще спасибо что обратили внимание на PIC10F200 — интересный микроб. Есть куча задач где его будет удобно применить (в основном из-за размеров корпуса).
0
Я брал в розницу PIC10F200 за 17-18р и ATTINY13 по примерно такой же цене или даже чуть ниже. STM8S003F3 обычно стоят от 17р в розницу (впрочем, я взял десяток у человека, бравшего себе сотню, вместе с доставкой вышло в 12.70 за штуку).
Оба представляют интерес как предельно дешевые малоногие МК.
У PIC10F200 — 256 слов памяти, команда занимает одно слово. Периферии практически нет — GPIO и счетчик, даже не имеющий прерывания.
0
Да выбор как раз верный, т.к. любой инженер должен обосновать свой выбор, и цену комплектухи в том числе… Если оно дешевле и не усложняет при этом разработку — то ни о каком неверном выборе речи идти те может.
+4
Хорошо бы ещё разрядный резистор параллельно C1 поставить.
+2
Думал об этом. Но устройство смонтировано в корпусе вентилятора, подключено к штатному выключателю, а значить никого вилкой не ударит. Потому и выкинул за ненадобностью.
0
После хорошего сна я еще раз обдумал Ваши слова о разрядном резисторе. Вы правы. Не все кто повторит эту схему будут использовать ее без вилки, а значит риск поражения током есть. Посему переделал схему и печатку.
Еще раз спасибо Вам за замечание!
0
Даже без вилки может понадобиться демонтировать устройства для ремонта, например.

R2 какого типа и какой мощности?
+1
* устройство
0
Ну ремонт делают как правило грамотные люди, посему ручной разряд конденсатора никто не отменял. Если думать что ремонтник без мозгов залезет в наглую — тут извините пускай природа решает что с ним дальше делать.
R2 — если честно то не знаю какого типа. Мощность, при указаном сопротивлении 0,5Вт. Место на плате хватит. Предельное напряжение в справочник не смотрел — но прикинул по формуле Uпр=300*sqrt(P*l):
Uпр = напряжение пробития
P = атмосферное давление (мм.рт.с)
l = длина между электродами (см.)

У меня в работающем устройстве он вообще отсутствует за ненадобностью. И устройство успешно работает больше года. Причем практически круглосуточно.
0
Для выводных резисторов напряжение ниже — они пробиваются между витками резистивной дорожки. Насчет SMD не знаю, но они, вероятно, пробиваются по поверхности и тоже имеют куда более скромные предельные напряжения (что-то вроде 200В для 0805, ЕМНИП).
0
На эту роль обычно хватает CF-0.25, только на сопротивление от 470к. Больших выбросов, выносящих R1, на нем нет благодаря шунтированию конденсатором.
0
Не совсем понял для какой цели вотчдог применён. Не поясните, конкретная ли цель, али прозапас?

«Нет предела совершенству»: не помешает подтяжка на неиспользуемые пины (как ни как рядом сеть и наводки будут); отправлять процессов в слип (прерывания будут же будить).

Спасибо за конструкцию. И отдельно спасибо за симистор.
0
WDT использую как раз на случай зависания, или сбоев вызванных наводками на висячие ножки. Подтяжку делать — вопрос хороший, надо будет подумать. Про режим сна думал, мозг кипел — но до это дошел только недавно. А проект делался год назад, я тогда только осваивал эти камни. Все плюшки типа сон, прерывания, контроль батареи выложу в новом проекте — мониторинг протечки води. Проект на стадии завершения, так что скоро будет.
0
а ещёмогу посоветовать резистор R1 сделать составным из 4-х удвоенного сопротивления два последовательно и два таких блока впарралель.

И желательно чтобы эти резисторы были не 1206 а МЛТ 0.5 не меньше, 0.25 выгорал после включения в сеть индукционной плиты, 0.5 выгорал при подключении инверторного кондиционера. 4 0.5-х не выгорели по сей день что я только ни делал :) Проблема в высокочастотной составляющей помех по питанию… ибо кондер для 1-2 килогерц колебаний — проволочка… да и стабилитрон я набирал из 3 последовательно соединенных на 4-5 вольт — на них меньше рассеивается а потом КРЕНкой понижал до напруги питания ибо одиночный на 5 вольт часто уходил в 10 вольт на иголках убивая некоротые мелкие полевички
0
Про вылеты резистора при таких условиях — не знал. Но мне кажется что вы преувеличиваете. Помехи про которые Вы говорите — имеют очень малую длительность. Резистор у меня стоит на 0.5 и при той длительности ВЧ помех он должен выдержать. Если на вход полазит высоковольтный импульс — то какой он должен быть длительности чтоб поднять напряжение до 10В на время достаточное для перегорания контролера. Попробую просимулировать схему для таких условий.
0
просто представьте у соседа индукционную варочную поверхность каждая плитка которой может 2-3 киловатта всосать из сети с модуляцией 6 килогерц!!! Ну и схему возьмите любой индукционки — там транзюк коротит катушку на диодный мостик! Кондера там нет. Ибо контролируется ток через транзистор и по сути он и держится константой…

Вот и получится по сети на всем протяжении периода гребенка 2-6 килогерцовая и её амплитуда тем больше чем ближе к нулю. Эт не теория — это практика — у меня индукционка… и первое же её включения на подобной схеме выпалило резюк… он как предохранитель
0
Странная какая-то схема. Отсутствие кондера, допустим, можно объяснить тем, что сей девайс работает как ККМ, но фильтр ВЧ помех там стоять должен.
0
у меня есть и другая варочная поверхность с тремя дросселями и кучей кондеров…
но увы полностью эту срамоту они из сети не убирают! Аналогично на этот резистор действует всё что импульсно к сети подключается — пылесосы, резуляторы оборотов которого — симистор с динистором, экономки некачественные, электронные трансы на 12 вольт галогенки и т.д.
0
У меня подобных источников помех хватает, но эти резисторы не вылетали (правда, в промышленных, а не самопальных девайсах). Возможно, твои слишком низковольтны и пробиваются помехой. С этой точки зрения желательно ставить достаточно мощные резисторы — у них выше пробивное напряжение, либо включать несколько последовательно.
0
ну дык и я о том же :) пару раз было а потом закончились феерверки… у меня просто на каждую лампу датчик движения поставлен… вот в них стоят 1 ваттные резюки… конечно они выживут :)
А разрядник я ставил 2 мегаомма… меньше греется и при кратковременном пропадании контакта не искрит
0
Такой мысли в лабиринтах моего мозга не находил. Спасибо!!!
0
Увы такой плиты у меня нет, и наверное мне повезло что у заказчика этого таймера тоже. Но как то странно что плита так фонит в сеть. Что об этом фоне думают соседи и службы энергосбыта, и как такие плиты допускают в продажу.
Можно увидеть амплитуду напряжения в сети при работе вашей плиты?
0
В принципе, эти помехи быстро затухают в проводке. Если не ошибаюсь, плита с точки зрения сети ведет себя аналогично устройству с APFC.
0
Именно о том я и говорю!
Только вместо диодного моста у этого APFC нагрузка — трансформатор воздушный с короткозамкнутым витком :) а ну и мощность у этого устройства не ваттами а киловаттами измеряется потому и помехи поболе будут даж не смотря на фильтрацию в некоторых дорогих экземплярах.
0
В дорогих сомневаюсь… В том же ЕС весьма жосткие стандарты по электромагнитной совместимости, и они бы такое быстро отправили обратно в Китай… Как вариант что на СНГ как обычно сливают все УГ…
0
[grammarnazi]жесткие[/grammarnazi]
0
Так как мой рейтинг после неудачной шутки «Адский код» упал ниже плинтуса — то вложения делать я не могу.
Теперь можешь, я полагаю.
+1
  • avatar
  • Vga
  • 30 июля 2013, 15:25
Да теперь могу :) Перешел, так сказать на светлую сторону силы. Кстати — почему не разрешено pdf загружать?
0
Потому, что местные админы не способны (да и не особо хотят) толком движок настроить. До последнего обновления pdf в списке разрешенного было, кстати говоря. Сейчас, по видимому, плагин загрузки файлов просто сброшен к дефолтным настройкам.
0
pdf'ку в zip и его добавлять. К счастью движек ещё не проверяет, что в загружаемом архиве находится недопустимый файл (как это любят делать почтовики).
0
Только если чистый pdf можно открыть в плагине к браузеру, то с этим лайвхаком уже не канает… Это я к тому, что действительно дерьмовая ситуация =)
0
Этот плагин отдает файл с такими заголовками, что браузер даже поддерживаемые им форматы вроде JPG предлагает скачать, а не открывает на месте.
+1
как это любят делать почтовики
Запаролить, делов-то :)))
0
Ну пароль, или другой формат — это не выход. Для меня формат zip хорош тем, что его все поддерживают так сказать из коробки. Человек тыц на ссылку и получи результат, а тут архив+пароль или и того хуже архив для которого нужен свой архиватор. Вот не пойму чем pdf то провинился что его по умолчанию в таком известном движке заблочили.
+1
Было время что через pdf'ки распространялись вирусы. Там был жесткий баг с запуском программ. И адоб как-то очень долго телился с выпуском патча. Но даже после выпуска народ долго посылал это обновление нафиг (оно там чё-то требовало, не помню уже). Вероятно так pdf и попал в немилость.
0
Я уже давно использую PDF-Xchange Viewer. Это небо и земля по сравнению с продуктами Adobe.
+1
Гы. Парольные они тем более посылают как вредоносное ПО :)
0
если Вы про гугол и зип, то дело в том, что пароли в зипках — полное фуфло, ничего не шифруется. используйте 7zip или rar
0
Кстати, для подобных применений IMHO, должны подходить неизолированные источники питания типа таких.
+1
Вечные «платформонезависимые» баги:
— переменные cnt и time не объявлены volatile;(что с ними сделает отпимизатор — остаётся только молиться Богу чтобы вообще не выкинул).
— доступ к двухбайтовой переменной time неатомарен в main. В результате времена могут в один прекрасный момент убежать.
Ванная, конечно, не Байконур, но… :)
+1
Спасибо за замечания — подправил.
0
В качестве последнего штриха в main надо сравнивать с T_ON и T_OFF не time, а ее копию. То есть в while(1) сразу сделать: disable_interrupt(); copy_time = time; enable interrupt(); и сравнивать copy_time.
Почему это надо сделать? Вот как может получиться: с T_ON у нас равно 300, то есть 0x012c. Пусть наше time = 0x00ff, то есть гораздо меньше чем T_ON.
Поехали. Начинаем сравнивать (time >= T_ON). Сравниваем мл. байты. FF>=2c — конечно! Значит, надо сравнивать старшие байты. Тут бабах — прерывание. time++ стало 0x0100. Возвращаемся из прерывания и сравниваем старшие байты: 01 >= 01? Ну да! То есть у нас time = 256, а оказывается уже пора «сливать воду».
+1
А что если сделать так:

//Global variables
uint8_t on = 1;
volatile uint8_t  cnt = 0;
volatile uint16_t time = 0;


void main(void)
{
    sysinit();
    fan_on;
    TIM4_CR1_CEN = 1;
    while(1)
    {
        __disable_interrupt();
        if ((on == 1) && (time >= T_ON))
        {
            fan_off;
            time = 0;
            on = 0;
        } else if ((on == 0) && (time >= T_OFF))
        {
            fan_on;
            time = 0;
            on = 1;
        }
        IWDG_KR = 0xAA;     //reset IWDG
        __enable_interrupt();
    }
}
0
Ну разумеется здесь этот свирепый прием будет хорошо работать :) Здесь же не критически к дрожанию фронтов импульсов включения и вообще к методу включения/выключения вентилятора. Но представьте себе: бизнес пошел, Ваши изделия нарасхват, и вот на комбинате вентилятор огромный и требует плавного разгона/торможения ШИМом в течение нескольких секунд. И получается что мы затупили на эти секунды — ни на текущее время не прерваться нифига. А тут еще начальник подошел говорит у конкурентов изделие такое же, но по MODBUSу управляется, и в архив пишет время включения-выключения. А у нас прерывания запрещены. Поэтому в принципе можно просто и безопасно локально делать маленькие критические секции. В арсенале у нас есть простые правила для 8-разрядников (простите за повтор из моей недавней писанины): 1) Любые переменные, как-то использующиеся в прерывании — делай их volatile. 2) Многобайтная переменная ИЗМЕНЯЕТСЯ в прерывании — делай атомарность везде в теле программы где она только есть. 3) Многобайтная переменная СЧИТЫВАЕТСЯ в прерывании — делай атомарность везде в теле программы где она будет ИЗМЕНЯТЬСЯ.
+2
Познавательно. Хочу попросить у Вас разрешения перенести эти правила в топик естественно с указанием авторства.
0
Да нет проблем — тут моего-то «авторства» немного. Только мой корявый и бескомпромиссный слог типа «делай атомарность везде в теле программы» — рассчитан, конечно, на человека понимающего, что если в этом месте тела программы прерывания и так явно запрещены, то зачем делать еще критическую секцию))
Теперь серьёзно: Плавно вытекло Правило 4) «Старайся, чтобы при выходе из твоей функции глобальное состояние разрешения прерываний было таким же, как и при входе в нее».
То есть: если в Вашей функции надо манипулировать разрешением прерываний, то надо сохранить текущее состояние прерываний, затем спокойно сделать критическое дело и восстановить старое значение бита разрешения прерываний.
Особенно это важно для отлаженных общеупотребительных библиотеках программиста, которые он будет использовать тыщу раз в нескольких проектах (например, работа с EEPROM, ADC,… ).
Вот почему: Вы не ожидаете подляны от своей старой надёжной функции, которая не раз доказывала свою железобетонность. Когда Вы ее вызывали из места, где прерывания разрешены. Но вот Вашу самописную функцию чтения EEPROM или ADC Вы (или Ваш последователь) вызовет из некого критического места, где прерывания были запрещены. И если в ней вдруг встретится явное enable_interrupt — пиши пропало критической секции.
+2
Вот поторопился — отвлекает начальник работой)).
Пропустил пару слов в фразе. Надо так: «сохранить текущее состояние прерываний, запретить прерывания, затем спокойно сделать критическое дело и восстановить старое значение бита разрешения прерываний».
+1
Спасибо огромное за Ваши труды. Насчет авторства это Вы зря. Только благодаря опыту и знаниям Вы сумели сформулировать эти правила. Я про атомарность тоже читал но вот знаний и практики практически «0» — потому и допустил ошибки в программе.
0
А не могли бы Вы объяснить, почему cnt нужно объявлять volatile? Если time еще кое-как понятно — двухбайтовая, то с cnt никак не пойму что может произойти. После прочтения этой статьи вообще запутался.
0
Из того что известно мне. Знания есть — применять учусь :) так что поправляйте если что.
Итак переменная «cnt» сидит в функции обработчике прерываний.
По сути говоря, эта функция нигде явным образом не вызывается. Директива __interrupt дает компилятору понять что эта функция вызывается внешним воздействием, а не явным вызовом — а для компилятора это значит добавить в начале функции сохранение состояния контролера, а при выходе восстановить. Ну и не дает линкеру вообще ее выбросить при оптимизации.

Теперь о переменной «cnt». Она объявлена как static — в данном случае это означает сохранение значения между вызовами функции. Но не факт что компилятор ее не выкинет при оптимизации — мол статик да еще в функции которая прямо не вызывается (не факт что директива __interrupt распространяется на переменные). Поэтому и использовал директиву volatile чтоб наверняка.
Вот как то так. Жду пинков :)
0
К стаи о размере переменной. Два байта или один значения не имеет. Как правило контролер для изменения переменной, даже размером один байт, сначала пихает ее в регистр а потом изменяет и возвращает на место. Тут есть загвоздка. Ядро STM8 умеет напрямую работать с RAM. Но это не значит что компилятор это использует. Например инкремент делается одной командой — но доблестный IAR, при максимальной оптимизации, делает это за три. Я им об этом написал — но пока только «Спс, мы учтем. Ждите» Вот кусок дизассемблера — четко видно что обнуление проходит за одну команду а инкремент за три.
+2
Абсолютно правильный ход мысли. Вы становитесь настоящим параноиком — только параноики способны написать надёжный код))
Проверять нужно даже гипотетические опасности, грозящие Вашему коду. Тут хорошо помогает, простите за психологизм, метод эмпатии — понимание состояния наблюдаемого объекта путём сопереживания, проникновения в его субъективный мир. Если Вы конструируете какой-то механизм — представлять себя на месте одной из шестерёнок, как ей хреново крутиться если не будет смазки, как она греется, ломается… Вот так и нам приходится представлять себя байтом, битом.
Да, Вы правы, и для однобайтовых переменных в 8-разрядниках тоже необходимо применять почти те же правила и приёмы. Разница лишь в одном — если ОДНОБАЙТОВАЯ переменная в прерывании только читается — то в теле программы на её атомарность неё можно «забить болт».
0
Стыдно сказать — у меня множество таких фобий. Например, перед считыванием состояния бита порта стараюсь по возможности вновь настроить его на приём (было хорошо на MCS51 и AVR — там это быстро. На новых кристаллах типа Xmega и STM32 это уже не везде сделаешь). Перед засыпанием кристалла проверяю настройки и разрешенность «будЯщего» прерывания, включенность таймера. Короче, порой код получается смешным.
+1
Ну так лучше чтоб над кодом посмеялись чем над трупом прибора поплакали. Так что ваши фобии не так плохи. Я пока так не могу. Пытаюсь переучить себя с «семь раз скомпилил — один раз проверил» на «семь раз проверил — один раз скомпилил». А то получается что сначала набыдлокодил, а потом сижу исправляю.
+2
LinkSwitch'и от Power Integrations тоже позволяют делать такие источники, кстати. И на этом сайте уже в какой-то конструкции такой применялся.
0
Да, это достаточно типичное применение для подобных чипов, просто по NCP-шкам информация под рукой оказалась. А так я встречал подобное и на TOP/TinySwitch и даже, если мне память не изменяет, на инфинеоновских ICE.
0
Да, забыл уточнить: такие источники хороши минимумом высоковольтных компонентов и тем, что они не рассеивают лишнего тепла (в отличие от резисторов).
0
www.dectel.ru/dectel_el/publications/10rul.shtml
десять правил, но на русском.
+1
Перетащил в топик. Спасибо!!!
0
www.dectel.ru/dectel_el/publications/3q.shtml
вот эту еще добавь
+1
Спасибо! Добавил.
0
А не подкините библиотек altium stm8s?
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.