Расширение количества портов микроконтролера pic18 через spi-интерфейс

Порты ввода/вывода МК PIC18XXXX

  • TRIS – регистр выбора направления данных в каналах  порта ввода/вывода, если соответствующий бит регистра “0”, то линия вывода работает на выход, если “1” то на вход. По умалчиванию порт настроен на вход.
  •  PORT – регистр порта , считывает логическую информацию с выводов порта.
  •   LAT – защелка порта ввода/вывода. (Очень полезный регистр. Подробней в статье…)

Порты ввода/вывода имеет буквенное обозначение. A, B, C ..и т.д., в зависимости от количества портов в микроконтроллере.

Каждый порт имеет свои регистры управления, порт “A”  к примеру: TRISA, PORTA, LATA, порт”B”  TRISB, PORTB, LATB и т.д..

Рассмотрим настройку порта:

Допустим  необходимо настроить порт “С”, линии вывода  С0-С3 на выход, а остальные на вход, для этого настраиваем регистр TRIS. Очень удобно записывать в двоичной системе .

       movlw        b'11110000' ; movwf              TRISC ;

Если необходимо весь порт настроить на выход, то достаточно очистить регистр TRIS.

       clrf              TRISC ;

На вход настраивать не нужно  (по умалчиванию).

То же самое и с другими регистрами.

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

Хотя типов микроконтроллеров достаточно много, тем не менее  практически все они “построены на базовом варианте” и рассматривая МК PIC18252 многое относится и к другим микроконтроллерам 18 серии.

На пример;

  • аналоговые линии располагаются в порту “А”, (если аналоговых входов больше, то  дополнительно в порту “В”).
  • подключение основного генератора.
  • линии порта”В” можно аппаратно подтянуть к шине питания +5В.
  • и т.д..

Порт”А”.

7-разрядный или 8-разрядный (в зависимости от типа МК) порт ввода/вывода. Линия  RA4/T0CKI  имеет триггер Шмитта на входе и открытый сток на  выходе, мультиплексирован  с  тактовым входом таймера TMR0. Для формирования на его выходе  “1” необходимо   подтянуть вывод внешним  резистором к  шине  питания +5В.

Каналы PORTA мультиплексированы  с  аналоговыми  входами  АЦП  и  аналоговым  входом  источника опорного напряжения VREF+ и VREF-. Если модуль АЦП не задействуется, то при конфигурации  нужно настроить линии порта как  цифровые каналы, т.к. при сбросе или  включении питания микроконтроллера часть линий ввода/вывода устанавливается как аналоговые входы.

Инициализация порта”А”

clrf PORTA ; очистка порта. movlw 07h ; настройка как цифровых movwf ADCON1 ; каналов ввода/вывода. movlw b'00000111 ; настройка RA0-2 на вход movwf TRISA ; остальные на выход.(пример)

Для настройки каналов, мультиплексированных с АЦП  вместо регистра ADCON1 (в зависимости от типа МК может применятся другой регистр “ANSEL”). Настройка порта  для работы с АЦП рассмотрена в соответствующей теме.

Порт”B”.

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

Для настройки каналов, мультиплексированных с АЦП  применяется регистр управления “ANSELH” (в зависимости от типа МК, к примеру в PIC18FXX2 его нет, как нет и каналов АЦП  на этом порту).

По этому, если АЦП на порту не задействовано, то  с помощью этого регистра необходимо настроить каналы как цифровые линии ввода/вывода.

В некоторых типов МК 18 серии для настройки отдельных цифровых каналов ввода/вывода порта”В”, при конфигурации микроконтроллера необходимо прописать   PBADEN=ON.

Инициализация порта “B” PIC18FXX2. (пример)

clrf PORTB ; очистка порта. movlw 07h ; настройка как цифровых movwf ADCON1 ; каналов ввода/вывода. movlw b'00000111 ; настройка RA0-2 на вход movwf TRISB ; остальные на выход.(пример)

Инициализация порта “B” PIC18FXXK20.(пример)

clrf PORTB ; очистка порта. Можно регистр LATB. clrf ANSELH ; цифровые каналы, конф.бит PBADAN должен установлен. movlw b'00000111 ; настройка RB0-2 на вход movwf TRISB ; остальные на выход.(пример)

Каналы порта часто применяют как источник прерываний . К примеру, изменение логического состояния на входе каналов RB4-7 часто применяют для опроса кнопок. (более подробно  можно почитать в статье….).

Порт”С”.

Восьмиразрядный  порт ввода/вывода. На этом порту сосредоточены  в основном модули “связи”, SPI, I2C, USART. Кроме этого различные модули таймеров и ШИМ.  Обычно если модули не задействованы, то  линии  работают как цифровые каналы вводы/вывода. Настройка порта производится с помощью специальных регистров TRISC, LATC, PORTC.

Порт”D”,”E”.

В зависимости от типа микроконтроллера порт”Е” бывает трех или восьмиразрядным  портом ввода/вывода, Порт”D” восьмиразрядный.

Настройка порта “D” производится с помощью специальных регистров TRISD, LATD, PORTD. Порта “E” соответственно регистры TRISЕ, LATЕ, PORTЕ.

В некоторых типах микроконтроллеров могут быть специальные порты для управления LCD индикатором. А так же  различные модули (специализированные  МК) для управления нагрузкой и т.д..

Источник: https://chipmk.ru/2014-08-10-05-51-44/41-samouchitel-pic18-asm-2-chast/190-porty-vvoda-vyvoda-mk-pic18xxxx

Знакомство с TCP стеком для микроконтроллеров фирмы Microchip

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

•Преобразователь RS-232—Ethernet, обычно представляющий собой виртуальный COM-порт, преобразующий поток данных RS-232 в IP-пакеты на одном конце, и неким устройством, которое занимается приёмом и раскодированием этих пакетов, и отдающее контроллеру в виде RS-232 на другом конце. Пример подобного устройства: Tibbo EM100.

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

Недостатки у такого решения тоже имеются—не получится использовать протоколы более высоких уровней, такие, как SNMP, HTTP и прочие, т.е. о WEB-интерфейсе, к примеру, можно забыть.

•Некое продвинутое устройство, «чёрный ящик», который обладает своим процессором, памятью, стеком протоколов, сам занимается обработкой Ethernet-пакетов, и наружу отдаёт опять же RS-232 или SPI.

Примеры таких решений: Lantronix XPort, представляющий собой законченный ультракомпактный встраиваемый сервер размером чуть больше разъёма RG-45:микросхема WIZNET W5100, и основанный на ней Arduino Ethernet Shield: Тут у разработчика уже больше свободы, например, можно поднять на этом контроллере WEB-сервер или Telnet, и через них управлять встраиваемым устройством. Из недостатков можно отметить невысокую гибкость (можно использовать только те протоколы, которые заложили разработчики) и высокую стоимость, зачастую превышающую стоимость управляемого устройства. •Взять контроль в свои руки, подключив к своему любимому контроллеру драйвер физического уровня (PHY), такой как микросхема ENC28J60 стандарта 10 Base-T, или микросхема ENC624J600 стандарта 10/100 Base-T от всё той-же фирмы Microchip, или же взять контроллер семейства PIC18FXXJXX со встроенным PHY, и программно реализовать все необходимые протоколы. Стек протоколов можно написать самому (не слишком тривиальная задача), или воспользоваться уже готовым стеком (существует довольно большой выбор TCP стеков для микроконтроллеров различных производителей разной степени бесплатности и качества). В этой статье будет представлен краткий обзор TCP стека фирмы Microchip, предназначенный для применения на микроконтроллерах этой фирмы. Итак, путь ясен, время определиться с инструментами.

Нам понадобятся:

•Один из поддерживаемых этих стеком контроллеров. Если будем использовать внешнюю микросхему PHY, то практически любой МК производства Microchip, семейств PIC18 (8бит), PIC24 (16бит), и PIC32 (32бит). Если хотим обойтись без внешнего PHY, берём что-нибудь из семейства PIC18F67J60.

•TCP/IP стек Microchip. Cтек входит в состав Microchip Application Libraries (далее MAL). Библиотека бесплатная, поддерживает довольно широкий ряд контроллеров Microchip, и помимо TCP стека содержит так-же стек USB, библиотеку для работы с тач-скринами, смарт-картами и т.п.

Последнюю версию библиотеки можно взять тут.

•Среда разработки. Бесплатные MPLab 8 (слегка устаревшая, но проверенная годами), или MPLab-X (вышедшая с Beta-стадии пару месяцев назад, основанная на Netbeans, перспективная, но пока не слишком стабильная среда разработки).

•Компилятор. Официально поддерживаются C18, C30, и C32. Ознакомительную 60-и дневную версию можно скачать с сайта. Через 60 дней ознакомительная версия остаётся функциональной, но выключает режим оптимизации, в связи с чем код может потребовать больше места в ROM.

•Программатор и (или) внутрисхемный отладчик. Рекомендую ICD3 или PICKIT3 (ICD2 тоже работает, но не поддерживается средой Mplab-X, и более медленная). Вместо пайки своей платы, можно воспользоваться одним из многочисленных отладочных комплектов, производства фирмы Microchip (которые всем хороши, кроме своей цены и трудностью покупки в России):

  • PIC18 Explorer с дочерней платой PICTail
  • Explorer 16 c дочерней платой PICTail+
  • PIC32 Starter Kit с платой расширения IO Expansion Board и PICTail+ (в этом случае не понадобится внешний отладчик, т.к. в PIC32 Starter Kit он уже встроен)

Существуют и альтернативные решения от фирм Olimex (ENC28J60-H) и «Тритон» (TRT-Ethernet).

Если мы решили сразу делать свою плату:

Можно задействовать как контроллер со встроенным PHY (PIC18F87J60)либо контроллер с внешним PHY (ENC28J60), подключенным по шине SPI (например, ENC28J60): Из внешней обвязки понадобится только трансформатор (например, PULSE H1012), разъём RJ-45 (существуют разъёмы RJ-45 сразу со встроенным трансформатором и светодиодами), да десяток резисторов. Для тактирования контроллера обязателен кварц на 25 МГц (при этом внутренняя частота МК может быть поднята до 40МГц при помощи PLL). Обратите внимание, что во внешнем PHY контроллере ENC624J600 уже содержится прошитый MAC-адрес, тогда как в ENC28J60 и PIC18F87J60 его нет, и нужно либо использовать покупную микросхему, содержащую MAC, либо устанавливать его програмно. Так же на этом этапе надо определиться, где будут храниться файлы для WEB-сервера и SNMP mib-ы. Вариантов несколько: или непосредственно в памяти программ контроллера (а при среднем размере стека с набором необходимых модулей ~33кб и контроллером с внутренней ROM 128кб мы получим ~95кб места для файлов), или использовать внешнюю микросхему EEPROM (стек поддерживает 25LC1024), FLASH (серия SST25), SD-карту или даже USB-диск (понадобится PIC32 с USB на борту). Итак, с «железом» определились, посмотрим теперь, что же может предложить нам эта библиотека?

Поддерживаемый функционал:

•Протоколы: ARP, IP, ICMP, UDP, TCP, DHCP, SNMP, SMTP, HTTP, FTP, TFTP •Поддержка TCP и UDP •Поддержка SSL •Поддержка NetBIOS •Поддержка DNS

Стек поддерживаемых протоколов:

Имеются исходники http-сервера, поддерживающего GET и POST запросы, SSL-аутентификацию и сжатие GZIP, клиент и сервер ICMP, клиент и сервер SNMP (версии 1, 2 и 3, в т.ч. SNMP TRAP), программный мост TCP2UART, сервер TELNET, клиент DynDNS, DNS, DHCP, и многое другое.

При всём при этом, стек занимает не так много памяти.

Так, реальный проект, содержащий WEB-сервер, DHCP и DNS-клиент, мост Ethernet─Serial, сервер TFTP и SNMP, клиент SMTP, потребует порядка 33 килобайта памяти программ (ROM) и 2 килобайта памяти данных (RAM), при том, что типичный размер памяти PIC18F67J60 составляет 128кб.

Производительность стека:

Источник: https://habr.com/post/138081/

» Интерфейс SPI

Кратко о SPI

Serial Peripheral Interface или SPI — последовательный периферийный интерфейс, служит для связи периферии и микроконтроллера.

Например, в качестве периферии может быть: дисплей, различные датчики, FLASH память, SD карта (да, да, SD карта или «флешка» которую вы используете в телефонах и фотоаппаратах общается с внешним миром с помощью интерфейса SPI) и т.д.

К сожалению официальной документации на интерфейс SPI нет, поэтому данный пост основывается на различных статьях в Интернете, собственного опыта и документации на микроконтроллеры.

О том что такое SPI читайте в статьях википедии

http://ru.wikipedia.org/wiki/Serial_Peripheral_Interface
http://en.wikipedia.org/wiki/SPI_bus

В SPI всегда есть один ведущий и один/несколько ведомых.

Передачу данных всегда инициализирует ведущий.

В SPI используются четыре линии связи:

  • MOSI или SI — выход ведущего, вход ведомого (англ. MasterOutSlaveIn). Служит для передачи данных от ведущего устройства ведомому.
  • MISO или SO — вход ведущего, выход ведомого (англ. MasterInSlaveOut). Служит для передачи данных от ведомого устройства ведущему.
  • SCLK или SCK — последовательный тактовый сигнал (англ. SerialClock). Служит для передачи тактового сигнала для ведомых устройств.
  • CS или SS — выбор микросхемы, выбор ведомого (англ. Chip Select, Slave Select).

P.S.

Для обеспечения односторонней связи с одним устройством, достаточно использовать SCLK, MOSI (в случае если ведомое устройство только принимает) или SCLK, MISO (в случае если ведомое устройство ничего не принимает, а только передает информацию). На входе CS ведомого устройства должен быть установлен логический ноль, иначе ведомый не будет работать.

P.S.

 Если ведомое устройство и передает и принимает, то можно ограничиться тремя проводами – MISO, MOSI, SCLK, на вход CS ведомого устройства также необходимо установить логический ноль.

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

Например, для ATmega328Р (микроконтроллер компании Atmel) при работе с SPI нам нужно самим программным путем установить на SS логический ноль при начале приема/передачи и установить логическую единицу обратно при окончание передачи.

Для передачи данных к ведомому устройству, нужно в сдвигающий регистр MASTER-а (на изображение сдвигающий регистр мастера — «8 BIT SHIFT REGISTER») записать байт передаваемой информации. При этом автоматически на SCK начнет генерироваться синхросигнал. Это и есть аппаратная реализация.

Если аппаратной поддержки SPI в микроконтроллере нет, то интерфейс SPI можно всегда реализовать программно, т.е. создать программу управляющая ножками контролера согласно протоколу обмена SP.

Различия в реализациях интерфейса SPI

Ведомые микросхемы могут по разному «интерпретировать» принятый сигнал по SPI, отличие может заключается в следующих моментах:

  • в размере передающих данных или размер пакета, обычно это 8 бит, но бывает и больше
  • в порядке следования бит, сначала старший бит или сначала младший бит
  • по какому уровню синхросигнала передаются данные (по логической единицы (HIGH) или логическому нулю (LOW))
  • по какому фронту импульса происходит синхронизация (по подъему или спуску), кратко это называют «фазой синхронизации»

Комбинация «уровня синхронизирующего сигнала» и «фазы синхронизации» определяется в спецификациях как режимы работы SPI. Их всего 4-е:

Режим Уровень сигнала (CPOL) Фаза (CPHA)
1 1
2 1
3 1 1

В столбце «Уровень сигнала» 1-ца, означает, что бит данных, принимаются ведомым устройством, когда по линии синхронизации передается ноль, другими словами — ведомое устройство ожидает и не принимает данные, когда на SCK установлена логическая 1-ца.

В столбце «Фаза» 1-ца, означает, что сигнал синхронизации определяется по спадающему фронту синхроимпульса, а логический 0-ль по нарастающему фронту синхроимпульса.

P.S.

Причем если в столбце «Уровень сигнала» установлена 1-ца, то спадающий и нарастающий фронт если изобразить на диаграмме будет «вверх ногами».

На диаграммах, данные 4-е режима можно изобразить следующим образом:

Более подробно о принципах работы SPI вы можете прочесть в статье

http://www.kit-e.ru/articles/interface/2009_03_53.php

Реализация SPI на микроконтроллерах ATmega серии AVR (ATmega328P) и «ранних» МК фирмы Motorola

В микроконтроллере ATmega328P (микроконтроллер фирмы Atmel серии AVR) можно управлять следующими параметрами SPI:

  • тип устройства (какую роль выполняет микроконтроллер, в качестве ведущего или ведомого)
  • порядок следования бит при передачи данных, сначала старший или младший бит
  • режим работы SPI (один из 4-ех указанных выше), с помощью комбинации 2-ух параметров — «полярность синхросигнала» и «фаза синхронизации».
  • частоту обмена данными по SPI

Для настройки и управлением SPI интерфейсом используют три регистра:

  • Регистр управления — SPCR
  • Регистр состояния — SPSR
  • Регистр данных — SPDR

Подробнее о каждом из них …

Регистр управления  – «SPCR» (адрес в ATmega328P для чтения 0x2C, адрес для записи 0x4C, если у вас другой МК, то найти адреса вы можете в документации)

— Логическая единица в 7-ом бите (имя бита SPIE) – разрешить прерывания от SPI (прерывание будет в том случае если установлен бит глобального разрешения прерываний регистра SREG (7-й бит)). После окончания передачи байта будет сгенерировано прерывание.

— Логическая единица в 6-ом бите (имя бита — SPE) — подключить SS, MOSI, MISO и SCK к портам микроконтроллера ATmega328P — PB2,PB3,PB4,PB5.

— Логическая единица в 5-ом бите (имя бита DORD) – определит, что по SPI сначала передается младший разряд, а потом старший – режим «LSB».   Логический ноль, наоборот, что сначала передается старший разряд, а далее младший – режим «MSB».

— Логическая единица в 4-ом бите (имя бита — MSTR) — режим ведущий включить, ноль – включить режим ведомого

— Логическая единица в 3-ем бите (имя бита CPOL) (полярность сигнала синхронизации или уровень синхронизации) – синхронизация ведется по отсутствию импульса (по логическому нулю) или тактовый сигнал в состоянии ожидания равен 1-цы. Логический ноль — синхронизация ведется по присутствию импульса (по логической единицы) или тактовый сигнал в состоянии ожидания равен 0-лю . По какому фронту (спад или подъем) ведется синхронизация определяется в 2-ом бите (CPHA).

— Логическая единица в 2-ом бите (имя бита CPHA) (фаза синхронизации) – определяет, что сигнал синхронизации определяется по спадающему фронту SCK, а логический ноль по нарастающему фронту SCK. Причем если в CPOL установлена 1-ца, то спадающий и нарастающий фронт если изобразить на диаграмме «вверхногами».

1-ый и 0-ой бит совместно с битом SPI2x в регистре SPSR определяют скорость передачи данных по SPI (или скорость тактовый сигналов по SCK). Данные биты имеют смысл только для ведущего, для ведомого они бессмысленны, т.к. скорость приема зависит от частоты SCK ведущего.

Где fosc тактовая частота задающего генератора SPI (обычно она равна частоте тактирования процессора).

Регистр состояния – «SPSR» (адрес в ATmega328P для чтения 0x2D, адрес для записи 0x4D, если у вас другой МК, то найти адреса вы можете в документации)

7-ой бит регистра «SPIF» : SPI Interrupt Flag

В бит устанавливается единица, когда передача байта данных по MOSI закончена. Если установлен бит разрешения прерывания SPI (бит SPIE) в регистре SPCR, то установка флага SPIF приводит к генерации запроса на прерывание.

6-ой бит регистра «WCOL»: Write COLlision Flag

Бит конфликта записи в регистр SPDR. В бит устанавливается единица, если во время передачи данных выполняется попытка записи в регистр данных SPDR.

— с 5-ого по 1-ый бит – зарезервированные биты, их значение всегда равняется 0-лю

0-ой бит «SPI2X»: Double SPI Speed Bit

Бит «двойная скорость передачи данных». Если в бит записана единица, то скорость передачи данных удвоенная.

С помощью сочетания данного бита и 1-ого и 0-ого бита (SPR1, SPR0) регистра SPCR, определяют скорость передачи данных по SPI. См. таблицу выше.

Регистр данных – «SPDR» (адрес в ATmega328P для чтения 0x2E, адрес для записи 0x4E, если у вас другой МК, то найти адреса вы можете в документации)

Размер регистра, как и выше указанных — 8 бит. Данный регистр используется для передачи и чтения данных по SPI. Помещая данные в него, вы запускаете процесс передачи.

Рассмотрим 3-и примера работы с интерфейсом SPI на ATmega328P в средах:

— Arduino

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879 #include<\p>  byte x=B11000000; //передаваемый бит  byte y= B00000000;  //в переменную y будет записываться принимающий битvoid setup() {  SPI.begin(); /* инициализация SPI */  /* инициализация в Arduino это значит- установить единицу в SS- настроить на выход SS (Slave Select или выбор ведомого) – 10 пин- установить 1-цу в следующие битах регистра управления SPCR:  в 4-ый бит (имя бита – MSTR) – режим ведущий включить  в 6-ой бит (имя бита – SPE)  – подключить                                 SS, MOSI, MISO и SCK                                 к портам  PB4,PB5,PB6,PB7                                 (10,11,12,13 пин в ардуино)- настроить следующие пины на выход:  SCK (Serial Clock или тактовый сигнал) – 13 пин    MOSI (Master Out Slave In или данные от ведущего) – 11 пин  В резульлтате иницилизации через SPI.begin()  конфигурация интерфейса SPI у нас выходит следующая:  – очередность битов “MSB”, т.е. сначала передается старший разряд, а далее младший  – синхронизация ведется по присутствию импульса    или тактовый сигнал в состоянии ожидания равен 0-лю  – сигнал синхронизации определяется по нарастающему фронту SCK    (два пункта выше указывают, что режим SPI в данном случае – 0)  – скорость передачи fosc/4  */  // МЫ МОЖЕМ ДОИНИЦИЛИЗИРОВАТЬ НЕКОТОРЫЕ ПАРАМЕТРЫ СВЯЗИ по SPI сами  // порядок следования бит  //SPI.setBitOrder(MSBFIRST);          /* LSBFIRST – сначала младший, далее старший           MSBFIRST – сначала старший, далее младший (стоит по умолчанию от SPI.begin) */  // частота обмена данными  //SPI.setClockDivider(SPI_CLOCK_DIV4);       /*  определяется как отношение           fosc к коэфициенту, возможные значения которого:              SPI_CLOCK_DIV2              SPI_CLOCK_DIV4              SPI_CLOCK_DIV8              SPI_CLOCK_DIV16              SPI_CLOCK_DIV32              SPI_CLOCK_DIV64              SPI_CLOCK_DIV128       */    //режим работы SPI  //SPI.setDataMode(SPI_MODE0);      /*              SPI_MODE0 – нулевой режим              SPI_MODE1 – первый режим              SPI_MODE2 – второй режим              SPI_MODE3 – третий режим      */}void loop(){  /* РЕАЛИЗАЦИЯ ПЕРЕДАЧИ ДАННЫХ ПО SPI */  digitalWrite(10, HIGH); /* от нас треубется, самому установить в SS 1-цу */   y=SPI.transfer(x); /* передача по битно аргумента (байта) и прием ответа от ведомого уст-ва                                                    передача осуществляется присваиванием регистру SPDR значение байта                      причем в это время автоматрически на SCK (13 пин)                      формируется тактовый сигнал */  digitalWrite(10, LOW); /* от нас треубется, самому установить в SS 0-ль */  SPI.end(); /* отключает шину SPI от 10,11,12,13 пинов */  /* Т.е. устанавливает 0-оль в 6-ой бит (SPE) регистра SPCR  */}

— Atmel Studio (AVR GCC)

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465 #include<\p>#include<\p>void init_spi() {DDRB=(1

Источник: http://s-engineer.ru/interfejs-spi/

SPI Communication with PIC Microcontroller – MPLAB XC8

SPI (Serial Peripheral Interface) is a full duplex synchronous serial communication interface used for short distance communications. It is usually used for communication between different modules in a same device or PCB. SPI devices communicates each other using a master slave architecture with a single master.

SPI Communication

SPI is called as a 4-wire bus as it requires four wires for its communication as shown above. In the case of single slave communications we need only 3 wires, as slave select (SS) is not required. So SPI requires more communication lines in contrast to UART, I2C, USB etc. Multiple slaves are supported through individual slave select lines.

SPI Master and Multi Slave Connections

Please read the article SPI – Serial Peripheral Interface for more details about the working of SPI.

PIC’s MSSP Module in SPI Mode

I hope you know basic understanding of SPI communication before continuing to following sections. Then you can easily understand the following block diagram in which MSSP module of PIC is working in SPI mode.

SPI Mode MSSP Module Block Diagram – PIC 16F877A

SSPSR is the serial in serial out shift register used to transmit/receive data. It is not directly accessible to the programer. We can do all read write operations through SSPBUF register. You can configure the MSSP module by using SSPSTAT and SSPCON1 registers.

SPI Registers

SSPSTAT – MSSP Status Register

SSPSTAT Register MSSP Module PIC 16F877A

  • Bit 0 BF : This is the buffer full status bit. It is applicable only in receive mode and indicates that the data is ready to read. This bit is set once the data reception is complete and it is transferred from SSPSR to SSPBUF register.
  • Bit 1 UA : Update Address Bit. This bit is used only in I2C Mode. So please ignore it.
  • Bit 2 R/W : Read/Write information. This bit is used only in I2C Mode. So please ignore it.
  • Bit 3 S : Start Bit. This bit is used only in I2C Mode. So please ignore it.
  • Bit 4 P : Stop Bit. This bit is used only in I2C Mode. So please ignore it.
  • Bit 5 D/A : Data/Address bit. This bit is used only in I2C Mode. So please ignore it.
  • Bit 6 CKE : SPI Clock Edge Select. If this bit is 0, data transmission occurs on transition from idle to active clock state. And if it is 1, data transmission occurs on transition from active to idle clock state. Idle state means the status of the line when there is no data transfer, it can be LOW (0) or HIGH (1).
  • Bit 7 SMP : Sample bit.
    • Master Mode : If this bit is set 0, input data is sampled at the middle of the data output frame. And if it is set 1, input data is sampled at the end of data output frame.
    • Slave Mode : This bit must be set 0 in the slave mode.

SSPCON1 – MSSP Control Register 1

SSPCON1 Register MSSP Module PIC 16F877A

  • Bit 0 ~ 3 SSPM0 ~ SSPM3 : Synchronous Serial Port Mode SelectSSP Mode Select Bits
  • Bit 4 CKP : SPI Clock Polarity select bit. If this bit is 0, idle clock state will be LOW (0) and if it is 1, idle clock state will be HIGH (1).
  • Bit 5 SSPEN : Synchronous serial port enable. Setting this bit enables the MSSP module for using in SPI or I2C mode.
  • Bit 6 SSPOV : Receive overflow indicator bit.
    • Slave Mode : This bit is  set when a new byte is received while SSPBUF is holding the previous data. In this case data in the SSPSR is lost. Overflow will only occur in slave mode. You have to read any previous data in the SSPBUF before transmitting data to avoid overflow. This bit must be cleared in the software.
    • Master Mode : Overflow bit won’t set in master mode as each transmission/reception is initiated by writing to SSPBUF. Slave cannot push any data to Master. For reading data from slave device, master has to write some data (dummy) to the slave.
  • Bit 7 WCOL : Write collision detect bit. This flag is applicable only in transmit mode. It is set when the SSPBUF register is written while transmitting the previous word.

SSPBUF – MSSP – Buffer Register

All data read/write operations has to happen with this register. For example we can write a data to this register to transmitting it to slave devices and we can read the received data from this register.

SPI Library for MPLAB XC8

For making the task simpler, I created a SPI library for MPLAB XC8. I tested this library only with PIC 16F877A. For other microcontrollers you might need to make some changes. Please refer the device datasheet for more information.

In the following section, I am explaining the SPI library code. You can simply use this SPI library in your program just by including the header file spi.h. Don’t forget to include spi.c file to your project. You can download these files at the end of .postlight.com”>

Источник: https://electrosome.com/spi-pic-microcontroller-mplab-xc8/

Программная реализация ведущего шины SPI (подробный разбор и некоторые процедуры на асме для PIC и AVR)

В этой статье рассматривается пример программной реализации на микроконтроллерах PIC и AVR функций ведущего шины SPI для разных режимов (mode0, mode1, mode2, mode3). Чтобы понимать что происходит — для начала, как всегда, читаем теорию (что такое SPI и как он работает). Если с теорией разобрались, тогда можно приступать к практической реализации.

Итак, что должен уметь делать SPI-мастер? Собственно говоря, всего четыре вещи:

  1. читать с шины MISO нужное количество бит;
  2. передавать по шине MOSI нужное количество бит;
  3. формировать на шине SCLK нужное количество импульсов, соблюдая правильную полярность;
  4. управлять шиной SS.

Как вы знаете (вы же с теорией знакомы?) — чтение и установку данных и «Мастер», и «Слэйв» производят по противоположным фронтам сигнала тактирования, причём для приёма и передачи может использоваться один и тот же сдвиговый регистр. Для наглядности давайте нарисуем для всех четырёх режимов диаграммы сигналов, соответствующие передаче по SPI двух бит, а уже по ним распишем действия контроллера:

Диаграммы нарисованы для случая, когда передача осуществляется младшим битом вперёд.

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

По диаграммам видно, что в результате обмена данными сдвиговые регистры «Мастера» и «Слэйва» поменялись содержимым (помните, в теоретической части я писал, что у SPI есть такая особенность, — для приёма и передачи можно использовать один и тот же регистр).

Прежде чем переходить к написанию кода, — давайте ещё подумаем вот о чём. Архитектура контроллеров у нас 8-ми битная, а для SPI часто может потребоваться бОльшая размерность сдвигового регистра.

Пусть в нашем примере размер сдвигового регистра можно будет выбрать от 1-го до 32-х бит. То есть максимально под сдвиговый регистр мы будем выделять 4 байта (4 восьмибитных регистра, расположенных в памяти так, как на рисунке справа).

Для случаев, когда размер регистра превышает 1 байт (то есть равен 2, 3 или 4 байта) мы будем программно имитировать работу с несколькими 8-ми битными регистрами как с одним большим.

Используемые для организации сдвигового регистра восьмибитные регистры в дальнейшем будем называть просто байтами, чтобы не путаться.

Что представляет собой чтение с точки зрения «Мастера»? Да ничего особенного, — нужно просто прочитать сигнал на входе (MISO) и записать его в младший или старший бит сдвигового регистра (в зависимости от того — младшим или старшим битом вперёд передаются данные и от значения CPHA). Вот так это выглядит в коде:

Для контроллеров PIC Для контроллеров AVR
1) Для передачи младшим битом вперёд при CPHA=0 и старшим битом вперёд при CPHA=1

Read_MISO: bcf INDF, 0 btfsc PORT_SPI, MISO_Line bsf INDF, 0 return

Read_MISO: bcf INDF, 0 btfsc PORT_SPI, MISO_Line bsf INDF, 0 return

2) Для передачи старшим битом вперёд при CPHA=0 и младшим битом вперёд при CPHA=1

Read_MISO: bcf INDF, 7 btfsc PORT_SPI, MISO_Line bsf INDF, 7 return

Read_MISO: bcf INDF, 7 btfsc PORT_SPI, MISO_Line bsf INDF, 7 return

Для случая 1 в регистр FSR должен быть предварительно загружен адрес младшего используемого байта нашего сдвигового регистра, а для случая 2 — адрес старшего используемого байта этого регистра.

PORT_SPI — адрес порта ввода /вывода, к которому подключена линия MISO,

MISO_Line — номер канала порта.

1) Для передачи младшим битом вперёд при CPHA=0 и старшим битом вперёд при CPHA=1

Read_MISO: ld temp, X cbr temp, 0b00000001 sbic PIN_SPI, MISO_Line sbr temp, 0b00000001 st X, temp ret

Read_MISO: ld temp, X cbr temp, 0b00000001 sbic PIN_SPI, MISO_Line sbr temp, 0b00000001 st X, temp ret

2) Для передачи старшим битом вперёд при CPHA=0 и младшим битом вперёд при CPHA=1

Read_MISO: ld temp, X cbr temp, 0b10000000 sbic PIN_SPI, MISO_Line sbr temp, 0b10000000 st X, temp ret

Read_MISO: ld temp, X cbr temp, 0b10000000 sbic PIN_SPI, MISO_Line sbr temp, 0b10000000 st X, temp ret

Для случая 1 в регистр X должен быть предварительно загружен адрес младшего используемого байта нашего сдвигового регистра, а для случая 2 — адрес старшего используемого байта этого регистра.

PIN_SPI — адрес регистра, отображающего состояния входов порта ввода/вывода, к которому подключена линия MISO,

MISO_Line — номер канала порта.

Здесь и далее, temp — просто некий вспомогательный регистр.

Кроме того, перед началом передачи, предназначенные для передачи биты, должны быть выровнены по старшему биту старшего используемого нами для организации сдвигового регистра байта при передаче старшим битом вперёд, и по младшему биту младшего используемого байта при передаче младшим битом вперёд. Картинка внизу иллюстрирует, что имеется ввиду на примере 12-ти битного пакета SPI (то есть, когда мы реализуем 12-ти битный сдвиговый регистр; при этом из наших зарезервированных четырёх байт используются только два).

Идём дальше. «Сдвиг», как видно по диаграммам, состоит для «Мастера» (впрочем как и для «Слэйва», но мы в этой статье занимаемся только «Мастером») из двух действий: это,
во-первых, собственно сдвиг регистра и, во-вторых, установка очередного бита на шину MOSI.

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

Кроме того, сдвиг нам нужен не простой, а циклический, то есть при сдвиге вправо младший бит нашего большого регистра должен стать старшим, а при сдвиге влево — старший бит должен стать младшим.

Код, реализующий сдвиг будет выглядеть следующим образом:

Для контроллеров PIC Для контроллеров AVR
1) Сдвиг вправо

Shift_Right: movf Hi_byte_Address,0 movlw FSR movf Byte_Number,0 movlw Byte_Counter bcf STATUS,C
Next_Shift_Right: rrf INDF,1 incf FSR decfsz Byte_Counter goto Next_Shift_Right movf Hi_byte_Address,0 movlw FSR btfsc STATUS,C bsf INDF,7 return

Shift_Right: movf Hi_byte_Address,0 movlw FSR movf Byte_Number,0 movlw Byte_Counter bcf STATUS,C Next_Shift_Right: rrf INDF,1 incf FSR decfsz Byte_Counter goto Next_Shift_Right movf Hi_byte_Address,0 movlw FSR btfsc STATUS,C bsf INDF,7 return

2) Сдвиг влево

Shift_Left: movf Low_byte_Address,0 movlw FSR movf Byte_Number,0 movlw Byte_Counter bcf STATUS,C
Next_Shift_Left: rlf INDF,1 decf FSR,1 decfsz Byte_Counter goto Next_Shift_Left movf Low_byte_Address,0 movlw FSR btfsc STATUS,C bsf INDF,0 return

Shift_Left: movf Low_byte_Address,0 movlw FSR movf Byte_Number,0 movlw Byte_Counter bcf STATUS,C Next_Shift_Left: rlf INDF,1 decf FSR,1 decfsz Byte_Counter goto Next_Shift_Left movf Low_byte_Address,0 movlw FSR btfsc STATUS,C bsf INDF,0 return

1) Сдвиг вправо

Shift_Right: mov XL, Hi_byte_Address mov Byte_Counter, Byte_Number clc
Next_Shift_Right: ld temp, X ror temp st X, temp inc XL dec Byte_Counter brne Next_Shift_Right brcc Shift_Right_Exit mov XL, Hi_byte_Address ld temp, X sbr temp, 0b10000000 st X, temp
Shift_Right_Exit: ret

Shift_Right: mov XL, Hi_byte_Address mov Byte_Counter, Byte_Number clc Next_Shift_Right: ld temp, X ror temp st X, temp inc XL dec Byte_Counter brne Next_Shift_Right brcc Shift_Right_Exit mov XL, Hi_byte_Address ld temp, X sbr temp, 0b10000000 st X, temp Shift_Right_Exit: ret

2) Сдвиг влево

Shift_Left: mov XL, Low_byte_Address mov Byte_Counter, Byte_Number clc
Next_Shift_Left: ld temp, X rol temp st X, temp dec XL dec Byte_Counter brne Next_Shift_Left brcc Shift_Left_Exit mov XL, Low_byte_Address ld temp, X sbr temp, 0b00000001 st X, temp
Shift_Left_Exit: ret

Shift_Left: mov XL, Low_byte_Address mov Byte_Counter, Byte_Number clc Next_Shift_Left: ld temp, X rol temp st X, temp dec XL dec Byte_Counter brne Next_Shift_Left brcc Shift_Left_Exit mov XL, Low_byte_Address ld temp, X sbr temp, 0b00000001 st X, temp Shift_Left_Exit: ret

  1. Low_byte_Address — адрес младшего байта нашего сдвигового регистра,
  2. Hi_byte_Address — адрес его старшего байта,
  3. Byte_Counter — счётчик обработанных байт,
  4. Byte_Number — количество байт, используемых для организации сдвигового регистра.

Ну вот, со сдвигом регистра разобрались, теперь можно приступать и к этапу передачи, именуемому «Сдвиг». Как я ранее уже писал, — этот этап передачи состоит из двух действий: сдвиг регистра и установка очередного бита на шину MOSI. В коде это будет выглядеть так:

Ссылка на основную публикацию
Adblock
detector
",css:{backgroundColor:"#000",opacity:.6}},container:{block:void 0,tpl:"
"},wrap:void 0,body:void 0,errors:{tpl:"
",autoclose_delay:2e3,ajax_unsuccessful_load:"Error"},openEffect:{type:"fade",speed:400},closeEffect:{type:"fade",speed:400},beforeOpen:n.noop,afterOpen:n.noop,beforeClose:n.noop,afterClose:n.noop,afterLoading:n.noop,afterLoadingOnShow:n.noop,errorLoading:n.noop},o=0,p=n([]),h={isEventOut:function(a,b){var c=!0;return n(a).each(function(){n(b.target).get(0)==n(this).get(0)&&(c=!1),0==n(b.target).closest("HTML",n(this).get(0)).length&&(c=!1)}),c}},q={getParentEl:function(a){var b=n(a);return b.data("arcticmodal")?b:(b=n(a).closest(".arcticmodal-container").data("arcticmodalParentEl"),!!b&&b)},transition:function(a,b,c,d){switch(d=null==d?n.noop:d,c.type){case"fade":"show"==b?a.fadeIn(c.speed,d):a.fadeOut(c.speed,d);break;case"none":"show"==b?a.show():a.hide(),d();}},prepare_body:function(a,b){n(".arcticmodal-close",a.body).unbind("click.arcticmodal").bind("click.arcticmodal",function(){return b.arcticmodal("close"),!1})},init_el:function(d,a){var b=d.data("arcticmodal");if(!b){if(b=a,o++,b.modalID=o,b.overlay.block=n(b.overlay.tpl),b.overlay.block.css(b.overlay.css),b.container.block=n(b.container.tpl),b.body=n(".arcticmodal-container_i2",b.container.block),a.clone?b.body.html(d.clone(!0)):(d.before("
"),b.body.html(d)),q.prepare_body(b,d),b.closeOnOverlayClick&&b.overlay.block.add(b.container.block).click(function(a){h.isEventOut(n(">*",b.body),a)&&d.arcticmodal("close")}),b.container.block.data("arcticmodalParentEl",d),d.data("arcticmodal",b),p=n.merge(p,d),n.proxy(e.show,d)(),"html"==b.type)return d;if(null!=b.ajax.beforeSend){var c=b.ajax.beforeSend;delete b.ajax.beforeSend}if(null!=b.ajax.success){var f=b.ajax.success;delete b.ajax.success}if(null!=b.ajax.error){var g=b.ajax.error;delete b.ajax.error}var j=n.extend(!0,{url:b.url,beforeSend:function(){null==c?b.body.html("
"):c(b,d)},success:function(c){d.trigger("afterLoading"),b.afterLoading(b,d,c),null==f?b.body.html(c):f(b,d,c),q.prepare_body(b,d),d.trigger("afterLoadingOnShow"),b.afterLoadingOnShow(b,d,c)},error:function(){d.trigger("errorLoading"),b.errorLoading(b,d),null==g?(b.body.html(b.errors.tpl),n(".arcticmodal-error",b.body).html(b.errors.ajax_unsuccessful_load),n(".arcticmodal-close",b.body).click(function(){return d.arcticmodal("close"),!1}),b.errors.autoclose_delay&&setTimeout(function(){d.arcticmodal("close")},b.errors.autoclose_delay)):g(b,d)}},b.ajax);b.ajax_request=n.ajax(j),d.data("arcticmodal",b)}},init:function(b){if(b=n.extend(!0,{},a,b),!n.isFunction(this))return this.each(function(){q.init_el(n(this),n.extend(!0,{},b))});if(null==b)return void n.error("jquery.arcticmodal: Uncorrect parameters");if(""==b.type)return void n.error("jquery.arcticmodal: Don't set parameter \"type\"");switch(b.type){case"html":if(""==b.content)return void n.error("jquery.arcticmodal: Don't set parameter \"content\"");var e=b.content;return b.content="",q.init_el(n(e),b);case"ajax":return""==b.url?void n.error("jquery.arcticmodal: Don't set parameter \"url\""):q.init_el(n("
"),b);}}},e={show:function(){var a=q.getParentEl(this);if(!1===a)return void n.error("jquery.arcticmodal: Uncorrect call");var b=a.data("arcticmodal");if(b.overlay.block.hide(),b.container.block.hide(),n("BODY").append(b.overlay.block),n("BODY").append(b.container.block),b.beforeOpen(b,a),a.trigger("beforeOpen"),"hidden"!=b.wrap.css("overflow")){b.wrap.data("arcticmodalOverflow",b.wrap.css("overflow"));var c=b.wrap.outerWidth(!0);b.wrap.css("overflow","hidden");var d=b.wrap.outerWidth(!0);d!=c&&b.wrap.css("marginRight",d-c+"px")}return p.not(a).each(function(){var a=n(this).data("arcticmodal");a.overlay.block.hide()}),q.transition(b.overlay.block,"show",1*")),b.overlay.block.remove(),b.container.block.remove(),a.data("arcticmodal",null),n(".arcticmodal-container").length||(b.wrap.data("arcticmodalOverflow")&&b.wrap.css("overflow",b.wrap.data("arcticmodalOverflow")),b.wrap.css("marginRight",0))}),"ajax"==b.type&&b.ajax_request.abort(),p=p.not(a))})},setDefault:function(b){n.extend(!0,a,b)}};n(function(){a.wrap=n(document.all&&!document.querySelector?"html":"body")}),n(document).bind("keyup.arcticmodal",function(d){var a=p.last();if(a.length){var b=a.data("arcticmodal");b.closeOnEsc&&27===d.keyCode&&a.arcticmodal("close")}}),n.arcticmodal=n.fn.arcticmodal=function(a){return e[a]?e[a].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof a&&a?void n.error("jquery.arcticmodal: Method "+a+" does not exist"):q.init.apply(this,arguments)}}(jQuery)}var debugMode="undefined"!=typeof debugFlatPM&&debugFlatPM,duplicateMode="undefined"!=typeof duplicateFlatPM&&duplicateFlatPM,countMode="undefined"!=typeof countFlatPM&&countFlatPM;document["wri"+"te"]=function(a){let b=document.createElement("div");jQuery(document.currentScript).after(b),flatPM_setHTML(b,a),jQuery(b).contents().unwrap()};function flatPM_sticky(c,d,e=0){function f(){if(null==a){let b=getComputedStyle(g,""),c="";for(let a=0;a=b.top-h?b.top-h{const d=c.split("=");return d[0]===a?decodeURIComponent(d[1]):b},""),c=""==b?void 0:b;return c}function flatPM_testCookie(){let a="test_56445";try{return localStorage.setItem(a,a),localStorage.removeItem(a),!0}catch(a){return!1}}function flatPM_grep(a,b,c){return jQuery.grep(a,(a,d)=>c?d==b:0==(d+1)%b)}function flatPM_random(a,b){return Math.floor(Math.random()*(b-a+1))+a}
");let k=document.querySelector(".flat_pm_modal[data-id-modal=\""+a.ID+"\"]");if(-1===d.indexOf("go"+"oglesyndication")?flatPM_setHTML(k,d):jQuery(k).html(b+d),"px"==a.how.popup.px_s)e.bind(h,()=>{e.scrollTop()>a.how.popup.after&&(e.unbind(h),f.unbind(i),j())}),void 0!==a.how.popup.close_window&&"true"==a.how.popup.close_window&&f.bind(i,()=>{e.unbind(h),f.unbind(i),j()});else{let b=setTimeout(()=>{f.unbind(i),j()},1e3*a.how.popup.after);void 0!==a.how.popup.close_window&&"true"==a.how.popup.close_window&&f.bind(i,()=>{clearTimeout(b),f.unbind(i),j()})}f.on("click",".flat_pm_modal .flat_pm_crs",()=>{jQuery.arcticmodal("close")})}if(void 0!==a.how.outgoing){let b,c="0"==a.how.outgoing.indent?"":" style=\"bottom:"+a.how.outgoing.indent+"px\"",e="true"==a.how.outgoing.cross?"":"",f=jQuery(window),g="scroll.out"+a.ID,h=void 0===flatPM_getCookie("flat_out_"+a.ID+"_mb")||"false"!=flatPM_getCookie("flat_out_"+a.ID+"_mb"),i=document.createElement("div"),j=jQuery("body"),k=()=>{void 0!==a.how.outgoing.cookie&&"false"==a.how.outgoing.cookie&&h&&(jQuery(".flat_pm_out[data-id-out=\""+a.ID+"\"]").addClass("show"),j.on("click",".flat_pm_out[data-id-out=\""+a.ID+"\"] .flat_pm_crs",function(){flatPM_setCookie("flat_out_"+a.ID+"_mb",!1)})),(void 0===a.how.outgoing.cookie||"false"!=a.how.outgoing.cookie)&&jQuery(".flat_pm_out[data-id-out=\""+a.ID+"\"]").addClass("show")};switch(a.how.outgoing.whence){case"1":b="top";break;case"2":b="bottom";break;case"3":b="left";break;case"4":b="right";}jQuery("body > *").eq(0).before("
"+e+"
");let m=document.querySelector(".flat_pm_out[data-id-out=\""+a.ID+"\"]");-1===d.indexOf("go"+"oglesyndication")?flatPM_setHTML(m,d):jQuery(m).html(e+d),"px"==a.how.outgoing.px_s?f.bind(g,()=>{f.scrollTop()>a.how.outgoing.after&&(f.unbind(g),k())}):setTimeout(()=>{k()},1e3*a.how.outgoing.after),j.on("click",".flat_pm_out .flat_pm_crs",function(){jQuery(this).parent().removeClass("show").addClass("closed")})}countMode&&(flat_count["block_"+a.ID]={},flat_count["block_"+a.ID].count=1,flat_count["block_"+a.ID].click=0,flat_count["block_"+a.ID].id=a.ID)}catch(a){console.warn(a)}}function flatPM_start(){let a=flat_pm_arr.length;if(0==a)return flat_pm_arr=[],void jQuery(".flat_pm_start, .flat_pm_end").remove();flat_body=flat_body||jQuery("body"),!flat_counter&&countMode&&(flat_counter=!0,flat_body.on("click","[data-flat-id]",function(){let a=jQuery(this),b=a.attr("data-flat-id");flat_count["block_"+b].click++}),flat_body.on("mouseenter","[data-flat-id] iframe",function(){let a=jQuery(this),b=a.closest("[data-flat-id]").attr("data-flat-id");flat_iframe=b}).on("mouseleave","[data-flat-id] iframe",function(){flat_iframe=-1}),jQuery(window).on("beforeunload",()=>{jQuery.isEmptyObject(flat_count)||jQuery.ajax({async:!1,type:"POST",url:ajaxUrlFlatPM,dataType:"json",data:{action:"flat_pm_ajax",data_me:{method:"flat_pm_block_counter",arr:flat_count}}})}).on("blur",()=>{-1!=flat_iframe&&flat_count["block_"+flat_iframe].click++})),flat_userVars.init();for(let b=0;bflat_userVars.textlen||void 0!==a.chapter_sub&&a.chapter_subflat_userVars.titlelen||void 0!==a.title_sub&&a.title_subc&&cc&&c>d&&(b=flatPM_addDays(b,-1)),b>e||cd||c-1!=flat_userVars.referer.indexOf(a))||void 0!==a.referer.referer_disabled&&-1!=a.referer.referer_disabled.findIndex(a=>-1!=flat_userVars.referer.indexOf(a)))&&(c=!0),c||void 0===a.browser||(void 0===a.browser.browser_enabled||-1!=a.browser.browser_enabled.indexOf(flat_userVars.browser))&&(void 0===a.browser.browser_disabled||-1==a.browser.browser_disabled.indexOf(flat_userVars.browser)))){if(c&&void 0!==a.browser&&void 0!==a.browser.browser_enabled&&-1!=a.browser.browser_enabled.indexOf(flat_userVars.browser)&&(c=!1),!c&&(void 0!==a.geo||void 0!==a.role)&&(""==flat_userVars.ccode||""==flat_userVars.country||""==flat_userVars.city||""==flat_userVars.role)){flat_pm_then.push(a),flatPM_setWrap(a),flat_body.hasClass("flat_pm_block_geo_role")||(flat_body.addClass("flat_pm_block_geo_role"),flatPM_ajax("flat_pm_block_geo_role")),c=!0}c||(flatPM_setWrap(a),flatPM_next(a))}}}let b=jQuery(".flatPM_sticky");b.each(function(){let a=jQuery(this),b=a.data("height")||350,c=a.data("top");a.wrap("
");let d=a.parent()[0];flatPM_sticky(this,d,c)}),debugMode||countMode||jQuery("[data-flat-id]:not([data-id-out]):not([data-id-modal])").contents().unwrap(),flat_pm_arr=[],jQuery(".flat_pm_start, .flat_pm_end").remove()}
Для контроллеров PIC Для контроллеров AVR
1) Для передачи младшим битом вперёд при CPHA=0

Shift_&_Set_MOSI: call Shift_Right movf Low_byte_Address,0 movwf FSR bcf PORT_SPI, MOSI_Line btfsc INDF, 0 bsf PORT_SPI, MOSI_Line return

Shift_&_Set_MOSI: call Shift_Right movf Low_byte_Address,0 movwf FSR bcf PORT_SPI, MOSI_Line btfsc INDF, 0 bsf PORT_SPI, MOSI_Line return

2) Для передачи старшим битом вперёд при CPHA=0

Shift_&_Set_MOSI: call Shift_Left movf Hi_byte_Address,0 movwf FSR bcf PORT_SPI, MOSI_Line btfsc INDF, 7 bsf PORT_SPI, MOSI_Line return

Shift_&_Set_MOSI: call Shift_Left movf Hi_byte_Address,0 movwf FSR bcf PORT_SPI, MOSI_Line btfsc INDF, 7 bsf PORT_SPI, MOSI_Line return

3) Для передачи младшим битом вперёд при CPHA=1

Shift_&_Set_MOSI: movf Low_byte_Address,0 movwf FSR bcf PORT_SPI, MOSI_Line btfsc INDF, 0 bsf PORT_SPI, MOSI_Line call Shift_Right return

Shift_&_Set_MOSI: movf Low_byte_Address,0 movwf FSR bcf PORT_SPI, MOSI_Line btfsc INDF, 0 bsf PORT_SPI, MOSI_Line call Shift_Right return

4) Для передачи старшим битом вперёд при CPHA=1

Shift_&_Set_MOSI: movf Hi_byte_Address,0 movwf FSR bcf PORT_SPI, MOSI_Line btfsc INDF, 7 bsf PORT_SPI, MOSI_Line call Shift_Left return

Shift_&_Set_MOSI: movf Hi_byte_Address,0 movwf FSR bcf PORT_SPI, MOSI_Line btfsc INDF, 7 bsf PORT_SPI, MOSI_Line call Shift_Left return

1) Для передачи младшим битом вперёд при CPHA=0

Shift_&_Set_MOSI: rcall Shift_Right in temp1, PORT_SPI cbr temp1, (1

Источник: http://radiohlam.ru/?p=1197

Расширяем порты

Рассмотрим 3 основных варианта добавления портов на микроконтроллерах или одноплатных компьютерах:

Микросхема MCP23017

Микросхема MCP23017 добавляет 16 портов,которые можно настроить как на вход,так и на выход.

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

Микросхемы MCP23017 можно нарасщивать до 8 штук на одной шине I2C ,например используя 3 провода (+питание) можно их разводить по квартире для уменьшения количества проводов к датчикам и исполнительным механизмам.Каждой микросхеме задается адрес через выводы А0,А1,А2 в двоичном виде , подключив их к минусу или плюсу.Цена одной микросхемы MCP23017 – 1.5$. 

Существует так же вариант микросхемы MCP23S17 ,которая использует шину SPI .

Работа MCP23017 в Arduino

 У плат Arduino имются отдельные выводы SCL и SDA ,но например плат,основанных на ATMEGA328P устройства подключаются к аналоговым входам А5 (SCL) и А4(SDA) .Шины SCL и SDA должны быть “подтянуты” через резисторы 4.7KoM к плюсу.
.Назначение выводов  определяется скетчем.

Библиотека для работы MCP23017 с Arduino: MCP23x17.zip 

Для некоторых случаев может быть выгоднее использовать MCP23017 без использования библиотек,смотрите пример ниже:

// Arduino code ,используется банк А на вход,а банк В – на вывод. // pins 15,16 и 17 к GND для I2C шины адреса 0x20 #include “Wire.h” // подключаем библиотеку I2C byte a=0; boolean registers[8]; // храним состояние регистров банка В void setup() {    Serial.begin(9600);         Wire.begin(); // wake up I2C bus // настраиваем банк B на вывод Wire.beginTransmission(0x20);// подключение к чипу Wire.write((byte)0x01); // выбираем банк B Wire.write((byte)0x00); // установка банка B на вывод,точнее устанавливаем на всех выводах значение 0 Wire.endTransmission(); // отключаемся. // } void loop() { // чтение банки A Wire.beginTransmission(0x20); // подключение к чипу Wire.write(0x12); // выбираем для работы банку A Wire.endTransmission(); // отключаемся. Wire.requestFrom(0x20, 1); // отправляем один байт a=Wire.read(); // чтение состояния портов банка А в переменную 'a' // выводим состояние портов банка А,если на них подан минус. if (!((a>>0)&1)) Serial.print(0); if (!((a>>0)&2)) Serial.print(1); if (!((a>>0)&4)) Serial.print(2); if (!((a>>0)&8)) Serial.print(3); if (!((a>>0)&16)) Serial.print(4); if (!((a>>0)&32)) Serial.print(5); if (!((a>>0)&64)) Serial.print(6); if (!((a>>0)&128)) Serial.print(7); //  Serial.print(a); Serial.println(“–“);   // тест мигалка на выводе банки В порта номер 3 mcWrite(3,0);  delay(500); mcWrite(3,1); delay(500); } // подпрограмма записи в банк B void mcWrite(int whichPin, int whichState) {  byte d=0;  byte l=1;   registers[whichPin] = whichState; for(int i = 0; i = 0; i–){     digitalWrite(SRCLK_Pin, LOW);     int val = registers[i];     digitalWrite(SER_Pin, val);     digitalWrite(SRCLK_Pin, HIGH);   }   digitalWrite(RCLK_Pin, HIGH); }

Пример подпрограммы для использования 2 регистров,изменение статуса вызывается через registerWrite(номер_порта, LOW);

  • Пример 74HC595 с  Arduino и Energia через шину SPI.

//  #include  #define SS_HC595 45 // ST_CP(12) // SH_CP (11) на SCK (13 uno,52 mega) // DS(14) на MOSI (11 uno,51 mega) //SER (10) на минус или при каскаде-с предыдущего регистра //количество регистров 1 или 2 #define number_of_74hc595s 1  //не трогать ! #define numOfRegisterPins number_of_74hc595s * 8 boolean registers[numOfRegisterPins]; void setup() { //  Serial.begin(9600);     SPI.begin();   pinMode(SS_HC595, OUTPUT); // pinMode(13, OUTPUT);    } void loop() { //  digitalWrite(13, HIGH);   registerWrite(4,1);  delay(1000); // digitalWrite(13, LOW); registerWrite(4,0); delay(1000); } void registerWrite(byte whichPin, byte whichState) {     // int d=0; //для 2 регистров  byte d=0;    byte l=1;   registers[whichPin] = whichState; for(byte i = 0; i =0; i–) { // i=15,если 2 регистра    digitalWrite(clock_SH_in_out,LOW);    delayMicroseconds(1);    a |= (digitalRead(data_SH_in) ? (1>0)&1)) Serial.print(0); if (!((a>>0)&2)) Serial.print(1); if (!((a>>0)&4)) Serial.print(2); if (!((a>>0)&8)) Serial.print(3); if (!((a>>0)&16)) Serial.print(4); if (!((a>>0)&32)) Serial.print(5); if (!((a>>0)&64)) Serial.print(6); if (!((a>>0)&128)) Serial.print(7); // выдаст номера портов,которые подключены на GND.    Serial.println(“–“); delay(1000); }

 

  • Пример 74HC165 с  Arduino и Energia через шину SPI.

//  #include  #define SS_HC165 8 // SH(1) // QH (9) на SCK (13 uno,52 mega) // CLK(2) на MISO (12 uno,50 mega) //CLK INH(15) на минус //SER (10) на минус или при каскаде-с предыдущего регистра void setup() {   Serial.begin(9600);     SPI.begin();   pinMode(SS_HC165, OUTPUT); } void loop() { digitalWrite(SS_HC165, HIGH); uint8_t a = SPI.transfer(0); digitalWrite(SS_HC165, LOW); Serial.print(a,BIN); Serial.print(“>”); if (!((a>>0)&1)) Serial.print(0); if (!((a>>0)&2)) Serial.print(1); if (!((a>>0)&4)) Serial.print(2); if (!((a>>0)&8)) Serial.print(3); if (!((a>>0)&16)) Serial.print(4); if (!((a>>0)&32)) Serial.print(5); if (!((a>>0)&64)) Serial.print(6); if (!((a>>0)&128)) Serial.print(7); // выдаст номера портов,которые подключены на GND.    Serial.println(“–“); delay(1000); }

 74HC165 и 74HC595 при использовании вместе могут использовать общий пин синхронизации.В итоге при подключении к м/к в сумме используют 5 выводов.

При использовании варианта с SPI на шине могут находится другие устройства,например Ethernet .В итоге используется дополнительно всего 1 вывод на регистр для выбора канала,а SCK,MISO,MOSI – общие. 

Микросхема PCF8574

Микросхема PCF8574.Так же используется шина  I2C,но выводов всего 8.

Примерная цена 1.15$.

  • Откройте,чтобы увидеть подпрограмму для работы PCF8574 с Arduino и Energia.

#include  #define expander B0100000  // адрес на шине i2c                             void setup() {   Wire.begin();   Serial.begin(9600); } void loop() {   Serial.println(“Writing B00000000.”);   expanderWrite(B00000000);   Serial.print(“Read: “);   Serial.println(expanderRead(), BIN);   delay(1000);   Serial.println(“Writing B11111111.”);   expanderWrite(B11111111);   Serial.print(“Read: “);   Serial.println(expanderRead(), BIN);   delay(1000); } void expanderWrite(byte _data ) {   Wire.beginTransmission(expander);   Wire.write(_data);   Wire.endTransmission(); } byte expanderRead() {   byte _data;   Wire.requestFrom(expander, 1);   if(Wire.available()) {     _data = Wire.read();   }   return _data; }

Данный скетч не тестировался !!<\p>

Примеры реализации расширения портов можно посмотреть тут .

{showhide title=”Откройте,чтобы увидеть пример работы MCP23017 с Arduino и Energia без использования библиотек.”changetitle=”Закройте”}

Источник: http://homes-smart.ru/index.php/oborudovanie/prochee/rasshiryaem-porty