Введение
Написал простой парсер для разбора данных. Он имеет минимальный, но достаточный функционал для организации программы управления микроконтроллером с компьютера или какого-нибудь другого устройства.
Парсер принимает в буфер поток символов и разбирает их на слова. Под словами в данном случае подразумевается один или несколько символов отделенных пробелами. Количество пробелов неважно, все они заменяются в буфере одним символом окончания строки ('\0'). Прием данных выполняется до первого символа перевода каретки ('\r'). Если внутренний буфер переполняется, данные перестают приниматься, но символ перевода каретки все равно ожидается.
Когда входная последовательность символов (входная строка) обработана, мы получаем следующий результат - в буфере лежат принятые слова, мы знаем количество этих слов и имеем указатели на каждое из них.
Далее нам нужно только написать интерпретатор принятых слов. Для этого в программном модуле парсера есть несколько дополнительных функций - функции для сравнения строк и функции для перевода строки в число.
Особенности
- не "привязан" к AVR,
- как обычно работа с тремя компиляторами: IAR, GCC и CodeVision,
- компактный код,
- простота использования.
Подключение к проекту
1. Переписываем файлы библиотеку в папку проекта.
2. Подключаем parser.c к проекту внутри среды разработки.
3. Инклюдим заголовочный файл parser.h к сишному файлу, в котором будут использоваться его функции.
4. Настраиваем конфигурацию в файле parser.h
5. Описываем функцию PARS_Handler(..)
6. Прописываем в свой код вызов функций парсера.
Настройка конфигурации
Нужно задать два параметра:
- вместимость приемного буфера SIZE_RECEIVE_BUF. Он определяет размер строки, который может принять парсер.
- количество принимаемых слов AMOUNT_PAR. Этот параметр определяет размер массива указателей на слова. Если во входной последовательности слов будет больше, чем размер массива - парсер их проигнорирует.
Пользовательские функции
void PARS_Init(void) - инициализирует внутренние переменны. Вызывается в начале main`a.
Пример:
//файл main.c
...
int main( void )
{
char sym;
PARS_Init();
USART_Init(USART_DOUBLED, 57600);
...
void PARS_Parser(char sym) - принимает последовательность символов и анализирует их.
Пример:
//файл main.c
...
while(1){
/*буфер UART`a не пустой,
передаем символ парсеру*/
if (USART_GetRxCount()){
sym = USART_GetChar();
PARS_Parser(sym);
}
extern void PARS_Handler(uint8_t argc, char *argv[]) - обработчик результата парсера. Эта функция вызывается парсером после обработки последовательности, но при условии приема хотя бы одного слова. Вызывать эту функцию самому не нужно.
Она определена как внешняя (extern) и должна быть описана пользователем. Функция принимает два параметра: argc - количество слов, argv[] - массив указателей на слова. Рисунок ниже поясняет, что содержат эти переменные.
Пример:
//файл main.c
...
//команды
__flash char com1[] = "ledon";
...
//обработка принятой последовательности
void PARS_Handler(uint8_t argc, char *argv[])
{
//если принята первая команда включить светодиод
if (PARS_EqualStrFl(argv[0], com1)){
LED_On();
}
...
}
uint8_t PARS_EqualStr(char *s1, char *s2) - сравнивает две строки, хранящиеся в ОЗУ. Если строки равны возвращает 1.
uint8_t PARS_EqualStrFl(char *s1, char __flash *s2) - сравнивает строку, хранящуюся в ОЗУ, со строкой из флэш памяти. Если строки равны возвращает 1.
uint8_t PARS_StrToUchar(char *s) - переводит строку в число типа uint8_t и возвращает его. Если передать строку, содержащую большее значение, то произойдет переполнение.
uint16_t PARS_StrToUint(char *s) - переводит строку в число типа uint16_t и возвращает его. Если передать строку, содержащую большее значение, то произойдет переполнение.
Пример использования
Для демонстрации написал тестовый проект: микроконтроллер принимает по UART`у команды и управляет портом, к которому подключено 8 светодиодов. Для зажигания светодиода нужно подать команду "set n", где n число от 0 до 7. Для выключения светодиода - "clear n". В ответ на каждую команду микроконтроллер отвечает "error", "ok" или " large value".
Весь код комментировать не буду, расскажу только про функцию void PARS_Handler(uint8_t argc, char *argv[]). Эту функцию вызывает парсер после приема символа перевода каретки и передает ей количество слов и массив указателей. Пользователь должен сам описать логику работы этой функции.
В моем примере я беру, грубо говоря, первое принятое слово и сравниваю его с заданными строками - "set" и "clear". Если принятое слово совпадает с одной из команд, то проверяю есть ли второе слово. Если оно есть, перевожу строку в число и "дергаю" соответствующий вывода порта.
...
/*команды*/
__flash char comSet[] = "set";
__flash char comClear[] = "clear";
/*ответы*/
__flash char error[] = "error\r";
__flash char ok[] = "ok\r";
__flash char largeValue[] = "large value\r";
__flash char start[] = "iar start\r";
/*обработчик команд*/
void PARS_Handler(uint8_t argc, char *argv[])
{
uint8_t value = 0;
char __flash *resp = error;
if (PARS_EqualStrFl(argv[0], comSet)){
if (argc > 1){
value = PARS_StrToUchar(argv[1]);
if (value <= 7){
PORTX |= (1<<value);
resp = ok;
}
else{
resp = largeValue;
}
}
}
else{
if (PARS_EqualStrFl(argv[0], comClear)){
if (argc > 1){
value = PARS_StrToUchar(argv[1]);
if (value <= 7){
PORTX &= ~(1<<value);
resp = ok;
}
else{
resp = largeValue;
}
}
}
}
USART_SendStrFl(resp);
}
...
Файлы
Проекты для Atmel Studio 6, WinAVR, CodeVision, IAR и Proteus.
Parser-IAR.rar
Parser-CV.rar
Parser-Winavr.rar
Parser-AS6.rar
Parser-Proteus.rar
Comments
Флаг RxC надо ведь сбрасывать, а то программа будет нырять в прерывание по приему байта после каждой инструкции.
Как применить этот парсер для разбора строк NMEA?
А как добавить?
Code:
if (sym != ','){
И он будет дербанить тебе строку на части. А по первому слову ясно, что пришло в остальной части. Просто сравниваешь argv[0] c $GPRMC или каким то другим.
arg[0]= $GPRMC
arg[1]= 123456
Как разложить arg[1] на часы минуты секунды?
argv[1][2], argv[1][3] - минуты
...
C уважением, Владимир.
а 0 нас уже не интересуют?... s
if ((*s<49) || (*s>57)) {return (0);}
...
Code:
*s<48
В протеусе норм, а в железе не пашет:(
Проверял с кварцем 11059200 Гц
RSS feed for comments to this post