Метеостанция

1_Ардуинщик_1
Offline
Зарегистрирован: 02.06.2017

Здравствуйте. прошу помощи у опытных людей. проблема такая, хочу сделать погодную станцию на ардуино нано и на датчиках: BMP280, MQ135, DHT11, дисплей с I2C 16 на 2.

очень прошу помоч, я ещё совсем новичок и буду благодарен тому кто поможет! И очень прошу скинуть все библиотеки .

ulis
ulis аватар
Offline
Зарегистрирован: 09.03.2011

1_Ардуинщик_1 пишет:

Здравствуйте. прошу помощи у опытных людей. проблема такая, хочу сделать погодную станцию на ардуино нано и на датчиках: BMP280, MQ135, DHT11, дисплей с I2C 16 на 2.

очень прошу помоч, я ещё совсем новичок и буду благодарен тому кто поможет! И очень прошу скинуть все библиотеки .

Начните с малого, подключите дисплей и научитесь на нем что-нить писать, примеров море. Как только освоите, начинайте подключать по очереди датчики и пробовать с ними работать - так вы больше поймете. Я конечно, могу скинуть готовый вариант, но предпологаю, у вас появится куча вопросов, а мне еще сад посадить нужно :).

 

1_Ардуинщик_1
Offline
Зарегистрирован: 02.06.2017

Очень вас прошу как будет время скинуть скетч!заранее спасибо!)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016
ulis
ulis аватар
Offline
Зарегистрирован: 09.03.2011

1_Ардуинщик_1 пишет:

Очень вас прошу как будет время скинуть скетч!заранее спасибо!)

Код состоит из двух частей - приемника и передатчика.

Передатчик и приемник соответственно

/*******************************************************************************************************************/
// Библиотеки для работы с датчиком температуры
#include "OneWire.h"
#include "DallasTemperature.h"
#include "NRF24L01.h"

//#include <Wire.h>
#include <Adafruit_BMP085.h>


#include "DHT.h"


/******************************************* Датчик давления BMP180 ************************************************/
Adafruit_BMP085 _mrBMP;

/************************************** Датчик влажности AM2302 (AM2302) *******************************************/
#define pinDHT 2              // Подключение датчика влажности к D2
DHT _mrDHT(pinDHT, DHT22);

/******************************************** Датчик температуры ***************************************************/
// Выход данных датчика температуры подключен к pin A3 (16) Arduino
#define one_wire_bus 16

// Создаем экземпляр класса oneWire, передаевая ему параметр (номер пина Arduino)
OneWire oneWire(one_wire_bus);
//
DallasTemperature sensors(&oneWire);

/********************************************************************************************************************/
/****************************************** Функции получения данных ************************************************/
/*******************************************************************************************************************/
// Объединение данных метеостанции двух видов - unsigned char и struct
union mrData
{
  unsigned char buf[32];
  struct 
    {
      float temp;
      int lux;
      long pressure;
      int humidity;
      int wspeed;
      int wdir;
    } txData;  
};

// Создаем экземпляр объединения
union mrData _mrData;

/*******************************************************************************************************************/
// Функция получения данных с датчиков освещенности и вычисления среднего значения
int fnGetLux(void)
{  
  return (analogRead(A0) + analogRead(A1))/2;
}

/*******************************************************************************************************************/
// Функция получения данных с датчиков температуры и вычисления среднего значения
float fnGetTemp(void)
{
  sensors.requestTemperatures();    
  return (sensors.getTempCByIndex(0) + sensors.getTempCByIndex(1))/2;  
}

/*******************************************************************************************************************/
// Функция получения давления с датчика
// Сразу переводим в миллиметры ртутного столба
//
long fnGetPressure(void)
{
  return (_mrBMP.readPressure())/133.322;  
}

/*******************************************************************************************************************/
// Функция получения влажности воздуха
int fnGetHumidity(void)
{
  return _mrDHT.readHumidity();
}

/*******************************************************************************************************************/
// Функция получения скорости ветра
int fnGetWSpeed(void)
{
  return 7;
}

/*******************************************************************************************************************/
// Функция получения направления ветра
int fnGetWDir(void)
{
  return 47;
}
/*******************************************************************************************************************/

/*******************************************************************************************************************/
/**************************** Переменные и  функции для работы с радиомодулем  *************************************/
/*******************************************************************************************************************/
#define TX_ADR_WIDTH    5   // 5 unsigned chars TX(RX) address width
#define TX_PLOAD_WIDTH  32  // 32 unsigned chars TX payload

unsigned char TX_ADDRESS[TX_ADR_WIDTH]  = 
{
  0x34,0x43,0x10,0x10,0x01
}; // Define a static TX address

unsigned char rx_buf[TX_PLOAD_WIDTH] = {0}; // initialize value
unsigned char tx_buf[TX_PLOAD_WIDTH] = {0};


/*******************************************************************************************************************/
// Функция инициализации модуля передатчика
void fnIniNRF()
{
  SPI_DIR = ( CE + SCK + CSN + MOSI);
  SPI_DIR &=~ ( IRQ + MISO);
  SPI_PORT&=~CE;      // chip enable
  SPI_PORT|=CSN;      // Spi disable  
  SPI_PORT&=~SCK;     // Spi clock line init high
}

/*******************************************************************************************************************/
// Функция передачи данных
void fnTransmitData()
{
  
// Заполняем буфер для передачи данными с датчиков
  for(int i=0; i<32; i++)
  {
    tx_buf[i] = _mrData.buf[i];        
  }        
   unsigned char status = SPI_Read(STATUS);                   // read register STATUS's value
   if(status&TX_DS)                                           // if receive data ready (TX_DS) interrupt
    {
      SPI_RW_Reg(FLUSH_TX,0);                                  
      SPI_Write_Buf(WR_TX_PLOAD,tx_buf,TX_PLOAD_WIDTH);       // write playload to TX_FIFO
    }
    if(status & MAX_RT)                                         // if receive data ready (MAX_RT) interrupt, this is retransmit than  SETUP_RETR                          
    {
      SPI_RW_Reg(FLUSH_TX,0);
      SPI_Write_Buf(WR_TX_PLOAD,tx_buf,TX_PLOAD_WIDTH);      // disable standy-mode
    }
    SPI_RW_Reg(WRITE_REG+STATUS,status);                     // clear RX_DR or TX_DS or MAX_RT interrupt flag
    
    delay(1000);   
}
/*******************************************************************************************************************/

//***************************************************
void setup() 
{
  
  // Начало работы с датчиками температуры
  sensors.begin();
  
  // Запускаем датчик давления
  _mrBMP.begin();

  // Запускаем датчик влажности
  _mrDHT.begin();
  
  fnIniNRF();
  TX_Mode();                       // set TX mode
}

void loop() 
{
  // Заполняем структуру значениями, полученными с датчиков
  _mrData.txData.temp = fnGetTemp();
  _mrData.txData.lux = fnGetLux();  
  _mrData.txData.pressure = fnGetPressure();
  _mrData.txData.humidity = fnGetHumidity();
  _mrData.txData.wspeed = fnGetWSpeed();
  _mrData.txData.wdir = fnGetWDir();  

  fnTransmitData();
}


/**************************************************
 * Function: SPI_RW();
 * 
 * Description:
 * Writes one unsigned char to nRF24L01, and return the unsigned char read
 * from nRF24L01 during write, according to SPI protocol
 **************************************************/
unsigned char SPI_RW(unsigned char Byte)
{
  unsigned char i;
  for(i=0;i<8;i++)                      // output 8-bit
  {
    if(Byte&0x80)
    {
      SPI_PORT |=MOSI;    // output 'unsigned char', MSB to MOSI
    }
    else
    {
      SPI_PORT &=~MOSI;
    }
    SPI_PORT|=SCK;                      // Set SCK high..
    Byte <<= 1;                         // shift next bit into MSB..
    if(SPI_IN & MISO)
    {
      Byte |= 1;                // capture current MISO bit
    }
    SPI_PORT&=~SCK;                     // ..then set SCK low again
  }
  return(Byte);                    // return read unsigned char
}
/**************************************************/

/**************************************************
 * Function: SPI_RW_Reg();
 * 
 * Description:
 * Writes value 'value' to register 'reg'
/**************************************************/
unsigned char SPI_RW_Reg(unsigned char reg, unsigned char value)
{
  unsigned char status;

  SPI_PORT&=~CSN;                   // CSN low, init SPI transaction
  status = SPI_RW(reg);             // select register
  SPI_RW(value);                    // ..and write value to it..
  SPI_PORT|=CSN;                    // CSN high again

  return(status);                   // return nRF24L01 status unsigned char
}
/**************************************************/

/**************************************************
 * Function: SPI_Read();
 * 
 * Description:
 * Read one unsigned char from nRF24L01 register, 'reg'
/**************************************************/
unsigned char SPI_Read(unsigned char reg)
{
  unsigned char reg_val;

  SPI_PORT&=~CSN;                // CSN low, initialize SPI communication...
  SPI_RW(reg);                   // Select register to read from..
  reg_val = SPI_RW(0);           // ..then read register value
  SPI_PORT|=CSN;                 // CSN high, terminate SPI communication

  return(reg_val);               // return register value
}
/**************************************************/

/**************************************************
 * Function: SPI_Read_Buf();
 * 
 * Description:
 * Reads 'unsigned chars' #of unsigned chars from register 'reg'
 * Typically used to read RX payload, Rx/Tx address
/**************************************************/
unsigned char SPI_Read_Buf(unsigned char reg, unsigned char *pBuf, unsigned char bytes)
{
  unsigned char status,i;

  SPI_PORT&=~CSN;                   // Set CSN low, init SPI tranaction
  status = SPI_RW(reg);            // Select register to write to and read status unsigned char

  for(i=0;i<bytes;i++)
  {
    pBuf[i] = SPI_RW(0);    // Perform SPI_RW to read unsigned char from nRF24L01
  }

  SPI_PORT|=CSN;                   // Set CSN high again

  return(status);                  // return nRF24L01 status unsigned char
}
/**************************************************/

/**************************************************
 * Function: SPI_Write_Buf();
 * 
 * Description:
 * Writes contents of buffer '*pBuf' to nRF24L01
 * Typically used to write TX payload, Rx/Tx address
/**************************************************/
unsigned char SPI_Write_Buf(unsigned char reg, unsigned char *pBuf, unsigned char bytes)
{
  unsigned char status,i;

  SPI_PORT&=~CSN;                   // Set CSN low, init SPI tranaction
  status = SPI_RW(reg);             // Select register to write to and read status unsigned char
  for(i=0;i<bytes; i++)             // then write all unsigned char in buffer(*pBuf)
  {
    SPI_RW(*pBuf++);
  }
  SPI_PORT|=CSN;                   // Set CSN high again
  return(status);                  // return nRF24L01 status unsigned char
}
/**************************************************/

/**************************************************
 * Function: TX_Mode();
 * 
 * Description:
 * This function initializes one nRF24L01 device to
 * TX mode, set TX address, set RX address for auto.ack,
 * fill TX payload, select RF channel, datarate & TX pwr.
 * PWR_UP is set, CRC(2 unsigned chars) is enabled, & PRIM:TX.
 * 
 * ToDo: One high pulse(>10us) on CE will now send this
 * packet and expext an acknowledgment from the RX device.
 **************************************************/
void TX_Mode(void)
{
  SPI_PORT&=~CE;

  SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH);    // Writes TX_Address to nRF24L01
  SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH); // RX_Addr0 same as TX_Adr for Auto.Ack

  SPI_RW_Reg(WRITE_REG + EN_AA, 0x01);      // Enable Auto.Ack:Pipe0
  SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01);  // Enable Pipe0
  SPI_RW_Reg(WRITE_REG + SETUP_RETR, 0x1a); // 500us + 86us, 10 retrans...
  SPI_RW_Reg(WRITE_REG + RF_CH, 40);        // Select RF channel 40
  SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07);   // TX_PWR:0dBm, Datarate:2Mbps, LNA:HCURR
  SPI_RW_Reg(WRITE_REG + CONFIG, 0x0e);     // Set PWR_UP bit, enable CRC(2 unsigned chars) & Prim:TX. MAX_RT & TX_DS enabled..
  SPI_Write_Buf(WR_TX_PLOAD,tx_buf,TX_PLOAD_WIDTH);

  SPI_PORT|=CE;
}


Приемник:
/*******************************************************************************************************************/
// 
// Приемник данных с метеостанции
// Версия 04-05-2017
//
// Метеостанция передает:
// среднюю температуру с двух датчиков температуры DS18B20
// среднюю освещенность с двух фоторезисторов серии GM55
// давление
// влажность
// 
// Данные принимаются по радиканалу с помощью модуля nRF24l01+
// Запрос данных с метеостанции по времени (модуль реального времени
// Данные для последующего анализа пишутся на SD карту (модуль
// Подключена клавиатура 4x4
//
/*******************************************************************************************************************/
//
// Подключение библиотек

#include <Keypad.h>
#include "U8glib.h"

// Библиотека часов реального времени
#include <iarduino_RTC.h>

// Библиотека работы с картой SD, аппаратный SPI
#include <SD.h>
#include <SPI.h>

// Библиотеки для работы с радиомодулем NRF24L01, программный SPI, порт A
#include "NRF24L01.h"

/****************************************** Переменные метеостанции  *******************************************/
//
char _mrStatus;           // Текущее состояние метеоприемника.
int _mrHd;                // Установка часы десятки 
int _mrHu;                // Установка часы единицы
int _mrMd;                // Установка минуты десятки
int _mrMu;                // Установка минуты единицы
int _mrSd;                // Установка секунды десятки
int _mrSu;                // Установки секунды единицы

int _mrYt;                // Установка год тысячи, по умолчанию всегда равно 2
int _mrYh;                // Установка год сотни
int _mrYd;                // Установка год десятки
int _mrYu;                // Установка год единицы
int _mrMnd;               // Установка месяц десятки
int _mrMnu;               // Установка месяц единицы
int _mrDd;                // Установка дни десятки
int _mrDu;                // Установка дни единицы

unsigned long _timeDelay; // Используется для вычисления времени мигания курсора
int _blinkCursor;         // Показывать или не показывать курсор
int _mrCursorPos;         // номер редактируемой цифры в режиме редактирования даты и времени 
String _dataD;            // Дата с датчика реального времени в строковом формате
String _dataT;            // Время с датчика реального времени в строковом формате
unsigned long _blink;     // Для мигания светодиодов
#define _ledSD 30        // Номер порта, к которому подключен светодиод (будет мигать при записи на SD карту)

// Массив координат курсора в режиме (_mrStatus = 'A') редактирования даты и времени
int _curPos[12] = {0,12,36,48,72,84,96,108,0,12,36,48};

// Объединение данных метеостанции - буфера обмена buf и структуры rxData
union mrData
{
  unsigned char buf[32];
  struct 
    {
      float temp;
      int lux;
      long pressure;
      int humidity;
      int wspeed;
      int wdir;
    } rxData;  
};

// Создаем экземпляр объединения
union mrData _mrData;

/*******************************************************************************************************************/
/*******************************************************************************************************************/
// Описание состояний приемника метеостанции
//  _mrStatus = 0 - обычное состояние (отображение текущего времени, температуры, давления, освещенности, влажности)
//  _mrStatus = 1 - режим отображения состояния SD карты
//

/*******************************************************************************************************************/
/************************************************** SD карта *******************************************************/
/*******************************************************************************************************************/
// Переменные для работы с SD
// для работы с файлами

bool _SDexists;               // карта в слоте установлена (_SDexists = true) или нет
File _mrFile;                 // Основной файл для записи данных на карту
String _fileName;

// для работы с информацией о карте
Sd2Card _mrCard;
SdVolume _mrVolume;
//SdFile _mrRoot;

// _write = 0; - запись еще не производилась, _write = 1; - запись уже произведена
// переменная необходима при циклической записи
int _write;

// Номер цифрового пина для управления сигналом cs карты SD
#define _csSD 53

File _root;                     // Файл для подсчета числа файлов и их объема на SD карте
File _entry; 

/*******************************************************************************************************************/
// Массив усредненных данных, считанных с SD карты
int _mrSDRead[120][4];

//String _readLine;

// Массив символов, прочитанных из файла карты SD
char _readLine[] = {};

/**********************************************************************************************************************/
/******************************************** Часы реального времени **************************************************/
/**********************************************************************************************************************/
// Переменная для работы с часами RTC
iarduino_RTC _myRTC(RTC_DS3231);

void fnIniRTC(void)
{
  _myRTC.begin();  
}

/*******************************************************************************************************************/
// Начальная настройка метеоприемника
/*******************************************************************************************************************/
void fnIniMeteoReceiver()
{  
  _mrStatus = '0';
  _mrCursorPos = 1;
  _timeDelay = millis();
  _blink = millis();
}

/*******************************************************************************************************************/
/************************************************* Клавиатура ******************************************************/
/*******************************************************************************************************************/
// Настройка клавиатуры
//
const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
char _customKey;

//define the cymbols on the buttons of the keypads
char hexaKeys[ROWS][COLS] = {
  {'A','3','2','1'},
  {'B','6','5','4'},
  {'C','9','8','7'},
  {'D','#','0','*'}
};
byte rowPins[ROWS] = {39,41,43,45};
byte colPins[COLS] = {31,33,35,37};

//Создание экземпляра клавиатуры
Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);

/*******************************************************************************************************************/
/*************************************************** Функции *******************************************************/
/*******************************************************************************************************************/
// Функция заполняет целочисленные переменные времени и даты с датчика реального времени
void fnFillDateTime()
{
  String _temp;
  
  _dataD = _myRTC.gettime("d-m-Y");
  _dataT = _myRTC.gettime("H-i-s");
 
  // Десятки день
  _temp = _dataD[0];  
  _mrDd = _temp.toInt();  
     
  // Единицы день
  _temp = _dataD[1];  
  _mrDu = _temp.toInt();  

   // месяц десятки
  _temp = _dataD[3];  
  _mrMnd = _temp.toInt();

  // месяц единицы
  _temp = _dataD[4];  
  _mrMnu = _temp.toInt();

  // год тысячи
  _temp = _dataD[6];
  _mrYt = _temp.toInt();
  
  // год сотни
  _temp = _dataD[7];
  _mrYh = _temp.toInt();

  // год десятки
  _temp = _dataD[8];
  _mrYd = _temp.toInt();

  // год единицы
  _temp = _dataD[9];
  _mrYu = _temp.toInt();
    
  // часы  десятки
  _temp = _dataT[0];
  _mrHd = _temp.toInt();

  // часы единицы
  _temp = _dataT[1];
  _mrHu = _temp.toInt();
    
  // минуты десятки
  _temp = _dataT[3];
  _mrMd = _temp.toInt();

  // минуты единицы
  _temp = _dataT[4];
  _mrMu = _temp.toInt();

  // секунды десятки
  _temp = _dataT[6];
  _mrSd = _temp.toInt();

  // секунды единицы
  _temp = _dataT[7];
  _mrSu = _temp.toInt();  
}

/*******************************************************************************************************************/
// Функция возвращает истину, если переданный параметр _number делится на другой параметр _div без остатка
/*******************************************************************************************************************/
bool fnRestDiv(int _number, int _div)
{  
  float _result;
  int _whole;
  int _rest;

  // Делим входное число на делитель
  _result = _number/_div;  
  // Вычисляем челую часть результата деления
  _whole = _result;
  // Вычисляем остаток от деления  
  _rest = _number - _whole*_div;
  
  if(_rest == 0)
  {
    return true;
  }
  else
  {
    return false;
  }  
}

/*******************************************************************************************************************/
/**************************** Переменные и  функции для работы с радиомодулем  *************************************/
/*******************************************************************************************************************/

#define TX_ADR_WIDTH    5           // 5 unsigned chars TX(RX) address width
#define TX_PLOAD_WIDTH  32          // 32 unsigned chars TX payload

unsigned char rx_buf[TX_PLOAD_WIDTH];
unsigned char tx_buf[TX_PLOAD_WIDTH];

unsigned char _NRFStatus;

unsigned char TX_ADDRESS[TX_ADR_WIDTH]  = 
{
  0x34,0x43,0x10,0x10,0x01
}; // Define a static TX address

// Инициализация радиомодуля
//**************************************************
// 
// Description:
// flash led one time,chip enable(ready to TX or RX Mode),
// Spi disable,Spi clock line init high
//**************************************************
void fnIniNRF()
{
  SPI_DIR = ( CE + SCK + CSN + MOSI);
  SPI_DIR &=~ ( IRQ + MISO);
  SPI_PORT&=~CE;      // chip enable
  SPI_PORT|=CSN;      // Spi disable  
  SPI_PORT&=~SCK;     // Spi clock line init high
}

/***************************************************************************************************************************/
/***************************************************************************************************************************/
 /*
 * Function: SPI_RW();
 * 
 * Description:
 * Writes one unsigned char to nRF24L01, and return the unsigned char read
 * from nRF24L01 during write, according to SPI protocol
 **************************************************/
unsigned char SPI_RW(unsigned char Byte)
{
  unsigned char i;
  for(i=0;i<8;i++)                      // output 8-bit
  {
    if(Byte&0x80)
    {
      SPI_PORT |=MOSI;    // output 'unsigned char', MSB to MOSI
    }
    else
    {
      SPI_PORT &=~MOSI;
    }
    SPI_PORT|=SCK;                      // Set SCK high..
    Byte <<= 1;                         // shift next bit into MSB..
    if(SPI_IN & MISO)
    {
      Byte |= 1;                        // capture current MISO bit
    }
    SPI_PORT&=~SCK;                     // ..then set SCK low again
  }
  return(Byte);                     // return read unsigned char
}
/***************************************************************************************************************************/
/***************************************************************************************************************************/
/**************************************************
 * Function: SPI_RW_Reg();
 * 
 * Description:
 * Writes value 'value' to register 'reg'
/**************************************************/
unsigned char SPI_RW_Reg(unsigned char reg, unsigned char value)
{
  unsigned char status;

  SPI_PORT&=~CSN;                   // CSN low, init SPI transaction
  status = SPI_RW(reg);             // select register
  SPI_RW(value);                    // ..and write value to it..
  SPI_PORT|=CSN;                    // CSN high again

  return(status);                   // return nRF24L01 status unsigned char
}
/***************************************************************************************************************************/

/***************************************************************************************************************************/
/*
 * Function: SPI_Read();
 * 
 * Description:
 * Read one unsigned char from nRF24L01 register, 'reg'
/***************************************************************************************************************************/
unsigned char SPI_Read(unsigned char reg)
{
  unsigned char reg_val;

  SPI_PORT&=~CSN;                // CSN low, initialize SPI communication...
  SPI_RW(reg);                   // Select register to read from..
  reg_val = SPI_RW(0);           // ..then read register value
  SPI_PORT|=CSN;                 // CSN high, terminate SPI communication

  return(reg_val);               // return register value
}
/***************************************************************************************************************************/

/***************************************************************************************************************************/
 /*
 * Function: SPI_Read_Buf();
 * 
 * Description:
 * Reads 'unsigned chars' #of unsigned chars from register 'reg'
 * Typically used to read RX payload, Rx/Tx address
 ***************************************************************************************************************************/
/***************************************************************************************************************************/
unsigned char SPI_Read_Buf(unsigned char reg, unsigned char *pBuf, unsigned char bytes)
{
  unsigned char status,i;

  SPI_PORT&=~CSN;                   // Set CSN low, init SPI tranaction
  status = SPI_RW(reg);             // Select register to write to and read status unsigned char

  for(i=0;i<bytes;i++)
  {
    pBuf[i] = SPI_RW(0);    // Perform SPI_RW to read unsigned char from nRF24L01
  }

  SPI_PORT|=CSN;                   // Set CSN high again

  return(status);                  // return nRF24L01 status unsigned char
}
/***************************************************************************************************************************/

/***************************************************************************************************************************/
 /*
 * Function: SPI_Write_Buf();
 * 
 * Description:
 * Writes contents of buffer '*pBuf' to nRF24L01
 * Typically used to write TX payload, Rx/Tx address
/**************************************************/
unsigned char SPI_Write_Buf(unsigned char reg, unsigned char *pBuf, unsigned char bytes)
{
  unsigned char status,i;

  SPI_PORT&=~CSN;                   // Set CSN low, init SPI tranaction
  status = SPI_RW(reg);             // Select register to write to and read status unsigned char
  for(i=0;i<bytes; i++)             // then write all unsigned char in buffer(*pBuf)
  {
    SPI_RW(*pBuf++);
  }
  SPI_PORT|=CSN;                   // Set CSN high again
  return(status);                  // return nRF24L01 status unsigned char
}
/***************************************************************************************************************************/

/***************************************************************************************************************************/
/*
 * Function: RX_Mode();
 * 
 * Description:
 * This function initializes one nRF24L01 device to
 * RX Mode, set RX address, writes RX payload width,
 * select RF channel, datarate & LNA HCURR.
 * After init, CE is toggled high, which means that
 * this device is now ready to receive a datapacket.
/***************************************************************************************************************************/
void RX_Mode(void)
{
  SPI_PORT&=~CE;
  SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH); // Use the same address on the RX device as the TX device
  SPI_RW_Reg(WRITE_REG + EN_AA, 0x01);      // Enable Auto.Ack:Pipe0
  SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01);  // Enable Pipe0
  SPI_RW_Reg(WRITE_REG + RF_CH, 40);        // Select RF channel 40
  SPI_RW_Reg(WRITE_REG + RX_PW_P0, TX_PLOAD_WIDTH); // Select same RX payload width as TX Payload width
  SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07);   // TX_PWR:0dBm, Datarate:2Mbps, LNA:HCURR
  SPI_RW_Reg(WRITE_REG + CONFIG, 0x0f);     // Set PWR_UP bit, enable CRC(2 unsigned chars) & Prim:RX. RX_DR enabled..
  SPI_PORT|=CE;                             // Set CE pin high to enable RX device
  //  This device is now ready to receive one packet of 16 unsigned chars payload from a TX device sending to address
  //  '3443101001', with auto acknowledgment, retransmit count of 10, RF channel 40 and datarate = 2Mbps.
}
/***************************************************************************************************************************/

/***************************************************************************************************************************/
// Функция приема данных с приемника
void fnReadMRData()
{
  // Проверяем статус приемника (передатчика)
  _NRFStatus = SPI_Read(STATUS);
   
  if(_NRFStatus & RX_DR)
  {
    SPI_Read_Buf(RD_RX_PLOAD, rx_buf, TX_PLOAD_WIDTH);              // read playload to rx_buf
    SPI_RW_Reg(FLUSH_RX,0);                                         // clear RX_FIFO
    
    // В цикле заполняем объединение    
    for(int j = 0; j < 32; j++)
    {
      _mrData.buf[j] = rx_buf[j];      
    }       
  }
  
  SPI_RW_Reg(WRITE_REG+STATUS,_NRFStatus);  
}

/**************************************************** Индикатор 7920 *******************************************************/
// Подключение индикатора по SPI
U8GLIB_ST7920_128X64_4X u8g(3, 4, 5);

/*******************************************************************************************************************/
// Функция вычисляет положение и рисует линию курсора (две полоски под цифрой, номер которой равен numDigit)
// Передаваемые параметры:
// numDigit - номер редактируемой цифры. Всего редактируемых цифр - 14.
// Из них первые 8 относятся к дате, а с 9 по 12 относятся ко времени
//
void fnDrawCursor(int numDigit, int cursorShow)
{
  // Координаты курсора на мониторе
  int x;
  int y;    
  x = _curPos[numDigit - 1];
  
  if(numDigit <=8)
  {
    y = 34; 
  }
  else
  {
    y = 58;
  }

  if(cursorShow == 1)
  {
    u8g.drawHLine(x,y,10);
    u8g.drawHLine(x,y+1,10);
  }    
}

/****************************************** Функции вывода информации ******************************************************/


/****************************************** Функции вывода температуры *****************************************************/
void fnShowTemp(void)
{
  // рисуем разделительную полоску
  u8g.setFont(u8g_font_profont11);
  u8g.drawStr(30, 8, "temperature");  
  u8g.drawLine(2,11,125,11);
  
   // устанавливаем крупный шрифт
      u8g.setFont(u8g_font_profont22);
      // выводим температуру снаружи
      u8g.drawStr(1, 32, "tO:");
      u8g.setPrintPos(40,32);
      u8g.print(_mrData.rxData.temp);
      // выводим температуру в помещении
      u8g.drawStr(1, 56, "tI:");
      u8g.setPrintPos(40,56);
      u8g.print(_mrData.rxData.temp);      
}

/****************************************** Функции вывода давления *****************************************************/
void fnShowPress(void)
{
  // рисуем разделительную полоску
  u8g.setFont(u8g_font_profont11);
  u8g.drawStr(36, 8, "pressure");  
  u8g.drawLine(2,11,125,11);
  
   // устанавливаем крупный шрифт
      u8g.setFont(u8g_font_profont22);
      u8g.drawStr(1, 32, "Pres:");
      u8g.setPrintPos(62,32);
      u8g.print(_mrData.rxData.pressure);      
      u8g.setPrintPos(100,32);
      u8g.print("mm");      
}

/**************************************** Функции вывода освещенности ****************************************************/
void fnShowLux(void)
{
    // рисуем разделительную полоску
  u8g.setFont(u8g_font_profont11);
  u8g.drawStr(30, 8, "illumination");  
  u8g.drawLine(2,11,125,11);

// устанавливаем крупный шрифт
  u8g.setFont(u8g_font_profont22);
  u8g.drawStr(1, 32, "Illum:");
  u8g.setPrintPos(74,32);
  u8g.print(_mrData.rxData.lux);   
}

/****************************************** Функции вывода влажности ****************************************************/
void fnShowHumidity(void)
{
  // рисуем разделительную полоску
  u8g.setFont(u8g_font_profont11);
  u8g.drawStr(34, 8, "humidity");  
  u8g.drawLine(2,11,125,11);

// устанавливаем крупный шрифт

  u8g.setFont(u8g_font_profont22);
  u8g.drawStr(1, 32, "humid:");
  u8g.setPrintPos(74,32);
  u8g.print(_mrData.rxData.humidity);   

}

/****************************************** Функции работы с картой SD ***************************************************/
// Получение информации о состоянии SD карты

void fnInfoSD(void)
{  
  // устанавливаем шрифт
    u8g.setFont(u8g_font_profont11);
    // выводим шапку
    u8g.drawStr(30, 8, "SD-card info");    
    // рисуем разделительную полоску
    u8g.drawLine(2,11,125,11); 

    if(_SDexists)
    {
      switch (_mrCard.type())
      {
        case SD_CARD_TYPE_SD1:
          u8g.drawStr(1, 22, "SD type: SD1");
        break;
        case SD_CARD_TYPE_SD2:
          u8g.drawStr(1, 22, "SD type: SD2");
        break;
        case SD_CARD_TYPE_SDHC:
          u8g.drawStr(1, 22, "SD type: SDHC");
        break;
        default:
          u8g.drawStr(1, 22, "SD type: unknown");          
      }
      if(!_mrVolume.init(_mrCard))
      {
        u8g.drawStr(1, 22, "Could not find partition");      
      }
      
      u8g.drawStr(1, 33, "FAT type: ");
      
      uint32_t _vs = _mrVolume.blocksPerCluster();
      
      _vs *= _mrVolume.clusterCount();
      
      _vs /= 1024;
      _vs /= 1024;
      _vs *= 512;
      String _sdSize = String(_vs, DEC);
    
      u8g.setPrintPos(58, 33); 
      u8g.print(_vs);

      u8g.drawStr(1, 45, "total files: ");
      u8g.setPrintPos(76, 45);
      //u8g.print(fnFileNumSD(0));      
      u8g.print(fnFileNumLines("10-05-17.txt"));     
                 
    }
    else
    {
      u8g.drawStr(8, 24, "--- no SD card ---");        
    }    
}

/************************************************************************************************************************/
// Функция создает на SD карте файл с именем формата dd-mm-YY.txt
// Данные берутся с часов реального времени, т.е. (_myRTC.gettime("d-m-Y")
// Сначала сравниваем текущее имя файла с текущей датой
// 
void fnCreateFile()
{
  String _Y = _myRTC.gettime("Y");
  String _dm = _myRTC.gettime("d-m");
  _fileName = _dm + "-" + _Y[2] + _Y[3] + ".txt";
 
  if(_SDexists)
  {
  // Проверяем, если файла с таким именем нет, то создаем его
    if(!SD.exists(_fileName))
    {
      _mrFile = SD.open(_fileName,FILE_WRITE);
      _mrFile.close(); 
    }
  }  
}

/***********************************************************************************************************************/
// Запись метео-информации на SD
// Запись производим каждые 10 минут (_m == 0)
// Каждый раз проверяем, если был переход на новую дату, то формируем новый файл с новым именем и пишем уже в него
//
void fnWriteSD()
{  
  String _s;
  // Строка содержит текущие минуты 
  // Запись производим только тогда, когда число минут кратно 10  

  // Переменной _s присваиваем значение минут текущего времени и преобразуем это значение в целое
  _s = _myRTC.gettime("i");
  int j;
  j = _s.toInt();

  if(_SDexists)     // Если карта вставлена, пишем в файл данные с метеостанции
  {
    // Если число минут кратно 10 (5) и запись еще не производилась (_write == 0), то начинаем запись   
  if(fnRestDiv(j,5) && _write == 0)
    {   
      _mrFile = SD.open(_fileName, FILE_WRITE);

      if(_mrFile)
        {
        _mrFile.print(_myRTC.gettime("d-m-Y"));
        _mrFile.print("/");
        _mrFile.print(_myRTC.gettime("H:i:s"));
        _mrFile.print("/");
        _mrFile.print(_mrData.rxData.temp);
        _mrFile.print("/");
        _mrFile.print(_mrData.rxData.lux);
        _mrFile.print("/");
        _mrFile.print(_mrData.rxData.pressure);
        _mrFile.print("/");
        _mrFile.print(_mrData.rxData.humidity);
        _mrFile.print("/");
        _mrFile.print(_mrData.rxData.wspeed);
        _mrFile.print("/");
        _mrFile.print(_mrData.rxData.wdir);
        
        _mrFile.println();        
        _mrFile.close();
        
        }
        // Записали, устанавливаем флаг, что запись уже была (_write = 1)
      _write = 1;
  }  
  // Сбрасываем признак произведенной записи
    if(!fnRestDiv(j,5))
    {
      _write = 0;
      _mrFile.close();
    }
  }
}

/*******************************************************************************************************************/
/************************* Функция считывает заданное значение из файла с SD карты *********************************/
// 
void fnReadSD(int par)
{
  
}


/*******************************************************************************************************************/
/*********************** Функция подсчитывает число строк в заданном файле на карте SD *****************************/
// 
int fnFileNumLines(String _fName)
{
  unsigned char _ch;
  int i = 0;
  
  // Открываем текущий файл
   _mrFile = SD.open(_fName);
   
   // Если файл удачно открыт, начинаем его побайтно читать
   if(_mrFile)
   {
    // Читаем до конца файла
    while(_mrFile.available())
      {
        _ch = _mrFile.read();
        // Если встречаем перевод строки, то увеличиваем i на единицу
        if(_ch == 0x0D) { i++; }    
      }    
   }
   _mrFile.close();
   return i;
}

/*******************************************************************************************************************/
/************************ Функция подсчитывает число файлов на карте SD  и их суммарный объем **********************/
// p = 0; - возвращает число файлов
// p = 1; - возвращает суммарный объем файлов
// Переменные _root и _entry объявлены как глобальные
//
long fnFileNumSD(int p)
{
  // пока игнорируем параметр p
  int i = 0;
  long _size = 0;  

// Перемещение в корневую директорию выполнено в setup
//  _root = SD.open("/");

// Перемещаемся к первому файлу
  _entry = _root.openNextFile();  

  while(true)
  {    
    _entry = _root.openNextFile();
    i++;

    if(!_entry)
    { break; }        

    /*
    Serial.print("file name = ");
    Serial.println(_entry.name());
     Serial.print("file size = ");
    Serial.println(_entry.size());
    */
    
    _size = _size + _entry.size();
    /*
    Serial.print("i = ");
    Serial.println(i);
    */
     /*
    Serial.print("_size = ");
    Serial.println(_size);
       */ 
  }
    
 // _root.close();
 // _entry.close();

// Снова вроде перемещаемся в корень
  _root = SD.open("/");
  return _size;   
}

/*******************************************************************************************************************/
// Инициализация карты
//
void fnIniSD(void)
{
  // Проверяем наличие карты
  // используется pin 53 Arduino-Mega сигнала CS карты
  if (!_mrCard.init(SPI_HALF_SPEED, _csSD))
  {
    _SDexists = false;    
  }
  else
  {
    _SDexists = true;    
    SD.begin(_csSD);    
  }  
}

/***********************************************************************************************************************/
/************************************ Основная функция вывода на экран *************************************************/
/***********************************************************************************************************************/
// Основная Функция вывода на экран информации
//
// Передаваемые параметры:
// status - статус метеоприемника, режим вывода информации на монитор
// cursorPos - позиция курсора
// digitToCorr - новое значение корректируемого параметра
// status = 0; основной режим работы, выводим мелким шрифтом дату, время, температуру, освещенность, давление, влажность
// status = 1; вывод информации о SD карты
// status = 9; режим установки даты и времени (нажатие кнопки 9 на клавиатуре)
//
void fnShowData(char status, int cursorPos, int digitToCorr)
{
  switch(status)
  {    
    // Основной режим: выводим дату, время, температуру, освещенность, давление, влажность
    case '0':
     // устанавливаем шрифт
      u8g.setFont(u8g_font_profont11);
      // выводим дату
      u8g.drawStr(4, 9, _myRTC.gettime("d-m-Y"));  
      // выводим время
      u8g.drawStr(76, 9, _myRTC.gettime("H:i:s"));
      // рисуем разделительную полоску
      u8g.drawLine(2,11,125,11);

      // далее выводим показания датчиков
      u8g.setFont(u8g_font_profont11);
      u8g.drawStr(0, 22, "temp:");
      u8g.setPrintPos(32, 22); 
      u8g.print(_mrData.rxData.temp);     
      
      u8g.drawStr(0, 34, "lumen:");
      u8g.setPrintPos(38, 34); 
      u8g.print(_mrData.rxData.lux);  
      
      u8g.drawStr(0, 58, "humi:");
      u8g.setPrintPos(38, 58); 
      u8g.print(_mrData.rxData.humidity);

      u8g.drawStr(0, 46, "press:");
      u8g.setPrintPos(38, 46); 
      u8g.print(_mrData.rxData.pressure);  

      if(_SDexists)
      {
        u8g.drawStr(64, 58, "SD present");              
      }
      else
      {
        u8g.drawStr(64, 58, "no SD");            
      } 
           
    break;    

    // Выводим информацию о SD карте
    case '1':
      fnInfoSD();
    break;

    case '2':
      fnShowTemp();
    break;

    case '3':
      fnShowPress();
    break;

    case '4':
      fnShowLux();
    break;

    case '5':
      fnShowHumidity();
    break;

    case '6':      
    break;

    // статус равен 'A', выводим дату и время для их редактирования
    case 'A':
      u8g.setFont(u8g_font_profont11);    
      u8g.drawStr( 1, 8, "date and time setting");
      u8g.drawLine(2,11,125,11);
      u8g.setFont(u8g_font_profont22);     
      u8g.drawStr( 0, 32, _myRTC.gettime("d-m-Y"));
      u8g.drawStr( 0, 56, _myRTC.gettime("H:i:s")); 
      fnDrawCursor(cursorPos, _blinkCursor);    
    break;    
  }
}

/*******************************************************************************************************************/

/*******************************************************************************************************************/
// Начальные установки
void setup()
{
  Serial.begin(9600);
  
  _mrStatus = '0';
  fnIniRTC();
  fnIniSD();
  _root = SD.open("/"); 
  
  fnIniNRF();
  RX_Mode();  
  pinMode(_ledSD,OUTPUT);  
}

/*******************************************************************************************************************/
// Основной цикл программы
// 1. Считываем символ нажатой клаваши
// 2. В зависимости от статуса метеоприемника выполняем определенные действия
//
//
void loop()
{
  // Тестовая запись в порт
  // Serial.println("987654321quir");

/*******************************************************************************************************************/
// Здесь мы должны запрашивать данные с метеостанции и заполнять соответствующие переменные
fnReadMRData();

/*******************************************************************************************************************/
// Здесь мы должны создать файл с заданным именем и записать на карту SD полученные с метеостанции данные
fnCreateFile();
fnWriteSD();
  
/*******************************************************************************************************************/
/*******************************************************************************************************************/
  
// В основном цикле постоянно считываем код нажатой клавиши
  _customKey = customKeypad.getKey();

  switch(_customKey)
  {

    // Если нажата клавиша "С", то независимо от статуса, переходим в статус 0
    case 'C':
      _mrStatus = '0';
    break;

// Если нажата клавиша 'A', то независимо от режима, переходим в режим коррекции времени
    case 'A':
      _mrStatus = 'A';
      _mrCursorPos = 1;
// Заполняем переменные текущим времением и датой
      fnFillDateTime();
    break;

    case '0':
      if(_mrStatus != 'A')
      {
        _mrStatus = '0';
      }      
    break;

    case '1':
    if(_mrStatus != 'A')
      {
        _mrStatus = '1';
      }      
    break;

    case '2':
    if(_mrStatus != 'A')
      {
        _mrStatus = '2';
      }  
      
    break;

    case '3':
    if(_mrStatus != 'A')
      {
        _mrStatus = '3';
      }  
      
    break;

    case '4':
    if(_mrStatus != 'A')
      {
         _mrStatus = '4';
      }  
     
    break;

    case '5':
    if(_mrStatus != 'A')
      {
       _mrStatus = '5';
      }  
      
    break;

    case '6':
      if(_mrStatus != 'A')
      {
        _mrStatus = '6';
      }  
      
    break;

    case '7':
      if(_mrStatus != 'A')
      {
       _mrStatus = '7';
      }  
      
    break;

    case '8':
      if(_mrStatus != 'A')
      {
        _mrStatus = '8';
      }      
    break;

    case '9':
      if(_mrStatus != 'A')
      {
        _mrStatus = '9';
      }      
    break;
        
  }

// Если статус равен 'A' (коррекция даты и времени), то в зависимости от нажатой клавиши
if(_mrStatus == 'A')
{ 
   
// Если в состоянии коррекции времени нажата цифровая клавиша, то присваеваем новой значение переменной заданной позиции курсора,
// и сразу заносим данные в часы реального времени
      if(isDigit(_customKey))
      {        
        switch(_mrCursorPos)
        {          
          case 1:
            _mrDd =  _customKey - 48;            
          break;

          case 2:
            _mrDu = _customKey - 48;
          break;

          case 3:
            _mrMnd = _customKey - 48;
          break;

          case 4:
            _mrMnu = _customKey - 48;
          break;

          case 5:
            _mrYt = _customKey - 48;
          break;

          case 6:
            _mrYh = _customKey - 48;
          break;

          case 7:
            _mrYd = _customKey - 48;
          break;

          case 8:
            _mrYu = _customKey - 48;
          break;

          case 9:
            _mrHd = _customKey - 48;
          break;

          case 10:
            _mrHu = _customKey - 48;
          break;

          case 11:
            _mrMd = _customKey - 48;
          break;     

          case 12:
            _mrMu = _customKey - 48;
          break;         
          
        }

// Заносим в часы новое значение даты и времени (если были изменения, т.е. была нажата цифровая клавиша)       
        _myRTC.settime(0,_mrMd*10+_mrMu, _mrHd*10+_mrHu, _mrDd*10+_mrDu, _mrMnd*10+_mrMnu, _mrYd*10+_mrYu);          
               
      }

// Если нажаты клавиши * или #, то перемещаем курсор
// Двигаемся "назад"
    switch(_customKey)
    {
        case '*':        
        if(_mrCursorPos == 1)
        {
          _mrCursorPos = 12; 
        }
        else
        {
          _mrCursorPos --;
        }
        break;
        
// Двигаемся вперед
        case '#':
        
        if(_mrCursorPos == 12)
        {
          _mrCursorPos = 1; 
        }
        else
        {
          _mrCursorPos ++;
        }      
    }  
}
 
/*****************************************************************************************************************************/  
  u8g.firstPage();  
  do
  {     
    fnShowData(_mrStatus, _mrCursorPos, 0);
  }
  while( u8g.nextPage() );  
/*****************************************************************************************************************************/  
// Чтобы показать мигающий курсор, вычисляем промежуток времени для получения интервала в 0.75 сек
// Если с момента _timeDelay = milis() прошло более 0.75 сек, то включаем курсор (в режиме установки даты и времени)
// и "обнуляем" временный промежуток
// Если прошло менее 0.75 сек, то просто выключаем курсор
if(millis() - _timeDelay > 750)
{
  _timeDelay = millis();
  _blinkCursor = 0;
  digitalWrite(_ledSD,LOW);  
}
else
{
  if(millis() - _timeDelay < 350)
  { _blinkCursor = 0; }
  else
  {
    _blinkCursor = 1;  
    digitalWrite(_ledSD,HIGH);
  }  
}
}

 

ulis
ulis аватар
Offline
Зарегистрирован: 09.03.2011

Ну где ж вы раньше были!? :)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ulis пишет:

Ну где ж вы раньше были!? :)

Да код для генератора пытался править, есть глюк при переходе из ручного в автоматический режим