Порты ввода/вывода GPIO в STM32 имеют по 16 линий, каждая из которых может быть настроена необходимым образом. Поддерживаются функции цифрового ввода, цифрового вывода, входа внешнего прерывания, а также функции ввода/вывода других модулей микроконтроллера. Программирование STM32 для работы с GPIO основано на использовании регистров конфигурации, чтения, записи, защиты конфигурации и регистра битового доступа.
Port configuration register low (GPIOx_CRL) (x=A..G)
Port configuration register high (GPIOx_CRH) (x=A..G)
Для программирования режимов работы портов ввода/вывода STM32, используются два 32 разрядных регистра для каждого GPIO. Они позволяют произвольно настроить режим работы любой отдельной линии. Регистр GPIOx_CRL отвечает за линии с номерами от 0 до 7, GPIOx_CRH – за линии 8-15. Для каждой из них в регистре имеется два двухразрядных поля CNFy[1:0] и MODEy[1:0]. Первое определяет тип работы линии, второе – направление обмена по линии. все биты доступны для чтения/записи.
Регистр GPIOx_CRL
Бит регистра |
31 |
30 |
29 |
28 |
27 |
26 |
25 |
24 |
23 |
22 |
21 |
20 |
19 |
18 |
17 |
16 |
Поле |
CNF7[1:0] |
MODE7[1:0] |
CNF6[1:0] |
MODE6[1:0] |
CNF5[1:0] |
MODE5[1:0] |
CNF4[1:0] |
MODE4[1:0] |
||||||||
Линия ввода/вывода |
7 |
6 |
5 |
4 |
||||||||||||
Бит регистра |
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
Поле |
CNF3[1:0] |
MODE3[1:0] |
CNF2[1:0] |
MODE2[1:0] |
CNF1[1:0] |
MODE1[1:0] |
CNF0[1:0] |
MODE0[1:0] |
||||||||
Линия ввода/вывода |
3 |
2 |
1 |
0 |
Бит регистра |
31 |
30 |
29 |
28 |
27 |
|
25 |
24 |
23 |
22 |
21 |
20 |
19 |
18 |
17 |
16 |
Поле |
CNF15[1:0] |
MODE15[1:0] |
CNF14[1:0] |
MODE14[1:0] |
CNF13[1:0] |
MODE12[1:0] |
CNF12[1:0] |
MODE12[1:0] |
||||||||
Линия ввода/вывода |
15 |
14 |
13 |
12 |
||||||||||||
Бит регистра |
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
Поле |
CNF11[1:0] |
MODE11[1:0] |
CNF10[1:0] |
MODE10[1:0] |
CNF9[1:0] |
MODE9[1:0] |
CNF8[1:0] |
MODE8[1:0] |
||||||||
Линия ввода/вывода |
11 |
10 |
9 |
8 |
Поле MODEy[1:0] может принимать следующие значения:
Поле CNFy[1:0] зависит от направления передачи. При работе на вход (MODEy[1:0]=0) доступны следующие состояния:
При работе на выход (MODEy[1:0]>0) поле CNFy[1:0] может иметь следующие состояния:
Port configuration lock register (GPIOx_LCKR) (x=A. .G)
Бит |
31 |
30 |
29 |
28 |
27 |
26 |
25 |
24 |
23 |
22 |
21 |
20 |
19 |
18 |
17 |
16 |
Поле |
Резерв |
LCKK |
||||||||||||||
Бит |
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
Поле |
LCK15 |
LCK14 |
LCK13 |
LCK12 |
LCK11 |
LCK10 |
LCK9 |
LCK8 |
LCK7 |
LCK6 |
LCK5 |
LCK4 |
LCK3 |
LCK2 |
LCK1 |
LCK1 |
Установить блокируемый бит в GPIOx_LCKRДля невозможности изменения настроек порта в микроконтроллерах STM32 используется регистр GPIOx_LCKR. Его младщие 15 бит отвечают за соответсвующие линии порта ввода/вывода. Бит 16, установленный в 1, разрешает блокировку изменения настроек. все биты доступны на чтение/запись. Для усложнения жизни пользователям 😉, используется специальный алгоритм установки защиты. Если он применен, то следующее изменение конфигурации доступно только после сброса. Алгоритм установки защиты выглядит следующим образом:
В отличие от привычных 8-ми битных моделей, в STM32 имеется несколько регистров, отвечающих за состояние линий порта ввода вывода. Условно они разделены на две группы – регистры порта и регистры установки отдельных битов.
Port output data register (GPIOx_ODR) (x=A. .G)
Бит |
31 |
30 |
29 |
28 |
27 |
26 |
25 |
24 |
23 |
22 |
21 |
20 |
19 |
18 |
17 |
16 |
Поле |
Резерв |
|||||||||||||||
Бит |
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
Поле |
ODR15 |
ODR14 |
ODR13 |
ODR12 |
ODR11 |
ODR10 |
ODR9 |
ODR8 |
ODR7 |
ODR6 |
ODR5 |
ODR4 |
ODR3 |
ODR2 |
ODR1 |
ODR0 |
Данный регистр имеет разрядность 32, но используются только младшие 16 бит. Биты с 16 по 31 не используются. При записи в GPIOx_ODR какого-либо значения, это значение устанавливается на выходных линиях соответствующего порта. Биты регистра доступны только для чтения/записи.
Port input data register (GPIOx_IDR) (x=A..G)
Бит | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Поле | Резерв | |||||||||||||||
Бит | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 1 |
Поле | IDR15 | IDR14 | IDR13 | IDR12 | IDR11 | IDR10 | IDR9 | IDR8 | IDR7 | IDR6 | IDR5 | IDR4 | IDR3 | IDR2 | IDR1 | IDR0 |
Аналогично регистру выхода, регистр входа имеет толь 16 младших действующих бит из 32. Чтение GPIOx_IDR возвращает значение состояния всех линий порта. Биты регистра доступны только для чтения.
Port bit set/reset register (GPIOx_BSRR) (x=A..G)
Бит | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Поле | BR15 | BR14 | BR13 | BR12 | BR11 | BR10 | BR9 | BR8 | BR7 | BR6 | BR5 | BR4 | BR3 | BR2 | BR1 | BR0 |
Бит | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 1 |
Поле | BS15 | BS14 | BS13 | BS12 | BS11 | BS10 | BS9 | BS8 | BS7 | BS6 | BS5 | BS4 | BS3 | BS2 | BS1 | BS0 |
Данный регистр позволяет обращаться к конкретной линии ввода вывода микроконтроллера STM32. Запись единицы в один из старших разрядов сбрасывает выход линии, а запись единицы в младшие разряды устанавливает высокий уровень сигнала на соответствующей линии. Запись в регистр производится в формате слова, при этом нулевые биты никакого действия не оказывают. Биты регистра доступны только для записи.
Port bit reset register (GPIOx_BRR) (x=A..G)
Бит | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Поле | Резерв | |||||||||||||||
Бит | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 1 |
Поле | BR15 | BR14 | BR13 | BR12 | BR11 | BR10 | BR9 | BR8 | BR7 | BR6 | BR5 | BR4 | BR3 | BR2 | BR1 | BR0 |
Данный регистр производит сброс высокого уровня линии, установленной в регистре GPIOx_ODR. Задействованы только младшие 16 бит, доступных только для записи.
STM32. Работа с базовыми портами ввода/вывода. Примеры.
Первый проект на STM32 Discovery.
You have no rights to post comments
Каждый порт STM32 состоит из 16 выводов, а каждый вывод может быть сконфигурирован одним из 8 способов.
Ниже изображена структура порта ввода-вывода.
Для того чтобы порт заработал его надо подключить к шине APB2, установив соответствующий бит IOPxEN, в регистре разрешения тактирования периферийных блоков RCC_APB2ENR.
RCC->APB2ENR |= RCC_APB2ENR_IOPxEN; // Разрешить тактирование PORTx.
После включения все выводы находятся в состоянии плавающего входа, он же высокоимпедансный вход, он же Hi-Z, он же третье состояние.
В режиме входа
В режиме выхода
В режиме альтернативной функции
Из таблицы видно, что возможны два варианта конфигурации, в режиме альтернативной функции: Push Pull и Open Drain. Например, мы хотим, настроить в режим альтернативной функции ножку, отвечающую за приём данных по USART. Для этого в Reference Manual RM0008, начиная с 161 страницы, идут таблицы, в которых можно посмотреть как cконфигурировать вывод, для разной периферии.
Нам подойдет Input floating или Input pull-up.
Конфигурация выводов задаётся в регистрах GPIOx_CRL, GPIOx_CRH, в этих регистрах для конфигурации каждого вывода отведено 4 бита, MODE[1:0] и CNF[1:0]. В GPIOx_CRL конфигурируются выводы с 0 по 7, а в GPIOx_CRH с 8 по 15.
Если MODE[1:0] = 00, то вывод настроен на вход, конфигурация входа в таком случае задаётся в регистрах CNF[1:0]. Если MODE[1:0] не равен 00, в таком случае вывод настроен как выход, а значение MODE [1:0] задаёт максимальную частоту, с которой может он переключаться.
//Полагаем что выводы после сброса в режиме плавающего входа //разрешаем тактирование порта A RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; //вход с подтяжкой к + GPIOA->CRL &= ~GPIO_CRL_CNF0; GPIOA->CRL |= GPIO_CRL_CNF0_1; GPIOA->ODR |= GPIO_ODR_ODR0; //вход с подтяжкой к - GPIOA->CRL &= ~GPIO_CRL_CNF1; GPIOA->CRL |= GPIO_CRL_CNF1_1; GPIOA->ODR &= ~GPIO_ODR_ODR1; //аналоговый режим GPIOA->CRL &= ~GPIO_CRL_CNF2; //выход с открытым стоком 2MHz GPIOA->CRL &= ~GPIO_CRL_CNF3; GPIOA->CRL |= GPIO_CRL_CNF3_0; GPIOA->CRL |= GPIO_CRL_MODE3_1; //двухтактный выход 10MHz GPIOA->CRL &= ~GPIO_CRL_CNF4; GPIOA->CRL |= GPIO_CRL_MODE4_0; //альтернативная ф-ция, двухтактный выход, 50 MHz GPIOA->CRL &= ~GPIO_CRL_CNF5; GPIOA->CRL |= GPIO_CRL_CNF5_1; GPIOA->CRL |= GPIO_CRL_MODE5; //альтернативная ф-ция, выход с открытым стоком, 50 MHz GPIOA->CRL |= GPIO_CRL_CNF6; GPIOA->CRL |= GPIO_CRL_MODE6;
Считать состояние входа можно с помощью Port input data register или коротко GPIOx_IDR, где x – название порта, может быть от A до G. Считать состояние любого вывода можно из 16 младших бит, старшие 16 бит не используются.
//проверяем значение нулевого вывода порта А if (GPIOА->IDR & GPIO_IDR_IDR0)
Если порт настроен на выход, управлять его состоянием можно с помощью регистра Port output data register или GPIOx_ODR. Значение, которое мы запишем в этот регистр, появится на соответствующих выводах порта. Для установки состояния порта, выделены 16 младших бит, старшие 16 бит не используются.
//если вывод в режиме входа то активируется подтяжка к питанию GPIOA->ODR |= GPIO_ODR_ODR0; //или к земле GPIOA->ODR &= ~GPIO_ODR_ODR0; //если в режиме выхода, то на нём установится соответствующий лог.уровень //например так можно установить все выходы порта в 1 GPIOA->ODR = 0xFFFF;
В STM32 возможно атомарно управлять отдельными битами порта с помощью регистров GPIOx_BSRR (Port Bit Set/Reset Register) и GPIOx_BRR (Port Bit Reset Register).
Для установки отдельного бита порта вручную, надо считать значение порта, изменить нужный бит с помощью маски и результат вернуть обратно в GPIOx_ODR. Так как действий целых три, то возникшее между ними прерывание, может подпортить данные. С помощью описанных выше регистров, это делается в одно действие.
Для сброса бита надо в нулевой бит GPIOx_BRR записать единичку, при этом в нулевой бит GPIOx_ODR запишется 0, для этой операции выделены младшие 16 бит, старшие 16 бит не используются.
//сбросить нулевой бит порта А GPIOA->BRR = GPIO_BRR_BR0;
С GPIOx_BSRR всё чуть интереснее, младшие 16 бит отвечают за установку 1, старшие 16 бит за сброс в 0. Чтобы установить 1 в нулевой бит, надо в нулевой бит GPIOx_BSRR записать 1. Чтобы установить 0 в нулевой бит, надо в 16 бит установить 1.
//сбросить нулевой бит GPIOA->BSRR = GPIO_BSRR_BR0; //установить нулевой бит GPIOA->BSRR = GPIO_BSRR_BS0;
У STM32 есть возможность защитить конфигурацию порта от изменения, для этого выделен регистр GPIOx_LCKR. Младшие 16 бит используются для выбора вывода, который хотим заблокировать (выбор бита осуществляется установкой единицы), затем специальной последовательностью записей в 16 бит(LCKK) осуществляется блокировка.
Последовательность следующая: записать в LCKK 1 , записать 0 ,записать 1, затем из регистра LCKR считать 0, считать 1. Последняя считанная единица говорит о том, что вывод заблокирован. Разблокировка вывода произойдёт только после перезагрузки контроллера.
#include "stm32f10x.h" uint32_t temp; int main(void) { //разрешаем тактирование порта RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; //настраиваем как двухтактный выход GPIOA->CRL &= ~GPIO_CRL_CNF0; //с максимальной частотой 50MHz GPIOA->CRL |= GPIO_CRL_MODE0; //выбираем вывод который хотим залочить GPIOA->LCKR |= GPIO_LCKR_LCK0; //записываем 1 GPIOA->LCKR |= GPIO_LCKR_LCKK; //записываем 0 GPIOA->LCKR &= ~GPIO_LCKR_LCKK; //записываем 1 GPIOA->LCKR |= GPIO_LCKR_LCKK; //считываем 2 раза temp = GPIOA->LCKR; temp = GPIOA->LCKR; }
Для получения более подробной информации можно обратиться Reference Manual RM0008, к разделу General-purpose and alternate-function I/Os (GPIOs and AFIOs).
Анализ портовОпубликовано Шавон Шахрияр |
В любом микроконтроллере есть хотя бы один порт ввода-вывода общего назначения. STM32 не другая порода и, как и ожидалось, также имеет несколько портов GPIO. Эти порты обычно называются GPIOA, GPIOB и т. д., но в отличие от большинства 8/16-битных микропроцессоров эти порты имеют ширину 16 бит. Таким образом, в общем случае каждый порт имеет 16 контактов ввода-вывода. Выводы портов имеют несколько режимов работы, и именно это делает их одновременно надежными и сложными. В макетных платах имена контактов порта ввода-вывода сокращены, поэтому вместо GPIOA0, GPIOB12 и т. д. мы найдем PA0, PB12 и т. д. Даже в справочных руководствах это короткое наименование широко используется. В конце концов, каждый контакт ввода-вывода по своей природе является универсальным.
Ключевые точки с GPIO STM32
Регистр CRL:
Регистр CRH:
Регистр ODR:
Регистр IDR:
Регистр включения периферийных часов APB2 (RCC_APB2ENR):
Регистр включения часов периферийных устройств APB1 (RCC_APB1ENR):
регистр включения часов (AHB0BENR ) 025
MikroC для ARM имеет встроенную библиотеку для GPIO. Хотя с такими библиотеками легко начать работу, даже не имея представления о внутренних регистрах, они требуют много места и времени выполнения. Таким образом, для простых работ лучше всего избегать их, если только их использование не упрощает понимание и работу с большой программой.
Пример программы
Программа будет просто мигать светодиодом, подключенным к PB15, с временем включения и выключения 200 мс, пока не будет нажата кнопка, подключенная к PA0. При нажатии кнопки время задержки изменяется на 600 мс вместо 200 мс. Задержка 600 мс сохраняется до тех пор, пока кнопка не будет отпущена.
Микросхема STM32F108C8, встроенная в макетную плату mini ARM от LC Technology, использовалась в этой демонстрации.
Примеры кода STM32 GPIO
Демонстрационный видеоклип: https://www.youtube.com/watch?v=X8jLZYZCCQw
Удачного кодирования STM32.
Репозиторий: https://github. com/sshahryiar/STM32-Tutorials
Автор: Shawon M. Shahryiar
https://www.youtube.com/c/sshahryiar
https://github .com/sshahryiar
by Khaled Magdy
Изучение программирования ПЛК — бесплатно 6 — De…
Пожалуйста, включите JavaScript ПЛК
В этом руководстве мы обсудим аппаратное обеспечение STM32 GPIO. Как это работает и какие функции существуют, чтобы вы могли настроить его наилучшим образом для удовлетворения потребностей ваших приложений. Мы рассмотрим скорость GPIO, альтернативные функции, механизм блокировки и различные возможные конфигурации. Итак, приступим!
Каждый из портов ввода/вывода общего назначения имеет два 32-битных регистра конфигурации, два 32-битных регистра данных, 32-битный регистр установки/сброса, 1 6 регистров сброса -битный регистр сброса и 32-битный регистр блокировки. Каждый бит порта ввода-вывода свободно программируется, однако доступ к регистрам порта ввода-вывода должен осуществляться как к 32-битным словам (полусловный или байтовый доступ не разрешен). Назначение регистров установки/сброса состоит в том, чтобы разрешить атомарное чтение/изменение доступа к любому из регистров GPIO. Таким образом, нет риска возникновения IRQ между доступом на чтение и изменение.
Вот цифровая схема внутренней структуры типичного контакта GPIO. Он показывает диодную защиту, внутреннее включение/выключение подтягивания вверх или вниз, а также двухтактный выходной драйвер, включение/выключение выхода для переключения между режимами ввода/вывода, цифровой вход, управляемый Шмиттом, аналоговый вход.
Вы должны предположить, что все контакты GPIO по умолчанию не устойчивы к 5 В, пока вы не найдете в таблице данных, что определенный контакт устойчив к 5 В, только тогда вы можете использовать его как контакт 5 В. Штыри в основном 3,3 В и могут быть повреждены при подключении к цифровым входным линиям до 5 В. Сдвиг уровня может быть обязательным во многих случаях.
Таким образом, вы должны быть осторожны с уровнем напряжения для входных контактов. А также вы должны обратить внимание на выходной ток при установке выходных контактов GPIO. Максимальный ток, который может подаваться или поступать на любой вывод GPIO, составляет 25 мА согласно техническому описанию. И вы должны проверить это для конкретного целевого микроконтроллера, с которым вы имеете дело.
Для режима ввода
Когда вывод GPIO установлен в режим ввода, данные, присутствующие на выводе ввода-вывода, записываются в регистр входных данных каждый тактовый цикл APB2. Это означает, что скорость шины APB2 определяет скорость выборки ввода для контактов GPIO.
Для режима вывода
Когда вывод GPIO установлен в режим вывода, у вас будет возможность настроить режим скорости вывода, запрограммировав соответствующие биты в регистрах конфигурации. Ниже приведена таблица различных режимов, доступных в техническом описании микроконтроллера STM32F103C8.
Однако другие микроконтроллеры будут иметь другие параметры скорости вывода вывода. Например, другой микроконтроллер, который мы будем использовать в этом курсе, STM32L432KC. Он имеет специальный регистр управления скоростью для контактов GPIO, которые имеют 4 различных варианта скорости: низкая скорость, средняя скорость, высокая скорость, очень высокая скорость.
Вы найдете, что означают эти классы скорости, в техническом описании устройства. Вот таблица для этого параметра из таблицы данных STM32L432KC.
Примечание: Типичные значения зависят от различных параметров, таких как линейное напряжение V DDio , общая емкость выводов.
Программе не нужно отключать прерывания при программировании GPIOx_ODR на битовом уровне: можно изменить только один или несколько битов в одном доступе на запись атомарного APB2. Это достигается путем программирования в «1» регистра установки/сброса битов (GPIOx_BSRR или только для сброса GPIOx_BRR), чтобы выбрать биты для изменения. Невыбранные биты не будут изменены.
Все порты поддерживают внешние прерывания. Чтобы использовать внешние линии прерывания, порт должен быть сконфигурирован в режиме ввода. Мы обсудим это более подробно, когда перейдем к теме EXTI (внешний контроллер прерываний/событий).
Чтобы оптимизировать количество функций периферийного ввода-вывода для различных корпусов устройств, можно переназначить некоторые альтернативные функции некоторым другим контактам. Это достигается программно, путем программирования соответствующих регистров.
Эта опция может помочь вам переназначить контакты ввода-вывода периферийных устройств, чтобы вам не пришлось сильно менять компоновку печатной платы при смене целевого микроконтроллера на плате. Это может быть чрезвычайно выгодно и упростить процесс маршрутизации. И помочь вам убрать высокоскоростные сигналы, чтобы снизить уровень шума в определенных частях.
Механизм блокировки позволяет заморозить конфигурацию ввода-вывода. Когда к биту порта применена последовательность LOCK, больше невозможно изменить значение бита порта до следующего сброса.
В зависимости от конкретных аппаратных характеристик каждого порта ввода-вывода, указанного в техническом описании , каждый бит порта ввода-вывода общего назначения может быть настроен отдельно (GPIO) программно в нескольких режимах:
Конфигурация выхода
Конфигурация входа
Конфигурация альтернативной функции
Аналоговая конфигурация
Не все выводы GPIO устойчивы к напряжению 5 В. В основном они 3.3v.
Вы должны включить часы для GPIO, который вы хотите использовать, независимо от режима работы.
При настройке выходного контакта GPIO вы можете выбрать скорость, подходящую для вашего приложения. Нужна ли вам высокочастотная коммутация на линии IO или нет.
Скорость шины APB2 определяет частоту дискретизации для всех сконфигурированных контактов входа GPIO.
Вы можете отключить любой вывод GPIO (сделать его высокоимпедансным), установив его в режим ввода с помощью Hi-Z.
Вы можете заморозить или заблокировать конфигурацию контактов GPIO после инициализации системы, если не предполагается никаких изменений с помощью механизма блокировки.
Альтернативные функциональные контакты могут быть заменены (переназначены) внутри, чтобы вы могли пользоваться большей свободой в маршрутизации этих сигналов.
Все выводы GPIO являются выводами с возможностью прерывания, но их необходимо настроить в EXTI, как мы увидим позже в курсе.
Это урок. В следующем уроке мы начнем нашу первую практическую лабораторную работу!
Присоединяйтесь к нашим более чем 25 000 подписчиков на рассылку новостей!
Будьте в курсе всех новых выпусков контента. Вы также получаете случайные БЕСПЛАТНЫЕ коды купонов для курсов и других вещей!
Введите адрес электронной почты…
Автор
Я инженер встраиваемых систем с многолетним опытом разработки встроенного программного и аппаратного обеспечения. Я работаю инженером по встроенному ПО в автомобильной промышленности. Тем не менее, я по-прежнему занимаюсь проектированием оборудования и разработкой программного обеспечения для DSP, систем управления, робототехники, искусственного интеллекта/машинного обучения и других областей, которыми я увлечен. Я люблю читать, писать, создавать проекты и заниматься технической подготовкой. Читатель днем и писатель ночью, это мой образ жизни.