Ассемблер (ASM) для AVR в вопросах и ответах

Обсуждаем контроллеры компании Atmel.
Ответить
Модератор
Аватара пользователя
Сообщения: 19103
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Сообщение Starichok51 »

Wladimir_TS писал(а):Неоднократно замечал что при старте проекта в студии имеет место быть 1 холостое прерывание от внешних источников если они разрешены и если настроено на фронт или спад сразу после SEI. В железе его нет
когда ты в студии запустил симуляцию и курсор встал на нулевой адрес, сначала пины соответствующих входов нужно поставить в нужное состояние. тогда не будет возникать ложного запуска прерывания.
изначально студия на всех пинах всех портов ставит нули.
а в железе пины при запуске стоят в нужном состоянии, потому в железе ложного запуска прерывания при старте не происходит.
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Реклама
Друг Кота
Сообщения: 5066
Зарегистрирован: Вс фев 15, 2009 01:04:58
Откуда: Kaluga

Сообщение Wladimir_TS »

Видимо так оно и есть.
Реклама
Первый раз сказал Мяу!
Аватара пользователя
Сообщения: 31
Зарегистрирован: Вс окт 18, 2020 19:01:52
Откуда: Харьковская область

Сообщение a1000 »

Всем привет!
В ходе изучения ASM в учебных целях решил сделать частотомер на 50 Гц. Принцип работы - измерение периода. Камень - atmega8, частота 8 МГц. Напяжение через диод и резисторный делитель подаю на ICP1. Для начала был написан такой код.
Спойлер

Код: Выделить всё

				
;=============
; Сегмент FLASH памяти
.CSEG
;=============
; Таблица прерываний
    .ORG 0x00        RJMP	RESET
    .ORG 0x05        RJMP	TIM1_CAPT			

;=============
; Прерывание по сбросу, стартовая инициализация 
RESET:	
    ; Инициализация стека
    LDI 	Temp1, LOW(RAMEND)
    OUT 	SPL, Temp1
    LDI 	Temp1, HIGH(RAMEND)	
    OUT 	SPH, Temp1
    ; Очистка ОЗУ и регистров R0-R31
    LDI		ZL, LOW(SRAM_START)		; Адрес начала ОЗУ в индекс
    LDI		ZH, HIGH(SRAM_START)
    CLR		Temp1				; Очищаем R16
RAM_Flush:
    ST 		Z+, Temp1				
    CPI		ZH, HIGH(RAMEND + 1)	
    BRNE	RAM_Flush			
    CPI		ZL, LOW(RAMEND + 1)	
    BRNE	RAM_Flush
    LDI		ZL, (0x1F-2)			; Адрес регистра R29
    CLR		ZH
Reg_Flush:
    ST		Z, ZH
    DEC		ZL
    BRNE	Reg_Flush
    CLR		ZL
    CLR		ZH
    ; Регистры и SRAM полностью очищены (обнулены)
    ; Но регистры ввода-вывода (IO) НЕОБХОДИМО очищать
    ; Глобальный запрет прерываний
    CLI

        ;настройка порта D
	ldi Temp1, 0xFF // порт D на выход
	out DDRD, Temp1
	
	
        ;настройка порта B
	cbi	DDRB,0    ; ICP1 на вход
	
	;настройка таймера1
	ldi Temp1, 0b00000000
	out TCCR1A, Temp1
	ldi Temp1, 0b01000011
	out TCCR1B, Temp1
	ldi Temp1, 0b00100000
	out TIMSK, Temp1
	out TIFR, Temp1

		
	SEI ;разрешаем прерывания
;***************************************************
LOOP:
	


rjmp	LOOP

;==============
TIM1_CAPT:            ;обработчик прерывания по захвату таймера 1
   
   SBIC PORTD,EXT
   rjmp	metka
   SBI  PORTD,EXT ;установить бит 
   rjmp	EXIT
   metka:
   CBI  PORTD,EXT ;установить бит
EXIT:
RETI                  


Подключенный к PD0 логический анализатор выдал красивую картинку
Изображение
Следующий этап - получение данных с регистра захвата. В качестве индикатора применил модуль из 4 семисегментных индикаторов на TM1637. Что-бы число импульсов влазило в индикатор, решил ограничится 1 байтом. По сему коэфициент предделителя выбрал 1024, должно получаться что-то около 156. Вывод на TM1637 уже давно отработан и в коде не приводится.
Спойлер

Код: Выделить всё

				
;=============
; Сегмент FLASH памяти
.CSEG
;=============
; Таблица прерываний
    .ORG 0x00        RJMP	RESET
    .ORG 0x05        RJMP	TIM1_CAPT			



;=============
; Прерывание по сбросу, стартовая инициализация 
RESET:	
    ; Инициализация стека
    LDI 	Temp1, LOW(RAMEND)
    OUT 	SPL, Temp1
    LDI 	Temp1, HIGH(RAMEND)	
    OUT 	SPH, Temp1
    ; Очистка ОЗУ и регистров R0-R31
    LDI		ZL, LOW(SRAM_START)		; Адрес начала ОЗУ в индекс
    LDI		ZH, HIGH(SRAM_START)
    CLR		Temp1				; Очищаем R16
RAM_Flush:
    ST 		Z+, Temp1				
    CPI		ZH, HIGH(RAMEND + 1)	
    BRNE	RAM_Flush			
    CPI		ZL, LOW(RAMEND + 1)	
    BRNE	RAM_Flush
    LDI		ZL, (0x1F-2)			; Адрес регистра R29
    CLR		ZH
Reg_Flush:
    ST		Z, ZH
    DEC		ZL
    BRNE	Reg_Flush
    CLR		ZL
    CLR		ZH
    ; Регистры и SRAM полностью очищены (обнулены)
    ; Но регистры ввода-вывода (IO) НЕОБХОДИМО очищать
    ; Глобальный запрет прерываний
    CLI
	
	;настройка порта D
	ldi Temp1, 0xFF // Порт D на выход
	out DDRD, Temp1

	;настройка порта B
	cbi	DDRB,0    ; ICP1 на вход
	
	;настройка таймера1
	ldi Temp1, 0b00000000
	out TCCR1A, Temp1
	ldi Temp1, 0b01000101
	out TCCR1B, Temp1
	ldi Temp1, 0b00100000
	out TIMSK, Temp1
	out TIFR, Temp1


; =========== 

	
	CLT  ;сбрасываем бит Т
	ORI R30, 0b00000001   ;устанасливаем бит 0 R30 в 1
	
	SEI ;разрешаем прерывания
;***************************************************
LOOP:
	
	BRTC    LOOP          ;если Т=0 не делаем ничего
	CLI                   ;запрещаем прерывания

;***************************************************

; вывод значения Temp1 на TM1637

;***************************************************


; =========== 
;    delay loop generator 
;     8000000 cycles:
; ----------------------------- 
; delaying 7999992 cycles:
          ldi  R17, $48
WGLOOP00:  ldi  R18, $BC
WGLOOP1:  ldi  R19, $C4
WGLOOP2:  dec  R19
          brne WGLOOP2
          dec  R18
          brne WGLOOP1
          dec  R17
          brne WGLOOP00
; ----------------------------- 
; delaying 6 cycles:
          ldi  R17, $02
WGLOOP3:  dec  R17
          brne WGLOOP3
; ----------------------------- 
; delaying 2 cycles:
          nop
          nop
; =========== 

	SEI ;разрешаем прерывания
	CLT  ;сбрасываем бит Т

rjmp	LOOP

;==============
TIM1_CAPT:            ;обработчик прерывания по захвату таймера 1
        SBRS R30,0    
	rjmp ZAHVAT
	CLR Temp1         ;обнуляем счётчмк  
	out TCNT1H,Temp1
	out TCNT1L,Temp1
	ANDI R30, 0b11111110   ;устанасливаем бит 0 R30 в 0
	rjmp EXT
ZAHVAT:
	in Temp1,ICR1L    ;копируем значение регистра захвата  
        in Temp2,ICR1H
	ORI R30, 0b00000001   ;устанасливаем бит 0 R30 в 1
        SET  ;устанавливаем бит Т

EXT:
RETI                  


В кратце логика такая. До первого прерывания ничего не делаем. По первому прерыванию сбрасываем TCNT1 в ноль, по второму забираем в Temp1 младший байт регистра захвата и разрешаем его вывод на индикатор. Перед выводом запрещаем прерывания, выводим значение Temp1. Задержка 1 сек. Разрешаем прерывания и всё по новой. В теории красиво, а на деле на индикаторе бегают цифры от 3 до 200.
Где косяк?
Это Спарта! В смысле, ассемблер. Все ручками.
akl
Друг Кота
Сообщения: 4475
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Сообщение akl »

Неполная очистка таймера, т.к. задействован предделитель

Код: Выделить всё

TIM1_CAPT:            ;обработчик прерывания по захвату таймера 1
        SBRS R30,0   
   rjmp ZAHVAT
   CLR Temp1         ;обнуляем счётчмк 
   out TCNT1H,Temp1
   out TCNT1L,Temp1
;================
   LDI	R16,1<<PSR10
   OUT	SFIOR,R16	; обнулить предделитель таймера
;================

   ANDI R30, 0b11111110   ;устанасливаем бит 0 R30 в 0
   rjmp EXT
ZAHVAT:
   in Temp1,ICR1L    ;копируем значение регистра захвата 
        in Temp2,ICR1H
   ORI R30, 0b00000001   ;устанасливаем бит 0 R30 в 1
        SET  ;устанавливаем бит Т

EXT:
RETI
Таймер при выходе из прерывания по окончании измерения не останавливается. За время вывода на индикацию и задержки входной сигнал на PB0/ICP1 установит флаг ICF1, т.е. при переходе на LOOP прерывание вызовется сразу, а не по фронту входного сигнала.
Спойлер

Код: Выделить всё

 .include "m8def.inc"	; ATMega8

.equ	Fo=8000000

.def	temp1=R16
.def	temp2=R17
            
;=============
; Сегмент FLASH памяти
.CSEG
;=============
; Таблица прерываний
.ORG 0x00
	RJMP   RESET
.ORG 0x05   ;     RJMP   TIM1_CAPT         
TIM1_CAPT:            ;обработчик прерывания по захвату таймера 1
	SBRS R30,0   
   rjmp ZAHVAT
   OUT	TCCR1B,R22
;   CLR Temp1         ;обнуляем счётчмк 
;   out TCNT1H,Temp1
;   out TCNT1L,Temp1
   CBR	R30,1<<0
;   ANDI R30, 0b11111110   ;устанасливаем бит 0 R30 в 0
   rjmp EXT
ZAHVAT:
	in Temp1,ICR1L    ;копируем значение регистра захвата 
    in Temp2,ICR1H
   SBR	R30,1<<0
;   ORI R30, 0b00000001   ;устанасливаем бит 0 R30 в 1

   ldi Temp1,0b01000000
   out TCCR1B, Temp1
;   ldi Temp1, 0b01000101
;   out TCCR1B, Temp1

   ldi Temp1, 0b00100000
   out TIMSK, Temp1
   out TIFR, Temp1

	LDI	R16,1<<PSR10
	OUT	SFIOR,R16
        SET  ;устанавливаем бит Т
EXT:
RETI



;=============
; Прерывание по сбросу, стартовая инициализация
RESET:   
    ; Инициализация стека
    LDI    Temp1, LOW(RAMEND)
    OUT    SPL, Temp1
    LDI    Temp1, HIGH(RAMEND)   
    OUT    SPH, Temp1
    ; Очистка ОЗУ и регистров R0-R31
    CLI
   
   ;настройка порта D
   ldi Temp1, 0xFF // Порт D на выход
   out DDRD, Temp1

   ;настройка порта B
   cbi   DDRB,0    ; ICP1 на вход
   
   ;настройка таймера1
   ldi Temp1, 0b00000000
   out TCCR1A, Temp1

   ldi Temp1,0b01000000
   out TCCR1B, Temp1
;   ldi Temp1, 0b01000101
;   out TCCR1B, Temp1

   ldi Temp1, 0b00100000
   out TIMSK, Temp1
   out TIFR, Temp1

	LDI	R16,1<<PSR10
	OUT	SFIOR,R16
; ===========
   CLT  ;сбрасываем бит Т
   SBR	R30,1<<0
;   ORI R30, 0b00000001   ;устанасливаем бит 0 R30 в 1
	LDI	R22,0b01000101
   SEI ;разрешаем прерывания
;***************************************************
LOOP:
   
   BRTC    LOOP          ;если Т=0 не делаем ничего
   CLI                   ;запрещаем прерывания

;***************************************************

; вывод значения Temp1 на TM1637

;***************************************************


; ===========
;    delay loop generator
;     8000000 cycles:
; ----------
; delaying 7999992 cycles:
          ldi  R17, $48
WGLOOP00:  ldi  R18, $BC
WGLOOP1:  ldi  R19, $C4
WGLOOP2:  dec  R19
          brne WGLOOP2
          dec  R18
          brne WGLOOP1
          dec  R17
          brne WGLOOP00
; ----------
; delaying 6 cycles:
          ldi  R17, $02
WGLOOP3:  dec  R17
          brne WGLOOP3
; ----------
; delaying 2 cycles:
          nop
          nop
; ===========

;   SEI ;разрешаем прерывания
;   CLT  ;сбрасываем бит Т

	rjmp   RESET
;rjmp   LOOP


;==============
.EXIT
Последний раз редактировалось akl Пн окт 19, 2020 05:31:45, всего редактировалось 1 раз.
Реклама
Эиком - электронные компоненты и радиодетали
Это не хвост, это антенна
Сообщения: 1495
Зарегистрирован: Ср июн 25, 2008 15:19:44

Сообщение Demiurg »

Замечание по комментариям. Комментарии должны быть информативными, нести смысловую нагрузку. А не информировать об очевидном.
Пример:

Код: Выделить всё

sbi LED_PORT, LED // Включение светодиода
Это очевидно. Масло масляное. Указывайте в комментариях непростые, неочевидные вещи. Алгоритм, пояснения. То, о чем другим будет непонятно, и что вы забудете через месяц.
Контактная информация:
Реклама
akl
Друг Кота
Сообщения: 4475
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Сообщение akl »

Далеко не очевидно.
Например, светик подключен через резистор анодом на плюс. Или для камня с переключением состояния через PIN

Код: Выделить всё

;.equ	LED_PORT=PORTD
.equ	LED_PORT=PIND
.equ	LED=0

	SER	ZH
	OUT	DDRD,ZH

	SBI	LED_PORT,LED ; переключить состояние светика
Реклама
Первый раз сказал Мяу!
Аватара пользователя
Сообщения: 31
Зарегистрирован: Вс окт 18, 2020 19:01:52
Откуда: Харьковская область

Сообщение a1000 »

[uquote="akl",url="/forum/viewtopic.php?p=3909119#p3909119"]Неполная очистка таймера, т.к. задействован предделитель
...............
Таймер при выходе из прерывания по окончании измерения не останавливается. За время вывода на индикацию и задержки входной сигнал на PB0/ICP1 установит флаг ICF1, т.е. при переходе на LOOP прерывание вызовется сразу, а не по фронту входного сигнала.[/uquote]

Предделитель сильно не повлияет. Плюс-минус один такт. А по второму согласен на все сто. Пока будем выводить значения и висеть в задержке флаг ICF1 будет установлен и первое прерывание произойдёт не по фронту а в момент разрешения прерывания. Попробовал решить вопрос в лоб, сбрасывать ICF1 в конце LOOP перед установкой бита I. Показания немного стабилизировались. Буду разбираться с вашим кодом. Спасибо за совет.

Добавлено after 8 minutes 46 seconds:
Ещё вопрос в догонку. Установив биты предделителя CS12 – CS10 в "000" мы останавливаем таймер. При этом TCNT1 обнуляется? Если опять запустить счёт он продолжится со значения в момент остановки или начнётся с нуля?
Это Спарта! В смысле, ассемблер. Все ручками.
Друг Кота
Аватара пользователя
Сообщения: 15816
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Сообщение BOB51 »

Зависит от режима работы.
При "ручном" останове текущее содержимое таймера не изменится (если момент останова не совпадет с соответствующей точкой работы таймера - например сброс по совпадению).
Насчет обнуления - это только или по сбросу или по выходу из сна оговорено - смотрим соответствующий раздел даташита.
8)
akl
Друг Кота
Сообщения: 4475
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Сообщение akl »

[uquote="a1000",url="/forum/viewtopic.php?p=3909218#p3909218"]... Установив биты предделителя CS12 – CS10 в "000" мы останавливаем таймер. При этом TCNT1 обнуляется? Если опять запустить счёт он продолжится со значения в момент остановки или начнётся с нуля?[/uquote]Да, таймер останавливает счёт. Предделитель нет! При последующем запуске продолжение счёта в моменты переполнения предделителя.
Первый раз сказал Мяу!
Аватара пользователя
Сообщения: 31
Зарегистрирован: Вс окт 18, 2020 19:01:52
Откуда: Харьковская область

Сообщение a1000 »

Сидел разбирался с кодом akl. Напишу, что я понял и свои вопросы.
Стартовая инициализация. Вы убрали очистку ОЗУ. Вы считаете это лишним, или спрятали что-бы не загромождать код? С настройками таймера понятно - счётчик стоит, прерывания по захвату разрешены, предделитель сброшен. В R22 заготовка для TCCR1B.
Основной цикл. Пока Т=0 - крутимся вначале.
Прерывание. По первому заходу всё ясно - запускаем счётчик, сбрасываем флаг из R30 и в основной цикл. А вот второй заход (с переходом на метку ZAHVAT) мне не совсем понятен. Я бы сократил его до

Код: Выделить всё

ZAHVAT:
   in Temp1,ICR1L    ;копируем значение регистра захвата
   in Temp2,ICR1H
   SET  ;устанавливаем бит Т
EXT:
RETI
Ведь после этого мы попадаем в LOOP с Т=1. Нас пропустит на вывод на индикатор и задержку. А в конце вы поставили

Код: Выделить всё

rjmp   RESET
А там все необходимые настройки таймера и флагов уже прописаны. Так-что все манипуляции с регистрами в прерываниями я считаю излишними.
И последний вопрос. Если вы убрали очистку ОЗУ из блока стартовой инициализации, что очистит TCNT1?
Это Спарта! В смысле, ассемблер. Все ручками.
akl
Друг Кота
Сообщения: 4475
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Сообщение akl »

[uquote="a1000",url="/forum/viewtopic.php?p=3909483#p3909483"]...убрали очистку ОЗУ из блока стартовой инициализации, что очистит TCNT1?[/uquote]Область адресов RAM и область регистров I/O разные. А так, да просто не включил при инициализации

Код: Выделить всё

   ;настройка таймера1
   ldi Temp1, 0b00000000
   out TCCR1A, Temp1

;   CLR Temp1         ;обнуляем счётчмк
   out TCNT1H,Temp1
   out TCNT1L,Temp1
;================
;   LDI   R16,1<<PSR10
;   OUT   SFIOR,R16   ; обнулить предделитель таймера
;================
Убрал очистку предделителя при инициализации. Лучше её делать в начале измерения, чтобы счет вкупе с предделителем начинался с одного и того же места.

Код: Выделить всё

TIM1_CAPT:            ;обработчик прерывания по захвату таймера 1
   SBRS R30,0   
   rjmp ZAHVAT

   LDI   R16,1<<PSR10 ;!!!!!!!!!!!!!!!!!!
   OUT   SFIOR,R16      ;!!!!!!!!!!!!!!!

   OUT   TCCR1B,R22
   CBR   R30,1<<0
   rjmp EXT
ZAHVAT:
Первый раз сказал Мяу!
Аватара пользователя
Сообщения: 31
Зарегистрирован: Вс окт 18, 2020 19:01:52
Откуда: Харьковская область

Сообщение a1000 »

Да, область регистров I/O при такой очистке не затрагиваются. Попробую вечером объединить свой код с вашим.
Это Спарта! В смысле, ассемблер. Все ручками.
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1394
Зарегистрирован: Ср янв 30, 2008 17:52:55

Сообщение vistador »

Подскажите пожалуйста..
Вот читаю ДШ на Тини13...

Про внешние прерывания..
Там написано что прерывания осуществляются от пинов: INT0 и PCINT0....PCINT5. с последними все понятно... но вот INT0 на каком выводе ???
Или я чтото не понял...?
Вложения
IMG_20201028_010908.jpg
(79.3 КБ) 226 скачиваний
akl
Друг Кота
Сообщения: 4475
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Сообщение akl »

Для soic
PB1 (MISO/AIN1/OC0B/INT0/PCINT1)
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1394
Зарегистрирован: Ср янв 30, 2008 17:52:55

Сообщение vistador »

[uquote="akl",url="/forum/viewtopic.php?p=3913981#p3913981"]Для soic
PB1 (MISO/AIN1/OC0B/INT0/PCINT1)
[/uquote]
Большое спасибо...

Пс
Вот я лох...
Не заметил...
Вложения
IMG_20201028_015235.jpg
(43.43 КБ) 207 скачиваний
Встал на лапы
Сообщения: 102
Зарегистрирован: Ср дек 25, 2019 21:17:31
Откуда: Саратов

Сообщение Игорь_396 »

Всем доброго дня. Завалялось у меня несколько штук attiny261, ради интереса решил попробовать запустить PWM6 Mode. Даташит изучал как мог, с помощью гуглопереводчика. Попробовал в протеусе - на выходах сигнала нет. В железе еще не собирал.. Подскажите, где ошибка? CKSEL fuses 0001, SUT1..0 = 10.
Код инициализации таймера1 под спойлером.

Код: Выделить всё

  ldi temp, 0b00111111  ; выводы ШИМ на выход (6 PWM)
		  out ddrb, temp        ;        
            
;        t1
                  ldi temp, 1<<PLLE ; включаем PLL
		  out PLLCSR, temp  ;

		  in temp, PLLCSR   ; ждем установки
		  sbrs temp, PLOCK  ; бита PLOCK 
		  rjmp PC-2         ;
                  ldi temp, 1<<PCKE|1<<PLLE ; включаем прескалер
		  out PLLCSR, temp  ;

                  ldi temp, 1<<DTPS10; Dead Time
		  out TCCR1B, temp     ;
		  ldi temp, 0b00110011 ;
		  out DT1, temp        ;

		  ldi temp, 1<<COM1D0|1<<PWM1D;
		  out TCCR1C, temp    ;
                  ldi temp, 1<<WGM11 ;
		  out TCCR1D, temp   ;
		  ldi temp, 1<<COM1A0|1<<COM1B0|1<<PWM1A|1<<PWM1B; PWM6, ïîäêë âûõîäû.
		  out TCCR1A, temp   ;

		  ldi temp, 1        ; 341
		  out TC1H, temp     ;
		  ldi temp,85        ;
		  out  OCR1A, temp   ;
И еще вопрос возник - что за регистр на фото? Не нашел про него описания в ДШ. По названию вроде бы понятно, что он должен делать, но в него ничего не пишется и адрес его странный. [img][img]https://img.radiokot.ru/files/138172/thumbnail/2e26kx6sqy.png[/img][/img]
akl
Друг Кота
Сообщения: 4475
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Сообщение akl »

Стартовать тоже нужно
Спойлер

Код: Выделить всё

	ldi temp, 0b00111111  ; выводы ШИМ на выход (6 PWM)
	out ddrb, temp        ;       
           
	ldi temp, 1<<PLLE ; включаем PLL
	out PLLCSR, temp  ;

         in temp, PLLCSR   ; ждем установки
         sbrs temp, PLOCK  ; бита PLOCK
         rjmp PC-2         ;
           ldi temp, 1<<PCKE|1<<PLLE ; включаем прескалер
         out PLLCSR, temp  ;

	LDI R21,1<<DTPS10; Dead Time
	out TCCR1B,R21     ;
;	ldi temp, 1<<DTPS10; Dead Time
;	out TCCR1B, temp     ;

         ldi temp, 0b00110011 ;
         out DT1, temp        ;

	ldi temp, 1<<PWM1A|1<<COM1A1|1<<COM1B1; PWM6, iiaee auoiau.
;????	lldi temp, 1<<PWM1A|1<<COM1A1|1<<COM1B1; PWM6, iiaee auoiau.
         out TCCR1A, temp   ;
         ldi temp, 1<<COM1D1 ;
         out TCCR1C, temp    ;
           ldi temp, 1<<WGM11 ;
         out TCCR1D, temp   ;

         ldi temp, 1        ; 341
         out TC1H, temp     ;
         ldi temp,85        ;
         out  OCR1A, temp   ;
         ldi temp,75        ;
         out  OCR1B, temp   ;
         ldi temp,65        ;
         out  OCR1C, temp   ;

	LDI R21,1<<DTPS10|1<<CS10; Старт Dead Time+F_CPU/1
	out TCCR1B,R21     ;

	RJMP	PC
По регистру :dont_know:
Первый раз сказал Мяу!
Аватара пользователя
Сообщения: 31
Зарегистрирован: Вс окт 18, 2020 19:01:52
Откуда: Харьковская область

Сообщение a1000 »

Всем счастливого нового года!
Прикупил на али такую приблуду
Изображение
Называется LED-матрица 8x8 с драйвером max7219. Поигрался с ней в среде Arduino и решил запустить её на ASM. МК atmega8. Включение отдельных пикселей реализовал без проблем. Решил сделать бегущий огонёк в первой строке. Вот код
Спойлер

Код: Выделить всё

.CSEG
;=============
; Таблица прерываний
    .ORG 0x00
        RJMP	RESET			

;=============
; ***** ПОДПРОГРАММы РАБОТЫ С MAX7219
SPI_transfer:     ;отправка данных (Temp5 - команда, Temp6 - данные)
    cbi PORTB, 2 // Вывод SS на 0
	OUT SPDR, Temp5 ;отправляем команду
vozvr_1:	
	sbis SPSR, SPIF ;ждём отправки    
    rjmp vozvr_1
	sbi PORTB, 2 // Вывод SS на +5
	cbi PORTB, 2 // Вывод SS на 0
	OUT SPDR, Temp6 ;отправляем данные
vozvr_2:	
	sbis SPSR, SPIF ;ждём отправки    
    rjmp vozvr_2
	sbi PORTB, 2 // Вывод SS на +5
	RET          


delay_01:         ;задержка 0,1 сек 
; delaying 799995 cycles:
          ldi  R17, $5F
WGLOOP0:  ldi  R18, $17
WGLOOP1:  ldi  R19, $79
WGLOOP2:  dec  R19
          brne WGLOOP2
          dec  R18
          brne WGLOOP1
          dec  R17
          brne WGLOOP0
; ----------------------------- 
; delaying 3 cycles:
          ldi  R17, $01
WGLOOP3:  dec  R17
          brne WGLOOP3
; ----------------------------- 
; delaying 2 cycles:
          nop
          nop
		  RET
; =========== 


; ***** КОНЕЦ ОБЛАСТИ ПОДПРОГРАММ******
;=============
; Прерывание по сбросу, стартовая инициализация 
RESET:	
    ; Инициализация стека
    LDI 	Temp1, LOW(RAMEND)
    OUT 	SPL, Temp1
    LDI 	Temp1, HIGH(RAMEND)	
    OUT 	SPH, Temp1
    
    CLI  ; Глобальный запрет прерываний
    
	
    ; настройка SPI
    ldi temp1,0b00101100 // SS, SCK, MOSI на выход
    out DDRB, temp1 // Отправляем в конфигуратор порта
    sbi PORTB, 2 // Вывод SS на +5 
    ldi temp1, 0b01010000 // Настраиваем SPI, SPE = 1 это разрешит протокол;
    out SPCR, temp1 // MSTR = 1 говорит что мы руководим посылкой
	

	; ***** ИНИЦИАЛИЗАЦИЯ МИКРОСХЕМЫ ******
	;режим "НЕ ТЕСТ"
	LDI 	Temp5, 0x0F
	LDI 	Temp6, 0x00
	RCALL SPI_transfer

	;режим "НЕ СОН"
	LDI 	Temp5, 0x0C
	LDI 	Temp6, 0x01
	RCALL SPI_transfer

	;яркость
	LDI 	Temp5, 0x0A
	LDI 	Temp6, 0x08
	RCALL SPI_transfer

	;режим "ВСЕ ИНДИКАТОРЫ"
	LDI 	Temp5, 0x0B
	LDI 	Temp6, 0x07
	RCALL SPI_transfer

	;режим "БЕЗ ДЕКОДЕРА"
	LDI 	Temp5, 0x09
	LDI 	Temp6, 0x00
	RCALL SPI_transfer

	;очистка
	CLR     Temp6
	LDI 	Temp4, 0x08
	m01:
	MOV     Temp5, Temp4
	RCALL SPI_transfer
	DEC     Temp4
	tst Temp4
    BRNE m01 


	; ***** КОНЕЦ ИНИЦИАЛИЗАЦИИ ******

	LDI 	Temp6, 0b00000001

	Proga: // Основная программа
	
	LDI 	Temp5, 0x01
	RCALL SPI_transfer
	rol     Temp6
	RCALL delay_01
	
	rjmp Proga
Огонёк бежит, но почему-то постоянно светятся первые пиксели во второй, четвёртой и восьмой строках. Выглядит это так

Не могу понять где косяк, подскажите.
Это Спарта! В смысле, ассемблер. Все ручками.
akl
Друг Кота
Сообщения: 4475
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Сообщение akl »

Не понятно дергание лапы PORTB,2/SS. Для защелки MAX7219 лапа PB2/SS не подходит

Код: Выделить всё

;=============
.equ	LOAD=PB1
; ***** ПОДПРОГРАММы РАБОТЫ С MAX7219
SPI_transfer:     ;отправка данных (Temp5 - команда, Temp6 - данные)
	CBI PORTB,LOAD //
;    cbi PORTB, 2 // Вывод SS на 0
   OUT SPDR, Temp5 ;отправляем команду
vozvr_1:   
   sbis SPSR, SPIF ;ждём отправки   
    rjmp vozvr_1
;   sbi PORTB, 2 // Вывод SS на +5
;   cbi PORTB, 2 // Вывод SS на 0
   OUT SPDR, Temp6 ;отправляем данные
vozvr_2:   
   sbis SPSR, SPIF ;ждём отправки   
    rjmp vozvr_2
	SBI	PORTB,LOAD
;   sbi PORTB, 2 // Вывод SS на +5
   RET
Первый раз сказал Мяу!
Аватара пользователя
Сообщения: 31
Зарегистрирован: Вс окт 18, 2020 19:01:52
Откуда: Харьковская область

Сообщение a1000 »

Попробовал поменять РВ2 на РВ1 и РВ0 - вообще не запустилось. Включает тестовый режим и всё. Это когда светят все пиксели. Убрал дёрганье ножкой между посылкой первого и второго байта - стало работать как надо на РВ2.
Это Спарта! В смысле, ассемблер. Все ручками.
Ответить

Вернуться в «AVR»