Разбираясь с ассемблером дошёл до динамической индикации. Решил повторить в железе эксперимент из видео Приобрёл 4 символьный индикатор E40281-I-UR3-0-W, подкорректировал код под 4 символа и Atmega8 Спойлер: Код №1 Код (C++): .include "m8def.inc" // Подключаем заголовочный файл ATMega16 .def temp = r16 // Присваиваем регистрам символические имена .def razr1 = r17 .def razr2 = r18 .def razr3 = r19 .def sys = r20 .def try = r21 .equ ch1=0b10011111 // Задаем эквивалентику цифр для общего анода .equ ch2=0b00100101 // кстати можешь в папке этого проекта найти .equ ch3=0b00001101 // файлы CHOC и CHOA, я в них поместил набор .equ ch4=0b10011001 // символов, для простоты написания кода, для .equ ch5=0b01001001 // общего катода и анода соответственно .equ ch6=0b01000001 .equ ch7=0b00011111 .equ ch8=0b00000001 .equ ch9=0b00001001 .equ ch0=0b00000011 .dseg // сегмент ОЗУ Visible: // метка Visible .byte 8 // по ней в ОЗУ зараезервируем 8 байт .cseg // Программный сегмент .org 0 // Адрес вектора Reset rjmp Reset // Переходим на Reset .org $009 // Адрес вектора таймера 0 по переполнению rjmp TIM0_OVF ; // Переходим на TIM0_OVF Reset: // Метка Reset ldi temp, high(RAMEND) // Инициализируем стек out sph, temp ldi temp, low(RAMEND) out spl, temp ldi temp, ch1 sts Visible, temp ldi temp, ch2 sts Visible+1, temp ldi temp, ch3 sts Visible+2, temp ldi temp, ch4 sts Visible+3, temp ldi temp, ch5 sts Visible+4, temp ldi temp, ch6 sts Visible+5, temp ldi temp, ch7 sts Visible+6, temp ldi temp, ch8 sts Visible+7, temp ldi temp, 0xff // Порты D и B на выход, на нем висит наш индикатор out DDRD, temp out DDRB, temp ldi temp, 0b00000010 // Ставим предделитель CS = 010 out TCCR0, temp ldi temp, 0b00000001 // TOV0 = 1 бит прерывания по переполнению таймера 0 out TIFR, temp out TIMSK, temp ldi temp, 0xFE out TCNT0, temp // А тут в тикающий регистр засовываем FE ldi sys, 0b10000000 // ставим начальное положение sys sei // Разрешаем прерывания Proga: // Основная программа rjmp Proga // Переход на Proga TIM0_OVF: // Прерывание по переполнению cli // Запрещаем прерывания lsr sys // Производим логический сдвиг вправо cpi sys, 0b00001000 // Проверяем, не ушли ли за пределы сегментов отображения на индикаторе breq Mary // Если ушли, переходим на обнуление т.е. метка Мэри out PORTD, sys // Если нет, выводим значение sys в порт ld temp, X+ // загрузим значение из X(Visible) в temp ld temp, X // загрузим значение из X(Visible) в temp out PORTB, temp // И выкинем на порт Vix: // Метка Vix ldi temp, 0x00 // Взводим тикающий регистр out TCNT0, temp sei // Разрешаем прерывания reti // Выходим из прерывания Mary: // Метка Мэри. Почти Поппинс =D ldi sys, 0b10000000 // В sys значение out PORTD, sys // Выводим на порт ldi XH, high(Visible+4) // Тут произведем зарядку 1 адреса нашего Visible в регистр косвенной ldi XL, low(Visible+4) // адресации, сперва старший, потом младший ld temp, X // загрузим значение из X(Visible) в temp out PORTB, temp // И выкинем на порт rjmp Vix // Перейдем на Vix При запуске получаем интересную картину. Первый разряд работает нормально, изменяются цифры от 1 до 5. На трёх остальных выводится какой-то мусор. Пробую вывести просто цифры. Загружаю такой код Спойлер: Код №2 Код (C++): .include "m8def.inc" // Подключаем заголовочный файл ATMega16 .def temp = r16 // Присваиваем регистрам символические имена .def razr1 = r17 .def razr2 = r18 .def razr3 = r19 .def sys = r20 .def try = r21 .equ ch1=0b10011111 // Задаем эквивалентику цифр для общего анода .equ ch2=0b00100101 // кстати можешь в папке этого проекта найти .equ ch3=0b00001101 // файлы CHOC и CHOA, я в них поместил набор .equ ch4=0b10011001 // символов, для простоты написания кода, для .equ ch5=0b01001001 // общего катода и анода соответственно .equ ch6=0b01000001 .equ ch7=0b00011111 .equ ch8=0b00000001 .equ ch9=0b00001001 .equ ch0=0b00000011 .dseg // сегмент ОЗУ Visible: // метка Visible .byte 8 // по ней в ОЗУ зараезервируем 6 байт .cseg // Программный сегмент .org 0 // Адрес вектора Reset rjmp Reset // Переходим на Reset .org $009 // Адрес вектора таймера 0 по переполнению rjmp TIM0_OVF ; // Переходим на TIM0_OVF Reset: // Метка Reset ldi temp, high(RAMEND) // Инициализируем стек out sph, temp ldi temp, low(RAMEND) out spl, temp ldi temp, ch1 sts Visible, temp ldi temp, ch2 sts Visible+1, temp ldi temp, ch3 sts Visible+2, temp ldi temp, ch4 sts Visible+3, temp ldi temp, ch5 sts Visible+4, temp ldi temp, ch6 sts Visible+5, temp ldi temp, ch7 sts Visible+6, temp ldi temp, ch8 sts Visible+7, temp ldi temp, 0xff // Порты D и B на выход, на нем висит наш индикатор out DDRD, temp out DDRB, temp //ldi temp, 0b00001101 //out PORTB, temp ldi temp, 0b00000010 // Ставим предделитель CS = 010 out TCCR0, temp ldi temp, 0b00000001 // TOV0 = 1 бит прерывания по переполнению таймера 0 out TIFR, temp out TIMSK, temp ldi temp, 0xFE out TCNT0, temp // А тут в тикающий регистр засовываем FE ldi sys, 0b10000000 // ставим начальное положение sys sei // Разрешаем прерывания Proga: // Основная программа rjmp Proga // Переход на Proga TIM0_OVF: // Прерывание по переполнению cli // Запрещаем прерывания lsr sys // Производим логический сдвиг вправо cpi sys, 0b00001000 // Проверяем, не ушли ли за пределы сегментов отображения на индикаторе breq Mary // Если ушли, переходим на обнуление т.е. метка Мэри out PORTD, sys // Если нет, выводим значение sys в порт ld temp, X+ // загрузим значение из X(Visible) в temp ld temp, X // загрузим значение из X(Visible) в temp out PORTB, temp // И выкинем на порт Vix: // Метка Vix ldi temp, 0x00 // Взводим тикающий регистр out TCNT0, temp sei // Разрешаем прерывания reti // Выходим из прерывания Mary: // Метка Мэри. Почти Поппинс =D ldi sys, 0b10000000 // В sys значение out PORTD, sys // Выводим на порт ldi XH, high(Visible) // Тут произведем зарядку 1 адреса нашего Visible в регистр косвенной ldi XL, low(Visible) // адресации, сперва старший, потом младший ld temp, X // загрузим значение из X(Visible) в temp out PORTB, temp // И выкинем на порт rjmp Vix // Перейдем на Vix Все разряды работают, Нормально отображает 1 2 3 4 Опять загружаю первый код - всё работает в норме. Ну думаю всё нормализовалось, пол первого ночи, пошёл спать. Утром включаю, та-же картина. Первый разряд работает нормально, изменяются цифры от 1 до 5. На трёх остальных выводится какой-то мусор. Делаю ту-же процедуру - гружу второй код, норма. Гружу первый код - опять заработало как надо. Кто нибудь сталкивался с такими фокусами? В чём причина неадекватного поведения индикатора?
ИМХО, не тратьте время на написание на чистом ассемблере, углубитесь в Си. Си - это прекрасный язык, позволяющий писать код, работающий быстро и оптимально! А если не хватает Си, есть ассемблерные вставки в Си-шном коде. Все возможности Асма решаютcя легко и просто! А ассемблер, можно прекрасно изучать по листингам компиляции Вашего Си-шного кода. И на основе изучения листинга - корректировать код. Советую на основании своего опыта! С Асма ушел на Си и не разу, посе этого ни посмотрел в сторону чистого Асма!
Я не буду с вами спорить, я с вами согласен. Я не занимаюсь микроконтроллерами на профессиональном уровне, мне просто интересно. Познакомился со всем этим через ардуино. Теперь захотелось посмотреть на это всё на более глубоком уровне. Так, что если возникнет идея реализации какого-либо проекта, то писать буду в в среде ардуино. Вопрос по индикатору возник при рассмотрении самого принципа динамической индикации. Когда возникла необходимость в применении 7 сегментного индикатора в реальном устройстве я использовал модуль со встроенным TM1637.
Этот индикатор - кучка светодиодов. Никакого "поведения" у него нет. Просто ваша первая программа не(адекватно) инициализирует какой-то регистр процессора. Это делает вторая программа. Потом первая нормально работает до выключения питания.
При ресете все регистры сбрасываются (кроме двух) в отличие от NVM памяти, коей является ОЗУ. Поэтому очистка ОЗУ перед инициализацией переменных - главная задача у компилятора. Как там у ASM компиляторов - ХЗ..
Обе программы аналогичны. Вторую я "сделал" из первой, когда индикатор адекватно не запустился. Убрал декремент первого разряда.
Написал так, как работает, ничего странного. Ну, вот посудите, Вы считаете нормально из подпрограммы Mary резкий переход на подпрограмму Viх, не смотря на то что выход из Vix как обработки прерывания?