Initial commit
This commit is contained in:
commit
3292123b06
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# Project exclude paths
|
||||
/cmake-build-debug/
|
63
CMakeLists.txt
Normal file
63
CMakeLists.txt
Normal file
@ -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
|
27
comparator-test.c
Normal file
27
comparator-test.c
Normal file
@ -0,0 +1,27 @@
|
||||
//
|
||||
// Created by vlad on 22.08.22.
|
||||
//
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <util/delay.h>
|
||||
#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);
|
||||
}
|
||||
}
|
48
config.h
Normal file
48
config.h
Normal file
@ -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
|
220
main.c
Normal file
220
main.c
Normal file
@ -0,0 +1,220 @@
|
||||
#include "config.h"
|
||||
#include "platform.h"
|
||||
#include <util/delay.h>
|
||||
|
||||
#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();
|
||||
}
|
||||
}
|
164
platform.c
Normal file
164
platform.c
Normal file
@ -0,0 +1,164 @@
|
||||
//
|
||||
// Created by vlad on 17.08.22.
|
||||
//
|
||||
#include "platform.h"
|
||||
#include "config.h"
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
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;
|
||||
}
|
43
platform.h
Normal file
43
platform.h
Normal file
@ -0,0 +1,43 @@
|
||||
//
|
||||
// Created by vlad on 17.08.22.
|
||||
//
|
||||
|
||||
#ifndef SDP_DRY_SENSOR_PLATFORM_H
|
||||
#define SDP_DRY_SENSOR_PLATFORM_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
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
|
Loading…
x
Reference in New Issue
Block a user