Наш канал в telegram

Управляющая программа для цифрового генератора опорного напряжения

В этой статье приводится пример простейшей программы управления микроконтроллером для цифрового генератора опорного напряжения (генератор у нас, если помните, сделан на ATtiny13).

Что наш генератор умеет с такой программой? С такой программой он умеет устанавливать любое выходное напряжение в пределах от 0 до 5 Вольт с шагом 19,6 мВ, умеет изменять выходное напряжение при нажатии на кнопки (одна кнопка — для увеличения выходного напряжения, другая — для уменьшения), а также ограничивать минимальное и максимальное значение выходного напряжения (то есть диапазон 0-5В можно сузить, скажем, до величины 0.98-4.9В).

В контроллере при нажатии на кнопки изменяется не сразу сам выход, а сначала изменяется внутренняя переменная (setup — уставка), к которой затем постепенно подтягивается выход. Сделано это для того, чтобы можно было менять выход с заданной плавностью, независимо от скорости изменения уставки, поскольку уставку можно и вообще мгновенно задавать, скажем по интерфейсу или с пульта.

Из интересного отмечу также алгоритм обработки нажатий кнопок. В данном случае вам не нужно жать кнопку столько же раз, на сколько шагов нужно изменить выход. Всё то время, пока вы держите кнопку нажатой — изменяется уставка (и вместе с ней, естественно, — выходное напряжение). Причём изменение уставки реализовано с двумя скоростями — сразу после нажатия на кнопку уставка изменяется медленно, а при удержании кнопки дольше определённого времени — она начинает изменяться гораздо быстрее. (Пришлось сделать такую фишку, поскольку шагов много и тыкать 256 раз на кнопку или держать её 3 часа нажатой — довольно утомительно).

Больше в общем-то никаких наворотов, типа управления от ИК-пульта или передачи данных по интерфейсу, в проге нет, поскольку это всего лишь простейший тестовый вариант, поэтому перейдём сразу к алгоритму и программе.

Для того, чтобы определить что нужно и чего не нужно делать программе в текущем цикле — нам понадобятся три флага, под которые мы выделим специальный регистр (flags). Установленный нулевой бит этого регистра будет говорить о том, что мы находимся в режиме изменения задания, установленный первый бит — о том, что выходное напряжение не равно уставке и его нужно корректировать, установленный второй бит — о том, что мы держим кнопку уже достаточно долго и уставку нужно менять с повышенной скоростью.

Алгоритм:

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

Текст программы под катом

.device ATtiny13
.include "tn13def.inc"
.list
;-- определяем свои переменные
.def     w=r16        ; это будет наш аккумулятор
.def     setup=r17    ; это задание
.def     current=r18  ; здесь текущее значение ширины импульсов
.def     maximum=r19  ; максимальное значение
.def     minimum=r20  ; минимальное значение
.def     flags=r21    ; флаги
;(0-идёт изменение задания, 1-выход не равен уставке, 2 - slow/fast)
.def     setup_counter=r22   ; счётчики для паузы между опросом кнопок
.def     setup_counter2=r23
.def     setup_counter3=r24
.def     output_counter=r25  ; счётчики для паузы между изменениями выхода
.def     output_counter2=r26
.def     counter_sch=r27     ; cчётчик для определения удержания кнопок
;--------------------------
.equ     slow_setup=5     ; задержка на изменение уставки медленная
.equ     fast_setup=1     ; задержка на изменение уставки быстрая
.equ     output_time=1    ; задержка на изменение выхода
.equ     s_maximum=238    ; начальное ограничение максимального выхода
.equ     s_minimum=24     ; начальное ограничение минимального выхода
.equ     s_setup=128      ; начальное значение уставки
;--- Используемые выходы
; PB0 - выход ШИМ, PB1 - вход КН2, PB2- вход КН1, PB3 - выход, PB4 - вход
;--- начало программного кода
.cseg
.org 0
rjmp Init  ; переход на начало программы
;-- вектора прерываний
reti       ; INT0
rjmp Pch   ; Pin Change
reti       ; Timer
reti       ; EEPROM
reti       ; comparator
reti       ; timer compare match A
reti       ; timer compare match B
reti       ; watchdog
reti       ; ADC
;-- начало программы
Init:  ldi w,RAMEND     ; устанавливаем указатель вершины
out SPL,w        ; стека на старший байт RAM
sbi ACSR,7       ; выключаем компаратор
ldi w,0b00001001 ; определяем входы и выходы порта (1-выход, 0-вход)
out DDRB,w
ldi w,0b11100110 ; включаем подтягивающие резисторы
out PORTB,w      ; и определяем начальное состояние выходов
;-- записываем начальные значения
ldi maximum,s_maximum
ldi minimum,s_minimum
ldi setup,s_setup    ; ставим начальное задание
ldi output_counter,255
ldi output_counter2,output_time
;-- включаем ШИМ на выходе PB0 (OC0A)
ldi w,128        ; записываем начальную ширину импульсов
out OCR0A,w
ldi w,0b10000011 ; fastPWM, set at TOP, clear at compare
out TCCR0A,w
ldi w,0b00000001 ; fastPWM, no_prescale
out TCCR0B,w
;-- разрешить прерывание от входов
ldi w,0b00100000
out GIMSK,w      ; разрешаем прерывание от входов
;-- разрешить прерывания на входах PB1, PB2
Start: ldi w,0b00100000
out GIFR,w       ; сбросить флаг прерываний от входов
ldi w,0b00000110
out PCMSK,w      ; разрешаем прерывания на входах PB2, PB1
sei              ; разрешить глобальные прерывания
 
;----------------------------------------------------------------------
Scan:  sbrc flags,0     ; если флаг сброшен - пропускаем команду
rcall Setup_update
sbrc flags,1     ; если флаг сброшен - выход не нужно изменять
rcall Change_output
rjmp Scan
 
;--- Меняем выход ---------------
Change_output:
dec output_counter
brne End_cho          ; если не отсчитали нужный интервал - прыгаем
ldi output_counter,255
dec output_counter2
brne End_cho          ; если не отсчитали нужный интервал - прыгаем
;--- Отсчитали время, через которое можно менять выход
in current,OCR0A      ; читаем текущее установленное значение
cp current,setup      ; current - setup
breq Equal            ; текущее значение равно уставке
brcc SetupIsLower; если переноса не было - setup меньше
SetupIsHigher:
inc current           ; увеличиваем
out OCR0A,current     ; устанавливаем новое значение
rjmp Exit
SetupIsLower:
dec current
out OCR0A,current     ; пишем новое значение
rjmp Exit
Equal: cbr flags,0b00000010  ; выход равен уставке, сбрасываем флаг
rjmp End_cho          ; и выходим
Exit:  ldi output_counter,255
ldi output_counter2,output_time
End_cho:
ret
 
;--- Меняем уставку -----------
Setup_update:
dec  setup_counter
brne End_chs   ; если счётчик не отсчитал интервал - прыгаем
ldi  setup_counter,255
dec  setup_counter2
brne End_chs   ; если счётчик не отсчитал интервал - прыгаем
ldi  setup_counter2,255
dec  setup_counter3
brne End_chs   ; если счётчик не отсчитал интервал - прыгаем
Setup_change:
sbis PINB,1    ; если первая кнопка не нажата - пропустить
rjmp Dec_setup
sbis PINB,2    ; если вторая кнопка не нажата - пропустить
rjmp Inc_setup
cbr  flags,0b00000001 ; отменяем изменение задания
rjmp End_chs
Dec_setup:
dec setup
cp  setup,minimum
brlo SetMin    ; если новое задание меньше минимального - ставим минимум
rjmp ExitSetup
SetMin: mov setup,minimum
rjmp ExitSetup
Inc_Setup:
inc setup
cp maximum,setup
brlo SetMax    ; если максимум меньше нового задания - ставим максимум
rjmp ExitSetup
SetMax: mov setup,maximum
ExitSetup:
sbr flags,0b00000010   ; выход нужно изменить
ldi setup_counter, 255 ; готовимся отсчитывать
ldi setup_counter2,255 ; следующий интервал
sbrc flags,2           ; если флаг поднят - fast режим
rjmp Fast_change
Slow_change:
inc  counter_sch       ; увеличиваем счётчик изменений задания
sbrc counter_sch,2     ; если 2-й бит поднят - перекл. в быстрый режим
sbr  flags,0b00000100  ; fast change
ldi  setup_counter3,slow_setup
rjmp End_chs
Fast_change:
ldi setup_counter3,fast_setup
End_chs:
ret
 
;-- ОБРАБОТЧИК ПРЕРЫВАНИЯ ПО ВХОДУ
Pch:   sbr  flags,0b00000001  ; ставим флаг изменения задания
ldi  setup_counter,255
ldi  setup_counter2,1
ldi  setup_counter3,1
clr  counter_sch       ; обнуляем счётчик изменений
cbr  flags,0b00000100  ; slow change
reti                   ; и выходим

[свернуть]

Вот и вся программа. Чтобы всё корректно работало — в контроллере должны быть «запрограммированы» фьюзы SPIEN, SUT0 и CKSEL0 (то есть в PonyProg напротив них должны стоять галочки).

Скачать одним архивом алгоритм, исходники и прошивку

Добавить комментарий