From 3292123b06878473d1618ec1935b86cefd1c8daa Mon Sep 17 00:00:00 2001 From: vlad Date: Tue, 23 Aug 2022 13:34:34 +0300 Subject: [PATCH] Initial commit --- .gitignore | 2 + CMakeLists.txt | 63 +++++++++++++ comparator-test.c | 27 ++++++ config.h | 48 ++++++++++ main.c | 220 ++++++++++++++++++++++++++++++++++++++++++++++ platform.c | 164 ++++++++++++++++++++++++++++++++++ platform.h | 43 +++++++++ 7 files changed, 567 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 comparator-test.c create mode 100644 config.h create mode 100644 main.c create mode 100644 platform.c create mode 100644 platform.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..da6ed1a --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# Project exclude paths +/cmake-build-debug/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..3241e80 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,63 @@ +cmake_minimum_required(VERSION 3.21) +project(sdp-dry-sensor C) + + +set(CMAKE_CXX_COMPILER avr-g++) +set(CMAKE_C_COMPILER avr-gcc) + +set(PROGRAMMER usbasp) + +add_definitions(-D'F_CPU=1000000L') + +set(CMAKE_CXX_FLAGS "-fno-exceptions -fno-threadsafe-statics -fpermissive -std=gnu++11 -mmcu=attiny2313 -Os -Wall -ffunction-sections -fdata-sections -flto") +set(CMAKE_C_FLAGS "-std=gnu11 -fno-fat-lto-objects -mmcu=attiny2313 -Os -Wall -ffunction-sections -fdata-sections -flto") + +add_executable(${PROJECT_NAME}.elf config.h main.c platform.c platform.h) +add_custom_command( + TARGET ${PROJECT_NAME}.elf + # Run after all other rules within the target have been executed + POST_BUILD + COMMAND avr-size -A ${PROJECT_NAME}.elf + VERBATIM +) + +add_custom_target( + upload-flash + # cmake -E support copy/env/echo and so on. use cmake -E to see + # COMMAND/COMMENT must be upper case + #COMMAND ${CMAKE_COMMAND} -E environment + COMMAND avrdude -c usbasp -p t2313a -e -Uflash:w:${PROJECT_NAME}.elf:e + + COMMENT "Flashing ${PROJECT_NAME}.elf to flash memory" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + + DEPENDS ${PROJECT_NAME}.elf +) + +########################################################################## + +add_executable(comparator-test.elf comparator-test.c comparator-test.c) +add_custom_command( + TARGET comparator-test.elf + # Run after all other rules within the target have been executed + POST_BUILD + COMMAND avr-size -A comparator-test.elf + VERBATIM +) + +add_custom_target( + upload-comparator-test + # cmake -E support copy/env/echo and so on. use cmake -E to see + # COMMAND/COMMENT must be upper case + #COMMAND ${CMAKE_COMMAND} -E environment + COMMAND avrdude -c usbasp -p t2313a -e -Uflash:w:comparator-test.elf:e + + COMMENT "Flashing comparator-test.elf to flash memory" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + + DEPENDS comparator-test.elf +) + +# avr-objcopy -O ihex -R .eeprom build/firmware.elf build/firmware.hex +# avr-objcopy -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 build/firmware.elf build/firmware-eeprom.hex +# avr-size -A build/firmware.elf \ No newline at end of file diff --git a/comparator-test.c b/comparator-test.c new file mode 100644 index 0000000..e48535c --- /dev/null +++ b/comparator-test.c @@ -0,0 +1,27 @@ +// +// Created by vlad on 22.08.22. +// + +#include +#include +#include "config.h" + + +int main() { + // сделаем как выход LED2 (красный) + DDRD = INIT_DDRD; + DDRB = INIT_DDRB; + for (;;) { +// if (ACSR & (1 << ACO)) { +// LED2_Set(); +// } else { +// LED2_Reset(); +// } + LED2_Set(); + EXTPWR_EN_Set(); + _delay_ms(500); + LED2_Reset(); + EXTPWR_EN_Reset(); + _delay_ms(500); + } +} diff --git a/config.h b/config.h new file mode 100644 index 0000000..72a12f1 --- /dev/null +++ b/config.h @@ -0,0 +1,48 @@ +#ifndef SDP_DRY_SENSOR_CONFIG_H +#define SDP_DRY_SENSOR_CONFIG_H + +#define SPEED_Gpio PIND +#define SPEED_Pin (1 << 2) + +#define GSM_EN_Gpio PORTD +#define GSM_EN_Pin (1 << 4) + +#define GSM_KEY_Gpio PORTD +#define GSM_KEY_Pin (1 << 3) + +#define EXTPWR_EN_Gpio PORTD +#define EXTPWR_EN_Pin (1 << 5) + +#define LED1_Gpio PORTB +#define LED1_Pin (1 << 4) + +#define LED2_Gpio PORTD +#define LED2_Pin (1 << 6) + +#define FRQ_Gpio PINB +#define FRQ1_Pin (1 << 3) +#define FRQ2_Pin (1 << 2) + +// требуется для аттини + +#define INIT_DDRD (GSM_EN_Pin | EXTPWR_EN_Pin | LED2_Pin | GSM_KEY_Pin) +#define INIT_DDRB (LED1_Pin) + +#define GSM_EN_Set() GSM_EN_Gpio |= GSM_EN_Pin +#define GSM_EN_Reset() GSM_EN_Gpio &= ~GSM_EN_Pin + +#define GSM_KEY_Set() GSM_KEY_Gpio |= GSM_KEY_Pin +#define GSM_KEY_Reset() GSM_KEY_Gpio &= ~GSM_KEY_Pin + +#define EXTPWR_EN_Set() EXTPWR_EN_Gpio |= EXTPWR_EN_Pin +#define EXTPWR_EN_Reset() EXTPWR_EN_Gpio &= ~EXTPWR_EN_Pin + +#define LED1_Set() LED1_Gpio |= LED1_Pin +#define LED1_Reset() LED1_Gpio &= ~LED1_Pin +#define LED1_Toggle() LED1_Gpio ^= LED1_Pin + +#define LED2_Set() LED2_Gpio |= LED2_Pin +#define LED2_Reset() LED2_Gpio &= ~LED2_Pin +#define LED2_Toggle() LED2_Gpio ^= LED2_Pin + +#endif //SDP_DRY_SENSOR_CONFIG_H diff --git a/main.c b/main.c new file mode 100644 index 0000000..2e53d31 --- /dev/null +++ b/main.c @@ -0,0 +1,220 @@ +#include "config.h" +#include "platform.h" +#include + +#define SMS_END "\032\n" +#define SIM800_DELAY_TIME 100 + +void sim800_wait_newline() { + while (1) { + char c = uart_read_char(); + if (c == '\n') { + return; + } + } +} + +void sim800_wait_for(PGM_P str) { + PGM_P curr_pos = str; + LED1_Set(); + while (1) { + char p = pgm_read_byte(curr_pos); + if (p == '\0') { + break; + } + + char c = uart_read_char(); + if (c == '\r') { + continue; + } + + if (c == p) { + curr_pos++; + } else { + curr_pos = str; + } + } + LED1_Reset(); +} + +void sim800_wait_for_ok() { + sim800_wait_for(PSTR("OK\n")); +} + +void sim800_start() { + LED2_Set(); + GSM_EN_Set(); + _delay_ms(1000); + + // зажимаем кнопку на секунду + GSM_KEY_Set(); + _delay_ms(1100); + GSM_KEY_Reset(); + + // еще 2 секунды на загрузку модуля + _delay_ms(3000); + + // врубаем юарт + uart_init(); + + uart_write_fstr(PSTR("AT\n")); + sim800_wait_for_ok(); + + // вырубить echo mode (повторяет команду, которая прилетела) ATE0 + _delay_ms(SIM800_DELAY_TIME); + uart_write_fstr(PSTR("ATE1\n")); // TODO поставить 0 чтобы модем лишнюю херню не слал + sim800_wait_for_ok(); + + // после готовности смс все сразу станет понятно + sim800_wait_for(PSTR("SMS Ready\n")); + + while (1) { + _delay_ms(SIM800_DELAY_TIME); + uart_write_fstr(PSTR("AT+CREG?\n")); + sim800_wait_for(PSTR("+CREG: ")); + char mode = uart_read_char(); + uart_read_char(); // запятая + char status = uart_read_char(); + if (mode == '0' && status == '1') { + break; + } + } +} + +void sim800_stop() { + // вырубить модуль + uart_write_fstr(PSTR("AT+CPOWD=1\n")); + sim800_wait_for(PSTR("DOWN\n")); // придет NORMAL POWER DOWN + uart_deinit(); + GSM_EN_Reset(); + LED2_Reset(); +} + +uint16_t sim800_get_battery() { + _delay_ms(SIM800_DELAY_TIME); + uart_write_fstr(PSTR("AT+CBC\n")); + sim800_wait_for(PSTR("+CBC:")); + for (uint8_t i = 0; i < 2; i++) { + sim800_wait_for(PSTR(",")); + } + // по идее тут будет напряжение + // 4 цифры, но мне не важно на самом деле сколько + uint16_t result = 0; + while (1) { + char c = uart_read_char(); + if (c == ' ' || c == '\r') { + continue; + } + + // туда попадет и символ конца строки + if (c < '0' || c > '9') { + break; + } + + result *= 10; + result += c - '0'; + } + + // ждем ок, то есть конец команды + sim800_wait_for_ok(); + return result; +} + +void sim800_prepare_sms() { + _delay_ms(SIM800_DELAY_TIME); + uart_write_fstr(PSTR("AT+CMGF=1\n")); // PDU режим + sim800_wait_for_ok(); + _delay_ms(SIM800_DELAY_TIME); + uart_write_fstr(PSTR("AT+CMGS=\"+79208109798\"\n")); // PDU режим + sim800_wait_for(PSTR(">")); +} + +void sim800_wait_for_sms_send() { + sim800_wait_for(PSTR("+CMGS")); +} + +static void num2buff(char* buffer, uint16_t num) { + int8_t len; // длинна числа + if (num < 10) len = 1; + else if (num < 100) len = 2; + else if (num < 1000) len = 3; + else if (num < 10000) len = 4; + else len = 5; + + buffer[len] = '\0'; // вставляем конец строки + + for (; len > 0; len--) { + uint8_t digit = (num % 10) + '0'; + num /= 10; + buffer[len - 1] = (char)digit; + } +} + +void sim800_send_telemetry() { + platform_read_sensors(); + uint16_t bat = sim800_get_battery(); + + sim800_prepare_sms(); + char buff[6]; +// sprintf(buff, "F1=%d F2=%d\033\n", sensor_1, sensor_2); + + _delay_ms(SIM800_DELAY_TIME); + + uart_write_fstr(PSTR("F1=")); + num2buff(buff, sensor_1); + uart_write_str(buff); + + uart_write_fstr(PSTR(" F2=")); + num2buff(buff, sensor_2); + uart_write_str(buff); + + uart_write_fstr(PSTR(" BAT=")); + num2buff(buff, bat); + uart_write_str(buff); + + uart_write_fstr(PSTR(SMS_END)); + + sim800_wait_for_sms_send(); +} + + +int main() { + platform_init(); + + // врубаем модем + sim800_start(); + + // рабочая отправка сообщений + sim800_prepare_sms(); + _delay_ms(SIM800_DELAY_TIME); + uart_write_fstr(PSTR("I'm working!" SMS_END)); // сама смска + sim800_wait_for_sms_send(); + + // отправляем сразу же телеметрию + sim800_send_telemetry(); + // рубим модем + sim800_stop(); + for (;;) { + uint16_t time = 0; + while (1) { + if (SPEED_Gpio & SPEED_Pin) { + // (скорость отпущена, пин подтянут к питанию) + // если скорости нет, шлем смс раз в час + if (time > 60 * 60) { + break; + } + } else { + // если скорость зажата, то максимальное ожидание 60 секунд + if (time > 60) { + break; + } + } + time++; + systick_sync(); + } + + sim800_start(); + sim800_send_telemetry(); + sim800_stop(); + } +} diff --git a/platform.c b/platform.c new file mode 100644 index 0000000..1c68f92 --- /dev/null +++ b/platform.c @@ -0,0 +1,164 @@ +// +// Created by vlad on 17.08.22. +// +#include "platform.h" +#include "config.h" +#include +#include + +static char systick_flag; +uint16_t sensor_1; +uint16_t sensor_2; + +ISR(TIMER1_OVF_vect) { + systick_flag = 1; +// LED2_Toggle(); +} + +void platform_init() { + // инициализация GPIO + DDRD = INIT_DDRD; + DDRB = INIT_DDRB; + + DIDR = 0x03; // отключение цифрового ввода/вывода на входах компаратора + + // инициализация юарта + uart_init(); + + // инициализация таймера 1 (16-ти битный) + + systick_flag = 0; + + // mode=14 (FastPWM, top in ICR1), x64, ICR1=1000000/64=15625 + TCCR1B = (1 << WGM13) | (1 << WGM12); + TCCR1A = (1 << WGM11); + + // выставляем TOP + ICR1 = (uint16_t)(F_CPU / 64); + + // разрешаем прерывание по переполнению + TIMSK |= (1 << TOV1); + + TCCR1B |= (1 << CS11) | (1 << CS10); // выставляем x64, то есть запускаем таймер + + sei(); +} + +void platform_wait_for_interrupt() { + // для режима сна Idle нужно отрубить компаратор (в даташите просили) + // в других режимах сна он отрубается автоматически + char acsr = ACSR; + ACSR |= (1 << ACD); // чтобы отрубить компаратор нужно записать 1 в этот бит + + MCUCR |= (1 << SE); + asm volatile ("sleep"); + MCUCR &= ~(1 << SE); + + // восстанавливаем состояние компаратора + ACSR |= acsr; +} + +void systick_sync() { + systick_flag = 0; // можно не запрещать прерывания: операция атомарна + for(;;) { + cli(); + char flag = systick_flag; + if (flag) { + systick_flag = 0; + } +// else { +// platform_wait_for_interrupt(); +// } + sei(); + if (flag) { + return; + } + } +} + +void uart_init() { + // U2X=1, baud=9600, error=0.2%, f=1M + UBRRH = 0; + UBRRL = 12; + + UCSRA = (1 << U2X); + UCSRB = (1 << TXEN) | (1 << RXEN); +} + +void uart_deinit() { + UCSRB = 0; // снимаем RXEN и TXEN +} + +void uart_write_char(char c) { + while ((UCSRA & (1 << UDRE)) == 0) + ; + UDR = c; +} + +void uart_write_str(const char* str) { + while (1) { + char c = *(str++); + if (c == '\0') { + break; + } + uart_write_char(c); + } +} + +void uart_write_fstr(PGM_P str) { + while (1) { + char c = pgm_read_byte(str++); + if (c == '\0') { + break; + } + uart_write_char(c); + } +} + +char uart_read_char() { + while (!(UCSRA & (1 << RXC))) + ; + return UDR; +} + +void uart_discard_input() { + while (UCSRA & (1 << RXC)) { + char __attribute__((__unused__)) _tmp = UDR; + } +} + +void platform_read_sensors() { + EXTPWR_EN_Set(); + systick_sync(); + sensor_1 = 0; + sensor_2 = 0; + uint8_t states = FRQ_Gpio & (FRQ1_Pin | FRQ2_Pin); + + for(;;) { + uint8_t tmp = FRQ_Gpio; + + if ((tmp & FRQ1_Pin) != (states & FRQ1_Pin)) { + states = (states & (~FRQ1_Pin)) | tmp; + sensor_1++; + } + + if ((tmp & FRQ2_Pin) != (states & FRQ2_Pin)) { + states = (states & (~FRQ2_Pin)) | tmp; + sensor_2++; + } + + cli(); + char flag = systick_flag; + if (flag) { + systick_flag = 0; + } + sei(); + if (flag) { + break; + } + } + EXTPWR_EN_Reset(); + // быстрое деление на 2 (считалось каждое изменение) + sensor_2 >>= 1; + sensor_1 >>= 1; +} \ No newline at end of file diff --git a/platform.h b/platform.h new file mode 100644 index 0000000..8fa4826 --- /dev/null +++ b/platform.h @@ -0,0 +1,43 @@ +// +// Created by vlad on 17.08.22. +// + +#ifndef SDP_DRY_SENSOR_PLATFORM_H +#define SDP_DRY_SENSOR_PLATFORM_H + +#include +#include + +extern uint16_t sensor_1; +extern uint16_t sensor_2; + +void platform_read_sensors(); + +/** + * Инициализация модуля + */ +void platform_init(); + +/** + * Переводит камень в режим ожидания, выход из ожидания по прерыванию + */ +void platform_wait_for_interrupt(); + +/** + * Ожидание прерывания по таймеру, то есть выравнивание исполнения программы по секундам. + * Задержит исполнение программы на время от 1 ... 0 секунд, вернет управление когда таймер даст прерывание + */ +void systick_sync(); + +void uart_init(); +void uart_deinit(); + +void uart_write_char(char c); +void uart_write_str(const char* str); +void uart_write_fstr(PGM_P str); + +char uart_read_char(); +void uart_discard_input(); + + +#endif //SDP_DRY_SENSOR_PLATFORM_H