Последний раз редактировалось _Ivana 18.12.2012, 20:32, всего редактировалось 3 раз(а).
Берем число (например, двухбайтовое целое), пока оно больше 10000 - вычитаем из него 10000, считаем сколько раз вычли в отдельном регистре. Прибавляем к значению регистра счетчика код символа "0" - получаем код символа нужной цифры текущего десятичного разряда - шлем его по USART на комп где в любой терминальной программе он выводится как десятичная цифра. Далее - в исходных регистрах у нас остался остаток меньше 10000 - начинаем вычитать из него 1000 и действуем по тому уже алгоритму. (Оффтоп)
Код: .include "Tn13def.inc"
; функции ножек
.equ _PIN_PC_OUT = PB2 ; 7 - й PIN - вывод данных на комп .equ _PIN_RELE_OUT1 = PB3 ; 2 - й PIN - выход на обмотку 1 .equ _PIN_RELE_OUT2 = PB1 ; 6 - й PIN - выход на обмотку 2 .equ _PIN_RELE_IN1 = PB4 ; 3 - й PIN - вход контакта 1 .equ _PIN_RELE_IN2 = PB0 ; 5 - й PIN - вход контакта 2
; регистры общего назначения
.def _r_mom = r16 ; служебный регистр для записи в порты .def _r_WAIT = r17
.def _r_count_measure_sets = r18 .def _r_transmit_data = r19
.def _r_t1_lb = r20 .def _r_t1_hb = r21 .def _r_t1_last_lb = r22 .def _r_t1_last_hb = r23 .def _r_t2_lb = r24 .def _r_t2_hb = r25 .def _r_t2_last_lb = r26 .def _r_t2_last_hb = r27
.def _r_count_measure_time_lb = r28 .def _r_count_measure_time_hb = r29
; переменные
.equ _one_measure_time = 96 ; тактов = 10us - дискретность измерения
.equ _max_measure_time = 3000 ; циклов по 10us = 30ms - интервал измерения
.equ _sets_of_measures = 10 ; количество измерений (1 измерение = туда + обратно)
;.equ _RS232_time = 1000 ; тактов бита RS232 для скорости 9600 бод .equ _RS232_time = 250 ; тактов бита RS232 для скорости 38400 бод
; для десятичной системы исчисления
.equ _SI_order = 10 ; для десятичной системы исчисления при выводе результатов ;.equ _max_length_SI = 5 ; макс. разрядность чисел в _SI_order
.equ _SI_order_0 = 1 .equ _SI_order_1 = _SI_order .equ _SI_order_2 = _SI_order_1*_SI_order_1 .equ _SI_order_3 = _SI_order_2*_SI_order_1 .equ _SI_order_4 = _SI_order_3*_SI_order_1
; нужные коды KOI_8
.equ KOI_8_comma = $2C ; код "," .equ KOI_8_semicolon = $3B ; код ";" .equ KOI_8_ps = $0A ; код "перевод строки" .equ KOI_8_vk = $0D ; код "возврат каретки"
;--------------------------------------------------------------------
rjmp RESET ; Reset Handler reti ;rjmp EXT_INT0 ; IRQ0 Handler reti ;rjmp PIN_CHANGE ; PCINT0 Handler reti ;rjmp TIM0_OVF ; Timer0 Overflow Handler reti ;rjmp EE_RDY ; EEPROM Ready Handler reti ;rjmp ANA_COMP ; Analog Comparator Handler reti ;rjmp TIM0_COMPA ; Timer0 CompareA Handler reti ;rjmp TIM0_COMPB ; Timer0 CompareB Handler reti ;rjmp WATCHDOG ; Watchdog Interrupt Handler reti ;rjmp ADCCONV ; ADC Conversion Handler ;--------------------------------------------------------------------
RESET:
ldi _r_mom, (1<<_PIN_RELE_OUT1) + (1<<_PIN_RELE_OUT2) + (1<<_PIN_PC_OUT) out DDRB, _r_mom ; пины выходов
ldi _r_mom, (1<<_PIN_RELE_IN1) + (1<<_PIN_RELE_IN2) out PORTB, _r_mom ; подтягиваюие резисторы на входы
; ldi _r_mom, (1<<_PIN_RELE_IN1) + (1<<_PIN_RELE_IN2) + (1<<_PIN_RELE_OUT1) + (1<<_PIN_RELE_OUT2) ; out PCMSK, _r_mom ; маска пинов для прерываний по pin change
rjmp MAIN ;-------------------------------------------------------------------- ; прерывание по изменению состояния выводов
;PIN_CHANGE:
; clr _r_mom ; out GIMSK, _r_mom
; reti ;--------------------------------------------------------------------
WAIT_Idle:
; для относительно длинных пауз ; ждем в состоянии Idle ПРИМЕРНО _r_WAIT / 37.5 секунд
cli
; clr _r_mom ; out GIMSK, _r_mom
in _r_mom, MCUCR cbr _r_mom, (1<<SM0) + (1<<SM1) sbr _r_mom, (1<<SE) ;ldi _r_mom, (0<<ISC00) + (0<<ISC01) + (0<<SM0) + (0<<SM1) + (1<<SE) + (0<<PUD) out MCUCR, _r_mom ; задаем режим sleep-а Idle и устанавливаем флаг его разрешения
ldi _r_mom, 250 out OCR0A, _r_mom ; значение счетчика таймера для прерывания clr _r_mom out TCNT0, _r_mom ; сброс счетчика таймера ldi _r_mom, (1<<OCIE0A) out TIMSK0, _r_mom ; разрешаем прерывание по счетчику таймера ldi _r_mom, (1<<CS02) + (0<<CS01) + (1<<CS00) out TCCR0B, _r_mom ; запускаем таймер с частотой СК/1024
sei
WAIT_Idle_sleep:
sleep ; Idle
clr _r_mom out TCNT0, _r_mom ; сброс счетчика таймера
dec _r_WAIT brne WAIT_Idle_sleep
cli in _r_mom, MCUCR cbr _r_mom, (1<<SE) out MCUCR, _r_mom ; сбрасываем флаг разрешения sleep-а
clr _r_mom out TIMSK0, _r_mom ; запрещаем прерывание по счетчику таймера out TCCR0B, _r_mom ; останавливаем таймер out OCR0A, _r_mom ; нулевое значение счетчика таймера для прерывания out TCNT0, _r_mom ; сброс счетчика таймера
ret ;;-------------------------------------------------------------------- ; ;EEPROM_write: ; ; sbic EECR, EEPE ; rjmp EEPROM_write ; ; ; Set Programming mode ; ldi _r_mom, (0<<EEPM1)|(0<<EEPM0) ; out EECR, _r_mom ; ; out EEARL, _r_EEPROM_address ; out EEDR, _r_EEPROM_data ; sbi EECR, EEMPE ; sbi EECR, EEPE ; ret ;;-------------------------------------------------------------------- ; ;EEPROM_read: ; ; sbic EECR, EEPE ; rjmp EEPROM_read ; out EEARL, _r_EEPROM_address ; sbi EECR, EERE ; in _r_EEPROM_data, EEDR ; ret ;;--------------------------------------------------------------------
DECIMAL_value_KOI_8:
; _r_t1_hb:_r_t1_lb - остаток от числа, _SI_order-ичный разряд которого надо получить ; _r_count_measure_time_hb:_r_count_measure_time_lb - число _SI_order в нужной степени ; результат - в _r_transmit_data (и уже +$30 к цифре для получения её кода KOI-8)
clr _r_transmit_data
DECIMAL_value_KOI_8_1:
cp _r_t1_lb, _r_count_measure_time_lb cpc _r_t1_hb, _r_count_measure_time_hb brlo DECIMAL_value_KOI_8_END sub _r_t1_lb, _r_count_measure_time_lb sbc _r_t1_hb, _r_count_measure_time_hb inc _r_transmit_data rjmp DECIMAL_value_KOI_8_1
DECIMAL_value_KOI_8_END:
ldi _r_mom, $30 ; свиг для кода KOI-8 цифры add _r_transmit_data, _r_mom
ret ;--------------------------------------------------------------------
PAUSE_RS232:
; _RS232_time - 13 (тактов на операции при передаче) - 5 (вызов rcall) - 2 (ret) ; итог / 5 (тактов каждого цикла) = в счетчик
ldi _r_mom, (_RS232_time - 13 - 5 - 2) / 5;
PAUSE_RS232_Count:
dec _r_mom nop nop brne PAUSE_RS232_Count
ret ;--------------------------------------------------------------------
DATA_transmit_RS232:
; содержимое _r_transmit_data - на комп по RS232
cli
; отправляем посылку RS232 ; 13 тактов операций после каждого бита + (_RS232_time - 9) тактов паузы
cbi PORTB, _PIN_PC_OUT ; старт-бит, до сего момента у нас была 1-ца и долго rcall PAUSE_RS232 nop nop nop nop nop nop
; 8 бит данных и 2 стоп бита = 10 бит ; для посылки их в одном цикле инвертируем байт даннных ; и будем посылать инвертированные биты - 2 стоп бита получатся ; как инвертированные нули при логическом сдвиге вправо :)
com _r_transmit_data ldi _r_WAIT, 10
DATA_transmit_RS232_DATA_BITS:
sbrc _r_transmit_data, 0 cbi PORTB, _PIN_PC_OUT sbrs _r_transmit_data, 0 sbi PORTB, _PIN_PC_OUT
rcall PAUSE_RS232 nop nop nop nop
lsr _r_transmit_data dec _r_WAIT brne DATA_transmit_RS232_DATA_BITS
; по хорошему, надо было запомнить флаг прерывания в начале процедуры ; и вернуть его такой же в конце. Но мы не будем возвращать ; - по умолчанию живем без прерываний, если надо - выставим когда надо ;sei
ret ;--------------------------------------------------------------------
VALUE_transmit_RS232:
;_r_t1_hb:_r_t1_lb - на комп по RS232 в десятичной системе с запятой ;_r_count_measure_time_hb:_r_count_measure_time_lb - _SI_order ;_r_transmit_data - который потом шлем на комп по RS232
ldi _r_count_measure_time_lb, low(_SI_order_4) ldi _r_count_measure_time_hb, high(_SI_order_4) rcall DECIMAL_value_KOI_8 rcall DATA_transmit_RS232
ldi _r_count_measure_time_lb, low(_SI_order_3) ldi _r_count_measure_time_hb, high(_SI_order_3) rcall DECIMAL_value_KOI_8 rcall DATA_transmit_RS232
ldi _r_count_measure_time_lb, low(_SI_order_2) ldi _r_count_measure_time_hb, high(_SI_order_2) rcall DECIMAL_value_KOI_8 rcall DATA_transmit_RS232
; запятая ldi _r_transmit_data, KOI_8_comma rcall DATA_transmit_RS232
ldi _r_count_measure_time_lb, low(_SI_order_1) ldi _r_count_measure_time_hb, high(_SI_order_1) rcall DECIMAL_value_KOI_8 rcall DATA_transmit_RS232
ldi _r_count_measure_time_lb, low(_SI_order_0) ldi _r_count_measure_time_hb, high(_SI_order_0) rcall DECIMAL_value_KOI_8 rcall DATA_transmit_RS232
ret ;--------------------------------------------------------------------
MEASURE_transmit_RS232:
; вынес в процедуру ИСКЛЮЧИТЕЛЬНО из-за ограничения количества строк перехода!
;_r_t1_hb:_r_t1_lb - на комп по RS232 в десятичной системе с запятой ;_r_count_measure_time_hb:_r_count_measure_time_lb - _SI_order ;_r_transmit_data - который потом шлем на комп по RS232
; сначала рассчитаем и приготовим все нужные рагистры для передачи ; а потом уже передадим - при передаче они корежатся :)
; расчет и запись ti_last как разница ti_lastт - ti
cp _r_t1_last_lb, _r_t1_lb cpc _r_t1_last_hb, _r_t1_hb brlo _clr_r_t1_last sub _r_t1_last_lb, _r_t1_lb sbc _r_t1_last_hb, _r_t1_hb rjmp _calc_r_t1_last_end _clr_r_t1_last: clr _r_t1_last_lb clr _r_t1_last_hb _calc_r_t1_last_end:
cp _r_t2_last_lb, _r_t2_lb cpc _r_t2_last_hb, _r_t2_hb brlo _clr_r_t2_last sub _r_t2_last_lb, _r_t2_lb sbc _r_t2_last_hb, _r_t2_hb rjmp _calc_r_t2_last_end _clr_r_t2_last: clr _r_t2_last_lb clr _r_t2_last_hb _calc_r_t2_last_end:
; тут в _r_t1_hb:_r_t1_lb уже нужное число для передачи - ничего не делаем
rcall VALUE_transmit_RS232 ldi _r_transmit_data, KOI_8_semicolon rcall DATA_transmit_RS232 ; символ ";"
mov _r_t1_lb, _r_t1_last_lb mov _r_t1_hb, _r_t1_last_hb rcall VALUE_transmit_RS232 ldi _r_transmit_data, KOI_8_semicolon rcall DATA_transmit_RS232 ; символ ";"
mov _r_t1_lb, _r_t2_lb mov _r_t1_hb, _r_t2_hb rcall VALUE_transmit_RS232 ldi _r_transmit_data, KOI_8_semicolon rcall DATA_transmit_RS232 ; символ ";"
mov _r_t1_lb, _r_t2_last_lb mov _r_t1_hb, _r_t2_last_hb rcall VALUE_transmit_RS232
; счетчик измерений считает от 0 вверх ; если он четный - в конце передаем ";", иначе переход на новую строку
sbrc _r_count_measure_sets, 0 rjmp MEASURE_transmit_RS232_SEND_TO_PC_new_line ldi _r_transmit_data, KOI_8_semicolon rcall DATA_transmit_RS232 ; символ ";"
rjmp MEASURE_transmit_RS232_END
MEASURE_transmit_RS232_SEND_TO_PC_new_line:
ldi _r_transmit_data, KOI_8_ps rcall DATA_transmit_RS232 ldi _r_transmit_data, KOI_8_vk rcall DATA_transmit_RS232 ; переход на новую строку
MEASURE_transmit_RS232_END:
ret ;--------------------------------------------------------------------
INITIALIZE_MEASURE:
; вынес в процедуру ИСКЛЮЧИТЕЛЬНО из-за ограничения количества строк перехода!
clr _r_count_measure_time_lb clr _r_count_measure_time_hb
ser _r_t1_lb ser _r_t1_hb ser _r_t2_lb ser _r_t2_hb
; используем тут _r_transmit_data для начального состояния входов in _r_transmit_data, PINB
in _r_mom, MCUCR cbr _r_mom, (1<<SM0) + (1<<SM1) sbr _r_mom, (1<<SE) out MCUCR, _r_mom ; задаем режим sleep-а Idle и устанавливаем флаг его разрешения
ldi _r_mom, _one_measure_time - 1 - 8 - 4 - 8 out OCR0A, _r_mom ; значение счетчика таймера для прерывания ; 1 - на установку флага прерывания ; 8 - на переход на адрес вектора прерывания ; 4 - на reti с адреса вектора прерывания ; 8 = 2 на сброс счетчика таймера + 6 на проверку условия цикла clr _r_mom out TCNT0, _r_mom ; сброс счетчика таймера ldi _r_mom, (1<<OCIE0A) out TIMSK0, _r_mom ; разрешаем прерывание по счетчику таймера ldi _r_mom, (0<<CS02) + (0<<CS01) + (1<<CS00) out TCCR0B, _r_mom ; запускаем таймер с частотой СК
sei
ret ;--------------------------------------------------------------------
MAIN:
cbi PORTB, _PIN_RELE_OUT1 cbi PORTB, _PIN_RELE_OUT2 sbi PORTB, _PIN_PC_OUT ; инициализируем передачу на комп
; ldi _r_mom, (1<<PCIE) ; out GIMSK, _r_mom ; разрешаем прерыванияпо изменению состояния выводов
; in _r_mom, MCUCR ; cbr _r_mom, (1<<SM0) ; sbr _r_mom, (1<<SM1) + (1<<SE) ; ;ldi _r_mom, (0<<ISC00) + (0<<ISC01) + (0<<SM0) + (0<<SM1) + (1<<SE) + (0<<PUD) ; out MCUCR, _r_mom ; задаем режим sleep-а Power-down и устанавливаем флаг его разрешения
; sei
; sleep ; Power-down
; тут проснемся от прерывания PIN_CHANGE ldi _r_WAIT, 20 ; 37.5 Гц rcall WAIT_Idle ; ждать 1s
; инициализировать контакты реле
sbi PORTB, _PIN_RELE_OUT2
ldi _r_WAIT, 6 ; 37.5 Гц rcall WAIT_Idle ; ждать 250ms
cbi PORTB, _PIN_RELE_OUT2
ldi _r_WAIT, 6 ; 37.5 Гц rcall WAIT_Idle ; ждать 250ms
; провести серию измерений, записывая результаты каждого в EEPROM
clr _r_count_measure_sets
SET_OF_MEASURES:
rcall INITIALIZE_MEASURE
; команда на переключение - инвертируем _PIN_RELE_OUT1 ldi _r_WAIT, (1<<_PIN_RELE_OUT1) in _r_mom, PORTB eor _r_mom, _r_WAIT out PORTB, _r_mom
; измеряем t1 и t2
MEASURE: ; опрос пинов строго раз в 10us = 96 тактов ; таких опросов строго до достижения _max_measure_time clr _r_mom out TCNT0, _r_mom ; сброс счетчика таймера
; тут у нас есть на все наши операции максимум 96 - 1 - 8 - 4 - 8 = 75 тактов!
; ldi _r_mom, 25 ;a3: dec _r_mom ; brne a3 ; ; 75 тактов ; ;nop ; ;nop ; nop
ldi _r_mom, 1 clr _r_WAIT add _r_count_measure_time_lb, _r_mom adc _r_count_measure_time_hb, _r_WAIT ; инкремент счетчика
; манипуляции с _r_mom, после которых в битах _PIN_RELE_IN1 и _PIN_RELE_IN2 ; будут 1-цы только если текущие значения не равны начальным из _r_transmit_data in _r_mom, PINB eor _r_mom, _r_transmit_data
; старшие байты _r_t1_hb и _r_t2_hb изначально забиты 1-цами ; а после занесения в них значений измерения - гарантированно меньше, ; т.к. максимальное значение у нас будет 3000 а возможное - 65536
cpi _r_t1_hb, 255 brne MEASURE_t1_END ; пропускаем если _r_t1_hb <> 255 - уже заполнили
sbrs _r_mom, _PIN_RELE_IN1 rjmp MEASURE_t1_END ; пропускаем если состояние не изменилось
mov _r_t1_lb, _r_count_measure_time_lb mov _r_t1_hb, _r_count_measure_time_hb
MEASURE_t1_END:
cpi _r_t2_hb, 255 brne MEASURE_t2_END ; пропускаем если _r_t2_hb <> 255 - уже заполнили
sbrs _r_mom, _PIN_RELE_IN2 rjmp MEASURE_t2_END ; пропускаем если состояние не изменилось
mov _r_t2_lb, _r_count_measure_time_lb mov _r_t2_hb, _r_count_measure_time_hb
MEASURE_t2_END:
; каждый цикл записываем тек. время если состояние вывода РАВНО исходному ; - так отследим время окончания дребезга
sbrc _r_mom, _PIN_RELE_IN1 rjmp MEASURE_t1_last_END ; пропускаем если состояние изменилось
mov _r_t1_last_lb, _r_count_measure_time_lb mov _r_t1_last_hb, _r_count_measure_time_hb
MEASURE_t1_last_END:
sbrc _r_mom, _PIN_RELE_IN2 rjmp MEASURE_t2_last_END ; пропускаем если состояние изменилось
mov _r_t2_last_lb, _r_count_measure_time_lb mov _r_t2_last_hb, _r_count_measure_time_hb
MEASURE_t2_last_END:
; заняли максимум 40 тактов
sleep
ldi _r_mom, low(_max_measure_time) ldi _r_WAIT, high(_max_measure_time) cp _r_count_measure_time_lb, _r_mom cpc _r_count_measure_time_hb, _r_WAIT brlo MEASURE ; прошли _max_measure_time - сделали очередное измерение cli
in _r_mom, MCUCR cbr _r_mom, (1<<SE) out MCUCR, _r_mom ; сбрасываем флаг разрешения sleep-а
clr _r_mom out TCCR0B, _r_mom ; останавливаем таймер out TCNT0, _r_mom ; сброс счетчика таймера
ldi _r_WAIT, 6 ; 37.5 Гц rcall WAIT_Idle ; ждать 250ms ; команда на исходное положение - инвертируем _PIN_RELE_OUT2 ldi _r_WAIT, (1<<_PIN_RELE_OUT2) in _r_mom, PORTB eor _r_mom, _r_WAIT out PORTB, _r_mom
; передать результаты на комп rcall MEASURE_transmit_RS232 ldi _r_WAIT, 6 ; 37.5 Гц rcall WAIT_Idle ; ждать 250ms ; если ещё не все измерения сделаны (а одно измерение - это сначала туда а потом обратно) ; то сделаем ещё измерение inc _r_count_measure_sets cpi _r_count_measure_sets, 2*_sets_of_measures brlo SET_OF_MEASURES ; провели серию измерений и передали результаты на комп - ; готовы к новой серии измерений (на старт и PowerDown)
;rjmp MAIN
; нет - тут падаем в Power-down без права прерывания и ждем RESET :)))
SLEEP_Power_down:
cli
in _r_mom, MCUCR cbr _r_mom, (1<<SM0) sbr _r_mom, (1<<SM1) + (1<<SE) ;ldi _r_mom, (0<<ISC00) + (0<<ISC01) + (0<<SM0) + (0<<SM1) + (1<<SE) + (0<<PUD) out MCUCR, _r_mom ; задаем режим sleep-а Power-down и устанавливаем флаг его разрешения
sleep ; Power-down
rjmp SLEEP_Power_down
|