Доброго времени суток, уважаемые.
В свободное от работы время увлекаюсь программированием микроконтроллеров, на ассемблере. Пока вожусь в основном со всякими PIC(12,16) и AVR, но и MCS-51 не брезгую, тем более что именно с них я собственно и начал. Уровень мой — «вечно начинающий». Это типа светодиодиком уже умею мигать, даже по таймеру.
Сейчас поставил себе задачу написать программу для взаимодействия с GSM модулем SIM900. Для этого необходимо уметь слать что-то в UART, и принимать что-то оттуда.
По грамотному на все это дело заводится 2 кольцевых буфера: на прием, и на передачу. Вроде как классика жанра, ничего нового не придумаешь. Но я такой человек, что не люблю костыли, но при этом обожаю велосипеды. Захотелось придумать свой. Итак:
1. У меня не мультизадачная система, предполагаеться отправка 1 команды в модуль, затем ожидание 1 ответа. А значит отправку уже можно делать не на прерываниях, а просто в основном цикле. Обойдемся без буфера на отправку.
2. Ответ от модуля меня устраивает только один (хотя если проверять например уровень сигнала, это уже не так), и я ожидаю, каким он должен быть. Поэтому я решил обойтись без буфера и парсить тоже прямо в основном цикле.
3. И чтобы все было удобно и красиво, оформить все это дело в макросы.
Основой моего кода стал пример из статьи «МК для начинающих» из журнала «Радиолюбитель», №3 за 2008г.
Сперва «печатаем»:
В сравнении с оригиналом я только добавил возможность вывода в несколько «точек назначения».
Увидев как получилось просто и красиво, я решил сделать и парсинг подобным образом. Вот что получилось:
Кварц 11,0592 МГц позволяет «принтить» и парсить строки на скорости 57600 bps прямо в основном цикле без каких-либо пропусков символов. При кварце в 22,1184 Мгц ожидаемо можно будет проделывать аналогичное на скорости 115200 bps.
В свободное от работы время увлекаюсь программированием микроконтроллеров, на ассемблере. Пока вожусь в основном со всякими PIC(12,16) и AVR, но и MCS-51 не брезгую, тем более что именно с них я собственно и начал. Уровень мой — «вечно начинающий». Это типа светодиодиком уже умею мигать, даже по таймеру.
Сейчас поставил себе задачу написать программу для взаимодействия с GSM модулем SIM900. Для этого необходимо уметь слать что-то в UART, и принимать что-то оттуда.
По грамотному на все это дело заводится 2 кольцевых буфера: на прием, и на передачу. Вроде как классика жанра, ничего нового не придумаешь. Но я такой человек, что не люблю костыли, но при этом обожаю велосипеды. Захотелось придумать свой. Итак:
1. У меня не мультизадачная система, предполагаеться отправка 1 команды в модуль, затем ожидание 1 ответа. А значит отправку уже можно делать не на прерываниях, а просто в основном цикле. Обойдемся без буфера на отправку.
2. Ответ от модуля меня устраивает только один (хотя если проверять например уровень сигнала, это уже не так), и я ожидаю, каким он должен быть. Поэтому я решил обойтись без буфера и парсить тоже прямо в основном цикле.
3. И чтобы все было удобно и красиво, оформить все это дело в макросы.
Основой моего кода стал пример из статьи «МК для начинающих» из журнала «Радиолюбитель», №3 за 2008г.
Сперва «печатаем»:
; Тип: процедура, вызываемая в макросе ; Передаваемые параметры: String,Destiny_ ; Возвращаемое значение: отсутствует ; Данная процедура позволяет строчить как на Бейсике, примеры: ; Print 'First string',UART ; Вывод в UART ; Print 'Second string',LCD ; Вывод на LCD UART equ 0 LCD equ 1 Print macro String;,Destiny_ ; String - строка для вывода, Destiny_ - пункт назначения: Display или UART mov destiny,#Destiny_ call Output ; При вызове процедуры мы автоматически заныкаем в стек адрес следующей команды. По факту это будет адрес 1 символа строки db String,0Dh,0Ah,0 endm Print_data segment data rseg Print_data destiny: ds 1 Print_code segment code rseg Print_code Output: ; Описываем процедуру, вызываемую из макроса pop DPH ; Извлекаем из стека в DPTR адрес возврата, pop DPL ; он понадобится нам в дальнейшем Loop_Output: clr A movc A, @A+DPTR ; Получаем очередной символ из строки inc DPTR ; Сразу берем следующий символ jnz Output_Symbol ; Если не конец строки, продолжаем вывод jmp @A+DPTR ; Иначе возврат Output_Symbol: ;------ Тут выводим очередной символ на дисплей или в UART ------------------------- push ACC ; Сохраним содежимое акумулятора, там очередной символ из строки mov A, Destiny jz Out_UART ; Смотрим пункт назначения строки Out_LCD: pop ACC ; Восстановим символ из строки call Out_2_LCD ; Выводим на дисплей jmp Loop_Output ; Повторяем цикл вывода Out_UART: pop ACC ; Восстановим символ из строки jnb TI, $ ; Ждем окончания предыдущей передачи clr TI ; Предыдущий байт ушел, сбросим флаг передачи mov SBUF, A ; Отправим байт jmp Loop_Output ; Повторяем цикл вывода
В сравнении с оригиналом я только добавил возможность вывода в несколько «точек назначения».
Увидев как получилось просто и красиво, я решил сделать и парсинг подобным образом. Вот что получилось:
; Тип: процедура, вызываемая в макросе ; Передаваемые параметры: String,Label,waiting_value ; Возвращаемое значение: jmp на Label в случае ошибки парсинга String ; Данная процедура позволяет парсить легко и непринужденно, примеры: ; Parsing 'First string',UART_Error,1000 ; Ждем строку из UART на протяжении 1000 мс, если ошибка парсинга, переход на метку UART_Error ; Parsing 'Second string',UART_Error,0 ; Ждем строку из UART, если приходит с ошибкой, переход на метку UART_Error, если не приходит вообще ничего - ждем вечно Parsing macro String,Label,waiting_value ; String - строка для сравнения, Label - метка для перехода в случае ошибки, waiting_value - время ожидания каждого символа строки в Х*100 мс (при 11,0592 MHz) mov parsing_delay,#waiting_value ; Минимальное время ожидания - 100 мс, максимальное - 25,5 сек call Intput ; При вызове процедуры мы автоматически заныкаем в стек адрес следующей команды. По факту это будет адрес 1 символа строки db String,0Dh,0Ah,0 jbc parsing_error,Label ; Проверяем признак ошибки парсинга endm Parsing_data segment data rseg Parsing_data parsing_delay: ds 3 Parsing_bit segment bit rseg Parsing_bit parsing_error: dbit 1 Parsing_code segment code rseg Parsing_code Intput: ; Описываем процедуру, вызываемую из макроса clr RI ; Сбросим признак последнего принятого байта, чтобы всякий мусор принятый до этого момента, не приводил к ошибке парсинга pop DPH ; Извлекаем из стека в DPTR адрес возврата, pop DPL ; там находиться адрес 1 символа строки Loop_Intput: clr A movc A, @A+DPTR ; Получаем очередной символ из строки inc DPTR ; Сразу берем следующий символ jnz Wait ; Если не конец строки, проверяем jmp @A+DPTR ; А теперь маленький грязный хак. В DPTR у нас адрес команды после строки, вернемся по этому адресу Wait: ; Принимаем и сравниваем полученный символ с символом из строки push ACC ; Сохраним символ из флеша mov A, parsing_delay jz Always_Wait ; Если задержка ожидания = 0, ждем входящий байт неограничено долго mov parsing_delay+2,#0 mov parsing_delay+1,#90 ; Задержка расчитана на кварц 11,0592 МГц Loop_Wait: jb RI, Stop_Wait ; Если принят байт, прекращаем ожидание djnz parsing_delay+2,Loop_Wait jb RI, Stop_Wait djnz parsing_delay+1,Loop_Wait jb RI, Stop_Wait mov parsing_delay+1,#90 ; Задерка расчитана на кварц 11,0592 МГц djnz parsing_delay,Loop_Wait ; Цикл ожидания входящего байта pop ACC ; Время ожидания байта истекло, восстановливаем АСС jmp Error_Intput ; Выход по превышению времени парсинга Always_Wait: jnb RI, $ ; Ждем входящий байт Stop_Wait: mov parsing_delay,SBUF ; Используем ячейку задержки для сравнения полученого символа с символом из строки clr RI pop ACC ; Восстановим символ из флеша cjne A,parsing_delay,Error_Intput ; Если хоть 1 полученный символ не совпал, на выход без восстановления АСС jmp Loop_Intput ; Иначе повторяем цикл сравнения Error_Intput: ; Выход по ошибке парсинга, либо превышению времени ожидания clr A movc A, @A+DPTR inc DPTR jnz Error_Intput ; Ищем конец строки setb parsing_error ; Устанавливаем признак ошибки парсинга jmp @A+DPTR ; А теперь маленький грязный хак. В DPTR у нас адрес команды после строки, вернемся по этому адресу
Кварц 11,0592 МГц позволяет «принтить» и парсить строки на скорости 57600 bps прямо в основном цикле без каких-либо пропусков символов. При кварце в 22,1184 Мгц ожидаемо можно будет проделывать аналогичное на скорости 115200 bps.
