Предостережение: Это не столько решение, сколько очистка вашего кода, чтобы вы могли найти решение. Это потому, что ваш код имеет так много ненужной сложности, что его трудно анализировать.
Однако, есть некоторые [очевидные] ошибки ...
Ваш ISR скачок с вашим уровнем задач
Ваш ISR syn c с уровнем задач для вашего буфера является подозрительным, несмотря на volatile
.
Когда вы пытаетесь получить доступ к нему на уровне задач, вам необходимо отключить прерывания на время доступа на уровне задач.
Вы должны заключить доступ в пары cli/sti
. Сделайте это для любого уровня доступа к ser_rec
или a
. И, не только вокруг одиночной выборки байтов в пределах l oop. Вы должны поставить cli
в качестве первого элемента функции уровня задачи и sti
в качестве последнего элемента в функции.
И я бы переименовал a
во что-то более описательное, например ser_len
.
Обрабатывать только те данные, которые вы знаете у вас есть
И на уровне задач (например, sms_decode
) ваш l oop предел равен sizeof(ser_rec)
, поэтому вы получаете доступ к мусорным / случайным значениям или частичным устаревшим значениям из предыдущего входящего сообщения.
Вместо:
while (i < sizeof(ser_rec))
Возможно, вы захотите:
while (i < a)
Или, если вы переименуете:
while (i < ser_len)
Если вы сделаете это, функция clear_sec_rec
больше не будет нужна обнулить буфер, но просто сбросить ser_len
. Обнуление было попыткой смягчить нарушенный предел l oop.
На уровне задачи необходимо "сдвинуть" буфер
То есть если текущая входящая запись имеет (например) 8 символов, но ser_len
равна (например) 12, уровень задачи должен «сдвинуть» буфер для удаления обработанной записи:
memmove(&ser_rec[0],&ser_rec[8],ser_len - 8);
ser_len -= 8;
ISR должен не сбросить буфер, если он переполнен
Ваш ISR "сбрасывает" буфер, если приходит слишком много символов. Это, вероятно, нарушает обработку на уровне задачи, потому что вы может выполнить сброс в середине обработки.
Если буфер / кольцо заполняется, ISR должен установить флаг «переполнения», который может проверять уровень задачи [и просто отбрасывать символ], а не вытаскивая коврик из-под уровня задачи со сбросом.
Использовать очередь звонков
Но, вы можете преобразовать буфер в очередь звонков , Это немного сложнее, но позволяет непрерывно передавать информацию из ISR в задачу. (то есть) Это устранит необходимость для ISR сбрасывать буфер. Кроме того, на уровне задач можно обрабатывать несколько записей без потери.
Может помочь установка слишком большого размера буфера (например, char ser_rec[10000]
). Но делайте это только после исправления синхронизации.
Вы могли бы даже иметь возможность использовать атомарность (например, stdatomic.h
в индексах кольцевого буфера) и устранить необходимость в cli/sti
в задача [хотя последняя медленнее, но проще].
Устранить ненужную сложность
Вы используете N уровня if/else
лестницы вместо простого memcmp
:
char
sms_index1()
{
int i = 0;
char index = 0;
#if 0
while (i < (sizeof(ser_rec) - 4)) {
i++; // check if gsm sends SM",
if (ser_rec[i] == ((char) 'S')) {
i++;
if (ser_rec[i] == ((char) 'M')) {
i++;
if (ser_rec[i] == ((char) '"')) {
i++;
if (ser_rec[i] == ((char) ',')) {
i++;
index = ser_rec[i]; // return index
}
}
}
}
} // returns it
#else
while (i < (sizeof(ser_rec) - 4)) {
// return index
if (memcmp(&ser_rec[i],"SM\",",4) == 0) {
i += 4;
index = ser_rec[i];
}
i += 1;
}
#endif
// clears the ser_rec buffer if there was index
if (index)
clear_sec_rec();
return index;
}
Сохранять код до 80 символов в строке
Разбивать длинные строки в логических точках
Изменить ( например):
if (BeeHive[j].Humidity_value > Humidity_high_range || BeeHive[j].Humidity_value < Humidity_low_range || BeeHive[j].Temperature_value > Temperature_high_range || BeeHive[j].Temperature_value < Temperature_low_range)
Into:
if ((BeeHive[j].Humidity_value > Humidity_high_range) ||
(BeeHive[j].Humidity_value < Humidity_low_range) ||
(BeeHive[j].Temperature_value > Temperature_high_range) ||
(BeeHive[j].Temperature_value < Temperature_low_range)) {
Избегайте [длинных] комментариев на «боковой панели» в коде. Вместо этого поместите их в строку выше. (например)
Изменить (например):
i++; // go forward only when there is a place for 16 characters
На:
// go forward only when there is a place for 16 characters
i++;
Использовать #define/enum
для специальных значений
Вы также делаете (например) UART_Transmit_char(34);
34
является «аппаратным» значением. Что это значит / представляет? Сделайте что-то вроде: #define STARTCHAR 34 // framing char
, а затем выполните: UART_Transmit_char(STARTCHAR);
Отдельные блоки связанного / несвязанного кода с пустыми строками
Добавьте несколько пустых строк в групповые вещи. Например, вы делаете UART_Transmit_char
, а затем делаете: _delay_ms(50)
. Добавьте пустую строку после _delay_ms
. Или, что еще лучше, создайте функцию, которая выполняет обе функции и вызывает функцию .
Исправление неработающих комментариев
Некоторые из ваших комментариев неверно / неуместно:
_delay_ms(200); // clear the buffer
Компиляция кода с предупреждениями включает и исправляет все предупреждения
Поскольку у меня нет доступа к файлам AVR (например, avr/interrupt.h
), я не могу скомпилировать ваш код. Но вы должны скомпилировать с -Wall -O2
, чтобы генерировать предупреждения и исправлять их. И я подозреваю, что у вас есть несколько.