В предыдущей части занятия мы создали проект для передатчика, добавили несколько новых функций, и только в сегодняшней части мы сможем наш код проверить, так как для этого нужен приёмник.
Займёмся теперь нашим приёмником.
Для него была выбрана плата NUCLEO-F401RE.
Подключим к данной схеме модуль. Соответствие ножек можно будет затем посмотреть в проекте Cube MX. Ну, хотя я и сейчас могу их написать для верности
CSN — PA10
CE — PA8
MOSI — PA7
SCK — PB3
IRQ — PA9
MISO — PA6
Вот. Теперь не ошибёмся.
Также подключим к данной плате восьмиразрядный семисегментный индикатор на микросхеме MAX7219, который подключается к контроллеру по шине SPI и с которым мы прекрасно умеем работать, так как мы его изучили в уроке 26.
Плату передатчика мы теперь подключим от независимого источника, а плату приёмника — к ПК через кабель Mini-USB.
Плата приёмника после этого будет выглядеть следующим образом. Для более интереного вида покажу её уже с прошитым работающим проектом (нажмите на картинку для увеличения изображения)
Пока займёмся проектом приёмника.
Запустим генератор проектов Cube MX, создадим новый проект, выбрав соответствующий контроллер
Включим резонатор
Настроим программатор
Включим USART2, который работает через ST-Link, чтобы нам не подключать никаких переходников
Включим SPI1 для работы с модулем NRF
Ножку SCK переопределим на PB3, так как на PA5 у нас светодиод
Включим ножку PA5 на выход для управления светодиодом
Назначим направление работы ножкам PA8 — PA10, назначение которых мы уже видели выше
Включим SPI3 для управления индикатором
Ножки на этой шине мы не переопределяем, только добавим ещё одну для CS
Перейдём в Clock Configuration и настроим частоты следующим образом (нажмите на картинку для увеличения изображения)
Перейдём в Configuration и для начала убедимся что у нас всё нормально с USART, а то всякое бывает
Настроим SPI1
Настроим SPI3
Заполним настройки проекта
Сохраним настройки, сгенерируем проект для Keil, откроем его там, настроим программатор на аторезет, установим уровень оптимизации 1 и попробуем собрать.
Из проекта для передатчика возьмем файлы NRF24.h и NRF24.c. Подключим файл NRF24.c к проекту.
В файле NRF24.h подправим подключаемую библиотеку, а также некоторые ножки портов и полярность ножки порта светодиода
#include "stm32f4xx_hal.h"
#include <string.h>
//------------------------------------------------
#define CS_GPIO_PORT GPIOA
#define CS_PIN GPIO_PIN_10
#define CS_ON HAL_GPIO_WritePin(CS_GPIO_PORT, CS_PIN, GPIO_PIN_RESET)
#define CS_OFF HAL_GPIO_WritePin(CS_GPIO_PORT, CS_PIN, GPIO_PIN_SET)
#define CE_GPIO_PORT GPIOA
#define CE_PIN GPIO_PIN_8
#define CE_RESET HAL_GPIO_WritePin(CE_GPIO_PORT, CE_PIN, GPIO_PIN_RESET)
#define CE_SET HAL_GPIO_WritePin(CE_GPIO_PORT, CE_PIN, GPIO_PIN_SET)
#define IRQ_GPIO_PORT GPIOA
#define IRQ_PIN GPIO_PIN_9
#define IRQ HAL_GPIO_ReadPin(IRQ_GPIO_PORT, IRQ_PIN)
#define LED_GPIO_PORT GPIOA
#define LED_PIN GPIO_PIN_5
#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)
#define LED_TGL HAL_GPIO_TogglePin(LED_GPIO_PORT, LED_PIN)
Подключим библиотеки в main.c
/* USER CODE BEGIN Includes */
#include "NRF24.h"
#include <string.h>
/* USER CODE END Includes */
Добавим глобальные массивы
/* Private variables ---------------------------------------------------------*/
char str1[150]={0};
uint8_t buf1[20]={0};
/* USER CODE END PV */
Вызовем функцию инициализации модуля в функции main()
/* USER CODE BEGIN 2 */
NRF24_ini();
/* USER CODE END 2 */
Подключим файлы для индикатора max7219.h и max7219.c из проекта урока 26., а также подключим файл max7219.c к проекту.
В файле max7219.c изменим ножку порта в следующих макросах
#define cs_set() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET)
#define cs_reset() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_SET)
В функции инициализации добавим интенсивность свечения, так как индикатор у нас питается от 3,3 вольта
Send_7219(0x0A,0x06);//интенсивность свечения
Также добавим функцию, которая будет выводить цифру в левую половину индикатора над функцией инициализации
//-------------------------------------------------------
void NumberL_7219 (volatile int n) //пишем в левую тетраду
{
uint8_t ng=0;//переменная для минуса
if(n<0)
{
ng=1;
n*=-1;
}
uint8_t i=4;
do
{
Send_7219(++i,n%10);//символ цифры
n/=10;
} while(n);
if(ng)
{
Send_7219(i+1,0x0A);//символ -
}
}
//-------------------------------------------------------
От функции обычного вывода цифры она почти не отличается, разве что только занчением переменной i.
Создадим в заголовочном файле прототип для данной функции и подключим данную библиотеку в файле main.c
#include "NRF24.h"
#include "max7219.h"
В функции main() вызовем функцию инициализации и после инициализации радиомодуля очистим индикатор
HAL_Delay(200);
Init_7219();
HAL_Delay(200);
NRF24_ini();
Clear_7219();
В файле NRF24.h также подключим библиотеку для индикатора
#include "stm32f4xx_hal.h"
#include "max7219.h"
Перейдём в файл и исправим канал приёма на pipe1
NRF24_WriteReg(EN_AA, 0x02); // Enable Pipe1
NRF24_WriteReg(EN_RXADDR, 0x02); // Enable Pipe1
И здесь также
NRF24_Write_Buf(RX_ADDR_P1, TX_ADDRESS, TX_ADR_WIDTH);
NRF24_WriteReg(RX_PW_P1, TX_PLOAD_WIDTH); //Number of bytes in RX payload in data pipe 1
Подключим хендл для USART
extern SPI_HandleTypeDef hspi1;
extern UART_HandleTypeDef huart2;
А также наш строковый массив, ну и заодно ещё одну глобальную переменную для подсчёта ошибок
uint8_t RX_BUF[TX_PLOAD_WIDTH] = {0};
extern char str1[150];
uint8_t ErrCnt_Fl = 0;
Добавим функцию приёма пактов от передатчика над функцией инициализации
//------------------------------------------------
void NRF24L01_Receive(void)
{
uint8_t status=0x01;
uint16_t dt=0;
}
//------------------------------------------------
И теперь немного поработаем над её телом.
Подождём, когда опустится ножка IRQ, считаем регистр сатуса и отправим его значение в терминальную программу, а также изменим состояние светодиода для наглядности мониторинга принятых пакетов
uint16_t dt=0;
while((GPIO_PinState)IRQ == GPIO_PIN_SET) {}
status = NRF24_ReadReg(STATUS);
sprintf(str1,"STATUS: 0x%02X\r\n",status);
HAL_UART_Transmit(&huart2,(uint8_t*)str1,strlen(str1),0x1000);
LED_TGL;
Подождём 10 микросекунд, ещё раз считаем регистр статуса, если нужный бит прерывания включен, то считаем буфер с пакетом, возьмём из этого пакета значения счётчиков и отобразим их на индикаторе, а затем сбросим требуемый флаг
LED_TGL;
DelayMicro(10);
status = NRF24_ReadReg(STATUS);
if(status & 0x40)
{
NRF24_Read_Buf(RD_RX_PLOAD,RX_BUF,TX_PLOAD_WIDTH);
dt = *(int16_t*)RX_BUF;
Clear_7219();
Number_7219(dt);
dt = *(int16_t*)(RX_BUF+2);
NumberL_7219(dt);
NRF24_WriteReg(STATUS, 0x40);
}
}
Добавим прототип для данной функции и вызовем её в функции main() файла main.c в бесконечном цикле
/* USER CODE BEGIN 3 */
NRF24L01_Receive();
}
Соберём проект, прошьём контроллер и посмотрим результат нашей работы
Только не пугайтесь, что у нас столько ошибок. Они набежали, пока мы писали проект для приёмника, ведь передатчик всё это время работал и, соответственно пакеты никуда не уходили.
Перезагрузим контроллер передатчика и всё будет нормально и неудачные попытки передачи исчезнут
А какие могут быть ошибки, если такие мощные приёмник и передатчик лежат рядом. Но зато мы теперь можем проверить дальность передачи, выйдя в открытую местность, например, подвесив передатчик на какое-нибудь дерево и отходя с приёмником на различное расстояние.
Посмотрим также в терминальную программу
Мы видим, что у нас результат техбитовой величины, находящихся в битах 3:1, соответствующий номеру канала обмена, в который пришел пакет равен одному, что и соответствует нашему каналу. Таким образом мы и определили, с какого именно передатчика нам пришел пакет.
А вот так выглядит вся наша общая схема и приёмника и передатчика (нажмите на картинку для увеличения изображения)
Таким образом, мы сегодня научились передавать и принимать информацию по радиоканалу с помощью модулей NRF24L01, а также научились отслеживать неудачные попытки передачи пакетов, что, думаю, наверняка пригодится в будущем.
К данным модулям мы ещё вернёмся и передадим с помощью них какую-нибудь уже полезную информацию.
Всем спасибо за внимание!
Предыдущая часть Программирование МК STM32 Следующий урок
Модуль NRF24L01+ с антенной можно купить здесь NRF24L01+
Модуль NRF24L01+ без антенны можно купить здесь NRF24L01+
Адаптер для NRF24L01 можно купить здесь (5 штук) Адаптер для NRF24L01
Отладочную плату можно приобрести здесь Nucleo STM32F401RE
Отладочную плату STM32F103C8T6 можно приобрести здесь STM32F103C8T6
Программатор недорогой можно купить здесь ST-Link V2
Индикатор светодиодный восьмиразрядный с драйвером MAX7219
Смотреть ВИДЕОУРОК (нажмите на картинку)
Стоит уделить особое внимание на стороне PTX команде REUSE_TX_PL.
Сам долго с ней бодался начитавшись советов об автоматическом сбросе флага MAX_RT, но как оказалось флаг надо сбрасывать вручную перед вызовом этой команды.
Я сделал на этих модулях беспроводной UART удлинитель.
Здравствуйте реализовал вашу схему и прошивку на двух микроконтроллерах stm32f103, изменил только ногу IRQ? сделал по внешнему прерыванию. Однако посылка успешно отправляется только через 20-100 попыток, в чём может быть дело, подскажите пожалуйста. Спасибо
Здравствуйте!
Очень странно, должно вообще-то работать. Где-то что-то напутано значит.
Как не пытался так нечего и не получилось, с MXCube не работаю, хотел всё перенести на SPL.
Такой вопрос: while((GPIO_PinState)IRQ == GPIO_PIN_SET) {} — ждем здесь пока не появится лог. 1 — на IRQ, верно понимаю?
Вопрос снят. Скачал CubeMX взял с сайта проект скомпилировал и вроде заработало, теперь буду искать почему на SPL не работает. Только судя по видео автора повторов пакетов нет, но у меня повторов больше чем счетчик тикает. Интересно почему, вроде проект с сайта?
Отлично!
Простите, что не мог вовремя ответить.
Очень много комментариев набежало.
Добрый день!
Спасибо Вам за уроки. Очень выручают.
У меня такой вопрос — как «подружить» Вашу библиотеку с ардуиновской? У меня передатчик на есп по ардуино, а приемник хочу собрать на stm32f030p4.
С есп на другую ардуину пакеты идут, а стм ничего не ловит. Вроде и настройки адреса изменил, и nrf вижу по прошлому уроку. А пакеты не принимает…
Максим,
Здравствуйте!
Спасибо за интерес к ресурсу!
С ардуиновской библиотекой подружить не получится да и смысла нет.
Только копать библиотеку и потихоньку разбирая код, делать подобное в своей.
Добрый день!
Собрал приемник и передатчик, все работает. Но если выключить приемник а потом включить, то связь не восстанавливается до тех пор, пока не перезапустишь передатчик. Тоже самое происходит при неудачной отправки пакета, связь теряется и восстанавливается только при перезапуске передатчика. Т. е. связь нормальная только когда счетчик неудачных попыток равен 0. В чем может быть причина?
Добрый день! Приёмник собрал на аврке, дисплей жк. Почему-то при запуске счётчик попыток скачет до 5635, обычный счётчик отображается нормально. Модули без антенны и без усилителя, дальность 15 метров через две стены.
Сегодня повесил IRQ на приёмнике на прерывание, теперь работает как надо! Спасибо Вам большое за уроки и дай Бог здоровья!