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

Программирование ATMEL в BASCOM.

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Программирование ATMEL в BASCOM. » Исходники » эксперименты с радиомодулем NRF24L01+


эксперименты с радиомодулем NRF24L01+

Сообщений 1 страница 4 из 4

1

Проводил эксперименты с NRF24L01.
Основа - ARDUINO UNO R3  +  LCD1602 Key Shild. 
Arduino uno 3
Шильд
Делаешь из них бутерброд. Как программировать  ардуинку из Bascom описывать не буду, googl в помощь. Очень удобно и недорого получилось. 

Модуль NRF повесил на свободные порты с помощью маленькой макетки с разъемами.
mosi - PB.5
miso - PB.6
sck  - PB.7
csn  - PB.3
ce   - PB.2
irq  - PB.1
  и еще светодиод PB.4 -<- Vcc 
Питание 3в имеется на ардуинке.

http://se.uploads.ru/t/OEaFn.png

Передатчик на ATTiny2313. . + DS18B20 повесил. Будет макет беспроводного датчика температуры. 

http://s7.uploads.ru/t/6Ri3V.png

Сначала я пошел по простому пути - нашел примеры в интернете и начал эксперименты. Ничего не получалось. До отчаянья.  :mad: 
Начал разбираться. Вплоть до того, что обмен по SPI написал ручками !!!  :tomato: 
Нужно было посмотреть что же пишется в регистры NRF-ки. Тут и пригодился экран и кнопки.
Теперь о работе программы: Сильно не пинайте, в Bascom пишу не часто, да и код в процессе эксперимента менялся.

После подачи питания в NRF-ку ничего не записывается.
Кнопка "Right" читает состояние нескольких регистров. Адреса и названия интересующих Вас регистров можно сменить в коде в разделе "Заполнение массива регистров чтения". 
Кнопки верх и вниз - просмотр прочитанного. Не текущее состояние, а то что было, когда нажали кнопку "Right".
Кнопка "Left" - настраивает NRF-ку на прием.  На экране появится "RX".

Если прием удался на экране появится температура. 

Весь описанный выше геморрой случился из-за того, что модуль не выставлял прерывание на выходе IRQ. Хотя Config.6 = 1.  То ли я их спалил (на обоих?) 
то ли Китайцы виноваты ?  (Покупал в "Чип-НН")
А в программах, которые я скачивал, реакция на прием как раз и строилась на состоянии этого контакта. Поэтому у меня ничего не работало.
В моей программе происходит постоянное чтение регистра STATUS и его анализ. 
Вот тут есть самое подробное описание этих модулей.
NRF24L01

Передатчик . Несколько коротких вспышек СД - это МК просыпается .... и засыпает.   Длинная вспышка - передача.

Код:
 
'*******************************************************************************
' ===== РАДИОПЕРЕДАТЧИК ТЕМПЕРАТУРЫ ============================================
'
'=== attiny2313a
'=== nRF24L01+
'=== DS18B20

$regfile = "attiny2313a.dat"
$crystal = 4000000
$hwstack = 40
$swstack = 16
$framesize = 32



'************************************************************************************************
' === ОБЪЯВЛЕНИЕ  ПОДПРОГРАММ  ================

Declare Sub Nrf__read(byval Nrf_read_adr As Byte , Byval Cnt_byte As Byte)       ' Чтение - ЗАПИСЬ
Declare Sub Nrf__write(byval Cnt_byte As Byte)



'************************************************************************************************
' === ОБЪЯВЛЕНИЕ  ПЕРЕМЕННЫХ  ==================================================

'/* Команды */

   Ncm_r_register Alias &H00                                ' + n Прочитать регистр n
   Ncm_w_register Alias &H20                                ' + n Записать регистр n
   Ncm_r_rx_payload Alias &H61                              ' Принять данные данные из верхнего слота очереди приёмника.
   Ncm_w_tx_payload Alias &HA0                              ' Записать в очередь передатчика данные для отправки
   Ncm_flush_tx Alias &HE1                                  ' Сбросить очередь передатчика
   Ncm_flush_rx Alias &HE2                                  ' Сбросить очередь приёмника
   Ncm_reuse_tx_pl Alias &HE3                               ' Использовать повторно последний переданный пакет
   Ncm_r_rx_pl_wid Alias &H60                               ' Прочитать размер данных принятого пакета в начале очереди приёмника.
   Ncm_w_ack_payload Alias &HA8                             ' + p Записать данные для отправки с пакетом подтверждения по каналу p.
   Ncm_w_tx_payload_noack Alias &HB0                        ' Записать в очередь передатчика данные, для отправки без подтверждения
   Ncm_nop Alias &HFF                                       ' Нет операции. Может быть использовано для чтения регистра статуса

'/* Регистры */

   Nrg_config Alias &H00                                    '  Регистр Настроек
   Nrg_en_aa Alias &H01                                     '  Выбор Автоподтверждения
   Nrg_en_rxaddr Alias &H02                                 '  Выбор Каналов Приёмника
   Nrg_setup_aw Alias &H03                                  '  Настройка Размера Адреса
   Nrg_setup_retr Alias &H04                                '  Настройка Повторной Отправки
   Nrg_rf_ch Alias &H05                                     '  Номер Радиоканала , На Котором Осуществляется Работа. От 0 До 125.
   Nrg_rf_setup Alias &H06                                  '  Настройка Радиоканала
   Nrg_status Alias &H07                                    '  Регистр Статуса.
   Nrg_observe_tx Alias &H08                                '  Количество Повторов Передачи И Потерянных Пакетов
   Nrg_rpd Alias &H09                                       '  Мощность Принимаемого Сигнала. Если Младший Бит = 1 , То Уровень Более -64dbm
   Nrg_rx_addr_p0 Alias &H0A                                '  3 -5 Байт(начиная С Младшего Байта). Адрес Канала 0 Приёмника.
   Nrg_rx_addr_p1 Alias &H0B                                '  3 -5 Байт(начиная С Младшего Байта). Адрес Канала 1 Приёмника.
   Nrg_rx_addr_p2 Alias &H0C                                '  Младший Байт Адреса Канала 2 Приёмника. Старшие Байты Из Rx_addr_p1
   Nrg_rx_addr_p3 Alias &H0D                                '  Младший Байт Адреса Канала 3 Приёмника. Старшие Байты Из Rx_addr_p1
   Nrg_rx_addr_p4 Alias &H0E                                '  Младший Байт Адреса Канала 4 Приёмника. Старшие Байты Из Rx_addr_p1
   Nrg_rx_addr_p5 Alias &H0F                                '  Младший Байт Адреса Канала 5 Приёмника. Старшие Байты Из Rx_addr_p1
   Nrg_tx_addr Alias &H10                                   '  3 -5 Байт(начиная С Младшего Байта). Адрес Удалённого Устройства Для Передачи
   Nrg_rx_pw_p0 Alias &H11                                  '  Размер Данных При Приёме По Каналу 0 : От 1 До 32. 0 - Канал Не Используется.
   Nrg_rx_pw_p1 Alias &H12                                  '  Размер Данных При Приёме По Каналу 1 : От 1 До 32. 0 - Канал Не Используется.
   Nrg_rx_pw_p2 Alias &H13                                  '  Размер Данных При Приёме По Каналу 2 : От 1 До 32. 0 - Канал Не Используется.
   Nrg_rx_pw_p3 Alias &H14                                  '  Размер Данных При Приёме По Каналу 3 : От 1 До 32. 0 - Канал Не Используется.
   Nrg_rx_pw_p4 Alias &H15                                  '  Размер Данных При Приёме По Каналу 4 : От 1 До 32. 0 - Канал Не Используется.
   Nrg_rx_pw_p5 Alias &H16                                  '  Размер Данных При Приёме По Каналу 5 : От 1 До 32. 0 - Канал Не Используется.
   Nrg_fifo_status Alias &H17                               '  Состояние Очередей Fifo Приёмника И Передатчика
   Nrg_dynpd Alias &H1C                                     '  Выбор Каналов Приёмника Для Которых Используется Произвольная Длина Пакетов.
   Nrg_feature Alias &H1D                                   '  Регистр Опций

  '/* Биты регистров */

  '  STATUS
   Bt_rx_dr Alias 6                                         '  Флаг получения новых данных в FIFO приёмника. Для сброса флага нужно записать 1
   Bt_tx_ds Alias 5                                         '  Флаг завершения передачи. Для сброса флага нужно записать 1
   Bt_max_rt Alias 4                                        '  Флаг превышения установленного числа повторов. Без сброса (записать 1) обмен невозможен
   Bt_rx_p_no Alias 1                                       '  3 бита. Номер канала, данные для которого доступны в FIFO приёмника. 7 -  FIFO пусто.
   Bt_tx_full_status Alias 0                                '  Признак заполнения FIFO передатчика: 1 - заполнено; 0 - есть доступные слоты
                                                             '  (переименовано из TX_FULL во избежание путаницы с одноимённым битом из регистра FIFO_STATUS)

   '  CONFIG
   Bt_mask_rx_dr Alias 6                                    '  Запрещает прерывание по RX_DR (получение пакета)
   Bt_mask_tx_ds Alias 5                                    '  Запрещает прерывание по TX_DS (завершение отправки пакета)
   Bt_mask_max_rt Alias 4                                   '  Запрещает прерывание по MAX_RT (превышение числа повторных попыток отправки)
   Bt_en_crc Alias 3                                        '  Включает CRC
   Bt_crco Alias 2                                          '  Размер поля CRC: 0 - 1 байт; 1 - 2 байта
   Bt_pwr_up Alias 1                                        '  Включение питания
   Bt_prim_rx Alias 0                                       '  Выбор режима: 0 - PTX (передатчик) 1 - PRX (приёмник)


 '* Константы для PIN модуля

         N_ce_sleep Alias 0                                 ' Значение вывода CE = SLEEP\настройка
         N_ce_tx Alias 1                                    ' Значение вывода CE = ПЕРЕДАЧА не менее 10мкс

         N_csn_spi_on Alias 0                               ' Значение вывода CSN = SPI вкл
         N_csn_spi_off Alias 1                              ' Значение вывода CSN = SPI откл


' -------------------------------------------------------------------------

' -------------------------------------------------------------------------
' ** ДЛЯ ручного  SPI  ****

Dim Spi_sch_bits As Byte                                    ' Для счета.
Dim Spi_sch_bytes As Byte                                   ' Для счета байт

Dim Spi_ms_out(6) As Byte                                   ' Это отправляем по SPI / 1 byte - команда "записать" + адрес регистра
Dim Spi_ms_in(5) As Byte                                    ' Это принято по SPI

' --------------------------------------------------------------------------

Dim B_tmp1 As Byte                                          ' Временный
Dim By_w As Byte                                            ' Для передачи

Dim Ds_a As Byte                                            ' Данные с датчика
Dim Ds_b As Byte                                            ' Данные с датчика



'*******************************************************************************
' ==============================================================================
' НАЗНАЧЕНИЕ ВЫВОДОВ

' Порт B
Ddrb.0 = 0                                                  ' ---
Ddrb.1 = 0 : Nrf_irq Alias Pinb.1                           ' Вх.  \ nrf - IRQ = прерыв. от NRF
Ddrb.2 = 1 : Nrf_ce Alias Portb.2                           ' Вых. \ nrf - CE = 1-прием 0-сон
Ddrb.3 = 1 : Nrf_csn Alias Portb.3                          ' Вых. \ nrf - CSN (SS) = 0-Включить SPI (обмен)
Ddrb.4 = 1 : P_lamp Alias Portb.4                           ' Вых. \ Светодиод
Ddrb.5 = 1 : Nrf_mosi Alias Portb.5                         ' Вых. \ nrf - MOSI = отправка в NRF
Ddrb.6 = 0 : Nrf_miso Alias Pinb.6                          ' Вх.  \ nrf - MISO = прием от NRF                                        '
Ddrb.7 = 1 : Nrf_sck Alias Portb.7                          ' Вых. \ nrf - SCK (spi) _/-


' Порт D
Ddrd.0 = 0 : Ds_data Alias Pind.0                           ' Вх.  \ Данные  DS18B20
Ddrd.1 = 0                                                  '  Вх.---
Ddrd.2 = 0                                                  '  Вх.---
Ddrd.3 = 0                                                  '  Вх.---
Ddrd.4 = 0                                                  '  Вх.---
Ddrd.5 = 0                                                  '  Вх.---
Ddrd.6 = 0                                                  '  Вх.---
Ddrd.7 = 0                                                  '  Вх.---


' ==============================================================================

Config 1wire = Portd.0                                      ' Вывод к которому подключен контакт DQ DS18B20


' === С Т А Р Т ================================================================


Nrf_csn = N_csn_spi_off                                     ' SPIу NRF отключен                                             '
Nrf_ce = N_ce_sleep                                         ' Nrf_ce = 0 Чип отключен
Nrf_sck = 0                                                 ' SCK исходное
By_w = 0

P_lamp = 0                                                  ' погасить лампу



Nrf_ce = N_ce_tx                                            ' Nrf_ce = ВКЛ
Waitms 15
Nrf_ce = N_ce_sleep                                         ' Nrf_ce = ОТКЛ
Nrf_csn = N_csn_spi_off                                     ' SPIу NRF отключен
Nrf_sck = 0                                                 ' SCK исходное

 Gosub Setup_tx                                             'Настройка на передачу
 Waitms 160                                                 ' Задержкад для настройки


' ============================================================================

 '*******************************************************************************
' ===== ОСНОВНОЙ ЦИКЛ  ==========================================================


Do

   P_lamp = 1                                               ' Вкл лампу
   Nrf_ce = N_ce_sleep                                      ' Nrf_ce = ОТКЛ

   1wreset                                                  ' Сброс датчика
   If Err = 1 Then
       ' Ошибка

       Ds_a = 0
       Ds_b = 0

   Else

      1wwrite &HCC                                          ' Команда "Skip ROM"
      1wwrite &H44                                          ' Команда "Convert  T".
      Waitms 750                                            ' Датчику нужно 750 миллисекунд для измерения температуры

      1wreset                                               ' Сброс датчика
      1wwrite &HCC                                          ' Команда "Skip ROM"
      1wwrite &HBE                                          ' Команда "Read scratchpad"

      Ds_a = 1wread()                                       'Чтение
      Ds_b = 1wread()                                       'Чтение

   End If



   Nrf_csn = N_csn_spi_off                                  ' SPIу NRF отключен


   Spi_ms_out(1) = Ncm_flush_rx                             'Команда: Очистка TX FIFO - буфера
   Call Nrf__write(1)                                       ' Записать 1 байт

   B_tmp1 = Ncm_r_register + Nrg_status
   Call Nrf__read(b_tmp1 , 1)                               ' Прочитать регистр
   B_tmp1 = Spi_ms_in(1)                                    ' Прочитанное
   B_tmp1 = B_tmp1 And &B01110000                           ' Выделение влагов прерываний

   Spi_ms_out(1) = Ncm_w_register + Nrg_status
   Spi_ms_out(2) = B_tmp1                                   ' Сброс флагов - записать в них 1
   Call Nrf__write(2)

   Spi_ms_out(1) = Ncm_w_tx_payload                         'Команда Положи 3 байт в TX pload буфера
   Spi_ms_out(2) = Ds_a                                     'Байт 1
   Spi_ms_out(3) = Ds_b                                     'Байт 2
   Spi_ms_out(4) = 0                                        'Байт 3
   Call Nrf__write(4)


   Nrf_ce = N_ce_tx                                         ' Nrf_ce = ВКЛ
   Waitms 10                                                ' Передача
   Nrf_ce = N_ce_sleep                                      ' Nrf_ce = ОТКЛ
   Nrf_csn = N_csn_spi_off                                  ' SPIу NRF отключен
   Nrf_sck = 0                                              ' SCK исходное


   P_lamp = 0                                               ' ВЫКЛ лампу

   Wait 5



Loop


'*******************************************************************************

'============================================================================
' === НАСТРОЙКА ПЕРЕДАТЧИКА  ================================================



Setup_tx:                                                   'Подготовка к TX

  ' Размер адреса  Nrg_setup_aw
   Spi_ms_out(1) = Nrg_setup_aw + Nrg_en_aa
   Spi_ms_out(2) = &B00000011                               ' Длина адреса 5 байт
   Call Nrf__write(2)                                       ' 2 байта

  ' Адрес КОМУ передача
   Spi_ms_out(1) = Ncm_w_register + Nrg_tx_addr
   Spi_ms_out(2) = &H34
   Spi_ms_out(3) = &H43
   Spi_ms_out(4) = &H10
   Spi_ms_out(5) = &H10
   Spi_ms_out(6) = &H01
   Call Nrf__write(6)                                       'Отправить 6 байт для SPI

  ' Запись адреса(код приемника). Канал 0  - нужно, если будет автоподтверждение
   Spi_ms_out(1) = Ncm_w_register + Nrg_rx_addr_p0
   Spi_ms_out(2) = &H34
   Spi_ms_out(3) = &H43
   Spi_ms_out(4) = &H10
   Spi_ms_out(5) = &H10
   Spi_ms_out(6) = &H01
   Call Nrf__write(6)                                       'Отправить 6 байт для SPI


  ' Автоподтверждение на всех каналах отключено
   Spi_ms_out(1) = Ncm_w_register + Nrg_en_aa
   Spi_ms_out(2) = 0
   Call Nrf__write(2)                                       ' 2 байта


   ' Включение канала 0
   Spi_ms_out(1) = Ncm_w_register + Nrg_en_rxaddr           'Включить RX адрес для pipe0  нужно, если будет вкл автоподтверждение
   Spi_ms_out(2) = &B00000001
   Call Nrf__write(2)                                       ' 2 байта


   ' Настройка Частоты каналов
   Spi_ms_out(1) = Ncm_w_register + Nrg_rf_ch               'Настройка Частоты каналов
   Spi_ms_out(2) = 40                                       'Частота 2440 MГц    ***
   Call Nrf__write(2)


   '  Размер Данных При Приёме = 3 байта
   Spi_ms_out(1) = Ncm_w_register + Nrg_rx_pw_p0
   Spi_ms_out(2) = 3
   Call Nrf__write(2)

   ' Настройка приемника-передатчика
   Spi_ms_out(1) = Ncm_w_register + Nrg_rf_setup            ' Выходная мощность 0 дБм, скорость 1 Мбит/c
   Spi_ms_out(2) = &B00000110
   Call Nrf__write(2)


   ' Включение приемника

   '  b7 ----
   '  b6(MASK_RX_DR)=0= ОТКЛ Прерывание по получению пакета.
   '  b5(MASK_TX_DS)=0= ОТКЛ Прерывание по успешной отправке пакета
   '  b4(MASK_MAX_RT)=0 ОТКЛ прерывание по превышению числа попыток повторной отправки
   '  b3(EN_CRC) =1=Включен расчет CRC
   '  b2(CRCO)   =1=размер CRC-2байта
   '  b1(PWR_UP) =1=включить питание
   '  b0(PRIM_RX)=0=передатчик

   Spi_ms_out(1) = Ncm_w_register + Nrg_config              'Настройка CONFIG -> I=1 (RX_device), PWR_UP=1, CRC 2bytes, Включить CRC
   Spi_ms_out(2) = &B00001110
   Call Nrf__write(2)




Return



'*******************************************************************************
' ==== П О Д П Р О Г Р А М М Ы  ================================================

' === ПП чтение SPI для NRF  ===================================================

Sub Nrf__read(byval Nrf_read_adr As Byte , Byval Cnt_byte As Byte)       ' Адрес и кол-во байтов для чтения
 ' Выводом CE (вкл чипа управлять програмно)


    Nrf_sck = 0                                             ' SCK исходное
    nop
    Spi_ms_in(1) = 0                                        ' Сброс принятого
    Spi_ms_in(2) = 0                                        ' Сброс принятого
    Spi_ms_in(3) = 0                                        ' Сброс принятого
    Spi_ms_in(4) = 0                                        ' Сброс принятого
    Spi_ms_in(5) = 0                                        ' Сброс принятого

    Spi_sch_bytes = 1                                       ' Сброс счетчика принятых байтов

    Nrf_csn = 0                                             ' Вкл SPI
    nop


    ' Запись команды-алреса в NRF - в это время он выдает регистр статус

    Spi_sch_bits = 7

    While Spi_sch_bits < 8

        Nrf_sck = 0
        nop
        Nrf_mosi = Nrf_read_adr.spi_sch_bits                ' Выставляю бит Spi_sch_bits на MOSI
        nop
        Nrf_sck = 1                                         ' Запись в NRF
        'By_nrf_prinat.Spi_sch_bits = Nrf_miso                  ' прием от NRF  НЕ запоминаю
        Decr Spi_sch_bits
    Wend

    Nrf_sck = 0                                             ' SCK исходное
    nop
    nop

    ' Чтение ответа

    While Cnt_byte >= Spi_sch_bytes

       Spi_sch_bits = 7

       While Spi_sch_bits < 8

           Nrf_sck = 0
           Nrf_mosi = 1                                     ' Выставляю бит 1 на MOSI  11111111 - пустая команда
           nop
           Nrf_sck = 1                                      ' Запись в NRF
           nop
           Spi_ms_in(spi_sch_bytes).spi_sch_bits = Nrf_miso ' прием от NRF
           nop
           Decr Spi_sch_bits

        Wend

        Incr Spi_sch_bytes

     Wend


    Nrf_sck = 0                                             ' SCK исходное
    Nrf_csn = 1                                             ' ОТкл SPI


End Sub


' ======================================================================

' === ПП ЗАПИСЬ SPI для NRF  ===================================================

Sub Nrf__write(byval Cnt_byte As Byte)

    Spi_sch_bytes = 1

    Nrf_sck = 0                                             ' SCK исходное
    Nrf_csn = 0                                             ' Вкл SPI
    nop

    ' Запись команды в NRF - в это время он выдает регистр статус
    Spi_sch_bits = 7

    While Spi_sch_bits < 8

        Nrf_sck = 0
        Nrf_mosi = Spi_ms_out(1).spi_sch_bits               ' Выставляю бит By_sch_nn на MOSI
        nop
        Nrf_sck = 1                                         ' Запись в NRF
        'By_nrf_prinat.by_sch_nn = Nrf_miso                  ' прием от NRF  НЕ запоминаю
        nop
        Decr Spi_sch_bits

    Wend

    Nrf_sck = 0                                             ' SCK исходное
    nop
    nop

     Incr Spi_sch_bytes

    ' Загрузка данных

    While Cnt_byte >= Spi_sch_bytes

       Spi_sch_bits = 7

       While Spi_sch_bits < 8

           Nrf_sck = 0
           Nrf_mosi = Spi_ms_out(spi_sch_bytes).spi_sch_bits       ' Выставляю бит By_sch_nn на MOSI
           nop
           Nrf_sck = 1                                      ' Запись в NRF
           nop
          Decr Spi_sch_bits

        Wend

        Incr Spi_sch_bytes

     Wend


    Nrf_sck = 0                                             ' SCK исходное
    Nrf_csn = 1                                             ' ОТкл SPI


End Sub
 

Приемник

Код:

'*******************************************************************************
' ===== РАДИОПРИЕМНИК ТЕМПЕРАТУРЫ ==============================================
'
'=== ARDUINO UNO R3  =
'=== Шильд LCD + Key =
'=== nRF24L01+
'
' =================================================================================

' =================================================================================
' =================================================================================

'$sim                                                        ' для симулятора  УБИРАТЬ ПРИ КОМПИЛЯЦИИ (ЗАПИСИ В ЧИП) - убирает все задержки

$regfile = "m328def.dat"
$crystal = 16000000
$hwstack = 40
$swstack = 16
$framesize = 32

'************************************************************************************************
' === ОБЪЯВЛЕНИЕ  ПОДПРОГРАММ  ================

Declare Sub Nrf__read(byval Nrf_read_adr As Byte , Byval Cnt_byte As Byte)       ' Чтение - ЗАПИСЬ
Declare Sub Nrf__write(byval Cnt_byte As Byte)



'************************************************************************************************
' === ОБЪЯВЛЕНИЕ  ПЕРЕМЕННЫХ  ==================================================

'/* Команды */

   Ncm_r_register Alias &H00                                ' + n Прочитать регистр n
   Ncm_w_register Alias &H20                                ' + n Записать регистр n
   Ncm_r_rx_payload Alias &H61                              ' Принять данные данные из верхнего слота очереди приёмника.
   Ncm_w_tx_payload Alias &HA0                              ' Записать в очередь передатчика данные для отправки
   Ncm_flush_tx Alias &HE1                                  ' Сбросить очередь передатчика
   Ncm_flush_rx Alias &HE2                                  ' Сбросить очередь приёмника
   Ncm_reuse_tx_pl Alias &HE3                               ' Использовать повторно последний переданный пакет
   Ncm_r_rx_pl_wid Alias &H60                               ' Прочитать размер данных принятого пакета в начале очереди приёмника.
   Ncm_w_ack_payload Alias &HA8                             ' + p Записать данные для отправки с пакетом подтверждения по каналу p.
   Ncm_w_tx_payload_noack Alias &HB0                        ' Записать в очередь передатчика данные, для отправки без подтверждения
   Ncm_nop Alias &HFF                                       ' Нет операции. Может быть использовано для чтения регистра статуса

'/* Регистры */

   Nrg_config Alias &H00                                    '  Регистр Настроек
   Nrg_en_aa Alias &H01                                     '  Выбор Автоподтверждения
   Nrg_en_rxaddr Alias &H02                                 '  Выбор Каналов Приёмника
   Nrg_setup_aw Alias &H03                                  '  Настройка Размера Адреса
   Nrg_setup_retr Alias &H04                                '  Настройка Повторной Отправки
   Nrg_rf_ch Alias &H05                                     '  Номер Радиоканала , На Котором Осуществляется Работа. От 0 До 125.
   Nrg_rf_setup Alias &H06                                  '  Настройка Радиоканала
   Nrg_status Alias &H07                                    '  Регистр Статуса.
   Nrg_observe_tx Alias &H08                                '  Количество Повторов Передачи И Потерянных Пакетов
   Nrg_rpd Alias &H09                                       '  Мощность Принимаемого Сигнала. Если Младший Бит = 1 , То Уровень Более -64dbm
   Nrg_rx_addr_p0 Alias &H0A                                '  3 -5 Байт(начиная С Младшего Байта). Адрес Канала 0 Приёмника.
   Nrg_rx_addr_p1 Alias &H0B                                '  3 -5 Байт(начиная С Младшего Байта). Адрес Канала 1 Приёмника.
   Nrg_rx_addr_p2 Alias &H0C                                '  Младший Байт Адреса Канала 2 Приёмника. Старшие Байты Из Rx_addr_p1
   Nrg_rx_addr_p3 Alias &H0D                                '  Младший Байт Адреса Канала 3 Приёмника. Старшие Байты Из Rx_addr_p1
   Nrg_rx_addr_p4 Alias &H0E                                '  Младший Байт Адреса Канала 4 Приёмника. Старшие Байты Из Rx_addr_p1
   Nrg_rx_addr_p5 Alias &H0F                                '  Младший Байт Адреса Канала 5 Приёмника. Старшие Байты Из Rx_addr_p1
   Nrg_tx_addr Alias &H10                                   '  3 -5 Байт(начиная С Младшего Байта). Адрес Удалённого Устройства Для Передачи
   Nrg_rx_pw_p0 Alias &H11                                  '  Размер Данных При Приёме По Каналу 0 : От 1 До 32. 0 - Канал Не Используется.
   Nrg_rx_pw_p1 Alias &H12                                  '  Размер Данных При Приёме По Каналу 1 : От 1 До 32. 0 - Канал Не Используется.
   Nrg_rx_pw_p2 Alias &H13                                  '  Размер Данных При Приёме По Каналу 2 : От 1 До 32. 0 - Канал Не Используется.
   Nrg_rx_pw_p3 Alias &H14                                  '  Размер Данных При Приёме По Каналу 3 : От 1 До 32. 0 - Канал Не Используется.
   Nrg_rx_pw_p4 Alias &H15                                  '  Размер Данных При Приёме По Каналу 4 : От 1 До 32. 0 - Канал Не Используется.
   Nrg_rx_pw_p5 Alias &H16                                  '  Размер Данных При Приёме По Каналу 5 : От 1 До 32. 0 - Канал Не Используется.
   Nrg_fifo_status Alias &H17                               '  Состояние Очередей Fifo Приёмника И Передатчика
   Nrg_dynpd Alias &H1C                                     '  Выбор Каналов Приёмника Для Которых Используется Произвольная Длина Пакетов.
   Nrg_feature Alias &H1D                                   '  Регистр Опций

  '/* Биты регистров */

  '  STATUS
   Bt_rx_dr Alias 6                                         '  Флаг получения новых данных в FIFO приёмника. Для сброса флага нужно записать 1
   Bt_tx_ds Alias 5                                         '  Флаг завершения передачи. Для сброса флага нужно записать 1
   Bt_max_rt Alias 4                                        '  Флаг превышения установленного числа повторов. Без сброса (записать 1) обмен невозможен
   Bt_rx_p_no Alias 1                                       '  3 бита. Номер канала, данные для которого доступны в FIFO приёмника. 7 -  FIFO пусто.
   Bt_tx_full_status Alias 0                                '  Признак заполнения FIFO передатчика: 1 - заполнено; 0 - есть доступные слоты
                                                             '  (переименовано из TX_FULL во избежание путаницы с одноимённым битом из регистра FIFO_STATUS)



 '* Константы для PIN модуля

         N_ce_sleep Alias 0                                 ' Значение вывода CE = SLEEP\настройка
         N_ce_rx Alias 1                                    ' Значение вывода CE = ПРИЕМ

         N_csn_spi_on Alias 0                               ' Значение вывода CSN = SPI вкл
         N_csn_spi_off Alias 1                              ' Значение вывода CSN = SPI откл


' -------------------------------------------------------------------------

Dim W_adc_val As Word                                       ' Значение АЦП
Dim By_kod_key As Byte                                      ' Код кнопки
Dim By_kod_key_0 As Byte                                    ' Обработанны код кнопки


Dim St_ind_str1 As String * 2                               ' Текст RX = приемник включен

Dim St_ind_rg As String * 6                                 ' Текст - имя регистра
Dim St_ind_rg_val As String * 8                             ' значение регистра

Dim St_ind_rx1 As String * 3                                ' Принятое значение байт 1
Dim St_ind_rx2 As String * 5                                ' Принятое значение байт 2
Dim St_ind_rx3 As String * 3                                ' Принятое значение байт 3


Dim By_flagi_1 As Byte                                      ' регистр флагов

   ' 7 - 1 =
   ' 6 - 1 = Обработать код кнопки
   ' 5 - 1 = Обновить LCD
   ' 4 -
   ' 3 -
   ' 2 -
   ' 1 -
   ' 0 -


' -------------------------------------------------------------------------
' ** ДЛЯ ручного  SPI  ****

Dim Spi_sch_bits As Byte                                    ' Для счета.
Dim Spi_sch_bytes As Byte                                   ' Для счета байт

Dim Spi_ms_out(6) As Byte                                   ' Это отправляем по SPI / 1 byte - команда "записать" + адрес регистра
Dim Spi_ms_in(5) As Byte                                    ' Это принято по SPI

' --------------------------------------------------------------------------

Dim B_tmp1 As Byte                                          ' Временный
Dim Rg_status As Byte                                       ' Регистр STATUS

Dim Rg_nomer As Byte                                        ' Номер регистра активный
Dim Rg_name(5) As String * 6                                ' Имя регистра
Dim Rg_adres(5) As Byte                                     ' Адрес ргистра
Dim Rg_value(5) As Byte                                     ' Значение регистра

Dim T1 As Byte
Dim T2 As Byte
Dim I1 As Integer


'*******************************************************************************
' ==============================================================================
' НАЗНАЧЕНИЕ ВЫВОДОВ


   Ddrb = &B00111111                                        'направление линий порта B: 1 - на вывод
   Portb = &B00110000                                       'исходное состояние линий B: Если PIN=вход, ТО ( 1= подтяжка 100КОм на + )(0= Hi-Z = просто вход)

           ' PB0  -  Вых \ LCD-RS
           ' РВ1  -  Вых \ LCD-E
           ' РВ2  -  Вых \ LCD-подсветка
           ' РВ3  -  Вых. \ nrf - CE = 1-прием 0-сон
           ' PB4  -  Вых. \ nrf - CSN (SS) = 0-Включить SPI (обмен)
           ' PB5  -  Вых. \ Светодиод на ПП NRF 0=горит
           ' PB6  -
           ' PB7  -
   Lcd_svet Alias Portb.2
   Nrf_ce Alias Portb.3
   Nrf_csn Alias Portb.4
   Nrf_lamp Alias Portb.5


'   Ddrc = &B00111111                                        'направление линий порта B: 1 - на вывод
'   Portc = &B00000000                                       'исходное состояние линий B: Если PIN=вход, ТО ( 1= подтяжка 100КОм на + )(0= Hi-Z = просто вход)
   Ddrc.0 = 0

           ' PC0  - Вх \ АЦП - 4 кнопки
           ' РC1  -
           ' РC2  -
           ' РC3  -
           ' PC4  -
           ' PC5  -
           ' PC6  -
           ' PC7  -

   Ddrd = &B11111100                                        'направление линий порта B: 1 - на вывод
   Portd = &B00000000                                       'исходное состояние линий B: Если PIN=вход, ТО ( 1= подтяжка 100КОм на + )(0= Hi-Z = просто вход)

           ' PD0  - Вх.  \ nrf - MISO = прием от NRF
           ' РD1  - Вх.  \ nrf - IRQ = прерыв. от NRF
           ' РD2  - Вых. \ nrf - SCK (spi) _/-
           ' РD3  - Вых. \ nrf - MOSI = отправка в NRF
           ' PD4  - Вых. LCD-D4
           ' PD5  - Вых. LCD-D5
           ' PD6  - Вых. LCD-D6
           ' PD7  - Вых. LCD-D7
      Nrf_miso Alias Pind.0
      Nrf_irq Alias Pind.1
      Nrf_sck Alias Portd.2
      Nrf_mosi Alias Portd.3




'*******************************************************************************
'==== НАСТРОЙКА  МК  ===========================================================

Config Adc = Single , Prescaler = Auto , Reference = Avcc   ' Настройка  АЦП

'===============================================================================

Config Lcd = 16 * 2                                         'указываем какой у нас дисплей
'и конфигурируем ножки для подключения
Config Lcdpin = Pin , Db4 = Portd.4 , Db5 = Portd.5 , Db6 = Portd.6 , Db7 = Portd.7 , E = Portb.1 , Rs = Portb.0

'===============================================================================

' === С Т А Р Т ================================================================


Nrf_csn = N_csn_spi_off                                     ' SPIу NRF отключен                                             '
Nrf_ce = N_ce_sleep                                         ' Nrf_ce = 0 Чип отключен
Nrf_sck = 0                                                 ' SCK исходное
By_flagi_1 = 0                                              ' Сброс флагов

By_kod_key_0 = 0                                            ' Ничего

Lcd_svet = 1                                                ' Вкл свет

Cursor Off                                                  'выключим отображение курсора
Cls                                                         'очистим дисплей

Start Adc                                                   ' Запуск АЦП


Nrf_ce = N_ce_rx                                            ' Nrf_ce = ВКЛ
Waitms 14
Nrf_ce = N_ce_sleep                                         ' Nrf_ce = ОТКЛ
Nrf_csn = N_csn_spi_off                                     ' SPIу NRF отключен
Nrf_sck = 0                                                 ' SCK исходное


' ============================================================================
'St_ind_str3 = "            "
Lcd_svet = 0                                                ' ОТкл свет
Waitms 50
Lcd_svet = 1                                                ' ОТкл свет

St_ind_str1 = "--"

St_ind_rx1 = "   "
St_ind_rx2 = "   "
St_ind_rx3 = "   "
St_ind_rg = "      "
St_ind_rg_val = "        "

 ' Заполнение массива регистров чтения

 Rg_nomer = 1
 Rg_name(rg_nomer) = "Config"
 Rg_adres(rg_nomer) = &H00
 Rg_value(rg_nomer) = 0

 Rg_nomer = 2
 Rg_name(rg_nomer) = "rf_set"
 Rg_adres(rg_nomer) = &H06
 Rg_value(rg_nomer) = 0

 Rg_nomer = 3
 Rg_name(rg_nomer) = "Status"
 Rg_adres(rg_nomer) = &H07
 Rg_value(rg_nomer) = 0

 Rg_nomer = 4
 Rg_name(rg_nomer) = "EN_aa "
 Rg_adres(rg_nomer) = &H01
 Rg_value(rg_nomer) = 0

 Rg_nomer = 5
 Rg_name(rg_nomer) = "en_rxa"
 Rg_adres(rg_nomer) = &H02
 Rg_value(rg_nomer) = 0

 Rg_nomer = 1


 '*******************************************************************************
' ===== ОСНОВНОЙ ЦИКЛ  ==========================================================


Do


   Gosub P_read_adc                                         ' Чтение АЦП --> Код кнопки By_kod_key

   ' ----------------------------------------
   '--- реакция на код кнопки ---------------


   If By_kod_key_0 = By_kod_key Then

   Else
         By_flagi_1.6 = 1                                   ' Обработать кнопку  Kod_key_0
         By_kod_key_0 = By_kod_key
   End If


'   If Nrf_irq = 0 Then
'      ' Есть прерывание
'      Gosub Pr_exec_irq                                     ' Обработать прерывание
'   End If


   B_tmp1 = Ncm_r_register + Nrg_status
   Call Nrf__read(b_tmp1 , 1)                               ' Прочитать регистр STATUS

   Rg_status = Spi_ms_in(1)

   If Rg_status.6 = 1 Then
        ' Это было действительно прерывание от приема.

        Gosub Pr_exec_irq                                   ' Обработать прерывание

   End If




   ' --- ОБРАБОТКА ФЛАГОВ  -----------------------------------

   If By_flagi_1.6 = 1 Then                                 ' Флаг - обработать кнопку
     ' Обработать команду

      Gosub Execute_key
      By_flagi_1.6 = 0                                      ' Команда обработана
      By_flagi_1.5 = 1                                      ' Флаг - обновить LCD

   End If


   If By_flagi_1.5 = 1 Then                                 ' Флаг - обновить LCD

      St_ind_rg = Rg_name(rg_nomer)
      St_ind_rg_val = Bin(rg_value(rg_nomer))

      ' ---- Вывод на экран ---------------------

      Locate 1 , 1                                          ' позиция курсора
      Lcd St_ind_str1                                       ' RX \ --

     ' Locate 1 , 4
     ' Lcd St_ind_rx1                                        ' Принятый байт 1

      Locate 1 , 8
      Lcd St_ind_rx2                                        ' Принятый байт 2

      Locate 1 , 13
      Lcd Chr(223) ; "C"                                    ' Принятый байт 3

      Locate 2 , 1                                          ' Имя регистра
      Lcd St_ind_rg

      Locate 2 , 9                                          ' Значение  регистра
      Lcd St_ind_rg_val

      ' ----------------------------------------
      By_flagi_1.5 = 0                                      ' Сброс флага

   End If


   Waitms 2



Loop


'*******************************************************************************


'*******************************************************************************

 '============================================================================
 '=== Прочитать  АЦП кнопки ==================================================

P_read_adc:

   W_adc_val = Getadc(0)                                    ' Опрос АЦП

   By_kod_key = 255                                         'Неизвестно

   ' --- Обработка результата АЦП ---> Код кнопки

   If W_adc_val > 1000 Then
      By_kod_key = 0                                        ' ничего
   Else
      If W_adc_val < 730 And W_adc_val > 720 Then
          By_kod_key = 1                                    ' Select
     Else
          If W_adc_val < 500 And W_adc_val > 470 Then
              By_kod_key = 2                                ' Left
          Else
             If W_adc_val < 320 And W_adc_val > 290 Then
                 By_kod_key = 3                             ' Down
             Else
               If W_adc_val < 140 And W_adc_val > 120 Then
                   By_kod_key = 4                           ' Up
               Else
                  If W_adc_val < 16 Then
                       By_kod_key = 5                       ' Right
                  End If
               End If
             End If
          End If
      End If

   End If


Return



 '============================================================================
 '=== обработка КОДА кнопки  =================================================

Execute_key:


 Select Case By_kod_key_0

   Case 0                                                   ' ничего

   Case 1                                                   ' "Select"
       ' НАстроить на прием

       Nrf_ce = N_ce_sleep                                  ' NRF - отключен чтобы получить доступ к регистрам
       Reset Nrf_lamp                                       ' Вкл LED
       Waitms 1

       Gosub Setup_rx                                       'Настройка nRF24L01 для RX
       Waitms 2                                             ' Задержка для включения приемника

       St_ind_str1 = "RX"
       By_flagi_1.5 = 1                                     ' Обновить LCD

       Nrf_ce = N_ce_rx                                     ' Включить прием

       Set Nrf_lamp                                         ' Выкл LED


   Case 2                                                   ' "Left  "


   Case 3                                                   ' "Down  "

      If Rg_nomer > 1 Then
          Rg_nomer = Rg_nomer - 1
      End If
      By_flagi_1.5 = 1                                      ' Обновить LCD

   Case 4                                                   ' "Up    "

      If Rg_nomer < 5 Then
          Rg_nomer = Rg_nomer + 1
      End If
      By_flagi_1.5 = 1                                      ' Обновить LCD

   Case 5                                                   ' "Right "

      ' Прочитать регистры

      Reset Nrf_lamp                                        ' Вкл LED
      Gosub Pr_read_reg
      Set Nrf_lamp                                          ' Выкл LED


   Case Else

 End Select

Return



'============================================================================
'=== ЧТЕНИЕ СОДЕРЖИМОГО РЕГИСТРОВ ===========================================

Pr_read_reg:

   Nrf_ce = N_ce_sleep                                      ' Nrf_ce = ОТКЛ прием

    For Rg_nomer = 1 To 5

       B_tmp1 = Ncm_r_register + Rg_adres(rg_nomer)
       Call Nrf__read(b_tmp1 , 1)                           ' Прочитать регистр
       Rg_value(rg_nomer) = Spi_ms_in(1)

    Next

   Nrf_ce = N_ce_rx                                         ' Включить прием

Return





'============================================================================
'=== обработка Прерывания ===================================================

 Pr_exec_irq:

    Reset Nrf_lamp                                          ' Вкл LED

    B_tmp1 = Ncm_r_register + Nrg_status
    Call Nrf__read(b_tmp1 , 1)                              ' Прочитать регистр STATUS
    Nrf_ce = N_ce_sleep                                     ' Nrf_ce = ОТКЛ прием
    B_tmp1 = Spi_ms_in(1)

    If B_tmp1.bt_rx_dr = 1 Then
        ' Это было действительно прерывание от приема.
        B_tmp1 = B_tmp1 And &B00001110

        If B_tmp1 = 0 Then
            ' Принято по каналу 0 = ЭТО МОЯ ПОСЫЛКА !

            Call Nrf__read(ncm_r_rx_payload , 3)            ' Прочитать 3 байта  в Spi_ms_in

            Spi_ms_out(1) = Ncm_flush_rx                    ' Команда: очистить буфер
            Call Nrf__write(1)

            Spi_ms_out(1) = Ncm_w_register + Nrg_status
            Spi_ms_out(2) = &B01000000                      ' Сброс флага RX_DR - записать в него 1
            Call Nrf__write(2)

            ' Подготовка данных для LCD

             St_ind_rx2 = "     "

             T1 = Spi_ms_in(1)
             T2 = Spi_ms_in(2)
             I1 = 0


       
             I1 = Spi_ms_in(2)
             Shift I1 , Left , 8
             I1 = I1 + Spi_ms_in(1)

             I1 = I1 * 10
             I1 = I1 \ 16
             St_ind_rx2 = Str(i1)
             St_ind_rx2 = Format(st_ind_rx2 , "0.0")


            By_flagi_1.5 = 1                                ' Обновить LCD


        Else
            ' Чужой пакет. Сбросить
            Spi_ms_out(1) = Ncm_flush_rx                    ' Команда: очистить буфер
            Call Nrf__write(1)
        End If

    End If

    Nrf_ce = N_ce_rx                                        ' Включить прием

    Waitms 20

    Set Nrf_lamp                                            ' Выкл LED

 Return


'============================================================================
' === НАСТРОЙКА ПРИЕМНИКА  ==================================================



Setup_rx:                                                   'Подготовка к RX

 ' Размер адреса  Nrg_setup_aw
   Spi_ms_out(1) = Nrg_setup_aw + Nrg_en_aa
   Spi_ms_out(2) = &B00000011                               ' Длина адреса 5 байт
   Call Nrf__write(2)                                       ' 2 байта


 ' Запись адреса(код приемника) для приемника. Канал 0
   Spi_ms_out(1) = Ncm_w_register + Nrg_rx_addr_p0
   Spi_ms_out(2) = &H34
   Spi_ms_out(3) = &H43
   Spi_ms_out(4) = &H10
   Spi_ms_out(5) = &H10
   Spi_ms_out(6) = &H01
   Call Nrf__write(6)                                       'Отправить 6 байт для SPI

 ' Автоподтверждение на всех каналах отключено
   Spi_ms_out(1) = Ncm_w_register + Nrg_en_aa
   Spi_ms_out(2) = 0
   Call Nrf__write(2)                                       ' 2 байта


   ' Включение канала 0
   Spi_ms_out(1) = Ncm_w_register + Nrg_en_rxaddr           'Включить RX адрес для pipe0
   Spi_ms_out(2) = &B00000001
   Call Nrf__write(2)                                       ' 2 байта


   ' Настройка Частоты каналов
   Spi_ms_out(1) = Ncm_w_register + Nrg_rf_ch               'Настройка Частоты каналов
   Spi_ms_out(2) = 40                                       'Частота 2440 MГц    ***
   Call Nrf__write(2)


   '  Размер Данных При Приёме = 3 байта
   Spi_ms_out(1) = Ncm_w_register + Nrg_rx_pw_p0
   Spi_ms_out(2) = 3
   Call Nrf__write(2)

   ' Настройка приемника
   Spi_ms_out(1) = Ncm_w_register + Nrg_rf_setup            ' Выходная мощность 0 дБм, скорость 1 Мбит/c
   Spi_ms_out(2) = &B00000110
   Call Nrf__write(2)


   ' Включение приемника

   '  b7 ----
   '  b6(MASK_RX_DR)=1= ВКЛ Прерывание по получению пакета.
   '  b5(MASK_TX_DS)=0= ОТКЛ Прерывание по успешной отправке пакета
   '  b4(MASK_MAX_RT)=0 ОТКЛ прерывание по превышению числа попыток повторной отправки
   '  b3(EN_CRC) =1=Включен расчет CRC
   '  b2(CRCO)   =1=размер CRC-2байта
   '  b1(PWR_UP) =1=включить питание
   '  b0(PRIM_RX)=1=приемник

   Spi_ms_out(1) = Ncm_w_register + Nrg_config              'Настройка CONFIG -> I=1 (RX_device), PWR_UP=1, CRC 2bytes, Включить CRC
   Spi_ms_out(2) = &B01001111
   Call Nrf__write(2)

   'Сброс прерываний



Return


'============================================================================

'*******************************************************************************
' ==== П О Д П Р О Г Р А М М Ы  ================================================

' === ПП чтение SPI для NRF  ===================================================

Sub Nrf__read(byval Nrf_read_adr As Byte , Byval Cnt_byte As Byte)       ' Адрес и кол-во байтов для чтения
 ' Выводом CE (вкл чипа управлять програмно)


    Nrf_sck = 0                                             ' SCK исходное
    nop
    Spi_ms_in(1) = 0                                        ' Сброс принятого
    Spi_ms_in(2) = 0                                        ' Сброс принятого
    Spi_ms_in(3) = 0                                        ' Сброс принятого
    Spi_ms_in(4) = 0                                        ' Сброс принятого
    Spi_ms_in(5) = 0                                        ' Сброс принятого

    Spi_sch_bytes = 1                                       ' Сброс счетчика принятых байтов

    Nrf_csn = 0                                             ' Вкл SPI
    nop

    ' Запись команды-алреса в NRF - в это время он выдает регистр статус

    Spi_sch_bits = 7

    While Spi_sch_bits < 8

        Nrf_sck = 0
        nop
        Nrf_mosi = Nrf_read_adr.spi_sch_bits                ' Выставляю бит Spi_sch_bits на MOSI
        nop
        nop
        Nrf_sck = 1                                         ' Запись в NRF
        'By_nrf_prinat.Spi_sch_bits = Nrf_miso                  ' прием от NRF  НЕ запоминаю
        Decr Spi_sch_bits
    Wend

    Nrf_sck = 0                                             ' SCK исходное
    nop


    ' Чтение ответа

    While Cnt_byte >= Spi_sch_bytes

       Spi_sch_bits = 7

       While Spi_sch_bits < 8

           Nrf_sck = 0
           Nrf_mosi = 1                                     ' Выставляю бит 1 на MOSI  11111111 - пустая команда
           nop
           nop
           Nrf_sck = 1                                      ' Запись в NRF
           nop
           Spi_ms_in(spi_sch_bytes).spi_sch_bits = Nrf_miso ' прием от NRF
           nop
           Decr Spi_sch_bits

        Wend

        Incr Spi_sch_bytes

     Wend


    Nrf_sck = 0                                             ' SCK исходное
    Nrf_csn = 1                                             ' ОТкл SPI


End Sub


' ===========================================================================================

' === ПП ЗАПИСЬ SPI для NRF  ===================================================

Sub Nrf__write(byval Cnt_byte As Byte)

    Spi_sch_bytes = 1

    Nrf_sck = 0                                             ' SCK исходное
    nop
    nop

     Nrf_csn = 0                                            ' Вкл SPI
    nop
    nop
    nop
    nop


    ' Запись команды в NRF - в это время он выдает регистр статус
    Spi_sch_bits = 7

    While Spi_sch_bits < 8

        Nrf_sck = 0
        Nrf_mosi = Spi_ms_out(1).spi_sch_bits               ' Выставляю бит By_sch_nn на MOSI
        nop
        nop
        Nrf_sck = 1                                         ' Запись в NRF
        'By_nrf_prinat.by_sch_nn = Nrf_miso                  ' прием от NRF  НЕ запоминаю
        nop
        Decr Spi_sch_bits

    Wend

    Nrf_sck = 0                                             ' SCK исходное
    nop


     Incr Spi_sch_bytes

    ' Загрузка данных

    While Cnt_byte >= Spi_sch_bytes

       Spi_sch_bits = 7

       While Spi_sch_bits < 8

           Nrf_sck = 0
           Nrf_mosi = Spi_ms_out(spi_sch_bytes).spi_sch_bits       ' Выставляю бит By_sch_nn на MOSI
           nop
           nop
           Nrf_sck = 1                                      ' Запись в NRF
           nop
          Decr Spi_sch_bits

        Wend

        Incr Spi_sch_bytes

     Wend


    Nrf_sck = 0                                             ' SCK исходное
    Nrf_csn = 1                                             ' ОТкл SPI


End Sub


P.S. Индикацию минусовых температур не проверял.

Отредактировано SV12 (2017-03-29 07:51:33)

+3

2

Крута конечно, но зачем? ESP8266 + DS1820 делает то-же самое и дешевле и компактнее.

0

3

ESP8266 + DS182 С этим разбираться лично мне оказалось сложно.
А вот проторенной дорожкой все же легче.
Ниже Modbus шлюз на NRF24. Одно устройство является шлюзом (Master)
остальные Slave устройства. Для беспроводных устройств (для работы через шлюз) надо задать адрес устройства от 200 до 255.
Если шлюз увидел обращение к адресному пространству выше 200 адреса , то он начинает радиообмен.
Slave:

Код:

    'доступны регистры с 1-25
    'в регистре  21 записан адрес устройства для обращения через шлюз Modbus
    'адреса могут быть в дапазоне 200-250
    '



    'в режиме приема запустить таймер . если нет данных перезагрузить инициализацию NRF
    'организовать 5 слов (10 байт) для передачи
    '


$regfile = "m328pdef.dat"
$crystal = 16000000

'Wait 3

$baud = 19200

$hwstack = 40
$swstack = 20
$framesize = 40

'Заявить отдельные подпрограммы
Declare Sub R_register(byval Command As Byte , Byval C_bytes As Byte)
Declare Sub R_register2(byval Command As Byte , Byval C_bytes As Byte)

Declare Sub W_register(byval C_bytes As Byte)

'Определить nRF24L01 прерывания, флаг
Const Idle_int = &H00                                       'Ожидания, нет прерывания
Const Max_rt = &H10                                         'Max #Tx, выберите Прерывания
Const Tx_ds = &H20                                          'Tx Данных, Переданных Прерывания
Const Rx_dr = &H40                                          'Rx Данные, Полученные

'SPI (nRF24L01) команды
Const Read_reg = &H00                                       'Определить Читать Команду Для Регистрации
Const Write_reg = &H20                                      'Определить Команду Записи В Реестр
Const Rd_rx_pload = &H61                                    'Define Rx Полезной Нагрузки Адрес Регистра
Const Wr_tx_pload = &HA0                                    'Определить Tx Полезной Нагрузки Адрес Регистра
Const Flush_tx = &HE1                                       'Определить Флеш Tx Зарегистрировать Команду
Const Flush_rx = &HE2                                       'Определить Флеш Rx Зарегистрировать Команду
Const Reuse_tx_pl = &HE3                                    'Определить Повторного Использования Tx Полезной Нагрузки Зарегистрировать Команду
Const Nop_comm = &HFF                                       'Определить Ни Одной Операции, Могут Быть Использованы Для Чтение Регистра Статуса

'SPI (nRF24L01) регистры (адреса)
Const Config_nrf = &H00                                     'Config адрес регистра
Const En_aa = &H01                                          'Включить Автоматическое Подтверждение регистрации адрес
Const En_rxaddr = &H02                                      'Включено Rx адреса " адрес регистра"
Const Setup_aw = &H03                                       'Настройка address ширина регистра адреса
Const Setup_retr = &H04                                     'Настройка Авто. Выберите " зарегистрировать адрес"
Const Rf_ch = &H05                                          'RF channel' адрес регистра
Const Rf_setup = &H06                                       'РФ Setup " (Настройка) адрес регистра"
Const Status = &H07                                         'Статус " адрес регистра"
Const Observe_tx = &H08                                     'Наблюдайте TX' адрес регистра
Const Cd = &H09                                             'carrier Detect " зарегистрировать адрес"
Const Rx_addr_p0 = &H0A                                     'rx адрес Pipe0 " зарегистрировать адрес"

Const Rx_addr_p1 = &H0B                                     'rx адрес Pipe1 " зарегистрировать адрес"
Const Rx_addr_p2 = &H0C                                     'rx адрес Pipe2 " зарегистрировать адрес"
Const Rx_addr_p3 = &H0D                                     'rx адрес Pipe3 " зарегистрировать адрес"
Const Rx_addr_p4 = &H0E                                     'rx адрес Pipe4 " зарегистрировать адрес"
Const Rx_addr_p5 = &H0F                                     'rx адрес Pipe5 " зарегистрировать адрес"
Const Tx_addr = &H10                                        'TX address (адрес)


Const Rx_pw_p0 = &H11                                       'rx полезной нагрузки ширина , Pipe0 " зарегистрировать адрес"
Const Rx_pw_p1 = &H12                                       'rx полезной нагрузки ширина , Pipe1 " зарегистрировать адрес"
Const Rx_pw_p2 = &H13                                       'rx полезной нагрузки ширина , Pipe2 " зарегистрировать адрес"
Const Rx_pw_p3 = &H14                                       'rx полезной нагрузки ширина , Pipe3 " зарегистрировать адрес"
Const Rx_pw_p4 = &H15                                       'rx полезной нагрузки ширина , Pipe4 " зарегистрировать адрес"
Const Rx_pw_p5 = &H16                                       'rx полезной нагрузки ширина , Pipe5 " зарегистрировать адрес"
Const Fifo_status = &H17                                    'fifo - Регистр Состояния " регистрация адреса"

'Различные
Const True = 1
Const False = 0

Dim D_bytes(38) As Byte , B_bytes(38) As Byte , B_bytes2(38) As Byte
Dim Temp As Byte , W As Word
Dim Packet_count As Byte

'&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&     дополнения
Dim Tx_mode As Byte
Dim Table_data_nrf24(32) As Word
Dim W_to_device As Byte
Dim N As Byte
Dim N_to_write As Byte
Dim Modbus_slave_dev As Eram Byte                           'адрес устройства в сети Modbus
Dim Modbus_slave As Byte
Dim Param_integer(5) As Integer
T_vozd Alias Param_integer(1)                               ' 1,2
T_vozd_float Alias Param_integer(2)                         ' 3,4
T_cod Alias Param_integer(3)                                ' 5,6
Param4 Alias Param_integer(4)                               ' 7,8
Param5 Alias Param_integer(5)                               ' 9,10
Dim Count_temp As Byte
Dim Temp_int As Integer
'&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&     дополнения

'Config оборудования
Config Spi = Hard , Interrupt = Off , Data Order = Msb , Master = Yes , Polarity = Low , Phase = 0 , Clockrate = 4 , Noss = 1

'Программное эмуляция SPI НЕ работает с nRF24L01, используйте встроеное SPI только, но эсэсовцы pin-код должен управляться нашей функцией
Config Portd.5 = Output : Ce Alias Portd.5                  'CE pin is output
Config Portb.2 = Output : Ss Alias Portb.2                  'SS pin is output
Config Pind.7 = Input : Irq Alias Pind.7                    'IRQ pin is input
Packet_count = 0
'@@@@@@@@@@@@@@@@@@@@@@@@@@   таймеры
Const N_timers = 5
Dim I As Byte
Dim T_counter As Long
Dim T_array_period(n_timers) As Word
Dim T_array_enable(n_timers) As Byte
Dim T_array_count(n_timers) As Word
Dim T_array_event(n_timers) As Byte

Declare Sub Timers(byval T_number As Byte , Byval T_period As Word , Byval T_enable As Byte )



     Call Timers(1 , 1 , 0 )                                'инициализация таймера  1 msek

     Call Timers(2 , 2 , 0 )                                'инициализация таймера  500 msek

     Call Timers(3 , 900 , 0 )                              'инициализация таймера  900 msek
     Call Timers(4 , 10000 , 0 )                            'инициализация таймера  10 сек

'@@@@@@@@@@@@@@@@@@@@@@@@@@   таймеры
'инициализация
 Modbus_slave = Modbus_slave_dev                            'адрес устройства в сети Modbus

   If Modbus_slave < 200 Or Modbus_slave > 250 Then         'ограничим диапазон адресов
       Modbus_slave = 200
      Else

   End If
Table_data_nrf24(21) = Modbus_slave
 Print "Modbus_slave=" ; Modbus_slave



';;;;;;;;;;;;;;;;;;;;;;;;;;;;;DS18b20;;;;;;;;;;;;;;;;;;;;;;;;;;;

Config 1wire = Portd.2

Dim T_refresh As Byte
Dim Timer_any_btn_toch As Byte
Dim Filter_t_value As Integer
Filter_t_value = 255
Declare Sub 1wire_temperatura
Dim Tmp As Integer
 'Dim T_vozd As Byte

';;;;;;;;;;;;;;;;;;;;;;;;;;;;;DS18b20;;;;;;;;;;;;;;;;;;;;;;;;;;;

Spiinit

Set Ce
Waitms 10
Reset Ce
Reset Ss

Print "RX_TX_device"

Call R_register(status , 1)                                 'Читать Регистр СОСТОЯНИЯ
Reset Ce                                                    'обратить внимание !!!!! когда надо уст./сбрасывать                                            'Set CE низко, чтобы получить доступ к регистрам

Gosub Setup_nrf                                             'Настройка nRF24L01 для RX
Gosub Enable_rx

 Config Watchdog = 512
 Start Watchdog
Dim Tx_mode_naladka As Byte

Do

'преобразование  Integer в байт
'Count_temp = 1
 'For I = 1 To 5

 'Table_data_nrf24(count_temp) = Low(param_integer(i))
 'Count_temp = Count_temp + 1
 'Table_data_nrf24(i + 2) = High(param_integer(i))
 'Count_temp = Count_temp + 1

'Next

If Tx_mode = 0 Then
   T_array_enable(4) = 1
   Else
     T_array_count(4) = 0
End If

       If T_array_event(4) = 1 Then                         'Организация Таймера 10 сек
          T_array_event(4) = 0
          T_array_enable(4) = 0
          ' перезагрузка режима прием
          Call R_register(status , 1)                       'Читать Регистр СОСТОЯНИ
          Reset Ce                                          'обратить внимание !!!!! когда надо уст./сбрасывать                                            'Set CE низко, чтобы получить доступ к регистрам
          Gosub Setup_nrf                                   'Настройка nRF24L01 для RX
          Gosub Enable_rx
          ' конец перезагрузка режима прием

        End If



      '0000000000000000000000000000000000000000000       режим примема     0000000000000000000000000000000
                              If Tx_mode = 0 Then

 If T_array_enable(2) = 0 Then                              ' если таймер №2 не запущен то выполняем

  If Irq = 0 Then                                           'Подождите, пока IRQ происходит, pin-код становится низким на прерывание



    Reset Ce                                                'Ресивер должен быть включен до чтения pload

      Call R_register2(status , 1)
      Temp = B_bytes2(1) And &B01110000                     'Маски IRQ бит, байт состояния
      If Temp = Rx_dr Then

          Do                                                'Цикл, пока все 3 буферы fifo пусты
            Call R_register(rd_rx_pload , 32)               'Читать 32 байт RX pload регистрации
            Call R_register2(fifo_status , 1)               'Читать FIFO_STATUS
            'надо переделать для чтения статуса отдельный вызов чтобы не смешивать его с данными (потому что B_bytes(1) занимается статусом после Call R_register(fifo_status , 1) )
         Loop Until B_bytes2(1).0 = True                    'Test или RX_EMPTY бит равен true, RX FIFO пустой

        For N = 1 To 32
             'Table_data_nrf24(n) = B_bytes(n)
      '       Print "B_bytes(" ; N ; ")=" ; B_bytes(n) ; Chr(13)
         Next
'         Print "_____________"
         'Print "!!!!!! B_bytes(28) = " ; B_bytes(28) ; " Table_data_nrf24(n_to_write)=" ; Table_data_nrf24(b_bytes(28)) ; "!!!!!! B_bytes(29) = " ; B_bytes(29) ; " Table_data_nrf24(n_to_write)=" ; Table_data_nrf24(b_bytes(29))

         If B_bytes(32) > 0 Then
            W_to_device = 1
            N_to_write = B_bytes(32)
     '       Print "N_to_write = B_bytes(32)" ; N_to_write
  'If N_to_write < 6 Then
  '          Select Case N_to_write
  '
  '          Case 1 : N_to_write = 1
  '          Case 2 : N_to_write = 3
  '          Case 3 : N_to_write = 5
  '          Case 4 : N_to_write = 7
  '          Case 5 : N_to_write = 9
  '          Case Else
  '         End Select
  '      Table_data_nrf24(b_bytes(32) ) = B_bytes(b_bytes(32))
  '      Temp_int = Makeint(b_bytes(n_to_write) , B_bytes(n_to_write + 1 ) )
  '      Param_integer(b_bytes(32)) = Temp_int
  ' Else

          N_to_write = B_bytes(32)
          Table_data_nrf24(n_to_write) = B_bytes(n_to_write)
  ' End If
    '     Print "!!!!!!!!!!!!!!!!!!!!!!!N_to_write=" ; N_to_write ; "    B_bytes(n_to_write )=" ; B_bytes(n_to_write ) ; "   Table_data_nrf24(n_to_write)=" ; Table_data_nrf24(n_to_write) ; "  B_bytes(32)=" ; B_bytes(32) ; Chr(13)
    '     Print "############Param_integer(b_bytes(32))=" ; Param_integer(b_bytes(32)) ; " Temp_int =" ; Temp_int ; Chr(13)

          B_bytes(32) = 0
         End If
         'Print "Pload:" ; Hex(b_bytes(1)) ; Hex(b_bytes(2)) ; Hex(b_bytes(3)) ; Hex(b_bytes(4)) ; Hex(b_bytes(5)) ; Hex(b_bytes(6)) ; Hex(b_bytes(7)) ; Hex(b_bytes(8)) ; B_bytes(32)
         'Print "-----------------------------" ; T_vozd ; "------------------------"
         'Packet_count = B_bytes(27) + 1
         D_bytes(1) = Write_reg + Status                    'Сброс RX_DR бит состояния
         D_bytes(2) = &B01110000                            'Напиши 1  для сброса IRQ
         Call W_register(2)
         Set Ce                                             'Включить приемник снова проверить если переходим в режим передачи нужно ли включать
      End If

   'D_bytes(1) = Flush_tx                                    'Flush the TX_fifo буфера
   'Call W_register(1)
   'Gosub Enable_tx
    'Waitms 5                                                'задержка 5 мсек  ?
      T_array_enable(2) = 1                                 'Организация Таймера 5 Мсек

                                                 '


  End If

 End If
                                                              ' если таймер №2 сработал то выполняем
       If T_array_event(2) = 1 Then                         'Организация Таймера 5 Мсек
          T_array_event(2) = 0
          T_array_enable(2) = 0
          Tx_mode = 1
        End If


                              End If

'0000000000000000000000000000000000000000000       режим примема     0000000000000000000000000000000





''''''''''''''''''''''''''''''''''                 режим передачи    '''''''''''''''''''''''''''''''
                                                   If Tx_mode = 1 Then
 If T_array_enable(1) = 0 Then


   Incr Packet_count

   If Packet_count > 254 Then
        Packet_count = 0
   End If
  Table_data_nrf24(27) = Packet_count
   Gosub Enable_tx                                          'Настройка nrf240l01 для TX
  D_bytes(1) = Wr_tx_pload                                  'Положи 32 байт в TX pload буфера





   ' Print "_______4________" ; Chr(13)
   'Tmp = 5
   For N = 1 To 25
   Tmp = N + 6
   D_bytes(tmp) = Table_data_nrf24(n)
   '  Print "B_bytes(" ; N ; ")=" ; B_bytes(n) ; "Table_data_nrf24(" ; N ; ") =" ; Table_data_nrf24(n) ; Chr(13)
   Next
    '   Print "_______4 end ________" ; Chr(13)
'   D_bytes(1) = Wr_tx_pload                                 'Положи 32 байт в TX pload буфера
'   D_bytes(2) = &HAA                                        'Байт 1
'   D_bytes(3) = &HBB                                        'Байт 2
'   D_bytes(4) = &HCC                                        'Байт 3
'   D_bytes(5) = T_vozd                                      'Байт 4
'   D_bytes(28) = Packet_count                               'Байт 33 показания датчика температуры
   Call W_register(33)                                      'Запись 33 байт для регистрации



   Set Ce                                                   'Set CE на короткий миг, чтобы передать буфер fifo


  'Waitms 1
   T_array_enable(1) = 1                                    'Организация Таймера 1 Мсек

 End If

   If T_array_event(1) = 1 Then
       T_array_event(1) = 0
       T_array_enable(1) = 0
    Else
         Goto T_1                                           ' пропускаем часть программы по таймеру
   End If


   Reset Ce



                                          If Irq = 0 Then
      Call R_register(status , 1)
      Temp = B_bytes(1) And &B01110000                      'Маски IRQ бит, байт состояния

      Select Case Temp                                      'Который IRQ происходит
               Case Max_rt                                  'MAX_RT
               Print "Максимальное количество повторных попыток, TX Flussing TX буфера сейчас!"
               D_bytes(1) = Flush_tx                        'Флеш TX буфера
               Call W_register(1)
               D_bytes(1) = Write_reg + Status
               D_bytes(2) = &B00010000                      'Очистить MAX_RT IRQ бит
               Call W_register(2)
'Waitms 10

    'Exit Do
      Case Tx_ds                                            'TX_DS
               'Print "Пакет" ; Packet_count ; "отправить и ACK-ответ"
               D_bytes(1) = Write_reg + Status
               D_bytes(2) = &B00100000                      'Clear the TX_DS IRQ bit
               Call W_register(2)
'Waitms 10

               '111111111111111111111111111111111111111111            11111111111111111111111111111111111
               ' Gosub Enable_rx

               '111111111111111111111111111111111111111111            11111111111111111111111111111111111

    'Exit Do
      Case Else                                             'Другое IRQ?
               Print "Другие irq" ; Bin(temp)
               D_bytes(1) = Flush_tx                        'Флеш TX буфера
               Call W_register(1)
               D_bytes(1) = Write_reg + Status
               D_bytes(2) = &B01110000                      'Очистить TX_DS IRQ бит

               Call W_register(2)
      End Select
               Gosub Enable_rx
                                          End If

'Waitms 100                                                  'Время ожидания для IRQ 1 мс * 100
 '  Incr W
 '    If W > 100 Then
 '       Print "Нет irq ответ от RF20L01 в 100 мс"
 '  Exit Do                                                  'Выход ждать цикла
 '    End If

   'Loop



                                                  End If

T_1:                                                        'переход по не таймеру 1

  ''''''''''''''''''''''''''''''''''                 режим передачи    '''''''''''''''''''''''''''''''


 If W_to_device = 1 Then                                    'при наличии признака записи в устройство (уставки, настройки, выходыи т.д.)
    W_to_device = 0
'    N_to_write=Table_data_nrf24(27)
    Select Case N_to_write                                  ' сохранить  значение в энергонезависимой память

            Case 2:
                     '

            Case 3:
                     'xxx=Table_data_nrf24(N_to_write)
            Case 4:
                     'Param4 = Makeint(table_data_nrf24(8) , Table_data_nrf24(7))
            Case 5:
                    ' Param5 = Makeint(table_data_nrf24(10) , Table_data_nrf24(9))
            Case 12:
                     'xxx=Table_data_nrf24(N_to_write)

            Case 21:

         Modbus_slave = Table_data_nrf24(n_to_write)
         Modbus_slave_dev = Modbus_slave
         Gosub Setup_nrf
         Print "_____Modbus_slave=" ; Modbus_slave ; Chr(13)
         'Gosub Setup_nrf_adress
                     'xxx=Table_data_nrf24(N_to_write)
    End Select
    'Table_data_nrf24(27) = 0

 End If


Call 1wire_temperatura
'Print "__8__";

Gosub T_timers
Reset Watchdog
Loop


'Sub подпрограмм
Sub W_register(byval C_bytes As Byte)                       'Пишите зарегистрировать с SPI
Reset Ss                                                    'Руководство управления СС контакт, установить СС низких до смещение, байт
Spiout D_bytes(1) , C_bytes                                 'Shiftout байты данных SPI корыта, C_bytes это количество байт, которые будут написаны
Set Ss                                                      'Set СС высокого
End Sub

Sub R_register(byval Command As Byte , Byval C_bytes As Byte) As Byte       'C_bytes = Count_bytes, номер off байт для чтения
Reset Ss                                                    'Ручное управление СС контакт, установить на низком уровне до переход в/из байт
Spiout Command , 1                                          'Первый shiftout в реестр, который будет читать
Spiin B_bytes(1) , C_bytes                                  'Прочитал назад байты из SPI направлять по nRF20L01
Set Ss                                                      'Установить СС обратно на высоком уровне
End Sub

Sub R_register2(byval Command As Byte , Byval C_bytes As Byte) As Byte       'C_bytes = Count_bytes, номер off байт для чтения
Reset Ss                                                    'Ручное управление СС контакт, установить на низком уровне до переход в/из байт
Spiout Command , 1                                          'Первый shiftout в реестр, который будет читать
Spiin B_bytes2(1) , C_bytes                                 'Прочитал назад байты из SPI направлять по nRF20L01
Set Ss                                                      'Установить СС обратно на высоком уровне
End Sub





Setup_nrf:                                                  'Подготовка к NRF инициализация
'Modbus_slave = 200
D_bytes(1) = Write_reg + Rx_addr_p0                         'RX адрес для pipe0 (5 байтовый адрес) при передаче RX адрес и  TX адрес должны быть одинаковыми
D_bytes(2) = &H34
D_bytes(3) = &H43

D_bytes(4) = &H10
D_bytes(5) = &H10

D_bytes(6) = Modbus_slave                                   '&H01                                           'Modbus_slave
Call W_register(6)

D_bytes(1) = Write_reg + Tx_addr                            'TX адрес            (5 байтовый адрес)
D_bytes(2) = &H34
D_bytes(3) = &H43

D_bytes(4) = &H10
D_bytes(5) = &H10

D_bytes(6) = Modbus_slave                                   '&H01                                           'Modbus_slave
Call W_register(6)                                          'Отправить 6 байт для SPI

D_bytes(1) = Write_reg + En_aa                              'Enable auto ACK на pipe0
D_bytes(2) = &H01
Call W_register(2)

D_bytes(1) = Write_reg + En_rxaddr                          'Включить RX адрес для pipe0
D_bytes(2) = &H01
Call W_register(2)

D_bytes(1) = Write_reg + Rf_ch                              'Настройка каналов
D_bytes(2) = 40
Call W_register(2)

D_bytes(1) = Write_reg + Rx_pw_p0                           'Set RX pload ширина для pipe0    (принимаем только 32 байт)
D_bytes(2) = 32
Call W_register(2)

D_bytes(1) = Write_reg + Rf_setup                           'Настройка РФ -> Выходной мощности 0 дБм, datarate 2 Мбит / с и МШУ прибыль по
D_bytes(2) = &H0F
Call W_register(2)

D_bytes(1) = Flush_tx                                       'Flush the TX_fifo буфера
Call W_register(1)

D_bytes(1) = Write_reg + Status                             'Reset IRQ бит
D_bytes(2) = &B0111000
Call W_register(2)


Return

Setup_nrf_adress:
D_bytes(1) = Write_reg + Rx_addr_p0                         'RX адрес для pipe0 (5 байтовый адрес) при передаче RX адрес и  TX адрес должны быть одинаковыми
D_bytes(2) = &H34
D_bytes(3) = &H43

D_bytes(4) = &H10
D_bytes(5) = &H10
D_bytes(6) = &H01                                           'Modbus_slave
Call W_register(6)

D_bytes(1) = Write_reg + Tx_addr                            'TX адрес            (5 байтовый адрес)
D_bytes(2) = &H34
D_bytes(3) = &H43

D_bytes(4) = &H10
D_bytes(5) = &H10

D_bytes(6) = &H01                                           'Modbus_slave
Call W_register(6)                                          'Отправить 6 байт для SPI

Return

Enable_rx:
Reset Ce
Tx_mode = 0

   D_bytes(1) = Write_reg + Status                          'Сброс RX_DR бит состояния
   D_bytes(2) = &B01000000                                  'Напиши 1 до RX_DR бит для сброса IRQ
   Call W_register(2)


D_bytes(1) = Write_reg + Config_nrf                         'Настройка CONFIG -> I=1 (RX_device), PWR_UP=1, CRC 2bytes, Включить CRC
D_bytes(2) = &H0F
Call W_register(2)

Waitms 2
Set Ce                                                      'Set nRF20L01 в режиме приема
Return

Enable_tx:
 Tx_mode = 1

D_bytes(1) = Flush_tx                                       'Flush the TX_fifo буфера
Call W_register(1)
D_bytes(1) = Write_reg + Status                             'Reset IRQ бит
D_bytes(2) = &B01110000
Call W_register(2)
D_bytes(1) = Write_reg + Config_nrf                         'Настройка CONFIG -> I=0 (TX_device), PWR_UP=1, CRC 2bytes, Включить CRC
D_bytes(2) = &H0E
Call W_register(2)

Return

  Sub Timers(byval T_number As Byte , Byval T_period As Word , Byval T_enable As Byte )       'можно сделать  и не используя функцию а только SUB или GoSub, проверяя значение  T_array_event(t_number) в цикле программы

        'If T_enable = 0 Then
         'T_array_enable(t_number) = 0
'         T_array_period(t_number) = 0                       'T_period
         'Else

         'T_array_enable(t_number) = 1


        'End If
    T_array_enable(t_number) = T_enable
    T_array_count(t_number) = 0
    T_array_event(t_number) = 0
    T_array_period(t_number) = T_period


End Sub


T_timers:
 Incr T_counter
 If T_counter > 50 Then                                     '150 циклов оновной програмы грубо равны 1 мсек  (значение можно изменять до требуемой точности)
     T_counter = 0

     For I = 1 To N_timers

          If T_array_enable(i) = 1 And T_array_event(i) = 0 Then
             Incr T_array_count(i)
             If T_array_count(i) > T_array_period(i) Then
                T_array_event(i) = 1
                T_array_count(i) = 0
             End If
          End If

     Next I

 End If

 Return




   Sub 1wire_temperatura
'   Print " 1 ";
    If T_array_enable(3) = 0 Then                           'если таймер паузы для измерения температуры не запущен
'   Print " 2 ";
       1wreset
       If Err = 1 Then                                      'Если не ответил
          'Table_data(15) = 1                'Тут можно что нибудь сделать, если МК не нашел термометр
       End If

       1wwrite &HCC                                         'Skip ROM [CCh]

       1wwrite &H44                                         'Запустим преобразование Convert T [44h]
                                                      'задержка для того чтоб датчик успел произвести измерение

       T_array_enable(3) = 1                                'Организация Таймера 1 сек

    End If
'   Print " 3 ";
   If T_array_event(3) = 1 Then                             'если таймер не отработал то пропускаем
       T_array_event(3) = 0
       T_array_enable(3) = 0
'   Print " 4 ==========================================================================================================";
    Else
'     Print " 5 "
         Exit Sub                                           ' пропускаем часть программы по таймеру

   End If
'   Print " 6 ";
                       1wreset
                       1wwrite &HCC                         'Skip ROM [CCh]
                       1wwrite &HBE                         'Read Scratchpad [BEh]

                     'Sc(1) = 1wread(9)     команды чтения занимают много времени. Для минимизации ошибок можно использовать фильтр
                     'Tmp_byte = Crc8(sc(1) , 8) расчитываем контрльную сумму


                     Tmp = 1wread(2)

'Print "*********Tmp==" ; Tmp ; "**********"
'Table_data(15) = Err
'Table_data(16) = Tmp                                        'для наладки вывод считанного кода температуры датчика
'Table_data_nrf24(6 ) = Tmp
T_cod = Tmp

Print "+++++++  Tmp=" ; Tmp ; "  +++++" ; Chr(13)
'       Tmp = Makeint(sc(1) , Sc(2))
'        If Sc(9) = Tmp_byte And Tmp <> 1360 And Tmp <> 65535 Then       'obliczamy CRC i porownujemy z przyslanym przez czujnik
        'If Tmp <> 1360 And Tmp <> 65535 And Tmp <> 17995 Then       'obliczamy CRC i porownujemy z przyslanym przez czujnik


                     Tmp = Tmp * 10
                    ' Tmp_temp = Tmp

T_vozd_float = Tmp Mod 100
                     Tmp = Tmp \ 160


 Print "+++++++  Tmp\160=" ; Tmp ; "  +++++" ; Chr(13)      'измерение температуры ххххххххххххххх  конец хххххххххххххххххххххххххххххххххххххххх
'Table_data_nrf24(6 ) = Tmp
 ' Table_data(25).2 = Menu_mode                              ' = Tmp_byte.2
  '************************8

  If Filter_t_value = 255 Then
    T_vozd = Tmp
    'Table_data_nrf24(5) = T_vozd
    'Lcd_refrsh = 1
  End If

If Err = 0 Then

  Filter_t_value = Tmp - T_vozd

  If Filter_t_value < 0 Then Filter_t_value = -1 * Filter_t_value

 If Filter_t_value < 5 Then

      If T_vozd <> Tmp Then                                 'Записывать значение температуры только при изменении
         'Lcd_refrsh = 1
         'Table_data(1) = Tmp
         T_vozd = Tmp
      'Table_data_nrf24(5) = T_vozd
Print "+++++++  T_vozd=" ; T_vozd ; "  +++++" ; Chr(13)
      End If

 End If
End If




  End Sub

+2

4

master :

Код:
'(
   Программа шлюза MODBUS и беспроводных устройств на основе nRF24L01
   Диапазон Адресов Устройств В Сети Модбас От 200 -250 Задается Для Беспроводных Устройств
   адрес в сети 255 по умолчанию и при наладке адрес шлюза
   Адреса От 1 -199 Могут Занимать Любые Другие Устройства В Сети Модбас

    счетчик   событий Максимальное количество повторных попыток, TX Flussing TX  или сразу ресет устройства

')

$regfile = "m328pdef.dat"
$crystal = 16000000

'Wait 3

$baud = 19200

$hwstack = 40
$swstack = 20
$framesize = 40



   ' ========================   объявления для nRF24L01   ====================

'Заявить отдельные подпрограммы
Declare Sub R_register(byval Command As Byte , Byval C_bytes As Byte)
Declare Sub R_register2(byval Command As Byte , Byval C_bytes As Byte)

Declare Sub W_register(byval C_bytes As Byte)

'Определить nRF24L01 прерывания, флаг
Const Idle_int = &H00                                       'Ожидания, нет прерывания
Const Max_rt = &H10                                         'Max #Tx, выберите Прерывания
Const Tx_ds = &H20                                          'Tx Данных, Переданных Прерывания
Const Rx_dr = &H40                                          'Rx Данные, Полученные

'SPI (nRF24L01) команды
Const Read_reg = &H00                                       'Определить Читать Команду Для Регистрации
Const Write_reg = &H20                                      'Определить Команду Записи В Реестр
Const Rd_rx_pload = &H61                                    'Define Rx Полезной Нагрузки Адрес Регистра
Const Wr_tx_pload = &HA0                                    'Определить Tx Полезной Нагрузки Адрес Регистра
Const Flush_tx = &HE1                                       'Определить Флеш Tx Зарегистрировать Команду
Const Flush_rx = &HE2                                       'Определить Флеш Rx Зарегистрировать Команду
Const Reuse_tx_pl = &HE3                                    'Определить Повторного Использования Tx Полезной Нагрузки Зарегистрировать Команду
Const Nop_comm = &HFF                                       'Определить Ни Одной Операции, Могут Быть Использованы Для Чтение Регистра Статуса

'SPI (nRF24L01) регистры (адреса)
Const Config_nrf = &H00                                     'Config адрес регистра
Const En_aa = &H01                                          'Включить Автоматическое Подтверждение регистрации адрес
Const En_rxaddr = &H02                                      'Включено Rx адреса " адрес регистра"
Const Setup_aw = &H03                                       'Настройка address ширина регистра адреса
Const Setup_retr = &H04                                     'Настройка Авто. Выберите " зарегистрировать адрес"
Const Rf_ch = &H05                                          'RF channel' адрес регистра
Const Rf_setup = &H06                                       'РФ Setup " (Настройка) адрес регистра"
Const Status = &H07                                         'Статус " адрес регистра"
Const Observe_tx = &H08                                     'Наблюдайте TX' адрес регистра
Const Cd = &H09                                             'carrier Detect " зарегистрировать адрес"
Const Rx_addr_p0 = &H0A                                     'rx адрес Pipe0 " зарегистрировать адрес" Const Rx_addr_p0 = &H10
Const Rx_addr_p1 = &H0B                                     'rx адрес Pipe1 " зарегистрировать адрес"
Const Rx_addr_p2 = &H0C                                     'rx адрес Pipe2 " зарегистрировать адрес"
Const Rx_addr_p3 = &H0D                                     'rx адрес Pipe3 " зарегистрировать адрес"
Const Rx_addr_p4 = &H0E                                     'rx адрес Pipe4 " зарегистрировать адрес"
Const Rx_addr_p5 = &H0F                                     'rx адрес Pipe5 " зарегистрировать адрес"
'Const Tx_addr = &H10                                        'TX address (адрес)
 Dim Tx_addr As Byte
 '    If Tx_addr < 200 Or Tx_addr > 250 Then
  '    Tx_addr = 200
   '  End If
     Tx_addr = &H10

Const Rx_pw_p0 = &H11                                       'rx полезной нагрузки ширина , Pipe0 " зарегистрировать адрес"
Const Rx_pw_p1 = &H12                                       'rx полезной нагрузки ширина , Pipe1 " зарегистрировать адрес"
Const Rx_pw_p2 = &H13                                       'rx полезной нагрузки ширина , Pipe2 " зарегистрировать адрес"
Const Rx_pw_p3 = &H14                                       'rx полезной нагрузки ширина , Pipe3 " зарегистрировать адрес"
Const Rx_pw_p4 = &H15                                       'rx полезной нагрузки ширина , Pipe4 " зарегистрировать адрес"
Const Rx_pw_p5 = &H16                                       'rx полезной нагрузки ширина , Pipe5 " зарегистрировать адрес"
Const Fifo_status = &H17                                    'fifo - Регистр Состояния " регистрация адреса"

'Различные
Const True = 1
Const False = 0

Dim D_bytes(33) As Byte , B_bytes(33) As Byte , B_bytes2(33) As Byte
Dim Temp As Byte , W As Word
Dim Packet_count As Byte
'Config оборудования

Config Spi = Hard , Interrupt = Off , Data Order = Msb , Master = Yes , Polarity = Low , Phase = 0 , Clockrate = 4 , Noss = 1
'Программное эмуляция SPI НЕ работает с nRF24L01, используйте встроеное SPI только, но ss pin-код должен управляться нашей функцией
Config Portd.5 = Output : Ce Alias Portd.5                  'CE pin is output
Config Portb.2 = Output : Ss Alias Portb.2                  'SS pin is output
Config Pind.7 = Input : Irq Alias Pind.7                    'IRQ pin is input
Packet_count = 0
' ======================== конец  объявления для nRF24L01   ====================

'**************************  объявления для MODBUS   ************************
 $lib "modbus.lbx"
 'Config Portb.5 = Output
 'Enable_tx Alias Portb.5                                   'для разрешение на передачу по 485
  Dim Enable_tx As Byte
  Dim S_t_m As Byte                                         'для вызова send_to_master

 Dim Mbuf(86) As Byte , Mbuf_frame(66) As Byte , Modc_frame As Byte , Modc As Byte , Modt As Byte , Modw As Word

 ' Dim Mbuf_clear(66) As Byte
 'Dim Table_data(30) As Word                                 'таблица с данными (текущие значения измерений, слова входов выходов уставки, настройки )
 Dim Table_data(32) As Word
 Dim Tmp As Integer
 Dim Tmp_byte As Byte                                       'промежуточные переменные
 Dim Tmp_byte2 As Byte
 Dim Tmp_word As Word
 Dim Tmp_byte_modbus As Byte
 Dim N_word As Byte                                         'количество слов в посылке
 Dim N_byte As Byte                                         'количество байт в посылке
 Dim Error_mod As Byte                                      ' код ошибки
 Dim Md_t_start As Bit
 Dim Beg_adr As Byte                                        'начальный адрес данных
 Dim Beg_adr_w As Byte                                      ' адрес данных  при записи
 Dim I As Byte                                              'счетчик циклов в for
 Dim Cnt_print As Bit                                       ' параметры для записи в энергонезависимую память
 Dim W_to_device As Byte                                    'признак записи в устройство
 Dim Modbus_slave_dev As Eram Byte                          'адрес устройства в сети Modbus
 Dim Modbus_slave As Byte

 Declare Sub Send_to_master                                 'подпрограмма передачи ответа мастеру
 Declare Sub Error_modbus                                   'подпрограмма формирования ошибки модбас

 Dim Load_timer_device As Eram Word
 Dim Load_timer As Word
                                          Config Timer1 = Timer , Prescale = 64       ' организация modbus,  при передаче на порт 485    (timer0 16 mhz 256 =1,048576 сек  64=0,262144 сек)
                                          On Timer1 Modbus_timers
                                          On Urxc Urxc_isr
                                          On Utxc Utxc_isr


'************************** конец  объявления для MODBUS   ************************
' Инициализация  Modbus   *******************************
 Enable Interrupts
 Load_timer = Load_timer_device
 If Load_timer < 500 Then                                   '16 Мгц timer0 64 преоывание=0,262144 сек 250 тиков соответствуют примерно=1 мсек
   Load_timer = 500
   Load_timer_device = Load_timer
 End If
 Tmp_word = Load_timer / 250                                ' текуще значение паузы между фреймами выводим в таблицу обмена Modbus
 Table_data(22) = Tmp_word

 Load Timer1 , Load_timer
 Enable Timer1
 Stop Timer1
 Enable Urxc
 Enable Utxc

   Modc = 0
   W_to_device = 0
   Tmp_byte = Modbus_slave_dev
   Modbus_slave = Tmp_byte
' конец Инициализация  Modbus   *******************************




'&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&     дополнения
Dim Table_data_nrf24(32) As Word                            ' массив для обмена Modbus с беспроводными устройствами
Dim Tx_mode As Byte                                         '  Tx_mode=1 передача;Tx_mode=0 прием; Tx_mode=3 не обрабатывается
Dim Plc_reset As Byte
Dim N As Byte
Dim Remote_device As Byte
Dim Modbus_slave_nrf24 As Byte
Dim Count_temp As Byte
Dim N_to_write As Byte
'&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&     дополнения


'@@@@@@@@@@@@@@@@@@@@@@@@@@   таймеры
'(                                      таймеры созданы на счетчиках основного цикла
                                        вместо задержек типа wait
                                        и для того чтоб не дергать лишний раз контроллер в прерываниях(это критично при обработке модбас)
                                        количество зависит от размера массивов(N_timers). Таймеры работают независимо друг от друга.
')

Const N_timers = 5
Dim Y As Byte
Dim T_counter As Long
Dim T_array_period(n_timers) As Word
Dim T_array_enable(n_timers) As Byte
Dim T_array_count(n_timers) As Word
Dim T_array_event(n_timers) As Byte

Declare Sub Timers(byval T_number As Byte , Byval T_period As Word , Byval T_enable As Byte )

     Call Timers(1 , 1 , 0 )                                'инициализация таймера  1 msek без его запуска

     Call Timers(2 , 5 , 0 )                                'инициализация таймера  5 msek без его запуска

    ' Call Timers(3 , 5000 , 1 )
'@@@@@@@@@@@@@@@@@@@@@@@@@@   таймеры


' 0000000000000  подготовка для nRF24L01
Spiinit
Set Ce
Waitms 10
Reset Ce
Reset Ss
Call R_register(status , 1)                                 'Читать Регистр СОСТОЯНИЯ
Reset Ce                                                    'обратить внимание !!!!! когда надо уст./сбрасывать                                            'Set CE низко, чтобы получить доступ к регистрам
Gosub Setup_nrf                                             'Настройка nRF24L01 для RX
Gosub Enable_transmit
Tx_mode = 3                                                 'Tx_mode = 3 означает , что nRF24L01 не обрабатывается программой (при этом nRF24L01 находится в режиме передачи по первоначальной инициализации  но ничего не транслирует)
'00000000000000   конец подготовка для nRF24L01

 Config Watchdog = 512
 Start Watchdog

 Do                                                         '                  Основной цикл

      '0000000000000000000000000000000000000000000       режим примема     0000000000000000000000000000000

                              If Tx_mode = 0 Then
 If T_array_enable(2) = 0 Then                              ' если таймер №2 не запущен то выполняем

  If Irq = 0 Then                                           'Подождите, пока IRQ происходит, pin-код становится низким на прерывание

    Reset Ce                                                'Ресивер должен быть включен до чтения pload
      Call R_register2(status , 1)
      Temp = B_bytes2(1) And &B01110000                     'Маски IRQ бит, байт состояния
      If Temp = Rx_dr Then

          'Disable Urxc
          'Disable Utxc
          Do                                                'Цикл, пока все 3 буферы fifo пусты
            Call R_register(rd_rx_pload , 32)               'Читать 32 байт RX pload регистрации
            Call R_register2(fifo_status , 1)               'Читать FIFO_STATUS
         Loop Until B_bytes2(1).0 = True                    'Test или RX_EMPTY бит равен true, RX FIFO пустой
         'Enable Urxc
         'Enable Utxc

         'Print "Pload:" ; B_bytes(1) ; B_bytes(2) ; B_bytes(3) ; "T=" ; B_bytes(4) ; " " ; B_bytes(5) ; B_bytes(6) ; B_bytes(7) ; B_bytes(8) ; B_bytes(32)

         'Packet_count = B_bytes(32) + 1
         D_bytes(1) = Write_reg + Status                    'Сброс RX_DR бит состояния
         D_bytes(2) = &B01110000                            'Напиши 1  для сброса IRQ
         Call W_register(2)
         Set Ce                                             'Включить приемник снова проверить если переходим в режим передачи нужно ли включать


          'Table_data_nrf24(1) = Makeint(b_bytes(1) , B_bytes(2))
          'Table_data_nrf24(2) = Makeint(b_bytes(3) , B_bytes(4))
          'Table_data_nrf24(3) = Makeint(b_bytes(5) , B_bytes(6))
          'Table_data_nrf24(4) = Makeint(b_bytes(7) , B_bytes(8))
          'Table_data_nrf24(5) = Makeint(b_bytes(9) , B_bytes(10))
         Count_temp = 5
         For N = 1 To 25
         Count_temp = Count_temp + 1
              Table_data_nrf24(n) = B_bytes(count_temp)
         Next

    'Table_data(1) = B_bytes(4)                              'температура
    'Table_data(2) = B_bytes(32)
                                                             'надо добавить: сформировать ошибку модбас если стройство не отвечает в течении определенного времени
      Call Send_to_master                                   ' передаем   текущее значение Table_data_nrf24 при втором запросе (если переделать обаботку фрейма модбас то можно передать сразу )

      Tx_mode = 3
      End If

    'Waitms 5                                                'задержка 5 мсек  ?
      'T_array_enable(2) = 1                                 'Организация Таймера 5 Мсек  Запускаем таймер №2

                                                 '


  End If

 End If
                                                              ' если таймер №2 сработал то выполняем
       If T_array_event(2) = 1 Then                         'Организация Таймера 5 Мсек
          T_array_event(2) = 0
          T_array_enable(2) = 0
          Tx_mode = 3
        End If


                              End If

'0000000000000000000000000000000000000000000       режим примема     0000000000000000000000000000000





''''''''''''''''''''''''''''''''''                 режим передачи    '''''''''''''''''''''''''''''''
                                                   If Tx_mode = 1 Then
 If T_array_enable(1) = 0 Then                              'если таймер №1 не запущен


   'Incr Packet_count

   If Packet_count > 254 Then
        Packet_count = 0
   End If

   Gosub Enable_transmit                                    'Настройка (инициализация) nrf240l01 для TX
   D_bytes(1) = Wr_tx_pload                                 'Положи 32 байт в TX pload буфера


   For N = 1 To 32
   D_bytes(n + 1) = Table_data_nrf24(n)
   Next
   Call W_register(33)                                      'Запись 33 байт для регистрации



   Set Ce                                                   'Set CE на короткий миг, чтобы передать буфер fifo


  'Waitms 1
   T_array_enable(1) = 1                                    'Организация Таймера 1 Мсек

 End If

   If T_array_event(1) = 1 Then
       T_array_event(1) = 0
       T_array_enable(1) = 0
    Else
         Goto T_1                                           ' пропускаем часть программы по таймеру
   End If


   Reset Ce
   'Table_data_nrf24(27) = 0                                 '                     в ячейку 28 помещаем номер слова который нужно сохранить на беспроводном устройстве  и после передачи обнуляем



                                          If Irq = 0 Then
      Call R_register(status , 1)
      Temp = B_bytes(1) And &B01110000                      'Маски IRQ бит, байт состояния

      Select Case Temp                                      'Который IRQ происходит
               Case Max_rt                                  'MAX_RT
               'Print "Максимальное количество повторных попыток, TX Flussing TX буфера сейчас!"
               D_bytes(1) = Flush_tx                        'Флеш TX буфера
               Call W_register(1)
               D_bytes(1) = Write_reg + Status
               D_bytes(2) = &B00010000                      'Очистить MAX_RT IRQ бит
               Call W_register(2)
               Tx_mode = 3
               'Waitms 10

      Case Tx_ds                                            'TX_DS
               'Print "Пакет" ; Packet_count ; "отправить и ACK-ответ"
               D_bytes(1) = Write_reg + Status
               D_bytes(2) = &B00100000                      'Clear the TX_DS IRQ bit
               Call W_register(2)
'Waitms 10
                Table_data_nrf24(32) = 0                    'очищаем признак записи при успешном выполнении
               '111111111111111111111111111111111111111111            11111111111111111111111111111111111
                Gosub Enable_rx

               '111111111111111111111111111111111111111111            11111111111111111111111111111111111

      Case Else                                             'Другое IRQ?
               Tx_mode = 3
               'Print "Другие irq" ; Bin(temp)
               D_bytes(1) = Flush_tx                        'Флеш TX буфера
               Call W_register(1)
               D_bytes(1) = Write_reg + Status
               D_bytes(2) = &B01110000                      'Очистить TX_DS IRQ бит
               Call W_register(2)
               'Tx_mode = 3             надо проверить как будет работать при таком положении

      End Select
                                          End If


                                                  End If

T_1:                                                        'переход по не таймеру 1

  ''''''''''''''''''''''''''''''''''                 режим передачи    '''''''''''''''''''''''''''''''


Gosub T_timers                                              ' обработка таймеров организованных на счетчиках основного цикла



       '******************************************* обработка принятого фрейма модбас ********************************

    If Md_t_start = 1 Then                                  '  если время между принятыми байтами больше 3.5 символа (примерно 21 мсек) то в буфере принят фрейм



    Md_t_start = 0                                          ' обнуляем все признаки

    Error_mod = 0                                           ' обнуляем ошибку и начинаем разбирать принятый фрейм из буфера.


       If Mbuf(1) > 199 And Mbuf(1) < 251 Then
            Remote_device = 1

          If Mbuf(1) <> Modbus_slave_nrf24 Then
            Modbus_slave_nrf24 = Mbuf(1)
            Gosub Setup_nrf
            'Gosub Setup_nrf_adress
          End If
        Else
            Remote_device = 0
       End If
  If Mbuf(1) = Modbus_slave Or Mbuf(1) = 0 Or Remote_device = 1 Then       'первый байт это адрес устройства

 '&&&&&&&&&&&&&&&&&&&&&&&&&&&&7 здесь разбор откуда брать. Из шлюза или из беспроводного.


      'Table_data(1) = T_vozd
     'Table_data(2) =
     'Table_data(3) =
     'Table_data(4) = Ust_0_min
     'Table_data(5) = Ust_0_max
     'Table_data(6) =
     'Table_data(7) =
     'Table_data(8) =
     'Table_data(9) =
     Table_data(10) = Plc_reset

     'Tmp_word = Load_timer / 250
     'Table_data(11) = Tmp_word
     'Table_data(12) =
     'Table_data(13) =
     'Table_data(14) =
     'Table_data(15) =
     'Table_data(16) =
     'Table_data(17) =
     'Table_data(18) =
     'Table_data(19) =
     'Table_data(20) =
     Table_data(21) = Modbus_slave
     'Table_data(22) =
     'Table_data(23) = Temp_timer3
     'Table_data(24) =
     'Table_data(25) = Avto
     Table_data(26) = Modbus_slave_nrf24
     'Table_data(27) = Menu_mode

 '&&&&&&&&&&&&&&&&&&&&&&&&&&&&7 здесь разбор откуда брать. Из шлюза или из беспроводного.

      Tmp_byte = Modc - 1                                   ' вычисляем адреса для расчета CRC
      Tmp_byte2 = Modc                                      ' вычисляем адреса для расчета CRC
      Modw = Makeint(mbuf(tmp_byte) , Mbuf(tmp_byte2))      ' считываем из принятого фрейма  CRC
      Tmp_byte = Modc - 2                                   ' вычисляем адреса для расчета CRC
      Tmp = Crcmb(mbuf(1) , Tmp_byte)                       ' вычисляем  CRC из фрейма принятых данных
      Modc = 0
      If Modw = Tmp Then                                    ' сравниваем расчитанный CRC и принятый CRC
                                                  'справедливо для функций 3,4 и 5,6.Если будут другие функции кроме 3,4 или 5,6 то  добавить сравнение с функциями
       Beg_adr = Makeint(mbuf(4) , Mbuf(3))
       Incr Beg_adr                                         'адрес региста чтения  (увеличиваем на 1 так как индекс массива начинается от 1, а адресация идет с 0 - 4000 адрес)


                                                             'второй байт это номер функции
        Select Case Mbuf(2)
                Case 3:                                     'функция 3- чтение регистров
                 N_word = Makeint(mbuf(6) , Mbuf(5))        'количество слов чтения
                 If N_word > 27 Then                        'я ограничил количество 27 словами
                    N_word = 1                              ' формируем ошибку если в запросе на чтение больше 27 слов
                    Error_mod = 2                           'если превышение размера буфера то формируем ошибку 2 - неправильный адрес
                 End If
                 N_byte = N_word + N_word                   'количество слов переводим в кол. байт
                 Mbuf(3) = N_byte                           'кол считываемых байт byte count wieviele Bytes sollen gesendet werden
                 Tmp_byte = 4                               'начинаем считать с 4-го байта(1-ый байт данных)

                 Tmp_byte2 = Beg_adr + N_word               'формируем индекс количества слов с учетом смещения от начального адресаа
                 For I = Beg_adr To Tmp_byte2               'цикл записи в буфер обмена запрашиваемого количества слов

                  Select Case Remote_device

                   Case 0:
                     Tmp_byte_modbus = High(table_data(i))  'разбираем по байтам на старший байт !!!!!!!!!!!!!!!!!!!
                     Mbuf(tmp_byte) = Tmp_byte_modbus       ' запись в буфер обмена  с разбивкой на байты (таблица данных)
                     Incr Tmp_byte                          '
                     Tmp_byte_modbus = Low(table_data(i))   'разбираем по байтам на младший байт
                     Mbuf(tmp_byte) = Tmp_byte_modbus       'запись в буфер обмена  с разбивкой на байты (таблица данных)
                     Incr Tmp_byte                          '
                   Case 1:
                     Tmp_byte_modbus = High(table_data_nrf24(i))       'разбираем по байтам на старший байт !!!!!!!!!!!!!!!!!!!
                     Mbuf(tmp_byte) = Tmp_byte_modbus       ' запись в буфер обмена  с разбивкой на байты (таблица данных)
                     Incr Tmp_byte                          '
                     Tmp_byte_modbus = Low(table_data_nrf24(i))       'разбираем по байтам на младший байт
                     Mbuf(tmp_byte) = Tmp_byte_modbus       'запись в буфер обмена  с разбивкой на байты (таблица данных)
                     Incr Tmp_byte                          '


                  End Select
                 Next I

              N_byte = N_byte + 3                           'номер последнего байта передаваемых в посылке слов с данными (таблица данных) 3-количество байт перед данными (номер устройства, функция, количество передаваемых слов )
              Modw = Crcmb(mbuf(1) , N_byte)                ' create checksum
              Incr N_byte                                   'номер предпоследнего байта во всей посылке   ()  (CRC LOW)
              Mbuf(n_byte) = Low(modw)                      'Checksumme LOWer Byte
              Incr N_byte                                   'номер последнего байта  во всей посылке (CRC High)
              Mbuf(n_byte) = High(modw)                     'Checksumme HIGHer Byte

                Case 6:                                     'функция 6- запись одного регистра
                         Select Case Remote_device
                                 Case 0:
                                        Table_data(beg_adr) = Makeint(mbuf(6) , Mbuf(5))       'записываем полученное значение
                                        W_to_device = 1     'формируем признак записи в устройство
                                        N_byte = 8          'длина посылки для функции 6 всегда =8 байт
                                        Beg_adr_w = Beg_adr 'номер слова для записи в память

                                 Case 1:


                                        'If Beg_adr < 6 Then
                                        '     Select Case Beg_adr
                                        '
                                        '              Case 1 : N_to_write = 1
                                        '              Case 2 : N_to_write = 3
                                        '              Case 3 : N_to_write = 5
                                        '              Case 4 : N_to_write = 7
                                        '              Case 5 : N_to_write = 9
                                        '        Case Else
                                        '     End Select


                                        'Table_data_nrf24(32) = Beg_adr       'записываем адрес по которому надо записать данные на беспроводном устройстве
                                        'Table_data_nrf24(n_to_write) = Mbuf(6)       'записываем полученное значение
                                        'Table_data_nrf24(n_to_write + 1) = Mbuf(5)



                                       'Else

                                            Beg_adr = Beg_adr
                                            Table_data_nrf24(32) = Beg_adr       'записываем адрес по которому надо записать данные на беспроводном устройстве
                                            Table_data_nrf24(beg_adr) = Makeint(mbuf(6) , Mbuf(5))       'записываем полученное значение
                                           ' Table_data(11) = Beg_adr       'тест и ртладка
                                           ' Table_data(12) = Table_data_nrf24(beg_adr)       'тест и ртладка
                                        'End If




                                 End Select



               Case Else:
                      Error_mod = 1                         'неподдерживаемая функция

        End Select


           If Error_mod > 0 Then
              'Call Error_modbus                             'код ошибки неправильный функциональный код
           End If
        S_t_m = 1
           'Call Send_to_master                              'ответ мастеру

        Else                                                'если неправильная контрольная сумма
                Error_mod = 3                               'код ошибки Checksumme
                'Call Error_modbus
                S_t_m = 1
                'Call Send_to_master                         'ответ мастеру
      End If
    End If


  End If


If S_t_m = 1 Then
   S_t_m = 0

   If Error_mod > 0 Then
      Call Error_modbus
      Call Send_to_master
    Else
      If Remote_device = 1 Then
         Tx_mode = 1                                        ' вызов Send_to_master после получения ответа от беспроводного устройства                                      '
       Else
       Call Send_to_master
      End If
   End If

End If



   '**************************************************************************************************************



                      'запись  полученных данных по модбас в энергонезависимую пямять
      If W_to_device = 1 Then                               'при наличии признака записи в устройство (уставки, настройки, выходыи т.д.)
         W_to_device = 0
         'Lcd_refrsh = 1
         Select Case Beg_adr_w                              'при записи (функция 6) Beg_adr = индексу в массиве  Table_data

            Case 1 :
                               'T_pol
            Case 2 :
                               'T_vozd
            Case 3 :
                               'Pw
            Case 4 :
                             ' Ust_0_min = Table_data(beg_adr_w)
                             ' Ust_0_min_dev = Ust_0_min


            Case 5 :                                        ' Ust_0_max = Table_data(beg_adr_w)
                            ' Ust_0_max_dev = Ust_0_max


            Case 6 :                                        'Ust_0_min = Table_data(beg_adr_w)
                                                             'Ust_0_min_dev = Ust_0_min

            Case 7 :                                        'Ust_1_min = Table_data(beg_adr_w)
                                                             'Ust_1_min_dev = Ust_1_min

            Case 8 :
                                                             'Ust_0_max = Table_data(beg_adr_w)
                                                             'Ust_0_max_dev = Ust_0_max

            Case 9 :                                        'Ust_1_max = Table_data(beg_adr_w)
                                                             ' Ust_1_max_dev = Ust_1_max

            Case 10 :
                              Plc_reset = Table_data(beg_adr_w)
            Case 11 :
                              'Ki = Table_data(beg_adr_w)
            Case 12 :                                       ' адрес 4011 -   (читать писать)
                       'Kd = Table_data(beg_adr_w)           'запись в энергонезависимую память
            Case 13 :                                       ' адрес 4012 -  (читать писать)
                       'Max_error = Table_data(beg_adr_w)    'запись в энергонезависимую память

            Case 14:                                        'адрес датчика темпертуры

            Case 15:                                        'температура временная отладка
            Case 21 :                                       ' адрес 4020 - номер устройства в сети модбас (читать писать)
                       Modbus_slave = Table_data(beg_adr_w) 'запись в энергонезависимую память
                       Modbus_slave_dev = Modbus_slave

            Case 22:
                       Tmp_word = Table_data(beg_adr_w) * 250       ' (в одной мсек 250 тиков)
                       If Tmp_word < 500 Then Tmp_word = 500
                       Load_timer = Tmp_word                ' (timer0 16 mhz 256 =1,048576 сек  1 тик=0,000016сек=0,016мсек  64=0,262144 сек)
                       Load_timer_device = Load_timer
                       Load Timer1 , Load_timer
            Case 24 :
            Case 25 :                                       'Avto = Table_data(beg_adr_w)
                       'Avto_device = Avto
           'Portc = Low(table_data(beg_adr))
                     'tmp_byte = Low(table_data(beg_adr_w))
                     'Avto = Tmp_byte.0
                     'Avto_light = Avto

           Case 26 :

           Case 27 :                                        'Menu_mode = Table_data(beg_adr_w)

         End Select

      End If


  If Plc_reset = 1 Then
      Wait 3                                                'удаленная перезагрузка контроллера
  End If



Reset Watchdog
Loop


'Sub подпрограмм
Sub W_register(byval C_bytes As Byte)                       'Пишите зарегистрировать с SPI
Reset Ss                                                    'Руководство управления СС контакт, установить СС низких до смещение, байт
Spiout D_bytes(1) , C_bytes                                 'Shiftout байты данных SPI корыта, C_bytes это количество байт, которые будут написаны
Set Ss                                                      'Set СС высокого
End Sub

Sub R_register(byval Command As Byte , Byval C_bytes As Byte) As Byte       'C_bytes = Count_bytes, номер off байт для чтения
Reset Ss                                                    'Ручное управление СС контакт, установить на низком уровне до переход в/из байт
Spiout Command , 1                                          'Первый shiftout в реестр, который будет читать
Spiin B_bytes(1) , C_bytes                                  'Прочитал назад байты из SPI направлять по nRF20L01
Set Ss                                                      'Установить СС обратно на высоком уровне
End Sub



Sub R_register2(byval Command As Byte , Byval C_bytes As Byte) As Byte       'C_bytes = Count_bytes, номер off байт для чтения
Reset Ss                                                    'Ручное управление СС контакт, установить на низком уровне до переход в/из байт
Spiout Command , 1                                          'Первый shiftout в реестр, который будет читать
Spiin B_bytes2(1) , C_bytes                                 'Прочитал назад байты из SPI направлять по nRF20L01
Set Ss                                                      'Установить СС обратно на высоком уровне
End Sub


Setup_nrf:                                                  'Подготовка к NRF инициализация
'Modbus_slave_nrf24 = 200
D_bytes(1) = Write_reg + Rx_addr_p0                         'RX адрес для pipe0 (5 байтовый адрес) при передаче RX адрес и  TX адрес должны быть одинаковыми
D_bytes(2) = &H34
D_bytes(3) = &H43

D_bytes(4) = &H10
D_bytes(5) = &H10
D_bytes(6) = Modbus_slave_nrf24                             '&H01                                           'Hex(modbus_slave_nrf24)
Call W_register(6)

D_bytes(1) = Write_reg + Tx_addr                            'TX адрес            (5 байтовый адрес)
D_bytes(2) = &H34
D_bytes(3) = &H43

D_bytes(4) = &H10
D_bytes(5) = &H10
D_bytes(6) = Modbus_slave_nrf24                             '&H01                                           'Hex(modbus_slave_nrf24)
Call W_register(6)                                          'Отправить 6 байт для SPI

D_bytes(1) = Write_reg + En_aa                              'Enable auto ACK на pipe0
D_bytes(2) = &H01
Call W_register(2)

D_bytes(1) = Write_reg + En_rxaddr                          'Включить RX адрес для pipe0
D_bytes(2) = &H01
Call W_register(2)

D_bytes(1) = Write_reg + Rf_ch                              'Настройка каналов
D_bytes(2) = 40
Call W_register(2)

D_bytes(1) = Write_reg + Rx_pw_p0                           'Set RX pload ширина для pipe0    (принимаем только 32 байт)
D_bytes(2) = 32
Call W_register(2)

D_bytes(1) = Write_reg + Rf_setup                           'Настройка РФ -> Выходной мощности 0 дБм, datarate 2 Мбит / с и МШУ прибыль по
D_bytes(2) = &H0F
Call W_register(2)

D_bytes(1) = Flush_tx                                       'Flush the TX_fifo буфера
Call W_register(1)

D_bytes(1) = Write_reg + Status                             'Reset IRQ бит
D_bytes(2) = &B0111000
Call W_register(2)


Return

Setup_nrf_adress:
'Modbus_slave_nrf24 = 200
D_bytes(1) = Write_reg + Rx_addr_p0                         'RX адрес для pipe0 (5 байтовый адрес) при передаче RX адрес и  TX адрес должны быть одинаковыми
D_bytes(2) = &H34
D_bytes(3) = &H43

D_bytes(4) = &H10
D_bytes(5) = &H10
D_bytes(6) = Modbus_slave_nrf24                             'Hex(modbus_slave_nrf24)
Call W_register(6)

D_bytes(1) = Write_reg + Tx_addr                            'TX адрес            (5 байтовый адрес)
D_bytes(2) = &H34
D_bytes(3) = &H43

D_bytes(4) = &H10
D_bytes(5) = &H10
D_bytes(6) = Modbus_slave_nrf24                             'Hex(modbus_slave_nrf24)
Call W_register(6)                                          'Отправить 6 байт для SPI

Return
Enable_rx:
Reset Ce
Tx_mode = 0

   D_bytes(1) = Write_reg + Status                          'Сброс RX_DR бит состояния
   D_bytes(2) = &B01000000                                  'Напиши 1 до RX_DR бит для сброса IRQ
   Call W_register(2)


D_bytes(1) = Write_reg + Config_nrf                         'Настройка CONFIG -> I=1 (RX_device), PWR_UP=1, CRC 2bytes, Включить CRC
D_bytes(2) = &H0F
Call W_register(2)

Waitms 2
Set Ce                                                      'Set nRF20L01 в режиме приема
Return

Enable_transmit:
 Tx_mode = 1

D_bytes(1) = Flush_tx                                       'Flush the TX_fifo буфера
Call W_register(1)
D_bytes(1) = Write_reg + Status                             'Reset IRQ бит
D_bytes(2) = &B01110000
Call W_register(2)
D_bytes(1) = Write_reg + Config_nrf                         'Настройка CONFIG -> I=0 (TX_device), PWR_UP=1, CRC 2bytes, Включить CRC
D_bytes(2) = &H0E
Call W_register(2)

Return

  Sub Timers(byval T_number As Byte , Byval T_period As Word , Byval T_enable As Byte )
    T_array_enable(t_number) = T_enable
    T_array_count(t_number) = 0
    T_array_event(t_number) = 0
    T_array_period(t_number) = T_period
'(  функция Timers(T_Number,T_period,T_Enable)
                               T_Number-номер таймера; T_period-заданное время;  T_Enable старт/стоп таймера;
                               T_Number- указатель на номер таймера
                               T_period- требуемое время таймера
                               T_Enable- если 1 то сбрасываем текущее значение и запускаем таймер Если 0 то сбрасываем таймер.
     для работы таймеров надо в основном цикле вызывать подпрограмму T_timers .
     Если надо организовать задержку, то (предварительно вызвав Timers - эту подпрограму с заданными параметрами. можно вызвать и вне основного цикла)
     запускаем таймер присвоив значение  T_array_enable(t_number)=1. Таймер сработает если  T_array_count(t_number) = 1

')


End Sub


T_timers:
 Incr T_counter
 If T_counter > 150 Then                                    '150 циклов оновной програмы грубо равны 1 мсек  (значение можно изменять до требуемой точности)
     T_counter = 0

     For Y = 1 To N_timers

          If T_array_enable(y) = 1 And T_array_event(y) = 0 Then
             Incr T_array_count(y)
             If T_array_count(y) > T_array_period(y) Then
                T_array_event(y) = 1
                T_array_count(y) = 0
             End If
          End If

     Next Y

 End If

 Return



  '_______________________________MODBUS_________________________________________
 '-------- interrupt handler for the URXC interrupt ----------------------------
  Urxc_isr:                                                 '  прерывание по приему данных
   sbis usr,7                                               ' Wait for character
   rjmp urxc_isr                                            ' wait until we can read the byte
  Modt = Udr                                                ' get the byte
  ' Load_timer = 65000                             'устанавливаем значение тишины между фреймами
 'Avto_light = 1
  Load Timer1 , Load_timer
  Start Timer1                                              'стартуем таймер фрейма
  Incr Modc_frame                                           'увеличиваем счетчик принятого байта
  Mbuf_frame(modc_frame ) = Modt                            ' пишем в буфер значение принятого байта

 Return

 Utxc_isr:
                                                    'Подпрограмма передачи данных
  'If Cnt_print = 1 Then                                     '  Косвенный признак того что буфер на передачу заполнен

 Enable_tx = 0                                              'переключаем передачу на прием
 'Cnt_print = 0                                              ' сбрасываем флаг заполнения буфера
 'End If


 Return

  Udre_isr:
  'sbis ucsra,udr
  If Cnt_print = 1 Then                                     '  Косвенный признак того что буфер на передачу заполнен
     Disable Udre
     Enable_tx = 0                                          'переключаем передачу на прием
     Cnt_print = 0                                          ' сбрасываем флаг заполнения буфера

 End If



Return



 Sub Send_to_master
     Enable_tx = 1
     For I = 1 To N_byte                                    'ответ мастеру.  цикл для передачи буфера обмена с заданным кол. байт c заданного адреса
     Print Chr(mbuf(i));                                    'отправка буфера обмена в Нех
     'Printbin Mbuf(i);N_byte                                      ' если ипользовать Printbin  то ошибка CRC
     Next
 End Sub

 Sub Error_modbus                                           'функция формирования пакета исключительного ответа мастеру по ошибке.
      Mbuf(2).7 = 1                                         ' 1дрес,2функц.код с 1(единицей),3код ошибки,4,5CRC всего 5 байт
      Mbuf(3) = Error_mod                                   'код ошибки (1- неправильный фунциональный код(неподдерживаемая функция); 2- неправильный адрес; 3- неправильные данные (CRC). )
      Modw = Crcmb(mbuf(1) , 3)                             ' create checksum
      Mbuf(4) = Low(modw)                                   'Checksumme LOWer Byte
      Mbuf(5) = High(modw)                                  'Checksumme HIGHer Byte
      N_byte = 5
      Error_mod = 0
 End Sub




 Modbus_timers:                                             'прерывание по таймеру.
  Stop Timer1
 'Load Timer1, Load_timer
 Md_t_start = 1                                             'выставляем признак того, что в буфере принят фрейм

 Modc = Modc_frame
 Modc_frame = 0

 'Mbuf = Mbuf_frame
 For N = 1 To Modc
     Mbuf(n) = Mbuf_frame(n)                                'выставляем признак того, что в буфере принят фрейм
     Mbuf_frame(n) = 0
  Next

 Return

+2


Вы здесь » Программирование ATMEL в BASCOM. » Исходники » эксперименты с радиомодулем NRF24L01+