воскресенье, 28 декабря 2014 г.

Простой код на С. Компилятор XC8

<< Назад к оглавлению

Я плавно переделываю уроки на использование пакета MPLABX и компилятора XC8. Так как старые уже не поддерживается. Тем не менее, вы можете найти старую статью здесь. Так же точно можете скачать компилятор C18 и использовать его. XC8 несколько отличается

Итак, нам понадобится компилятор XC8. Его можно скачать с официального сайта. ссылка, либо же с зеркала зеркало

Итак, создаем проект в MPLABX
Это делается примерно так же как во втором уроке, только выбираем компилятор XC8

 Это аналог программе, написанной в уроке 2.
#include <p18f2550.h>
#include <stdio.h>
#include <stdlib.h>
#include <p18f2550.h>
#include "config.h"


void delay(void)
{
long i;
for (i=0;i<100000;i++);
}

int main(int argc, char** argv) {
  TRISA = 0;
  PORTA = 0;
  while (1)
  {
  PORTAbits.RA2 = 1;
  delay();
  PORTAbits.RA2 = 0;
  delay();
};
    return (EXIT_SUCCESS);
}
Сначала запускается функция main(). Идет настройка вывода сигнала через порт А (TRISA=0;) а потом обнуляется этот выход с порта А (PORTA=0); Далее идет бесконечный цикл, в котором мы мигаем лампочкой на порту RA2 и вызываем функцию задержки.
Пока что у вас не скомпилируется этот проект. Потому что в include стоит файл config.h, а мы пока его еще не создали. Там будут конфигурационные биты.
Необходимо их настроить. Для этого идем в Window->PIC memory views->configuration bits

откроется окно, и выставляем там FOSC=INTOSCIO, WDT=OFF, MCLRE=OFF
Щелкаем правой клавишей и Generate Source Code to Output. Эта опция создаст код, необходимый для задачи конфигурационных битов. 
Копируем код, создаем файл заголовков config.h и вставляем сгенерированный код в конец файла.

Все обозначений навроде портов и встроенных устройств можно найти в файле p18f2550.h или p18f4550.h, так же всегда вы можете обратиться к ТО на контроллер.
директива #include <p18f2550.h> подключает заголовки для контроллера
#pragma config - Это опять же выбор конфигурационных битов для контроллера. См урок №2.
Эти настройки у нас хранятся теперь в файле config.h 

Если вы будете использовать этот код с бутлоадером. А это намного удобнее, нам необходимо сдвинуть его в памяти программы на 0x1000. Если в C18 компиляторе для этого была специальная директива, то теперь для этого служит настройка компилятора. Грубо говоря, теперь когда мы пишем код в XС8, компилятор сам знает где должны быть прерывания, как размечена память, и.т.д. Все, что мы можем сделать - это сделать сдвиг. 
Итак, чтобы программа корректно работала с бутлоадером, нужно сделать следующее:
File->Project properties
Потом XC8 global options (не XC8 compiler options, специально на это обращаю внимание), и пишем в поле additional options

--CODEOFFSET=1000

Это означает, что весь код компилируется со сдвигом в 0x1000



Если вы захотите вставить код ассемблера в файл Си, то вам нужно будет его заключить между директивами

#asm

#endasm

Файлы проекта: ссылка

вторник, 23 декабря 2014 г.

Второй урок. Простой код на ассемблере и устройство вкратце.


<< Назад к оглавлению

В данном тексте приведены ссылки на книги. "название книги":страница обозначает указатель на определенную страницу книги. "название книги":Гглава - главу. При этом ТО - сокращение для тех. описания контроллера (Datasheet). Например ТО:15 - 15 страница технического описания. ТО:Г3 - третья глава технического описания
 
Эта статья переработана. Существует так же старая версия с оболочкой MPLAB 8.91. Прочесть ее можно здесь.

Вот и ладушки, если вы читаете второй урок, то наверное, в первом вы смогли подготовить инструменты. Или и так без меня все умеете. Теперь небольшое отступление для начинающих. За более подробной
информацией, обращайтесь к серьезным книгам, особенно к техническому описанию контроллера.

Итак, что такое контроллер, и как он работает?
Конечно же, это просто черный жучек с ножками. За неимением никаких других членов, он общается с окружающим миром исключительно напряжением на ножках. Что в общем и демонстрировалось в программе в первом уроке. Просто с определенной переодичностью контроллер зажигал
светодиодик.
В расcматриваемых нами контроллерах память разделена. Программа записывается в отдельное пространство, именуемое памятью программы (PROGRAM MEMORY). Переменные и настройки хранятся в памяти данных (DATA MEMORY). Причем, ячейки памяти, выделенные для использования как переменные называются регистрами общего назначения (GENERAL PURPOSE REGISTERS или GPR) и настройки находятся в регистрах специального назначения (SPECIAL FUNCTIONS REGISTERS или SFR). Память данных поделена на 15 блоков и блоки меняются регистром BSR (BLOCK SELECT REGISTER).
Так же существует EEPROM memory - это флеш память, используемая для длительного хранения информации.
Подробнее о памяти контроллера смотри главу 1 ссылка.

Код программы


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

Ладно, начнем.

Открываем MPLABX IDE жмем File->New Project. В открывшемся окне выбираем Microchip Embedded Standalone Project


 выбираем семейство контроллеров advanced 8 bit MRUs и наш контроллер, например pic18f2550
Next, Next.Теперь компилятор предлагает нам выбрать соответствующий набор для разработки. К этому моменту должно быть установлено все необходимое.
Первый урок на ассемблере, поэтому выбираем MPASM. Далее. Задаем имя и прочие свойства. Укажите кодировку с русским. Например. UTF-8. Иначе ваши комментарии на кириллице не сохранятся.

И вот проект открыт. По началу в нем есть только makefile. Это файл для сборки проекта. Поэтому щелкаем на Source files->new->empty file

Ну назовем его например main.asm
Переписываем туда программу. Вот код:

Листинг source.asm


  #include <p18f2550.inc> ;подключение заголовков
list p=18f2550 ; выбор контроллера
CONFIG FOSC=INTOSCIO_EC ; Выбран внутренний генератор
  CONFIG MCLRE = OFF ; отключаем сигнал сброса
  CONFIG WDT   = OFF ; отключаем сторожевой таймер

DELAYCOUNTER EQU 0x00  ; задаем две переменные для создания задержки (паузы)
DELAYCOUNTER1 EQU 0x01; в программе. Они по адресу 0x00 и 0x01
A EQU 0; под буквой A будем подразумевать, что используется access bank

ORG 0 ; начинаем с 0 адреса памяти программы
  GOTO main ; перейти на метку main
  ORG 28h ; теперь пишем с 28 адреса. (сделано это для работы с прерываниями)
main ;(начинается программа main- просто метка для нашего удобства)


  CLRF BSR,A;       ; - выбираем нулевой блок памяти данных
  CLRF PORTA,A       ; - обнуляем выход на порту а    ;

  CLRF WDTCON,A; выключаем сторожевой таймер
  MOVLW 0x0F       ; записываем 0x0F в аккумулятор
  MOVWF ADCON1,A    ; перебрасываем значение в ADCON1 - настраиваем порт A на цифровой вход/выход
  CLRF TRISA,A ;- настраиваем порт а - только на выход
  
endloop ; это цикл, в который будет без конца гонять наша программа
  BTG LATA,2,A; мигнуть светодиодом 
  CALL delay255; вызвать паузу
  GOTO endloop; вернуться к началу цикла

delay255 ; функция вызова паузы
  SETF DELAYCOUNTER,A; записать 0xFF в счетчик времени
  GOTO delay; перейти к delay
delay 
  SETF DELAYCOUNTER1,A; записать 0xFF во 2й счетчик времени
delaysub1 ;
  DECFSZ DELAYCOUNTER1,F,A; уменьшить 2й счетчик на 1. если >0
  GOTO delaysub1; то вернуться на шаг назад
  DECFSZ DELAYCOUNTER,F,A; иначе - уменьшить 1й счетчик, если >0
  GOTO delay; вернуться на метку delay
  RETLW 0; иначе - выйти из функции

END ;конец программы

Для контроллера pic18f2550
https://yadi.sk/d/1YkpyyJTVLg2V
Для контроллера pic18f4550
https://yadi.sk/d/FxMGleO_VLgp7 - к сожалению не могу сейчас проверить
для копиляции щелкаем Run->build main project

после компиляции у нас должен в папке проекта появиться HEX файл. Он находится в папке dist\default\production. Его можно и нужно прошить в контроллер. Это та же программа, что и в уроке 1.
На самом деле среда MPLABX умеет работать с программаторами, но у меня PICkit 2 и с ней она работает посредственно, поэтому я прошиваю HEX файл напрямую через PICKIT

Пояснения к коду программы



Начнем потихоньку разбирать что там написано

В самом верху указываем то, какой у нас будет контроллер
#include <pic18f2550.inc>
Мы их рлдключаем для того. чтобы вместо того, чтобы всегда и везде мы записывали цифрами. мы могли использовать некоторые уже привычные нам обозначения.
напирмер, без подключения заголовков. команда записи в регистр выбора блока (BSR) -строка 16 нашей программы выглядела бы так
MOVWF 0FE0;

так... Еще директива. 
list p=18f2550
Она просто говорит
компилятору, какой контроллер будем прошивать. 

Дальше уже интереснее. Нам нужно задать управляющее слово. это - настройки контроллера. 
Задает их директива CONFIG 
По поводу всех настроек контроллера обращаемся так же к техническому описанию. ТО:288


Конфигурационные биты


CONFIG FOSC=INTOSCIO_EC
Эта настройка говорит о том, что мы будем использовать внутренний генератор импульсов. Он - внутри контроллера. Читаем в ТО:25

CONFIG MCLRE = OFF
Здесь мы отключаем сигнал сброса. То есть контроллер будет включаться сразу с подачей на него питания.

CONFIG WDT = OFF
Отключаем сторожевой таймер. Просто. чтобы не "запариваться". Он служит защитой от зависания контроллера. Читаем в ТО:299

Более подробно конфигурационные биты рассмотрены во 2-й главе к этому уроку. ссылка

Тело программы


DELAYCOUNTER EQU 0x00
Эта директива (EQU) ставит в соответствие к DELAYCOUNTER 0x00
То есть мы пишем DELAYCOUNTER, а программа думает "0x00"
Вообще мы будем использовать DELAYCOUNTER как переменную. а 0x00 - просто адрес, где она хранится в общих регистрах.
Кстати. Забыл сказать. 0x00 - это просто число. Так мы записываем числа в 16ричной системе счисления.
то есть 0x6B = 107

Мы используем для нашей программы память, входящую в access RAM, поэтому мы вольны использовать ячейки памяти от 0x00 до 0x5F. А ячейки от 0x60 до 0xFF - это регистры общего назначения.

ORG 0
Этим мы указываем компилятору, чтобы он писал все последующие команды последовательно с адреса 0.
GOTO main
ORG 28h
main
Переходим на метку main. И начиная с 0x28 адреса пишем программу дальше. Метка main - адрес 0x28
Обратите внимание, мы оставили свободное место между адресом программы 0x1 и 0x28. Зачем? Если мы будем в последствии использовать прерывания, то в случае. если прерывание будет требовать на время приостановить программу. оно начнет выполнять команды по адресу 0x8 или 0x18. и это место нужно будет заполнить программой обработки прерывания.

Все последующие команды смотри в главе 3. Команды ассемблера. ссылка

MOVWF ADCON1
Когда мы записываем значение в регистр ADCON1. мы меняем настройки АЦП. По поводу 
использования встроенных устройств контроллера смотри главу 4. ссылка


Пожалуйста, помогите сделать статью лучше. Увидели непонятность, неточность или  ошибку, сообщите в комментарии, или напишите мне. Спасибо. Jasuramme@mail.ru

воскресенье, 29 июня 2014 г.

CAN интерфейс и контроллер pic18f2550

<< Назад к оглавлению

ЭТО УСТАРЕВШАЯ ВЕРСИЯ. НОВУЮ МОЖНО НАЙТИ Здесь
Мы будем говорить о контроллере pic18f2550, поскольку только он сейчас есть у меня перед глазами. Но все нижесказанное должно быть справедливо и для pic18f4550.
В этом контроллере есть специальные встроенные возможности общаться с периферией, но нету возможности создать сеть штатными средствами.
Предположим, что необходимо создать связь между несколькими отдаленными контроллерами. Можно конечно продумать то, как они будут общаться, написать для этого программу и установить усилители сигналов, чтобы их можно было передать на дальние расстояния. Но не много ли работы?
Есть множество готовых решений, с помощью которых можно это сделать.
Мы будем рассматривать CAN интерфейс. Он изначально был предложен фирмой Bosch и в сети есть множество информации, описывающей can интерфейс.
В двух словах о нем.
- передача идет по двум проводам
- настраивается скорость передачи информации
- существует механизм проверки сообщений
- гарантированная доставка сообщений.
На самом деле мне кажется абсолютно неважным описывать что-то столько раз документированное.
http://ru.wikipedia.org/wiki/Controller_Area_Network
Так же официальная спецификация на стандарт CAN 2.0
http://www.bosch-semiconductors.de/media/pdf_1/canliteratur/can2spec.pdf

Есть специальный интерфейсный контроллер CAN от фирмы microchip MCP2515
http://ww1.microchip.com/downloads/en/DeviceDoc/21801G.pdf
Это специальное "добавление" к контроллеру, осуществляющее реализацию сети CAN. И для этого контроллера еще нужен будет передатчик MCP2551
http://ww1.microchip.com/downloads/en/DeviceDoc/21667f.pdf
Ниже показано подключение pic18f2550 к MCP2515
Файлы проекта:
https://yadi.sk/d/7MknbTTtVNWJD
Проект рассчитан на то, чтобы быть прошитым через bootloader.

Общение между pic18f2550 и MCP 2515 происходит с помощью протокола SPI, созданного для общения с периферийными устройствами.
Для SPI используются соответствующие ноги SDI SDO SCK и CS
причем SDI (input) mcp2515 нужно подключить к SDO (output) pic18f2550. А в качестве CS используется любой цифровой вывод контроллера.

В проекте следующие файлы
2550can.c - основной файл команды
io.h - файл, в котором настроены вводы выводы pic18f2550
mcp2515address.h - адреса регистров внутри модуля MCP2515
spi.h - файл для работы со SPI интерфейсом

В программе используются следующие специфические комманды

OpenSPI(SPI_FOSC_16, MODE_00, SMPMID)  - Настройка регистров, связанных со SPI модулем

WriteSPI(msg)  - записать через SPI интерфейс сообщение msg

ReadSPI(msg)  - Возвращает прочитанный байт через SPI
в коде программы определены следующие функции, выполняющие действия с контроллером MCP2515

SPIByteRead(адрес) - прочитать регистр по адресу
SPIReset() - перезагрузить
SPImsg() - передать через SPI одно сообщение
SPIByteWrite(адрес,сообщение) - записать в адрес сообщение
transmitmsg() - передать сообщение

Настройка контроллера производится в функции userinit(); и в последствии в CANinit();
нужно выставить соответствующие пины контроллера на вывод (SDO,SCK) и ввод (SDI) - читай подробнее в комментариях к контроллеру.

потом идет перезагрузка контроллера и модуль CAN переводится в конфигурационный режим. Все основные настройки можно делать только в этом режиме. Настраиваются соответствующие конфигурационные регистры. Во-первых bit-timing (CNF1,CNF2,CNF3). Все узлы сети CAN должны работать на одной тактовой частоте.

Потом настраиваются маски и фильтры передачи. Грубо говоря это адреса, который наш узел будет принимать. Читайте подробнее в документации.
Настраивается идентификатор передачи. - это адрес, с которым будет передаваться сообщение от этого узла.

У контроллера MCP2515 есть возможность отправлять сообщение при высоком сигнале на входах RTS. Мы отключаем их. Будем отправлять с помощью команд, передаваемых через SPI.
настраиваем прерывания. Например, когда контроллер увидит сеть CAN вывод INT будет нулем. По умолчанию на нем будет 1.
Так же настраиваются RX0BF и RX1BF. Когда буфер 0 будет заполнен, на RX0BFпропадет напряжение.
Потом мы включаем нормальный режим, в котором контроллер работает.

А потом передаем сообщение (по факту передастся при первой возможности - подключении к CAN сети). И просто мигаем светодиодом на RA2

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

У модуля CAN есть множество возможностей. Советую почитать спецификацию CAN и техническое описание MCP2515.

Подключение узлов осуществляется следующим образом.

То, что указано на схеме подключения имеет выводы CANH и CANL это и должно быть подключено к сетевым линиям.

Прошу спрашивать, если что-либо непонятно или требует дополнительного рассмотрения.