Код:
'###############################################################################
'
'
'        Библиотека обработки приема данных с кодированием Manchester
'
'        В библиотеке задействованы ресурсы MK:
'        * Таймер T0 (для подсчета длительности импульсов мanchester сигнала)
'        * Линия внешнего прерывания Int0 (вход сигнала)
'
'        Ресурсы контроля и управления:
'        * Transmit - бит флаг активности режима передачи пакета (1=идет передача)
'        * Man_in_line - порт приема должен быть порт INT0 (Man_in_line Alias Pin_x.x)
'        * Man_out_line - порт отправки (Man_out_line Alias Port_х.х)
'        * Rcvdata_check (возвращает количество принятых байт) - функция проверки наличии данных
'        * Transmit_start (количество отправляемых байт) - программа отправки данных из буффера Manbuffer ()
'        * Receive_start - программа инициализации и старта приема данных, по приему пакета останавливается.
'
'
'                          Programmed By Yuriy.pv
'                          
'
'###############################################################################


'Const $crystal = 8000000                                   'Частота МК
Const Man_speed = 1000                                      '800-4000 бит\сек - частота Manchester cигнала
Const Man_period_len = 125                                  '$crystal / 64 / MAN_SPEED - длит периода MANCHESTER сигнала (в тиках таймера)
Const Period_1_2 = 194                                      'Period 1/2 = 256-(Man_period_len/2)
Const Period_2_3 = 83                                       'Period 2/3 = Man_period_len*2/3
Const Period_3_4 = 163                                      'Period 3/4 = 256-(Man_period_len*3/4)

Const Man_pilot_len = 1                                     '1-16 бит. Длина пилотного сигнала
Const Man_buf_length = 2                                    '1-255 байта, размер буфера данных
Const Man_identifier_length = 2                             '1-16 байта, размер идентификатора пакета
Dim Man_identifier As String * Man_identifier_length
Dim Manidentifier(man_identifier_length) As Byte At Man_identifier Overlay       'идентификационный заголовок сообщения

    Man_identifier = "sh"                                   '1-16 латинских символов должно = Man_identifier_length. строковый - идентификатор пакета

Dim Manbuffer(man_buf_length) As Byte                       'буфер для накопления принимаемых Manchester данных
Dim Checksumm_byte As Byte                                  'байт подсчета CRC
Dim Bit_counter As Byte                                     'счетчик количества принятых бит
Dim Byte_counter As Byte                                    'счетчик принимаемых байтов
Dim Byte_in_out As Byte                                     'накопитель принимаемого \ контейнер передаваемого - байта
Dim Data_length As Byte                                     'длина блока данных в принимаемой\передаваемой серии (может быть <= MAN_BUF_LENGTH)


Dim Manflags_temp As Byte
Dim Manflags As Byte                                        'байт флагов
    Data_enbl Alias Manflags.0                              'флаг наличия в буфере принятых данных
    Tim0_ovf Alias Manflags.1                               'флаг наличия переполнения Т0
    Flag_pilot Alias Manflags.2                             'флаг окончания пилотного сигнала
    Header_rcv Alias Manflags.3                             'флаг приема заголовка
    Line_inv Alias Manflags.4                               'флаг необходимости инверсии сигнала в линии
    Transmit_stop Alias Manflags.5                          'флаг завершения передачи
    Bit_part_num Alias Manflags.6                           'флаг младшей\старшей половины бита при передаче
    Transmit Alias Manflags.7                               'флаг активности режима передачи пакета

Dim Timer_val As Byte                                       'значение таймера
Dim Temp_lib As Byte
'Dim Byte_ As Byte

'######################### Функции и подпрограммы ##############################
Declare Sub Init_
Declare Sub Receive_start
Declare Sub Receive_stop
Declare Sub Checksumm(byval Data_ As Byte)
Declare Sub Transmit_start(byval Count As Byte)
Declare Function Rcvdata_check As Byte

Config Pind.2 = Input : Man_in_line Alias Pind.2            'порт приема (должен быть порт INT0)
Config Portd.3 = Output : Man_out_line Alias Portd.3


'###########################  Главный цикл  ####################################
 Dim Temp As Byte
 Dim Tempw As Word

 Print "Test Manchester"
 Call Init_
 Call Receive_start
 Do
   Tempw = Rcvdata_check()
   If Tempw > 0 Then
     ' Set Led
      For Temp = 1 To Tempw
        Print "Rcvdata_check() = 1    data out=" ; Manbuffer(temp)
      Next
     ' Reset Led
      Call Receive_start
   End If


 Loop

'###############################################################################

 Sub Init_                                                  'Инициализация
   Disable Interrupts
   Config Timer0 = Timer , Prescale = 64                    'предделитель на 64 (частота счета 8000000 / 64 = 125000 Hz)
   On Timer0 Timer_ovf_vector:                              'вектор прерывания при переполнении
   Enable Timer0
   Config Int0 = Change                                     'прерывание по любому изменению уровня INT0
   On Int0 Int0_vector:                                     'вектор прерывания INT0
   Enable Interrupts
 End Sub


 Sub Receive_start                                          'Инициализация и старт приема данных
   Transmit = 0
   Data_enbl = 0                                            'очистить флаг наличия данных
   Tim0_ovf = 0                                             'и флаг переполнения
   Header_rcv = 1                                           'включить режим приема заголовка
   Byte_counter = 0                                         'начать прием с начала
   Byte_in_out = 0                                          'очистить байт приемник
   Start Timer0
   Enable Timer0
   Gifr.6 = 1                                               'сбросить возможно проскочившее прерывание
   Enable Int0
 End Sub


 Sub Receive_stop                                           'Останов приема данных
   Stop Timer0                                              'выключить прерывание при переполнении Т0
   Disable Int0                                             'выключить внешнее прерывание от INT0
 End Sub


 Function Rcvdata_check                                     'Проверка наличия Manchester данных в буфере
   If Data_enbl = 1 Then                                    'проверка наличия принятых данных если есть,
      Data_enbl = 0                                         'очистить флаг наличия данных
      Rcvdata_check = Data_length                           'при наличии данных - возвращаем количество принятых байт
   Else
      Rcvdata_check = 0
   End If
 End Function


 Sub Transmit_start(byval Count As Byte)
    Call Receive_stop()
    Checksumm_byte = 0
    Call Checksumm(count)                                   'подсчет контрольной суммы пакета для передачи
    For Temp_lib = 1 To Count
       Call Checksumm(manbuffer(temp_lib))                  'подсчет контрольки пакета
    Next
    Byte_in_out = 128                                       'для передачи пилот сигнала
    Byte_counter = 0                                        'до 0 - передача пилота, а от 0 до sizeof(MAN_IDENTIFIER)  - передача идентификатора
    Data_length = Count                                     'передать столько байт из буфера
    Flag_pilot = 0
    Bit_part_num = 0 : Transmit_stop = 0                    'сбросить флаги
    Transmit = 1 : Header_rcv = 1                           'включить режим передачи заголовка
    Start Timer0                                            'включить "прерывание при переполнении Т0"
 End Sub


  Sub Checksumm(byval Data_ As Byte)
 'CheckSummByte - глобальная переменная контрольной суммы
 'в начале обмена необходимо обнулить CheckSummByte
   Local Temp As Byte
   Local I As Byte

   For I = 1 To 7

     Temp = Data_
     Temp = Temp Xor Checksumm_byte

     If Temp.0 = 1 Then
       Checksumm_byte = Checksumm_byte Xor 24
       Temp = 128
     Else
       Temp = 0
     End If

     Shift Checksumm_byte , Right
     Checksumm_byte = Checksumm_byte Or Temp
     Shift Data_ , Right

   Next

 End Sub




 Timer_ovf_vector:                                          'Обработка прерывания при переполнении TIMER0
   'Byte_ = Byte_in_out

  'Если включена передача
   If Transmit = 1 Then

      Timer0 = Period_1_2

     'начало передачи первой чсти бита
      If Bit_part_num = 0 Then
         If Byte_in_out.7 = 1 Then
            Man_out_line = 0
         Else
            Man_out_line = 1
         End If

         If Transmit_stop = 1 Then
            Stop Timer0
            Transmit = 0
         End If
      Else
        'Начало передачи второй части бита
         If Byte_in_out.7 = 1 Then
            Man_out_line = 1
         Else
            Man_out_line = 0
         End If
         Shift Byte_in_out , Left                           'сдвигаем биты в передаваемом байте
         Incr Bit_counter

        'Если это пилот или заголовок
         If Header_rcv = 1 Then
           'Если это пилот
            If Byte_counter < Man_pilot_len And Flag_pilot = 0 Then
               Byte_in_out = 128                            'для передачи бита 1
               Incr Byte_counter
               If Byte_counter = Man_pilot_len Then
                  Byte_in_out = Manidentifier(1)
                  Bit_counter = 0                           'счетчик переданных бит
                  Flag_pilot = 1
                  Byte_counter = 1
               End If
           'Если это заголовок
            Elseif Bit_counter = 8 Then                     'если переданы все биты байта

               Bit_counter = 0

               If Byte_counter = Man_identifier_length Then 'если ноль - значит конец строки идентификатора
                  Header_rcv = 0
                  Byte_counter = 0
                  Byte_in_out = Data_length
               Else
                  Incr Byte_counter
                  Byte_in_out = Manidentifier(byte_counter)
               End If

            End If

        'Если это передача блока данных
         Elseif Bit_counter = 8 Then                        'если переданы все биты байта
            Bit_counter = 0
            If Byte_counter < Data_length Then              'передаем основной блок данных
               Incr Byte_counter
               Byte_in_out = Manbuffer(byte_counter)
            Elseif Byte_counter = Data_length Then          'передаем контрольную сумму
               Byte_in_out = Checksumm_byte
               Incr Byte_counter
            Else                                            'завершение передачи
               Transmit_stop = 1                            'установить флаг завершения передачи
               Byte_in_out = 128                            '128                                  'для сброса линии в 0
            End If
         End If
      End If

      Toggle Bit_part_num                                   'меняем состояние флага младшей\старшей половины бита

   Else

     'Если включен прием
      If Gicr.6 = 1 Then                                    'если ожидали внеш прерывания INT0 то
         Tim0_ovf = 1                                       'отметить переполнение
      Else                                                  'если внеш прерывания INT0 были выключены то
         Gifr.6 = 1                                         'сбросить возможно проскочившее прерывание
         Enable Int0
      End If
   End If

   'Byte_in_out = Byte_
 Return



 Int0_vector:                                               'Обработка внешнего прерывания INT0
   Byte_in_out = Byte_in_out

   Timer_val = Timer0
   Timer0 = Period_3_4                                      'счетчик таймера настроить на 3/4 длины периода MANCHESTER бита данных
   Disable Int0
   Gifr.6 = 1                                               'сбросить возможно проскочившее прерывание

  'задвигаем принятый бит
   Shift Byte_in_out , Left                                 'сдвигаем байт перед записью бита
   If Man_in_line <> 0 Then Byte_in_out.0 = 1

  'проверка на корректность длительности замера (измеряли начиная с 1/4 бита до середина бита (момент перепада)
   If Timer_val > Period_2_3 Or Tim0_ovf = 1 Then
Init:
      Tim0_ovf = 0                                          'сбросить флаг переполнения
      Header_rcv = 1                                        'ожидать прием заголовка
      Byte_counter = 0                                      'начать прием с начала
      Byte_in_out = 0                                       'очистить байт приемник
   End If

  'крутимся тут до окончания приема хедера
   If Header_rcv = 1 Then

     If Byte_counter = 0 Then                               'крутимся тут пока не совпадет первый байт хедера

       If Byte_in_out = Manidentifier(1) Then
          Line_inv = 0                                      'сбросить флаг инверсии
          Bit_counter = 0                                   'готовимся к приему следующих байтов хедера
          Incr Byte_counter
          Incr Byte_counter
       End If

       Toggle Byte_in_out
       If Byte_in_out = Manidentifier(1) Then
          Line_inv = 1                                      'инверсное совпадение
          Bit_counter = 0                                   'готовимся к приему следующих байтов хедера
          Incr Byte_counter
          Incr Byte_counter
       End If
       Toggle Byte_in_out

       Goto Return_
     End If

    'принимаем остальные байты хедера и байт длины пакета
     Incr Bit_counter
     If Bit_counter < 8 Then Goto Return_                   'ждем заполнения байта
     If Line_inv = 1 Then Toggle Byte_in_out                'если сигнал инверсный

     If Byte_counter <= Man_identifier_length Then          'если хедер еще не закончен
       If Byte_in_out <> Manidentifier(byte_counter) Then Goto Init       'проверяем идентичность хедера
       Bit_counter = 0                                      '
       Incr Byte_counter                                    'ожидаем следующий байт хедера
       Goto Return_
     End If

    'хедер закончился, значит принят байт длины блока данных
     If Byte_in_out > Man_buf_length Then Goto Init         'размер блока данных превышает допустимый - рестарт
     Data_length = Byte_in_out                              'запомним длину пакета

     Header_rcv = 0                                         'заголовок принят переходим к приему основного файла
     Bit_counter = 0
     Byte_counter = 0
     Goto Return_

   End If

  'принимаем основной блок данных
   Incr Bit_counter
   If Bit_counter < 8 Then Goto Return_                     'ждем накопления байта
   Bit_counter = 0

   If Line_inv = 1 Then Toggle Byte_in_out                  'необходима ли инверсия

   If Byte_counter < Data_length Then                       'если это еще байты пакета
     Incr Byte_counter
     Manbuffer(byte_counter) = Byte_in_out                  'сохраняем принятый байт
   Else                                                     'если пакет закончен
     Checksumm_byte = 0                                     'очистить байт контрольной суммы
     Call Checksumm(data_length)                            'подсчет контрольки длинны пакета
     For Temp_lib = 1 To Data_length
        Call Checksumm(manbuffer(temp_lib))                 'подсчет контрольки пакета
     Next
     If Checksumm_byte <> Byte_in_out Then Goto Init        'если контролька не верна (не 0) - рестарт                                                            'Контролька правильная
     Data_enbl = 1                                          'установить флаг наличия данных
     Call Receive_stop()                                    'тормозим дальнейший прием
   End If

   Return_:
  ' Byte_in_out = Byte_
 Return

Отредактировано Yuriy.pv (2017-01-24 20:34:54)