Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ;====================================================================
- ; Main.asm file generated by New Project wizard
- ;
- ; Created: Вт окт 25 2016
- ; Processor: ATmega8535
- ; Compiler: AVRASM (Proteus)
- ;====================================================================
- ;====================================================================
- ; DEFINITIONS
- ;====================================================================
- ;====================================================================
- ; VARIABLES
- ;====================================================================
- .DSEG
- .equ XTAL = 8000000 ; частота ОМК
- .equ baudrate = 4800 ; скорость передачи в RS-485
- .equ bauddivider = XTAL/(16*baudrate) - 1
- ; Адрес результата
- .equ resAddrL = $70
- .equ resAddrH = 0
- ; Адрес посчитанной нормальной частоты
- .equ buffAddrL = $0A0
- .equ buffAddrH = 0
- .def A = r2
- .def B = r3
- .def Ql = r4
- .def Qh = r5
- .def Qdopl = r6
- .def Qdoph = r7
- .def tmp0 = r6 ; множимое мл. байт
- .def tmp1 = r7 ; множимле ст. байт
- .def tmp2 = r8 ; множитель мл. байт
- .def tmp3 = r9 ; множитель ст. байт
- ; частное деления 32 на 32 или произведение 16 на 16
- .def res1 = r10
- .def res2 = r11
- .def res3 = r12
- .def res4 = r13
- ; остаток от деления 32 на 32
- .def res5 = r17
- .def res6 = r18
- .def res7 = r19
- .def res8 = r20
- .def AAddr = r14 ; Адрес константы А
- .def BAddr = r15 ; Адрес константы B
- .def NdopAddr = r23 ; Адрес константы N допустимая
- .def SensorAddr = r24 ; Адрес датчика
- .def Index = r25 ; Номер ветви
- ;====================================================================
- ; RESET and INTERRUPT VECTORS
- ;====================================================================
- .CSEG
- ; Reset Vector
- rjmp Start
- .org $01 rjmp INT0Handler
- .org $02 rjmp INT1Handler
- .org $08 rjmp TOV1Handler
- ;====================================================================
- ; CODE SEGMENT
- ;====================================================================
- .org $80
- QdopAddr: .db $06, $36
- .org $82
- StartNdop: .db $14, $0A, $0A, $0A
- .org $86
- StartA: .db $03, $03, $01, $01, $01, $01, $01, $01
- .org $8E
- StartB: .db $5A, $5A, $5A, $5A, $5A, $5A, $5A, $5A
- Start:
- ; Инициализация стека
- ldi r16, high(ramend)
- out sph, r16
- ldi r16, low(ramend)
- out spl, r16
- ; Разрешение прерываний INT0 и INT1
- ldi r16, $0C0
- out gicr, r16
- ldi r16, $0A
- out mcucr, r16
- clr r16
- out gifr, r16
- ; Настраиваем порт на вывод
- ldi r16, $0FF
- out DDRA, r16
- ldi r16, $0C0
- out PORTA, r16
- ; Разрешаем прерывания
- sei
- rjmp Loop
- ; Накапливаем переполнения таймера T1
- TOV1Handler:
- in r16, sreg
- push r16
- inc r3
- pop r16
- out sreg, r16
- reti
- TOV0Handler:
- brts clrBit
- rjmp setBit
- rjmp clrBit
- clrBit:
- clt
- rjmp finish
- setBit:
- set
- finish:
- reti
- ; По приходу запроса INT0 подготавливаем
- ; ресурсы и запускаем алгоритм подсчета Q
- INT0Handler:
- in r16, sreg
- push r16
- rcall init_task
- rcall DoTask
- pop r16
- out sreg, r16
- reti
- ; По приходу запроса INT1 подготавливаем
- ; ресурсы и запускаем алгоритм передачи данных
- INT1Handler:
- in r16, sreg
- push r16
- wait_task_end:
- sbrs r19, 0
- rjmp wait_task_end
- ldi yl, resAddrL
- ldi yh, resAddrH
- rcall Transmit
- pop r16
- out sreg, r16
- reti
- ; Подготавливаем ресурсы
- ; для подсчета Q
- init_task:
- in r16, sreg
- push r16
- clr r16
- out PORTA, r16
- ldi NdopAddr, StartNdop
- clr SensorAddr
- ldi yl, resAddrL
- ldi yh, resAddrH
- ldi xl, buffAddrL
- ldi xh, buffAddrH
- clr r18
- out PORTA, r18
- clr Index
- pop r16
- out sreg, r16
- ret
- mul16x16_32:
- in r16, sreg
- push r16
- push r20
- push tmp0
- push tmp1
- push tmp2
- push tmp3
- ; Очистка результата
- clr res1
- clr res2
- clr res3
- clr res4
- ; Умножение
- clr r20
- mul tmp0, tmp2
- movw res1, r0
- mul tmp1, tmp3
- movw res3, r0
- mul tmp1, tmp2
- add res2, r0
- adc res3, r1
- adc res4, r20
- mul tmp0, tmp3
- add res2, r0
- adc res3, r1
- adc res4, r20
- pop tmp3
- pop tmp2
- pop tmp1
- pop tmp0
- pop r20
- pop r16
- out sreg, r16
- ret
- ; ------------------------------------------------------------------------------
- ; Деление двойного слова на двойное слово (32 / 32 -> 32.32) ///////////////////
- ; ------------------------------------------------------------------------------
- ; --> res1, res2 -- делимое младшие два байта,
- ; res3, res4 -- делимое старшие два байта;
- ; tmp0, tmp1 -- делитель младшие два байта,
- ; tmp2, tmp3 -- делитель старшие два байта;
- ; <-- res1, res2 -- частное младшие два байта,
- ; res3, res4 -- частное старшие два байта;
- ; res5, res6 -- остаток младшие два байта,
- ; res7, res8 -- остаток старшие два байта.
- div32to32:
- in r16, sreg
- push r16
- ldi r16, 33 ; Количество разрядов + бит C
- clr res5 ; Остаток мл.слово мл.байт
- clr res6 ; Остаток мл.слово ст.байт
- clr res7 ; Остаток ст.слово мл.байт
- clr res8 ; Остаток ст.слово ст.байт
- clc
- S_Div_DWordDWord_Loop:
- rol res5
- rol res6
- rol res7
- rol res8
- sub res5, tmp0 ; Остаток минус делитель
- sbc res6, tmp1
- sbc res7, tmp2
- sbc res8, tmp3
- brcc S_Div_DWordDWord_1
- add res5, tmp0
- adc res6, tmp1
- adc res7, tmp2
- adc res8, tmp3
- S_Div_DWordDWord_1:
- rol res1
- rol res2
- rol res3
- rol res4
- dec r16
- brne S_Div_DWordDWord_Loop
- com res1
- com res2
- com res3
- com res4
- pop r16
- out sreg, r16
- ret
- ; Подпрограмма подсчета расхода топлива
- DoTask:
- in r16, sreg
- push r16
- push r17
- ; Считаем Q12
- rcall calculateQ
- ; Загружаем константу Qдоп
- ldi zl, low(QdopAddr << 1)
- ldi zh, high(QdopAddr << 1)
- lpm r7, Z+
- lpm r6, Z
- ; Вычислим 1/3Qдоп
- devideQdopBy3:
- mov tmp0, r6 ; Загружаем мл. байт Qdop
- mov tmp1, r7 ; Загружаем ст. байт Qdop
- ldi r16, low(0x5555)
- mov tmp2, r16 ; Загружаем мл. байт константы 21845
- ldi r16, high(0x5555)
- mov tmp3, r16 ; Загружаем ст. байт константы 21845
- rcall mul16x16_32 ; Умножаем
- ; Старшие 2 байты и есть результат деления на 3
- mov Qdopl,res3
- mov Qdoph,res4
- check1:
- ; Проверка
- sub Qh, Qdoph
- brsh check2 ; Если Qh >= Qdoph/3, идем к след. условию
- rjmp includePipe1 ; Иначе включаем только 1 ветвь
- check2:
- add Qh, Qdoph ; Восстанваливаем Q
- ; Умножаем Qдоп на 2
- rol Qdopl
- rol Qdoph
- ; Проверка
- sub Qh, Qdoph
- brsh includePipe123 ; Если Qh >= 2*Qdoph/3, включаем все ветви
- rjmp includePipe12 ; Иначе включаем только 2 ветви
- includePipe1:
- ; Включаем 1 индикатор
- in r16, PINA
- ldi r17, (0 << 5)|(0 << 4)|(1 << 3)
- add r16, r17
- out PORTA, r16
- ; Увеличиваем адрес канала(ветви)
- inc Index
- inc Index
- ; Увеличиваем адрес константы N допустимой
- inc NdopAddr
- ; Считаем расход топлива в ветви
- rcall calculateQ
- ; Сохраняем результат в буфер
- st Y+, Ql
- st Y+, Qh
- clr r16
- st Y+, r16
- st Y, r16
- rjmp endTask
- includePipe12:
- ; Включаем 2 индикатора
- in r16, PINA
- ldi r17, (0 << 5)|(1 << 4)|(1 << 3)
- add r16, r17
- out PORTA, r16
- ; Увеличиваем адрес канала(ветви)
- inc Index
- inc Index
- ; Увеличиваем адрес константы N допустимой
- inc NdopAddr
- ; Считаем расход топлива в ветви
- rcall calculateQ
- ; Записываем Q в r6, r7 для последующего суммирования
- mov r6, Ql
- mov r7, Qh
- ; Увеличиваем адрес канала(ветви)
- inc Index
- inc Index
- ; Увеличиваем адрес константы N допустимой
- inc NdopAddr
- ; Считаем расход топлива в ветви
- rcall calculateQ
- ; Q = Q34 + Q56
- clc
- add r6, Ql
- adc r7, Qh
- ; Сохраняем результат в буфер
- st Y+, r6
- st Y+, r7
- st Y+, r8
- clr r16
- st Y, r16
- rjmp endTask
- includePipe123:
- ; Включаем 3 индикатора
- in r16, PINA
- ldi r17, (1 << 5)|(1 << 4)|(1 << 3)
- add r16, r17
- out PORTA, r16
- ; Увеличиваем адрес канала(ветви)
- inc Index
- inc Index
- ; Увеличиваем адрес константы N допустимой
- inc NdopAddr
- ; Считаем расход топлива в ветви
- rcall calculateQ
- ; Записываем Q в r6, r7 для последующего суммирования
- mov r6, Ql
- mov r7, Qh
- ; Увеличиваем адрес канала(ветви)
- inc Index
- inc Index
- ; Увеличиваем адрес константы N допустимой
- inc NdopAddr
- ; Считаем расход топлива в ветви
- rcall calculateQ
- ; Q = Q34 + Q56
- clc
- add r6, Ql
- adc r7, Qh
- ; Увеличиваем адрес канала(ветви)
- inc Index
- inc Index
- ; Увеличиваем адрес константы N допустимой
- inc NdopAddr
- ; Считаем расход топлива в ветви
- rcall calculateQ
- ; Q = Q + Q78
- clc
- add r6, Ql
- adc r7, Qh
- ; Сохраняем результат в буфер
- st Y+, r6
- st Y+, r7
- st Y+, r8
- clr r16
- st Y, r16
- endTask:
- sbr r19, 1
- pop r17
- pop r16
- out sreg, r16
- ret
- ; Подпрограмма вычисления расхода
- ; топлива по 1 ветви
- calculateQ:
- in r16, sreg
- push r16
- push r18
- push zl
- push A
- push B
- push r6
- push r7
- rcall CalculateFreq ; Считываем частоты с датчиков
- in r16, PINA ; Считываем текущее состояние порта
- inc SensorAddr ; Увеличиваем адрес датчика
- cbr r16, $07 ; Очищаем младшие 3 бита,
- or r16, SensorAddr ; загружаем в эти 3 бита адрес датчика
- out PORTA, r16 ; и передаем в порт
- rcall CalculateFreq ; Считываем частоты с датчиков
- in r16, PINA
- clz ; Если дошли до последнего датчика,
- cpi SensorAddr, $07 ; мы не увеличиваем адрес
- breq next ; (чтобы индикаторы горели до след. нажатия)
- inc SensorAddr
- cbr r16, $07
- or r16, SensorAddr
- out PORTA, r16
- next:
- rcall GetNormFreq ; Вычисляем нормальную частоту
- ; (выходные параметры - r20, r21)
- ; Загружаем константу А
- ldi r16, low(StartA << 1)
- ldi zh, high(StartA << 1)
- add r16, Index
- mov zl, r16
- add zl, r19
- lpm A, Z
- ; Загружаем константу В
- ldi r16, low(StartB << 1)
- ldi zh, high(StartB << 1)
- add r16, Index
- mov zl, r16
- add zl, r19
- lpm B, Z+
- ; Q = A*N + B
- calculateQ12:
- ; r20 - мл. байт частоты
- ; r21 - ст. байт частоты
- ; Умножаем А на частоту
- mul A, r20
- mov Ql, r0
- mov r6, r1
- mul A, r21
- add r0, r6
- mov Qh, r0
- ; Прибавляем В
- clc
- add Ql, B
- clr r16
- adc Qh, r16
- pop r7
- pop r6
- pop B
- pop A
- pop zl
- pop r18
- pop r16
- out sreg, r16
- ret
- ; Инициализируем счетчики
- CT_init:
- in r16, sreg
- push r16
- clr r3 ; Очищаем регистр переполнений T1
- ldi r16, $04 ; Разрешаем прерывания по
- out timsk, r16 ; переполнению T1
- out tifr, r3 ; Сбрасываем флаги
- ldi r16, $0FF
- out tcnt0, r3
- out tccr1a, r3
- out tcnt1h, r3 ; Обнуляем счетчик T1
- out tcnt1l, r3
- pop r16
- out sreg, r16
- ret
- CalculateFreq:
- in r16, sreg
- push r16
- push r17
- push r18
- push r2
- cli
- rcall CT_init ; Инициализируем счетчики
- ldi r16, $07
- sei
- out tccr0, r16 ; Счет по фронту импульса
- ldi r16, $02 ; clk/8
- ;ldi r16, $01 ; clk
- waitStart:
- sbis PINB, 0
- rjmp waitStart
- out tccr1b, r16 ; Устанавливаем предделитель = 8
- waitEnd:
- sbic PINB, 0
- rjmp waitEnd
- waitNextStart:
- sbis PINB, 0
- rjmp waitNextStart
- clr r16
- out tccr1b, r16 ; Останавливаем таймер T1
- out tccr0, r16
- ; задание делимого(частота генератора) = 1MHz(0F4240h)
- ldi r16, $40
- mov res1, r16
- ldi r16, $42
- mov res2, r16
- ldi r16, $0F
- mov res3, r16
- clr res4
- ; задание делителя(тики таймера)
- in tmp0, tcnt1l
- in tmp1, tcnt1h
- mov tmp2, r3
- clr tmp3
- ; подсчет исходной частоты = (частота генератора)/(тики таймера)
- rcall div32to32
- ; Загружаем результат в буфер
- st X+, res1
- st X+, res2
- pop r2
- pop r18
- pop r17
- pop r16
- out sreg, r16
- ret
- GetNormFreq:
- in r16, sreg
- push r16
- push r15 ; мл. байт первой частоты
- push r14 ; ст. байт первой частоты
- push r13 ; мл. байт второй частоты
- push r12 ; ст. байт второй частоты
- push r17 ; номер канала
- push r18
- push r22 ; N допустимая
- push r0
- push zl
- push zh
- push yl
- push yh
- ; Загрузка Nдоп
- mov zl, NdopAddr
- clr zh
- rol zl
- rol zh
- lpm r0, Z
- mov r22, r0
- ; Загрузка частот из буфера
- ld r12, -X
- ld r13, -X
- ld r14, -X
- ld r15, -X
- ; Вычисление разности двух частот
- clc
- mov r16, r15
- sub r16, r13
- mov r18, r14
- sbc r18, r12
- brlo second_more_than_first ; Если разность < 0, то 2-я частота больше 1-й
- breq numbers_are_equal
- first_more_than_second:
- ; Вычисление (N1 - N2) - Ndop
- clc
- sub r16, r22
- sbci r18, $0
- brlo numbers_are_equal ; Если (N1 - N2) - Ndop < 0, считаем их средн. арифм.
- mov r20, r15 ; Иначе возвращаем
- mov r21, r14 ; большую частоту
- cbr r19, $01
- rjmp end
- second_more_than_first:
- ; (N1 - N2) -> (N2 - N1)
- com r18
- com r16
- ; Вычисление (N2 - N1) - Ndop
- clc
- sub r16, r22
- sbci r18, $0
- brlo numbers_are_equal ; Если (N2 - N1) - Ndop < 0, считаем их средн. арифм.
- mov r20, r13 ; Иначе возвращаем
- mov r21, r12 ; большую частоту
- sbr r19, $01
- rjmp end
- numbers_are_equal:
- ; Делим на 2 первое число
- lsr r15
- lsr r14
- ; Делим на 2 второе число
- lsr r13
- lsr r12
- ; Складываем полученное
- clc
- add r15, r13
- adc r14, r12
- mov r20, r15
- mov r21, r14
- sbr r19, $01
- end:
- pop yh
- pop yl
- pop zh
- pop zl
- pop r0
- pop r22
- pop r18
- pop r17
- pop r12
- pop r13
- pop r14
- pop r15
- pop r16
- out sreg, r16
- ret
- ; Инициализация UART
- Uart_init:
- in r16, sreg
- push r16
- ; Устанавливаем скорость передачи
- ldi r16, low(bauddivider)
- out ubrrl, r16
- ldi r16, high(bauddivider)
- out ubrrh, r16
- ; Сбрасываем флаги
- clr r16
- out ucsra, r16
- ; Разрешаем передачу
- ldi r16, (1 << TXEN)|(0 << TXCIE)|(0 << UDRIE)
- out ucsrb, r16
- ; Обращаемся к UCSRC и устанавливаем формат кадра - 8 бит
- ldi r16, (1 << URSEL)|(1 << UCSZ1)|(1 << UCSZ0)
- out ucsrc, r16
- pop r16
- out sreg, r16
- ret
- Transmit:
- in r16, sreg
- push r16
- push r17
- push yl
- push yh
- rcall Uart_init ; Инициализируем UART
- ldi r17, $04 ; Передаем 4 байта данных
- uart_send_cycle:
- sbis ucsra, UDRE ; Если регистр данных пуст, передаем след. байт
- rjmp uart_send_cycle
- ld r16, Y+
- out udr, r16 ; Загружаем в регистр данных след. байт
- dec r17
- brne uart_send_cycle
- pop yh
- pop yl
- pop r17
- pop r16
- out sreg, r16
- ret
- Loop:
- rjmp Loop
- ;====================================================================
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement