Warllord 0 20 мая, 2020 Опубликовано 20 мая, 2020 (изменено) · Жалоба Добрый день есть код программы моделирующий частично синус .include "m128def.inc" .def temp1 = R16 .equ CENTER = 0x80 .cseg .org 0x0000 JMP RESET .org 0x002A JMP ADC_Conversion_Complete_Handler ;Основная программа .org 0x0046 RESET: ;Проинициализируем стек ;Необходимо для того, чтобы правильно возвращатся из CALL и прерываний LDI temp1, high(RAMEND); OUT SPH, temp1; LDI temp1, low(RAMEND); OUT SPL, temp1; ;Вызовим процедуру инициализации переферии. CALL INIT; ;Разрешим прерывания. SEI; ;Все происходит в прерывании, поэтому бесконечный цикл ничего не делает (контроллер всегда в ожидании прерываний). ;Бесконечный цикл. LOOP: JMP LOOP; ;Процедура инициализации переферии INIT: ;Проинициализируем ЦАП, т.к. ЦАП внешний, проинициализируем выводы микроконтроллера для работы с микросхемой ЦАПа. SER temp1; OUT DDRA, temp1;Порт, куда будем выводить данные для ЦАПа. Установим его направление работы на выход. ;Установим выход ЦАПа - OUTA, контролируем на XS7 LDI temp1, (1 << PC0); OUT DDRC, temp1; ;DDRG = (1 << PG0); ;При обращении к порту G при помощи "OUT" симулятор ругается, что адрес этого порта находится за пределами действия "OUT" ;Поэтому будем обращаться к этому порту как к оперативной памяти через регистровую пару R31:R30 (Z) ;Из даташита адрес 0x0064 - адрес DDRG, а адрес 0x0065 - адрес PORTG LDI R30, 0x64; LDI R31, 0x00; LDI temp1, (1 << PG0); ST Z+, temp1;Т.к. к DDRG нам больше не понадобится обращаться, что перейдём автоматически на следуюий одрес, он же адрес PORTG ;PORTG = (1 << PG0); ST Z, temp1;Т.к. нам ещё понадобится обращаться к PORTG, то его адрес оставим в регистровой паре R31:R30 (Z) без изменений ;Проинициализируем ADC0 (PF0, XS4, АЦП) ;Кодключим вход АЦП к PF0, сместим результат влево (будем получать результат в ADCH), подключим внешний источник опорного напряжения LDI temp1, (1 << ADLAR); OUT ADMUX, temp1; ;Включим АЦП, запустим преобразование, включим режим FR, включим прерывания от АЦП ;В режиме FreeRun нам нет необходимости каждый раз запускать новое преобразование, это происходит автоматически. LDI temp1, (1 << ADEN) | (1 << ADSC) | (1 << ADFR) | (1 << ADIE); OUT ADCSRA, temp1; ;Выход из процедуры инициализации переферии RET; ;Процедура прерывания по завершению преобразования АЦП. ADC_Conversion_Complete_Handler: ;Заберём результат преобразования (достаточно старших 8 бит) IN temp1, ADCH; ;Сравнием результат преобразования со средним уровнем синусоиды (CENTER). CPI temp1, CENTER; BRPL NO_EDIT_temp1;Переходим на NO_EDIT_temp1 и пропустим следующую команду, если (temp1 - CENTER) > 0 (если флаг N = 0). LDI temp1, CENTER; Если эту команду не пропускаем, то идёт нижная половина синусоиды, и вместо неё в temp1 записываем сдений уровень (CENTER). NO_EDIT_temp1: ;Отобразим результат в ЦАП OUT PORTA, temp1; ;Простробируем ЦАП, переводя PG0 в низкий уровень, а затем обратно в высокий. ;Таким образом ЦАП сформирует и запомнит установленный нами уровень до следующего его изменения. ;PG0 -> lo ;Регистровая пара R31:R30 (Z) должна хранить адрес на PORTG CLR temp1; ST Z, temp1; NOP; ;PG0 -> hi LDI temp1, (1 << PG0); ST Z, temp1; RETI; данный код выдаёт вот такой импульс что нужно изменить в коде чтобы выдавал модуль синуса Изменено 20 мая, 2020 пользователем Warllord Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ae_ 2 21 мая, 2020 Опубликовано 21 мая, 2020 · Жалоба On 5/20/2020 at 4:12 PM, Warllord said: LDI temp1, CENTER; Если эту команду не пропускаем... Заменить на: NEG temp1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Warllord 0 21 мая, 2020 Опубликовано 21 мая, 2020 · Жалоба спасибо за ответ Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться