ШИМ (широтно-импульсная модуляция) — широтно-импульсная модуляция. В системе с инерцией требуемые аналоговые параметры можно получить эквивалентным образом, управляя шириной серии импульсов. Часто используется в управлении скоростью двигателя, импульсных источниках питания и т. д. поле.
В ШИМ есть три важных параметра: частота, скважность (отношение длительности высокого уровня к длительности всего периодического сигнала) и разрешение (регулируемая точность скважности).
На следующем рисунке показана диаграмма формы сигнала в режиме ШИМ 1:
Принцип выхода волны ШИМ таков:,Использование ТИМтаймера и сравнение результатов,ТИМтаймер будет периодически расти линейно,Когда значение счетчика ниже установленного значения сравнения, он выводит высокий уровень.,Когда оно больше или равно значению сравнения, выводится низкий уровень. Потому что это линейный рост,Пропорция длительности высокого уровня ко всей длительности сигнала цикла фиксирована.,Это соотношение называется «рабочим циклом».,Английский“Duty Cycle
”。
во встроенных системах,Особенно при использовании таймера для генерации сигналов ШИМ.,Часто используетсятаймерсравнить регистр(Capture/Compare Register
,CCR)и автоперезагрузка реестра(Auto-Reload Register
,ARR) для управления рабочим ШИМ цикл。
Данный:
Так:Duty=CCR/(ARR+1)
Почему ARR+1, а не ARR?
Диапазон подсчета фактически составляет от 0 до ARR, с общим количеством значений ARR+1.
Предположим, что значение ARR равно 99, а значение CCR — 50.
меньше, чемCCRиз Числа0-49
общий50индивидуальный,Диапазон счета составляет0-99
общий100индивидуальный,рабочий цикл должен составлять 50%.
Это CCR/(ARR+1)
Регулируя CRR,Рабочий цикл ШИМ может быть изменен. ARR - это другое,Точность регулировки рабочего цикла также различна. Значение CCR плюс один,Такрабочий циклулучшится1/(ARR+1)
,Чем больше ARR,Чем меньший минимальный шаг может быть достигнут,Чем выше разрешение,вернорабочий циклиз Чем тоньше регулировка。
PWMизразрешение(Resolution)только сARRсвязанный:Reso=1/(ARR+1)
Последний параметр — это частота ШИМ, то есть частота, с которой счетчик изменяется от 0 до ARR.
таймерчасколоколчастота Сразудаприлавокизсчитатьчастота,каждый цикл,Значение счетчика +1. Нужно прибавить от 0 к ARR,общийARR+1
индивидуальныйчасколокол周期。
То есть: длина цикла ШИМ = длина цикла таймера * (ARR + 1)
Обратной величиной длины цикла является частота: частота ШИМ = частота таймера/(ARR+1)
Частоту таймера можно получить путем деления частоты источника тактовой частоты на коэффициент деления.
Данный:
Так:Freq=CK_PSC/(PSC+1)/(ARR+1)
Далее в качестве примера возьмем рулевой механизм SG90, двигатель постоянного тока и светодиодные фонари, Выход ШИМ. В том числе «Как получить доступ к документации по выбору контактов».
Под изображением выше расположены «События» и «Прерывания и выход DMA».
Запросите контакт светодиодного индикатора и на каком канале какого таймера он включен.
На принципиальной диаграмме мы видим, что светодиод LED1 соответствует выводу PA8. Но получить конкретный канал по принципиальной схеме невозможно.
Запросив определение контакта, вы увидите, что PA8 также является каналом CH1 расширенного таймера TIM1.
Включить часы TIM1
Нам нужно сначала запросить место, где установлены часы TIM1. Это можно увидеть в определении библиотечной функции.
TIM1Появиться вRCC_APB2PeriphClockCmd()
из Список параметровсередина,Функция этой функции заключается в управлении включением или отключением часов определенных периферийных устройств, подключенных к шине APB2 в микроконтроллере STM32.
RCC
:представлятьReset and Clock Control (сброс и управление часами) — модуль, отвечающий за управление часами в микроконтроллере серии STM32.APB2
:представлятьAdvanced Peripheral Bus 2 (Advanced Peripheral Bus 2) — периферийная шина в STM32, используемая для подключения определенных периферийных устройств к ядру.Periph
:даPeripheral(периферийные устройства)изаббревиатура,Относится к периферийным устройствам, подключенным к шине APB2.ClockCmd
:даClock Аббревиатура Command (команда часов) относится к функции, используемой для управления включением или отключением периферийных часов.На шине APB2 также установлен GPIOA, который можно включить с помощью операции ИЛИ и строки кода:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1|RCC_APB2Periph_GPIOA,ENABLE);
Инициализация GPIO
Порт PA8 в настоящее время является каналом TIM1, и необходимо установить режим на мультиплексированный двухтактный выход.
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
инициализация таймера
Этот шаг устанавливает внутренние часы в качестве источника синхронизации。существоватьstm32f10x_tim.h
Найдено актуальное вфункция。
ПозвонивTIM_InternalClockConfig
функция,таймер может быть Конфигурация для использования внутренних ресурсов синхронизации。
TIM_InternalClockConfig(TIM1);
После настройки источника синхронизации вам необходимо настроить единицу измерения времени.
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 100 -1;
TIM_TimeBaseInitStructure.TIM_Prescaler = 720 -1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStructure);
Настройка сравнения выходных данных OC
Каждый таймер имеет несколько каналов, и вам необходимо указать канал и таймер во время инициализации. в:
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse=0;
TIM_OC1Init(TIM1,&TIM_OCInitStructure);
TIM_OCInitTypeDef
Есть много структур Конфигурацияэлемент,Приведенный выше код является лишь его частью.,оставатьсяиз Все могутпроходитьTIM_OCStructInit(&TIM_OCInitStructure);
Инициализировать。этотиндивидуальныйфункцияиз内容Сразудадля структурыизкаждыйэлемент Присвоить начальное значение,Поскольку данные необходимо изменить,Следовательно, методом передачи параметров является передача адреса.
Режим сравнения выходов установлен на TIM_OCMode_PWM1. Это режим сравнения вверх,Это пример в начале статьи.,>=CCRнаходится на низком уровне, когда。
БолееизTIM_OCMode
Можетсуществоватьstm32f10x_tim.h
Искать в。
TIM_OCPolarity
изэффектда Конфигурация Сигнализполярность:
TIM_OCPolarity_High
:Полярность не меняетсяTIM_OCPolarity_Low
:полярность翻转尽管TIM_OCMode_PWM1
Уже указаноPWM1
режимизметод работы,Но для того, чтобы гарантировать, что выходной сигнал соответствует ожиданиям и соответствует требованиям внешнего устройства,Еще нужно дальше Конфигурация Сравнение результатоврядизполярность。
TIM_OutputState
да Конфигурация Включение выхода,установлен наTIM_OutputState_Enable
нормально выводить。
TIM_Pulse
изценить СразудаCCRСравниватьзарегистрироватьсяизценить,установить на 0,Указывает, что он включен после сброса.,И яркость 100%.
Включить таймер TIM
Вышеуказанная операция — это всего лишь настройка, а не запуск.
TIM_Cmd(TIM1,ENABLE);
TIM_CtrlPWMOutputs(TIM1,ENABLE);
TIM_Cmd(TIM1,ENABLE);
изэффектдадавать возможностьTIM1таймер。
существоватьпередовойтаймерсередина,нуждатьсяTIM_CtrlPWMOutputs()
Выход ШИМ волна.
Достичь эффекта дышащего света
Нужно внести ясность:
TIM_TimeBaseInitTypeDef
частьда Конфигурациямодуль временной базы,это часы+счетTIM_OCInitTypeDef
частьда Конфигурация Модуль сравнения выходов,Обработка подсчета
TIM_SetCompare1()
изэффектда Исправлятьтаймеризряд1изCCR。
Задержка добавлена, чтобы сделать эффект дыхания более заметным.
Сигнал управления рулевым механизмом SG90 представляет собой сигнал широтно-импульсной модуляции (ШИМ) с периодом 20 мс. Длительность импульса изменяется линейно от 0,5 мс до 2,5 мс, что соответствует положению рулевого колеса от 0 до 180 градусов. (версия с сервоприводом 180°).
Другими словами, период волны ШИМ составляет 20 мс.
Найдите контакт, на котором расположен сервоинтерфейс.
через схему,Может看到四индивидуальныйрулевой механизмиз БулавкаSERVO_x
верноотвечатьPB12-PB15
。
такой же Светодиодный дыхательный светильник: По принципиальной схеме невозможно определить конкретный канал.
В таблице определения контактов вы можете запросить функцию мультиплексирования по умолчанию.
Эти четыре контакта отличаются от «Светодиодного». дыхательный светильник”серединаизPA8
。
PA8
даTIM1_CH1
PB12
даTIM1_BKIN
:TIM1из Резервный вход(Break Input)PB13-15
даTIM1_CHxN
:TIM1изрядxиздополнительныйрядЗдесь мы по-прежнему используем PA8Выход Волна ШИМ через летающую линию выводит волну ШИМ на интерфейс сервопривода. Эта часть кода унаследована от светодиодной части, и ее нужно только изменить:
Изменить период волны ШИМ
TIM_TimeBaseInitStructure.TIM_Period = 2000 -1;
TIM_TimeBaseInitStructure.TIM_Prescaler = 720 -1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_Prescaler
Значение прескалера720,Системный такт составляет 72M.,Таким образом, частота после деления равна 0,1 МГц.,Период 10 мс.TIM_Period
Целевое значение счетчика2000,Требуется 2000 тактов,Частота TIM составляет 0,1/2000 МГц.,Период 20мс.Нажмите клавишу, чтобы изменить CCR
Включить кнопки относительно просто: вам нужно найти на принципиальной схеме порт GPIO, соответствующий кнопке.
При поиске в определении библиотечной функции GPIOB смонтирован на APB2.
void Key_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1|GPIO_Pin_4|GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
Когда кнопка нажата,GPIO читает низкий уровень,После отпускания его следует подтянуть до высокого уровня.。То есть принятьGPIO_Mode_IPU
режим подтягивающего ввода。
uint8_t Key_GetNum(void)
{
uint8_t KeyNum = 0;
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)
{
Delay_ms(20);
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0);
Delay_ms(20);
KeyNum = 1;
}
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
{
Delay_ms(20);
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0);
Delay_ms(20);
KeyNum = 2;
}
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_4) == 0)
{
Delay_ms(20);
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_4) == 0);
Delay_ms(20);
KeyNum = 3;
}
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_5) == 0)
{
Delay_ms(20);
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_5) == 0);
Delay_ms(20);
KeyNum = 4;
}
return KeyNum;
}
Функция Delay_ms — предотвращать тряску клавиш и удалять заусенцы.
Подключение согласно принципиальной схеме
На рисунке ниже я вставил положение J4, которое соответствует контакту 26.
Подключите контакт 26 к контакту 17, где расположен PA8, с помощью провода Dupont.
VID_20240208_204405
В отличие от светодиодных фонарей и сервоприводов, двигатель постоянного тока — устройство большой мощности.,Требуются дополнительные драйверы,Обычных возможностей управления портом ввода-вывода недостаточно.
Согласно принципиальной схеме найдите положение штифта драйвера двигателя.
PA0
повторное использованиеTIM2_CH1_ETR
,Еще не учусь。Поэтому данная статья выбираетPA2иPA3。верноотвечатьиздаTIM2_CH3
иTIM2_CH4
。
Настройте RCC TIM2
TIM2 монтируется под APB1, а место монтажа указано выше: его можно посмотреть через комментарии в исходном файле функции библиотеки.
Иди сюда, Нужно внести ясность:
TIM_OCInitTypeDef
даверно Сравнение результатоврядиз Конфигурацияинформация。TIM_OCxInit
да Воля Конфигурациязагрузить в конкретныйизрядначальство。потому чтожитьсуществоватьмногоиндивидуальныйTIMтаймер,Каждый таймер имеет несколько каналов. Поэтому необходимо указать, в какой канал и в какой таймер загружается файл Конфигурации. таймер указывается через параметр функции,Каналы указаны по названию функции.。На передний светодиод и сервопривод необходимо вывести волну ШИМ только на один канал:
исуществоватьдвигатель постоянного По току два входных контакта имеют разные состояния на разных высоких и низких уровнях:
Оба контакта должны быть выходными. Волна ШИМ, а не фиксированная на низком или высоком уровне. Затем необходимо загрузить файл конфигурации на каналы CH3 и CH4 таймера TIM2.
TIM_OC3Init(TIM2,&TIM_OCInitStructure);
TIM_OC4Init(TIM2,&TIM_OCInitStructure);
TIM2 не является продвинутым таймером,Поэтому нетнуждатьсяTIM_CtrlPWMOutputs()
。
Используйте OLED для облегчения отладки
Таймеры TIM этих двух каналов одинаковы, и период изменения тоже одинаков. CCR обоих каналов можно указать отдельно, чтобы регулировать уровни двух выводов отдельно, но период изменения одинаков.
захват ввода(Input Захват), также известный как IC。 существоватьзахват В режиме ввода, когда на входном выводе канала происходит указанный переход уровня, текущее значение CNT будет зафиксировано в CCR, который можно использовать для измерения частоты, рабочего цикла, интервала импульсов, длительности уровня и других параметров ШИМ. форма волны. Каждый таймер высокого уровня и общий таймер имеют по 4 захвата. Канал ввода имеет две цели:
f=N/T
f=fc/N
Два приведенных выше результата теста будут иметь присущую погрешность, то есть «в подсчете есть ошибка плюс-минус 1»:
но:
Метод измерения частоты подходит для высокочастотных сигналов, а метод измерения цикла подходит для низкочастотных сигналов. Споры вызовет диапазон высокочастотных сигналов и низкочастотных сигналов, то есть сколько частот считаются высокими частотами и сколько частот считаются низкими частотами. Поэтому вводится концепция добавления «средней частоты». Сигналы с частотой выше средней частоты являются высокочастотными сигналами, и ошибка измерения с использованием метода измерения частоты меньше, сигналы с частотой ниже средней частоты являются низкочастотными сигналами, и ошибка измерения; меньше при использовании метода измерения перицикла. Средняя граничная частота: используйте метод измерения частоты и метод измерения периферии для измерения частоты сигнала. Если ошибки, вызванные этими двумя, равны, частота сигнала определяется как средняя граничная частота.
Настройте RCC для входных каналов
Вам нужно только выбрать канал CH для одновременного измерения частоты ШИМ и коэффициента заполнения: после входа во входной фильтр и детектор фронта срабатывает последующая схема и генерируются один или оба сигнала TI1FP1 и TI1FP2.
Эти каналы являются дополнительными. двигатель на предыдущем шаге постоянного тока мы использовали PA2 и PA3, TIM2_CH3 и TIM2_CH4. Теперь мы можем выбрать TIM3 в качестве захватывающего. вводаизтаймер。потому чтоCH1иCH2существоватьвходитьчас Может交叉使用,Любой вход можно разделить на два канала. Таким образом, временные развертки каналов CH1 и CH2 соответствуют конфигурации IC.,Отличается только расположение инициализированного контакта GPIO.
Инициализировать входной контакт
В этой статье выбирается канал CH1 TIM3.
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
источник синхронизации
Установите внутренние часы в качестве источника синхронизации TIM3.
TIM_InternalClockConfig(TIM3);
Настройка базовой единицы времени
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period=65536-1;
TIM_TimeBaseInitStructure.TIM_Period=72-1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);
Сравнивая этот код с приведенным выше выводом ШИМ, разницы, похоже, нет.
TIM_Period
иTIM_Period
из Конфигурацияпричина Волясуществоватьобъяснил позже,Прежде чем объяснятьнуждаться Подготовьте почву для некоторого контента。
Возникает вопрос: он все равно запускается нарастающим фронтом внутренних часов, а за периодическое накопление отвечает ТИМ. Идет подсчет количества ударов внутренних часов, и захватывает При чем тут ввод?
КонфигурацияICзахват ввода
На рисунке входному каналу дано двоичное представление, которое можно найти в определении библиотечной функции:
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel=TIM_Channel_1;
TIM_ICInitStructure.TIM_ICFilter=0;
TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;
TIM_ICInit(TIM3,&TIM_ICInitStructure);
На данный момент, похоже, до сих пор не ясно, что делать с захватом. Какое отношение имеет ввод к тому, как определить частоту ввода. Для достижения автоматического измерения необходимо настроить режим «ведущий-подчиненный».
Настроить подчиненный режим
ВоляTI1FP1Сигналустановлен наперезагрузитьчасбазовый блокиз触发Сигнал。TI1FP1выражатьTimer Input 1 Filtered Channel 1
,Это означает, что внешний сигнал из канала 1 (через фильтр) будет использоваться в качестве входного сигнала запуска TIM3.
TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);
TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);
Процесс измерения частоты
Частота чтения
TIM_Period, настроенный в единице измерения времени, делится на 72, то есть стандартная частота равна 1 МГц. Когда срабатывает сигнал нарастающего фронта, регистр CCR сохраняет значение в таймере, которое представляет собой количество раз на стандартной частоте. Нарастающий фронт запускает стандартную частоту N раз, тогда частота этого периода ШИМ равна: стандартная частота/N.
uint16_t IC_GetFreq()
{
return 1000000/(TIM_GetCapture1(TIM3) + 1);
}
Чтобы облегчить отладку, значения различных параметров выводятся через OLED.
int main(void)
{
uint16_t FOR=0;
uint16_t BAK=0;
PWM_Init();
Key_Init();
OLED_Init();
IC_Init();
OLED_ShowString(1,1,"FOR:");
OLED_ShowString(2,1,"BAK:");
OLED_ShowString(3,1,"Freq:00000Hz");
while(1)
{
uint16_t keyNum=Key_GetNum();
if(keyNum==1){
PWM_SetCompare3(FOR+=100);
PWM_SetCompare4(BAK+=0);
}
else if(keyNum==2){
PWM_SetCompare3(FOR-=100);
PWM_SetCompare4(BAK-=0);
}
else if(keyNum==3){
PWM_SetCompare3(FOR+=0);
PWM_SetCompare4(BAK+=100);
}
else if(keyNum==4){
PWM_SetCompare3(FOR-=0);
PWM_SetCompare4(BAK-=100);
}
OLED_ShowNum(1,5,FOR,5);
OLED_ShowNum(2,5,BAK,5);
OLED_ShowNum(3,6,IC_GetFreq(),5);
}
}
Попробуйте изменить FOR и BAK и обнаружите, что оба результата составляют 100 Гц. Это потому, что 100Гц — это частота волны ШИМ, а FOR и BAK — значения регистра сравнения. Изменяется рабочий цикл, а не частота. Изменение частоты требует изменения коэффициента деления частоты и целевого числа циклов.
Регистр CCR используется как для ввода, так и для вывода.
CCR зарегистрироваться(Capture/Compare Register
,регистры захвата/сравнения) имеют разные роли на входе и выходе:
Как видно, TIM_SetCompare и захват вызываются при сравнении результатов. вводасерединавызовизTIM_GetCapture,Доступ к тому же регистру,Выполните операции присвоения и получения значения соответственно.
Частота и рабочий цикл
Входной канал может быть назначен двум линиям для измерения частоты и рабочего цикла соответственно. Приведенный выше код представляет только частоту. Параметры, соответствующие частоте и рабочему циклу, различны, и их нельзя получить, принимая как должное одну линию захвата. При нахождении частоты непосредственно получается значение регистра CCR, которое представляет собой количество циклов, которое на самом деле является «временем». Если требуется рабочий цикл, спадающий фронт можно фиксировать в строке 2 и определять «время» высокого уровня. Сравнивая это со временем всего цикла, получаем рабочий цикл.
Настройте GPIO, временную развертку, OC, IC
Соглашения об именахда:xInitTypeDef xInitStructure
。
этот只да:Конфигурацияиз“информация”,Это не «процесс» Конфигурации. После завершения настройки,проходитьxInit()
,Воля Конфигурацияинформация Действует доверноотвечатьизинтерфейс。
Когда объявляется структура информации о конфигурации, она четко не указывает, к какому выводу GPIO или к какому каналу какого таймера TIM она относится. Эта информация указывается в методе инициализации либо через параметры функции, либо через имя функции.
Прерывания и события
событие Нет необходимости реализовывать функцию обработки прерываний,Например, при вводе захвата,Триггер — это событие,Может быть установлен в режим сброса с помощью функции библиотеки.,Аппаратное обеспечение автоматически перезагружается.
Как получить доступ к документации
Способы получения информации:
«Определение макроса» и «магическое число» в проектах на языке C.
«Магические числа» обычно относятся к жестко закодированным числам или константам, которые появляются в программировании и используются непосредственно в коде без предоставления четких объяснений или комментариев. Такой подход может привести к тому, что код станет трудным для понимания, сопровождения и плохо читаемым. Хотя в руководстве дано двоичное представление, макросы следует использовать, если их можно использовать в реальном коде. Строка 0011 вызовет много проблем при обслуживании кода, поэтому следует избегать, насколько это возможно, «магических чисел». Вместо этого используйте осмысленные именованные константы или перечисления, которые могут повысить читаемость и удобство сопровождения вашего кода.