В предыдущей части урока мы подключили символьный LCD-дисплей к плате приёмника, настроили для него проект, также немного подправили наши библиотеки.
Передатчик мы также используем пока только один, только для него мы заведём новый проект, сделанный из проекта урока 105 NRF24_TX и назовём его NRF24_TX_PIPE0.
Приёмник от ПК отключим, запитаем его отдельно, подключим схему передатчика вместе с программатором к ПК и займёмся нашим проектом.
Запустим его в Cube MX, ничего не трогая, сгенерируем проект для Keil, откроем его в нём, настроим программатор на автоперезагрузку, включим уровень оптимизации в 1, подключим файл NRF24.c и попробуем собрать проект.
Если проект нормально собрался, то перейдём в файл NRF24.c и прибавим там поначалу наш буфер
#define TX_PLOAD_WIDTH 7
Если мы соберём сейчас и прошьём наш проект, то у нас уже будет всё корректно передаваться
Только мы хотели ещё передавать информацию о совсем непереданных пакетах.
В принципе, у нас уже такая информация получена, так как мы считали регистр OBSERVE_TX, в котором есть оба показателя, мы данную информацию пока просто не отправляли. Поэтому в этом файле мы больше ничего не трогаем и переходим в файл main.c и сначала в функции main() немного подправим наши локальные переменные
/* USER CODE BEGIN 1 */
uint8_t dt;
uint16_t i=1,retr_cnt_full=0, cnt_lost=0;
/* USER CODE END 1 */
Теперь идём в бесконечный цикл и начинаем делать там также исправления.
Первым делом снимем все ограничения, связанные с нехваткой разрядов на индикаторе, у нас теперь таких проблем нет, у нас дисплей вместимый
if(retr_cnt_full>999) retr_cnt_full=999;
if(i>=999) i=1;
Отправим количество совсем непереданных пакетов, то есть тех, которые не передались приёмнику даже при использовании максимального количества попыток. Мы поместим их в буфер по адресу 4
memcpy(buf1+2,(uint8_t*)&retr_cnt_full,2);
memcpy(buf1+4,(uint8_t*)&cnt_lost,2);
Данные параметра из регистра с ошибками поместим сразу в нужную переменную
retr_cnt_full += dt & 0xF;
Также считаем данные о непереданных пакетах
retr_cnt_full += dt & 0xF;
cnt_lost = dt>>4;
А вот эта строчка нам теперь также будет не нужна
retr_cnt_full += retr_cnt;
Ошибки передачи пакетов считаются только до 15, затем они не сбрасываются. Сбросить их не так-то легко, но нам и не нужно. Если наберётся 15 ошибок, то уже будет ясно что у нас что-то не то и так дело не пойдёт. Поэтому нам и этого хватит с лихвой.
Уберём также из бесконечного цикла наш ранее закомментированный код, думаю, он нам не пригодится.
Соберём код прошьём контроллер и убедимся, что наши пакеты также нормально передаются.
А чтобы испробовать что у нас ошибки также считаются, то достаточно на некоторое время (секунд на 10) отключить от питания приёмник и затем его опять включить. Мы увидим вот такую картину
У нас набежало 11 ошибок, а также 165 попыток передачи, всё сходится. 11×15=165. Значит всё работает.
Можно сказать, подготовительные мероприятия к достижению цели занятия проведены. А цель занятия мы хорошо помним — передать на приёмник данные с нескольких передатчиков — а точнее с трёх.
Поэтому передатчик мы теперь также запитаем отдельно от ПК и подключим теперь следующий передатчик. собранный на удобной маленькой плате Nucleo F303K8. Данной платой мы уже пользовались в уроках по модулям HC-05, поэтому никаких сложностей по подключению к ней модуля, думаю не возникнет. Тем более, программатор и переходник USART нам к данной плате подключать не надо, в ней всё уже на борту. Подключим следующий модуль NRF к данной плате, у нас получится вот такая симпатичная схемка
Какие ножки куда подключать, можно посмотреть в проекте для Cube MX, который мы сейчас и создадим.
Запустим Cube MX, выберем наш контроллер
Включим тактирование
Включим отладку
Включим SPI
Включим USART2, может пригодится
Для ножки CS включим ножку PA4
Для ножки CE включим ножку PA8, а для ножки IRQ — ножку PA9
Также на выход включим ножку PB3, подключенную к светодиоду
Теперь настроим наши частоты во вкладке Clock Configuration (нажмите на картинку для увеличения изображения)
Теперь перейдём в Configuration и настроим шину SPI
Настроим USART
Зайдём в настройки проекта, зададим проекту имя, выберем среду программирования и путь к проекту
Сохраним настройки, сгенерируем проект и откроем его в Keil.
Настроим программатор на авторезет, включим уровень оптимизации в 1 и попробуем собрать наш проект.
Если всё нормально собралось, то из проекта нашего первого передатчика скопируем в наш новый проект файлы для модулей NRF24.c и NRF24.h. Файл NRF24.c также подключим к дереву проекта.
Ещё раз попробуем собрать проект, хоть он и, конечно, вряд ли без ошибок соберётся, но тем не менее, у нас появится возможность навигации по новым файлам.
Перейдём в файл NRF24.h и изменим там номер подключаемой библиотеки
#include "stm32f3xx_hal.h"
Также поменяем некоторые служебные ножки
#define CE_PIN GPIO_PIN_8
…
#define IRQ_PIN GPIO_PIN_9
…
#define LED_GPIO_PORT GPIOB
#define LED_PIN GPIO_PIN_3
И, так как светодиод в данной плате подключен стандартно к общему проводу, а не к питанию, то перевернём его состояния
#define LED_ON HAL_GPIO_WritePin(LED_GPIO_PORT, LED_PIN, GPIO_PIN_SET)
#define LED_OFF HAL_GPIO_WritePin(LED_GPIO_PORT, LED_PIN, GPIO_PIN_RESET)
Перейдём теперь в файл NRF24.c и тоже кое-что там изменим.
Во-первых, нельзя допустить того, чтобы два передатчика имели одинаковые адреса, поэтому изменим адрес
uint8_t TX_ADDRESS[TX_ADR_WIDTH] = {0xb7,0xb5,0xa1};
Также ещё одно желательное условие. Когда мы пытаемся осуществить несколько попыток передачи одного и того же пакета, мы можем также менять время между данными попытками. Если это время у двух разных передатчиков будет одинаковое, то, если случится одновременная передача пакетов с них на приёмник, то повторные попытки передачи данных пакетов также совпадут. Пусть это будет редкая ситуация, но если есть возможность её побороть, то лучше этим воспользоваться. Поэтому давайте в функции инициализации модуля немного изменим данное время
NRF24_WriteReg(SETUP_RETR, 0x6F); // // 1750 us, 15 retrans
Идём в main.c и перенесём весь пользовательский код (или почти весь) в него из одноимённого файла проекта первого передатчика
/* USER CODE BEGIN Includes */
#include "NRF24.h"
#include <string.h>
/* USER CODE END Includes */
…
/* Private variables ---------------------------------------------------------*/
char str1[20]={0};
uint8_t buf1[20]={0};
/* USER CODE END PV */
…
/* USER CODE BEGIN 1 */
uint8_t dt;
uint16_t i=1,retr_cnt_full=0, cnt_lost=0;
/* USER CODE END 1 */
…
/* USER CODE BEGIN 2 */
NRF24_ini();
/* USER CODE END 2 */
…
/* USER CODE BEGIN 3 */
HAL_Delay(691);
memcpy(buf1,(uint8_t*)&i,2);
memcpy(buf1+2,(uint8_t*)&retr_cnt_full,2);
memcpy(buf1+4,(uint8_t*)&cnt_lost,2);
dt = NRF24L01_Send(buf1);
retr_cnt_full += dt & 0xF;
cnt_lost = dt>>4;
i++;
}
/* USER CODE END 3 */
Я специально выделил время задержки другим цветом, так как она будет другая, так интереснее. Мы с данного модуля будем передавать пакеты немного чаще.
Соберём наш код, прошьём контроллер.
Правда толку от этого пока мы не дождёмся, приёмник «не знает» о нашем передатчике, он не знает даже его адреса.
Поэтому запитаем наш второй передатчик от отдельного питания, плату приёмника подключим к ПК.
Перейдём в файл NRF24.c и добавим адрес второго передатчика, немного изменив для красоты имя адреса первого
uint8_t TX_ADDRESS0[TX_ADR_WIDTH] = {0xb3,0xb4,0x01};
uint8_t TX_ADDRESS1[TX_ADR_WIDTH] = {0xb7,0xb5,0xa1};
В связи с изменением имени массива адреса, в функции NRF24L01_TX_Mode также внесём коррективу
NRF24_Write_Buf(TX_ADDR, TX_ADDRESS0, TX_ADR_WIDTH);
В функции инициализации мы также скорректируем имя в некоторых строках, а также добавим ещё одну для второго передатчика
NRF24_Write_Buf(TX_ADDR, TX_ADDRESS0, TX_ADR_WIDTH);
NRF24_Write_Buf(RX_ADDR_P0, TX_ADDRESS0, TX_ADR_WIDTH);
NRF24_Write_Buf(RX_ADDR_P1, TX_ADDRESS1, TX_ADR_WIDTH);
Для первого передатчика у нас теперь будет настроен канал PIPE0, а PIPE1 будет теперь для второго.
Только это не всё. Мы теперь должны включить оба канала в соответствующем регистре, поэтому для него строку также подправим
NRF24_WriteReg(EN_AA, 0x03); // Enable Pipe0 and Pipe1
NRF24_WriteReg(EN_RXADDR, 0x03); // Enable Pipe0 and Pipe1
Добавим также ещё одну строку для настройки величины пакета для первого канала
NRF24_Write_Buf(RX_ADDR_P1, TX_ADDRESS1, TX_ADR_WIDTH);
NRF24_WriteReg(RX_PW_P0, TX_PLOAD_WIDTH); //Number of bytes in RX payload in data pipe 0
NRF24_WriteReg(RX_PW_P1, TX_PLOAD_WIDTH); //Number of bytes in RX payload in data pipe 1
Если мы соберём проект и прошьём контроллер, то мы увидим отображение пакетов с обеих передатчиков, причём выглядеть это будет очень хаотично, но интересно. Всё дело в том. что мы отображаем всё в одну строку. Для красоты картины мы будем содержимое пакетов отображать на разных строках. Для каждого передатчика будет своя строка, не зря же этих строк у дисплея целых 4. Но прежде чем послать данные пакета на определённую строку, надо ещё определить, с какого именно передатчика (адреса) данный пакет пришёл. Всё это у нас присутствует в регистре статуса. Когда мы только начинали заниматься приёмом данных, то мы номер канала отслеживали через терминальную программу.
Для этого мы в функции IRQ_Callback определим канал, на который пришел пакет. Извлечём номер канала из регистра состояния
if(status & 0x40)
{
pipe = (status>>1)&0x07;
Дальше отправим номер канала в буфер
NRF24_Read_Buf(RD_RX_PLOAD,RX_BUF,TX_PLOAD_WIDTH);
*(RX_BUF+7) = pipe;
В связи с этим немного увеличим буфер
uint8_t RX_BUF[TX_PLOAD_WIDTH+1] = {0};
Можно было бы просто завести глобальную переменную, но я просто решил поиграться с массивом, всё равно он у нас уже есть.
Теперь в функции NRF24L01_Receive исправим позиционирование
LCD_SetPos(0, *(RX_BUF+7));
Соберём код, прошьём контроллер, и у нас после этого все пакеты наши нормально распределятся по экрану дисплея
В следующей части урока мы настроим проект для третьего передатчика, в приёмнике добавим возможность приёма пакетов с трёх источников и проверим код на практике.
Предыдущая часть Программирование МК STM32 Следующая часть
Модуль NRF24L01+ с антенной можно купить здесь NRF24L01+
Модуль NRF24L01+ без антенны можно купить здесь NRF24L01+
Адаптер для NRF24L01 можно купить здесь (5 штук) Адаптер для NRF24L01
Датчик температуры и влажности можно приобрести здесь DHT22
Отладочную плату можно приобрести здесь Nucleo STM32F401RE
Отладочную плату STM32F103C8T6 можно приобрести здесь STM32F103C8T6
Программатор недорогой можно купить здесь ST-Link V2
Отладочную плату NUCLEO-F303K8 можно купить здесь NUCLEO-F303K8
Переходник I2C to LCD можно приобрести здесьI2C to LCD1602 2004
Смотреть ВИДЕОУРОК (нажмите на картинку)
Добавить комментарий