nRF24L01+ ATMEGA + Raspberry Pi
nRF24L01+ - радио модуль, работающий на частоте 2.4ГГц. Позволяет передавать информацию в обоих направлениях и объединять несколько устройств одновременно.
Основные технические характеристики nRF24L01 +
- Рабочая частота - 2.4ГГц. Возможность выбора одного из 126 каналов (при скорости 2Mbps используются два канала)
- Возможность работать на одном канале с 6-ю устройствами
- Скорость передачи данных - 250kbps, 1Mbps, 2Mbps
- Несколько режимов мощности (влияет на рабочую дистанцию)
- Дистанция - до 100 метров на открытом пространстве, до 30 метров в помещении. На практике уверенно "пробивает" 2 железобетонных стены на скорости 1Mbps
- Питание - от 1.9 до 3.6B. Максимальный ток - 13.5мA, 26мкА в режиме standby, минимальный - 900нА в режиме power down
- Интерфейс взаимодействия с микроконтроллером - SPI
- Входы выдерживают 5В, но питание модуля не более 3.6В
- Максимальная длинна пакета данных - 32 байта
- Цена модуля - $1- $2
Принцип работы и основные настройки nRF24L01 +


Частота 2.4ГГц очень популярна и на ней работает достаточно большое количество приборов, например: WiFi, радиоуправляемые модели, и тому подобное. Как они не мешают друг другу? Дело в том, что частота 2.4ГГц - это условное обозначение. На самом деле, имеется в виду диапазон частот, близкий к 2.4ГГц. nRF24L01+ работает на частотах 2.400-2.4835ГГц. Частота, на которой будут работать ваши модули, определяется номером канала. Каналы имеют шаг в 1МГц. То есть если Вы выбираете канал 0 - это частота 2.400ГГц, если канал 76 - 2.476ГГц. Разумеется, нужно выбирать свободную волну (канал) - иначе связь будет не стабильной или вообще отсутствовать.
Вы можете выбрать одну из трех скоростей передачи данных. Чем меньше скорость - тем больше чувствительность. То есть, при скорости 250kbps модули будут работать на большей дистанции, чем при более высоких скоростях.
На дальность работы модулей также влияет настройки выходной мощности модуля. Вы можете выбрать мощность в зависимости от приоритетов. То есть, если для вас важнее максимальная дальность, то надо выбрать максимальную мощность. Если приоритетной является экономичность, а дальность - несколько метров, разумно выбрать меньшую мощность сигнала. Интересное наблюдение в режиме приема данных (RX) модуль потребляет больший ток, чем в режиме передачи (TX).
Модуль nRF24L01+ в один момент времени может находиться в одном из режимов:
Power Down - выключен Standby - спящий режим RX Mode - режим ресивера (приемника) TX Mode - режим трансмиттера (передатчика)
Диаграмма переходов из режима в режим изображенны на рисунке:
Информационный пакет, который передает модуль nRF24L01+ имеет следующий формат:
Preamble - Преамбула представляет собой последовательность битов и используется для синхронизации демодуляторов приемников.
Address - Адрес приемника. Адрес гарантирует, что пакет получит нужен приемник. Вы можете настроить длину адреса 3, 4 или 5 байт. Надо стараться чтобы адреса были уникальны. Но иногда Адреса могут быть одинаковые в нескольких nRF24L01+ если этого требуют Ваши задачи.
Packet Control Field - контрольное поле. Содержит: 6 бит, определяющих длину пакета (имеется в виду длина пакета полезных данных (от 0 до 32 байт)); 2 бита PID, используемые для определения является ли пакет новым или пересланным повторно; 1 бит - флаг NO_ACK.
Payload - полезный "груз". То есть данные, которые передает микроконтроллер. Может быть от 0 до 32 байт. Длину Payload можно настроить.
CRC - CRC является обязательным механизмом обнаружения ошибок в пакете. Длина CRC - 1 или 2 байта и зависит от общей длины пакета.
Для того, чтобы переданный пакет был принят нужным приемником, настройки приемника должны быть такими же, как и у передатчика. Если параметры пакета будут отличаться, приемник не сможет его обработать. Также надо корректно указывать адреса (об этом чуть ниже).
Если одновременно будут передавать несколько передатчиков, или возникнут другие препятствия, произойдет коллизия. Приемник не сможет получить пакет. Поэтому nRF24L01+ имеет настройку автоматической повторной отправки пакета (Aoto Retransmission (ART)). Эти настройки указывают с каким интервалом и сколько раз пытаться отправить пакет.
Как отмечалось в самом начале nRF24L01+ может работать на одном канале с 6-ю nRF24L01+. Для этого все модуля должны работать на одном канале, но каждый nRF24L01+ должен иметь уникальный адрес. Относительно адресации в документации приведена наглядная диаграмма:
Обратите внимание, что адреса для Data Pipe 1 - Pipe 5 отличаются друг от друга лишь последним байтом. Этого требует документация на nRF24L01+. На этой диаграмме модуль отмеченный как PRX прослушивает эфир для указанных адресов RX_ADDR_P0..RX_ADDR_P5. Каждый из PTX1..PTX6 отправляет пакеты на адреса TX_ADDR. Модуль, который работает как PRX тоже может отправлять модулям пакеты по их адресам.
Если все настройки (разумеется, кроме адресов) будут одинаковыми - модули будут работать нормально. Основные проблемы возникают когда настройки передатчика и приемника имеют отличия. Также проблемы могут возникнуть, если вы выбрали канал, который занят и радиопомехи мешают радиосвязи.
Распиновка модуля nRF24L01 +

Схема подключения nRF24L01 + к микроконтроллеру Atmega8

Схема подключения nRF24L01+ к Raspberry Pi

Возможные проблемы с питанием nRF24L01+
В отдельных случаях отмечались проблемы при слабом питании. Некоторые платы Arduino имеют слабый стабилизатор напряжения на 3.3В. Эта проблема решается допайкой на ноги питания модуля дополнительного керамического конденсатора 1-2мкФ.Пример трансмиттера и ресивера для микроконтроллеров
Скачать пример для Atmega8 и Raspberry PiВ примерах для Atmega8 использована библиотека, написанная Davide Gironi. Оригинальные файлы и примеры также находятся в архиве.
Сначала рассмотрим пример для микроконтроллеров, когда один модуль отправляет данные, а другой - принимает. В этом примере приемник получает данные по 6 адресам (Pipe). Передатчик последовательно отправляет пакеты по всем адресам (Pipe). Для мониторинга работы я подключал UART-USB переходник к приемнику или передатчика. И терминальной программой через компьютер наблюдал за происходящим.
Передатчик (sender.c):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "uart/uart.h"
#define UART_BAUDRATE (F_CPU/16/9600)-1
#include "nrf24l01/nrf24l01.h"
int main(void) {
uint8_t i = 0;
uint8_t bufferout[NRF24L01_PAYLOAD];
uart_init(UART_BAUDRATE);
//init nrf24l01
nrf24l01_init();
//init interrupt
sei();
uart_puts("Starting as TX...\r\n");
//setup buffer
for(i=0; i<sizeof(bufferout); i++)
bufferout[i] = i+'A';
//sending buffer addresses
uint8_t sendpipe = 0;
uint8_t addrtx0[NRF24L01_ADDRSIZE] = NRF24L01_ADDRP0;
uint8_t addrtx1[NRF24L01_ADDRSIZE] = NRF24L01_ADDRP1;
uint8_t addrtx2[NRF24L01_ADDRSIZE] = NRF24L01_ADDRP2;
uint8_t addrtx3[NRF24L01_ADDRSIZE] = NRF24L01_ADDRP3;
uint8_t addrtx4[NRF24L01_ADDRSIZE] = NRF24L01_ADDRP4;
uint8_t addrtx5[NRF24L01_ADDRSIZE] = NRF24L01_ADDRP5;
nrf24l01_printinfo(uart_puts, uart_putc);
//main loop
while(1) {
//TX
char pipebuffer[5];
uart_puts("Pipe: ");
itoa(sendpipe, pipebuffer, 10);
uart_puts(pipebuffer);
uart_puts("...");
if(sendpipe == 0) {
//set tx address for pipe 0
nrf24l01_settxaddr(addrtx0);
} else if(sendpipe == 1) {
//set tx address for pipe 1
nrf24l01_settxaddr(addrtx1);
} else if(sendpipe == 2) {
//set tx address for pipe 2
nrf24l01_settxaddr(addrtx2);
} else if(sendpipe == 3) {
//set tx address for pipe 3
nrf24l01_settxaddr(addrtx3);
} else if(sendpipe == 4) {
//set tx address for pipe 4
nrf24l01_settxaddr(addrtx4);
} else if(sendpipe == 5) {
//set tx address for pipe 5
nrf24l01_settxaddr(addrtx5);
}
//write buffer
uint8_t writeret = nrf24l01_write(bufferout);
if(writeret == 1)
uart_puts("OK\r\n");
else
uart_puts("Failed\r\n");
sendpipe++;
sendpipe%=6;
_delay_ms(100);
}
}
Приемник (reciver.c):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "uart/uart.h"
#define UART_BAUDRATE (F_CPU/16/9600)-1
#include "nrf24l01/nrf24l01.h"
int main(void) {
uint8_t i = 0;
uint8_t bufferin[NRF24L01_PAYLOAD+1];
uart_init(UART_BAUDRATE);
nrf24l01_init();
//init interrupt
sei();
uart_puts("Starting as RX...\r\n");
//reset buffer
for(i=0; i<sizeof(bufferin); i++)
bufferin[i] = 0;
nrf24l01_printinfo(uart_puts, uart_putc);
//main loop
while(1) {
uint8_t pipe = 0;
if(nrf24l01_readready(&pipe)) { //if data is ready
char pipebuffer[5];
uart_puts("Pipe: ");
itoa(pipe, pipebuffer, 10);
uart_puts(pipebuffer);
uart_puts("\r\n");
//read buffer
nrf24l01_read(bufferin);
bufferin[NRF24L01_PAYLOAD] = '\0';
uart_puts("Data: ");
uart_puts(bufferin);
uart_puts("\r\n");
for(i=0; i<sizeof(bufferin); i++)
bufferin[i] = 0;
}
_delay_ms(10);
}
}
Пример ресивера для Raspberry Pi
Теперь подключим модуль к Raspberry Pi и напишем пример для получения данных. Сначала установим библиотеку RF24:
git clone https://github.com/tmrh20/RF24.git
cd RF24
sudo make install
Для Raspberry Pi код приемника выглядит так (nRF24L01_example1.cpp):
#include <cstdlib>
#include <iostream>
#include <RF24/RF24.h>
using namespace std;
// gpio pins, spi speed
RF24 radio(RPI_V2_GPIO_P1_22, RPI_V2_GPIO_P1_24, BCM2835_SPI_SPEED_8MHZ);
int main(int argc, char** argv)
{
char receivePayload[16];
uint8_t pipe_num=0;
radio.begin();
radio.setPALevel(RF24_PA_MAX);
radio.setDataRate(RF24_1MBPS);
radio.setCRCLength(RF24_CRC_16);
radio.setRetries(15, 15);
radio.setAutoAck(1);
radio.setChannel(76);
radio.setPayloadSize(16);
radio.openReadingPipe(0,0xE8E8F0F0E2LL);
radio.openReadingPipe(1,0xC1C2C2C2C2LL);
radio.openReadingPipe(2,0xC1C2C2C2C3LL);
radio.openReadingPipe(3,0xC1C2C2C2C4LL);
radio.openReadingPipe(4,0xC1C2C2C2C5LL);
radio.openReadingPipe(5,0xC1C2C2C2C6LL);
radio.startListening();
printf("Start\n");
while(1) {
while (radio.available(&pipe_num))
{
// Clear measurement values
memset(receivePayload,0,sizeof(receivePayload));
radio.read(&receivePayload, sizeof(receivePayload));
printf("pipe %d: %s\n", pipe_num, receivePayload);
}
}
return 0;
}
Режим "спросил - ответил"
Представьте себе какой шум стоит в эфире, если несколько nRF24L01+ постоянно отправляют данные даже тогда, когда их никто не слушает. Они могут мешать друг другу. Переделаем наш пример для микроконтроллеров таким образом, чтобы nRF24L01+ отвечали только после того, как его спросят. Для этого nRF24L01+ будут работать в режиме приема и когда получат любой пакет в свой адрес - будут отправлять данные. В примере пакет запроса не разбирается. То есть, любой пакет воспринимается как запрос. При необходимости можно выполнять анализ пакета и выдавать те или иные данные.Сторона, которая будет запрашивать данные, сначала посылает пакет на запрос (в примере - пакет с любыми данными), затем переходит в режим приема и ожидает поступления данных в течение определенного времени. Если данные за указанный период не поступают, считается, что нужный модуль недостижим.
Отвечающая сторона, (reply.c):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "uart/uart.h"
#define UART_BAUDRATE (F_CPU/16/9600)-1
#include "nrf24l01/nrf24l01.h"
int main(void) {
uint8_t pipe = 0;
uint8_t i;
uint8_t bufferout[NRF24L01_PAYLOAD];
uint8_t bufferin[NRF24L01_PAYLOAD];
uart_init(UART_BAUDRATE);
nrf24l01_init();
//init interrupt
sei();
//setup buffer
for(i=0; i<sizeof(bufferout); i++)
bufferout[i] = i+'a';
for(i=0; i<sizeof(bufferin); i++)
bufferin[i] = 0;
nrf24l01_printinfo(uart_puts, uart_putc);
while(1) {
if(nrf24l01_readready(&pipe)) { //if data is ready
char pipebuffer[5];
uart_puts("Pipe: ");
itoa(pipe, pipebuffer, 10);
uart_puts(pipebuffer);
uart_puts("\r\n");
//read buffer
nrf24l01_read(bufferin);
uart_puts("Data: ");
uart_puts(bufferin);
uart_puts("\r\n");
for(i=0; i<sizeof(bufferin); i++)
bufferin[i] = 0;
_delay_us(10);
//write buffer
uint8_t writeret = nrf24l01_write(bufferout);
if(writeret == 1)
uart_puts("OK\r\n");
else
uart_puts("Failed\r\n");
}
}
}
В этом примере сторона, которая получает данные, последовательно опрашивает шесть модулей по разным адресам адресов (request.c):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "uart/uart.h"
#define UART_BAUDRATE (F_CPU/16/9600)-1
#include "nrf24l01/nrf24l01.h"
int main(void) {
uint8_t i = 0;
uint8_t state = 0;
uint8_t counter = 0;
uint8_t pipe = 0;
uint8_t bufferout[NRF24L01_PAYLOAD];
uint8_t bufferin[NRF24L01_PAYLOAD+1];
uart_init(UART_BAUDRATE);
nrf24l01_init();
sei();
//setup buffer
for(i=0; i<sizeof(bufferout); i++)
bufferout[i] = i+'a';
for(i=0; i<sizeof(bufferin); i++)
bufferin[i] = 0;
//sending buffer addresses
uint8_t sendpipe = 0;
uint8_t addrtx0[NRF24L01_ADDRSIZE] = NRF24L01_ADDRP0;
uint8_t addrtx1[NRF24L01_ADDRSIZE] = NRF24L01_ADDRP1;
uint8_t addrtx2[NRF24L01_ADDRSIZE] = NRF24L01_ADDRP2;
uint8_t addrtx3[NRF24L01_ADDRSIZE] = NRF24L01_ADDRP3;
uint8_t addrtx4[NRF24L01_ADDRSIZE] = NRF24L01_ADDRP4;
uint8_t addrtx5[NRF24L01_ADDRSIZE] = NRF24L01_ADDRP5;
nrf24l01_printinfo(uart_puts, uart_putc);
while(1) {
if (state == 0) {
//TX
char pipebuffer[5];
uart_puts("Pipe: ");
itoa(sendpipe, pipebuffer, 10);
uart_puts(pipebuffer);
uart_puts("... ");
if(sendpipe == 0) {
//set tx address for pipe 0
nrf24l01_settxaddr(addrtx0);
} else if(sendpipe == 1) {
//set tx address for pipe 1
nrf24l01_settxaddr(addrtx1);
} else if(sendpipe == 2) {
//set tx address for pipe 2
nrf24l01_settxaddr(addrtx2);
} else if(sendpipe == 3) {
//set tx address for pipe 3
nrf24l01_settxaddr(addrtx3);
} else if(sendpipe == 4) {
//set tx address for pipe 4
nrf24l01_settxaddr(addrtx4);
} else if(sendpipe == 5) {
//set tx address for pipe 5
nrf24l01_settxaddr(addrtx5);
}
//write buffer
uint8_t writeret = nrf24l01_write(bufferout);
if(writeret == 1)
uart_puts("OK\r\n");
else
uart_puts("Failed\r\n");
sendpipe++;
sendpipe%=6;
state = 1;
counter = 0;
nrf24l01_setRX();
}
else {
if(nrf24l01_readready(&pipe)) { //if data is ready
//read buffer
nrf24l01_read(bufferin);
bufferin[NRF24L01_PAYLOAD]='\0';
uart_puts("Data: ");
uart_puts(bufferin);
uart_puts("\r\n");
for(i=0; i<sizeof(bufferin); i++)
bufferin[i] = 0;
state = 0;
}
_delay_ms(1);
counter ++;
if (counter > 200) {
state = 0;
}
}
}
}
Для Raspberry Pi программа отправляет запрос на на один адрес - 0xE8E8F0F0E2 (nRF24L01_example2.cpp):
#include <cstdlib>
#include <iostream>
#include <RF24/RF24.h>
using namespace std;
// gpio pins, spi speed
RF24 radio(RPI_V2_GPIO_P1_22, RPI_V2_GPIO_P1_24, BCM2835_SPI_SPEED_8MHZ);
int main(int argc, char** argv)
{
char receivePayload[16];
uint8_t pipe_num = 0;
uint8_t state = 0;
uint8_t counter = 0;
radio.begin();
radio.setPALevel(RF24_PA_MAX);
radio.setDataRate(RF24_1MBPS);
radio.setCRCLength(RF24_CRC_16);
radio.setRetries(15, 15);
radio.setAutoAck(1);
radio.setChannel(76);
radio.setPayloadSize(16);
radio.openWritingPipe(0xE8E8F0F0E2LL);
printf("Start\n");
while(1) {
if (state == 0) {
// Send request
printf("Send request...\n");
radio.openWritingPipe(0xE8E8F0F0E2LL);
radio.write(receivePayload,sizeof(receivePayload));
state = 1;
counter = 0;
// Start to Listening
radio.startListening();
}
else {
if (radio.available(&pipe_num)) {
memset(receivePayload,0,sizeof(receivePayload));
radio.read(&receivePayload, sizeof(receivePayload));
printf("pipe %d: %s\n", pipe_num, receivePayload);
state = 0;
radio.stopListening();
}
delay(0.01);
counter ++;
if (counter > 200) {
radio.stopListening();
state = 0;
printf("Nefiga :(\n");
}
}
delay(1);
}
return 0;
}
Массив - это не интересно, передаём структуру
С точки зрения программиста получать, а потом разбирать массив, - не всегда удобно. Чаще всего требуется пересылать числовые данные, иногда несколько. Или, вообще, разнотипные данные. Как упростить себе жизнь? Обычно создают структуру и используют ее следующим образом:Отвечающая сторона (Atmega8) (reply_struct.c):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "uart/uart.h"
#define UART_BAUDRATE (F_CPU/16/9600)-1
#include "nrf24l01/nrf24l01.h"
typedef struct
{
int8_t value1;
int8_t value2;
int8_t text[14];
} PAYLOAD;
int main(void) {
uint8_t pipe = 0;
uint8_t i;
//uint8_t bufferout[NRF24L01_PAYLOAD];
PAYLOAD bufferout;
uint8_t bufferin[NRF24L01_PAYLOAD];
uart_init(UART_BAUDRATE);
nrf24l01_init();
//init interrupt
sei();
//setup buffer
bufferout.value1 = 10;
bufferout.value2 = 13;
for(i=0; i<sizeof(bufferout.text); i++)
bufferout.text[i] = i+'a';
for(i=0; i<sizeof(bufferin); i++)
bufferin[i] = 0;
nrf24l01_printinfo(uart_puts, uart_putc);
while(1) {
if(nrf24l01_readready(&pipe)) { //if data is ready
char pipebuffer[5];
uart_puts("Pipe: ");
itoa(pipe, pipebuffer, 10);
uart_puts(pipebuffer);
uart_puts("\r\n");
//read buffer
nrf24l01_read(bufferin);
uart_puts("Data: ");
uart_puts(bufferin);
uart_puts("\r\n");
for(i=0; i<sizeof(bufferin); i++)
bufferin[i] = 0;
_delay_us(10);
//write buffer
uint8_t writeret = nrf24l01_write(&bufferout);
if(writeret == 1)
uart_puts("OK\r\n");
else
uart_puts("Failed\r\n");
}
}
}
Запрашивающая сторона, должен принимать данные в такую же структуру. Так выглядит пример для Raspberry Pi (nRF24L01_example3.cpp):
#include <cstdlib>
#include <iostream>
#include <RF24/RF24.h>
using namespace std;
// gpio pins, spi speed
RF24 radio(RPI_V2_GPIO_P1_22, RPI_V2_GPIO_P1_24, BCM2835_SPI_SPEED_8MHZ);
typedef struct
{
int8_t value1;
int8_t value2;
int8_t text[14];
} PAYLOAD;
PAYLOAD receivePayload;
int main(int argc, char** argv)
{
char bufferout[16];
uint8_t pipe_num = 0;
uint8_t state = 0;
uint8_t counter = 0;
radio.begin();
radio.setPALevel(RF24_PA_MAX);
radio.setDataRate(RF24_1MBPS);
radio.setCRCLength(RF24_CRC_16);
radio.setRetries(15, 15);
radio.setAutoAck(1);
radio.setChannel(76);
radio.setPayloadSize(16);
radio.openWritingPipe(0xE8E8F0F0E2LL);
printf("Start\n");
while(1) {
if (state == 0) {
// Send request
printf("send request...\n");
radio.openWritingPipe(0xE8E8F0F0E2LL);
radio.write(bufferout,sizeof(bufferout));
state = 1;
counter = 0;
// Start to Listening
radio.startListening();
}
else {
if (radio.available(&pipe_num)) {
memset(receivePayload,0,sizeof(receivePayload));
radio.read(&receivePayload, sizeof(receivePayload));
printf("pipe %d: value1=%d value2=%d text=%s\n", pipe_num, receivePayload.value1, receivePayload.value2, receivePayload.text);
state = 0;
radio.stopListening();
}
delay(0.01);
counter ++;
if (counter > 200) {
radio.stopListening();
state = 0;
printf("Nefiga :(\n");
}
}
delay(1);
}
return 0;
}
Надо быть внимательным и следить за тем, чтобы размер структуры не превысил 32 байта (максимально возможный размер Payload для nRF24L01+) и совпадал с длиной Payload, которая указывается при настройке модуля nRF24L01+.
Видео
Что я могу сказать в завершение о nRF24L01+. Это достаточно доступный путь к созданию простых беспроводных систем. Но существуют более интересные модули, с помощью которых можно обеспечить беспроводную связь более современными методами. О них поговорим в следующих статьях.
Скачать пример для Atmega8 и Raspberry Pi
Успехов.
Смотри также:
- Raspberry Pi — Что это такое?
- Raspberry Pi — GPIO
- Raspberry Pi — UART
- Raspberry Pi — FT232
- Raspberry Pi — ШИМ и Сервопривод
- Raspberry Pi — DHT11
- Raspberry Pi - FM Transmitter
- Прошивка AVR микроконтроллеров с помощью Raspberry Pi
- Raspberry Pi — LCD дисплей 1602
- Raspberry Pi — Wi-Fi
- Raspberry-Pi — I2C (TWI)
- Raspberry Pi - DS18B20
- Raspberry Pi Camera
- nRF24L01+ ATMEGA + Raspberry Pi
- BMP180 + Raspberry Pi + WH1602
- Wi-Fi Метео станция
- Raspbian. Apache + PHP + Python + MySQL
- Устанавливаем Raspbian на Raspberry Pi без клавиатуры и монитора
- ИК-дистанционное управление. Использование LIRC в Python
- Raspberry Pi. Raspbian. Отправка почты через аккаунт Gmail
- Neoway M590 – GSM/GPRS modem
- MPU-6050 – гироскоп – акселерометр
- HMC5883L Магнитометер
- PWM контролер на базе микросхемы PCA9685
- Метеостанция на Raspberry Pi своими руками
- Raspberry Pi. Live-stream video
Касательно Вашего вопроса о том, нужно ли ставить пробелы после цифр в русском языке, я не могу дать никаких консультаций. Дело в том, что русский язык не является для меня родным. Статья была переведена на русский язык с украинского языка и может содержать опечатки.
Я не большой знаток языков. Но, если Вы позволили себе построить одно предложение, которое начинается как указание, а заканчивается как вопрос, быть может, Вы найдете в себе силы простить мне мои «пробелы»?
Додати коментар
Недавні записи
- 🇺🇦 FOC Board STM32F103RB 🧩
- STM32 Motor control SDK - керування оборотами мотора за допомогою потенціометра 📑
- Flask✙Gunicorn✙Nginx➭😎
- STM32 Motor control SDK - програмне керування обертами мотора
- STM32 Motor control SDK - як створити перший проект
- Vue SVG. Приклад побудови живого параметричного креслення
- Вимірювання моменту мотора
- Vue SVG - компонент. Приклад 📑
- Flask + Vue 🏁 Финальный пример 🏁
- Flask, CORS, JSON-файл. Пример#6
Tags
bldc brushless stm32 motor web html css flask atmega foc git java-script pmsm raspberry-pi python websocket mongodb esp8266 nodemcu st-link tim timer docker ngnix programmator ssd1331 ssd1306 wifi uart meteo bme280 bmp280 i2c gps mpu-6050 mpu-9250 sensors 3d-printer options usb barometer remap watchdog flash eeprom rtc bkp encoder pwm servo capture examples dma adc nvic usart gpio books battery dc-dc sms max1674 avr lcd dht11 piezo rs-232 rfid solar exti bluetooth eb-500 displays ethernet led smd soldering mpx4115a hih-4000
Архіви