Содержание
Битовые операции
Переходим к более сложным вещам. На самом деле они максимально просты для микроконтроллера, настолько просты, что выполняются за один такт. При частоте 16 МГц (большинство плат Arduino) одна операция занимает 0.0625 микросекунды.
Битовое И
И (AND), оно же “логическое умножение”, выполняется оператором или и возвращает следующее:
0 & 0 == 0 0 & 1 == 0 1 & 0 == 0 1 & 1 == 1
Основное применение операции И – битовая маска. Позволяет “взять” из байта только указанные биты:
myByte = 0b11001100; myBits = myByte & 0b10000111; // myBits теперь равен 0b10000100
То есть при помощи мы взяли из байта 0b11001100 только биты 10000111, а именно – 0b11001100, и получили 0b10000100
Также можно использовать составной оператор
myByte = 0b11001100; myByte &= 0b10000000; // берём старший бит // myByte теперь 10000000
Битовое ИЛИ
ИЛИ (OR), оно же “логическое сложение”, выполняется оператором или и возвращает следующее:
0 | 0 == 0 0 | 1 == 1 1 | 0 == 1 1 | 1 == 1
Основное применение операции ИЛИ – установка бита в байте:
myByte = 0b11001100; myBits = myByte | 0b00000001; // ставим бит №0 // myBits теперь равен 0b11001101 myBits = myBits | bit(1); // ставим бит №1 // myBits теперь равен 0b11001111
Также можно использовать составной оператор
myByte = 0b11001100; myByte |= 16; // 16 - 2 в 4, включаем бит №4 // myByte теперь 0b11011100
Вы уже поняли, что указывать на нужные биты можно любым удобным способом: в бинарном виде (0b00000001 – нулевой бит), в десятичном виде (16 – четвёртый бит) или при помощи макросов или ( даёт 128 или 0b10000000, делает то же самое)
Битовое НЕ
Битовая операция НЕ (NOT) выполняется оператором и просто инвертирует бит:
~0 == 1 ~1 == 0
Также она может инвертировать байт:
myByte = 0b11001100; myByte = ~myByte; // инвертируем // myByte теперь 00110011
Битовое исключающее ИЛИ
Битовая операция исключающее ИЛИ (XOR) выполняется оператором или и делает следующее:
0 ^ 0 == 0 0 ^ 1 == 1 1 ^ 0 == 1 1 ^ 1 == 0
Данная операция обычно используется для инвертирования состояния отдельного бита:
myByte = 0b11001100; myByte ^= 0b10000000; // инвертируем 7-ой бит // myByte теперь 01001100
То есть мы взяли бит №7 в байте 0b11001100 и перевернули его в 0, получилось 0b1001100, остальные биты не трогали.
Битовый сдвиг
Битовый сдвиг – очень мощный оператор, позволяет буквально “двигать” биты в байте вправо и влево при помощи операторов и , и соответственно составных и Если биты выходят за границы блока (8 бит, 16 бит или 32 бита) – они теряются.
myByte = 0b00011100; myByte = myByte << 3; // двигаем на 3 влево // myByte теперь 0b11100000 myByte >>= 5; // myByte теперь 0b00000111 myByte >>= 2; // myByte теперь 0b00000001 // остальные биты потеряны!
Битовый сдвиг делает не что иное, как умножает или делит байт на 2 в степени. Да, это операция деления, выполняющаяся за один такт процессора! К этому мы ещё вернёмся ниже. Посмотрите на работу оператора сдвига и сравните её с макросами и :
1 << 0 == 1 1 << 1 == 2 1 << 2 == 4 1 << 3 == 8 ... 1 << 8 == 256 1 << 9 == 512 1 << 10 == 1024
Да, это возведение двойки в степень!
Включаем-выключаем
Вспомним пример из пункта про битовое ИЛИ, про установку нужного бита. Вот эти варианты кода делают одно и то же:
myByte = 0b11000011; // ставим бит №3 разными способами // по сути - одно и то же myByte |= (1 << 3); myByte |= bit(3); myByte |= _BV(3); bitSet(myByte, 3); // myByte равен 0b11001011
Как насчёт установки нескольких бит сразу?
myByte = 0b11000011; // ставим бит №3 и 4 разными способами // по сути - одно и то же myByte |= (1 << 3) | (1 << 4); myByte |= bit(3) | bit(4); myByte |= _BV(3) | _BV(4); // myByte равен 0b11011011
Или прицельного выключения бит? Тут чуть по-другому, используя и
myByte = 0b11000011; // выключаем бит №1 разными способами // по сути - одно и то же myByte &= ~(1 << 1); myByte &= ~_BV(1); bitClear(myByte, 1); // myByte равен 0b11000001
Выключить несколько бит сразу? Пожалуйста!
myByte = 0b11000011; // выключаем биты №0 и 1 разными способами myByte &= ~( (1 << 0) | (1 << 1) ); myByte &= ~( _BV(0) | _BV(1) ); // myByte равен 0b11000000
Именно такие конструкции встречаются в коде высокого уровня и библиотеках, именно так производится работа с регистрами микроконтроллера.
Вернёмся к устройству Ардуиновских макросов:
#define bitRead(value, bit) (((value) >> (bit)) & 0x01) #define bitSet(value, bit) ((value) |= (1UL << (bit))) #define bitClear(value, bit) ((value) &= ~(1UL << (bit))) #define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit)) #define bit(b) (1UL << (b))
Я думаю, комментарии излишни: макросы состоят из тех же элементарных битовых операций и сдвигов!
Виды носителей
Привод DVD
Оптические носители
Информацию с оптических носителей считывают в оптическом приводе с помощью лазера. Во время написания этой статьи (весна 2013 года) самые распространенные оптические носители — оптические диски CD, DVD, Blu-ray и Ultra Density Optical (UDO). Накопитель может быть один, или их может быть несколько, объединенных в одном устройстве, как например в оптических библиотеках. Некоторые оптические диски позволяют осуществлять повторную запись.
Полупроводниковый накопитель
Полупроводниковые носители
Полупроводниковая память — одна из наиболее часто используемых видов памяти. Это вид памяти параллельного действия, позволяющий одновременный доступ к любым данным, независимо в какой последовательности эти данные были записаны.
Почти все первичные устройства памяти, а также устройства флеш-памяти — полупроводниковые. В последнее время в качестве альтернативы жестким дискам становятся более популярными твердотельные накопители SSD (от английского solid-state drives). Во время написания этой статьи эти накопители стоили намного дороже жестких дисков, но скорость записи и считывания информации на них значительно выше. При падениях и ударах они повреждаются намного меньше, чем магнитные жесткие диски, и работают практически безшумно. Кроме высокой цены, твердотельные накопители, по сравнению с магнитными жесткими дисками, со временем начинают работать хуже, и потерянные данные на них очень сложно восстановить, по сравнению с жесткими дисками. Гибридные жесткие диски совмещают твердотельный накопитель и магнитный жесткий диск, увеличивая тем самым скорость и срок эксплуатации, и уменьшая цену, по сравнению с твердотельными накопителями.
Накопитель на жестких магнитных дисках
Магнитные носители
Поверхности для записи на магнитных носителях намагничиваются в определенной последовательности. Магнитная головка считывает и записывает на них данные. Примерами магнитных носителей являются накопители на жестких магнитных дисках и дискеты, которые уже почти полностью вышли из употребления. Аудио и видео также можно хранить на магнитных носителях — кассетах. Пластиковые карты часто хранят информацию на магнитных полосах. Это могут быть дебетовые и кредитные карты, карты-ключи в гостиницах, водительские права, и так далее. В последнее время в некоторые карты встраивают микросхемы. Такие карты обычно содержат микропроцессор и могут выполнять криптографические вычисления. Их называют смарт-картами.
Перфокарта для ткацкого станка
Бумажные носители
Перфокарта и USB-флеш-накопитель
До появления магнитных и других носителей данные хранили на бумаге. Обычно в таком виде были записаны машинные команды, и их могли читать как люди, так и машины, например компьютеры или ткацкие станки. В основном для этих целей использовали перфокарты и перфоленты, где информация хранилась в виде чередующихся отверстий, и отсутствия отверстий. Перфоленту использовали, чтобы записывать текст на телеграфе и в типографии или редакции газет, а также в кассовых аппаратах. Постепенно с конца 50-x и до конца 80-х их заменили магнитные носители. Сейчас бумажные носители используют для подсчета голосов на выборах и для автоматической проверки контрольных работ, ответы к которым записываются на специальную карту, а потом читаются компьютером.
Автор статьи: Kateryna Yuri
Шестнадцатеричная система счисления
В программировании микроконтроллеров очень часто пользуются шестнадцатеричными числами. Данная система счисления имеет основание 16, соответственно и 16 различных символов. Первые десять символов 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 заимствованы из десятеричной системы. В качестве оставшихся шести символов применяются буквы A, B, C, D, E, F.
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F
Высокая популярность шестнадцатеричной системы счисления поясняется тем, что при отображении одного и того же значения используется меньше разрядов по сравнению с десятичной системой и тем более с двоичной. Например, при отображении 100 используется три десятичных разряда 10010 или 7 двоичных разрядов 11001002 и только 2 шестнадцатеричных разряда 6416.
10010 = 11001002 = 6416
А если записать 1000000, то разница в количестве занимаемых разрядов буде еще более ощутима:
1 000 00010 = 1111 0100 0010 0100 00002 = F424016
Сколько битов в Байте
Как Вы уже поняли выше, сам по себе, бит — это самая маленькая единица в системе измерения информации. Оттого и пользоваться ею совсем неудобно. В итоге, в 1956 году Владимир Бухгольц ввёл ещё одну единицу измерения — Байт, как пучок из 8 бит. Вот наглядный пример байта в двоичной системе:
00000001 10000000 11111111
Таким образом, вот эти 8 бит и есть Байт. Он представляет собой комбинацию из 8 цифр, каждая из которых может быть либо единицей, либо нулем. Всего получается 256 комбинаций. Вот как то так.
Килобайт, Мегабайт, Гигабайт
Со временем, объёмы информации росли, причём в последние годы в геометрической прогрессии. Поэтому, решено было использовать приставки метрической системы СИ: Кило, Мега, Гига, Тера и т.п.
Приставка «кило» означает 1000, приставка «мега» подразумевает миллион, «гига» — миллиард и т.д. При этом нельзя проводить аналогии между обычным килобитом и килобайтом. Дело в том, что килобайт — это отнюдь не тысяча байт, а 2 в 10-й степени, то есть 1024 байт.
Соответственно, мегабайт — это 1024 килобайт или 1048576 байт.
Гигабайт получается равен 1024 мегабайт или 1048576 килобайт или 1073741824 байт.
Для простоты можно использовать такую таблицу:
Для примера хочу привести вот такие цифры:
Стандартный лист А4 с печатным текстом занимает в средем около 100 килобайт
Обычная фотография на простой цифровой фотоаппарат — 5-8 мегабайт
Фотографии, сделанные на профессиональный фотоаппарат — 12-18 мегабайт
Музыкальный трек формата mp3 среднего качества на 5 минут — около 10 мегабайт.
Обычный фильм на 90 минут, сжатый в обычном качестве — 1,5-2 гигабайта
Тот же фильм в HD-качестве — от 20 до 40 гигабайт.
P.S.:
Теперь отвечу на вопросы, которые мне наиболее часто задают новички.
1. Сколько Килобит в Мегабите? Ответ — 1000 килобит (по системе СИ)
2. Сколько Килобайт в Мегабайте? Ответ — 1024 Килобайта
3. Сколько Килобит в Мегабайте? Ответ — 8192 килобита
4. Сколько Килобайт в Гигабайте? Ответ — 1 048 576 Килобайт.
Другие системы счисления
В цифровой технике также применяется восьмеричная система счисления, но она не нашла применения в микроконтроллерах.
Теоретические можно получить бесконечное значение систем счисления: троичную, пятиричную и даже сторичную, т.е. с любым основанием. Однако практической необходимости в этом пока что нет.
Наиболее простой и быстрый способ преобразования чисел с одной системы счисления в другую – это применение встроенного в операционную систему калькулятора. Найти его можно следующим образом: Пуск – Все программы – Стандартные – Калькулятор.
Чтобы перейти в «нужный» режим следует кликнуть по вкладке Вид и выбрать Программист или нажать комбинацию клавиш Alt+3.
В открывшемся окне можно вводить двоичные, восьмеричные, шестнадцатеричные и десятичные числа, выбрав соответствующий режим. Кроме того можно выполнять различные математические операции между ними.
В дальнейшем, при написании кода программы мы часто будем обращаться к данному калькулятору. Кроме того, опытные программисты любят использовать шестнадцатеричные числа, а нам проще будет понять двоичный код, поэтому калькулятор в помощь)
“Трюки” с битами
Целые
Установка nго бита
Выключение nго бита
Инверсия nго бита
Округление до ближайшей степени двойки
Округление вниз
Получение максимального целого
Получение минимального целого
Получение максимального long
Умножение на 2
Деление на 2
Умножение на mую степень двойки
Деление на mую степень двойки
Остаток от деления
И так далее
Проверка равенства
Проверка на чётность (кратность 2)
Обмен значениями
Получение абсолютного значения
Максимум из двух
Минимум из двух
Проверка на одинаковый знак
Смена знака
Вернёт 2n
Является ли число степенью 2
Остаток от деления на 2n на m
Среднее арифметическое
Получить mый бит из n (от младшего к старшему)
Получить mый бит из n (от старшего к младшему)
Проверить включен ли nый бит
Выделение самого правого включенного бита
Выделение самого правого выключенного бита
Выделение правого включенного бита
Выделение правого выключенного бита
n + 1
n – 1
Получение отрицательного значения
if (x == a) x = b; if (x == b) x = a;
Поменять смежные биты
Different rightmost bit of numbers m & n
Common rightmost bit of numbers m & n
Десятичные дроби
Примечание: хаки с float могут не работать на Ардуино!
Разбить float в массив бит (unsigned uint32_t)
#include <stdint.h> typedef union {float flt; uint32_t bits} lens_t; uint32_t f2i(float x) { return ((lens_t) {.flt = x}).bits; }
Вернуть массив бит обратно в float
float i2f(uint32_t x) { return ((lens_t) {.bits = x}).flt; }
Быстрый обратный квадратный корень
return i2f(0x5f3759df - f2i(x) / 2);
Быстрый nый корень из целого числа
float root(float x, int n) { #DEFINE MAN_MASK 0x7fffff #DEFINE EXP_MASK 0x7f800000 #DEFINE EXP_BIAS 0x3f800000 uint32_t bits = f2i(x); uint32_t man = bits & MAN_MASK; uint32_t exp = (bits & EXP_MASK) - EXP_BIAS; return i2f((man + man / n) | ((EXP_BIAS + exp / n) & EXP_MASK)); }
Быстрая степень
return i2f((1 - exp) * (0x3f800000 - 0x5c416) + f2i(x) * exp)
Быстрый натуральный логарифм
#DEFINE EPSILON 1.1920928955078125e-07 #DEFINE LOG2 0.6931471805599453 return (f2i(x) - (0x3f800000 - 0x66774)) * EPSILON * LOG2
Быстрая экспонента
return i2f(0x3f800000 + (uint32_t)(x * (0x800000 + 0x38aa22)))
Строки
Конвертировать в нижний регистр
Конвертировать в верхний регистр
Инвертировать регистр
Позиция буквы в алфавите (англ)
Позиция большой буквы в алфавите (англ)
Позиция строчной буквы в алфавите (англ)
Важные страницы
- Каталог ссылок на дешёвые Ардуины, датчики, модули и прочие железки с AliExpress у проверенных продавцов
- Подборка библиотек для Arduino, самых интересных и полезных, официальных и не очень
- Полная документация по языку Ардуино, все встроенные функции и макро, все доступные типы данных
- Сборник полезных алгоритмов для написания скетчей: структура кода, таймеры, фильтры, парсинг данных
- Видео уроки по программированию Arduino с канала “Заметки Ардуинщика” – одни из самых подробных в рунете
- Поддержать автора за работу над уроками
- Обратная связь – сообщить об ошибке в уроке или предложить дополнение по тексту (alex@alexgyver.ru)
Важные страницы
- Каталог ссылок на дешёвые Ардуины, датчики, модули и прочие железки с AliExpress у проверенных продавцов
- Подборка библиотек для Arduino, самых интересных и полезных, официальных и не очень
- Полная документация по языку Ардуино, все встроенные функции и макро, все доступные типы данных
- Сборник полезных алгоритмов для написания скетчей: структура кода, таймеры, фильтры, парсинг данных
- Видео уроки по программированию Arduino с канала “Заметки Ардуинщика” – одни из самых подробных в рунете
- Поддержать автора за работу над уроками
- Обратная связь – сообщить об ошибке в уроке или предложить дополнение по тексту (alex@alexgyver.ru)
Общие сведения
Данные и их хранение необходимы для работы компьютеров и цифровой техники. Данные — это любая информация, от команд до файлов, созданных пользователями, например текст или видео. Данные могут храниться в разных форматах, но чаще всего их сохраняют как двоичный код. Некоторые данные хранятся временно и используются только во время исполнения определенных операций, а потом удаляются. Их записывают на устройствах временного хранения информации, например, в оперативной памяти, известной под названием запоминающего устройства с произвольным доступом (по-английски, RAM — Random Access Memory) или ОЗУ — оперативное запоминающее устройство. Некоторую информацию хранят дольше. Устройства, обеспечивающие более длительное хранение — это жесткие диски, твердотельные накопители, и различные внешние накопители.
Подробнее о данных
Данные представляют собой информацию, которая хранится в символьной форме и может быть считана компьютером или человеком. Бо́льшая часть данных, предназначенных для компьютерного доступа, хранится в файлах. Некоторые из этих файлов — исполняемые, то есть они содержат программы. Файлы с программами обычно не считают данными.
Избыточный массив независимых дисков RAID.
Избыточность
Во избежание потери данных при поломках используют принцип избыточности, то есть хранят копии данных в разных местах. Если эти данные перестанут читаться в одном месте, то их можно будет считать в другом. На этом принципе основывается работа избыточного массива независимых дисков RAID (от английского reduntant array of independent discs). В нем копии данных хранятся на двух или более дисках, объединенных в один логический блок. В некоторых случаях для большей надежности копируют сам RAID-массив. Копии иногда хранят отдельно от основного массива, иногда в другом городе или даже в другой стране, на случай уничтожения массива во время катаклизмов, катастроф, или войн.
Десятичные дроби
Примечание: хаки с float могут не работать на Ардуино!
Разбить float в массив бит (unsigned uint32_t)
#include <stdint.h> typedef union {float flt; uint32_t bits} lens_t; uint32_t f2i(float x) { return ((lens_t) {.flt = x}).bits; }
Вернуть массив бит обратно в float
float i2f(uint32_t x) { return ((lens_t) {.bits = x}).flt; }
Быстрый обратный квадратный корень
return i2f(0x5f3759df - f2i(x) / 2);
Быстрый nый корень из целого числа
float root(float x, int n) { #DEFINE MAN_MASK 0x7fffff #DEFINE EXP_MASK 0x7f800000 #DEFINE EXP_BIAS 0x3f800000 uint32_t bits = f2i(x); uint32_t man = bits & MAN_MASK; uint32_t exp = (bits & EXP_MASK) - EXP_BIAS; return i2f((man + man / n) | ((EXP_BIAS + exp / n) & EXP_MASK)); }
Быстрая степень
return i2f((1 - exp) * (0x3f800000 - 0x5c416) + f2i(x) * exp)
Быстрый натуральный логарифм
#DEFINE EPSILON 1.1920928955078125e-07 #DEFINE LOG2 0.6931471805599453 return (f2i(x) - (0x3f800000 - 0x66774)) * EPSILON * LOG2
Быстрая экспонента
return i2f(0x3f800000 + (uint32_t)(x * (0x800000 + 0x38aa22)))
Приставки К, М, Г, Т («кило-», «киби-» и т.д.)
…чтобы измерять большие объемы данных, используют кратные приставки (это как «килограмм»). Привычная же нам приставка «кило-» означает умножение на 1000 (103), но в двоичной системе счисления используют два в десятой степени (210).
Давайте же вместе с сайтом IT-уроки разберемся в этом запутанном вопросе.
История введения двоичных приставок
Для обозначения величины 210=1024 байт, ввели двоичную приставку «К» (именно прописная буква «К»), но в разговорной речи единицу «К» стали называть «кило», что не совсем одно и то же. Чтобы избежать путаницы, ввели названия приставкам:
Т.е. второй слог изменили с привычного на «би», «бинарный».
Но путаница не исчезла, многие расшифровывали «К» и «М» привычными «кило» и «мега». Даже международные стандарты по-разному интерпретировали расшифровку двоичных приставок. Кроме того, производители добавили масла в огонь внесли свой вклад в запутывание ситуации (одни считали 210, другие 103).
В итоге, чтобы окончательно убрать несоответствие, изменили не только названия, но и приставки:
Как Вы думаете, помогло? Конечно же, нет
В обиходе говорят «кило», в программах ОС Windows пишут «К», в Linux обозначают «Ки», производители жестких и оптических дисков пишут «К», а имеют в виду «Ки» и т.д.
Что же делать обычному пользователю?
Если подвести итог всему сказанному, то на сегодняшний день три варианта использования двоичных приставок, их мы и сведем в три таблицы.
1. Обычное использование двоичных приставок
В свойствах файлов почти все программы, да и сама операционная система Windows использует приставку в виде прописной буквы «К», «М», «Г» и т.д. Производители оперативной памяти используют тот же принцип. То есть можно пользоваться следующей таблицей:
Двоичные приставки в ОС Windows и у производителей ОЗУ 1 Кбайт (КБ или KB или Kbyte) = 1024 байт
Эта «К» на самом деле двоичная приставка «киби» (а не «кило», как все говорят).
2. Правильное использование двоичных приставок
В других операционных системах, а также в профессиональных обзорах серьезных ИТ-изданий сразу пишут «Киб», «МиБ», «ГиБ», чтобы не было сомнений, о чем идет речь.
Двоичные приставки в ОС Linux, OS X и в профессиональных обзорах 1 кибибайт (КиБ или KiB или kebibyte) = 1024 байт
3. Использование десятичных приставок
Если используется приставка «кило», «мега», «гига» и т.д., то имеются в виду следующие соотношения:
Десятичные приставки используют производители накопителей (Жесткие диски, флэшки, DVD-диски) 1 килобайт (кБ или kB или kbyte) = 1000 байт
Куда исчезли 70 гигабайт на жестком диске???
Посмотрим, как Windows видит два моих жестких диска 500 ГБ и 1 ТБ:
Жесткий диск 500 ГБ отображается как 465.76 ГБ, а винчестер объемом 1000 ГБ содержит всего 931.51 гигабайт.
Наверное, Вы уже догадались, почему жесткий диск объемом 1 Терабайт в ОС Windows отображается как 931 ГБ, а не 1000.
Так что, не ругайте производителей и уж тем более компьютерную фирму, всё отмерено верно, но разными рулетками
Т.е. 70 гигабайт никуда не делись, просто гибибайт на жестком диске меньше, чем гигабайт.
Не запутались? Тогда еще один пример.
«Почему на флешке меньше места?»
То же самое и с флэш-накопителями. Если Вы посмотрите на свойства своей флэшки, то (к примеру) вместо 16 GB, указанных на корпусе, увидите 14.9 ГБ!!!
На флешке вместо 16 GB — 14.9 ГБ
Теперь Вы знаете, что 1.1 ГБ «потерялся» при пересчете из килобайт в кибибайты.