Ремонт принтеров, сканнеров, факсов и остальной офисной техники


назад Оглавление вперед




[10]

Микроконтроллеры AVR. Ступень 7

С.М. Рюмик, г. Чернигов

В предыдущей статье цикла была приведена электрическая схема "кибер-отгадчика" (РА 6/2005, с.39, рис.9), выводящего информацию на жидкокристаллический индикатор (ЖКИ). Надеемся, что устройство успешно собрано и готово для дальнейших экспериментов.

До сих пор удавалось оберегать читателей от применения таких сложных и специфических конструкций языка Си, как указатели, классы, структуры, ассемблерные вставки. Однако минималистский подход - это не самоцель. Поэтому там, где "высшая Си-математика" нужна, она будет использоваться с кратким объяснением по сути. На практике достаточно запомнить одно правило: "Большинство программ пишутся по шаблонам".

В качестве примера рассмотрим несколько новых приемов программирования для "кибер-отгадчика" из "Ступени 6". Чтобы лучше понимать алгоритмы, необходимо в общих чертах представлять архитектуру памяти МК семейства AVR.

На рис.1 приведена упрощенная схема, показывающая внутреннее устройство микросхемы ATmega8. Три блока (FLASH, EEPROM, фьюзы) предназначены для долговременного хранения данных. Информация в них не исчезает при выключении питания. Блок RAM -это оперативное запоминающее устройство ОЗУ, которое хранит данные только по поданном питании.

FLASH-память является самой большой по объему. В нее записываются коды управляющей программы. Те самые, которые получаются в результате компиляции. Для записи используется адаптер программатора ISP и программа PonyProg.

Фьюзы определяют аппаратную конфигурацию процессорной системы, в частности, способ подачи тактовой частоты, величину задержек, порог срабатывания детектора BOD, организацию сброса. Фьюзы также программируются через PonyProg, независимо от

EEPROM - это отдельная область памяти, по устройству похожая на FLASH. Отличаются они не только названием, но и технологией изготовления. С точки зрения пользователя главное отличие в том, что FLASH "зашивается" только через внешний программатор, а EEPROM - дополнительно еще и от процессорного ядра МК. В итоге получается функция самопрограммирования, которая на рис.1 показана стрелкой от FLASH.

Технология FLASH появилась по времени позже, чем EEPROM и с легкой руки фирмы Intel быстро закрепилась в электронных изделиях. Ячейки FLASH-памяти занимают меньше места на кристалле и стоимость их изготовления ниже. Другое дело, что запись и стирание информации в них производится целыми блоками. Поэтому в ATmega8 оставлена небольшая часть памяти EEPROM, допускающая относительно быстрый доступ к отдельным байтам и имеющая на порядок выше число циклов перезаписи (100 тысяч).

RAM представляет собой быстродействующее статическое ОЗУ, в котором хранятся константы и переменные Си-программы, а также результаты промежуточных расчетов. Программисту полезно запомнить объем RAM в байтах, чтобы примерно ориентироваться, какой максимальной величины массив чисел можно открывать в программах. Например, в ATmega8 массивы должны иметь размерность до 1000 элементов.

Находите время для игры, это - секрет молодости

Лотар Зайверт

Листинг 1

Кибер-отгадчик, =AVR, ступень 7=, Рад±оаматор, №7, 2005 =1 Make: Name=avr71, MCU=atmega8, Level=2, Debug=VMLab=2

Фьюзы: BODEN=BODLEVEL=SUT0=CKSEL3=CKSEL2=CKSELl="0" 1МГц=3 #include <avr/io.h> Библиотека ввода-вывода =4

#include <avr/eeprom.h> Библиотека работы с EEPROM =5

#include <stdlib.h> Библиотека стандартных утилит =6

#define Е unsigned attribute ((section(".eeprom"))) =7

ttdefine RS PCO Условное имя для сигнала RS (ЖКИ) =8

#define EN PC2 Условное имя для сигнала Е (ЖКИ) =9

#define SB PB2 Условное имя линии для кнопки SB1 (МК) =10 #define TIME 10 Базовая задержка при частоте 1 МГц =11

static Е char t0[]= static Е char tl[]= static E char t2[] = static E char t3[]= static E char t4[] =

"=Кибер-отгадчик=Журнал PA-7/05="; =12 "Задумайте число. Умножьте на "; =13 ПрибавьтеРазделите на "; =14

Отнимите заду- манное число. "; =15 "У вас получилось \\\ Угадал ? "; =16

---------------Функция задержки времени---------------=17

void pause(unsigned int a) "a" - длительность паузы =18 ( unsigned int cn; "cn" - счетчик времени =19

for (cn=a; cn > 0; cn-); Цикл задержки времени =20

} Окончание функции "pause" =21

-----------Функция записи команды в ЖКИ---------------=22

void lcd com (unsigned char p) "p" - байт команды =23

Сигнал RS=0 =24 Сигнал EN=1 =25 / / Старший ниббл =2 б Длительность сигнала EN =27 фронт записи команд в ЖКИ =28 Длительность сигнала EN =29 Сигнал EN=1 =30 PORTD = (р « 4); Младший ниббл =31

Длительность сигнала EN =32 EN=0, фронт записи команд в ЖКИ =33 Пауза для выполнения команды =34 Окончание функции "lcd com" =35

Функция записи данных в ЖКИ----------------=36

"р" - байт данных =37 Сигналы RS=1, EN=1 =38

{ PORTC S= ~ BV(RS) PORTC = BV(EN) ;

PORTD S= OxOF; PORTD = (p S OxFO); pause(TIME); PORTC £= <v- BV(EN) pause(TIME); PORTC = BV(EN) ; PORTD &= OxOF pause(TIME); PORTC S= ~ BV(EN) ; pause(5 * TIME);

------void lcd dat(unsigned char p) { PORTC 1= BV(RS) I BV(EN);

PORTD &= OxOF; PORTD = (p S OxFO);

Старший ниббл =39

Длительность сигнала EN =40 EN=0, фронт Записи данных в ЖКИ =41 Длительность сигнала EN =42 Сигнал EN=1 =43 PORTD = (р « 4); Младший ниббл =44

Длительность сигнала EN =45 EN=0, фронт Записи данных в ЖКИ =46 Пауза для выполнения команды =47 } Окончание функции "lcd dat" =48

------------Функция инициализации ЖКИ-----------------=49

void lcd init(void) Режим 4 бит, мигающий курсор =50

pause(TIME); PORTC S= ~ BV(EN) , pause(TIME); PORTC = BV(EN); PORTD &= OxOF; pause(TIME); PORTC &= ~ BV(EN) ; pause(5 * TIME);

pause(500*TIME); Подготовка =51

lcd com(0x28); 4 бит, 2 строки =52

Полное выключение дисплея =53 pause(1000*TIME); Очистка дисплея =54

Сдвиг курсора вправо =55 Включение дисплея, мигающий курсор =56 Окончание функции "lcd init" =57 =ОСНОВНАЯ ПРОГРАММА==== =58

{ lcd com(0x33) lcd com(0x32) lcd com(0x08) lcd com(0x01) lcd com(0x06) lcd com(0x0D)

int main(void) Начало основной программы =59

{ unsigned char a, b, с; Счетчики =60

unsigned int d=0, e=0; Генераторы случайных чисел =61 PORTB = DDRD = OxFF; В=входы с резисторами, Б=выходы =62 PORTC = 0xF8; DDRC = 0x07; PCO...3 выходы с лог.О =63 lcd init(); Инициализация ЖКИ (4 бит, 16x2) =64

while (1) Бесконечный цикл =65

{ for (b=0; b<5; b++) Перебор текстов из пяти фраз =66 { for (lcd com(0x80), а=0; а<32; а++) Первая строка=67 { if (а=1б) lcd com(0xC0) ; Вторая строка =68

if <Ь=0) lcd dat(eeprom read byte<St0[a])) ; 1=69 if (b=l) lcd dat(eeprom read byte(Stl[a])) ; 2=70 if (b=2) lcd dat(eeprom read byte(St2[a])) ; 3=71 if (b=3) lcd dat<eeprom read. byte(&t3[a])) ; 4 =72 if (b=4) lcd dat(eeprom read byte(St4 [a])) ; 5=73 } Окончание вывода текста в 2 строки по 16 букв =74 if <(b=l) I I (b=2)) Вывод чисел к фразам 2 и 3 =75 { lcd com<0xCE); lcd dat{d + 0x30); Ума., деление=76 } Окончание вывода чисел умножения и деления =77

if (Ь==2) Вывод числа прибавления к фразе 3 =78

{ c=d * е; lcd com(0x8C); Установка курсора =79

lcd dat{c/10 + 0x30); lcd dat(c%10 + 0x30); =80 } Окончание вывода числа прибавления =81

if (b=4) Вывод числа предсказания к фразе 5 =82

{ lcd com(0xCl); lcd dat(e + 0x30); Курсор, дата =83 } Окончание вывода числа предсказания =84

while(bit is set{PINB,SB)) Ждать нажатия кнопки =85 { if (b==0) Начальная генерация случайных чисел =86 { d=rand()%8 + 2; e=rand()%9 + 1; d=2-9, е=1-9 =87 } Окончание генерации случайных чисел =88

} Окончание процедуры нажатия кнопки SB1 =89

pause(65000); pause(65000); Пауза антидребезга =90 } Переход к следующей из пяти фраз =91

} Переход к новому предсказанию числа =92

} WinAVR-20050214, FLASH 1240 байтов, EEPROM 165 байтов=93


Из всех перечисленных областей памяти только EEPROM не встречалась ранее в программах. Восполнить пробел позволяет "кибер-отгадчик", программа которого приведена в листинге 1.

Пояснения к программе

Строка 3. Настройка фьюзов на работу от внутреннего генератора частотой 1 МГц. Новинка - обнуляются фьюзы BODEN и BODLEVEL, вследствие чего включается в работу детектор просадок напряжения питания BOD. Теперь сброс МК будет происходить при каждом снижении питания ниже 4 В (технологический разброс 3,7...4,5 В).

Почему раньше, когда в программах была задействована только FLASH-память, включение детектора BOD было не обязательным? Дело в том, что МК не может самостоятельно перепрограммировать свой FLASH (наводки на входы адаптера ISP не в счет). А вот область EEPROM он перепрограммировать может, причем даже при очень низких напряжениях питания 2...2,7 В.

Чтобы МК случайно не "запортил" данные в EEPROM при медленном нарастании или спаде питания, применяется детектор BOD. Если бы разрабатываемое устройство эксплуатировалось в заводских условиях при мощных промышленных помехах, то не помешала бы и внешняя микросхема-супервизор КР1171СП42, обеспечивающая надежный сброс МК по выводу RESET.

Строки 5,6 - подключение двух новых системных библиотек. Первая из них обслуживает все, что связано с EEPROM в строках 7, 12-16, 69-73. Вторая библиотека нужна для одной-единственной системной функции "rand" в строке 87, которая обеспечивает генерацию псевдослучайных чисел в диапазоне 0-7FFFh.

Строка 7 содержит длинное макроопределение для буквы "Е". Выражение, которое оно замещает, подставляется при компиляции в строках 12-16. Это типичный прием в языке Си по сокращению листинга и улучшению его читаемости. Вместо "E" могла быть другая буква, что не принципиально.

С физической точки зрения текстовые массивы t0[ ]-t4[ ], определенные с параметром "E", будут размещаться не в FLASH, а в EEPROM. Зачем? С целью экономии места в памяти. В данном учебном листинге это не столь критично, однако если представить, что FLASH заполнено на 99%, то лишние полкилобайта памяти сродни "палочке-выручалочке".

Строки 23-35, 37-48, 50-57 аналогичны одноименным функциям из листинга 1 "Ступени 6", но для 4-битового интерфейса связи. Функция инициализации, как и прежде, является главной. Ее текст насыщен паузами, а последовательность расстановки команд напоминает заклинания шамана, поскольку явная логика не прослеживается. Однако примерно такой алгоритм указан в DATASHEET на микросхему HD44780, являющуюся главной в применяемом ЖКИ. Абсолютные значения времени пауз выбраны с запасом по сравнению с DATASHEET, чтобы нормально проходило моделирование в среде VMLab.

Строка 66. Общение человека с "кибером" происходит с помощью пяти последовательно генерируемых фраз. Текст располагается в верхней и нижней частях экрана. Поменять его можно в строках 12-16. При этом надо знать, что первые 16 символов массивов t0[ ]-t4[ ] индицируются в верхней, а последние 16 символов - в нижней строчке.

Строки67-74. Стандартный прием полной загрузки текста в ЖКИ. Начальное положение курсора (по-другому, начальный адрес) устанавливается только один раз в строке 67 ("lcd com"), причем для сокращения места оператор включен прямо в состав функции "for". Дальнейший вывод текста происходит автоматически слева направо, сверху вниз.

Строки 69-73. С помощью библиотечной функции "eep-rom read byte" читается один байт данных из EEPROM. Поскольку его абсолютный адрес не указан, то применяют так называемые "указатели" в виде знака "&" перед текстовыми массивами t0[ ]-t4[ ]. Указатели относят к базовым понятиям в языке Си. Они достаточно сложные для "объяснения на пальцах". Поэтому на первых порах надо просто запомнить шаб-

лон и знать, что применяется он, в частности, при обращении к текстовым массивам в функции "eeprom read byte".

Строки 75-84. После вывода на экран фраз в строках 13, 14, 16, их надо дополнить цифрами умножения, деления и сложения. Процедура простая: в начале указывается местоположение на экране курсора ("lcd com"), а затем код символа ("lcd dat") согласно табл.3 в "Ступени 6" (РА 6/2005, с.37).

Строки85-89. Процесс опроса кнопки SB1 совмещен с генерацией случайных чисел. Однако производится он только при фразе 1, во время экранной заставки. Строго говоря, функция "rand" в строке 87 возвращает псевдослучайное (почти случайное) число, но, благодаря циклическому выполнению функции "while" и произвольному во времени моменту нажатия кнопки SB1, префикс "псевдо" исчезает.

Строка 90 определяет задержку времени, учитывающую "дребезг" контактов кнопки SB1, иначе фразы могут слишком быстро проскакивать по экрану.

Строка 93. В комментариях указывается, что программировать следует две области памяти: FLASH и EEPROM. Как это сделать, будет рассказано дальше.

Симуляция "Кибер-отгадчика" в VMLab и перекодирование текста

Перед дальнейшей работой надо создать на жестком диске отдельную папку, в которую поместить файл "avr71.c" (листинг 1) и стандартный make-файл, созданный программой

Моделирование разработанного устройства в VMLab проводится по той же методике, что и для листинга 1 в "Ступени 6". Единственное, что в файле проекта "avr71.prj" надо заменить строку, отвечающую за ЖКИ, по образцу: "X1 (16 2 250K) PC0 PC1 PC2 PD7 PD6 PD5 PD4 nc3 nc2 nc1 nc0". В результате моделирования на экране симулятора появится надпись начальной застав-

J LCD (HD447S0tiipe): 1.16 char

=Кибер-отгадчик= =Журнал РА-7/05=

ки (рис.2). Необычность ситуации в том, что фраза написана по-русски, а ведь текст еще не перекодирован! Получает-

Листинг 2

Бегущий текст анонса, =AVR. Ступень 7=, РА, №7, 2005 г. =1 Make: Name=avr72, MCU=atmega8, Level=2, Debug=VMLab =2 Фьюзы: SUT0=CKSEL3=CKSEL2=CKSELl="rano4KH" (1 МГц)=3

#include <avr/io.h> Библиотека ввода-вывода =4

linclude <avr/pgmspace.h> Библиотека для "sigeofO" =5 Sdefine TEMP 7000 Скорость движения бегущей строки =6 extern void lcd com(unsigned char p); Ввод команд ЖКИ =7 extern void lcd dat(unsigned char p); Ввод данных ЖКИ =8 extern void lcd init(void); Инициализация ЖКИ =9

extern void pause(unsigned int p); Пауза для ЖКИ =10

unsigned char t0[]="=Кибер-отгадчик= Правила\

игры. Вы задумываете любое число и выполняете над ним прос\ тые арифметические действия, которые просит <кибер>. Фокус \ в том, что <кибер> угадает результат! Вы готовы? Нажмите кн\ опку."; Текст верхней строки =15

unsigned char tl[]="=Журнал РА-7/05="; Нижняя строка =16 ============ОСНОВНАЯ ПРОГРАММА============== =17

int main(void) Начало основной программы =18

{ unsigned char а, Ь, с; Счетчики =19

PORTB = DDRD = OxFF; В=входы с резисторами, О=выходы =20 PORTC = 0xF8; DDRC = 0x07; РСО...3 выходы с лог.О =21 lcd init(); Инициализация ЖКИ (4 бит, 16x2) =22

lcd COm(0x0C); Выключение курсора ЖКИ =23

for (lcd com(0xC0), с=0; с<16; C++) Нижняя строка =24 ( lcd dat(tl[c]); Вывод текущего символа =25

) Окончание вывода 16 символов в нижней строке =26

while (1) Бесконечный цикл =27

{ for (Ь=0; Ь < (sizeof(t0)-16); Ь++) Смещение текста=28 ( for (lcd com(0x80), с=0; с<16; С++) Верхн.строка =29 { lcd dat(t0[c+b]); Вывод текущего символа =30

} Окончание вывода 16 символов в верхней строке =31 for (а=0; а<20; а++) pause(TEMP); Скорость =32

} Переход к смещению текста на один символ влево =33 ) Переход к новому циклу движения бегущей строки =34 } WinAVR-20050214, длина кода 594 байтов =35


ся, что модель ЖКИ в VMLab подстраивается под текущий шрифт Windows и показывает то, что хотелось бы видеть пользователю, а не то, что на самом деле имеется в знакогенераторе ЖКИ. С другой стороны, это облегчает симуляцию программы, поскольку все надписи легко читаются.

Вывод - симуляцию процессов в VMLab надо проводить до перекодирования текста, т.е. сразу после составления листинга.

После завершения работы с VMLab наступает этап перекодирования шрифта и окончательной компиляции программы.

Листинг 3

Файл "led.с", набор функций ЖКИ. =Ступень 7=, РА-7/2005 Интерфейс 4-бита по линиям PD4...PD7, WinAVR-20050214 linclude <avr/io.h> Библиотека ввода-вывода Idefine RS PCO Условное имя для сигнала RS (ЖКИ) Idefine EN РС2 Условное имя для сигнала Е (ЖКИ) Idefine TIME 10 Базовая задержка для ЖКИ ---------------Функция задержки времени---------------void pause(unsigned int p) "p" - длительность паузы ( unsigned int cn; "cn" - счетчик времени

for (cn=p; cn > 0; cn-); Цикл задержки времени =

} Окончание функции "pause" =

-------Общая часть функций lcd com, lcd dat-----------=

void lcd(unsigned char p) "p" - байт данных или команд = ( PORTD S= OxOF; PORTD = (p S OxFO); Старший ниббл =

Длительность сигнала EN = EN=0, фронт записи данных в ЖКИ = Длительность сигнала EN = Сигнал EN=1 = = (р « 4); Младший ниббл =

Длительность сигнала EN = EN=0, фронт записи данных в ЖКИ = Пауза для выполнения команды = ) Окончание функции "led" =

-----------Функция записи команды в ЖКИ---------------=

void lcd com(unsigned char p) "p" - байт команды =

{ PORTC S=~ BV(RS); PORTC = BV(EN); RS=0, EN=1 =

lcd(p); Вызов общей части функций lcd com, lcd dat = } Окончание функции "lcd com" =

-----------Функция записи данных в ЖКИ----------------=

void lcd dat(unsigned char p) "p" - байт данных =

{ PORTC = BV(RS) I BV(EN); RS=1, EN=1 =

lcd(p); Вызов общей части функций lcd com, lcd dat = } Окончание функции "lcd dat" =

------------Функция инициализации ЖКИ-----------------=

void led init(void) Режим 4 бит, мигающий курсор =

pause(TIME); PORTC S= ~ BV(EN); pause(TIME); PORTC = BV(EN); PORTD S= OxOF; PORTD pause(TIME); PORTC S= ~ BV(EN); pause(5*TIME);

{ lcd com(0x33) lcd eom(0x32) lcd eom(0x08) lod com(0x01) lcd com(0x06) lcd eom(0x0D)

pause(500*TIME); Подготовка

lcd com(0x28); 4 бит, 2 отроки

Полное выключение дисплея pause(1000*TIME); Очистка дисплея Сдвиг курсора вправо Включение дисплея, мигающий курсор Окончание функции "led init"

Файл "makefile"

Файл "avr72.c"

Файл "led.с"

Заголовок программы

ххххх"

Заголовок программы

Функция "main" {

Оператор 1;

Оператор Р; ххххх (); Оператор К;

Функция "ххххх"

Оператор 1;

Оператор S; return;

Если этого не сделать, то реально видимые фразы в ЖКИ станут похожими на "китайскую грамоту".

Порядок действий. Скопировать с сайта РА авторскую утилиту "ruslcd.exe" в папку, где размещен файл "avr71.c". Набрать в командной строке "ruslcd avr71.c", после чего все русскоязычные фразы в строках 12-16 листинга 1 будут заменены "абракадаброй" с точки зрения IBM PC и нормальным текстом с точки зрения ЖКИ. Далее проводится стандартная компиляции программы редактором Programmers Notepad через меню "Tools - [WinAVR] Make All".

Надписи русскоязычных комментариев после обработки текста утилитой "ruslcd.exe" остаются без изменений, поэтому ее можно использовать и в других Си-программах для самых разных семейств МК.

Программирование EEPROM в PonyProg

После компиляции перекодированной программы "avr71.c", как обычно, появится файл "avr71.hex", в котором содержится информация для записи FLASH. Параллельно с этим в той же папке будет создан файл "avr71.eep", который также содержит HEX-коды, но уже для записи в EEPROM. Логично, что методика программирования МК немного изменится.

Порядок действий. Запустить на выполнение программу PonyProg. Загрузить файл "avr71.hex" через меню "File - Open Program (FLASH) File - <выбрать расширение *.hex> - <указать "avr71.hex">". Загрузить файл "avr71.eep" через меню "File Open Data (EEPROM) File - <выбрать расширение *.eep> - <указать "avr71.eep">". Открыть закладку "Command - Program Option" и к уже установленным "галочкам" возле пунктов "Reload Files", "Erase", "Write Program memory (FLASH)" поставить "галочку" в окне "Write Data memory (EEPROM)". Вернуться в начальное меню и нажатием клавиш <Ctrl>+<P> запрограммировать сразу обе области памяти МК.

ЖКИ с бегущей строкой

Бегущая строка обычно ассоциируется с рекламными титрами. Но ее также с успехом можно использовать для вывода большой по объему информации на малоразмерный экран. В качестве примера предлагается добавить в "кибер-отгадчик" бегущую строку с пояснениями правил игры.

Программное обеспечение для удобства разбито на 2 части (листинги 2, 3). Здесь реализована архитектура третьего типа по классификации, рассмотренной ранее для МК семейства MCS-51. На рис.3 показаны взаимосвязи основной программы "avr72.c" (листинг 2), блока внешних функций "lcd.c" (листинг 3) и управляющего make-файла. Символом "xxxxx" обозначены вызываемые функции. Такой подход позволяет использовать файл "lcd.c" без изменений и в других программах.

Пояснения к листингу 2

Строка 5. Подключение новой системной библиотеки "pgm-space", отвечающей за обслуживание массивов памяти.

С2 47мкх16В R1 20 к

>. го а. о. Ф о

DD1 ATmega8-8PI

RES MOSI MISO SCK

PD4 PD5 PD6 PD7

VCC AVCC

GND GND

>+5B HG1 „, MTC-16204X



[стр.Начало] [стр.1] [стр.2] [стр.3] [стр.4] [стр.5] [стр.6] [стр.7] [стр.8] [стр.9] [стр.10] [стр.11]