Еще раз а также немного о прерываниях

mikroPascal for AVR. Урок 3. Еще раз UART а также немного о прерываниях

Ну вот, после очень большого перерыва я наконец что-то смог сделать. Эта третья по счету статья о среде программирования mikroPascal, речь в которой пойдет снова о UART. 
Первая статья, вторая статья

В этот раз все будем делать наглядно. В качестве “экспоната” я решил использовать исходник программы “iCPU”. Вообще то в связке должны работать две программы: на ПК и на микроконтроллере.

Так как выбор пал на микроконтроллер Atmega8, то связь с ПК будет через COM порт (виртуальный). Под словом “связь” имеется ввиду прием данных.

Но на данный момент, в программа под Windows не готова, и будем использовать моделирование в Proteus + терминал.

Итак, еще раз о UART:

UARTx_Init(baud_rate : dword); //Инициализация 1 UART модуля (для тех МК, где их несколько)
UARTx_Init_Advanced(baud_rate : dword; parity : byte; stop_bits : byte); //Расширенная инициализация UART. Можно задать параметры: бауд рейт, четность, стоповые биты.
UARTx_Data_Ready(): byte; //Возвращает “1” если в буфере приема есть данные.
UARTx_Tx_Idle(): byte; //Возвращает “1” если данные были переданы.
UARTx_Read(): byte; //Процедура считывания данных;
UARTx_Read_Text(var Output : string[255]; var Delimiter : sting[10]; Attempts : byte); //То же самое, но запись ведется в строковую переменную. Параметры: переменная, разделитель, какой длинны строки нужно обрабатывать.
UARTx_Write(data_ : byte); //Процедура записи в порт.
UARTx_Write_Text(var uart_text : string[255]); //То же самое, только отсылает строковую переменную.
UART_Set_Active (read_ptr : ^Tread_ptr; write_ptr : ^Twrite_ptr; ready_ptr : ^Tready_ptr; tx_idle_ptr : ^Ttx_idle_ptr); //Выбор модуля UART, который должен быть активным на данный момент (подробнее есть в справке).

А вот после того, как вы вспомнили что представляет из себя UART в mikroPascal, можно и с прерываниями познакомиться. Я и сам не так давно с ними разобрался, так что если где увидите косяк, то сразу пишите в коментах 🙂

И так , обращение к прерываниям в mikroPascal ничем кардинально не отличается от других сред программирования, ведь регистры прерываний в микроконтроллере не меняются в разных средах программирования.

В данном случае нас интересуют прерывания по таймеру/счетчику 1. А точнее, из всех прерываний только прерывание по совпадению. Для этого нам нужны такие регистры:

TCCR1B (настраиваем предделитель (1, 8, 64, 256, 1024) , OCR1A (настраиваем компаратор) , TIMSK (выбор прерываний), SREG (регистр статуса).

Теперь, когда знаем зачем нам эти регистры, можно и сконфигурировать их.

TCCR1B:=0x04; //устанавливаем предделитель на 256
OCR1AH:=0x05; //Записываем старший бит регистра сравнения
OCR1AL:=0xdc; //Записываем младший бит регистра сравнения
TIMSK:=0x10; //Выбираем прерывание по совпадению SREG_I_bit:=1; //Разрешаем прерывания

Вы скорее всего обратили внимание, что регистр OCR1A странный. Просто он состоит из двух восьмибитных регистров. В итоге его разрядность составляет 16 бит.

Теперь можно создать процедуру для обработки прерываний. Назовем ее Light().

procedure Light(); iv IVT_ADDR_TIMER1_COMPA; //тут мы выбрали, по какое прерывание будет вызывать выполнение процедуры.
begin TCNT1H:=0x00; //Обнуляем счетный регистр (он тоже “двойной”). TCNT1L:=0x00;
end;

Ну вот, основное по части прерываний сделали, а теперь….

program iCPU; uses AADL; var c, inp:integer; iarr:array [0..3] of integer; str:string [10]; procedure Light(); iv IVT_ADDR_TIMER1_COMPA;
begin TCNT1H:=0x00; TCNT1L:=0x00; PORTD7_bit:=1; delay_ms(10); PORTD7_bit:=0; if inp100) and (c200) and (c300) and (c400) and (c100) and (c200) and (c300) and (c400) and (c

Источник: http://cxem.net/mc/mc279.php

Правописание “так же” и “так же”: когда в два и одно слово, примеры, пунктуация, синонимы

Правильно писать «так же», если «так» – это наречие, а «же» – частица. Их используют для сравнения объектов.

  • Она во всем стремилась походить на подругу: так же ярко красила губы, подолгу крутилась перед зеркалом и манерно растягивала слова.
  • Стоял апрель, а на улице все так же хлопьями валил снег.
  • Так же, как и я, она терпеть не может сливки.
  • Животные так же, как и люди, умеют любить.

Слитное написание

«Также» представляет собой союз, который образовался путем сращения наречия с частицей. Писать его нужно слитно.

  • Артист нервничал перед выступлением, в зале также ощущалось волнение.
  • Доллар, как и евро, также продолжает стремительно расти.
  • Артист нервничал перед выступлением, и в зале ощущалось волнение.
  • И доллар, как евро, продолжает стремительно расти.

Задаем вопрос

Написание слова зависит еще и от вопроса. К наречию с частицей можно задать вопрос «как?». Зато с союзом такой номер не пройдет, поскольку это не самостоятельная часть речи.

Отбрасываем частицу

Рассмотрим такое предложение:

  • Мой сегодняшний день прошел так же, как и вчера.

Помня о том, что частица «же» придает лишь эффект усиления, попробуем ее отбросить. Что у нас получилось?

  • Мой сегодняшний день прошел так, как и вчера.

Предложение абсолютно не пострадало, значит, в данном случае «так же» следует написать раздельно.

Теперь другой пример:

  • Мой друг любит суши и роллы, я также люблю японскую кухню.

Попробуем снова отбросить «же». И вот что у нас получится:

  • Мой друг любит суши и роллы, я так люблю японскую кухню.

С предложением явно что-то не то! Еще бы, ведь в этом случае мы отбросили не частицу «же», а оторвали кусочек союза! Запоминаем: в такой ситуации наше слово пишется слитно.

В то же время, если заменить также на тоже — смысл не изменится. Это — убедительный повод для слитного написания.

  • Мой друг любит суши и роллы, я тоже люблю японскую кухню.

Синонимы

Наречию с частицей «так же» соответствуют следующие синонимы:

  1. таким же образом,
  2. точно так же,
  3. как и,
  4. равно как и,
  5. так же как,
  6. подобно,
  7. похоже,
  8. одинаково,
  9. аналогично.

Союз «также» можно заменить словами:

  1. тоже,
  2. в равной мере,
  3. вместе с тем,
  4. равным образом.

Бывают, правда, непростые ситуации, когда смысл можно определить лишь по широкому контексту, который включает в себя несколько предложений, либо по интонации.

  • Девочка была так же очень красивая. (Эта девочка была такая же красивая, как и другая.)
  • Настроен он был также решительно. (И настроен он был решительно.)

Пунктуация

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

  • Я, так же как и большинство студентов, рассчитываю на стипендию.

(= Я, равно как и большинство студентов, рассчитываю.)

  • Я так же, как и большинство студентов, рассчитываю на стипендию.

(= Рассчитываю таким же образом, в такой же степени.)

Надеемся, наша статья помогла вам уяснить разницу между союзом «также» и наречием с частицей «так же». Всегда обращайте внимание на контекст – он поможет разрешить любые трудности. А также не забывайте руководствоваться правилами и подсказками. И на десерт – поучительная лингвистическая сказка.

О силе дружбы

Жили-были на свете наречие Так и частица Же. Так всегда сторонилась Же, потому что считала себя выше нее.

– Я самостоятельное слово! А она кто? – говорило Так вздернув нос.

Же молча сносила обиды и порой даже уходила из предложения, чтобы не оказаться рядом с высокомерным Так. Пожалуй, так бы они никогда и не подружились, если бы не один случай.

Союз И однажды сильно захворал. Настолько, что не мог встать с постели и занять свое законное место в предложении: «И дружба важна для нас». И ведь, как назло, все его ближайшие друзья разъехались – некому было подменить несчастного! Тогда слова решили собрать совет.

– Как же нам быть! Если И не встанет в предложение, оно потеряет смысл!

– Жаль бедолагу. Но мы все можем лишиться работы.

И все слова тихонечко заплакали. Как вдруг Так подошло к Же и опустив голову прошептало:

– Прости меня. Давай дружить. Я знаю, мы сможем помочь.

Же приветливо улыбнулась, протянула Так руку и сказала:

– Дружба также важна для нас.

И тут случилось чудо: предложение обрело смысл! Слова подняли удивленные глаза на бывших врагов и просияли. Они спасены!

С тех пор Так и Же стали такими друзьями, что водой не разольешь. А если и оказывались в предложении порознь, то все равно поддерживали друг друга.

Правописание этих слов надо знать:

Источник: http://pishempravilno.ru/takzhe-i-tak-zhe/

AVR. Учебный Курс. Отладка программ. Часть 4

Продолжаем трактат об отладке программ. На этот раз в бой идут одни старики.
 

Осциллограф Очень часто хочется в динамике поглядеть как работает программа. Особенно если ее структура сложней чем просто суперцикл.

Если там конечные автоматы на прерываниях или разделение задач на флаговом автомате/очередном диспетчере, то аналитическое тупление в код и прогоны в отладчике мало что дадут — наслоение прерываний, процессов в очереди, стадии и взаимодействие разных конечных автоматов взорвут мозг кому угодно. А если еще программа не написана с нуля, а собрана из кучи чужих исходников, да даже если из своих, но древних и уже забытых.

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

Для примера возьму ту программу, что идет в доке к демоплате Pinboard. Там стоит мой диспетчер очереди, а также немного автоматики на прерываниях. Плюс старая библиотека для HD44780
 

В принципе все с виду работает пучком и никаких косяков. Но одолели меня сомнения, так ли это? Если двигатель вращается, то это еще не значит, что он работает хорошо и без ошибок. Так и у нас, надо проверить, все ли в порядке. Слушать мы будем осциллографом «механику» тиканья службы таймера. Почему его? Ну так вокруг него вся логика программы построена. 

Переназначаем выводы PD4 и PD5 на выход и будем их использовать для своих грязных целей. Для отладки в смысле.

Поставим дрыг импульсом на прерывание таймерной службы и посмотрим насколько красиво и правильно тикает системный таймер. Дискретность которого 1мс. И который определяет почти все выдержки в программе. В общем, прописываем в таймерное прерывание такую байду:
 

1
2
3
4
5
6
OutComp2Int: SBI BTA_P,BTB ; For Debug   TimerService ; Служба таймера диспетчера   CBI BTA_P,BTB ; For Debug RETI

OutComp2Int: SBI BTA_P,BTB ; For Debug TimerService ; Служба таймера диспетчера CBI BTA_P,BTB ; For Debug RETI

Вначале мы ставим бит порта PD4, а перед выходом сбрасываем. Это даст нам время выполнения и частоту выполнения. И тыкаемся нашим осциллографом, глядим:

Обана, а в таймере то глюки есть! Тикать то он тикает и с первого взгляда все нормально. Но почему то у него возникла аритмия и если это сейчас не вылезло, то может вылезти потом, при добавлении новых фич, где от четкости таймера будет многое зависеть.

Причем глюк по времени плавающий, возникающий раз в сколько то сработок. А это значит, мы его трассировкой не поймаем. Можно, конечно, и аналитически протупить в код и найти, но это еще надо знать, что глюк есть.

Да и код может быть такой, что сам черт ногу сломит.
 

Попробуем вычислить кто это нам тут таймер сбивает. Первое что приходит на ум — другое прерывание. Оно во время своей обработки запрещает другие прерывания и может сбить нам таймер. Что там у нас еще есть? Да хотя бы прерывание от АЦП. Выведем как его на вторую отладочную ногу:
 

1
2
3
4
5
6
7
8
9
10
ADC_INT: SBI BTA_P,BTC ; For Debug   PUSH OSRG ; Сохраняем рабчий регистр IN OSRG,ADCH ; Берем данные из АЦП STS ADC_Data,OSRG ; Перекладываем их в ОЗУ POP OSRG ; Восстанавливаем рабочий регистр   CBI BTA_P,BTC ; For Debug   RETI ; Выход из прерывания

ADC_INT: SBI BTA_P,BTC ; For Debug PUSH OSRG ; Сохраняем рабчий регистр IN OSRG,ADCH ; Берем данные из АЦП STS ADC_Data,OSRG ; Перекладываем их в ОЗУ POP OSRG ; Восстанавливаем рабочий регистр CBI BTA_P,BTC ; For Debug RETI ; Выход из прерывания

Это будет дрыганье ногой PD5.
 

Смотрим что получилось:

То же самое, но на аналоговом осциллографе. Там не так наглядно, поэтому не стал выносить в пост и перегружать страницу
 

Как видно из видео, у нас есть проблема — где то в коде есть процедура которая блокирует прерывания. Причем это не атомарный доступ, слишком уж большие задержки.

Скорей что то похожее на цикл ожидания, в котором есть CLI/SEI конструкция. Где то что то я забыл удалить после отладки. Начинаем проглядывать код уже на предмет забытых прерываний.

Мелкие процедурки видны сразу, а крупные, состоящие из нескольких файлов и макросов можно и прощупать.
 

Давайте как пощупаем задачу вывода на экран, переместим дрыгалку туда:
 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
;—————————————————————————– ; Задача обновления экрана дисплея. Дисплей обновляется 5 раз в секунду, каждые 200мс ; данные берутся из видеопамяти и фоном записываются в контроллер HD44780 Fill: SBI BTA_P,BTC ; ForDebug   SetTimerTask TS_Fill,200 ; Самозацикливание задачи через диспетчер таймеров   LCDCLR ; Очистка дисплея   LDZ TextLine1 ; Взять в индекс Z адрес начала видеопамяти   LDI Counter,DWIDTH ; Загрузить счетчик числом символов в строке  
Filling1: LD OSRG,Z+ ; Брать последовательно байты из видеопамяти, увеличивая индекс Z RCALL DATA_WR ; И передавать их дисплею   DEC Counter ; Уменьшить счетчик. BRNE Filling1 ; Пока не будет 0 (строка не кончилась) – повторять   LCD_COORD 0,1 ; Как кончится строка – перевести строку в дисплее   LDI Counter,DWIDTH ; Опять загрузить длинной строки  
Filling2: LD OSRG,Z+ ; Адрес второй строки видеопамяти указывать не надо – они идут друг за другом RCALL DATA_WR ; И таким же макаром залить вторую строку из видеопамяти   DEC Counter ; Уменьшаем счетчик BRNE Filling2 ; Если строка не кончилась – продолжаем.   CBI BTA_P,BTC ; ForDebug RET

;—————————————————————————– ; Задача обновления экрана дисплея.

Дисплей обновляется 5 раз в секунду, каждые 200мс ; данные берутся из видеопамяти и фоном записываются в контроллер HD44780 Fill: SBI BTA_P,BTC ; ForDebug SetTimerTask TS_Fill,200 ; Самозацикливание задачи через диспетчер таймеров LCDCLR ; Очистка дисплея LDZ TextLine1 ; Взять в индекс Z адрес начала видеопамяти LDI Counter,DWIDTH ; Загрузить счетчик числом символов в строке Filling1: LD OSRG,Z+ ; Брать последовательно байты из видеопамяти, увеличивая индекс Z RCALL DATA_WR ; И передавать их дисплею DEC Counter ; Уменьшить счетчик. BRNE Filling1 ; Пока не будет 0 (строка не кончилась) – повторять LCD_COORD 0,1 ; Как кончится строка – перевести строку в дисплее LDI Counter,DWIDTH ; Опять загрузить длинной строки Filling2: LD OSRG,Z+ ; Адрес второй строки видеопамяти указывать не надо – они идут друг за другом RCALL DATA_WR ; И таким же макаром залить вторую строку из видеопамяти DEC Counter ; Уменьшаем счетчик BRNE Filling2 ; Если строка не кончилась – продолжаем. CBI BTA_P,BTC ; ForDebug RET

И смотрим что получилось:
 

Аналоговый вариант данного действа.
 

Как видим, у нас в задаче Fill есть запрет прерываний, который на значительный период блокирует не только таймерную службу, но и прерывания от АЦП и все остальное.

При этом у нас один тик таймерной службы откладывается до тех пор, пока прерывания не разрешат. ВЫполняется, а в этом время уже нащелкало на второй тик и прерывание выполняется еще раз.

Пока катастрофы не случилось, но будь Fill подольше, то мы бы прозевали один тик. А какое то событие уплыло по времени.
 

Это черевато тем, что разные синхронизированные по времени задачи могут глючить, причем глючить не всегда, а только тогда, когда на них выпадает совпадение по времени с Fill. Попробуй такое отловить. Тем более по дефолту то считаем, что Fill работает и не глючит! Ведь раньше то ничего не мешало! Ну ну. Просто условия не создавались нужные.
 

Лезем в lcd4.asm и находим там запреты прерываний почти везде:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
;========================================================================================= BusyWait: CLI ; Ожидание флага занятости контроллера дисплея RCALL PortIn ; Порты на вход   CBI CMD_PORT,RS ; Идет Команда! SBI CMD_PORT,RW ; Чтение!  
 
BusyLoop: SBI CMD_PORT,E ; Поднять строб RCALL LCD_Delay ; Подождать   IN R16,DATA_PIN ; Считать байт   PUSH R16 ; Сохранить его в стек. Дело в том, что у нас R16 убивается в LCD_Delay   CBI CMD_PORT,E ; Бросить строб – первый цикл (старший полубайт) RCALL LCD_Delay ; Подождем маленько   SBI CMD_PORT,E ; Поднимем строб RCALL LCD_Delay ; Подождем CBI CMD_PORT,E ; Опустим строб- нужно для пропуска второго полубайта   RCALL LCD_Delay ; Задержка снова   POP R16 ; А теперь достаем сныканый байт – в нем наш флаг. Может быть.   ANDI R16,0x80 ; Продавливаем по маске. Есть флаг? BRNE BusyLoop ; Если нет, то переход  
BusyNo: SEI ; Разрешаем прерывания. RET

;========================================================================================= BusyWait: CLI ; Ожидание флага занятости контроллера дисплея RCALL PortIn ; Порты на вход CBI CMD_PORT,RS ; Идет Команда! SBI CMD_PORT,RW ; Чтение! BusyLoop: SBI CMD_PORT,E ; Поднять строб RCALL LCD_Delay ; Подождать IN R16,DATA_PIN ; Считать байт PUSH R16 ; Сохранить его в стек. Дело в том, что у нас R16 убивается в LCD_Delay CBI CMD_PORT,E ; Бросить строб – первый цикл (старший полубайт) RCALL LCD_Delay ; Подождем маленько SBI CMD_PORT,E ; Поднимем строб RCALL LCD_Delay ; Подождем CBI CMD_PORT,E ; Опустим строб- нужно для пропуска второго полубайта RCALL LCD_Delay ; Задержка снова POP R16 ; А теперь достаем сныканый байт – в нем наш флаг. Может быть. ANDI R16,0x80 ; Продавливаем по маске. Есть флаг? BRNE BusyLoop ; Если нет, то переход BusyNo: SEI ; Разрешаем прерывания. RET

И это только в процедуре ожидания флага готовности дисплея. Дальше оно есть и в процедуре чтения, записи и по всей библиотеке. Самое страшное, конечно, это в BusyWait т.к. оно зацикливается. Поэтому то и на половине задачи прерывания и срубались.
 

Е..й стыд! И я когда то это написал!? Нет, тогда запрет прерываний был оправдан. Я уже не помню почему, но без него в том случае было никак. Но вот переносить эти CLI/SEI в универсальную библиотеку это был полный маразм.

Кстати, многие кто ее юзал отметили эту фишку с ненужным запретом прерываний. Многие, но далеко не все.

Колитесь, кто не заглядывал в код и подключиле его к своей программе «as is» поленившись проверять и поверив на слово? 😉 Все руки не доходят поправить 😉
 

Правим, заливаем в демоплату новую прошивку. Наблюдаем эффект:

Ничего не сломалось, все отлично работает. Done!
 

Ну и, напоследок, маленький трюк. Я тут вовсю юзаю многоканальный осцилл, а у меня тут еще и 16ти канальный анализатор есть… В общем, полный набор удовольствий. А кто то мучается с одноканальным осциллографом и как тут ему быть?
 

Не беда — можно применить одну хитрость. Обьединить несколько сигналов в один канал. Делается это вот по такой схеме:
 

Работает просто — когда на одном входе единичка, то напряжение с нее течет в землю. Этот ток создает падение напряжения на R3 которое видно на осциллографе.

Когда на входе две единички, то через R3 уже идет ток с двух источников и падение напряжения становится суммой двух сигналов и это явно видно.

Значения резисторов R1 и R2 лучше подбирать так, чтобы они были в пределах одного порядка, но различались раза в полтора-два. Это даст визуальное разделение сигналов и можно будет понять что к чему.
 

У меня же на демоплате я решил заюзать те резисторы, что уже стояли — 500омные на ограничение тока для светодиодов.

А в качестве суммирующего применил один из переменников, выкрутив его на сопротивление около 800Ом. И с него отправил сигнал на осциллографы.

Резисторы там правда правда одинаковые и сигналы будут равные по высоте, но тут у нас по частоте уже понятно кто есть кто, так что не запутаемся 🙂

Вот что получилось:

Таким образом, можно на каждый канал загнать столько сигналов, что в экран не влезут. Правда анализировать их на глазок будет уже сложней. Но где наша не пропадала! 🙂
 

Игры с синхронизацией Также не стоит забывать про такой канал как внешняя синхронизация (Ext Trig) Обычно на него забивают т.к. не находят ему применения. А зря! Например, можно на него вывести какой либо сигнал который тоже надо ловить.

И настроить осцил в такой режим, что без этого сигнала триггер не срабатывает (Normal режим, не Auto). И тогда если сигнала нет, то мы ничего и не увидим.

Отсутствие информации тоже информация — о том, что сигнала нет 🙂 А если есть, то у нас останутся еще два свободных канала на отлов последующих событий.

Также вовсю стоит играться с разными видами синхры. Аналоговые и самые дешевые цифровые ограничены только синхрой по фронтам, да всяким телесигналам.

А вот более продвинутые цифровые, вроде ATTEN или тот же RIGOL (про Лекрои и прочие Тектроники я даже не вспоминаю) умеют синхронизироваться и по длине импульса, по расстоянию между импульсами ,по скорости нарастания/спада сигнала и еще по полудесятку разных параметров.

Ловить ими сбои в работе программ милое дело! Раз уж раззорились на цифроосцил, так юзайте его возможности на все сто! :)))
 

Исходник программы на которой я баловался

Источник: http://easyelectronics.ru/avr-uchebnyj-kurs-otladka-programm-chast-4.html

Еще раз о прерываниях

Структура прерываний типичной персональной ВС проиллюстрирована на рис. 4.

На аппаратном уровне прерывания работают следующим образом.

Когда устройство ввода-вывода заканчивает свою работу, оно инициирует прерывание (при условии, что прерывания разрешены операционной системой). Для этого устройство выставляет сигнал на выделœенную устройству специальную линию шины. Этот сигнал распознается микросхемой контроллера прерываний, расположенной на материнской плате. Контроллер прерываний принимает решение о дальнейших действиях.

При отсутствии других необработанных запросов прерывания контроллер прерываний обрабатывает прерывание немедленно.

В случае если прерывание уже обрабатывается, и в это время приходит запрос от другого устройства по линии с более низким приоритетом, то новый запрос просто игнорируется.

В этом случае устройство продолжает удерживать сигнал прерывания на шинœе до тех пор, пока оно не будет обслужено центральным процессором.

Для обработки прерывания контроллер выставляет на адресную шину номер устройства, требующего к себе внимания, и устанавливает сигнал прерывания на соответствующий контакт процессора.

Этот сигнал заставляет процессор приостановить текущую работу и начать выполнять обработку прерывания. Номер, выставленный на адресную шину, используется в качестве индекса в таблице, называемой вектором прерываний, из которой извлекается новое значение счетчика команд. Новый счетчик команд указывает на начало соответствующей процедуры обработки прерывания.

Обычно с этого места аппаратные и эмулированные прерывания используют один и тот же механизм и часто пользуются одним и тем же вектором. Расположение вектора должна быть либо жестко прошито на аппаратном уровне, либо, напротив – располагаться в произвольном месте памяти, на ĸᴏᴛᴏᴩᴏᴇ указывает специальный регистр процессора, загружаемый операционной системой.

Вскоре после начала своей работы процедура обработки прерываний подтверждает получение прерывания, записывая определœенное значение в порт контроллера прерываний. Это подтверждение разрешает контроллеру издавать новые прерывания.

Благодаря тому, что центральный процессор откладывает выдачу подтверждения до момента͵ когда он уже готов к обработке нового прерывания, удается избежать ситуации состязаний при появлении почти одновременных прерываний от нескольких устройств.

Аппаратура всœегда, прежде чем начать процедуру обработки прерывания, сохраняет определœенную информацию. Сохраняемая информация и место ее хранения широко варьируются исходя из центрального процессора.

Как минимум сохраняется счетчик команд, что позволяет продолжить выполнение прерванного процесса.

Другая крайность представляет собой сохранение всœех программно доступных регистров и большого количества внутренних регистров центрального процессора.

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

В противном случае любое новое прерывание просто стерло бы всю сохраненную таким образом информацию, записав поверх нее новые данные.

В результате прерывания оказываются запрещенными в течение довольно длительных интервалов времени, что приводит к возможному игнорированию некоторых сигналов прерывания от устройств и, соответственно, к возможной потере данных.

По этой причине большинство центральных процессоров сохраняют такую информацию в стеке.

Источник: http://referatwork.ru/category/computer/view/105232_esche_raz_o_preryvaniyah

Записки программиста

Вы могли обратить внимание, что до сих пор при изучении микроконтроллеров STM32 мы как-то обходились исключительно синхронным кодом.

Это может неплохо работать для игрушечных примеров, но при попытке написать что-то действительно полезное без прерываний и таймеров далеко не уедешь. Так что, пришла пора научиться с ними работать.

Должен предупредить, что статья вышла довольно длинной, поскольку тема непростая.<\p>

Немного матчасти

В контексте обсуждения прерываний можно встретить много странных терминов и аббревиатур. Поэтому прежде, чем перейти к примерам, давайте определимся с действующими лицами.

Если на пальцах, то прерывание (оно же Interrupt Request, или IRQ) — это какой-то сигнал, генерируемый по определенному событию, и обычно приводящий к выполнению некого отрывка кода.

Соответствующий отрывок кода называется Interrupt Service Routine (ISR), или просто обработчиком прерывания. Например, прерывание может генерироваться при нажатии пользователем кнопки.

Такие прерывания называют внешними, так как они генерируются внешними по отношению к МК событиями.

За доставку в МК внешних прерываний отвечают специальные куски кремния, называемые External Interrupt / Event Controller, или EXTI.

EXTI0 отвечает за пины PA0, PB0, PC0, и так далее, EXTI1 — за пины PA1, PB1, PC1, и так далее, и по аналогии для остальных пинов.

Некоторым EXTI назначается уникальный ISR, а некоторые делят его с другими EXTI. Подробности следует искать в даташите конкретного МК.

Соответствующая иллюстрация (источник [PDF]):

Важное следствие из этой картинки заключается в том, что у микроконтроллера нет возможности отличить внешние прерывания, случающиеся на пинах, обслуживаемых одним EXTI.

Например, нельзя отличить нажатие кнопки, подключенной к PA0, от нажатия кнопки, подключенной к PB0. Поэтому определять такие «конфликтующие» прерывания не представляется возможным (в частности, STM32CubeMX не позволит вам этого сделать).

Но если одна кнопка подключена к PA0, а вторая к PB1, то пожалуйста.

Прерывания могут возникать и в самом МК. Например, прерывания генерируют аппаратные реализации протоколов I2C, SPI и всех остальных.

Помимо прочего, это позволяет реализовать асинхронную передачу данных.

Также в МК встроены специальные устройства, называемые таймерами, которые умеют генерировать прерывания раз в заданный интервал времени. Таймеры имеют имена вроде TIM1, TIM2, TIM3, и так далее.

Часть микроконтроллера, отвечающая за управление прерываниями, называется Nested Vectored Interrupt Controller, или NVIC, что переводится примерно как Контроллер Вложенных Векторных Прерываний. Название отражает сразу два факта об этом устройстве.

Во-первых, адреса ISR хранятся в специально отведенном участке памяти, называемом vector table. Сам же адрес (то есть, элемент vector table) принято называть вектором. Во-вторых, прерывания имеют настраиваемые приоритеты.

Если во время обработки прерывания придет более приоритетное прерывание, выполняемый в данный момент ISR будет приостановлен, и управление будет передано ISR более приоритетного прерывания.

Когда он отработает, управление будет возвращено обратно в обработчик менее приоритетного прерывания. Отсюда и слово nested (вложенных) в названии устройства.

Сказанное выше можно изобразить в виде такой картинки (источник):

Соответственно, выполнение ISR прерываний с тем же или более низким приоритетом, чем приоритет прерывания, чей ISR сейчас выполняется, откладывается до завершения текущего ISR.

Если одновременно происходит два или более одинаковых прерываний, они «схлопываются» в одно. Другими словами, прерывания не копятся в очереди. Также прерывания не являются re-entrant.

То есть, если сейчас выполняется ISR некого прерывания, при возникновении того же прерывания NVIC дождется завершения ISR и только после этого вызовет его во второй раз.

Есть множество других занятных моментов, но в рамках данной статьи они нам не понадобятся. В этом контексте хотелось бы поблагодарить пользователей форума easyelectronics.

ru, в особенности BusMaster, за то, что объяснили мне тонкости работы прерываний в разных граничных случаях. На этом теории, думаю, достаточно, и можно перейти к примерам.

Примеры были проверены мной на плате Nucleo-F411RE, но с минимальными изменениями будут работать и ну других платах.

Пример использования таймера

В мире STM32 существует по крайней мере девять видов таймеров, из которых основными видами являются basic, general purpose (делятся на 16-и и 32-х битные) и advanced. Таймеры, находящиеся правее в приведенном списке включают в себя функции тех таймеров, что находятся в списке левее.

Например, general purpose таймеры умеют все, что умеют basic таймеры, а также могут использоваться для генерации ШИМ-сигнала.

Чтобы совсем не уходить в дебри, рассмотрим только типичный сценарий использования 16-и битного general purpose таймера, коим является TIM3 (cм табличку в AN4013, «STM32 cross-series timer overview» [PDF]).

Откроем STM32CubeMX и найдем TIM3 во вкладке Pinout. Изменим Clock Source на Internal Clock. Далее идем во вкладку Configuration и снова находим там TIM3.

В поле Prescaler вводим 41999, в Counter Mode выбираем Up, в Counter Period вводим 1000.

В тех же настройках TIM3 находим вкладку NVIC Settings и ставим галочку напротив TIM3 Global Interrupt, тем самым разрешая генерацию прерывания. Теперь давайте попробуем понять, что же означают все эти настройки.

Таймер TIM3 подключен к шине APB1, о чем мы можем узнать, например, из «Table 10. STM32F411xC/xE register boundary addresses» даташита нашего МК [PDF]. Также, открыв в STM32CubeMX вкладку Clock Configuration, мы можем узнать, что часы на этой шине работают на частоте 84 МГц:

Параметр Prescaler, указанный нами выше, используется для деления этой частоты. Чтобы случайно не получить деление на ноль, к этому параметру всегда прибавляется единица. Таким образом, часы будут работать на частоте 2 кГц:

>>> 84000000/(41999+1)
2000.0

Параметр Counter Period определяет, как часто будет выстреливать прерывание, связанное с часами. В нашем случае это будет происходить два раза в секунду:

Наконец, значение Up параметра Counter Mode говорит о том, что значение связанного с часами счетчика должно начинаться с нуля и увеличиваться на единицу 2000 раз в секунду (для нашей конфигурации) до тех пор, пока не достигнет значения Counter Period. В этот момент генерируется прерывание и счетчик обнуляется. Можно и наоборот, считать от Counter Period до нуля, указав в Counter Mode значение Down. Но насколько я могу судить, на практике от этого ничего не меняется.

Генерируем код. Затем в Src/main.c дописываем:

int main(void)
{
  // … пропущено …

  /* Initialize all configured peripherals */

  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_TIM3_Init();

  /* USER CODE BEGIN 2 */

  // добавляем вот эту строчку, запускаем таймер:

  HAL_TIM_Base_Start_IT(&htim3);

  /* USER CODE END 2 */

  // … пропущено …

}

Также правим Src/stm32f4xx_it.c:

void TIM3_IRQHandler(void)
{
  /* USER CODE BEGIN TIM3_IRQn 0 */

  /* USER CODE END TIM3_IRQn 0 */

  HAL_TIM_IRQHandler(&htim3);
  /* USER CODE BEGIN TIM3_IRQn 1 */

  // дописываем вот эту строчку:

  HAL_GPIO_TogglePin(Led1_GPIO_Port, Led1_Pin);

  /* USER CODE END TIM3_IRQn 1 */

}

Как альтернативный вариант, вместо последнего шага можно определить такую процедуру:

/* USER CODE BEGIN 1 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
    if(htim->Instance == TIM3) {
        HAL_GPIO_TogglePin(Led1_GPIO_Port, Led1_Pin);
    }
}
/* USER CODE END 1 */

Эффект будет аналогичным. Эта процедура объявлена с атрибутом __weak в коде HAL, в файле Src/stm32f4xx_hal_tim.c, поэтому наша реализация ее переопределяет. Тема с атрибутом __weak нам уже знакома по заметке Микроконтроллеры STM32: работа с внешним EEPROM. Если вас интересуют прочие колбэки, доступные для переопределения, то их можно найти в том же файле.

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

Использование внешних прерываний

Давайте повесим прерывание на нажатие кнопки. Для этого в STM32CubeMX во вкладке Pinout кликнем на пин PC13 и в появившемся списке выберем GPIO_EXTI13.

Во вкладке Configuration → System → GPIO в GPIO Mode можно выбрать, когда будет приходить прерывание, например, по переднему фронту, заднему фронту, или по обоим. Я выбрал «External Interrupt Mode with Rising/Falling edge trigger detection».

Там же нажимаем кнопку NVIC и включаем прерывание, поставив галочку Enabled напротив «EXTI line[15:10] interrupts».

Генерируем код. Затем правим Src/stm32f4xx_it.c так, чтобы светодиод мигал не все время, как это сделано сейчас, а только пока пользователь держит кнопку нажатой:

/* USER CODE BEGIN 0 */
#include

bool buttonPressed = false;

/* USER CODE END 0 */

// … пропущено …

// в данном случае EXTI10..EXTI15 имеют общий ISR

// но эту процедуру мы не трогаем
void EXTI15_10_IRQHandler(void) {
  /* USER CODE BEGIN EXTI15_10_IRQn 0 */

  /* USER CODE END EXTI15_10_IRQn 0 */

  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);
  /* USER CODE BEGIN EXTI15_10_IRQn 1 */

  /* USER CODE END EXTI15_10_IRQn 1 */

}

/* USER CODE BEGIN 1 */

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
    if (GPIO_Pin == GPIO_PIN_13) {
        buttonPressed = !buttonPressed;
    }  
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {

    if(htim->Instance == TIM3) {
        if(buttonPressed) {
            HAL_GPIO_TogglePin(Led1_GPIO_Port, Led1_Pin);
        }
    }
}
/* USER CODE END 1 */

Компилируем, прошиваем, проверяем. Ради эксперимента можете изменить код так, чтобы прерывание выстреливало, например, только по переднему фронту сигнала. В этом случае нажатие кнопки один раз должно запускать мигание светодиода, а нажатие во второй раз — останавливать мигание.

В контексте внешних прерывание не могу не напомнить о проблеме дребезга контактов. К счастью, бороться с ним довольно просто. Например, так:

volatile static uint32_t lastPress = 0;

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {

    uint32_t tstamp = HAL_GetTick();

    // если кнопка нажимается чаще одного раза в 200 мс,

    // считаем это дребезгом
    if(tstamp – lastPress >> 84000000/(40+1)/256
8003.048780487805

Что примерно совпадает с 8 кГц, которые мы видим на осциллографе. Как и TIM3, использованный нами TIM2 подключен к шине APB1, поэтому в числителе фигурирует 84 МГц. Кроме того, параметр Counter Period определяет количество возможных значений коэффициента заполнения (duty cycle). В приведенном примере мы можем менять его от 0 до 255. На скриншоте используется значение около 150.

Заключение

Если вдруг вам показалось, что теперь-то вы знаете все о прерываниях и таймерах в STM32, боюсь вас огорчить. Как минимум, у прерываний еще есть приоритеты и сабприортитеты, которые можно менять динамически во время работы прошивки. Также прерывания можно временно отключать (маскировать).

Таймеры могут использовать в качестве источника сигнала не только internal clock, но и другие таймеры, а также внешние источники. А еще у таймеров есть режимы работы, которые не были рассмотрены в данной статье, в частности input capture mode и output compare mode.

Кроме того, таймеры в STM32 имеют специальные режимы для чтения роторных энкодеров и датчиков Холла.

Понятно, что все это невозможно рассмотреть в рамках одного поста. В качестве дополнительного источника информации можно порекомендовать книгу Mastering STM32 за авторством Carmine Noviello. Правда, даже она покрывает далеко не все, и отправляет за дополнительной информацией в даташиты и application notes.

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

Источник: https://eax.me/stm32-interrupts-timers-pwm/

Валерия Михайлова. «Глубинный смысл прерывания беременности» / Православие.Ru

Одна знакомая мне старушка делала аборты пять раз – в те времена их делали все: их прописывали, как вырывание зубов. Но один из своих абортов она очень часто потом вспоминала, всегда при этом плача. «Кусая локти»…

Дело было весенним днем. Кажется, тайком от мужа, узнав об очередной беременности, она пошла на «обычную операцию» по ее прерыванию. Взяла с собой двух своих детей дошкольного возраста, поскольку оставить малюток было не с кем. И вот дети остались ждать внизу, в больничном дворе, пока вернется их мама. Женщина поднялась в кабинет, все уже было готово к процедуре.

А медсестра возьми да выгляни в окно! Увидела двух смугленьких, большеглазых карапузов и говорит этой женщине: «Это ваши дети – мальчик и девочка?» – «Да, мои». – «Вы знаете, я никому этого ни разу не говорила, но вам скажу: не делайте аборт. Послушайте, у вас такие красивые дети… А будет третий, такой же хорошенький. Я вас очень прошу, подумайте. Не делайте…

»

Женщина все-таки аборт сделала – «ну куда третьего, куда?».. И в 75 лет слезы у нее лились градом, когда она вспоминала этот диалог в абортарии…

Как же бесконечно жаль ее было в те моменты! Она плакала и говорила: «Я же не знала, я не знала, что делаю! Нам ведь говорили, что это просто операция, несложная процедура. На первый аборт меня вообще мама отвела. Никто даже не думал, что мы детей своих убиваем, – никто мне не сказал об этом!»

И это действительно так. У многих тогда не было возможности задуматься об этом: аборты стали негласной нормой.

Но у современной женщины такая возможность задуматься есть. Интернет, Википедия, плакаты в метро, в поликлиниках, кабинеты психолога при абортариях и женских консультациях… Вряд ли хоть кто-то сегодня может сказать, что ни разу не слышал о словах «аборт» и «убийство», стоящих в связке. А почему же они не действуют?

«Глубинный смысл прерывания беременности»

Слова вообще очень многое значат в жизни. Поставьте рядом «аборт» и «убийство» – срабатывает один ассоциативный и эмоциональный ряд. Но ведь рядом можно поставить совсем другие слова.

Как это сделал, например, один красочный журнал по психологии. На днях редакция объявила конкурс «Стань автором», участникам было предложено множество тем на выбор. И одна из тем задана следующим образом: «Глубинный смысл прерывания беременности в том, что этот опыт раскрывает в женщине ее подлинное Я».

Смотрите, как интересно. Ведь раскрытие своего «я» – безусловная добродетель, с точки зрения психологии и здравого смысла. Познавать себя – хорошо, нужно, полезно, единственно верно. И редактор ставит в один ряд самораскрытие, «глубинный смысл», «опыт» и… аборт.

Вроде не подкопаешься – никто же не соврал! А что в итоге откладывается у нас с вами в головах? Хорошо + плохо = не так уж плохо.

Оказывается, и в аборте есть глубинный смысл! Да и слово «аборт» звучит грубовато и жестко, на него уже налипли негативные и пугающие ассоциации, куда мягче и деликатней – «прерывание беременности», правда?

Этот трюк – не что иное, как языковая манипуляция. Более тонкий, более изощренный способ объяснить сомневающейся женщине, что убить ребенка – …как бы чуть ли не «обратимо», во всяком случае, это опыт, и в нем есть смысл. Все не так плохо, не забивай голову религиозными «пугалками», дорогая!

Есть такая метода – «окна Овертона». Это способ постепенно сделать то или иное понятие из абсолютно неприемлемого – приемлемым, а часто и одобряемым. Способ заключается в том, чтобы потихоньку менять тот ключ, в котором говорится о предмете.

Сначала о нем просто много говорят, то есть из табуированного, каким был прежде, он становится обсуждаемым.

Потом, когда люди привыкли, появляется вариативность отношения к предмету: «Друзья, давайте не осуждать, давайте не закидывать камнями, будем терпимы, всяко бывает!» Позже предмет стараются ввести в ранг варианта нормы: есть такие люди, есть другие; есть такое поведение, есть другое.

И наступает момент, когда общество уже ополчается на тех, кто ставит новый взгляд под сомнение: «Ты что?! У нас же свобода, права… Да ты мракобес!» По этой схеме были легализованы гомосексуализм, эвтаназия; вполне вероятно, что на очереди педофилия, зоофилия, право на самоубийство и т.д. Нормы меняются, а все начинается – со слов и смысловых связок. И о слове «свобода» мы обязательно поговорим далее.

Метод «Лалала»

Есть более грубый метод.

Помните, в детстве, когда мы хотели донести до надоедливого сверстника, что его мнение нам неинтересно, мы затыкали уши и начинали громко, с упоением тараторить: «Лалалалааа! Ничего не слышу, я тебя не слышу, лалалаа!» Метод «Лалала» давал просто поразительные результаты.

И работает он не только у детей, но и у взрослых. «Лалалала, не хочу задумываться о смерти. Лалала, Бога все равно нет»; «Лалалааа, аборт – это такая же медицинская процедура, как вырвать зуб, лалала! А еще обрезать ногти или волосы – то же самое!»

Аборт и удаление зуба – процедуры одного порядка? А зуб может отрастить ножки, ручки, сказать: «Мама»?

Поразительным образом логика отказывает многим людям – хорошим и неглупым, – когда речь заходит о таких предметах, как Бог, вечная жизнь, нравственные нормы. Вырвать зуб и прервать беременность – вещи одного порядка? Друзья, ну подумайте.

Из вашего кариозного вырванного зуба, посеченного состриженного волоса когда-нибудь что-нибудь может вдруг волшебным образом вырасти, преобразиться в мыслящее существо? Может такое быть, что ваш зуб однажды отрастит ножки, ручки, выпучит глазки и умилительно скажет вам свое первое «Мама»? Все же вряд ли, согласитесь! Зуб останется зубом. Волос волосом. Ноготь ногтем.

А вот то существо, «сгусток клеток», эмбрион, плод – назовите как угодно, – которое вы с зубом сравниваете, через девять месяцев скажет: «Уа! Уа!», через 18 лет пойдет собирать-разбирать автомат Калашникова в армию, через 19 – поступит на мехмат МГУ, на первом курсе женится под ваши негодующие крики и принесет внуков на радость вам и окружающим.

Еще Аристотель предлагал рассуждать о вещах не как о чем-то сиюминутном, а с точки зрения перспективы, цели – а уж его в отсутствии логики упрекнуть трудно.

Ну подумайте еще, друзья! Вот перед вами стоят шесть человек: три брата и три сестры. Все выросли, у каждого своя судьба, свой характер, свои планы на будущее.

Кто из них вам меньше всего нравится, а? Давайте, чтобы долго не думать, младшего брата и младшую сестру уберем, так сказать, сотрем с лица нашей прекрасной планеты.

Ведь это то же самое – только в случае «прерывания беременности» выбор вы делаете на определенное количество лет раньше.

Все настолько становится на свои места, когда даешь себе труд подумать…

А что, как правило, в ответ? «Лалалалаа».

Кто освободил мужчину от ответственности?

Но оставим в покое женщину.

Ведь в одном ряду с врачами, которые извлекают из женской матки части исковерканной человеческой плоти, с теми родственниками и, может быть, даже мужьями, которые подталкивают женщину на аборт – «Я уйду от тебя, мне не нужен ребенок!»; «Нечего нищету плодить», – в одном ряду с государством, которое далеко не всегда и не всем создает такие условия, при которых ребенок не снижал бы и без того низкий уровень жизни миллионов наших соотечественников… В этом ряду стоят молодые (иногда и зрелые) мужчины и парни, от которых «залетают» женщины, вступая в необременительные, легкие отношения. Абсолютные и непременные соучастники прерывания огромного количества беременностей.

Неужели мужчина в 18–30 лет не знает, откуда берутся дети? Не предполагает такой возможности, особенно если избранница молода и пышет женским здоровьем? Ведь что это, как не тот же детский способ отношения к жизни: «Лалалала, я не слышу, я не слышу!» Или просто беда в том, что такой мир, так принято, так все делают и выбраться из матрицы этих «так» самостоятельно, непредвзято подумать – очень и очень непросто?

А ведь логическая цепочка нехитрая. Женщины беременеют от соития с мужчиной – даже порой от так называемого «защищенного». Факт.

Заводя соответствующие отношения, ты готов стать отцом и заботиться об этой женщине и вашем ребенке? Нет? Тогда пошел вон! Какой может быть разговор? Ведь иначе в какую ситуацию ты ставишь свою возлюбленную? Вы оба знаете, что не готовы прожить вместе до последнего вздоха, делить дни горя и радости, последнюю краюху хлеба; она вполне осознаёт, что ты не станешь ей опорой и стеной, не готов позаботиться о ней и ребенке… Так что же сделает такая женщина, когда не начнется у нее следующий месячный цикл, зато резко обострится нюх, различающий все на свете запахи? Правильно: она испугается. Нет опоры, нет мужа, впереди – непонятная, пугающая, нераспланированная жизнь. Конечно, по проторенной дорожке в абортарий пройдут еще одни женские сапожки, и «возлюбленный» узнает об этом в sms-ке, если вообще узнает.

Безусловно, таков выбор женщины. Но и мужчины. И его не меньшая ответственность.

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

Священное слово «свобода» и одинокая старость

Весь антиабортный гнев верующих (и неверующих) можно легко разбить одним словом: свобода. Ведь это священное слово. И оно действительно священно – и для атеистов, и для верующих. Свобода – неотъемлемая принадлежность человеческой личности. Но вместе с тем, по меткому выражению одного журналиста, «свобода и ответственность – две стороны одной и той же монеты: без второй нет первой».

Ответственность рано или поздно наступает. Готовы ли мы к ней? Или воображаем, что готовы? Это же не ответственность за несвоевременно вырванный зуб, а за то, взял ты на себя право прекратить жизнь или дал жизнь. А ведь и психологи признают, что самое большее, что нам дали наши родители, – это жизнь, все остальное мы можем взять сами…

И дальнейшее – это следствие выбора, который в своей жизни делает человек. Аборт – такой же выбор. И когда придется за него ответить и как – Бог знает!

Я не имею морального права препарировать судьбы людей и искать в них железобетонные причинно-следственные связи, но еще одна картина стоит у меня перед глазами, когда речь заходит об абортах.

Старенькая бабушка (другая – не та, о которой я писала вначале), очень хорошая, юморная, серьезно болеет, с трудом встает с кровати, живет одна. Совсем одна. Ее дочь живет в соседней квартире, на одной с матерью лестничной клетке, и перед отпуском приходит, чтоб перенести в бабушкину квартиру все свои цветы – чтобы та поливала.

На день рождения и праздники дарит подарки. В том же районе живут внучка и правнучка, которые чаще заезжают в гости. Но постоянно, приходя два-три раза в неделю, ухаживают за бабушкой абсолютно посторонние люди – волонтеры.

Они ее моют, готовят ей еду, покупают продукты и лекарства, убирают постель, стирают, покупают ночнушки и халаты взамен прохудившихся, приводят священника, чтобы причастил. В общем, вы поняли: ухаживают – волонтеры. Это просто факт, судите о нем, как хотите.

Никому из волонтеров в голову не приходило искать какие-то причины такой семейной трагедии этой несчастной женщины – это абсолютно не их дело. Но вот сама она однажды сказала: «Наверное, если б я не сделала все эти аборты, мои детки сейчас бы ухаживали за мной»…

Источник: http://www.pravoslavie.ru/92282.html

Ссылка на основную публикацию
Adblock
detector
",css:{backgroundColor:"#000",opacity:.6}},container:{block:void 0,tpl:"
"},wrap:void 0,body:void 0,errors:{tpl:"
",autoclose_delay:2e3,ajax_unsuccessful_load:"Error"},openEffect:{type:"fade",speed:400},closeEffect:{type:"fade",speed:400},beforeOpen:n.noop,afterOpen:n.noop,beforeClose:n.noop,afterClose:n.noop,afterLoading:n.noop,afterLoadingOnShow:n.noop,errorLoading:n.noop},o=0,p=n([]),h={isEventOut:function(a,b){var c=!0;return n(a).each(function(){n(b.target).get(0)==n(this).get(0)&&(c=!1),0==n(b.target).closest("HTML",n(this).get(0)).length&&(c=!1)}),c}},q={getParentEl:function(a){var b=n(a);return b.data("arcticmodal")?b:(b=n(a).closest(".arcticmodal-container").data("arcticmodalParentEl"),!!b&&b)},transition:function(a,b,c,d){switch(d=null==d?n.noop:d,c.type){case"fade":"show"==b?a.fadeIn(c.speed,d):a.fadeOut(c.speed,d);break;case"none":"show"==b?a.show():a.hide(),d();}},prepare_body:function(a,b){n(".arcticmodal-close",a.body).unbind("click.arcticmodal").bind("click.arcticmodal",function(){return b.arcticmodal("close"),!1})},init_el:function(d,a){var b=d.data("arcticmodal");if(!b){if(b=a,o++,b.modalID=o,b.overlay.block=n(b.overlay.tpl),b.overlay.block.css(b.overlay.css),b.container.block=n(b.container.tpl),b.body=n(".arcticmodal-container_i2",b.container.block),a.clone?b.body.html(d.clone(!0)):(d.before("
"),b.body.html(d)),q.prepare_body(b,d),b.closeOnOverlayClick&&b.overlay.block.add(b.container.block).click(function(a){h.isEventOut(n(">*",b.body),a)&&d.arcticmodal("close")}),b.container.block.data("arcticmodalParentEl",d),d.data("arcticmodal",b),p=n.merge(p,d),n.proxy(e.show,d)(),"html"==b.type)return d;if(null!=b.ajax.beforeSend){var c=b.ajax.beforeSend;delete b.ajax.beforeSend}if(null!=b.ajax.success){var f=b.ajax.success;delete b.ajax.success}if(null!=b.ajax.error){var g=b.ajax.error;delete b.ajax.error}var j=n.extend(!0,{url:b.url,beforeSend:function(){null==c?b.body.html("
"):c(b,d)},success:function(c){d.trigger("afterLoading"),b.afterLoading(b,d,c),null==f?b.body.html(c):f(b,d,c),q.prepare_body(b,d),d.trigger("afterLoadingOnShow"),b.afterLoadingOnShow(b,d,c)},error:function(){d.trigger("errorLoading"),b.errorLoading(b,d),null==g?(b.body.html(b.errors.tpl),n(".arcticmodal-error",b.body).html(b.errors.ajax_unsuccessful_load),n(".arcticmodal-close",b.body).click(function(){return d.arcticmodal("close"),!1}),b.errors.autoclose_delay&&setTimeout(function(){d.arcticmodal("close")},b.errors.autoclose_delay)):g(b,d)}},b.ajax);b.ajax_request=n.ajax(j),d.data("arcticmodal",b)}},init:function(b){if(b=n.extend(!0,{},a,b),!n.isFunction(this))return this.each(function(){q.init_el(n(this),n.extend(!0,{},b))});if(null==b)return void n.error("jquery.arcticmodal: Uncorrect parameters");if(""==b.type)return void n.error("jquery.arcticmodal: Don't set parameter \"type\"");switch(b.type){case"html":if(""==b.content)return void n.error("jquery.arcticmodal: Don't set parameter \"content\"");var e=b.content;return b.content="",q.init_el(n(e),b);case"ajax":return""==b.url?void n.error("jquery.arcticmodal: Don't set parameter \"url\""):q.init_el(n("
"),b);}}},e={show:function(){var a=q.getParentEl(this);if(!1===a)return void n.error("jquery.arcticmodal: Uncorrect call");var b=a.data("arcticmodal");if(b.overlay.block.hide(),b.container.block.hide(),n("BODY").append(b.overlay.block),n("BODY").append(b.container.block),b.beforeOpen(b,a),a.trigger("beforeOpen"),"hidden"!=b.wrap.css("overflow")){b.wrap.data("arcticmodalOverflow",b.wrap.css("overflow"));var c=b.wrap.outerWidth(!0);b.wrap.css("overflow","hidden");var d=b.wrap.outerWidth(!0);d!=c&&b.wrap.css("marginRight",d-c+"px")}return p.not(a).each(function(){var a=n(this).data("arcticmodal");a.overlay.block.hide()}),q.transition(b.overlay.block,"show",1*")),b.overlay.block.remove(),b.container.block.remove(),a.data("arcticmodal",null),n(".arcticmodal-container").length||(b.wrap.data("arcticmodalOverflow")&&b.wrap.css("overflow",b.wrap.data("arcticmodalOverflow")),b.wrap.css("marginRight",0))}),"ajax"==b.type&&b.ajax_request.abort(),p=p.not(a))})},setDefault:function(b){n.extend(!0,a,b)}};n(function(){a.wrap=n(document.all&&!document.querySelector?"html":"body")}),n(document).bind("keyup.arcticmodal",function(d){var a=p.last();if(a.length){var b=a.data("arcticmodal");b.closeOnEsc&&27===d.keyCode&&a.arcticmodal("close")}}),n.arcticmodal=n.fn.arcticmodal=function(a){return e[a]?e[a].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof a&&a?void n.error("jquery.arcticmodal: Method "+a+" does not exist"):q.init.apply(this,arguments)}}(jQuery)}var debugMode="undefined"!=typeof debugFlatPM&&debugFlatPM,duplicateMode="undefined"!=typeof duplicateFlatPM&&duplicateFlatPM,countMode="undefined"!=typeof countFlatPM&&countFlatPM;document["wri"+"te"]=function(a){let b=document.createElement("div");jQuery(document.currentScript).after(b),flatPM_setHTML(b,a),jQuery(b).contents().unwrap()};function flatPM_sticky(c,d,e=0){function f(){if(null==a){let b=getComputedStyle(g,""),c="";for(let a=0;a=b.top-h?b.top-h{const d=c.split("=");return d[0]===a?decodeURIComponent(d[1]):b},""),c=""==b?void 0:b;return c}function flatPM_testCookie(){let a="test_56445";try{return localStorage.setItem(a,a),localStorage.removeItem(a),!0}catch(a){return!1}}function flatPM_grep(a,b,c){return jQuery.grep(a,(a,d)=>c?d==b:0==(d+1)%b)}function flatPM_random(a,b){return Math.floor(Math.random()*(b-a+1))+a}