Учусь писать программу на asm, возник вопрос - у меня есть циклы считывания 50 временных интервалов сигнала и время каждого интервала нужно записать в свою ячейку оперативной памяти для дальнейшего вывода на индикацию - вопрос: как численно и коротко адресоваться к массиву ячеек для сохранения в них результата счета? Я пока придумал такой вариант - приращение значения регистра по счетчику команд с каждым переполнением счетчика таймера. Пример: REG1 equ 20h ;объявление регистров REG2 и т.д. REG50 equ 52h Chet equ 53h ; счетчик интервалов ****************** тело программы ****************** ;приращение результатов movlw .1 ; первая ячейка subwf Chet,0 btfss STATUS,C incf REG1,1 ; если в счетчике значение 1 - то приращение идет в первой ячейке памяти movlw .2 subwf Chet,0 btfss STATUS,C incf REG2,1 ;если 2 - то во второй и т.д. movlw .50 subwf Chet,0 btfss STATUS,C incf REG50,1 ;если 50 - то в 50-й
только получается очень много кода - только на счет 200 строк
что за МК (10,12,16 или 18-я серии, энхансед среднемладшие)? что откуда читаем и куда пишем (таблица из ПЗУ в ОЗУ или чтение/запись массива данных в пределах ОЗУ)?
[code]REG1 equ 20h ;объявление регистров Chet equ 53h ;[/code] .. movlw .1 ; первая ячейка subwf Chet,0 btfss STATUS,C incf REG1,1 ; если в счетчике значение 1 - то приращение идет в первой ячейке памяти
Явно не ПЗУ
_________________ У того, кто делает — получается редко. У того, кто не делает — не получается никогда.
Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей.
MK Pic16F648A - Считаем количество переполнений таймера TMR0 - в регистре оперативной памяти "К" - а далее нужно выгрузить это значение в регистр ОП с 1 по 50. А нельзя обратиться к оперативной памяти по номеру ячейки (плюс Сhet)?
Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре.
Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.
Шозабред? Зачем для упорядоченного массива данных писать табличный код непосредственной адресации? BOB51 всё объяснил. Обращение к массивам данных реализуют через индексы или указатели (что в общем одно и тоже по сути). Для этих целей в обсуждаемой архитектуре есть специальный регистр-указатель (FSR) и виртуальное "окно" доступа (INDF) по этому указателю. ЗЫ. Даже если массив и неупорядочен, то таблица может пересчитывать адрес для FSR, но реализовывать кучу вариантов кода путем непосредственной адресации (адрес данных в инструкции) - это идиотизм.
и ссыль на учебно -практическую документацию на русском: http://www.microchip.ru/lit/?mid=1x0 там на выбор изучающего. PIC16F62X как раз про 627 - 628 (более ранние версии 648го)
Разобрался! Все на первый взгляд очень просто устроено - если записать в регистр FSR номер ячейки памяти - то в регистре INDF будет значение этой ячейки, с которым можно работать как с самой ячейкой. И код тогда нужен примерно такой:
Код:
REG1 equ 20h ;объявление регистров REG2 и т.д. REG50 equ 52h Chet equ 53h ; счетчик интервалов ****************** тело программы ****************** movlw .19 addwf Chet,0 ; теперь в аккумул номер нужной ячейки упорядоченного блока памяти (а можно вообще убежать в ОП четвертого банка памяти!) movwf FSR ; записали номер ячейки в FSR - теперь INDF - это виртуально она же movf TINTERVALA,0 ; переслали значение n-го интервала времени в аккум movwf INCF ; все - в ячейке 20h (и далее) сохранено значение времени
Продолжу тему. Заглянул в Proteus7,7 sp2 - SAMPLES\VSM for PIC16\PIC Doorbell\ Увидел там вот такие команды ... movlw tune0 / 0x100 ; как это понимать? movwf tptrh movlw tune0 % 0x100 ; как это понимать? movwf tptrl ... Полный текст программы. Спойлер
initialise ; Register set up: clrw ; Zero. movwf PORTA ; Ensure PORTB is zero before we enable it. movwf PORTB ; Ensure PORTB is zero before we enable it. bsf STATUS,RP0 ; Select Bank 1 clrf TRISB ; Port B is outputs
; Set up timer 0 for tone generation movlw 0x02 ; Prescaler on, internal clocking, divide by 4 movwf OPTION_REG bcf STATUS,RP0 ; Back to bank 0
; Poll for a button wait clrf PORTB wloop btfss PORTA,0 goto playtune0 btfss PORTA,1 goto playtune1 goto wloop
;Routines to play the tunes playtune0 movlw 0x13 movwf PORTB movlw 0x50 movwf tempo movlw tune0 / 0x100 movwf tptrh movlw tune0 % 0x100 movwf tptrl goto playtune
;Subroutine to play a tune playtune call gettunedata ; Lookup note from tune table movwf note ; Store the note code btfsc note,7 ; Bit 7 set => end of tune goto wait ; Back to waiting for a button press incf tptrl,F ; Increment the tune pointer call gettunedata ; Get the note length movwf length ; Store it
; Play the stored note ; The tune table supports two octaves and 8 note lengths. playnote btfsc note,6 ; Bit 6 set => rest goto playwait ; Silence ensues... movf note,W ; Retrieve the note andlw 0x3F ; Mask off the pitch index call pitchtable ; and look it up in the pitchtable movwf pitch ; Transfer the value to Timer 0 movwf TMR0 bcf INTCON,T0IF ; Clear Timer Interrupt bsf INTCON,T0IE ; Enable interrupts for Timer 0 bsf INTCON,GIE playwait movf length,W ; Retrieve the note length movwf dl1 ; and store it in delay counter 1 loop1 movf tempo,W ; This value sets the timing resolution movwf dl2 loop2 nop ; Inner delay loop delay nop decfsz dl2,F goto loop2 decfsz dl1,F ; Outer delay loop goto loop1 bcf INTCON,T0IE ; Timer interrupts off
;Fetch next note/length pair: incf tptrl,F ; Increment tune ptr btfsc STATUS,Z ; Test for low byte rollover incf tptrh,F ; Inc high byte goto playtune ; Loop for next note
; Routine to fetch data from the tune tables gettunedata movf tptrh,W ; Set up PCLATH for the jump movwf PCLATH movf tptrl,W ; Get low address of tptr movwf PCL ; Jump off to the table entry
;Interrupt service - toggle the drive polarity to the sounder ;Note that this does not preserve the status bits - be careful, ;and that there is an assumption we are addressing bank 0. toggle movwf temp movf pitch,W movwf TMR0 movf PORTB,W xorlw 0x0F movwf PORTB bcf INTCON,T0IF movf temp,w retfie
Так и понимать: movlw tune0 / 0x100 => WREG=tune0/0x100, где tune0 - константа, которая должна быть объявлена в коде или в хедере. Соответственно movlw tune0 % 0x100 => WREG=остаток от деления (tune0/0x100) Все это математика препроцессора. Но так как tune0 - это МЕТКА, то есть по факту АДРЕС, то значение адреса и будет константой.
В коде tune0 прибит гвоздями к конкретному адресу:
Код:
org 0x0080
; Tune 0 Data ; Bach 'Badinerie' from Suite No 2 tune0 retlw 0x17 ;B retlw 0x78 ;240 retlw 0x1A ;D
То есть tune0=0х0080 Но код написан так, что tune0/tune1 могут быть размещены на произвольный адрес. Поэтому, чтобы изменение расположения таблиц не требовало изменения констант в коде, применен расчет страницы (деление на 0х100) и смещения в странице (остаток от деления) препроцессором. Посмотрите содержимое флеша (дизасм), там нет никаких делений и подставлены уже результирующие константы. ЗЫ. Вообще метод расчета констант из меток - плохая идея. При перемещаемом коде (линкер определяет позицию метки) всё это перестает работать. Патамушта препроцессор работает ДО линкера и он не может получить значение метки.
Похоже там еще и "прыжки по указателю" задействованы... А это уже в комплекте с PCLATH пойдет (вычисляемый переход)... в зависимости от садизма автора исходника.
Последний раз редактировалось BOB51 Пн дек 28, 2020 17:01:11, всего редактировалось 1 раз.
Очень полезный, но требует весьма много внимания и аккуратности. Поскольку во многих случаях надо где-то хранить предшествующее значение PCLATH, а у среднемладших прямое помещение в аппаратный стек... проблематично - надо делать программный стек. Второе - нет переноса из PCL (при операциях, где результат операции размещается в PCL) при переполнении в PCH. В то же время прием "вычислительного перехода" по адресу, формируемому содержимым "PCLATH:результат операции с PCL", специфичный именно для среднемладших ПИКов, весьма удобная штука.
Может быть Вы правы. Вот такое обращение с PCLATH тоже решает все проблемы. Спойлер
Код:
;---------- TABLE movlw high PC_ADR ; Установка (через W), в PCH (посредством PCLATH), числового movwf PCLATH ; значения старшего байта адреса той команды, которая помечена ; меткой PC_ADR. ;---------- ; Будем “прыгать” в текущий PC-блок или в следующий? ;---------- movf Reg,W ; “Прыжковое” число копируется в W. addlw low PC_ADR ; Суммирование "прыжкового" числа и числового значения младшего ; байта адреса той команды, которая помечена меткой PC_ADR. btfsc STATUS,C ; Перенос был или нет? incf PCLATH,F ; Если перенос был (соответствует работе в следующем PC-блоке), ; то PCLATH+1=... (то есть, PCH+1=...). ; Если переноса не было (соответствует работе в текущем ; PC-блоке), то команда инкремента не исполняется. movf Reg,W ; “Прыжковое” число копируется в W. ;---------- ; Таблица вычисляемого перехода. ;---------- addwf PCL,F ; PCL + W = ... PC_ADR retlw b'00111111' ; ..FEDCBA -> символ “0” 3Fh retlw b'00000110' ; .....CB. -> символ “1” 06h
Сейчас этот форум просматривают: CMETAHA и гости: 21
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения