Печать
Категория: PIC
Просмотров: 6694

Среда разработки программ для микроконтроллеров 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.

Пример:
PORTB=0b01010101;

Двоичная запись 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 байта.

Так же любые вопросы можно обсудить на форуме.

Авторизоваться, чтобы комментировать
belperson ответил в теме #500 1 год 5 мес. назад
Все приходит с опытом. Комментариев давать не буду, так как сам программирую исключительно ради хобби. С кнопками большая часть вопросов отпадет, когда освоишь прерывания.
И вот еще: иногда костыль может быть фичей=) Так, что меньше об этом думай. Удачи.
wade ответил в теме #499 1 год 5 мес. назад
Спасибо за советы! мне они помогли! Статью про сдвиги прочитал, но не все понял из нее.
Код изменил, теперь все работает нормально. А могли бы вы дать какиенить комментарии по коду? Все ли я делаю правильно? мне кажется, что я в некоторых местах использую костыли, когда можно сделать проще. И еще у меня небольшие проблемы в коде из следующей статьи. Вроде все работает, но бывают глюки в переключении кнопок и тоже кажется, что сделал кривовато.
belperson ответил в теме #498 1 год 5 мес. назад
1. Не злоупотребляйте сдвигами! Вот вам статья для раздумья: Я не профессиональный программист, но придерживаюсь правила всегда учитывать даже незначительные моменты и не допускать неопределённостей.
Я бы в функции бегущего огня вместо
ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]

написал бы
ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]

2.Давайте прочитаем ваш код:
ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]

if (knopka1==0) begogon(); - если кнопка один нажата, то выполняется функция бегущего огня,
else PORTB.F0=1; - иначе зажигаем светодиод на PB0.
А кто должен гасить светодиод, который зажгла функция "бегущий огонь"?
wade ответил в теме #497 1 год 5 мес. назад
Проект собрал и все работает, но есть пару вопросов:
1. После того, как гаснет последний светодиод, проходит достасточно времени(порядка 3-4 сек), пока вновь загорится первый светодиод и цикл пойдет по новой. Не могу понять, с чем это связано.
2. Теперь, когда я отпускаю кпонку1, загорается "дежурный" светодиод и продолжает гореть последний светодиод, на котором остановился цикл. Тоже не пойму, в чем дело.
github.com/e-Wade/Lesson9/blob/master/lesson9