В начало | Зарегистрироваться | Заказать наши киты почтой
 
 
 
 

Беспроводной канал связи 2,4 ГГц на базе трансивера nRF24L01+ от Nordic Semiconductor. Часть 3

📆31 июля 2016   ✒️erbol   🔎23.603   💬19  

Приветствую всех настоящих и будущих поклонников отладочной платы Arduino! Сегодня, в завершение темы о трансивере nRF24L01+, мы, обобщив всю информацию, которая была изложена ранее, и добавив немного новой, соберём и запустим вот такое устройство.

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

Всё, что нам понадобится, перечислено ниже.
1) Среда программирования Arduino IDE 1.6.х и выше, которую можно скачать на сайте компании arduino.cc. Возможно, она уже установлена у вас.
2) Плата Arduino UNO или Nano с USB-шнуром
3) 1.8-дюймовый TFT-дисплей на базе ST7735S
4) Два радио-модуля nRF24L01+
5) Микроконтроллер ATtiny85
6) Термометр-датчик DS18B20
7) Резистор на 4.7 кОм
8) Макетная плата – бредборд
9) Соединительные провода
10) Две батарейки на 1.5 В Если всё это есть у вас в наличии, приступим!

Знакомим Arduino IDE и ATtiny85

В стандартной конфигурации Arduino IDE не в состоянии распознать, а тем более прошить ATtiny85, поскольку не имеет в своём составе соответствующих файлов.

Решить эту задачу можно несколькими путями: написать эти файлы самому, найти их в интернете и поместить в нужные папки. Но, учитывая, что мы – начинающие, пойдём третьим, самым простым путём.

Запускаем Arduino IDE и переходим в меню «Файл > Настройки»

Выйдет окно настроек, в поле «Дополнительные ссылки для Менеджера плат», которого вставьте следующую ссылку:
https://raw.githubusercontent.com/damellis/attiny/ide-1.6.x-boards-manager/package_damellis_attiny_index.json

Жмём «Ок» и перезагружаем Arduino IDE. После перезагрузки переходим в «Инструменты > Менеджер плат»

Появится окно со списком плат, в самом низу которого вы увидите и наш МК. Кликните левой клавишей мышки в районе надписи «ATtiny85». При этом поле должно затемниться и появится кнопка «Установка».

Жмём её, ждём завершения установки, после чего закрываем Менеджер плат.

При установке автоматически создаётся папка «C:\Arduino\hardware\attiny\avr», в которой и хранятся файлы, обеспечивающие добрые отношения между Arduino IDE и ATtiny85. К ним мы ещё вернемся.

Вновь переходим в «Инструменты > Менеджер плат», но теперь уже в списке плат появилась группа «ATtiny».

Вот мы и подружили Arduino IDE с ATtiny85.

Превращаем Arduino в программатор и прошиваем ATtiny85

Пройдём в «Инструменты» и убедимся, что там выставлены нужные нам параметры:
1. Плата: Arduino UNO (или Nano),
2. Порт: COM-порт, к которому подключена Arduino,
3. Программатор: «AVR ISP».

Открываем скетч «ArduinoISP» из «Файл > Примеры > ArduinoISP»

и загружаем его в Arduino, нажав иконку Беспроводной канал связи 2,4 ГГц на базе трансивера nRF24L01+ от Nordic Semiconductor. Часть 3, либо «Скетч > Загрузка».
Соединяем Arduino и ATtiny85 по следующей схеме.

В интернете рекомендуют подключать конденсатор между выводами Reset и GND Arduino, но я благополучно обхожусь без него.

Далее переходим в «Инструменты» и выбираем следующие параметры:
1. Плата: «Attiny»
2. Процессор: «ATtiny85»
3. Clock: «8 MHz (internal)», поскольку в нашем проекте использовать внешний кварцевый резонатор мы не будем, а при выборе частоты 1 MHz временные интервалы искажаются настолько, что библиотека OneWire.h, которую мы будем использовать, перестаёт работать корректно.
4. Порт: COM-порт, к которому подключена Arduino
5. Программатор: «Arduino as ISP».

Жмём «Записать Загрузчик» и ждём появления в указанном поле сообщения об успешной загрузке.

Может создаться ложное впечатление, будто мы только что залили в ATtiny85 т.н. «загрузчик» - бутлоадер. На самом деле это не так. Те, кому это интересно, могут пройти в папку «C:\Program Files\Arduino\hardware\arduino\avr». Она аналогична упомянутой выше папке «avr», но содержит файлы уже для самой Arduino. Как видите в нашей папке отсутствует папка «bootloaders». Кроме того, если вы откроете файлы «boards» и сравните их содержимое, то обнаружите, что в файле для ATtiny85 нет строки с указанием пути к бутлоадеру, а вот в файле для Arduino обязательно найдутся строки типа:
atmega328.bootloader.file=atmega/ATmegaBOOT_168_atmega328.hex

Что же кроется под надписью «Записать Загрузчик» в случае ATtiny85? Ответ мы найдём в следующих строках из файла «boards»:
attiny.menu.clock.internal8=8 MHz (internal)
attiny.menu.clock.internal8.bootloader.low_fuses=0xe2
attiny.menu.clock.internal8.bootloader.high_fuses=0xdf
attiny.menu.clock.internal8.bootloader.extended_fuses=0xff
attiny.menu.clock.internal8.build.f_cpu=8000000L

Как вы догадались, только что мы сконфигурировали фьюзы и установили выбранную тактовую частоту.

Ну что ж, теперь мы готовы залить в ATtiny85 скетч или, говоря по-другому, прошить, запрограммировать его. Используем неувядающую классику - откроем скетч: «Файл > Примеры > Basics > Blink»

Здесь нас ждёт сюрприз – скетч попеременно выводит логические 1 и 0 на вывод D13, а у нас их всего 5, без учёта пина Reset. Чем заменить число «13» и какую нотацию понимает Arduino IDE – привычную ардуинщикам (D0 – D5) или академическую (PB0 – PB5)?

Чтобы понять это, вернемся к нашей папке «avr», откроем файл «pins_arduino.h» из папки «variants\tiny8» и найдём следующую информацию:

Как видно, вы можете использовать обе нотации. В привычном варианте скетч «Blink» будет выглядеть так:
void setup() 
{
  pinMode(1, OUTPUT);
}

void loop() 
{
  digitalWrite(1, HIGH);   
  delay(1000);              
  digitalWrite(1, LOW);    
  delay(1000);              
}

Вносим изменения и жмём «Скетч > Загрузить через программатор»

После завершения загрузки можете подключить через резистор 1 кОм светодиод к соответствующему пину ATtiny85 (в нашем случае это - вывод 6, PB1 или D1 в ардуиновской нотации) и наблюдать аппаратное «Hello, World!».

Хочу обратить ваше внимание на один важный момент. Если вы будете использовать одну и ту же тактовую частоту для ATtiny85 в разных проектах, то процедура конфигурирования фьюзов, приведённая выше, делается для конкретного микроконтроллера только один раз, а далее только загружаются написанные вами скетчи.
В случае, если новый проект потребует изменения тактовой частоты, придется выбрать соответствующее значение в строке «Clock» и заново сконфигурировать фьюзы.


Собираем и запускаем беспроводной электронный термометр

Создайте у себя на компьютере папку с понравившимся названием (или не мудрствуя - «Термометр») и скачайте туда папки «transmitter» и «receiver» из архива в конце статьи.

Поскольку на данный момент ATtiny85 соединён с Ардуино, сама отладочная плата сконфигурирована как программатор, а в IDE выставлены параметры «тиньки», разумнее начать с передатчика.

Открываем скетч «transmitter» из соответствующей папки и загружаем его в ATtiny85, точно так же, как мы это делали со скетчем «Blink».
Отсоединяем ATtiny85 от Ардуино и собираем передатчик по этой схеме.

Возможно, кому-то из вас из соображений схемотехники понадобится изменить порядок соединения выводов nRF24L01+ и ATtiny85. В этом случае найдите во вкладке «defines.h» скетча «transmitter» строки, отмеченные красным на рисунке ниже, и переназначьте выводы микроконтроллера в соответствии с вашим выбором.

Передатчик готов!
Как только вы подадите 3 В от двух батареек на выводы 8 и 4 ATtiny85, модуль начнёт выдавать в эфир значение температуры.

Перейдём к принимающей части. Выставляем в Arduino IDE параметры для работы с Ардуино:
1. Плата: Arduino UNO (или Nano)
2. Порт: COM-порт, к которому подключена Arduino
3. Программатор: «AVR ISP».

Открываем скетч «receiver» из скачанного датагорского архива и прошиваем его в плату любым освоенным способом.
Отсоединяем на всякий случай USB-шнур от платы и собираем приёмник по следующей схеме.

Подключаем питание через USB-шнур и наблюдаем на дисплее температуру, переданную «по воздуху» от датчика ds18b20.

Алгоритм работы нашего термометра и настройка его параметров

Алгоритм работы устройства озвучен в видеоролике, но всё же повторюсь. Передающий модуль работает следующим образом.
1. Один раз в 8 секунд ATtiny85 выходит из состояния Power Down по прерыванию сторожевого таймера.
2. Производит опрос термодатчика ds18b20.
3. Выводит трансивер из такого же состояния Power Down.
4. Отправляет в эфир два байта со значением температуры
5. Погружает трансивер обратно в спячку.
6. Сам уходит в сон.

Почему именно 1 раз в 8 секунд происходит измерение и можно ли изменить этот параметр? Указанный период – максимальное возможное время, по истечении которого сторожевой таймер будит микроконтроллер. Уменьшать это время нет смысла, поскольку измерять так часто температуру вряд ли кто-то будет, к тому же это сведёт на нет энергосбережение.
А вот увеличить период измерений аппаратными средствами уже не получится, поэтому в скетче предусмотрен программный вариант. Откройте упомянутую выше вкладку «defines.h» скетча «transmitter» и пройдите к самой нижней строке.

Числовое значение в этой строке – количество периодов по 8 секунд, после которого ATtiny85 станет измерять температуру и будить трансивер, чтобы отправить данные.

Если это значение будет больше единицы, п.1 алгоритма изменится следующим образом:
1. Один раз в 8 секунд ATtiny85 выходит из состояния Power Down по прерыванию сторожевого таймера, увеличивает программный счётчик на 1 и сравнивает получившееся число со значением WDT_LIMIT. Если они не равны, микроконтроллер перескакивает на п.6, т.е. засыпает. При равенстве значений – переходит к п.2.
Какое именно значение WDT_LIMIT выставить – решать вам. Просто имейте в виду, что, когда и микроконтроллер, и трансивер находятся в режиме Power Down, энергопотребление модуля сводится к минимуму - 0.9 мА, а самый большой расход энергии происходит во время работы nRF24L01+ - около 20 мА.
Для примера скажу, что в термометре, висящем уже полгода за моим окном, прописано значение 300, т.е. измерение происходит один раз в 300х8/60 = 40 минут и батарейки я пока ещё не менял. Самое большое возможное значение для WDT_LIMIT - 32 767, что обеспечивает одно измерение за 3 суток.

В отличие от передатчика, приёмник всё время бодрствует, сканируя эфир. Как только обнаруживается пакет данных, nRF24L01+ выдаёт прерывание на Ардуино, а та считывает два байта из трансивера, переводит их в понятное нам значение температуры и выводит на дисплей.

Альтернативный передатчик

Вполне может случится так, что под рукой у вас не окажется ATtiny85, а термометр всё же захочется собрать. Проще всего можно выйти из этой ситуации при наличии ещё одной платы - Arduino UNO, причём в классическом исполнении, с микроконтроллером в корпусе DIP28, установленным на панельке.

Для начала нужно внести минимальные изменения в программу. Проходим во вкладку «wdt» скетча «transmitter» и в самой верхней функции wdt_init() исправляем надписи «WDTCR» на «WDTCSR».

Загружаем во вторую плату исправленный скетч, соблюдая следующие настройки Arduino IDE:
1. Плата: Arduino UNO
2. Порт: COM-порт, к которому подключена Arduino
3. Программатор: «AVR ISP».
Загрузим скетч на плату.

В принципе, уже сейчас можно подключить к плате трансивер и термодатчик, подать питание и получить рабочий передающий модуль. Но, во-первых, передатчик будет далёк от понятия «миниатюрный», а, во-вторых, светодиоды и дополнительные микросхемы, установленные на плате (контроллер USB, преобразователь напряжения и пр.) сведут на нет наши усилия по энергосбережению в силу своей прожорливости.
Выход прост – после загрузки скетча вынуть ATMega328P из колодки и использовать его отдельно.

Итак, скетч загружен, ATMega328P вынут из колодки, мы готовы собрать передатчик, но тут появляются нюансы.
Первый из них – напряжения питания. Стандартная конфигурация фьюзов Arduino UNO определяет минимальный порог для этого параметра в 4.1 Вольт. Поэтому, придётся добавить ещё одну батарейку на 1.5В.
На энергопотреблении это скажется не существенно, а ds18b20 работает и при таком напряжении.

Второй момент – частота тактирования. Поскольку для нашей платы она составляет 16 МГц, в схему передатчика нужно будет добавить соответствующий кварцевый резонатор, подключив его выводы к пинам PB6 (XTAL1) и PB7 (XTAL2) микроконтроллера.

Окончательно схема передатчика будет выглядеть так.

Питание надо подавать, как вы поняли, на выводы 7 (+VCC) и 8 (GND) чипа ATMega328P.

Всё изложенное можно осуществить и в случае, если единственная имеющаяся у вас плата - именно такая, как на рисунке выше, плюс к этому вы располагаете микроконтроллером ATMega328P с уже залитым в бутлоадером.

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

Алгоритм ваших действий будет таким же, только после того, как из платы будет вынут ATMega328P с программой передатчика, вы поместите на его место другой микроконтроллер и загрузите скетч приёмника.

Снова экономим ноги МК. Особенности программного кода и пр.

Этот раздел для тех, кто читал предыдущие части статьи. Вы, наверное, заметили странности соединения микроконтроллера и радио-модуля в передатчике – отсутствует линия MISO, как и резистор, который мог бы подразумевать объединение выводов MOSI и MISO в MOMI и, в то же время, оставлена линия CE.

Дело в том, что в данном проекте нужен лишь один дополнительный вывод - для ds18b20. Поэтому я решил использовать, а заодно показать вам, ещё один способ экономии выводов.
Базируется он на двух допущениях.
1. nRF24L01+ работает только как передатчик
2. Мы чётко представляем, какие процессы происходят в трансивере в тот или иной момент времени.
При соблюдении этих условий нам не надо знать содержимое регистра STATUS, а значит протокол SPI можно реализовать без линии MISO.

Тогда известные вам функции программного SPI для передатчика будут выглядеть вот так:
void SPI_init(void)
{
  nRF_DDR = (1<<CE_pin) | (1<<SCK_pin) | (1<<CSN_pin) | (1<<MOSI_pin);
  sbi(CSN_pin);  
}

void SPI_byte(uint8_t byte)
{
  for(uint8_t counter = 8; counter; counter--)
    {
      if (byte & MSBit)
        sbi(MOSI_pin);
      else
        cbi(MOSI_pin);
      
      sbi(SCK_pin); 
      cbi(SCK_pin); 
      
      byte <<= 1;
    }
}


Есть и другие изменения в коде, причём как для передатчика, так и для приёмника. Связаны они с тем, что значение температуры выдаётся термодатчиком двумя байтами.
Можно конечно отправлять их по одному, но такой вариант, во-первых, требует хоть чуть-чуть, но всё же больше времени (читай - энергии), а, во-вторых, повышает риски частичной утери данных и, как следствие, искажения показаний на дисплее.

Поэтому к макроопределениям было добавлено ещё одно:
#define PAYLOAD_SIZE     2

а функции nRF_read_register() и nRF_write_register() универсализированы для работы с любым количеством байт и приведены к следующему виду:
uint8_t nRF_read_register(uint8_t reg, uint8_t* buf, uint8_t len)
{
  uint8_t status;
  cbi(CSN_pin);  
  status = SPI_byte(reg);
  while(len--)
    {
      *buf++ = SPI_byte(NOP);    
    }
  sbi(CSN_pin); 
  return status;
}

void nRF_write_register(uint8_t reg, uint8_t* buf, uint8_t len)
{ 
  reg |= W_REGISTER; 
  cbi(CSN_pin);
  SPI_byte(reg); 
  while (len--)
    {
      SPI_byte(*buf++);
    }
  sbi(CSN_pin);  
}

Функция nRF_command() по-прежнему оперирует одним байтом, поэтому не претерпела изменений.

Функции передатчика в настоящем проекте будут выглядеть следующим образом:
void nRF_flush_status(void)
{
  uint8_t mask = (1<<RX_DR) | (1<<TX_DS) | (1<<MAX_RT);
  nRF_write_register(STATUS, &mask, sizeof(mask));
}

void nRF_flush_fifo(void)
{
  nRF_command(FLUSH_TX);
  nRF_command(FLUSH_RX);
}

void nRF_init(void)
{
  SPI_init(); 
  _delay_ms(100); 
  nRF_flush_status();
  nRF_flush_fifo();  
}  

void nRF_power_up(void)
{
  uint8_t mask = (1<<MASK_RX_DR) | (1<<MASK_TX_DS) | (1<<MASK_MAX_RT) | (1<<EN_CRC) | (1<<PWR_UP);
  nRF_write_register(CONFIG, &mask, sizeof(mask));
  _delay_ms(2);     
  
}

void nRF_power_down(void)
{
  uint8_t mask = (1<<MASK_RX_DR) | (1<<MASK_TX_DS) | (1<<MASK_MAX_RT) | (1<<EN_CRC);
  nRF_write_register(CONFIG, &mask, sizeof(mask));
}

void nRF_trasmit(uint8_t *payload)
{
  nRF_write_register(W_TX_PAYLOAD, payload, PAYLOAD_SIZE);
  sbi(CE_pin);
 _delay_us(15);
  cbi(CE_pin);
 _delay_us(135);  
}


А приёмника - вот так:
void nRF_set_prx(void)
{
  uint8_t mask = (1<<MASK_TX_DS) | (1<<MASK_MAX_RT) | (1<<EN_CRC) | (1<<PWR_UP) | (1<<PRIM_RX);
  uint8_t payload_size = PAYLOAD_SIZE; 
  SPI_init();   
  _delay_ms(100);  
  nRF_write_register(RX_PW_P0, &payload_size, sizeof(payload_size));     
  nRF_write_register(CONFIG, &mask, sizeof(mask));
  _delay_ms(2);  
  sbi(CE_pin);
  _delay_us(135);       
}

void nRF_receive(uint8_t* buf)
{
  nRF_read_register(R_RX_PAYLOAD, buf, PAYLOAD_SIZE); 
}

void nRF_flush_status(void)
{
  uint8_t mask = (1<<RX_DR) | (1<<TX_DS) | (1<<MAX_RT);
  nRF_write_register(STATUS, &mask, sizeof(mask));
}

void nRF_flush_fifo(void)
{
  nRF_command(FLUSH_TX);
  nRF_command(FLUSH_RX);
}

void nRF_init(void )
{
  nRF_set_prx();
  nRF_flush_status();
  nRF_flush_fifo();    
}


Ну и фрагмент основной функции для передатчика:
//в этот буфер предварительно записываются два байта, полученные из ds18b20
uint8_t ds18b20_data[PAYLOAD_SIZE];

nRF_trasmit(ds18b20_data);
nRF_flush_status();  
nRF_flush_fifo();  

и приёмника:
//в этот буфер считываются данные из трансивера
uint8_t payload[PAYLOAD_SIZE];

float temperature;

nRF_receive(payload);
temperature = (payload[1] << 8 | payload[0])/16.0;


Файлы

Коды и исходники для приёмника:
🎁receiver.7z  1.91 Kb ⇣ 165

Коды и исходники для передатчика:
🎁transmitter.7z  1.68 Kb ⇣ 172

Заключение

На этом статья о радио-модуле nRF24L01+ завершена. В случае, если у кого-то из вас возникнут вопросы, с радостью отвечу на них. При необходимости можно открыть соответствующую тему на датагорском форуме.

Спасибо всем за внимание, а тем, кому хватило сил прочитать все три части - ещё и за терпение!
Всем удачи!

Камрад, рассмотри датагорские рекомендации

🌼 Полезные и проверенные железяки, можно брать

Опробовано в лаборатории редакции или читателями.




 

Читательское голосование

Нравится

Статью одобрили 66 читателей.

Для участия в голосовании зарегистрируйтесь и войдите на сайт с вашими логином и паролем.
 

Поделись с друзьями!

 

 

Связанные материалы

 

Схема на Датагоре. Новая статья Визуализация для микроконтроллера. Часть 4. Android... Вообще то я планировал рассказать сегодня про дисплей на базе ILI9481. Однако, он настолько похож...
Схема на Датагоре. Новая статья Использование МК ATMega163, ATMega163L, ATMega16 в Arduino IDE... Популярная среда разработки Arduino IDE привлекает большим количеством готовых библиотек и...
Схема на Датагоре. Новая статья Беспроводной канал связи 2,4 ГГц на базе трансивера nRF24L01+ от Nordic Semiconductor. Часть 1... Доброго вам дня, уважаемые граждане и гости Датагор.ру - этого замечательного сообщества увлечённых...
Схема на Датагоре. Новая статья Беспроводной канал связи 2,4 ГГц на базе трансивера nRF24L01+ от Nordic Semiconductor. Часть 2... Продолжаем разговор. Как-то раз мы с пацанами решили соединить радио-модуль «nRF24L01+» вот с таким...
Схема на Датагоре. Новая статья Трансивер 2,4 ГГц Nordic Semiconductor nRF24L01. Перевод таблиц даташита, пояснения и коды для организации сети... Wireless Transceiver Module NRF24L01+ 2.4GHz, 4 шт. на Али Привет, датагорцы! Выкладываю перевод...
Схема на Датагоре. Новая статья Предварительный усилитель на аудиопроцессоре TDA7318 (TDA7313) и Arduino. Часть 2... Проект в сборе. Сборка займет у вас примерно 15 минут. В первой части статьи мы подробно...
Схема на Датагоре. Новая статья Знакомьтесь: Flowcode. Программирование для AVR и PIC без программирования... Здравствуйте, друзья! В данной статье я хочу рассказать о своих впечатлениях при работе с...
Схема на Датагоре. Новая статья Windows 10 и программаторы на базе AVR910 Prottos... Я он-лайн геймер, поэтому недавно пришлось на моём компьютере обновить ОС с MS Windows 8.1 до MS...
Схема на Датагоре. Новая статья Предварительный усилитель на аудиопроцессоре TDA7318 (TDA7313) и Arduino. Часть 1... Благодарим Тимофея Носова за идею проекта на TDA7318. При построении усилителя звуковой частоты,...
Схема на Датагоре. Новая статья Как создавать темы, отвечать, прикреплять картинки и файлы?... Создание нового вопроса, новой темыВсё просто. Новая тема = новая статья. Изучите меню по ссылке...
Схема на Датагоре. Новая статья Грызем микроконтроллеры. Урок 6. Прошиваем МК... Ну вот, писать программы для микроконтроллеров мы научились. Работоспособность прошивки тоже...
Схема на Датагоре. Новая статья Анатомия микроконтроллеров ATmega... Здравствуйте, датагорцы! После публикации моей первой статьи, меня завалили вопросами о...
 

Комментарии, вопросы, ответы, дополнения, отзывы

 

Назад Вперед
<
Читатель Датагора

erbol

<
Читатель Датагора

UA6EM

<
Читатель Датагора

erbol

Назад Вперед

Добавить комментарий, вопрос, отзыв 💬

Камрады, будьте дружелюбны, соблюдайте правила!

  • Смайлы и люди
    Животные и природа
    Еда и напитки
    Активность
    Путешествия и места
    Предметы
    Символы
    Флаги
 
 
В начало | Зарегистрироваться | Заказать наши киты почтой