Помощничек
Главная | Обратная связь


Археология
Архитектура
Астрономия
Аудит
Биология
Ботаника
Бухгалтерский учёт
Войное дело
Генетика
География
Геология
Дизайн
Искусство
История
Кино
Кулинария
Культура
Литература
Математика
Медицина
Металлургия
Мифология
Музыка
Психология
Религия
Спорт
Строительство
Техника
Транспорт
Туризм
Усадьба
Физика
Фотография
Химия
Экология
Электричество
Электроника
Энергетика

Алгоритм функционирования программы



Закодировать точки (ступеньки) синусоиды можно двумя методами:

1) Задаем число точек (ступенек) на период. Период квантования синусоиды можно рассчитать:

Преимущество метода: простота.

Недостаток метода: если скорость нарастания сигнала различна (у синусоиды она уменьшается по мере приближения к ), появляется много одинаковых точек (расположенных на одном уровне), которые занимают много места в памяти.

Решить эту проблему позволяет второй метод.

2) Задаем период квантования синусоиды. Число точек (ступенек) на период заранее неизвестно. Генерируем 12-битный синусоидальный сигнал и через каждый промежуток времени, равный периоду квантования синусоиды, смотрим, изменился ли уровень сигнала. Если уровень сигнала не изменился, увеличиваем число повторов текущей точки на единицу. Если уровень изменился, это означает, что мы получили следующую точку синусоиды. Число ее повторов находится аналогично.

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

Для получения точек синусоиды был выбран период квантования синусоиды, равный 4000 мкс, при частоте синусоиды, равной 1 Гц. Синусоида будет состоять из 246 точек (ступенек) на период. При изменении частоты синусоиды от 5 до 100 Гц число точек меняться не будет, изменится лишь период квантования синусоиды. Рассчитывается он следующим образом.

Так как частота синусоиды может меняться от 5 до 100 Гц, период квантования синусоиды будет различным для разных частот и его можно найти (в пересчете на такты микроконтроллера, для 16-битного таймера):

- период квантования синусоиды для частоты 1 Гц, равный 4000 мкс;

- тактовая частота кварца, равная 30 МГц;

– число тактов кварца за 1 машинный цикл, равное 12-ти;

– заданная частота синусоиды (от 5 до 100 Гц):

Алгоритм функционирования программы приведен на рис. 6-9:

Рис. 6. Алгоритм основной программы.

 

 

Рис. 7. Алгоритм подпрограммы обслуживания внешнего прерывания INT0.

 

Рис. 8. Алгоритм подпрограммы обслуживания прерывания от таймера T0.

Рис. 9. Алгоритм подпрограммы обслуживания прерывания от таймера T1.

­­­­В соответствии с данным алгоритмом была разработана программа, обеспечивающая выполнение микроконтроллером заданной функции.

Составим граф состояний клавиатуры (рис. 10) , согласно которому в дальнейшем будет удобнее работать с клавиатурой. Здесь вершины графа:

1 – режим RABOTA: входим в режим по нажатию клавиши RABOTA, в этом режиме происходит вывод синусоиды.

2 – режим VVOD: входим в режим по нажатию клавиши VVOD, в этом режиме происходит опрос клавиатуры.

3 – режим VVOD_U: входим в режим по нажатию клавиши BUTTON_U, в этом режиме происходит опрос клавиатуры и изменение амплитудного значения напряжения синусоиды.

4 – режим VVOD_f: входим в режим по нажатию клавиши BUTTON_f, в этом режиме происходит опрос клавиатуры и изменение частоты синусоиды.

 

 

Рис. 10. Граф состояний клавиатуры.


Описание программы

В начале программы объявим все необходимые константы, а именно:

· константы для ЦАПов, определяющие выводы шины управления для ЦАПов;

· константы для клавиатуры, определяющие коды режимов работы и коды клавиш;

· константы для дисплея, определяющие выводы шины управления для дисплея и др.

Далее будут располагаться макроопределения (макросы) для работы с ЦАПами:

· Макрос MACRO_WR_DAC передает байт указанному ЦАП (его старшему или младшему байту):

MACRO_WR_DAC macro pin_,data_

;сначала выводим данные на пины порта - см. timing diagram

mov P0,data_

clr pin_

clr WR_DAC

nop

nop

setb WR_DAC

setb pin_

ENDM

· Макрос MACRO_LDAC обновляет значение на выходе выбранного ЦАПа:

MACRO_LDAC macro pin_

clr pin_

nop

nop

setb pin_

ENDM

В данной программе мы будем использовать сегмент данных (DS) и сегмент кода (CS). В сегменте данных (т.е. в ОЗУ) начиная с адреса 08h будут располагаться следующие переменные:

Addr_tochki: DS 2 ;адрес выводимой точки в массиве

Counter_tochka: DS 1 ;число повторений выводимой точки

Cod_tochki: DS 2 ;код текущей точки – мл. и старш. байты

Regim_raboty: DS 1 ;код режима работы

U_value: DS 1 ;величина напряжения

f_value: DS 1 ;величина частоты

Predidyshiy_kod_s_klavy: DS 1 ;предыдущий код, получ. с клавиатуры

Zaderzhka_f_5_100: DS 2 ;период квантования синусоиды

Stack_base: DS 0 ;начальный адрес стека в памяти

В сегменте кода (т.е. в ПЗУ) будет располагаться программа.

По адресу в ПЗУ 00h мы должны разместить команду абсолютного перехода на метку start (т.е. на начало программы).

Далее следует директива ORG 0003h, которая устанавливает в счетчик РС адрес вектора прерывания INT0 - в том случае, если прерывание было вызвано определенным событием (в данном случае – нажатием на кнопку VVOD, т.е. фронтом). В случае, если данное прерывание было вызвано, выполнится команда, находящаяся в ПЗУ по адресу 0003h – а это команда абсолютного перехода на метку interrupt_VVOD (т.е. на начало подпрограммы обработки прерывания от внешнего источника INT0).

Аналогично с директивами ORG 000Вh и ORG 001Вh, которые устанавливают в счетчик РС адрес вектора прерывания T0 и Т1 соответственно - в том случае, если прерывание было вызвано переполнением таймера Т0 или Т1. В случае, если было вызвано одно из этих прерываний, выполнится команда, находящаяся в ПЗУ по адресу 000Вh или 001Вh, т.е. команда абсолютного перехода на начало подпрограммы обработки прерывания от таймера Т0 или Т1 соответственно.

CSEG

ajmp start

org 0003h ;установили в счетчик РС адрес вектора прерывания INT0

ajmp interrupt_VVOD

org 000Bh ;установили в счетчик РС адрес вектора прерывания T0

ajmp interrupt_T0

org 001Bh ;установили в счетчик РС адрес вектора прерывания T1

ajmp podprog_DAC_OUT

Далее в ПЗУ у нас располагается основная программа. В начале основной программы необходимо выполнить инициализацию:

· стека:

mov SP,#Stack_base

· порта Р0 (начальным значением):

mov P0,#0FFh ;установим на пины порта Р0 все 1цы

· ЦАПов:

;пины должны быть не активны + учтем, что они инверсные:

setb CSL_REF

setb CSM_REF

setb LDAC_REF

setb WR_DAC

setb CSL_OUT

setb CSM_OUT

setb LDAC_OUT

· клавиатуры:

setb IT0 ;тип прерывания INT0 - по фронту

setb EA ;снятие блокировки прерываний

setb EX0 ;разрешение внешнего прерывания 0

mov Predidyshiy_kod_s_klavy,#00h

· дисплея:

clr E_LCD

acall podprog_nastroyka_displaya

· режима работы

mov Regim_raboty,#VVOD

mov U_value,#05h;#0Ah

mov f_value,#05h

acall Redraw_LCD_RABOTA

Далее мы настраиваем таймеры Т0 и Т1 и запускаем таймер Т0, который опрашивает клавиатуру раз в 1 мс:

mov TMOD,#00010001b ;16-битные таймеры Т0 и Т1

setb EA ;снимаем запрет всех прерываний

setb ET0 ;разрешаем прерывания от таймера Т0

setb ET1 ;разрешаем прерывания от таймера Т1

mov TL0,#low(Timer_1_ms)

mov TH0,#high(Timer_1_ms)

setb TR0 ;запускаем таймер Т0

Затем мы инициализируем синусоиду. Для получения точек синусоиды был выбран период квантования синусоиды, равный 4000 мкс, при частоте синусоиды 1 Гц. Синусоида будет состоять из 246 точек (ступенек) на период. В конце программы (после основной программы и всех подпрограмм) с помощью директивы DB размещена таблица точек синусоиды, где последовательно располагаются: время удержания точки и код точки синусоиды (младший и старший байты).

 

 

Инициализация синусоиды:

;адрес первой выводимой точки в таблице

mov Addr_tochki,#LOW(Start_sin)

mov Addr_tochki+1,#HIGH(Start_sin)

;число повторений точки - получим из таблицы в ПЗУ

mov DPTR,#Start_sin

mov A,#00h

movc A,@A+DPTR

mov Counter_tochka,A

;выводим код точки на выходной ЦАП

;старший байт - получим из таблицы в ПЗУ

mov A,#02h

movc A,@A+DPTR

MACRO_WR_DAC CSM_OUT,A ;сначала ст. байт кода точки в ст.байт ЦАП

;младший байт - получим из таблицы в ПЗУ

mov A,#01h

movc A,@A+DPTR

MACRO_WR_DAC CSL_OUT,A ;потом мл. байт кода точки в мл. байт ЦАП

MACRO_LDAC LDAC_OUT

В конце основной программы нам необходимо поместить команду ajmp $, которая выполняет абсолютный переход на саму себя, что не дает выполниться подпрограммам, расположенным далее. Подпрограммы обработки прерываний смогут выполниться лишь в том случае, если произойдут события, по которым вызываются прерывания (например, нажатие кнопки VVOD или переполнение таймера Т0/Т1).

 

 

По умолчанию при запуске программы установлен режим работы VVOD. В этом режиме происходит следующее.

В данном режиме останавливается вывод синусоиды и раз в миллисекунду начинает происходить опрос клавиатуры по таймеру Т0, а также производится проверка корректности введенных значений напряжения и частоты:

interrupt_VVOD:

clr TR1

clr TR0

mov TL0,#low(Timer_1_ms)

mov TH0,#high(Timer_1_ms)

mov Regim_raboty,#VVOD

setb TR0

;проверка нижнего допустимого значения напряжения - больше или равно 5

mov A,#5

subb A,U_value

jc loop_podprog_VVOD_U_Value_correktno_vvod

mov U_value,#5

loop_podprog_VVOD_U_Value_correktno_vvod:

;проверка нижнего допустимого значения частоты - больше или равно 5

mov A,#5

subb A,f_value

jc loop_podprog_VVOD_f_Value_correktno_vvod

mov f_value,#5

loop_podprog_VVOD_f_Value_correktno_vvod:

acall Redraw_LCD_Rabota

reti

Клавиатура будет опрашиваться до тех пор, пока не будет нажата клавиша BUTTON_RABOTA (т.е. пока не начнется вывод синусоиды).

При переполнении таймера Т0, который мы запустили при инициализации микроконтроллера, произойдет вызов подпрограммы обработки прерывания от таймера Т0.

В начале данной подпрограммы перезапускается таймер Т0 для дальнейшего опроса клавиатуры:

interrupt_T0:

;перезапустим таймер Т0

clr TR0

mov TL0,#low(Timer_1_ms)

mov TH0,#high(Timer_1_ms)

setb TR0

Затем код режима работы сравнивается с кодами всех режимов работы.

mov A,Regim_raboty

cjne A,#VVOD,interrupt_T0_VVOD_U

В случае если код изменился, в переменную Regim_raboty помещается новый код режима работы, после чего происходит выход из прерывания.

Рассмотрим работу подпрограммы более подробно.

Если мы находимся в режиме работы VVOD, мы получаем с клавиатуры код нажатой клавиши (с помощью подпрограммы, возвращающей код нажатой клавиши и осуществляющей защиту клавиатуры от дребезга), и в зависимости от полученного кода выполняем различные действия.

acall podprog_anti_drebezg

cjne A,#BUTTON_U,interrupt_T0_BUTTON_f

;если была нажата клавиша U, на дисплее высветится *U(B):000

mov Regim_raboty,#VVOD_U

mov U_value,#00h

acall Redraw_LCD_U

ajmp interrupt_T0_end

interrupt_T0_BUTTON_f:

cjne A,#BUTTON_f,interrupt_T0_BUTTON_RABOTA

;если была нажата клавиша f, на дисплее высветится *f(B):000:

mov Regim_raboty,#VVOD_f

mov f_value,#00h

acall Redraw_LCD_f

ajmp interrupt_T0_end

Если были нажаты клавиши BUTTON_U или BUTTON_f, режим работы меняется соответственно на VVOD_U или VVOD_f, а также с помощью подпрограмм Redraw_LCD_U/Redraw_LCD_f обновляется дисплей (рис. 11 и 12):

Рис.11. Символы, выводимые на дисплей подпрограммой Redraw_LCD_U.

Рис.12. Символы, выводимые на дисплей подпрограммой Redraw_LCD_f.

Если же была нажата клавиша BUTTON_RABOTA, режим работы меняется на RABOTA, останавливается таймер Т0, в первый (опорный) ЦАП выводится опорное напряжение (по умолчанию равное 5 В), устанавливается значение частоты синусоиды (по умолчанию равное 5 Гц), а также настраивается и запускается таймер Т1, который используется для вывода синусоиды.

interrupt_T0_BUTTON_RABOTA:

cjne A,#BUTTON_RABOTA,interrupt_T0_end

mov Regim_raboty,#RABOTA

;здесь настроим вызов прерывания для синусоиды

clr TR0 ;остановили таймер клавиатуры и дисплея

acall podprog_DAC_U

acall podprog_f_SIN

acall Redraw_LCD_RABOTA

;запускаем таймер для синусоиды

mov TL1,Zaderzhka_f_5_100

mov TH1,Zaderzhka_f_5_100+1

setb TR1

ajmp interrupt_T0_end

Таким образом, если в свой предыдущий вызов подпрограмма установила режим работы VVOD_U или VVOD_f, вызываются подпрограммы podprog_VVOD_U или podprog_VVOD_f соответственно, которые осуществляют ввод напряжения/частоты с клавиатуры.

interrupt_T0_VVOD_U:

cjne A,#VVOD_U,interrupt_T0_VVOD_f

;поместим на 1ю строчку дисплея 00:

acall podprog_VVOD_U

mov Regim_raboty,A

ajmp interrupt_T0_end

interrupt_T0_VVOD_f:

cjne A,#VVOD_f,interrupt_T0_end

acall podprog_VVOD_f

mov Regim_raboty,A

interrupt_T0_end:

reti

При переполнении таймера Т1 произойдет вызов подпрограммы обработки прерывания от таймера Т1.

В начале данной подпрограммы перезапускается таймер Т1, что позволит вывести следующую точку синусоиды через время, определяемое частотой синусоиды (т.е. через время, равное периоду квантования синусоиды для данной частоты). Период квантования синусоиды для частот от 5 до 100 Гц с шагом 1 Гц рассчитан и помещен в таблицу в конце программы с использованием директивы DW (т.к. значения периода квантования – двухбайтные числа).

После перезапуска таймера Т1 производится проверка, сколько осталось повторений текущей точки. Если число оставшихся повторений текущей точки равно нулю, в данном прерывании мы будем работать со следующей точкой синусоиды. Если текущая точка является последней точкой синусоиды, в данном прерывании мы будем работать с первой точкой синусоиды.

Выводим код точки на второй (выходной) ЦАП – сначала старший байт, потом младший, и выходим из прерывания.

 

 

Помимо подпрограмм обработки прерываний, программа включает следующие необходимые подпрограммы.

1) Подпрограмма задержки на N мкс: podprog_wait_N_mks

В подпрограмму передается число в DPTR, равное времени задержки, пересчитанному в тактах МК.

2) Подпрограмма установки напряжения на опорном ЦАП: podprog_DAC_U

Максимальный код, который мы можем передать на 12-битный ЦАП (4095), ставим в соответствие максимальному напряжению, которое мы можем ввести с клавиатуры, т.е. 15В:

.

Т.е. умножая вводимое с клавиатуры напряжение на 273 (т.е. 111h), мы будем выдавать на ЦАП соответствующий такому напряжению код:

5В – 555h

6B – 666h

7B – 777h

14B – EEEh

15B - FFFh

3) Подпрограмма загрузки периода квантования синусоиды, пересчитанного для частот синусоиды от 5 до 100 Гц, из ПЗУ: podprog_f_SIN

Подпрограмма загружает в 2-байтную переменную Zaderzhka_f_5_100 2-байтное число, равное периоду квантования синусоиды, пересчитанному в тактах МК.

 

 

4) Подпрограмма работы с клавиатурой, которая возвращает 8-битный код нажатой клавиши в регистр R0: podprog_klava

Используя операцию «логическое И с маской», выделяем сначала младшую тетраду кода клавиши (в используемой нами матричной клавиатуре это определяет «строку», в которой находится клавиша), а затем старшую тетраду кода клавиши (в используемой нами матричной клавиатуре это определяет «столбец», в котором находится клавиша). Затем объединяем тетрады с помощью логического ИЛИ и получаем код нажатой клавиши.

5) Подпрограмма защиты клавиатуры от дребезга, которая возвращает в аккумулятор код нажатой клавиши с учетом защиты от возможного дребезга: podprog_anti_drebezg

Эта подпрограмма получает код нажатой клавиши с помощью предыдущей подпрограммы, запоминает его, а затем еще пять раз получает код клавиши и выполняет сравнение текущего кода с самым первым.

6) Подпрограмма ввода напряжения с клавиатуры: podprog_VVOD_U

Получаем напряжение с клавиатуры, используя две предыдущие подпрограммы, затем выясняем, была ли нажата цифровая клавиша (0-9) либо другая клавиша (BUTTON_U, BUTTON_f, BUTTON_RABOTA).

Если была нажата какая-либо из цифровых клавиш, вычисляем значение напряжения, проверяем, не превышает ли оно 255 (чтобы не произошло переполнение), а затем – не превышает ли оно 15 (максимальное допустимое значение напряжения). Если все верно, выводим это значение напряжения на дисплей.

Если же была нажата какая-либо из клавиш BUTTON_U, BUTTON_f, BUTTON_RABOTA, соответственно обрабатываем эти состояния.

7) Подпрограмма ввода частоты с клавиатуры: podprog_VVOD_f

Данная подпрограмма работает аналогично предыдущей подпрограмме.

8) Подпрограмма, выводящая на дисплей строки U(B):0ХХи *f(Hz):ХХХ: Redraw_LCD_f

9) Подпрограмма, выводящая на дисплей строки *U(B):0ХХи f(Hz):ХХХ: Redraw_LCD_U

10) Подпрограмма, выводящая на дисплей строки U(B):0ХХи f(Hz):ХХХ: Redraw_LCD_ RABOTA

11) Подпрограмма, выводящая на дисплей строку символов U(B): или f(Hz): print_string_LCD

В подпрограмму передается в DPTR адрес начала строки в ПЗУ, после чего строка выводится на дисплей.

12) Подпрограмма, выводящая на дисплей численное значение напряжения или частоты: print_num_LCD

В подпрограмму передается в аккумуляторе содержимое переменной U_value или f_value. Выводим на дисплей поочередно сотни, десятки и единицы, которые выделяем с помощью операции DIV AB – деление A на B. Результат: в A -частное, в B - остаток.

13) Подпрограмма преобразования двоичного кода цифровой клавиши в число от нуля до 9: podprog_kod_v_chislo

14) Подпрограмма настройки дисплея, которая осуществляется согласно таблице "Начальная настройка индикатора" из даташита: podprog_nastroyka_displaya

15) Подпрограмма ожидания флага BUSY: podprog_wait_BUSY_flag_LCD

Ожидаем, пока флаг BUSY (старший бит байта команды) не сбросится (т.е. пока не станет равен нулю).

16) Подпрограмма чтения данных из дисплея, данные возвращаются в аккумулятор: podprod_read_data_LCD

17) Подпрограмма записи данных в дисплей, данные в подпрограмму передаются в аккумуляторе: podprog_write_data_LCD

18) Подпрограмма чтения команд из дисплея, команды возвращаются в аккумулятор: podprod_read_command_LCD

19) Подпрограмма записи команд в дисплей, команды в подпрограмму передаются в аккумуляторе: podprod_write_command_LCD

 

 




Поиск по сайту:

©2015-2020 studopedya.ru Все права принадлежат авторам размещенных материалов.