Приветствую коллега, заглянул с соседней ветки (
http://radiokot.ru/forum/viewtopic.php? ... &start=440), увидел GSM…. Думаю, о дай ка гляну, что за зверь такой на всеобщее обозрение выставлен.
В общем…. Сначала критика. Когда- то давно, что- то вдруг не с того ни с сего решил слепить gsm оповещалку, так тема gsm до сих пор и не отпускает

И вот читаю Вашу статью и прям, ухты- те же юзабилити ляпы, те же косяки, но только чуть с другого ракурса. Но, мы же здесь зачем, правильно, помогать друг другу. Лично по моему мнению, сейчас!!!!, с точки зрения эксплуатационной и программной устройство никуда не годится, от слова совсем. Программная часть вызывает больше вопросов и недоумений - нежели ответов. Только ещё раз обращаю внимание, я критикую не для того что бы гадость сказать, а для того, что бы поделиться опытом и помочь.
Теперь давайте по порядку. Вводное – хотите верьте, хотите нет, но если устройство является не закоченей конструкцией, а скажем так «полуфабрикатом», то годится оно только лишь для индивидуального исполнения/повторения, но с другой стороны, тогда какой смысл публиковать статью?! Вы скажите, ну так это же не сайт «мамочек», а сайт технический и всё такое… Нееее, всё не так, на самом деле человек может быть хорошим схемотехником- но совсем не быть программистом, да и вообще продукт должен быть логически закончен и не важно как он позиционируется. Короче, смысл прост, есть железка, есть прошивка, дальнейшее управление и настройка должна осуществляться без допиливания пользователем прошивки под себя и последующим дебагом, вообще исходников может и не быть (только если Вы просто желаете поделиться знаниями, не более), в ином случае – это «полуфабрикат», который не имеет шансов на выживание или же хоть какое- то повторение.
Вводные бросания фекалиями я закончил

теперь давайте к делу.
Что я предлагаю:
Никаких допилов пришивки юзером!
Варианты решений:
1. Настройка осуществляется через терминал т.е. скидываем GSM модуль, вместо модуля подключаем USB-UART модуль и уже по средствам терминала запиндориваем в еепром те системные настройки- которые потом, в последствии будут использованы. При чём проц сам будет последовательно спрашивать, ну типа того: 1. MASTER PASS? – ввели мастер пасс, нажали ентер и т.д. 2. MASTER PHONE NUMBER? И т.д.
Технически всё просто, на плате девайса появляется перемычка- обучение, накидываем перемычку, подключаем юарт, включаем проц в розетку))) Проц стартует- смотрит, оп а там перемычка стоит, значит мне нельзя работать, я буду обучаться….
2. Настройка осуществляется по средствам SMS. При этом мастер пассом является не статичное «12345», а например, последние 4 – 6 цифр имей модуля (вариантов может быть много, но с имеем самый лучший вариант, он никуда не потеряется и не забудется, он всегда у всех разный и т.д.). При этом мастер пасс служит только лишь для того, что бы можно было поменять юзерпас и не более! Ну, а дальше всё просто….
3. Настройка и управление осуществляется по средствам SMS, но только с мастерномера, т.е. как и в предыдущем варианте, только полностью отсутствует понятие «пароля», паролем является номер с которого была отправлена SMS. Тоже всё просто, всё та же перемычка (как в пункте выше) накидываем перемычку, включаем проц, проц видит что есть перемычка, значит начинает ждать входящего вызова, первый входящий вызов на модуль и будет запомнен как мастерномер. Это только лишь первые мысли которые пришли в голову, можно ещё кучу вариантов придумать…
Что сейчас? В текущем виде прошивка не позволяет настраивать девайс под свои нужды, кроме как перепилом прошивки, все настройки будут уничтожены при следующем включении- это плохо!
unsigned char eeprom eemasterpass[5] ="WE32";
unsigned char eeprom eeuserpass[5] ="1234";
unsigned char eeprom eealarmphone[13] ="+70000000000" ;
.
.
.
Т.е. что Вы делаете, Вы из еепром переменной делаете еепром константу, ибо у Вас определение этих переменных в заголовке программы, но большой вопрос зачем? Ладно, дальше хуже, юзер меняет, например значение пароля, значение падает в еепром переменную, потом бац- питание проца пропало, старт иииии- снова все переменные вернулись на свои ранее заданные значения. Коль пошла такая пьянка, то делать нужно было хотя бы так:
Объявляем переменные еепрома:
unsigned char eeprom eemasterpass[5];
unsigned char eeprom eemasterpass[5];
unsigned char eeprom eeuserpass[5];
unsigned char eeprom eealarmphone[13];
……..
unsigned char eeprom eefirststart;
перед майном:
void check_first_start( void ) {
if ( eefirststart != 0xAA ) {
eemasterpass[5] ="WE32";
eeuserpass[5] ="1234";
…….
eefirststart = 0xAA
}
eeprom2var();
}
Ну и перед главным вайл( 1 ) пишем уже
check_first_start();
Смысл понятен, да, т.е. мы перед тем как уйти в майн цикл, смотрим- это первый запуск МК после прошивки или нет, определяем по переменной eefirststart, которая хранится в еепром. Если она не равна условным 0хАА, значит после прошивки МК это первое включение, значит надо заполнить еепром переменные каким- то значениями стартовыми, соответственно при следующем включении питания eefirststart уже будет равна 0хАА и в оперативку просто будут изыматься значения из еепрома, а не перезаписываться одними и теми же константами.
При чём, скажу больше, в этом исполнении вообще еепром нахрен не нужен, можно было бы с таким же успехом объявить глобальные массивы и переменные со стартовыми значениями и всё.
Грубо говоря сейчас unsigned char eeprom eemasterpass[5] ="WE32"; имеет такой же смысл как и unsigned char masterpass[5] ="WE32";
Дальше, это вообще трешак)))))
float eeprom voltdev =0.02685546875; // 1/25-devider(1k+24k) 1.1V/1024*25=0.02685546875
Может так?
#define voltdev 0.02685546875
Короче я вообще не понял нафига хранить конкретную константу в еепроме.
Ладно, едем дальше.
Функция eeprom2var. Это короче тоже круто.
Во первых, если уж изобретать лисапед, то лисапед должен быть как минимум собран правильно, у Вас в принципе по коду везде капут такой творится, но вот первое на что упал взгляд, если Вы собираете массив, то он обязательно должен быть закрыт всегда нулём, это первое правило, которое должно стоять на вершине всего остального!
Короче так не правильно:
while (eemasterpass[counter]) {
masterpass[counter] = eemasterpass[counter];
counter++;
#asm("wdr")
}
Правильно:
while ( eemasterpass[ counter ] ) {
masterpass[ counter ] = eemasterpass[counter];
masterpass[ counter + 1 ] = 0;
counter++;
#asm("wdr")
}
А Вообще я так и не понял зачем это было сделано, но вот как бы лисапед заводского производства в компиляторе уже имеется и выглядит он так:
memcpy(masterpass, eemasterpass, strlen(eemasterpass ) );
Штатная функция приёма строки от модуля- в топку и на свалку! Ну в каких- то (может) решениях и такая сгодится, но в нашем случае – это КОСЯЧИЩЩЩЩЕ!!!!
Вот это неправильно:
// USART Receiver interrupt service routine
interrupt [USART_RXC] void usart_rx_isr(void)
{
char status,data;
status=UCSR0A;
data=UDR0;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0){
rx_buffer0[rx_wr_index0]=data;
if (++rx_wr_index0 == RXFIFO_BUFFER_SIZE0) rx_wr_index0=0;
if (++rx_counter0 == RXFIFO_BUFFER_SIZE0){
rx_counter0=0;
rx_buffer_overflow0=1;
};
};
}
Правильная функция приёма строки от модуля:
Используемые переменные для работы с юартом:
// размер буфера приёма строки
#define RX_BUFFER_SIZE 255
// USART буфер
unsigned char rx_buffer[ RX_BUFFER_SIZE ];
// индекс записи в массив
unsigned char rx_wr_index = 0;
// бит указывающий на "полный" приём данных
bit rx_buffer_complete;
Функция очистки:
// Очистка приёмного буфера UART
void rx_clear( void ) {
rx_wr_index = 0;
rx_buffer_complete = 0;
rx_buffer[ 0 ] = 0;
}
// Сама функция по приёму строки от модуля
interrupt [USART_RXC] void usart_rx_isr(void) {
char status,data;
status=UCSR0A;
data=UDR0;
// проверка была ли обработана предыдущая строка
// игнорируем новые входящие данные пока юзер не обработал последнюю принятую строку
if ( rx_buffer_complete ) return;
// смотрим ошибки
if ( status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN) ) return;
// всегда игнорируем 0x0A, чтобы реагировать только на 0x0D
if ( data == 0x0A ) return;
// проверяем 0x0D - конец строки, а модуль всегда будет закрывать отправленную строку символом 0D
if ( data == 0x0D ) {
// если длинна принемаемых данных составила менее двух символов, значит обнуляем результаты приёма, обязательный КОСТЫЛЬ, модули шлют двойной ентер, нулевые строки нам никчему!!!
if ( strlen(rx_buffer) < 2 ) {
// чистим буфер приёма
rx_clear();
// выходим
return;
}
}
else {
// записываем принятый байт
rx_buffer[ rx_wr_index ] = data;
// всегда записываем 0 после принятого байта
rx_buffer[ rx_wr_index + 1 ] = 0;
// увеличиваем индекс для следующего байта
rx_wr_index++;
// проверяем переполнение
if ( rx_wr_index > RX_BUFFER_SIZE - 2 ) rx_wr_index = RX_BUFFER_SIZE - 2;
// выходим
return;
}
}
Вот теперь есть фалг полностью принятой строки, есть буфер приёма, делайте с ним что хотите и главное когда хотите…..
«Модуль не умеет кириллицу….» Разочарую, ни один модуль не умеет кириллицу, но это не значит, что не получиться слать смс на человечем, а не на буржуйском языке, просто слать надо не в формате AT+CSCS="GSM", а в формате AT+CSCS="UCS".
Ну тут совсем всё просто, делаете например так:
#define DOOR_OPEN 0414043204350440044C0020043E0442043A0440044B044204300021 // что в свою очередь на великом и могучем = Дверь открыта!
А дальше пишите свой printf( DOOR_OPEN );
Номер получателя вроде тоже в юцсе должен быть, но и это не проблема
// нам поможет цикл)))))
for ( i = 0; i < strlen( alarmphone ); i++ ) printf( "%04X", alarmphone[ i ] );
Соответственно на выходе, например +79101231212 превратится в 002B00370039003100300031003200330031003200310032
Фух….
Всё, что- то я уже подзаморился мануалы писать, а по хорошему вся прошивка требует перепила.
В общем, ещё раз, я всё выше написанное изложил только лишь для того, что бы указать на то, что такое хорошо и что такое плохо и только лишь потому, что сам лично набил в своё время огромное колл- во шишек, просто мне повезло, у меня были и есть люди, которые могут подсказать и указать, ну и образование программиста чуть чуть

Ну, а дальше смотрите, захотите общения- велком, всегда помогу чем смогу, а если надо будет и прошивку вместе свояем)
Ах да, я приложил ещё програмульку юцс калькулятор, для себя писал, чтоб голову не ломать когда требуется кодировки туда сюда гонять, может и Вам пригодится.