PIC Урок 3. Бегущие огни



Теперь у нас есть среда программирования и компилятор. Также у нас есть готовый проект. Поэтому теперь самое время заняться написанием какого-нибудь кода.

Ну и, по традиции, давайте напишем код, который будет управлять свечением светодиодов, подключенных к ножкам портов микроконтроллера. То есть за счёт поочерёдного поступления положительного потенциала от ножек портов на ножки светодиодов, а также нулевого номинала на другие ножки, мы создадим поочерёдное свечение и потухание светодиодов, за счёт чего произойдёт эффект бегущих огней. Почему именно нужно начинать с такого проекта? Да потому, что светодиоды, как ничто другое, позволяют наглядно оценить управление уровнями на ножках портов, в ту же очередь управление битами в регистрах специального назначения — а именно в регистрах портов ввода-вывода.

Сначала давайте соберём схему с контроллером PIC16F84A и подключенными через токоограничивающие резисторы светодиодами в программе-стимуляторе — Proteus

 

image00

 

Также мы обязаны подать питание на соответствующие ножки, а также на соответствующие ножки обязаны подключить кварцевый резонатор и конденсаторы на 15 пикофарад. Но, как известно, в проетусе этого делать необязательно. Всё и так будет работать. А в практической схеме, конечно, .об этом ни в коем случае нельзя забывать.

Далее откроем наш проект и настроим ножки портов, к которым подключены светодиоды, на выход. Делается это подобно тому, как мы это делали, когда работали с микроконтроллерами AVR. Также установим низкий уровень на этих ножках, так как в отличие от AVR при старте может быть любой случайный уровень, нам этого не нужно

 

void main(void) {

  TRISB = 0x00;

  PORTB = 0x00;

  TRISA &= ~0x03;

  PORTA &= ~0x03;

  while(1)

 

Чуть не забыл, давайте настроим конфигурационные биты. Это биты, без которых нам не обойтись. С помощью них мы настраиваем некоторые свойства нашего контроллера, подобна фьюзам в AVR. Для того, чтобы более удобно их настраивать, есть специальный инструмент в среде программирования MPLAB X IDE.

Проследуем по пунктам меню Window -> PIC Memory Views -> Configuration Bits и внизу у нас появятся настроики этих самых битов конфигурации. Настроим там следующие занчения

 

image01

 

Мы выбрали нужный кварцевый резонатор — это высокоскоростной резонатор от 4 мегагерц. Кстати, у нас будет установлен кварцевый резонатор именно на 4 мегагерца. Так как одна элементарная операция в нашем контроллере занимает 4 машинных цикла, то очень легко будет подсчитывать время. То есть операция будет выполняться ровно за 1 микросекунду.

Сохраним наши конфигурационные биты в удобочитаемый код с помощью нажатию на кнопку ниже

 

image02

 

и получим код в окне вывода информации

 

image03

 

Скопируем его и добавим в наш файл main.c сразу после подключения библиотеки и заодно сразу объявим частоту нашего резонатора, иначе у нас не будут работать корректно задержки

 

#include <xc.h>

 

#define _XTAL_FREQ 4000000

 

#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)

#pragma config WDTE = OFF // Watchdog Timer (WDT disabled)

#pragma config PWRTE = ON // Power-up Timer Enable bit (Power-up Timer is enabled)

#pragma config CP = OFF // Code Protection bit (Code protection disabled)

 

Теперь давайте с помощью удобных инструкций (написанных с помощью макросов в стандартной библиотеке PIC) добавим код в бесконечный цикл

 

while(1)

{

  PORTAbits.RA1 = 0;

  PORTBbits.RB0 = 1;

  __delay_ms(100);

  PORTBbits.RB0 = 0;

  PORTBbits.RB1 = 1;

  __delay_ms(100);

  PORTBbits.RB1 = 0;

  PORTBbits.RB2 = 1;

  __delay_ms(100);

  PORTBbits.RB2 = 0;

  PORTBbits.RB3 = 1;

  __delay_ms(100);

  PORTBbits.RB3 = 0;

  PORTBbits.RB4 = 1;

  __delay_ms(100);

  PORTBbits.RB4 = 0;

  PORTBbits.RB5 = 1;

  __delay_ms(100);

  PORTBbits.RB5 = 0;

  PORTBbits.RB6 = 1;

  __delay_ms(100);

  PORTBbits.RB6 = 0;

  PORTBbits.RB7 = 1;

  __delay_ms(100);

  PORTBbits.RB7 = 0;

  PORTAbits.RA0 = 1;

  __delay_ms(100);

  PORTAbits.RA0 = 0;

  PORTAbits.RA1 = 1;

  __delay_ms(100);

}

 

То есть мы поочерёдно включаем ножки, отключая при этом предыдущие. Всё просто.

 

 

Соберём код и попробуем его поотлаживать.

Для этого установим брейкпоинт на какую-нибудь строку

 

image04

 

Запустим отладку соответствующей кнопкой на тулбаре

 

image05

 

Программа остановится на заданной точке.

Давайте теперь посмотрим какие-нибудь регистры. Запустим сначала инструмент для просмотра всех регистров посредством команды меню Window -> PIC Memory Views -> File Registers

 

image06

 

Мы увидим все регистры, то есть всю память в обоих банках, предназначенную для данных. Давайте прошагаем до следующей строчки с помощью соответствующей кнопки на тулбаре

 

image07

 

У нас изменится только байт-счётчик, так как в бите RA1 у нас и так уже был ноль. Причём байт изменится в обоих банках ибо он банконезависимый

 

image08

 

Шагнём ещё один шаг

 

image09

 

И мы увидим что теперь байт по адресу 0x06 изменил своё значение

 

image10

 

Причём не обязательно искать в даташите, что это за адрес, достаточно поднести курсор мыши к значению и мы увидим всё в подсказке

 

image11

 

Только постоянно подносить курсор тоже не совсем удобно. Для этого есть другой инструмент, созданный именно для просмотра регистров специального назначения, который вызывается командой меню Window -> PIC Memory Views -> SFRs

 

image12

 

Шагнём ещё пару шагов и увидим изменение в регистре порта B

 

image13

 

Также существует ещё один интересный инструмент, позволяющий измерять время, за которое выполняется та или иная команда, а если поставить точку останова в другом месте и выполнить код сразу до неё, то и целого участка кода. Данный инструмент вызывается по команде меню Window -> Debugging -> Stopwatch. Вызовем его и шагнём одну команду

 

image14

 

Мы видим, что команда выполнилась за 1 микросекунду, то есть за 1 машинный цикл. Сбросим время кнопкой Clearstopwatch

 

image15

 

Время должно будет сброситься

 

image16

 

Теперь прошагаем ещё одну команду. У нас как раз задержка, вот и измерим её время

 

image17

 

 

Всё точно. 100 милисекунд. Остановим отладку, перейдём в Proteus. Настроим свойства контроллера, добавив там 16-битную величину наших конфигурационных битов, а также показав путь к нашей прошивке и задав частоту тактирования

 

image18

 

Сохраним настройки и попробуем запустить проект. Мы должны увидеть, как светодиоды «побегут» сверху вниз

 

image19

 

Конечно, в статической картинке я показать этого не смогу, поэтому смотрите видеоурок.

А теперь посмотрим нашу практическую схему, которую я собрал на макетной плате

 

image20

 

Вместо десяти диодов была подключена светодиодная матрица, кварцевый резонатор подключен к ножкам контроллера 15 и 16 и от этих же ножек на общий провод подключены конденсаторы по 15 пикофарад каждый. Питать схему будем от программатора.

Программатор мы будем использовать PICkit2. У меня он клон. Настоящий фирменный у меня есть PICkit3, но так как для данной схемы достаточно и второго, да и не у всех есть третий, то будем использовать пока его.

А вот и программатор

 

image21

 

Подключается данный программатор к контроллеру по интерфейсу ICSP следующим образом

 

PICkit — MC

1 (VPP) — 4

2 (VDD) — 14

3 (VSS) — 5

4 (ICSPDAT) — 13

5 (ICSPCLK) — 12

6 (Aux) — в нашем случае не используется

 

Давайте так его и подключим (нажмите на картинку для увеличения изображения)

 

image23_0500

 

Теперь, чтобы нам прошить наш файл в контроллер и проверить результат нашей работы по написанию кода, нам необходима будет программа. Скачаем и установим программу PICkit2. Так как на официальном сайте вы её вряд ли уже найдёте, то я её прикреплю к странице внизу.

Скачаем программу, установим её и запустим, подключив перед этим программатор к схеме, а с другой стороны — к USB-разъёму компьютера. Если всё подключено правильно, то программа сама обнаружит и определит контроллер

 

image24

 

Покажем программе нашу прошивку, проследовав по пунктам меню File -> Import Hex и показав путь к файлу с прошивкой в файловом диалоге. Конфигурационные биты должны будут выставиться сами, как мы их и настраивали в среде программирования

 

image25

 

Включим питание, заранее выставив напряжение. Пойдёт и 5 вольт, но я всегда на всякий случай выбираю 4,8. Включение питание производится установкой галки в чекбокс On

 

image26

 

Прошьём нашу прошивку в контроллер с помощью кнопки Write, после чего контроллер должен будет перезагрузиться и программа должна будет начать выполняться, о чём будут свидетельствовать бегущие огни светодиодов в матрице

 

image27

 

Таким образом, мы сегодня написали исходный код, научились некоторым приёмам отладки программы, а также испытали работу кода как в программе Proteus так и на практике.

Всем спасибо за внимание!

 

 

Предыдущий урок Программирование МК PIC Следующий урок

 

Исходный код

 

 

Программа для прошивки PICkit2

 

 

Купить программатор (неоригинальный) можно здесь: PICKit3

Купить программатор (оригинальный) можно здесь: PICKit3 original

 

 

Смотреть ВИДЕОУРОК в RuTube (нажмите на картинку)

PIC Бегущие огни

 

Смотреть ВИДЕОУРОК в YouTube (нажмите на картинку)

PIC Бегущие огни

26 комментариев на “PIC Урок 3. Бегущие огни
  1. Сергей:

    судя по программе…. можно резисторы убрать и заменить одним в цепь светодиодов на землю

  2. Сергей:

    и схема… так себе…. обычно светодиоды нулём зажигают, чтобы контроллер не перегружать…
    поэтому- катодами в контроллер …. аноды в кучу и один резистор на +5
    ну и программу переделать 🙂

    • Нет не так. Именно такая схема используется чаще. И токоограничивающие резисторы ставятся на каждую ножку порта, так как в случае зажигания нескольких светодиодов одновременно будет протекающий ток умножаться на количество зажжённых.

      • Сергей:

        это вы серьёзно? 🙂
        да хоть сотню светодиодов попробуйте зажечь…. один резистор в 250 ом — ни какому току не даст протечь 🙂
        просто светодиоды гореть не будут…
        я предложил упрощение схемы по вашей программе…..
        кстати- 250 ом… это 20ма на ножку…. если все одновременно «загорятся»- контроллер выдержит?

        • imperror:

          По вашей схеме каждый последующий зажженный светодиод будет влиять на яркость свечения предыдущих, так что ваш вариант схемы, мягко говоря, неудачен.

          • Это общепринятая схема. У каждой ножки порта есть предельный ток, который она может выдержать. Можете проверить. Зажечь сразу все светодиоды, а затем один. Будет яркость 1 и та же.

          • Кстати в официальном мануале по FreeRTOS «Mastering the FreeRTOS™
            Real Time Kernel» есть раздел 12.3 Stack Overflow. Может поможет.

          • Сергей:

            для данной программы- нормальный вариант…. один гасится- другой зажигается 🙂

        • Игорь:

          При 250 Ом ток будет (5В-2В)/250Ом = 12мА.

  3. Сергей:

    добавлю…. по даташиту…. порт В имеет максимальную нагрузку 100-150ма если все сразу зажечь, то контроллеру может поплохеть….

    статья… для начинающих нормальная….
    не обижайтесь за критику- просто я разработкой больше 20 лет занимаюсь 🙂

  4. Сергей:

    программу поменять надо…
    сначала
    TRISA=0xFF;
    TRISB=0xFF;
    а по тексту:
    TRISBbits.TRISB4=0;
    PORTBbits.RB4=1;
    TRISBbits.TRISB4=1;

    и т.д.

    тогда точно одновременно не зажгутся

  5. Сергей:

    забыл про делей 🙂
    TRISBbits.TRISB4=0;
    PORTBbits.RB4=1;
    __delay_ms(100);
    TRISBbits.TRISB4=1;
    TRISBbits.TRISB5=0;
    PORTBbits.RB5=1;
    __delay_ms(100);
    TRISBbits.TRISB5=1;

  6. Сергей:

    кстати… неудобные посты… да и вообще все мои посты -можете удалить

  7. Вы не объяснили назначение регистров,какой же это урок для начинающих?
    TRIS – регистр выбора направления данных в каналах порта ввода/вывода, если соответствующий бит регистра «0», то линия вывода работает на выход, если «1» то на вход. По умалчиванию порт настроен на вход.
    PORT – регистр порта , считывает логическую информацию с выводов порта.

    • Во первых, я нигде не заявлял, что уроки эти для начинающих.
      1 предъява не принимается.
      Назначение данного регистра очевидна и мы в этом убедились практически.

  8. Елена:

    Здравствуйте.
    Пытаюсь научиться писать (необходимые мне в дальнейшей работе) программы для микроконтроллеров, но пока сталкиваюсь с большим количеством трудностей в самых разных неожиданных для меня местах. Очень надеюсь на вашу помощь или ответы ваших читателей.

    Так как мне будет для работы необходим другой контроллер — PIC16F73, то и эту программу я переписала для него (пока для части ног портов B и C потому что в дальнейшей работе будут задействованы именно они) — заодно для проверки работоспособности имеющихся у меня контроллеров вообще (так как более сложный проект сразу не получился).
    Резисторы в вашей схеме чуть увеличила — поставила 270 Ом. Плюс ещё добавила светодиод с сопротивлением 330 Ом непосредственно на питание (между + и — на входе).
    И столкнулась с неожиданными для меня явлениями.
    1) сразу после прошивки программы в контроллер (программатор у меня PICkit3, но не фирменный. Но MPLab его «видит»),контроллер НЕ перезагружается и выполнение программы НЕ начинается. Хотя питание на схему программатор подаёт и после прошивки. Пробовала на нескольких экземплярах контроллеров. Может быть нужно специально подать контроллеру какой-то сигнал?
    2) Если после прошивки питание от программатора отключить и подать иное внешнее питание, то выполнение программы начинается, но бесконечный цикл выполняется не бесконечно, а несколько раз (от 1-2-3 — чаще всего до нескольких десятков изредка). Т.е. огоньки пробегают несколько раз и больше не бегут — гаснут, хотя питание по прежнему подано. От чего именно зависит кол-во повторений так и не поняла. Думала, что от конкретного экземпляра контроллера, но многократные повторения с разными экземплярами контроллеров показали, что не только от этого.
    3) После того как огоньки погасли, снятие и повторная подача напряжения далеко не всегда приводит к тому, что они снова побегут. Чаще всего они НЕ бегут. Что приводит к мысли, что контроллер как-то испортился. Но через некоторое время (проведённое контроллером при выключенном питании) часто снова начинают бежать.

    Что же это за проблемы? И как их решить?? Особенно
    волнуют 2 и 3.
    Всё имеющиеся у меня контроллеры «дохлые»?
    Что-то не так с питанием? Источник даёт недостаточный ток питания? Пробовала USB порт компьютера и блок питания зарядного устройства (который вроде может выдавать до 1А).
    Может велико напряжение питания? Оба доступных мне внешних источника, судя по мультиметру, выдают напряжение 6В. (А по инструкции к контроллеру максимальное напряжение питания — 5.5). Программатор при установке в MPLab 5В выдаёт тоже 6В по мультиметру. Поэтому при прошивке ставлю в настройках 4.5В, тогда на выходе на контроллер намеревается 5.5В.

    Посоветуйте пожалуйста мне что-нибудь…

    • Александр:

      Елена, не превышайте напряжения питания выше 5 В. Если внешний кварц — проверте генерацию, не срывается ли? Сложно давать советы более детальные не видя схему и текст программы.

  9. Владимир:

    Подскажите зачем с портом А при инициализации делать такие финты:
    TRISA &= ~0x03;
    PORTA &= ~0x03;
    Я так понимаю что это:
    1. сначала инвертирует (~0x03) и мы получаем: 1111 1100.
    2. TRISA после любого ресета имеет 00011111 (так как порт имеет 5ть выводов)
    3. Далее мы делаем поразрядное И и записываем в TRISA — таким образом насильно записываем в два младших 00, и получаем 0x1C в регистре. Это можно сделать и сразу: TRISA = 0xFC (TRISA = 0x1C).
    PORTB — тоже. Но там после включении питания состояние неопределенно и логически было бы его обнулить.
    После других ресетов состояние портов не меняется и после &= в PORTA мы не меняем 2, 3, 4 бит но насильно сбиваем в 0 младшие, которые используем. В данной схеме это не нужно, но на будущее это хороший трюк. Но зачем это делать с TRISA, и почему мы не делаем єто с PORTB?
    Если мое предположение с сохранением предыдущего состояния верно,то: зачем делать инвертирование?

  10. Дмитрий:

    Компилятор ругается: Unable to resolve identifier __delay_ms
    помогает следующая строка:
    #define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))

  11. Алекс:

    Владимир, можно и по другому, зато нам показали как можно применять » & «. В будущем пригодиться.

  12. Олег:

    Подскажите программу как подключить 13 светодиодов и задействовать все выводы портов А и В. У, меня, диод с порта А4 не загорается.

  13. Фаизнур:

    PORTAbits.RA0 = 1;
    PORTAbits.RA1 = 0;
    PORTAbits.RA2 = 0;
    PORTCbits.RC0 = 0;
    PORTCbits.RC1 = 0;
    В протеусе эти команды вместе почему то не работают. Мне нужно каждый регистр менять по отдельности не затрагивая другие порты. Если командой porta = 0b00000001 я могу выставить первый выход в 1 то как мне остальные не трогать?

  14. mole85:

    make[2]: *** [build/default/production/main.p1] Error 1
    make[1]: *** [.build-conf] Error 2
    make: *** [.build-impl] Error 2
    main.c:10:1: error: expected '}'
    ^
    Здравствуйте. Решил научиться писать программы самостоятельно. MPLAMPLAB X IDE v6.00 После копирования программы с сайта в окно MPLAMPLAB X IDE v6.00 и сборки появляются такие строки. Как исправить?

  15. Сергей:

    У мня тоже самое ругался я в место __delay_ms, написал delay(), только в скобках надо указывать другое значение а то прерывания быстрые , не знаю по чему ругается компилятор __delay_ms(); красным не подсвечивает

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*