Разработка библиотеки

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Здравствуйте.

Хочу вынести функции обработки команд оn модуля SIM800 в отдельную библиотеку

#include <SoftwareSerial.h>
#include <Sim800L.h>
SoftwareSerial SIM800(9,10);// RX, TX


void setup() {
  SIM800.begin(19200);
  Serial.begin(19200);
  Serial.println("Zagruzka");
}
void loop() {

  if(SIM800.available())  Sim800L Otvet(SIM800.readString());

}






 

/*
  Sim800L.h - Заголовочный файл
*/

#ifndef _Sim800L_H_
#define _Sim800L_H_




#include <Arduino.h>
class Sim800L
{
  public:
	Sim800L(String Otvet);
};
 
#endif

 

/*
  Sim800L.cpp - Файл реализации
*/
#include "Sim800L.h"


Sim800L::Sim800L(String Otvet)
{
  Otvet.trim();
  Serial.println("Otvet: "+Otvet);
}

 

Верна ли логика?

rkit
Offline
Зарегистрирован: 23.11.2016

Нет. Правильная логика - взять готовую библиотеку, а свое время потратить продуктивно.

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Какую готовую? У меня свои функции в библиотеке будут.

Меня интересует логика работы библиотеки, разработка библиотеки

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

Наверно должно быть так:
SoftwareSerial SimPort(9, 10); // RX, TX
SIM800 mySim(SimPort);

 

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Примитивненько, но работает
http://arduino.ru/forum/apparatnye-voprosy/vse-o-sim800l-i-vse-chto-s-ni...

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

andycat пишет:
Примитивненько, но работает http://arduino.ru/forum/apparatnye-voprosy/vse-o-sim800l-i-vse-chto-s-nim-svyazano?page=2#comment-494752

а я по моему по твоей подсказке в допиленный SomeSerial CustomSoftwareSerial обернул, надо было обязательно выставить 8N2 для порта, работает как швейцарские часы, даже на одно прерывание с портом энкодер повесил для экспериментов

ЗЫ Иринка, иди мужу рогалики пеки, основа библиотеки уже есть, даже больше, на сегодня план выполнен )))

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Спасибо, Буду разбираться.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Irinka пишет:

Это не к логике, но всё-таки, вместо

Sim800L(String Otvet);

пишите

Sim800L(String & Otvet);

Намного лучше в данном случае.

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

Irinka пишет:

Спасибо, Буду разбираться.

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

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Здравствуйте.  Проверить работу кода не могу, нет под рукой устройств, поэтому немного теоретических вопросиков.

Скетч

#include "Modem.h"

#define MAX_BUF_SIZE 50
Modem SIM800(MAX_BUF_SIZE);

void setup() {
  Serial.begin(9600);
  Serial.println("Start");
}

void loop() {}

Modem.h

//Modem.h

#pragma once
#include <Arduino.h>

class Modem {
  public:
    Modem (uint8_t max_buf_size);
    void Reading(uint8_t temp);

  private:
    void clear_buffer();

    uint8_t _max_buf_size;
    uint8_t  _pos_buf;
    char _buffers[50];
};
Modem.cpp
//Modem.cpp
#include "Modem.h"

Modem::Modem(uint8_t max_buf_size = 50) {
  _max_buf_size = max_buf_size;
}

void Modem::clear_buffer() {
  memset(_buffers, 0, _max_buf_size);
  _pos_buf = 0;
}


void Modem::Reading(uint8_t temp) {

  if (_pos_buf >= _max_buf_size) {
    clear_buffer();
  } else {
    _buffers[_pos_buf] = temp;
    _pos_buf++;

    if (temp == '\n' && _pos_buf > 1 && _buffers[_pos_buf - 2] == '\r') {


      clear_buffer();
    }
  }
}

 

 

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Вопрос первый:

Код Modem.cpp 17 и 25 строки, верное обращение к функции? или Modem::clear_buffer()

Второй вопрос:

Modem.h переменная char _buffers[50]; Вместо значения 50 должна быть переменная.

В private объявлять пустой массив

  private:
    char _buffers[];

а в конструкторе устанавливать размер?

Modem::Modem(uint8_t max_buf_size = 50) {
  _max_buf_size = max_buf_size;
  _buffers[_max_buf_size];
}

 

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Я конечно не спец по C++, но основная функция конструктора именно выделерие памяти и инициализация переменных/объектов.
ЗЫ. Тяжела женская логика, вопроса на понял (

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Я прочитала что размер массива должен быть известен до начала выполнения программы

 

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

Первый, вопрос - да, верное
Второй вопрос в привате объявляете указатель на массив, а в конструкторе выделяете под массив память
Как делать можно глянуть в этой теме - https://arduino.ru/forum/pesochnitsa-razdel-dlya-novichkov/problemka-s-d...

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Irinka пишет:

Я прочитала что размер массива должен быть известен до начала выполнения программы

 


Всё зависит от задачи и от МК, например :
Если места нет как в avr для крупной обработки, выделяем крошечный буфер байт сто и в нем работаем, типичный пример можете посмотреть библиотеку ethernet 2, там буфер байт 30 и его заполняют и online отправляют.
Другой пример из последнего : ioLibrary от wiznet, там в http server разработчики вообще не парились, через alloc выделяют памяти в размер страницы http,есть у вас пару тройку килобайт, столько и нарисуют.

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

v258 пишет:
Первый, вопрос - да, верное Второй вопрос в привате объявляете указатель на массив, а в конструкторе выделяете под массив память Как делать можно глянуть в этой теме - https://arduino.ru/forum/pesochnitsa-razdel-dlya-novichkov/problemka-s-digisparkom

 

private:
char* _buffers = NULL;

Modem::Modem(uint8_t max_buf_size = 50) {
  _max_buf_size = max_buf_size;
  _buffers = new char(max_buf_size);
}


Так?

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Irinka, вопрос: те кто теоретически будут использовать вашу библиотеку должны мозг включать чтоб знать сколько байт долно быть в буфере?
Если делаете для себя то и пропишите жёстко количество.
Ну а если универсальное - то сами должны определить количество.

sadman41
Offline
Зарегистрирован: 19.10.2016

MAX_BUF_SIZE часто меняться будет? В зависимости от чего?

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

всё, сгорели котлеты )))

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

andycat пишет:
Irinka, вопрос: те кто теоретически будут использовать вашу библиотеку должны мозг включать чтоб знать сколько байт долно быть в буфере? Если делаете для себя то и пропишите жёстко количество. Ну а если универсальное - то сами должны определить количество.

Библиотеку буду использовать только я сама. С размером буфера возник вопрос, только потому что хочу понять как задать размер массива при создании объекта

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

ua6em пишет:

всё, сгорели котлеты )))

А я то чего, я то ничего. Какие котлеты в 22 часа? (по МСК)

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

sadman41 пишет:
MAX_BUF_SIZE часто меняться будет? В зависимости от чего?

Нет, но хочу знать как задать размер массива при создании объекта

sadman41
Offline
Зарегистрирован: 19.10.2016

При создании - константой. В рантайме malloc-ом (он же new).

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Irinka пишет:

andycat пишет:
Irinka, вопрос: те кто теоретически будут использовать вашу библиотеку должны мозг включать чтоб знать сколько байт долно быть в буфере? Если делаете для себя то и пропишите жёстко количество. Ну а если универсальное - то сами должны определить количество.

Библиотеку буду использовать только я сама. С размером буфера возник вопрос, только потому что хочу понять как задать размер массива при создании объекта


Всё зависит от логики работы, в примерах выше мне 16 байт хватало на все,. Дело вкуса...

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Вот смотрите

class Modem {
  public:
    Modem (uint8_t max_buf_size);
    void Reading(uint8_t temp);
    void counts();

  private:
    void clear_buffer();

    uint8_t _max_buf_size;
    uint8_t  _pos_buf;
    char* _buffers = NULL;
};
Modem::Modem(uint8_t max_buf_size = 50) {
  _max_buf_size = max_buf_size;
  //_buffers = new char(max_buf_size);
  _buffers = (char *)calloc(5, sizeof(char));
}

void Modem::counts() {
  Serial.println(_max_buf_size);
  Serial.println(sizeof(_buffers) / sizeof(_buffers[0]));
}
#define MAX_BUF_SIZE 40
Modem SIM800(MAX_BUF_SIZE);

void setup() {
  Serial.begin(9600);
  Serial.println("Start");
  SIM800.counts();
//Получаю 40
//Получаю 2
}

void loop() {}

В протеусе проект накидала с ардуинкой)

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

Irinka пишет:

ua6em пишет:

всё, сгорели котлеты )))

А я то чего, я то ничего. Какие котлеты в 22 часа? (по МСК)

я о перпективе...шучу конечно...

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

Irinka пишет:

v258 пишет:
Первый, вопрос - да, верное Второй вопрос в привате объявляете указатель на массив, а в конструкторе выделяете под массив память Как делать можно глянуть в этой теме - https://arduino.ru/forum/pesochnitsa-razdel-dlya-novichkov/problemka-s-digisparkom

 

private:
char* _buffers = NULL;

Modem::Modem(uint8_t max_buf_size = 50) {
  _max_buf_size = max_buf_size;
  _buffers = new char(max_buf_size);
}


Так?


Да

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Тогда я получаю
SIM800.counts();

Получаю 40
Получаю 2
Код выше

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

Строка 04

_buffers = (char *)calloc(max_buf_size, sizeof(char));

Ну как бэ немножко-то думать нужно ))

sadman41
Offline
Зарегистрирован: 19.10.2016

Irinka пишет:
Тогда я получаю
SIM800.counts();

Получаю 40
Получаю 2
Код выше


Работа с указателями не эквивалентна работе с массивами. Указатель ничего "не знает" о размерности массива, он просто хранит адрес его первого элемента.

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

v258 пишет:
Строка 04 _buffers = (char *)calloc(max_buf_size, sizeof(char)); Ну как бэ немножко-то думать нужно ))

_buffers = (char *)calloc(5, sizeof(char));

У меня так и есть, просто поставила размер 5)

А получаю в мониторе

40

2

 

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

sadman41 пишет:
Irinka пишет:
Тогда я получаю SIM800.counts(); Получаю 40 Получаю 2 Код выше
Работа с указателями не эквивалентна работе с массивами. Указатель ничего "не знает" о размерности массива, он просто хранит адрес его первого элемента.

То есть размер массива у меня задаётся верно?

Если я ставлю размер изначально char _buffers[25] то получаю

25

25

sadman41
Offline
Зарегистрирован: 19.10.2016

Вам нужно понимать, что когда память выделяется статически через buffers[25], компилятор (!) может учесть эту размерность и правильно ей оперировать, проверяя выход за границы массива, вычисление sizeof и т.п. В случае со всякими *alloc, компилятор в процессе не участвует, так как все уже превращено в инструкции процессора, а *alloc выполняется как и другой пользовательский код. Программисту (!) следует самому озаботиться хранением размерности фрагмента выделенной памяти и проверкой на всякие записи "не туда".

Одним словом - если буфер статичен всегда, не нужно извращаться с указателями, особенно - если пока не понимаете их механики. Задайте размер массива через константу и позвольте компилятору делать то, что он умеет лучше. Всяким там маллокам место в других ситуациях. Например, когда нужно только иногда организовывать такой буфер попеременно используя один и тот же фрагмент памяти то для формирования JSON, который будет отдан в сеть, то для строки вывода на LCD.

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Хорошо. Спасибо)

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Здравствуйте.

Подскажите

Buttons.h

//Buttons.h
#pragma once
#include <Arduino.h>


class Buttons {
  public:
    Buttons (uint8_t pin);

    bool pressing() {
      bool pinstat = digitalRead(_pin);
      return pinstat;
    };




  private:
    uint8_t _pin;
};

 

Buttons.cpp

//Buttons.cpp
#include "Buttons.h"


Buttons::Buttons(uint8_t pin) {
  _pin = pin;
  pinMode(_pin, INPUT);
}

 

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Если я объявляю в классе bool pressing();

class Buttons {
  public:
    Buttons (uint8_t pin);
    bool pressing();
 
  private:
    uint8_t _pin;
};

То  в Buttons.cpp компилятор ругается на Buttons::pressing() {

prototype for 'int Buttons::pressing()' does not match any in class 'Buttons

Buttons::pressing() {
  bool pinstat = digitalRead(_pin);
  return pinstat;
};
 
Что это значит? Как я понимаю неправильно обращаюсь к переменной bool pressing ?
Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Разобралась...

bool Buttons::pressing() {
  bool pinstat = digitalRead(_pin);
  return pinstat;
};

 

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

Irinka пишет:

Разобралась...

bool Buttons::pressing() {
  bool pinstat = digitalRead(_pin);
  return pinstat;
};

за 4-ре минуты, похвально...

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Ахах, а как же время написания ответа?))) Минусуйте! Максимум 1,7 минуты! XDDD

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Скетч

#include "Buttons.h"

Buttons bu1(2);
Buttons bu2(3);

void setup() {
  Serial.begin(9600);
  Serial.println("Start");
}

void loop() {
  if (bu1.pressing())Serial.println("bu1 > 500");
  if (bu2.pressing())Serial.println("bu2 > 500");
}

Buttons.h

//Buttons.h
#pragma once
#include <Arduino.h>


class Buttons {
  public:
    Buttons (uint8_t pin);
    bool pressing();

  private:
    uint8_t _pin;
    uint32_t _tmr;
    uint8_t _stat;
};

Buttons.cpp

//Buttons.cpp
#include "Buttons.h"


Buttons::Buttons(uint8_t pin) {
  _pin = pin;
  _stat = 0x00;
  pinMode(_pin, INPUT);
}

bool Buttons::pressing() {
  bool pinstat = digitalRead(_pin);
  bool stat_ret = false;

  switch (_stat) {

    case 0x00:
      if (pinstat)_stat = 0x01;
      break;

    case 0x01:
      if (!pinstat ) {
        _tmr = millis();
        _stat = 0x02;
      }
      break;

    case 0x02:
      if (!pinstat) {
        if (millis() - _tmr >= 500) {
          _stat = 0x00;
          stat_ret = true;
        }
      } else {
        _tmr = millis();
      }
      break;
  }
  return stat_ret;
};

Задача: отследить изменение состояния кнопки с 1 на 0 плюс дребезг 500 мс

Верна логика? Или намудрила?

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

дребезг полсекунды - это через край, обычно 50 мс достаточно

что касается логики - могу посоветовать нарисовать блок-схему - так будет наглядно видно, что да как. А по блок-схеме уже и код писать ))

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

Irinka пишет:

Ахах, а как же время написания ответа?))) Минусуйте! Максимум 1,7 минуты! XDDD

всё таки минута 48 секунд )))

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

v258 пишет:

дребезг полсекунды - это через край, обычно 50 мс достаточно

что касается логики - могу посоветовать нарисовать блок-схему - так будет наглядно видно, что да как. А по блок-схеме уже и код писать ))

Больше подходит слово удержание, чем дребезг)

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

ua6em пишет:

Irinka пишет:

Ахах, а как же время написания ответа?))) Минусуйте! Максимум 1,7 минуты! XDDD

всё таки минута 48 секунд )))

Agree)

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

Irinka пишет:

v258 пишет:

дребезг полсекунды - это через край, обычно 50 мс достаточно

что касается логики - могу посоветовать нарисовать блок-схему - так будет наглядно видно, что да как. А по блок-схеме уже и код писать ))

Больше подходит слово удержание, чем дребезг)

Это разные понятия )) Дребезг нужно отсеивать в любом случае

В общем случае нужна одна функция, которая постоянно мониторит состояние кнопки и по изменениям выставляет события/флаги событий. Это если нужно отслеживать разные события кнопки - нажата, отпущена, удерживается и т.д.

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Ну тут и получается как антидребезг, поставить время 50 мс

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

Примерный алгоритм

Если поднят флаг антидребезга, то
  
  Если интервал антидребезга еще не прошел, то ничего не делать, иначе

    - опустить флаг антидребезга
    - выдать событие нажатия/отпускания кнопки в зависимости от текущего состояния ее контактов
    - сохранить текущее состояние кнопки

Если флаг антидребезга не поднят, то

  Если текущее состояние кнопки равно сохраненному, то ничего не делать, иначе
    
    - поднять флаг антидребезга
    - запустить таймер антидребезга

Как-то так

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

Если нужно отслеживать еще и удержание кнопки, то алгоритм немного усложняется

Если поднят флаг антидребезга, то
  
  Если интервал антидребезга еще не прошел, то ничего не делать, иначе

    - опустить флаг антидребезга
    - выдать событие нажатия/отпускания кнопки в зависимости от текущего состояния ее контактов
    - сохранить текущее состояние кнопки

Если флаг антидребезга не поднят, то

  Если текущее состояние кнопки не равно сохраненному, то
    
    - поднять флаг антидребезга
    - запустить таймер антидребезга

  Если текущее состояние кнопки равно сохраненному, и кнопка нажата, то

    Если интервал удержания прошел (можно использовать таймер антидребезга, тогда удержание будет отсчитываться от момента первого касания контактов кнопки)

      - выдать событие удержания кнопки нажатой

Событие удержания будет выдаваться все время, пока кнопка удерживается нажатой. Если нужно однократное событие удержания, то придется заводить еще один флаг - удержания кнопки и выдавать событие только если флаг еще не поднят (и тут же его поднимать). И сбрасывать этот флаг в момент отпускания кнопки ))

В общем, без поллитры блок-схемы мозг сломать можно )))

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

Irinka пишет:

Ну тут и получается как антидребезг, поставить время 50 мс

зависит от кнопок, для моих от 70 до 120 миллисекунд

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

https://github.com/kakmyc-github/kakmyc_btn

И не парюсь уже пару лет. ))