Статьи                Главная

Алгоритм программирования микроконтроллеров PICmicro.


  Программирование микроконтроллеров (МК) семейства PICmicro осуществляется последовательным способом. Обмен информацией производится через двунаправленную линию DATA (обычно RB7). Синхронизирующие импульсы поступают в МК по однонаправленной линии CLOCK (обычно RB6). Перевод МК в режим программирования происходит после подачи повышенного напряжения, обычно равного 12В на вывод MCLR при нулевых логических уровнях на линиях CLOCK и DATA. Существуют два способа перевода МК в этот режим.

   При включённом напряжении питания подать напряжение 12В на вывод MCLR

   При выключенном напряжении питания подать напряжение 12В на вывод MCLR, после чего включить напряжение питания.

Второй способ считается более предпочтительным, поскольку в этом случае отсутствует ограничение на конфигурацию вывода MCLR, что особенно актуально в МК, имеющих небольшое количество выводов. К сожалению, его не поддерживают некоторые типы МК и большинство "простых" программаторов, подключаемый через COM порт. Это связано с тем, что у COM порта слишком мало линий вывода информации, поэтому нет возможности управлять подачей напряжения питания программируемого МК. Иногда, чтобы преодолеть это препятствие, в программаторе аппаратно реализуют небольшую задержку между подачей напряжения программирования и питания. Существует ещё так называемый низковольтный режим программирования, но его мы рассматривать не будем.

После перевода МК в режим программирования станут доступными специальные регистры команд и данных блока программирования. Запись и чтение информации из регистров осуществляется через линию DATA, подавая тактовые импульсы на линию CLOCK. Активным перепадом является спад тактового импульса. Для выполнения какой-либо операции, сначала нужно послать команду, а затем в зависимости от команды, выполнить необходимое действие, например, прочитать информационное слово из регистра данных. Список команд для МК серий PIC16F6ХХ приведён в таблице

 

Команда

Формат

Формат данных

Загрузка конфигурации

Х Х 0 0 0 0

0 b b b b b b b b b b b b b b 0

Загрузка данных в память программ

Х Х 0 0 1 0

0 b b b b b b b b b b b b b b 0

Загрузка данных в память данных

Х Х 0 0 1 1

0 0 0 0 0 0 0 b b b b b b b b 0

Увеличение адреса

Х Х 0 1 1 0

 

Чтение данных из памяти программ

Х Х 0 1 0 0

0 b b b b b b b b b b b b b b 0

Чтение данных из памяти данных

Х Х 0 1 0 1

0 0 0 0 0 0 0 b b b b b b b b 0

Программирование

Х 0 1 0 0 0

 

Полное стирание памяти программ

Х Х 1 0 0 1

 

Полное стирание памяти данных

Х Х 1 0 1 1

 

 
    В таблице символами X обозначены биты, которые могут иметь произвольное значение. Обратите внимание, что команды состоят только из 6 бит! После некоторых команд нужно производить чтение либо запись данных. Данные передаются словами, состоящими, из 16 бит, но не все биты несут в себе информацию. Положение информационных бит показаны символами b. Первым передаётся нулевой бит. Это касается команд и данных.

Программы для компьютера написаны на языке PureBasic. На момент написания статьи была доступна версия 4.30. Для компиляции программ нужна дополнительная библиотека функций MVCOM, поддерживающая COM порт. Для установки библиотеки достаточно извлечь содержимое архива в папку с программой PureBasic. В архиве есть также библиотека MicroDelayTimer, содержащая в себе одноимённую функцию. Она необходима для формирования задержек меньше 1 мс.  

В файле MK_Prog_Procedure.pbi приведены базовые процедуры, с помощью которых производится  работа с МК в режиме программирования. В начале кода объявляются некоторые переменные как глобальные (доступные в процедурах), назначение которых можно узнать из комментариев.

Код:
; *********************************************
; * Базовые процедуры работы с программатором *
; *********************************************

Global ComProg_Delay.l ; Задержка, заданная в микросекундах
Global ComProg_DataOut_Inv.c ; Инверсия отправляемых данных по DTR (1-инверсия, 0-нет)
Global ComProg_DataIn_Inv.c ; Инверсия входящих данных по CTS (1-инверсия, 0-нет)
Global ComProg_Clock_Inv.c ; Инверсия строба по RTS (1-инверсия, 0-нет)
Global ComProg_Pitanie.c ; Инверсия напряжения программирования (1-инверсия, 0-нет)
Global ComPortName.s ; Имя порта, через который происходит программирование

Global ComProg_ComId.l=0 ; Идентификатор открытого COM порта.

Procedure ComProg_Init()
; Чтение настроек из файла Preferences.ini
If OpenPreferences("Preferences.ini")=0
MessageRequester("Ошибка", "Файл Preferences.ini не найден", 16)
EndIf
; Чтение данных
ComProg_Delay = ReadPreferenceLong("ComProg_Delay",200)
ComProg_DataOut_Inv = ReadPreferenceLong("ComProg_DataOut_Inv",0)
ComProg_DataIn_Inv = ReadPreferenceLong("ComProg_DataIn_Inv",0)
ComProg_Clock_Inv = ReadPreferenceLong("ComProg_Clock_Inv",0)
ComProg_Pitanie = ReadPreferenceLong("ComProg_Pitanie",0)
ComPortName = ReadPreferenceString("ComPortName","COM1")
ClosePreferences()
EndProcedure

Procedure ComProg_Test()
; Проверяется есть ли программатор (перемычка между DSR и RTS)

Delay(10) ; Пауза на 10 мс.
ComSetRTS(ComProg_ComId,1) ; Установка лог. 1 на выводе RTS
Delay(10) ; Пауза на 10 мс.
If ComGetDSR(ComProg_ComId)<>1
ProcedureReturn 0 ; Ошибка, обратной связи нет!
EndIf
ComSetRTS(ComProg_ComId,0) ; Установка лог. 0 на выводе RTS
Delay(10) ; Пауза на 10 мс.
If ComGetDSR(ComProg_ComId)<>0
ProcedureReturn 0 ; Ошибка, обратной связи нет!
EndIf
Delay(10) ; Пауза на 10 мс.

ProcedureReturn 1 ; Программатор обнаружен.
EndProcedure

Procedure.c ComProg_DataIn()
; Чтение одного бита из микроконтроллера

If ComProg_Clock_Inv=1 ; Нужна инверсия такта
Start.c=0 : Stop.c=1
Else ; Инверсия такта не требуется
Start.c=1 : Stop.c=0
EndIf

ComSetRTS(ComProg_ComId,Start) ; Фронт такта (или спад при инверсии)
MicroDelayTimer(ComProg_Delay) ; Пауза
ComSetRTS(ComProg_ComId,Stop) ; Спад такта (или фронт при инверсии)
MicroDelayTimer(ComProg_Delay) ; Пауза
MicroDelayTimer(ComProg_Delay) ; Пауза
Bit.c=ComGetCTS(ComProg_ComId) ; Читаем бит

If ComProg_DataIn_Inv=1 ; Нужна инверсия полученных данных
Bit=Bit!1 ; Инвертируем данные
EndIf
ProcedureReturn Bit
EndProcedure

Procedure ComProg_DataOut(Bit.c)
; Отправка одного бита микроконтроллеру

If Bit>0
Bit_x.c=1 ; Число в Bit больше нуля
Else
Bit_x.c=0 ; Число в Bit равно или меньше нуля
EndIf
If ComProg_DataOut_Inv=1 ; Нужна инверсия отправляемых данных
Bit_x=Bit_x!1 ; Инвертируем данные
EndIf
If ComProg_Clock_Inv=1 ; Нужна инверсия такта
Start.c=0 : Stop.c=1
Else ; Инверсия такта не требуется
Start.c=1 : Stop.c=0
EndIf
ComSetDTR(ComProg_ComId,Bit_x) ; Отправляем бит
MicroDelayTimer(ComProg_Delay) ; Пауза
MicroDelayTimer(ComProg_Delay) ; Пауза
ComSetRTS(ComProg_ComId,Start) ; Фронт такта (или спад при инверсии)
MicroDelayTimer(ComProg_Delay) ; Пауза
ComSetRTS(ComProg_ComId,Stop) ; Спад такта (или фронт при инверсии)
MicroDelayTimer(ComProg_Delay) ; Пауза
EndProcedure

Procedure ComProg_StartStop(State.c)
; Включает (State=1) или выключает (State=0) напряжение программирования.

; Установка лог. нуля на лини CLOCK
If ComProg_Clock_Inv = 1 ; Требуется инверсия
ComSetRTS(ComProg_ComId,1)
Else
ComSetRTS(ComProg_ComId,0)
EndIf
; Установка лог. нуля на лини DATA
If ComProg_DataOut_Inv = 1 ; Требуется инверсия
ComSetDTR(ComProg_ComId,1)
Else
ComSetDTR(ComProg_ComId,0)
EndIf

Delay(40)

If State>0
StatePit=1
Else
StatePit=0
EndIf
If ComProg_Pitanie=1 ; Требуется инверсия
StatePit=StatePit!1
EndIf
ComSetTXD(ComProg_ComId, StatePit)
EndProcedure

Procedure ComProg_OutByteCommand(DataOut.c)
; Передача команды программируемому микроконтроллеру
For i=1 To 6 ; Цикл передачи команды (6 бит)
Out.c=DataOut
Out=Out & 1 ; Обнуление всех бит кроме нулевого
ComProg_DataOut(Out) ; Отправляем бит микроконтроллеру
DataOut=DataOut>>1 ; Сдвиг информации на одну позицию вправо.
Next i
EndProcedure

Procedure ComProg_OutByteData(DataOut.l)
; Передача данных программируемому микроконтроллеру
DataOut=DataOut<<1 ; Сдвиг информации на одну позицию влево
DataOut=DataOut & %0111111111111110 ; Обнуление нулевого и пятнадцатого бита
For i=1 To 16 ; Цикл передачи данных (16 бит)
Out.l=DataOut
Out=Out & 1 ; Обнуление всех бит кроме нулевого
ComProg_DataOut(Out) ; Отправляем бит микроконтроллеру
DataOut=DataOut>>1 ; Сдвиг информации на одну позицию вправо.
Next i
EndProcedure

Procedure.l ComProg_InByteData()
; Чтение данных из программируемого микроконтроллера

; Установка высокого логического уровня на линии данных
If ComProg_DataOut_Inv=1 ; Нужна инверсия логического уровня
ComSetDTR(ComProg_ComId,0)
Else
ComSetDTR(ComProg_ComId,1)
EndIf

For i=1 To 16 ; Цикл приёма данных (16 бит)
Bit.c=ComProg_DataIn() ; Чтение бита из микроконтроллера
If Bit=0 ; Прочитанный бит равен нулю
In=In & %0111111111111111 ; Обнуление 15 бита с помощью "логического И"
Else ; Бит не равен нулю
In=In | %1000000000000000 ; Установка 15 бита с помощью "логического ИЛИ"
EndIf
In=In>>1 ; Сдвиг информации на одну позицию вправо.
Next i

In=In & $3FFF ; Обнуление 14 и 15 бита
ProcedureReturn In
EndProcedure

Procedure OpenCom_Port(Port.s)
; Открытие COM порта
ResultPotr.s=Port+":9600,N,8,1"
ComProg_ComId=ComOpen(ResultPotr,#HandShakeModeNone,1,1)
ProcedureReturn ComProg_ComId
EndProcedure

Procedure CloseCom_Port()
; Закрытие COM порта
ComClose(ComProg_ComId)
ComProg_ComId=0
EndProcedure

Процедура ComProg_Init(), загружает из файла "Preferences.ini", расположенного в одной папке с программой текущие настройки в ранее объявленные глобальные переменные. Это нужно для того, чтобы можно было бы настроить программу под конкретный тип программатора после того, как она была скомпилирована.

Процедура ComProg_Test() проверяет наличие соединения выводов DSR и RTS порта, для того чтобы убедится в наличии подключённого программатора. Это производится следующим образом: На выходе RTS порта, с помощью функции ComSetRTS() последовательно устанавливаются противоположные логические уровни.  Функция ComGetDSR, определяет текущий логический уровень на входе DSR. Если он не соответствует требуемому, делается вывод о том, что программатор не подключён и процедура возвращает в качестве результата своей работы число 0 с помощью оператора ProcedureReturn. При наличии программатора (соединения между DSR и RTS) этот тест будет успешно пройден и процедура вернёт число 1.

Процедура ComProg_DataIn() формирует один тактовый импульс и считывает бит из МК. Вначале процедуры анализируется значение переменной ComProg_Clock_Inv, в которой хранится признак инверсии тактовых импульсов. В зависимости от этого записываются противоположные значения в переменные Start и Stop, что обеспечивает инвертирование такта. Далее формируется один тактовый импульс на выводе RTS порта, с помощью функции ComSetRTS(). Затем, появившейся на линии CTS порта информационный бит от МК считывается функцией ComGetCTS() и помещается в переменную Bit.  После этого, при необходимости осуществляется инверсия бита.

Процедура ComProg_DataOut() отправляет МК один бит. В начале при необходимости производится инверсия бита и тактового импульса. Далее, устанавливается на линии DTR, порта передаваемый бит, после чего формируется тактовый импульс.

Процедура ComProg_StartStop() управляет напряжением программирования. Прежде всего, устанавливаются нулевые логические уровни на линиях DATA и CLOCK, что является обязательным условием корректного перевода МК в режим программирования. Далее при помощи функции ComSetTXD() устанавливается заданный логический уровень на выводе TXD, что позволяет управлять напряжением программирования. Нужно отметить, что функция ComSetTXD() предназначена для совсем других целей. Она позволяет переводить передатчик COM порта в режим ожидания для временного прекращения передачи информации. Но в этом режиме выходное напряжение противоположно тому, что находится на выводе, во время паузы между отдельными байтами.

Процедура ComProg_OutByteCommand() отправляет команду МК. Команда передаётся в цикле ForNext. Переменной "i", являющейся счётчиком цикла присваивается значение 1. На каждом витке цикла значение этой переменной увеличивается на единицу, когда оно достигнет числа, заданного после оператора To - цикл прервётся. В нашем случае, код внутри цикла будет выполнен 6 раз, поскольку именно такая длина у всех команд. Внутри цикла, выполняется выделение отдельных бит и их отправка МК. Для этого производится копирование информации из переменной DataOut в переменную Out и обнуление 1..7 бита последней. Производится это с помощью операции "логическое И", которая выполняется с помощью оператора "&". Таким образом, выделяется нулевой бит и отправляется в МК с помощью ранее рассмотренной процедуры ComProg_DataOut(). Далее содержимое переменной DataOut сдвигается на одну позицию вправо, тем самым, подготавливая очередной бит к передаче. После передачи шести бит работа процедуры завершится.

   Для передачи данных в МК служит процедура ComProg_OutByteData(). Данные из переменной DataOut сдвигаются на одну позицию влево и обнуляются нулевой и пятнадцатый бит, чтобы формат данных соответствовал таблице. Далее следует цикл For Next. Он аналогичен ранее рассмотренному, единственное отличие в том, что код, расположенный в нём будет выполнен не шесть, а шестнадцать раз.

   Процедура ComProg_InByteData() считывает одно слово, равное двум байтам из МК. В самом начале, на выводе DATA МК устанавливается высокий логический уровень, что требуется для безошибочного чтения информации. Это связанно с аппаратными особенностями программаторов. В цикле ForNext, который выполняется 16 раз, производится побитное чтение информации. Бит читается с помощью ранее рассмотренной процедуры ComProg_DataIn(). Затем анализируется и в зависимости от его значения, добавляется с помощью различных логических операций в конец переменной In. После чего, информация в переменной In сдвигается на одну позицию вправо. Таким образом, к концу чтения в переменной In окажется принятое слово.  Далее обнуляются 14 и 15 биты  переменной с помощью операции "Логическое И" и её значение возвращается в качестве результата работы процедуры.

  Процедура OpenCom_Port() открывает требуемый COM порт. В качестве аргумента нужно указать имя порта. При успешном открытии, в переменной ComProg_ComId окажется идентификатор порта, который не равен нулю. В случае неудачной попытки открытия порта, в переменной будет число 0, что однозначно указывает на ошибку при доступе к порту. Процедура ComClose() закрывает ранее открытый порт.

Теперь настало время с помощью этих процедур запрограммировать МК. Исхдный текст программы находится в файле MK_WriteProgram.pb

Код:
; --------------------------------------------------------------
; **** Программирование первых десяти ячеек памяти программ ****
; --------------------------------------------------------------
XIncludeFile "MK_Prog_Procedure.pbi" ; Подключение дополнительного исходного текста

ComProg_Init() ; Загрузка настроек из файла Preferences.ini

If OpenCom_Port(ComPortName)=0 ;- Открытие COM порта
MessageRequester("Ошибка", "Не удалось открыть порт "+ComPortName, 16)
End ; Завершение работы программы
EndIf

If ComProg_Test()=0 ; Проверка наличия программатора
MessageRequester("Ошибка", "Не найден программатор", 16)
EndIf

ComProg_StartStop(1) ; Подача напряжения программирования
Delay(1000) ; Ждём секунду

ComProg_OutByteCommand(%000010) ;- Команда "Загрузка данных в память программ"
ComProg_OutByteData($3FFF) ; Отправка данных
ComProg_OutByteCommand(%001001) ;- Команда "Полное стирание памяти программ"
ComProg_OutByteCommand(%001000) ;- Команда "Программирование"
Delay(20) ; Ожидание (20 мс) завершения процесса стирания

ComProg_StartStop(0) ;- Отключение напряжения программирования
Delay(200) ; Ждём 200 мс
ComProg_StartStop(1) ; Подача напряжения программирования
Delay(200) ; Ждём 200 мс

For x=1 To 10 ; Цикл записи данных в микроконтроллер
ComProg_OutByteCommand(%000010) ;- Команда "Загрузка данных в память программ"
ComProg_OutByteData(x) ; Отправка данных
ComProg_OutByteCommand(%001000) ;- Команда "Программирование"
Delay(20) ; Ожидание (20 мс) завершения процесса программирования текущей ячейки памяти.
ComProg_OutByteCommand(%000110) ;- Команда "Увеличение адреса"
Next x

Delay(100) ; Ждём 0.1 секунды
ComProg_StartStop(0) ;- Отключение напряжения программирования
CloseCom_Port() ;- Закрытие порта
MessageRequester("Память программ", "Программирование завершено", 64)
End ; Завершение работы программы

Он записывает данные в первые 10 ячеек памяти программ.  В начале программы, при помощи оператора XIncludeFile подключается файл с ранее рассмотренными процедурами, с именем MK_Prog_Procedure.pbi. Он должен находиться в той же папке что и основная программа. Далее вызывается процедура ComProg_Init() загружающая данные об инверсии сигналов и имени COM порта из файла Preferences.ini. После этого открывается COM порт и проверяется наличие программатора. Далее вызывается процедура ComProg_StartStop() с аргументом 1, подающая напряжение программирования на МК.  После этого осуществляется полное стирание памяти программ. Без чего, информация некоторые типы МК записывалась с искажениями. Для этого сначала посылается команда 000010, сообщающая о том, что предстоит запись в память программ, а затем число 3FFFH. Далее следуют команды 001001 - "Полное стирание памяти программ" и 001000 - "Программирование". После чего следует пауза, равная 20 мс. Учтите, при этом будет стёрто слово конфигурации! Запись информации осуществляется в цикле ForNext. Для того чтобы МК понял, что намечается процесс программирования памяти программ, ему отправляется команда 000010. Затем, с помощью процедуры ComProg_OutByteData() передаётся текущее содержимое переменной X. Далее подаётся команда 001000 – "Программирование". После этой команды нужно выждать определённое время, которое по паспортным данным должно быть не менее 10 миллисекунд. Для гарантированного завершения программирования, с помощью функции Delay() формируется пауза, равная 20 миллисекунд. После этого МК отправляется команда 000110, увеличивающая текущее значение счётчика адреса. После завершения цикла и выжидания 100 мс., будет отключено напряжение программирования и закрыт порт, а затем на экране появится окно, сообщающее об окончании процесса.

Теперь прочитаем ранее записанную информацию с помощью кода из файла MK_ReadProgram.pb

Код:
; ----------------------------------------------------
; **** Чтение первых десяти ячеек памяти программ ****
; ----------------------------------------------------
XIncludeFile "MK_Prog_Procedure.pbi" ; Подключение дополнительного исходного текста

ComProg_Init() ; Загрузка настроек из файла Preferences.ini

If OpenCom_Port(ComPortName)=0 ;- Открытие COM порта
MessageRequester("Ошибка", "Не удалось открыть порт "+ComPortName, 16)
End ; Завершение работы программы
EndIf

If ComProg_Test()=0 ; Проверка наличия программатора
MessageRequester("Ошибка", "Не найден программатор", 16)
EndIf

ComProg_StartStop(1) ; Подача напряжения программирования
Delay(1000) ; Ждём секунду

Text.s="" ; Объявление переменной строкового типа

For x=1 To 10 ; Цикл чтения данных из микроконтроллера
ComProg_OutByteCommand(%000100) ;- Команда "Чтение данных из памяти программ"
Slovo=ComProg_InByteData() ; Чтение слова (два байта) из памяти программ
Text=Text+RSet(Hex(Slovo),4,"0")+Chr(10) ; Преобразование полученных данных в строковой вид.
ComProg_OutByteCommand(%000110) ;- Команда "Увеличение адреса"
Next x

Delay(100) ; Ждём 0.1 секунды
ComProg_StartStop(0) ;- Отключение напряжения программирования
CloseCom_Port() ;- Закрытие порта
MessageRequester("Чтение памяти программ",Text, 64)
End ; Завершение работы программы

По сравнению с предыдущим, он отличается отсутствием кода, стирающего память и содержимым цикла ForNext, которое и будет рассмотрено. Для того чтобы МК понял, что намечается чтение информации из памяти программ, ему отправляется команда 000100. Затем, при помощи процедуры ComProg_InByteData() считывается одно слово из текущей ячейки в переменную Slovo. Далее выполняется преобразование данных этой переменной в шестнадцатиричную систему исчисления. Результат добавляется к текущему содержимому строковой переменной Text. Это преобразование необходимо только для последующего отображения результатов. После это МК отправляется команда 000110, увеличивающая текущее значение счётчика адреса. Когда процесс чтения информации завершится, будет отключено напряжение программирования и закрыт порт. Затем, функция MessageRequester() создаёт окно, в котором отобразятся данные из первых десяти ячеек памяти программ 

рисунок

Программирование памяти данных выполняется аналогично программированию памяти программ. Различие только в некоторых командах. В файле MK_WriteData.pb показан код, записывающий числа в пределах 1…10 в первые десять ячеек памяти данных. 

Код:
; -------------------------------------------------------------
; **** Программирование первых десяти ячеек памяти данных ****
; -------------------------------------------------------------
XIncludeFile "MK_Prog_Procedure.pbi" ; Подключение дополнительного исходного текста

ComProg_Init() ; Загрузка настроек из файла Preferences.ini

If OpenCom_Port(ComPortName)=0 ; Открытие COM порта
MessageRequester("Ошибка", "Не удалось открыть порт "+ComPortName, 16)
End ; Завершение работы программы
EndIf

If ComProg_Test()=0 ; Проверка наличия программатора
MessageRequester("Ошибка", "Не найден программатор", 16)
EndIf

ComProg_StartStop(1) ; Подача напряжения программирования
Delay(200) ; Ждём 200 мс.

ComProg_OutByteCommand(%000011) ;- Команда "Загрузка данных в память данных"
ComProg_OutByteData($3FFF) ; Отправка данных
ComProg_OutByteCommand(%001011) ;- Команда "Полное стирание памяти данных"
ComProg_OutByteCommand(%001000) ;- Команда "Программирование"
Delay(20) ; Ожидание (20 мс) завершения процесса стирания

ComProg_StartStop(0) ;- Отключение напряжения программирования
Delay(200) ; Ждём 200 мс
ComProg_StartStop(1) ; Подача напряжения программирования
Delay(200) ; Ждём 200 мс

For x=1 To 10 ; Цикл записи данных в микроконтроллер
ComProg_OutByteCommand(%000011) ;- Команда "Загрузка данных в память данных"
ComProg_OutByteData(x) ; Отправка данных
ComProg_OutByteCommand(%001000) ;- Команда "Программирование"
Delay(20) ; Ожидание (20 мс) завершения процесса программирования текущей ячейки памяти.
ComProg_OutByteCommand(%000110) ;- Команда "Увеличение адреса"
Next x

Delay(100) ; Ждём 0.1 секунды
ComProg_StartStop(0) ;- Отключение напряжения программирования
CloseCom_Port() ;- Закрытие порта
MessageRequester("Память данных", "Программирование завершено", 64)
End ; Завершение работы программы

Рассмотрим участки программы, имеющие отличия от файла MK_WriteProgram.pb. Процесс стирания начинается с подачи команды 000011 - "Загрузка данных в память данных" а затем число 3FFFH, за которым следует команда 001011 - "Полное стирание памяти данных". Далее следует команда программирования, что приведёт к полному стиранию информации в памяти данных. В цикле ForNext производится запись информации. Сперва отправляется команда 000011 - "Загрузка данных в память данных", а затем данные – текущее содержимое переменной X, являющейся счётчиком цикла, значение которого увеличивается на каждом витке цикла. Далее следуют команды программирования и увеличения текущего адреса. После завершения работы цикла, питание программируемого МК будет отключено и программа завершит свою работу.

Программа чтения памяти данных (файл MK_ReadData.pb) основана на ранее рассмотренном коде, работающем с памятью программ. Отличие только в том, что для чтения информации МК отправляется команда 000101.

Код:
; --------------------------------------------------
; **** Чтение первых десяти ячеек памяти данных ****
; --------------------------------------------------
XIncludeFile "MK_Prog_Procedure.pbi" ; Подключение дополнительного исходного текста

ComProg_Init() ; Загрузка настроек из файла Preferences.ini

If OpenCom_Port(ComPortName)=0 ;- Открытие COM порта
MessageRequester("Ошибка", "Не удалось открыть порт "+ComPortName, 16)
End ; Завершение работы программы
EndIf

If ComProg_Test()=0 ; Проверка наличия программатора
MessageRequester("Ошибка", "Не найден программатор", 16)
EndIf

ComProg_StartStop(1) ; Подача напряжения программирования
Delay(1000) ; Ждём секунду.

Text.s="" ; Объявление переменной строкового типа

For x=1 To 10 ; Цикл чтения данных из микроконтроллера
ComProg_OutByteCommand(%000101) ;- Команда "Чтение данных из памяти данных"
Slovo=ComProg_InByteData() ; Чтение слова (два байта)
Slovo=Slovo & %11111111 ; Обнуление незначащих бит
Text=Text+RSet(Hex(Slovo),2,"0")+Chr(10) ; Преобразование полученных данных в строковой вид.
ComProg_OutByteCommand(%000110) ;- Команда "Увеличение адреса"
Next x

Delay(100) ; Ждём 0.1 секунды
ComProg_StartStop(0) ;- Отключение напряжения программирования
CloseCom_Port() ;- Закрытие порта
MessageRequester("Чтение памяти данных",Text, 64)
End ; Завершение работы программы

            Идентификаторы и слово конфигурации МК находятся в одном адресном пространстве. Идентификаторы располагаются в ячейках с адресами 2000H - 2003H, а слово конфигурации имеет адрес 2007H. Для доступа к этому адресному пространству нужно МК отправить команду 000000 – "Загрузка конфигурации". Далее с помощью команд, работающих с памятью программ, производятся требуемые операции. Программа, записывающая информацию в идентификаторы и слово конфигурации, находится в файле MK_WriteConfig.pb

Код:
; -----------------------------------------------
; **** Запись идентификаторов и конфигурации ****
; -----------------------------------------------
XIncludeFile "MK_Prog_Procedure.pbi" ; Подключение дополнительного исходного текста

ComProg_Init() ; Загрузка настроек из файла Preferences.ini

If OpenCom_Port(ComPortName)=0 ;- Открытие COM порта
MessageRequester("Ошибка", "Не удалось открыть порт "+ComPortName, 16)
End ; Завершение работы программы
EndIf

If ComProg_Test()=0 ; Проверка наличия программатора
MessageRequester("Ошибка", "Не найден программатор", 16)
EndIf

ComProg_StartStop(1) ; Подача напряжения программирования
Delay(1000) ; Ждём секунду.

ComProg_OutByteCommand(%000000) ;- Команда "Загрузка конфигурации"
ComProg_OutByteData($3FFF)
For i=1 To 4 ; Код в цикле будет выполнен четыре раза
ComProg_OutByteCommand(%000010) ;- Команда "Загрузка данных в память программ"
ComProg_OutByteData(i)
ComProg_OutByteCommand(%001000) ;- Команда "Программирование"
Delay(20) ; Ожидание окончания программирования
ComProg_OutByteCommand(%000110) ;- Команда "Увеличение адреса"
Next i

ComProg_OutByteCommand(%000110) ;- Команда "Увеличение адреса"
ComProg_OutByteCommand(%000110) ;- Команда "Увеличение адреса"
ComProg_OutByteCommand(%000110) ;- Команда "Увеличение адреса"

ComProg_OutByteCommand(%000010) ;- Команда "Загрузка данных в память программ"
ComProg_OutByteData($3FF1)
ComProg_OutByteCommand(%001000) ;- Команда "Программирование"

Delay(100) ; Ждём 0.1 секунды
ComProg_StartStop(0) ;- Отключение напряжения программирования
CloseCom_Port() ;- Закрытие порта
MessageRequester("","Запись идентификаторов и конфигурации завершена", 64)
End ; Завершение работы программы

    После открытия порта и проверки наличия программатора, МК отправляется команда 000000 - "Загрузка конфигурации". Это установит текущим адрес 2000H. В цикле ForNext производится запись значения переменной i в текущую ячейку идентификатора. Для программирования ячейки, сначала отправляется команда 000010 – "Загрузка данных в память программ", а затем содержимое переменной i. Далее отправляется команда 001000 - "Программирование", за которой следует пауза, равная 20 мс. Это время требуется для записи полученной информации. После чего при помощи команды 000110 увеличивается текущее значение счётчика адреса. После завершения цикла в счётчике адреса будет число 2004H. Для доступа к ячейке, хранящей слово конфигурации, трижды посылается команда 000110. После этого в счётчике адреса будет значение 2007H. Далее в МК записывается слово конфигурации 3FF1H. Учтите, оно предназначено для МК PIC16F84А! После чего на экране появится сообщение об окончании процесса программирования. Как только это окно будет закрыто, работа программы завершится при помощи директивы End. К сожалению, этот код при работе с некоторыми типами МК, программирует идентификаторы с искажениями!

            В файле MK_ReadConfig.pb приведён код, считывающий данные из идентификаторов и конфигурации МК. Как и при записи, для перехода в служебную область, отправляется команда 000000. Далее следует цикл ForNext , в котором производится чтение информации из четырёх ячеек идентификаторов. Полученные данные преобразуются в шестнадцатиричный вид. Это нужно только для отображения результатов чтения. Затем значение счётчика адреса увеличивается на три пункта, для того чтобы прочитать слово конфигурации. Перед завершением работы программы появится окно с результатами чтения.

Код:
; -----------------------------------------------
; **** Чтение идентификаторов и конфигурации ****
; -----------------------------------------------
XIncludeFile "MK_Prog_Procedure.pbi" ; Подключение дополнительного исходного текста

ComProg_Init() ; Загрузка настроек из файла Preferences.ini

If OpenCom_Port(ComPortName)=0 ;- Открытие COM порта
MessageRequester("Ошибка", "Не удалось открыть порт "+ComPortName, 16)
End ; Завершение работы программы
EndIf

If ComProg_Test()=0 ; Проверка наличия программатора
MessageRequester("Ошибка", "Не найден программатор", 16)
EndIf

ComProg_StartStop(1) ; Подача напряжения программирования
Delay(1000) ; Ждём секунду.

Text.s="Идентификаторы:"+Chr(10)

ComProg_OutByteCommand(%000000) ;- Команда "Загрузка конфигурации"
ComProg_OutByteData($3FFF)
For i=1 To 4
ComProg_OutByteCommand(%000100) ;- Команда "Чтение данных из памяти программ"
IDSlovo=ComProg_InByteData() ; Чтение идентификатора
Text=Text+RSet(Hex(IDSlovo),4,"0")+Chr(10)
ComProg_OutByteCommand(%000110) ;- Команда "Увеличение адреса"
Next i

ComProg_OutByteCommand(%000110) ;- Команда "Увеличение адреса"
ComProg_OutByteCommand(%000110) ;- Команда "Увеличение адреса"
ComProg_OutByteCommand(%000110) ;- Команда "Увеличение адреса"

ComProg_OutByteCommand(%000100) ;- Команда "Чтение данных из памяти программ"
ConfigSlovo=ComProg_InByteData() ; Чтение слова конфигурации

Text=Text+Chr(10)
Text=Text+"Конфигурация: "+RSet(Hex(ConfigSlovo),4,"0")


Delay(100) ; Ждём 0.1 секунды
ComProg_StartStop(0) ;- Отключение напряжения программирования
CloseCom_Port() ;- Закрытие порта
MessageRequester("Чтение идентификаторов и конфигурации",Text, 64)
End ; Завершение работы программы

рисунок

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

На основе данного материала был разработан этот софт


            Из кода файла MK_Prog_Procedure.pbi была создана динамическая библиотека подпрограмм -  "ComProg_PIC.dll". Это позволит его использовать в других средах разработки приложений. Почти у всех процедур сохранены оригинальные имена и назначения аргументов. Исключение составляет процедура ComProg_Init(), которая в этом случае не загружает данные из внешнего файла, а лишь копирует их из аргументов в переменные. В качестве примера использования библиотеки возьмём прежде рассмотренную программу, читающую информацию из памяти данных МК. Её исходные код код находится в файле MK_ReadData_DLL.pb. В начале программы при помощи функции OpenLibrary() подключается библиотека ComProg_PIC.dll, которой присваивается условный идентификатор 1. Он будет использоваться в дальнейшей работе с библиотекой. Далее открывается файл Preferences.ini и из него загружаются данные об инверсии сигналов и имени COM порта. После чего полученная из файла информация посылается в библиотеку с  помощью CallFunction(). Для этого вызывается функция ComProg_Init динамической библиотеки, которая как отмечалось ранее, копирует информацию об инверсии сигналов из аргументов во внутренние переменные библиотеки.  Остальная часть кода отличается от MK_ReadData.pb только тем, что функции вызываются не непосредственно, а при помощи CallFunction(), первый аргумент которой является условным идентификатором библиотеки, который был задан в OpenLibrary(). Второй аргумент определяет имя функции, а остальные передают информацию вызываемой функции.

Скачать файлы



Статьи                Главная
Сайт создан в системе uCoz