Текст главного модуля управляющей программы высокого уровня на языке Delphi приведен ниже.
В начале своей работы программа пытается последовательно открыть первые четыре COM-порта компьютера. Через каждый порт, дескриптор которого удалось получить, устройству посылается запрос на передачу строки подтверждения “ATmega8”. Если строка была получена, то программа продолжает свое продолжение. В противном случае приложение закрывается.
Когда связь успешно установлена, появляется окно основной формы, вид которой изображен выше. Пользователю доступно два действия: стирание и программирование FLAS-памяти. В последнем случае данные из HEX-файла переносятся в буфер для записи и по страницам передаются в микроконтроллер. После завершения записи производится верификация памяти программ. При этом данные считываются из устройства в буфер для чтения. Результатом удачной операции программирования будет являться равенство содержимого обоих буферов.
Размер файла не должен превышать 4096–128=3968 слов, иначе во время записи произойдет повреждение загрузчика. По этой же причине стиранию подлежат только первые 124 из 128 страниц памяти программ. Перед записью HEX-файла ведется проверки диапазона адресов и контрольной суммы каждой из строк. Файл должен быть 8-ричным файлом формата Intel Hex и, кроме этого, не должен содержать команд смещения адресов. Присутствие, например строки :020000020100FB (смещение начального адреса записи на 0x0100 б) приведет к ошибки.
unit MainUnit; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Buttons, ComCtrls, ExtCtrls, AppEvnts, CheckLst; type TMainForm = class(TForm) PbProgressBar: TProgressBar; LbInfo: TLabel; CbLowFuse: TCheckListBox; CbHighFuse: TCheckListBox; CbLockBits: TCheckListBox; BtFilePath: TButton; EdFilePath: TEdit; BtProgramFlash: TBitBtn; BtEraseFlash: TBitBtn; DlOpenDialog: TOpenDialog; function StrToHex(const Sim: char): byte; function CheckHexFile: boolean; function PrepareFlashBuffer: boolean; function ProgramFlash: boolean; procedure ReadFuseBits; function ReadFlash: boolean; function EraseFlash: boolean; procedure OnFormCreate(Sender: TObject); procedure OnFormDestroy(Sender: TObject); procedure BtFilePathClick(Sender: TObject); procedure BtProgramFlashClick(Sender: TObject); procedure BtEraseFlashClick(Sender: TObject); end; var MainForm: TMainForm; PortHandle: THandle; //дескриптор COM-порта FlashWriteBuffer: array of word;//массивы данных для записи во FLASH-памяти FlashReadBuffer: array of word;//массивы прочитанных из FLASH-памяти данных const FLASH_SIZE = 4096;//число слов FLASH-памяти программ (4096 слова для ATmega8) PAGE_SIZE = 32;//число слов в странице (32 слова для ATmega8) implementation {$R *.dfm} // Функция открытия COM-порта. В качестве параметра принимает номер порта //ComNumber в интервале 0…9. В случае удачного завершения возвращает 0. function OpenPort(const ComNumber: cardinal): boolean; var ComName:string; begin ComName:=Format('\\.\COM%-d',[ComNumber]); // API-функция CreateFile производит открытие COM-порта по имени, в режиме //чтения/записи. Установка флага FILE_FLAG_OVERLAPPED позволяет использовать //асинхронные операции чтения/записи. При удачном завершении функция //возвращает дескриптор устройства; в случае ошибки - INVALID_HANDLE_VALUE. PortHandle:=CreateFile(PChar(ComName),GENERIC_READ or GENERIC_WRITE,0, nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL or FILE_FLAG_OVERLAPPED,0); Result:=PortHandle<>INVALID_HANDLE_VALUE; end; // Процедура закрытия COM-порта. procedure ClosePort; begin // API-функция CloseHandle закрывает дескриптор, полученный вызовом //CreateFile. CloseHandle(PortHandle); end; // Процедура задания настроек COM-порта. В качестве параметров принимает: //скорость обмена BaudRate, тип контроля четность Parity, количество стоп-бит //StopBits и разрядность данных ByteSize. // Скорость обмена BaudRate в бит/с задается одной из констант: //CBR_110 = 110, CBR_300 = 300, CBR_600 = 600, CBR_1200 = 1200, //CBR_2400 = 2400, CBR_4800 = 4800, CBR_4800 = 9600, CBR_4800 = 14400, //CBR_19200 = 19200, CBR_19200 = 19200, CBR_38400 = 38400, CBR_56000 = 56000, //CBR_57600 = 57600, CBR_115200 = 115200. // Контроль четности Parity задается одной из констант: //NOPARITY = 0 – контроль четности отсутствует(бит четности отсутствует), //ODDPARITY = 1 – проверка на нечетность(бит четности дополняет сумму // единиц в слове данных до нечетного числа), //EVENPARITY = 2 – проверка на четность(бит четности дополняет сумму // единиц в слове данных до четного числа), //MARKPARITY = 3 – проверка бита четности на 1, //SPACEPARITY = 4 – проверка бита четности на 0. // Количество стоп-бит StopBits задается одной из констант: //ONESTOPBIT = 0 – 1 стоп-бит, //ONE5STOPBITS = 1 – 1.5 стоп-бит, //TWOSTOPBITS = 2 – 2 стоп-бит(только для 6…8-битовых данных). // Разрядность данных ByteSize может быть 5…8 бит. procedure SetComProperty (const BaudRate,Parity,StopBits,ByteSize: cardinal); var DCB:TDCB; begin // Основные настройки COM-порта содержит структура DCB. FillChar(DCB,SizeOf(DCB),0); DCB.DCBLength:=SizeOf(DCB); DCB.Flags:=1; DCB.BaudRate:=BaudRate; DCB.Parity:=Parity; DCB.StopBits:=StopBits; DCB.ByteSize:=ByteSize; // API-функция SetCommState переписывает структуру DCB порта. SetCommState(PortHandle,DCB); end; // Функция чтения буфера данных из COM-порта. В качестве параметров //принимает: указатель на буфер памяти Buffer и размер буфера BufSize. В //случае удачного завершения функция возвращает 0. function ReadBuffer(var Buffer:Pointer;const BufSize:cardinal): boolean; var BytesRead:cardinal; ReadOL:TOverlapped; ReadDone:cardinal; begin FillChar(ReadOL,SizeOf(ReadOL),0); // API-функция Функция CreateEvent создает событие ReadOL.hEvent (дескриптор //события ReadOL.hEvent размещен в структуре асинхронного доступа ReadOL типа //TOverlapped), которое будет переведено в сигнальное состояние после //завершения операции асинхронного чтения. ReadOL.hEvent:=CreateEvent(nil,true,true,nil); try // API-функция Функция ReadFile производит чтение данных из COM-порта. В //случае удачного завершения функция возвращает 0. В данном случае чтение //происходит в асинхронном режиме. После вызова ReadFile поток не блокируется //до окончания операции, а продолжает свое выполнение. О завершении операции //чтения можно судить по состоянию объекта ReadOL.hEvent, который должен //перейти в сигнальное состояние. ReadFile(PortHandle,Buffer^,BufSize,BytesRead,@ReadOL); // API-функция Функция WaitForSingleObject ожидает перевода в сигнальное //состояние объекта синхронизации определенный период времени. В нашем случае //объектом служит событие ReadOL.hEvent, интервал времени 100 мс. При //успешном завершении (если объект перешел в сигнальное состояние раньше, //чем истек период ожидания) функция возвратит код WAIT_OBJECT_0. ReadDone:=WaitForSingleObject(ReadOL.hEvent,100); finally Result:= ReadDone = WAIT_OBJECT_0; // API-функция Функция CloseHandle закрывает дескриптор события //ReadOL.hEvent, полученный с помощью CreateEvent. CloseHandle(ReadOL.hEvent); end; end; // Функция записи буфера данных в COM-порт. В качестве параметров //принимает: указатель на буфер памяти Buffer и размер буфера BufSize. В //случае удачного завершения функция возвращает 0. function WriteBuffer (var Buffer:Pointer; const BufSize:cardinal): boolean; var BytesWritten:cardinal; WriteOL:TOverlapped; WriteDone:cardinal; begin FillChar(WriteOL,SizeOf(WriteOL),0); // API-функция Функция CreateEvent создает событие WriteOL.hEvent (дескриптор //события WriteOL.hEvent размещен в структуре асинхронного доступа WriteOL типа //TOverlapped), которое будет переведено в сигнальное состояние после //завершения операции асинхронной записи. WriteOL.hEvent:=CreateEvent(nil,true,true,nil); try // API-функция Функция WriteFile производит запись данных в COM-порт. В //случае удачного завершения функция возвращает 0. В данном случае запись //происходит в асинхронном режиме. После вызова WriteFile поток не //блокируется до окончания операции, а продолжает свое выполнение. //О завершении операции чтения можно судить по состоянию объекта. WriteFile(PortHandle,Buffer^,BufSize,BytesWritten,@WriteOL); // API-функция Функция WaitForSingleObject ожидает перевода в сигнальное //состояние объекта синхронизации определенный период времени. В нашем случае //объектом служит событие WriteOL.hEvent, интервал времени 100 мс. При //успешном завершении (если объект перешел в сигнальное состояние раньше, //чем истек период ожидания) функция возвратит код WAIT_OBJECT_0. WriteDone:=WaitForSingleObject(WriteOL.hEvent,100); finally Result:= WriteDone = WAIT_OBJECT_0; // API-функция Функция CloseHandle закрывает дескриптор события //WriteOL.hEvent, полученный с помощью CreateEvent. CloseHandle(WriteOL.hEvent); end; end; // Функция чтения байта данных из COM-порта. Возвращает прочитанный байт. function ReadByte: byte; var Ptr:Pointer; begin Ptr:=@Result; ReadBuffer(Ptr,1); end; // Процедура записи байта данных в COM-порт. В качестве параметров принимает //байт данных для записи. procedure WriteByte(const TX:byte); var Ptr:Pointer; begin Ptr:=@TX; WriteBuffer(Ptr,1); end; // Функция преобразования символов ACSII (“0”…“9”, “A”…“F”) в число. В //качестве параметров принимает символ, подлежащий преобразованию Sim. //Возвращает преобразованное число. function TMainForm.StrToHex(const Sim: char): byte; begin if ((Byte(Sim)>=$30) and (Byte(Sim)<=$39)) then Result:= Byte(Sim)-$30 else Result:= Byte(Sim)-$37; end; // Функция проверки HEX-файла на ошибки. В случае удачного завершения //возвращает 0. function TMainForm.CheckHexFile: boolean; var F:TStringList; Str: string; Size,Sum: Byte; I,J: integer; begin Result:= false; F:= TStringList.Create; F.LoadFromFile(EdFilePath.Text); Str:= F.Strings[F.Count-1]; // Если 4 последних символа последней строки отличны от “01FF” (признак //конца файла), то HEX-файл поврежден. if Copy(Str,Length(Str)-3,4)<>'01FF' then begin F.Free; Exit; end; // Если в начале хотя бы одной из строк отсутствует символ “:” (признак //начала строки), то HEX-файл поврежден. for I:= 0 to F.Count-1 do begin Str:= F.Strings[I]; if Str[1]<>':' then begin F.Free; Exit; end; Size:= 16*StrToHex(Str[2])+StrToHex(Str[3])+4; Sum:=0; // Если в хотя бы одной из строк не сходится контрольная сумма (сумма всех //байтов в строке без учета переполнения должна равняться 0), то HEX-файл //поврежден. for J:= 0 to Size do Sum:= Byte(Sum+16*StrToHex(Str[2*J+2])+ StrToHex(Str[2*J+3])); if Sum <> 0 then begin F.Free; Exit; end; end; F.Free; Result:=true; end; // Функция подготовки данных для записи. В случае удачного завершения //возвращает 0. function TMainForm.PrepareFlashBuffer: boolean; var F: TStringList; Str: string; W,Size,MaxFlashSize,Offset: word; I,J,K: integer; begin Result:= false; F:=TStringList.Create; F.LoadFromFile(EdFilePath.Text); Str:=F.Strings[F.Count-2]; Size:=0; for I:=0 to 3 do Size:= 16*Size+StrToHex(Str[4+I]); MaxFlashSize:= (Size+16*StrToHex(Str[2])+StrToHex(Str[3])) div 2; // Если максимальный размер HEX-файла превышает размер доступной памяти //программ (загрузчик boot-loader размещен в Boot Loader Section размером 128 //слов), то запись не возможна. if MaxFlashSize > (FLASH_SIZE-128) then begin F.Free; Exit; end; // Выделение под буфер памяти в MaxFlashSize 16-разрядных слов, чистка и //заполнение его данными из HEX-файла. SetLength(FlashWriteBuffer,MaxFlashSize); SetLength(FlashReadBuffer,MaxFlashSize); for I:=0 to MaxFlashSize-1 do FlashWriteBuffer[I]:= $FFFF; for I:=0 to F.Count-2 do begin Str:= F.Strings[I]; if Copy(Str,8,2)<>'00' then Continue; Size:= (16*StrToHex(Str[2])+StrToHex(Str[3])) div 2; Offset:= 0; for J:=0 to 3 do Offset:=16*Offset+StrToHex(Str[4+J]); for J:=0 to Size-1 do begin W:=0; for K:=0 to 3 do W:=16*W+StrToHex(Str[4*J+K+10]); FlashWriteBuffer[Offset div 2 +J]:= W; end; end; F.Free; Result:= true; end; // Процедура чтения байтов конфигурации и содержимого ячеек защиты. procedure TMainForm.ReadFuseBits; var LowFuseBit,HighFuseBit,LockBits: byte; I: integer; begin // Передача команды чтения (символ “F”). WriteByte(Byte('F')); // Чтение младшего байта конфигурации. LowFuseBit:=ReadByte; // Чтение ячеек защиты. LockBits:=ReadByte; // Чтение старшего байта конфигурации. HighFuseBit:=ReadByte; for I:=0 to 7 do CbLowFuse.Checked[I]:=((LowFuseBit shl I) and $80)<>$80; for I:=0 to 7 do CbHighFuse.Checked[I]:=((HighFuseBit shl I) and $80)<>$80; LockBits:=LockBits shl 2; for I:=0 to 3 do CbLockBits.Checked[I]:=((LockBits shl I) and $80)<>$80; end; // Функция программирования FLASH-памяти. В случае удачного завершения //возвращает 0. function TMainForm.ProgramFlash: boolean; var Adress,Data,Page: word; I,J: integer; begin Result:= false; PbProgressBar.Visible:= true; PbProgressBar.Position:=0; PbProgressBar.Min:=0; PbProgressBar.Max:=Length(FlashWriteBuffer); Page:= Length(FlashWriteBuffer) div PAGE_SIZE + 1; Adress:=0; // Программирование FLASH-памяти из буфера FlashWriteBuffer. Сначала //передается команда программирования (символ “P”). Затем передаются номер //страницы и 32 слова для записи. for I:=0 to Page-1 do begin WriteByte(Byte('P')); WriteByte(Byte(Adress and $00FF)); WriteByte(Byte((Adress and $FF00) shr 8)); for J:=0 to PAGE_SIZE-1 do begin if (PAGE_SIZE*I+J) >= Length(FlashReadBuffer) then Data:= $FFFF else Data:= FlashWriteBuffer[PAGE_SIZE*I+J]; WriteByte(Byte((Data and $FF00) shr 8)); WriteByte(Byte(Data and $00FF)); // Небольшая задержка времени и принудительный запуск цикла обработки ообщений. Sleep(10); Application.ProcessMessages; end; // Если после завершения операции микроконтроллер не выдал символ //подтверждения “!”, то произошла ошибка записи. if ReadByte <> Byte('!') then begin PbProgressBar.Visible:= false; Exit; end; Adress:= Adress + 2*PAGE_SIZE; PbProgressBar.Position:= PbProgressBar.Position+PAGE_SIZE; end; PbProgressBar.Visible:= false; Result:= true; end; // Функция верификации данных FLASH-памяти. В случае удачного завершения //возвращает 0. function TMainForm.ReadFlash: boolean; var Adress,Data,Page: word; I,J: integer; begin Result:= false; PbProgressBar.Visible:= true; PbProgressBar.Position:=0; PbProgressBar.Min:=0; PbProgressBar.Max:=Length(FlashReadBuffer); Page:= Length(FlashReadBuffer) div PAGE_SIZE + 1; Adress:=0; // Считывание FLASH-памяти в буфер FlashReadBuffer. Сначала передается //команда верификации (символ “R”). Затем передается номер страницы и //считываются 32 слова. for I:=0 to Page-1 do begin WriteByte(Byte('R')); WriteByte(Byte(Adress and $00FF)); WriteByte(Byte((Adress and $FF00) shr 8)); for J:=0 to PAGE_SIZE-1 do begin Data:=ReadByte; Data:=(Data shl 8)+ReadByte; if (PAGE_SIZE*I+J) < Length(FlashReadBuffer) then FlashReadBuffer[PAGE_SIZE*I+J]:= Data; Application.ProcessMessages; end; // Если после завершения операции микроконтроллер не выдал символ //подтверждения “!”, то произошла ошибка чтения. if ReadByte <> Byte('!') then begin PbProgressBar.Visible:= false; Exit; end; Adress:= Adress + 2*PAGE_SIZE; PbProgressBar.Position:= PbProgressBar.Position+PAGE_SIZE; end; PbProgressBar.Visible:= false; Result:= true; end; // Функция стирания данных FLASH-памяти. В случае удачного завершения //возвращает 0. function TMainForm.EraseFlash: boolean; var Adress,Page: word; I: integer; begin Result:= false; PbProgressBar.Visible:=true; PbProgressBar.Position:=0; PbProgressBar.Min:=0; PbProgressBar.Max:=FLASH_SIZE-128; Page:=(FLASH_SIZE-128) div PAGE_SIZE; Adress:=0; // Стирание FLASH-памяти программ. Сначала передается команда стирания //(символ “E”). Затем передается номер страницы. for I:=0 to Page-1 do begin WriteByte(Byte('E')); WriteByte(Byte(Adress and $00FF)); WriteByte(Byte((Adress and $FF00) shr 8)); // Небольшая задержка времени и принудительный запуск цикла обработки //сообщений. Sleep(10); Application.ProcessMessages; // Если после завершения операции микроконтроллер не выдал символ //подтверждения “!”, то произошла ошибка стирания. if ReadByte <> Byte('!') then begin PbProgressBar.Visible:= false; Exit; end; Adress:= Adress + 2*PAGE_SIZE; PbProgressBar.Position:= PbProgressBar.Position+PAGE_SIZE; end; PbProgressBar.Visible:= false; Result:= true; end; // Обработчик события создания формы. procedure TMainForm.OnFormCreate(Sender: TObject); var Str: string; Found: boolean; I: integer; begin Found:= false; SetLength(Str,7); // Попытка последовательно открыть первые 4 COM-порта. for I:=1 to 4 do begin if not OpenPort(I) then Continue; // Если порт успешно открыт, то устанавливаем параметры связи (в данном //случае 115200, 8-N-2). SetComProperty(CBR_115200,NOPARITY,TWOSTOPBITS,8); // Посылка микроконтроллеру запроса (символ “D”) выдать информацию о //присутствии на линии. WriteByte(Byte('D')); // Если не получена строка из семи символов, то устройство не найдено. if not ReadBuffer(Pointer(Str),7) then begin ClosePort; Continue; end; // Если была получена строка подтверждения “ATmega8”, то устройство найдено //и можно продолжать дальнейшую работу. Found:= Str = 'ATmega8'; if Found then Break else ClosePort; end; // Если микроконтроллер не обнаружен, то приложение прекращает свою работу. if not Found then begin ShowMessage('Не удалось связаться с устройством!'); Application.Terminate; end; LbInfo.Caption:= 'ATmega8 подключен к ' + Format('COM-%d.',[I]); ReadFuseBits; end; // Обработчик события уничтожения формы. procedure TMainForm.OnFormDestroy(Sender: TObject); begin // Посылка микроконтроллеру команды завершения связи (символ “O”). WriteByte(Byte('O')); if PortHandle <> INVALID_HANDLE_VALUE then ClosePort; end; // Обработчик нажатия кнопки выбора пути к HEX-файлу. procedure TMainForm.BtFilePathClick(Sender: TObject); begin DlOpenDialog.Execute; EdFilePath.Text:= DlOpenDialog.FileName; end; // Обработчик нажатия кнопки программирования FLASH-памяти. procedure TMainForm.BtProgramFlashClick(Sender: TObject); var Str: string; I: integer; Begin // Если выбранный файл имеет расширение отличное от HEX, то //программирование не возможно. Str:= Copy(EdFilePath.Text,Length(EdFilePath.Text)-3,4); if (Str <> '.hex') and (Str <> '.HEX') then begin ShowMessage('Файл должен иметь расширение .hex !'); Exit; end; // Если путь, указанный к файлу не верный, то программирование не возможно. if not FileExists(EdFilePath.Text) then begin ShowMessage('Файл не найден !'); Exit; end; // Если в файле содержаться ошибки, то программирование не возможно. if not CheckHexFile then begin ShowMessage('Файл поврежден !'); Exit; end; // Если при подготовки данных оказалось, что размер HEX-файла превышает //размер доступной памяти то программирование не возможно. if not PrepareFlashBuffer then begin ShowMessage('Слишком большой размер файла !'); Exit; end; BtProgramFlash.Enabled:= false; BtEraseFlash.Enabled:= false; LbInfo.Caption:= 'Программирование...'; // Запись данных из буфера FlashWriteBuffer. if not ProgramFlash then begin LbInfo.Caption:= 'Ошибка программирования !'; BtProgramFlash.Enabled:= true; BtEraseFlash.Enabled:= true; Exit; end; // Чтение данных в буфер FlashReadBuffer. LbInfo.Caption:= 'Программирование... Верификация...'; if not ReadFlash then begin LbInfo.Caption:= 'Ошибка чтения !'; BtProgramFlash.Enabled:= true; BtEraseFlash.Enabled:= true; Exit; end; // Сравнение записанных и считанных данных. for I:= 0 to Length(FlashWriteBuffer)-1 do begin if FlashReadBuffer[I] = FlashWriteBuffer[I] then Continue; ShowMessage(Format('Ошибка записи по адресу 0x%x : 0x%x вместо 0x%x !', [I,FlashReadBuffer[I],FlashWriteBuffer[I]])); LbInfo.Caption:= 'Ошибка верификации !'; BtProgramFlash.Enabled:= true; BtEraseFlash.Enabled:= true; Exit; end; LbInfo.Caption:= 'Программирование успешно завершено.'; BtProgramFlash.Enabled:= true; BtEraseFlash.Enabled:= true; end; // Обработчик нажатия кнопки стирания FLASH-памяти. procedure TMainForm.BtEraseFlashClick(Sender: TObject); begin BtProgramFlash.Enabled:= false; BtEraseFlash.Enabled:= false; LbInfo.Caption:= 'Стирание...'; if not EraseFlash then LbInfo.Caption:= 'Ошибка при стирании !' else LbInfo.Caption:= 'Стирание успешно завершено.'; BtProgramFlash.Enabled:= true; BtEraseFlash.Enabled:= true; end; end.
Скачать исходник проекта
Перейти к следующей части: Самоуничтожение программы
Комментарии (0) | Я собрал (0) | Подписаться
Для добавления Вашей сборки необходима регистрация