Ниже показан пример исходного кода беспроводного датчика влажности с возможностью "дергания" пинов на языке Си для микроконтроллеров AVR.Проект можно легко адаптировать под другие микроконтроллеры. Структура отправляемых данных должна соответствовать массиву в файле nRF-USB.h исходного кода клиентской утилиты nRF24L01+USB.
Клиент подойдет и для варианта шлюза Ethernet-nRF24L01.
Порядок данных массива: 1 байт номер клиента, 2 байта чтения analogread,1 байт свободный,2 байта счетчик ошибок,4 байта счетчик передач,4 байта тип float температура,4 байта тип float влажность.
Исходный код подходит для м/к Atmega 328, Atmega168, Atmega88, Atmega48, Atmega8 и других.Данный пример подстроен под использование м/к Atmega8 - он дешевый и в его помещается данный пример с большим запасом.
Функция чтения датчика влажности используется универсальная с автоматическим определением со странички Датчики влажности DHT11 и DHT22.
Возможен вариант прошивки с спящим режимом, в котором отправка данных может происходить,например, раз в 5 минут - в таком режиме работа от батареи может быть значительно дольше.
Архив с исходным кодом и необходимыми библиотеками можно скачать тут. Обновлено 14.08.14.
Исходный код беспроводного датчика:
#define chclient 1 // номер клиента 1... #define timeoutper 400 // таймаут запросов от сервера. #define timesend 100 // интервал отправки данных,для обычных датчиков можно установить время выше. #define DHT_PORT PORTC #define DHT_DDR DDRC #define DHT_PIN PINC #define DHT_BIT 3 #define nofloat 0 // без float , данные передаются умноженные на 10.Очень экономит место. // Настройка nRF #define ce_pin 0 #define csn_pin 1 #define csport PORTD #define ceport PORTD #define csddr DDRD #define ceddr DDRD #include <avr/io.h> #include <avr/wdt.h> #include <avr/sleep.h> #include <avr/interrupt.h> /* for sei() */ #include <util/delay.h> /* for delayMicroseconds() */ #include <avr/pgmspace.h> //#include <avr/eeprom.h> #include "spi.c" #include "ml.c" #include "nRF.c" // структура принятых данных.МЕНЯТЬ НЕЛЬЗЯ typedef struct{ uint8_t identifier; uint8_t val1; uint8_t val2; uint8_t val3; uint8_t val4; } nf0; nf0 servernf; // структура отправляемых данных.Изменяемые данные.Размер структуры должен быть не больше 32 байт ! typedef struct{ uint8_t identifier;// номер передатчика.МЕНЯТЬ НЕЛЬЗЯ int Analog; uint8_t test_data; int Error_Message; // счетчик ошибок long count;// счетчик передач для контроля качества канала #if nofloat int temperature_Sensor; //передаём температуру. int Humidity_Sensor;// передаём влажность #else float temperature_Sensor;// передаём температуру. float Humidity_Sensor;// передаём влажность #endif } nf1; nf1 clientnf; unsigned long time1=0; unsigned long time2=0; unsigned char datadht[5]; uint8_t dhtread () { uint8_t j = 0, i = 0; datadht[0] = datadht[1] = datadht[2] = datadht[3] = datadht[4] = 0; DHT_DDR|=(1<<DHT_BIT); //pin as output DHT_PORT&=~(1<<DHT_BIT); //0 _delay_ms(18); DHT_PORT|=(1<<DHT_BIT); //1 DHT_DDR&=~(1<<DHT_BIT); //pin as input //=============check DHT11 response _delay_us(51); // +1 if (DHT_PIN&(1<<DHT_BIT)) return 0; _delay_us(81); // +1 if (!(DHT_PIN&(1<<DHT_BIT))) return 0; //===============receive 40 data bits while (DHT_PIN&(1<<DHT_BIT)); for (j=0; j<5; j++) { datadht[j]=0; for(i=0; i<8; i++) { while (!(DHT_PIN&(1<<DHT_BIT))); _delay_us (30); if (DHT_PIN&(1<<DHT_BIT)) datadht[j]|=1<<(7-i); while (DHT_PIN&(1<<DHT_BIT)); } } return 1; } //------------------------------------------------ //-----------------Main программа----------------- //------------------------------------------------ int __attribute__((noreturn)) main(void) { DDRC |= _BV(0); //1 /* make the LED bit an output */ DDRC |= _BV(1); //2 TCCR0=(1 << CS01)|(1 << CS00); // делитель TCNT0 = 0; // счетчик таймера, тик 10 миллисекунд TIMSK = (1 << TOIE0); // разрешить прерывание таймера radiobegin(); //эти данные и так установлены в radiobegin: //setDataRate(2); // 1 - 250кб , 2 - 1 мб , 3 -2 мб. //setCRCLength(2); // 0 - crc off ,1 - 8bit ,2 - 16bit //setPALevel(3); // 0...3 -уровень PA. //setRetries(15,15); //setAutoAck(0); // отключили автопотверждение setChannel(25); openWritingPipe(0xF0F0F0F0D2LL); // Открываем канал передачи openReadingPipe(1,0xF0F0F0F0E1LL); // Открываем канал приема clientnf.identifier = chclient; startListening(); sei(); DDRC |= _BV(0); //1 /* светодиоды на выход */ DDRC |= _BV(1); //2 PORTC |= _BV(0); // 1 /* светодиоды погасить */ PORTC |= _BV(1); // 2 for(;;){ // основной цикл программы if ((millis()-time1) >= 1000) { // обновляем сенсоры раз в секунду (1000млс) // тут будут опросы сенсоров dhtread (); uint8_t crc= (datadht[0] + datadht[1] + datadht[2] + datadht[3]); if (datadht[0]==0 && datadht[1]==0 && datadht[2]==0 && datadht[3]==0) { //обработка ошибки:не подключен датчик !! } else if ( crc == datadht[4]) { #if nofloat if (datadht[1]==0 && datadht[3]==0) { // dht11 clientnf.temperature_Sensor=datadht[2]*10; // умножение на 10,чтобы было однинаково как у dht22,можно убрать. clientnf.Humidity_Sensor=datadht[0]*10; }else { // dht22 clientnf.Humidity_Sensor = (datadht[0] * 256 + datadht[1]); clientnf.temperature_Sensor = ((datadht[2] & 0x7F)* 256 + datadht[3]); if (datadht[2] & 0x80) clientnf.temperature_Sensor *= -1; } #else if (datadht[1]==0 && datadht[3]==0) { // dht11 clientnf.temperature_Sensor=datadht[2]; clientnf.Humidity_Sensor=datadht[0]; }else { // dht22 clientnf.Humidity_Sensor = (float)(datadht[0] * 256 + datadht[1])/10; clientnf.temperature_Sensor = (float)((datadht[2] & 0x7F)* 256 + datadht[3])/10; if (datadht[2] & 0x80) clientnf.temperature_Sensor *= -1; } #endif } else {/* обработка ошибки:ошибка CRC */} time1 = millis(); } //*****************************************************************************************/ if ((millis() - time2) >= timesend) { if (clientnf.count <= 2147483646) clientnf.count++; /// счетчик передач для контроля качества канала else clientnf.count = 0; stopListening(); radiowrite(&clientnf, sizeof(clientnf)); startListening(); unsigned long started_waiting_at = millis(); uint8_t timeout = false; uint8_t t=0; while ( ! available(0) && ! timeout ) if (millis() - started_waiting_at > timeoutper ) timeout = true; if ( timeout ) clientnf.Error_Message++; else { radioread( &servernf, sizeof(servernf) ); } if (servernf.identifier == chclient) { // выполнение команд с сервера,если данные предназначены для этого клиента: // val1= 10 -значит дергаем пинами, val2 - номер пина, val3 - состояние пина // не забудте установить режим OUTPUT для нужных пинов. // nRF-USB write 1 10 1 1 1 - что значит установить на 1 выводе порта C логический уровень 1 if (servernf.val1==10) { if (servernf.val3==1) PORTC |= _BV(servernf.val2); else PORTC &= ~_BV(servernf.val2); } // val1= 11 -значит управляем ШИМ пинами, val2 - номер пина, val3 - уровень 0..255. // не забудте установить режим OUTPUT для нужных пинов. // ШИМ возможен только на некоторых пинах !! // if (servernf.val1==11) analogWrite(servernf.val2,servernf.val3); } time2 = millis(); } } }