Ви не увійшли.
Є код, не спаплюжений автоперекладачем?
В цьому "коді", як можна зрозуміти, налаштування кожного таймера зберігається в EEPROM у такому форматі:
#байта значення
0 активний/неактивний
1 година увімкнення
2 хвилина увімкнення
3 година вимкнення
4 хвилина вимкнення
5 номер канала
6 рівень сигнала
7 бітова маска днів тижняТобто час задається дискретно по хвилинах.
Щоб зробити по секундах, можна доповнити структуру ще двома полями: секунда увімкнення і секунда вимкнення. Тоді в обчисленні часу замість
timeTimerStart = (uint32_t)funcReadTimer(i, 1) * 3600 + funcReadTimer(i, 2) * 60;
timeTimerStop = (uint32_t)funcReadTimer(i, 3) * 3600 + funcReadTimer(i, 4) * 60; буде щось типу
timeTimerStart = (uint32_t)funcReadTimer(i, 1) * 3600 + funcReadTimer(i, 2) * 60 + funcReadTimer(i, 8);
timeTimerStop = (uint32_t)funcReadTimer(i, 3) * 3600 + funcReadTimer(i, 4) * 60 + funcReadTimer(i, 9);Тоді структура займатиме 10 байт замість 8-ми, тому потрібно змінити індексування EEPROM:
uint8_t funcReadTimer(uint8_t i, uint8_t j) {
return EEPROM[i * 10 + j];
}
...
void funcSaveTimer(uint8_t i, uint8_t j, uint8_t k) {
EEPROM[i * 10 + j] = k;
}і решту коду, де очікується 8-байтова структура. Відповідно зміниться і кількість доступних таймерів з "кількість байт EEPROM/8" на "кількість байт EEPROM/10".
Також знадобиться додати установку секунд в UI.
Якщо буде достатньо дискретності в 2 секунди (тобто тільки 0, 2, 4, .. 58 секунд), то можна упакувати поле часу в ті ж два байта і обійтись без зміни розміру структури: 5 біт на години, 6 біт на хвилини і 5 біт на секунди. Або зберігати час просто як кількість 2-секундних інтервалів від початку доби.
UPD: ще, щоб не змінювати розмір структури, але отримати дискретність в 1 секунду, можна використати біти з нульового байта структури і упакувати додаткові біти секунд у нього.
В чому полягає питання? Звідки -38?
Ви вводите два символи: '3' і перевод строки з кодом 10. 10 - 48 (код символу '0') = -38.
Що вже працює і на якому етапі перестає?
GSM-модуль реєструється в мережі? Отримує IP-адресу?
Вдається встановити TCP-зʼєднання хоч з яким-небудь сервером, без передачі даних? Наприклад, з будь-яким працюючим web-сервером на порт 443?
Ваш хост, який ви плануєте використовувати в ролі сервера, має глобальну (білу) IP-адресу? Якщо ні, то прокиньте порт на свій хост на роутері. Спробуйте встановити зʼєднання з девайса на вашу глобальну адресу і цей порт. У wireshark маєте побачити хоча би спробу TCP зʼєднання (SYN-пакет). Потім запустіть той же socat, чи netcat, чи що там є під вашу операційну систему.
шлях до бібліотек я вставляла в c_cpp_properties.json, який я скинула вище
Налаштування в c_cpp_properties.json впливають на збірку вбудованими в VSCode засобами та на IntelliSense. На збірку проекту зі стороннім Makefile вони не впливають.
Ваш Makefile не підходить для збірки ардуіно-скетчів. Як мінімум, він компілює проект на C, а скетчі пишуться на C++. Проблему з #include <OneWire.h> можна вирішити, додавши "INCLUDE += -I<шлях_до_хідера>". Але це вам не допоможе, тому що бібліотеку потрібно ще теж скомпілювати і прилінкувати. В принципі, і ваш Makefile можна адаптувати для компіляції C++, компіляції бібліотеки і лінковки з нею. Але простіше буде, як порадили вище, взяти готове рішення у вигляді arduino-mk.
З якою із частин яка конкретно проблема?
Будь-яку задачу, складнішу за блимання єдиним світлодіодом, декомпонуйте на простіші підзадачі і вирішуйте їх послідовно.
Спочатку реалізуйте індикацію, просто відображення довільних цифр.
Потім реалізуйте взаємодію з мікросхемою годинника по I²C, відображайте поточний час.
Далі реалізуйте обробку натиснення кнопок і перемикання внутрішнього стану. Меню - це класичний скінченний автомат, ознайомтесь із теорією автоматів.
Поступово доповнюйте функціонал, але беріться за наступну функцію після того як попередні вже працюють.
За яким протоколом "сайт" очікує дані? "Сирий" TCP чи UDP? HTTP GET/PUT/POST? В якому форматі мають бути дані?
Прімітивний TCP сервер можна запустити за допомогою
$ socat TCP-LISTEN:8080 - Звісно, хост, на якому запускається сервер, має бути доступний з GPRS-мережі.
Відслідковувати трафік можна, наприклад, за допомогою wireshark.
Існують різні методи. Можна відтворювати PCM-кодований сигнал за допомогою ШІМ або зовнішнього DAC. Але при розрядності 8 біт і частоті дискретизації 8 кГц 1 секунда звуку займатиме 8 кб. На Atmega328p без зовнішньої EEPROM влізе не більше 4 секунд, а там ще код і бутлоадер. Якщо знизити розрядність до 4 біт, то влізе вдвічі більше, але якість буде гіршою.
Одноголосну мелодію можна відтворити "цифровим" методом, генеруючи прямокутний сигнал. tone()/delay() - це найпростіший спосіб.
#define PIN_BUZZER 3
void setup() {
pinMode(PIN_BUZZER, OUTPUT);
}
struct note {
uint16_t frequency;
uint16_t duration;
};
static const PROGMEM note notes[] = {
{ 293, 240 },
{ 329, 240 },
{ 349, 240 },
{ 392, 240 },
{ 329, 480 },
{ 261, 240 },
{ 293, 720 }
};
void loop() {
for (auto *p = notes; p < notes + sizeof(notes)/sizeof(*notes); ++p) {
note note;
memcpy_P(¬e, p, sizeof(note));
if (note.frequency) {
tone(PIN_BUZZER, note.frequency);
} else {
noTone(PIN_BUZZER);
}
delay(note.duration);
}
noTone(PIN_BUZZER);
for (;;) {}
}Порахувати частоту ноти можна за формулою f=F*2^(n/12), де F - частота базової ноти, n - кількість напівтонів від базової ноти. Додатні значення - вверх, від'ємні - вниз. Зазвичай за базову ноту беруть "ля" першої октави, і її частоту - 440 Гц, але це не обовʼязково.
Але в метода з tone()/delay() є недоліки. По-перше, delay() виконується процесором, і в цей час він не може робити нічого іншого.
По-друге, tone() обчислює дільник таймера по частоті в рантаймі, що не дуже ефективно. Можна розрахувати дільники заздалегідь при компіляції, і в рантаймі завантажувати їх безпосередньо в регістр таймера. Тим більше для низьких нот похибка в половину герца вже становить десятки центів і відчутна вухом.
Можна поєднати відтворення окремих нот з ШІМ і отримати щось схоже на поліфонію. Для апаратного ШІМ в ардуіно скоріш за все доведеться використовувати TIM1 або TIM2, тому що TIM0 ардуіно використовує для своїх потреб.
Вибір оптимального метода залежить від конкретних вимог і можливостей заліза.
UPD: перемикати пін в OUTPUT не потрібно, tone() це робить сама: Tone.cpp:255