Среда разработки программ для микроконтроллеров mikroC понимает несколько систем исчисления: десятичную, двоичную, шестнадцатеричную. Таким образом, одни и те же числа можно представлять в этих разных системах. Сразу же возникает вопрос: Зачем? Почему бы не использовать знакомую нам с детства десятичную?
Дело в том, что иногда удобнее использование других систем для получения более практичной программы.
Формы записи чисел в различных системах исчисления |
Десятичная |
Двоичная |
|
Шестнадцатеричная |
Десятичная |
Десятичная |
|
Шестнадцатеричная |
00 |
00000000 |
|
00 |
11 |
00001011 |
|
0B |
01 |
00000001 |
|
01 |
12 |
00001100 |
|
0C |
02 |
00000010 |
|
02 |
13 |
00001101 |
|
0D |
03 |
00000011 |
|
03 |
14 |
00001110 |
|
0E |
04 |
00000100 |
|
04 |
15 |
00001111 |
|
0F |
05 |
00000101 |
|
05 |
16 |
00010000 |
|
10 |
06 |
00000110 |
|
06 |
17 |
00010001 |
|
11 |
07 |
00000111 |
|
07 |
18 |
00010010 |
|
12 |
08 |
00001000 |
|
08 |
19 |
00010011 |
|
13 |
09 |
00001001 |
|
09 |
20 |
00010100 |
|
14 |
10 |
00001010 |
|
0A |
|
|
|
|
Рассмотрим использование двоичной и шестнадцатеричной систем вместо десятичной на примере описанных раньше бегущих огнях, задействовав весь порт B, т.е. 8 выводов: RB0, RB1, … , RB7.
При использовании десятичной системы исчисления, как было раньше, нам необходимо описывать каждый вывод порта в отдельности: когда на нем будет единица, когда время паузы, когда на выводе будет ноль. Таким образом, получится громоздкий текст программы.
Рассмотрим теперь, как можно решить задачу бегущих огней с помощью других систем исчислений.
Возьмем для примера порт B. В нем есть 8 выводов, которые нумеруются от 0 до 7. На каждом из них может быть либо 1 либо 0. Определить, что будет на каждом из всех выводов порта можно одной командой, если использовать двоичную систему. Для записи числа в этой системе используется 8 символов: например, 00000001 = 1 в десятичной (смотрите таблицу выше). Номера выводов портов в МК обозначается справа налево: 76543210, и для того, чтобы задать значение для каждого вывода, можно записать вместо его номера то, что нужно: либо 1 либо 0. А теперь сравним эти две строчки: 76543210 и 00000001.
Как думаете, что будет на выводе 0? А на остальных? Правильный ответ: на нулевом выводе будет 1, а на остальных нули.
Еще раз: 76543210 и 01010101. На выводах 0, 2, 4, 6 будут единицы, а на выводах 1, 3, 5, 7 - нули.
Для того, чтобы сказать компилятору, что мы будем использовать двоичную систему, в начале самого числа ставим 0b.
Пример:
Двоичная запись 01010101 в шестнадцатеричной системе будет иметь вид 55. Ее так же можно использовать в программах, только перед самим числом в этой системе нужно поставить 0x, опять еж для того, чтобы компилятор знал какой системой мы пользуемся.
Пример:
PORTB=0x55; /*тоже самое, что и*/ PORTB=0b01010101; //только в разных системах исчислений. |

В десятичной же системе, число 01010101 будет равно 85. И его тоже можно использовать (PORTB=85), но уже совершенно непонятно, на каких выводах порта B, что он определяет.
Можно сделать вывод. Для описания конкретных величин лучше использовать десятичную систему, однако для определения состояния выводов портов – двоичную.
А теперь адаптируем нашу программу бегущих огней из
прошлой статьи под полученные знания. Кроме того, «повесим» светодиоды на все выводы порта B.
Полный текст программы будет в конце, здесь же переберем только саму функцию бегущих огней.
/*------------------------ Функция бегущего огня ----------------------------*/ void begogon () { temp=0b00000001; // Присваиваем temp значение состояния выводов // (на 0-вом 1, на остальных 0) while(knopka1==0 && knopka2 == 1 )// Цикл будет выполятя пока SW1 вкл и SW2 отпущена { if (temp!=0) // Если temp не равен нулю (0b00000000) { // вполняем цикл PORTB=temp; // Порту B присваиваем значение temp temp=temp<<1; // Сдвиг temp влево на 1 бит pause(); // Пауза } else temp=0b00000001; // Иначе (если temp=0), присваиваем temp нач. значение } } /*------------------------ Конец функции бегущего огня ----------------------*/ |
Из вышеописанного, есть новшество (temp=temp<<1;), которое нужно пояснить, но пойдем по порядку.
Временное хранилище значения temp у нас строковое (ввел в начале программы, смотрите в полном коде).
Сначала присваиваем ему начальное значение, которое хотим присвоить порту B. В данном случае 0b00000001 – нулевой светодиод горит, остальные нет.
Входим в цикл, следя за состояниями кнопок.
Проверяем условие: если temp не равно нулю (0b00000000, все светодиоды не горят), то присваиваем порту B значение которое сейчас хранится в temp (0b00000001, зажигается светодиод на нулевом выводе).
Изменяем значение temp. Запись temp=temp<<1; говорит МК о том, что расположение символов находящихся в temp сдвигается влево на 1 символ (бит), крайний правый бит при этом заменяется нулем. Если было temp=0b00000001, то станет temp=0b00000010. Если было, например temp=0b10101010, станет temp=0b01010100.
Пауза - все понятно, надеюсь.
Цикл повторяется сначала. С каждым циклом наша единица будет передвигаться в лево, а на прежнем ее месте будет образовываться 0. Светодиоды по очереди будут зажигаться и гаснуть. После того, как зажгутся последний светодиод (temp=0b10000000), содержимое temp опять сдвинется на один бит в лево и будет temp=0b00000000 – светодиоды не горят.
При следующем цикле будет проверятся условие if(temp!=0). Так как условие будет не верно (temp=0), то МК выполнит else temp=0b00000001; - присвоить temp значение 0b00000001 – светодиод один горит.
Все начинается сначала.
Так же следует заметить, что, используя двоичную систему, мы не только избежали громоздкого текста программы, описывая каждый вывод в отдельности, но и сэкономили место в МК. Я сначала написал программу, описывая каждый порт в отдельности, в результате чего скомпилированная прошивка весила 985 байт. При использовании вышеописанного метода hex файл уже весит 903 байта.
Так же любые вопросы можно обсудить на форуме.