Теперь у нас есть среда программирования и компилятор. Также у нас есть готовый проект. Поэтому теперь самое время заняться написанием какого-нибудь кода.
Ну и, по традиции, давайте напишем код, который будет управлять свечением светодиодов, подключенных к ножкам портов микроконтроллера. То есть за счёт поочерёдного поступления положительного потенциала от ножек портов на ножки светодиодов, а также нулевого номинала на другие ножки, мы создадим поочерёдное свечение и потухание светодиодов, за счёт чего произойдёт эффект бегущих огней. Почему именно нужно начинать с такого проекта? Да потому, что светодиоды, как ничто другое, позволяют наглядно оценить управление уровнями на ножках портов, в ту же очередь управление битами в регистрах специального назначения — а именно в регистрах портов ввода-вывода.
Сначала давайте соберём схему с контроллером PIC16F84A и подключенными через токоограничивающие резисторы светодиодами в программе-стимуляторе — Proteus
Также мы обязаны подать питание на соответствующие ножки, а также на соответствующие ножки обязаны подключить кварцевый резонатор и конденсаторы на 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 и внизу у нас появятся настроики этих самых битов конфигурации. Настроим там следующие занчения
Мы выбрали нужный кварцевый резонатор — это высокоскоростной резонатор от 4 мегагерц. Кстати, у нас будет установлен кварцевый резонатор именно на 4 мегагерца. Так как одна элементарная операция в нашем контроллере занимает 4 машинных цикла, то очень легко будет подсчитывать время. То есть операция будет выполняться ровно за 1 микросекунду.
Сохраним наши конфигурационные биты в удобочитаемый код с помощью нажатию на кнопку ниже
и получим код в окне вывода информации
Скопируем его и добавим в наш файл 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);
}
То есть мы поочерёдно включаем ножки, отключая при этом предыдущие. Всё просто.
Соберём код и попробуем его поотлаживать.
Для этого установим брейкпоинт на какую-нибудь строку
Запустим отладку соответствующей кнопкой на тулбаре
Программа остановится на заданной точке.
Давайте теперь посмотрим какие-нибудь регистры. Запустим сначала инструмент для просмотра всех регистров посредством команды меню Window -> PIC Memory Views -> File Registers
Мы увидим все регистры, то есть всю память в обоих банках, предназначенную для данных. Давайте прошагаем до следующей строчки с помощью соответствующей кнопки на тулбаре
У нас изменится только байт-счётчик, так как в бите RA1 у нас и так уже был ноль. Причём байт изменится в обоих банках ибо он банконезависимый
Шагнём ещё один шаг
И мы увидим что теперь байт по адресу 0x06 изменил своё значение
Причём не обязательно искать в даташите, что это за адрес, достаточно поднести курсор мыши к значению и мы увидим всё в подсказке
Только постоянно подносить курсор тоже не совсем удобно. Для этого есть другой инструмент, созданный именно для просмотра регистров специального назначения, который вызывается командой меню Window -> PIC Memory Views -> SFRs
Шагнём ещё пару шагов и увидим изменение в регистре порта B
Также существует ещё один интересный инструмент, позволяющий измерять время, за которое выполняется та или иная команда, а если поставить точку останова в другом месте и выполнить код сразу до неё, то и целого участка кода. Данный инструмент вызывается по команде меню Window -> Debugging -> Stopwatch. Вызовем его и шагнём одну команду
Мы видим, что команда выполнилась за 1 микросекунду, то есть за 1 машинный цикл. Сбросим время кнопкой Clearstopwatch
Время должно будет сброситься
Теперь прошагаем ещё одну команду. У нас как раз задержка, вот и измерим её время
Всё точно. 100 милисекунд. Остановим отладку, перейдём в Proteus. Настроим свойства контроллера, добавив там 16-битную величину наших конфигурационных битов, а также показав путь к нашей прошивке и задав частоту тактирования
Сохраним настройки и попробуем запустить проект. Мы должны увидеть, как светодиоды «побегут» сверху вниз
Конечно, в статической картинке я показать этого не смогу, поэтому смотрите видеоурок.
А теперь посмотрим нашу практическую схему, которую я собрал на макетной плате
Вместо десяти диодов была подключена светодиодная матрица, кварцевый резонатор подключен к ножкам контроллера 15 и 16 и от этих же ножек на общий провод подключены конденсаторы по 15 пикофарад каждый. Питать схему будем от программатора.
Программатор мы будем использовать PICkit2. У меня он клон. Настоящий фирменный у меня есть PICkit3, но так как для данной схемы достаточно и второго, да и не у всех есть третий, то будем использовать пока его.
А вот и программатор
Подключается данный программатор к контроллеру по интерфейсу ICSP следующим образом
PICkit — MC
1 (VPP) — 4
2 (VDD) — 14
3 (VSS) — 5
4 (ICSPDAT) — 13
5 (ICSPCLK) — 12
6 (Aux) — в нашем случае не используется
Давайте так его и подключим (нажмите на картинку для увеличения изображения)
Теперь, чтобы нам прошить наш файл в контроллер и проверить результат нашей работы по написанию кода, нам необходима будет программа. Скачаем и установим программу PICkit2. Так как на официальном сайте вы её вряд ли уже найдёте, то я её прикреплю к странице внизу.
Скачаем программу, установим её и запустим, подключив перед этим программатор к схеме, а с другой стороны — к USB-разъёму компьютера. Если всё подключено правильно, то программа сама обнаружит и определит контроллер
Покажем программе нашу прошивку, проследовав по пунктам меню File -> Import Hex и показав путь к файлу с прошивкой в файловом диалоге. Конфигурационные биты должны будут выставиться сами, как мы их и настраивали в среде программирования
Включим питание, заранее выставив напряжение. Пойдёт и 5 вольт, но я всегда на всякий случай выбираю 4,8. Включение питание производится установкой галки в чекбокс On
Прошьём нашу прошивку в контроллер с помощью кнопки Write, после чего контроллер должен будет перезагрузиться и программа должна будет начать выполняться, о чём будут свидетельствовать бегущие огни светодиодов в матрице
Таким образом, мы сегодня написали исходный код, научились некоторым приёмам отладки программы, а также испытали работу кода как в программе Proteus так и на практике.
Всем спасибо за внимание!
Предыдущий урок Программирование МК PIC Следующий урок
Программа для прошивки PICkit2
Купить программатор (неоригинальный) можно здесь: PICKit3
Купить программатор (оригинальный) можно здесь: PICKit3 original
Смотреть ВИДЕОУРОК в RuTube (нажмите на картинку)
Смотреть ВИДЕОУРОК в YouTube (нажмите на картинку)
судя по программе…. можно резисторы убрать и заменить одним в цепь светодиодов на землю
Судя по программе, можно, но если кто-то перепутает инверсию, то до свидания — контроллер.
и схема… так себе…. обычно светодиоды нулём зажигают, чтобы контроллер не перегружать…
поэтому- катодами в контроллер …. аноды в кучу и один резистор на +5
ну и программу переделать 🙂
Нет не так. Именно такая схема используется чаще. И токоограничивающие резисторы ставятся на каждую ножку порта, так как в случае зажигания нескольких светодиодов одновременно будет протекающий ток умножаться на количество зажжённых.
это вы серьёзно? 🙂
да хоть сотню светодиодов попробуйте зажечь…. один резистор в 250 ом — ни какому току не даст протечь 🙂
просто светодиоды гореть не будут…
я предложил упрощение схемы по вашей программе…..
кстати- 250 ом… это 20ма на ножку…. если все одновременно «загорятся»- контроллер выдержит?
По вашей схеме каждый последующий зажженный светодиод будет влиять на яркость свечения предыдущих, так что ваш вариант схемы, мягко говоря, неудачен.
Это общепринятая схема. У каждой ножки порта есть предельный ток, который она может выдержать. Можете проверить. Зажечь сразу все светодиоды, а затем один. Будет яркость 1 и та же.
Кстати в официальном мануале по FreeRTOS «Mastering the FreeRTOS™
Real Time Kernel» есть раздел 12.3 Stack Overflow. Может поможет.
для данной программы- нормальный вариант…. один гасится- другой зажигается 🙂
При 250 Ом ток будет (5В-2В)/250Ом = 12мА.
добавлю…. по даташиту…. порт В имеет максимальную нагрузку 100-150ма если все сразу зажечь, то контроллеру может поплохеть….
статья… для начинающих нормальная….
не обижайтесь за критику- просто я разработкой больше 20 лет занимаюсь 🙂
программу поменять надо…
сначала
TRISA=0xFF;
TRISB=0xFF;
а по тексту:
TRISBbits.TRISB4=0;
PORTBbits.RB4=1;
TRISBbits.TRISB4=1;
и т.д.
тогда точно одновременно не зажгутся
забыл про делей 🙂
TRISBbits.TRISB4=0;
PORTBbits.RB4=1;
__delay_ms(100);
TRISBbits.TRISB4=1;
TRISBbits.TRISB5=0;
PORTBbits.RB5=1;
__delay_ms(100);
TRISBbits.TRISB5=1;
кстати… неудобные посты… да и вообще все мои посты -можете удалить
Вы не объяснили назначение регистров,какой же это урок для начинающих?
TRIS – регистр выбора направления данных в каналах порта ввода/вывода, если соответствующий бит регистра «0», то линия вывода работает на выход, если «1» то на вход. По умалчиванию порт настроен на вход.
PORT – регистр порта , считывает логическую информацию с выводов порта.
Во первых, я нигде не заявлял, что уроки эти для начинающих.
1 предъява не принимается.
Назначение данного регистра очевидна и мы в этом убедились практически.
Здравствуйте.
Пытаюсь научиться писать (необходимые мне в дальнейшей работе) программы для микроконтроллеров, но пока сталкиваюсь с большим количеством трудностей в самых разных неожиданных для меня местах. Очень надеюсь на вашу помощь или ответы ваших читателей.
Так как мне будет для работы необходим другой контроллер — 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 В. Если внешний кварц — проверте генерацию, не срывается ли? Сложно давать советы более детальные не видя схему и текст программы.
Подскажите зачем с портом А при инициализации делать такие финты:
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?
Если мое предположение с сохранением предыдущего состояния верно,то: зачем делать инвертирование?
Компилятор ругается: Unable to resolve identifier __delay_ms
помогает следующая строка:
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))
Круто!
Достойный макрос.
Владимир, можно и по другому, зато нам показали как можно применять » & «. В будущем пригодиться.
Подскажите программу как подключить 13 светодиодов и задействовать все выводы портов А и В. У, меня, диод с порта А4 не загорается.
PORTAbits.RA0 = 1;
PORTAbits.RA1 = 0;
PORTAbits.RA2 = 0;
PORTCbits.RC0 = 0;
PORTCbits.RC1 = 0;
В протеусе эти команды вместе почему то не работают. Мне нужно каждый регистр менять по отдельности не затрагивая другие порты. Если командой porta = 0b00000001 я могу выставить первый выход в 1 то как мне остальные не трогать?
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 и сборки появляются такие строки. Как исправить?
У мня тоже самое ругался я в место __delay_ms, написал delay(), только в скобках надо указывать другое значение а то прерывания быстрые , не знаю по чему ругается компилятор __delay_ms(); красным не подсвечивает