Запись констант через UART

June 27, 2010 by admin Комментировать »

Научившись таким образом принимать и передавать данные через UART, мы можем внести изменения в нашу программу измерителя с тем, чтобы загру­жать коэффициенты в EEPROM без перепрограммирования системы. Снача­ла, конечно, придется добавить к схеме один из вариантов модуля преобразо­вателя UART/RS-232 (рис. 21.3 или 21.4), который будет подсоединяться к выводам 14 (RxD) и 15 (TxD) контроллера ATmega8535.

Инициализацию UART удобно производить в той же секции начальной за­грузки, например, сразу после инициализации таймеров. Вставьте туда фраг­мент задания скорости и режима, приведенный ранее (см. разд, «Прием и пе­редача данных через UART»). Процедуры Outcom и incom можно вставить, например, в начало текста, сразу после векторов прерываний. Затем вместо пустого цикла в конце программы впишите следующий код:

Gcykle:

sei /разрешаем прерывания rcall in_com

cli /запрещаем прерывания, чтобы не испортить temp cpi temp,OxEO /записать коэффициенты + 8 байт breq ргос_ЕО

cpi temp,0xE2 /читать коэффициенты 8 байт breq ргос_Е2 rjmp Gcykle

Работает этот кусок программы описанным ранее способом: программа в ос­новном непрерывно опрашивает бит rxc, «отвлекаясь» только на выполнение настоящего прерывания (в данном случае оно одно: Timer О, см. главу 20). И только если через UART был принят какой-то байт (он окажется в temp), про­грамма переходит к его последовательной проверке на одно из заданных зна­чений. Здесь мы полагаем, что после приема байта из ПК, за время выполнения команды ret (возврата из процедуры incom), «вклинивание» прерывания маловероятно: в самом крайнем случае команда из ПК будет пропущена, хотя на практике мне ни разу не удалось словить такое совпадение. Правильный способ обхода этого скользкого момента: каждый обработчик прерывания начинать с команды push temp и заканчивать командой pop temp. Можно также, например, в процедуру incom вставить команду запрещения преры­ваний cli сразу по выходу из цикла опроса бита rxc (перед оператором out udr, temp), а команду разрешения прерываний sei оставить после метки Gcykle. Однако в этих случаях программа усложняется, и мы сейчас не будем на этом останавливаться.

В данном случае мы договариваемся, что значение $Е0 кодирует команду на перезапись коэффициентов в памяти, а значение $Е2 — чтение ранее запи­санных значений. Естественно, в первом случае программа обязана ожидать «сверху» дополнительно еще 8 байт значений, а во втором — наоборот, про­честь записанные коэффициенты и выдать их «наверх». Если же принятый байт не равен ни одной из этих величин, то программа спокойно возвращает­ся по метке Gcykie и продолжает опрос бита rxc до следующего отправлен­ного ей байта.

Для единообразия записи текста процедуры приема и отправки не вызывают­ся напрямую, а дополнительно структурированы. Процедура приема органи­зуется так:

ргос_ЕО: /записать коэффициенты +8 байт

rcall WriteKoeff rjmp Gcykie

Процедура чтения ранее загруженных коэффициентов вызывается так:

ргос_Е2: /читать все коэффициенты 8 байт из eeprom

rcall ReadKoeff rjrrp Gcykie

Метки procEO и proc_E2 должны располагаться сразу после основного цик­ла Gcykie (потому что команда breq имеет ограниченное пространство дей­ствия). Далее, где-то (в конце программы, например) записываем, наконец, собственно процедуру WriteKoeff присма коэффициентов и записи их в па­мять. Аналогично оформим процедуру чтения ранее записанных коэффици­ентов, но сначала зададимся вопросом: а куда их писать и откуда читать?

Хранение констант в EEPROM

Полученные коэффициенты пересчета кода в физические величины мы «за­шивали» прямо в программу МК. Излишне говорить, что это приемлемый метод лишь тогда, когда изготавливается один-единственный экземпляр при­бора, который стоит лично у вас на столе. Изготовить пару-другую экземпля­ров и подарить их кому-то уже не получится — при необходимости попра­вить коэффициенты пересчета владельцу придется обращаться к вам. Поэтому логично придумать способ хранения констант, которые могут быть изменены в процессе эксплуатации, отдельно от программы. Для этой цели и служит энергонезависимая память данных, называемая EEPROM.

Большинство МК семейства AVR имеют не менее 512 байт такой памяти, а младшие модели семейства Tiny— 64—128 байт. Для подавляющего боль­шинства применений этого более чем достаточно. Рассмотрим детали обра­щения с EEPROM.

Сначала — подробнее о сохранности данных в EEPROM. Как мы уже гово­рили (см. главу 18), при снижении питания ниже определенных величин МК начинает совершать непредсказуемые операции, и EEPROM с большой веро­ятностью может быть повреждена. Для защиты от этой напасти (и вообще от выполнения каких-то операций, которые могут навредить, например, внеш­ним устройствам) в AVR предусмотрена система BOD (см. главу 19\ которая при снижении напряжения питания ниже определенного порога (4 или 2,7 В) «загоняет» МК в состояние сброса. Это помогает, но, как показывает опыт, для абсолютной защищенности данных в EEPROM, к сожалению, встроен­ной системы BOD недостаточно. Потому приходится применять надежный и проверенный способ с внешним монитором питания. Это небольшая микро­схема (как правило, трехвыводная), которая при снижении питания ниже до­пустимого закорачивает свой выход на «землю». Если питание находится в норме, то выход находится в состоянии «разрыва» и никак не влияет на рабо­ту схемы. Присоединив этот выход к выводу Reset, мы получаем надежный предохранитель (рис. 21.5).

clip_image002

Рис. 21.5. Подсоединение внешнего монитора питания МС34064 к МК (схема из руководства фирмы Motorola)

Для напряжений питания 5 В один из самых популярных мониторов пита­ния — микросхема МС34064, которая имеет встроенный порог срабатывания 4,6 В, выпускается в корпусе ТО-92 с гибкими выводами и обладает доста­точно малым собственным потреблением (менее 0,5 мА). Время срабатыва­ния у нее составляет при плавном снижении напряжения порядка 200 не, чего достаточно для того, чтобы «вредные» команды не успели выполниться.

Заметки на полях

Если у вас питание автономное (от батарей), то к выбору монитора питания следует подходить довольно тщательно — так, чтобы не приводить схему в неработоспособное состояние тогда, когда батареи еще не исчерпали свой ресурс. При напряжении питания схемы 3,3 В можно использовать мониторы питания DS1816-10, MAX809S или MAX803R, а также некоторые другие.

Собственно запись и чтение данных в EEPROM осуществляется через специ­альные регистры ввода-вывода: регистр данных eedr, регистр адреса eear (если объем EEPROM более 256 байт, то последний делится на два — eearh и eearl) и регистр управления eecr. Основная особенность этого процесса — медленность процедуры записи, которая для разных моделей AVR может длиться от 2 до 9 мс, то есть в тысячи раз дольше, чем выполнение обычных команд (обратим внимание, что в отличие от записи чтение осуществляется всего за один машинный цикл, даже быстрее, чем из обычной SRAM).

Для удобства проведения всех подобных процедур, которые могут длиться достаточно долго, в AVR предусмотрено соответствующее прерывание. Его использование можно бьшо бы назвать «правильным», но, как и в случае UART, профамма получается заметно сложнее. Потому мы ограничимся при­менением простого «лобового» метода, рекомендуемого, кстати, и в фирмен­ном описании. Этот простой метод состоит в том, что мы запускаем бесконеч­ный цикл ожидания, пока EEPROM освободится, и только тогда производим запись (или чтение) данных. В этом случае, если нам нужно произвести запись всего одного байта, МК вообще не будет затормаживаться, и лишь если нам надо подряд записать несколько байт, будет возникать задержка. Факт задерж­ки стоит учесть на будущее, когда нам придется стыковать запись в EEPROM с процедурами приема данных из последовательного порта.

Процедуру записи в EEPROM я привожу в удобных для нас обозначениях регистров:

WriteEEP: ;в ZH:ZL – адрес EEPROM куда писать ;в temp – записываемый байт sbiс EECR,EEWE ; ждем очистки бита rjmp WriteEEP /разрешения записи EEWE out EEARH,ZH /старшая часть адреса out EEARL,ZL /младшая часть адреса out EEDR,temp /данные

sbi EECR,EEMWE /установить флаг разрешения записи sbi EECR,EEWE /установить бит разрешения ret /(конец WriteEEP)

Установленный бит разрешения eewe в регистре управления сбросится автома­тически, когда запись закончится — этого сброса мы и ожидаем в начале про­цедуры. Естественно, в самый первый раз никакого ожидания на самом деле не потребуется. На всякий случай то же самое рекомендуется делать и при чтении, но это практически всегда (если только мы не читаем непосредственно после записи) не будет задерживать программу дольше, чем на время выполнения команды sbic, то есть на два такта. Так как при чтении не требуется устанав­ливать никаких флагов, то процедура получается несколько короче: ReadEEP: ;в ZH:ZL – адрес откуда читать

/возврат: temp – прочтенный байт

sbic EECR,EEWE /ожидание очистки флага записи

rjmp ReadEEP

out EEARH,ZH /старшая часть адреса out EEARL,ZL /младшая часть адреса sbi EECR,EERE /бит чтения in temp,EEDR /чтение ret /конец ReadEEP

В этих процедурах регистр Z не играет никакой выделенной роли, просто ис­пользуется, как удобная пара регистров, и может быть заменена любой дру­гой парой. Отметим еще, что на время записи следует запрещать прерывания, однако в наших программах далее это будет обеспечиваться автоматически.

Кроме записи констант, наиболее часто EEPROM используется для хранения, например, заводского номера и названия прибора, фамилии конструктора-программиста или названия фирмы-изготовителя, и всякой другой полезной информации (ср. данные, которые извлекает операционная система ПК при подсоединении р1и§&р1ау-устройства, например, через USB). Можно запол­нять различные поля, вплоть до серийного номера, и вести базу выпущенных экземпляров. К процедурам извлечения и записи подобных данных мы сейчас и перейдем.

Прием коэффициентов из ПК и запись их в память

в процедуре writeKoef f мы учтем, что коэффициенты нельзя писать сразу в EEPROM, так как запись байта длится дольше, чем его прием через UART, и во избежание их потери необходим некий буфер. Но нам и не нужно его спе­циально изобретать, так как коэффициенты все равно дублируются в SRAM, откуда их извлекает программа. Потому мы первоначально запишем коэффи­циенты в SRAM, а потом перепишем их в EEPROM для сохранения «навсе­гда». В результате получим следующую процедуру:

WriteKoeff: /записать коэффициенты +8 байт /прерывания уже запрещены

ldi гид

ldi ZL,tZH /начальный адрес SRAM LoopWR:

rcall in_com /принимаем следующий байт St Z+,temp /сложили в SRAM cpi ZL,pKL+l /до адреса pKL ровно 8 байт, /см. листинг в приложении 4

brne LoopWR

/теперь коэффициенты находятся в SRAM, складываем в EEPROM clr ZH

clr ZL /адрес EEPROM = 0:0 ldi YH,1

ldi YL,tZH / начальный адрес SRAM LoopWE:

Id temp,Y+ /забираем из SRAM

rcall WriteEEP /переписываем в EEPROM

inc ZL /следующий адрес

cpi ZL,8

brne LoopWE

ldi temp,$AA /все Ok, посылаем ответ rcall out_com ret

Если все благополучно, по окончании процедуры в компьютер будет послан байт со значением $АА. Если такой байт не получен, это означает, что про­изошел какой-то сбой.

А процедура чтения будет гораздо короче, так как не требуется спешить с приемом байт и, соответственно, обращаться к SRAM (вообще-то нам без­различно, откуда читать коэффициенты, так что будем читать из оригина­ла—из EEPROM):

ReadKoeff: /читать коэффициенты 8 байт из EEPROM

clr ZH

clr ZL LoopRE:

rcall ReadEEP

rcall out_com

inc ZL

cpi ZL,8 /счетчик до 8 brne LoopRE ret

Добавлением этих процедур модификация программы не может ограничить­ся, потому что при включении питания МК запомненные коэффициенты должны пропитаться из EEPROM в SRAM, раз уж в процессе обработки про­грамма читает их оттуда (этот фрагмент включается в процедуру по метке RESET):

inm_RK: /извлечение коэффициентов из EEPROM в SRAM clr ZH

clr ZL /начальный адрес EEPROM 0:0

ldi YL,tZH /начальный адрес SRAM, см. основной текст LoopRK:

rcall ReadEEP /читаем байт

St Y+,tertp /складываем в ОЗУ

inc ZL /следующий адрес

cpi ZL,8 /всего 4 коэффициента, 8 байт

brne LoopRK

Разобранный нами последовательный порт UART хорош своей изумительной простотой. Эта простота, однако, оборачивается и некоторыми недостатками: во-первых, он может работать только на определенной, заранее заданной скорости обмена, во-вторых, предназначен только для соединения не более двух устройств между собой. Протокол 1^С, который мы сейчас разберем, устроен иначе, и потому широко применяется для обмена данными между микросхемами различных типов (например, между контроллером и внешней энергонезависимой памятью, между контроллером и часами реального вре­мени и т. д.).

Оставить комментарий

микросхемы мощности Устройство импульсов питания пример приемника провода витков генератора выходе напряжение напряжения нагрузки радоэлектроника работы сигнал сигнала сигналов управления сопротивление усилитель усилителя усиления устройства схема теория транзистора транзисторов частоты