# Алгоритмы ### Умножение целого на целое (беззначные) ```cp= ; умножение - это сложение числа с самим собой n раз ldi r22, n; clr r18 mulR18: add r18, r16 ; складываем с с самим собой dec r22 ; уменьшаем счетчик цикла cp r22, 0; проверяем, что в регистре 0 brne mulR18 ; если счетчик не кончился - считаем дальше ``` ### Деление (целые, беззначные) ```cp= ; умножение - это количество раз, которое нужно из числа вычесть n clr r18; частное ldi r17, n ; делитель cp r16, r17 ; если делимое меньше делителя, то сразу на выход brmi final delR16: inc r18 ; увеличиваем счетчик sub r16, r17 ; вычитаем из делимого делитель. brmi final ; если делимое оказалось меньше, значит счет окончен jmp delR16 final: ; вот здесь у нас получено итоговое значение r18 ``` ### Задержка Высчитывать ровное количество тактов для задержки бесполезно потому что скорее всего какие-то левые куски кода (на которые тоже тратятся такты процессора) всё попортят. Приблизительно можно написать. ```cp= clr r18 ; cycle param delay: ; cycle body inc r18 cpi r18, N ; do while r18(++) < N brmi delay ``` ### Задержка в 255+ тактов ```cp= ldi r20, 255 ForR20In255To0 : ldi r21, 255 ForR21In255To0 : dec r21 brne ForR21In255To0 ; если != 0, то продолжаем уменьшать dec r20 brne ForR20In255To0 ``` ### Инициализация стека ```cp= ldi r16, low(RAMEND) out spl, r16 ldi r16, hight(RAMEND) out sph, r16 ``` ### Заброс/Получение значения в стек ```cp= out r16 SREG push r16 ... pop r16 in SREG r16 reti ``` ### Получение числа едениц и десятков в двузначном числе ```cp= ; логика такая. У нас число 54. 5 - это количество раз, которое из числа можно отнять 10. 4 - это остаток clr r20; тут будут десятки ; еденицы останутся в r16 cpi r16, 10; сначала сравниваем с 10, чтобы понять, есть ли вообще смысл считать brmi final; если число в r16 < 10, то у нас нет десятков, только r16 едениц, на выход subi r16, 10 ; calcDecs: inc r20 ; если можно из числа вычесть 10, значит прибавить 1 к числу десятков subi r16, 10; вычитаем из r16 10 brmi final ; такая же логика, как и раньше. Если теперь стало меньше 10, значит в r16 дсятков нет jmp calcDecs; если больше или равно, продолжаем считать final: ``` ### Чтение с клавиатурки ![](https://i.imgur.com/kZX8pTT.png) 4 пина [0:3] кодируют координату кнопки по вертикали (1 если нажата). 4 пина [4:7] кодируют координату кнопки по горизонтали. Буду делать так, просто сравнивать значение с пина с каждой из координат ```cp= .equ button7 = 0b10001000 .equ button4 = 0b01001000 ... .equ button8 = 0b10000100 ... .equ buttonEqual = 0b00010001 main: in r16, PIND cpi r16 button7 breq clickButton7 cpi r16 button4 breq clickButton4 .... и так далее по каждой кнопке ``` ### Добавление цифры 1) для хранения трехзначного числа на индикаторе нам нужно 2 байта (999) Я думаю как сделать, пока идут цифры сохранять в 4 регистрах цифры. А уже когда случится сигнал на сложение, сформировать из этих цифр трехзначное число. Пожалуй буду использовать для этого стек + регистр счетчик количества цифр. Благодаря счетчику количества цифр мы еще и выведем нужное число на экран ```cp= .def numberCounter = r20; количество цифр .def numberToDraw = r21; цифра, которую будем рендерить. если = 10, то ничего не отображать .equ maxNumberCount = 3 clickButton7: если нажали на кнопку 7 cpi numberCounter, maxNumberCount breq main; если количество цифр уже максимально, проигнорировать команду ldi r16, 7; закинуть в стек 7 push r16 jmp renderNumber; идем на рендер ``` ### Обработка сброса нам нужно вытащить все из стека, обнулить текущий numberCounter, отрендерить пустые ячейки ```cp= clickC: ldi numberToDraw = 10; конфигурируем рендер на отображение ничего cpi numberCounter, 0 breq main; если количество цифр = 0, возвращаемся к ожиданию pop r16; достаем из стека цифру renderNumber; идем рисуем, что её нет. dec numberCounter; уменьшаем количество цифр jmp clickC; повторяем ``` ### Обработка плюса нам нужно вытащить все из стека. обнулить текущий numberCounter, отрендерить пустые ячейки и сложить его с первым слагаемым. Для самого первого введенного числа первое слагаемое = 0. После сложения полученное число само становится 1 слагаемым 2) преобразовать 3 цифры в 3значное число. Для этого 1 цифру просто складываем. 2 цифру умножаем на 10 и складываем. 3 цифру умножаем на 100 и складываем. 3) складываем с 1 слагаемым. Сначала складываем младшие байты, потом старшие + флаг С от младших байтов #### Собираем число из цифр ```cp= .def inputNumberH r20 .def inputNumberL r29 cpi numberCounter, 0 breq main; игнорируем команду если ничего не введено pop inputNumberL; достаем последнюю цифру cpi numberCounter, 1 breq startPlus; если была только 1 цифра перестаем считывать pop r21 ; достаем десятки ldi r22, 10 ; нельзя умножить регистр на число, поэтому кидаем число в регистр mul r21, r22 ; получаем количество десятков add inputNumberL, r21 ; получаем сумму десятков и едениц cpi numberCounter, 2 breq startPlus; если была только 2 цифра перестаем считывать pop r21 ; достаем сотни ; 99 точно помещается в 1 байт, а 9*100 в 1 байт не поместится и mul использовать нельзя. Тогда просто запускаем цикл где 100 раз добавляем в inputNumber r21. Учитываем конечно, что число может стать двубайтным getHundreds: ldi r22, 100 ; сто раз складываем к inputNumber число сотен add inputNumberL, r21; складываем с младшим разрядом число сотен adc inputHubmerH, 0 ; складываем со старшим разрядом 0 и значение флага C subi r22, 1 ; уменьшаем значение цикла на 1 breq fin ; если = 0, выходим jmp getHundreds ``` #### Складываем с 1 слагаемым (которое заранее = 0) ```cp= add firstNumberL, inputNumberL adc firstNumberH, inputNumberH ; сложение с учетом флага C ``` #### Обратно в цифры количество тысяч - количество раз из числа вычесть 1000. количество сотен - сколько раз из остатка вычесть 100. количество десятков - сколько раз из остатка вычесть 10. количество едениц - остаток тысяча - это 1111101000. 11101000 вычитаем из младшего бита, 11 из старшего ```cp= mov tempH, firstNumberH mov tempL, firstNumberL clr thouthands calcThouthands: <тут нужна проверка на то, что число >= 1000> <и так же где-то тут нужно сделать так, чтобы numberCount стало = 4> brmi calcHundreds sub tempL, 0b11101000 subc tempH, 0b11 inc thouthands jmp calcThouthands ; Аналогично для сотен, десятков, но даже проще, так можно будет с регистром h не работать. Полученное на вывод. ``` ### АЦП #### Инициализация ```cp= .org 0x01С jmp ADC_1 ; задаем переход на функцию по вектору прерывания sei ; включаем прерывания ``` #### Старт ```cp= .edu ADCSRA_SETUP = 0b11001<3 бита на предделитель> ; 7 - активация ; 6 - включение ; 5 - ADATE (запуск от периферийки). Сами запускаем ; 4 - флаг прерывания - мы не активируем ; 3 - разрешаем прерывания ; 2 - 0 - коэф. предделителя .equ ADMUX_SETUP = 0b11100000 ; 7-6 - источник опорного напряжения. Если в задаче никаких всратых пинов не подведено, то берем 11 (внутренний) ; 5 - ADLAR - 8 бит результата будут расположены в ADCH ; 4 - зарезервирован ; 3-0 - адрес пина входа. Смотрим по табличкам ldi r16, ADMUX_SETUP out ADMUX, r16 ldi r16, ADCSRA_SETUP out ADCSRA, r16 ``` #### Чтение 10 битного значения ```cp= read: sbrs ADCRA, 5 ; 5 бит ADLAR регитсра ADCRA означает, что старшие 8 бит в регистре H jmp readFromL: ; если бит не установлен, то старшие 8 бит в регистре L readFromH: out r16 ADCH out r17 ADCL jmp calc readFromL: out r16 ADCL out r17 ADCH ``` ### SPI #### Инициализация Так как мы являемся мастером, то нам самим нужно настроить порты ввода\вывода на выход. ```cp= SPI_MasterInit: ; Set MOSI, SS and SCK output, all others input ldi r17,(1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS) out DDR_SPI,r17 ; Enable SPI, Master, set clock rate fck/16 ldi r17, (1<<SPIE)|(1<<SPE)|(1<<MSTR)|(1<<SPR0) out SPCR,r17 sei ; разрешаем прерывания если нужно reti ``` #### Передаем данные не используя прерывания ```cp= SPI_MasterTransmit: ; Start transmission of data (r16) out SPDR,r16 Wait_Transmit: ; Wait for transmission complete sbis SPSR,SPIF rjmp Wait_Transmit ret ``` #### Получаем данные не используя прерывания ```cp= SPI_SlaveTransmit: ; Start transmission of data (r16) Wait_Transmit: ; Wait for transmission complete sbis SPSR,SPIF jmp Wait_Transmit sbis SPSR, WCOL ; если обнаружилась ошибка данных, ждем их снова ret ldi r16 (0>>SPIF) ; очищаем флаг завершения передачи jmp Wait_Transmit: ``` ### USART ```cp= ``` ### TWI ### таймер