Светофор на ATtiny13A

Обсуждаем контроллеры компании Atmel.
Ответить
Потрогал лапой паяльник
Сообщения: 359
Зарегистрирован: Чт авг 08, 2013 01:06:54

Сообщение Пока_без_кота »

Доброго времени суток. Задался целью сделать простой проект на AVR. Начать решил с ассемблера, потому что в обучалке ассемблер. Набрал программу.
Спойлер.include "tn13Adef.inc"

.def Temp =R16
.def Temp1=R17
.def Temp2=R18
.def Temp3=R19

.cseg

ldi Temp,RamEnd ;инициализация стека
out SPL,Temp

ldi Temp,0b111 ;светодиоды подключены на первых 3 портах, поэтому по минимуму лишних букв
out DDRB,Temp

Begin: ldi Temp,0b001
rcall Delay

ldi Temp,0b011
rcall Delay1

ldi Temp,0b100
rcall Delay

ldi Temp,0b000
rcall Delay2

ldi Temp,0b100
rcall Delay2

ldi Temp,0b000
rcall Delay2

ldi Temp,0b100
rcall Delay2

ldi Temp,0b000
rcall Delay2

ldi Temp,0b100
rcall Delay2

ldi Temp,0b010
rcall Delay1

rjmp Begin ;поехали по новой!

;****************************************************
;Задержки (Delay - между Красным и Красным с Желтым, Delay1 - между Красный+Желтый и Зеленым, а также Желтым и Красным, Delay2 - при мигании зеленого)

Delay: out PortB,Temp

ldi Temp1,0
ldi Temp2,0
ldi Temp3,20

Loop: dec Temp1
brne Loop

dec Temp2
brne Loop

dec Temp3
brne Loop

ret

Delay1: out PortB,Temp

ldi Temp1,0
ldi Temp2,0
ldi Temp3,6


Loop1: dec Temp1
brne Loop1

dec Temp2
brne Loop1

dec Temp3
brne Loop1

ret

Delay2: out PortB,Temp

ldi Temp1,0
ldi Temp2,0
ldi Temp3,2


Loop2: dec Temp1
brne Loop2

dec Temp2
brne Loop2

dec Temp3
brne Loop2

ret
Все прекрасно работает, но хочеться научиться оптимизировать программы. В учебке прочитал про вывод задержек в отдельные процедуры, сделал. Но дальше никак не соображу, как еще можно "укомпактнить". Сдвиг сдесь нельзя применить, ведь по алгоритму работы светофора иногда должно одновременно гореть 2 света (Красный+Желтый). Может можно как-то сделать 1 задержку вместо 3 и просто разбить ее на части, вызывая каждый раз с нужного места ?
Переходить сразу на прерывания, матрицы, произвольно задаваемые массивы как в учебке, просьба не предлагать, я сперва из этого метода хочу все соки выжать.
Последний раз редактировалось Пока_без_кота Пт май 09, 2014 19:37:23, всего редактировалось 1 раз.
Реклама
Вымогатель припоя
Аватара пользователя
Сообщения: 577
Зарегистрирован: Ср июн 19, 2013 08:10:48
Откуда: Москва, СПб, Липецк, Рязань

Сообщение ИС-пытатель »

А что не хотите сделать загрузку значения задержки перед вызовом самой задержки? тогда у вас получится всего одна процедура, реализующая задержку, а значение для нее Вы вносите перед вызовом этой процедуры.

Или еще вариант.
Делаете что-то вроде флагов. И отдельные переменные для задержек каждого цвета.
Включаете нужные цвета, взводите флаги, инициализируете переменные для каждого цвета. В цикле увеличиваете/уменьшаете значение переменных с одновременной проверкой флагов. Когда переменные достигают нужного значения - сбрасывате флаги и выключаете цвета.
Реклама
Мучитель микросхем
Аватара пользователя
Сообщения: 444
Зарегистрирован: Вс ноя 28, 2010 15:18:52
Откуда: Минск

Сообщение ANALOG »

ИС-пытатель писал(а):А что не хотите сделать загрузку значения задержки перед вызовом самой задержки?
Врядли автор не хочет, пишет же, что только начал разбираться, не знает с чего начать :)
Ну а так да, кроме объединения задержек в одну тут особо ничего не оптимизируешь без таймеров/прерываний.
Но оптимизация - тоже штука хитрая, увлекаться особо не стоит, иногда это делает код очень узкоспециализированными непригодным даже для малейших переделок. Так что тут надо знать золотую середину :) (разумеется, с передачей параметра времени задержки проблем нет, тут только повышается универсальность кода)

А то, что с ассемблера решили начать - это очень правильно, начинать изучение AVR с С - дохлый номер, потом для людей это все превращается в темный лес.

Ну а в прерываниях тоже ничего особо сложного нет, особенно если оно только одно в программе, а когда разберетесь с одним - правильно все организовать для нескольких труда не составит. :)
Еще перед изучением прерываний можно бы разобраться с массивами во flash-памяти и с работой с оперативкой (хотя я в свое время сначала прерывания изучил), но я не особо представляю, как это можно применить в поставленной задаче

Желаю успехов в этом интересном деле :beer: :wink:
Потрогал лапой паяльник
Сообщения: 359
Зарегистрирован: Чт авг 08, 2013 01:06:54

Сообщение Пока_без_кота »

Спасибо за подсказки. Пока получилось так:
Спойлер.include "tn13Adef.inc"

.def Temp =R16
.def Temp1=R17
.def Temp2=R18
.def Temp3=R19

.cseg

ldi Temp,RamEnd ;èíèöèàëèçàöèÿ ñòåêà
out SPL,Temp

ldi Temp,0b111
out DDRB,Temp

Begin: ldi Temp,0b001
rcall Delay

ldi Temp,0b011
rcall Delay1

ldi Temp,0b100
rcall Delay

ldi Temp,0b000
rcall Delay2

ldi Temp,0b100
rcall Delay2

ldi Temp,0b000
rcall Delay2

ldi Temp,0b100
rcall Delay2

ldi Temp,0b000
rcall Delay2

ldi Temp,0b100
rcall Delay2

ldi Temp,0b010
rcall Delay1

rjmp Begin ;ïîåõàëè ïî íîâîé!

;****************************************************
;Çàäåðæêè

Delay: out PortB,Temp

ldi Temp1,0
ldi Temp2,0
ldi Temp3,20
rjmp Loop

Delay1: out PortB,Temp

ldi Temp1,0
ldi Temp2,0
ldi Temp3,6
rjmp Loop

Delay2: out PortB,Temp

ldi Temp1,0
ldi Temp2,0
ldi Temp3,2
rjmp Loop

Loop: dec Temp1
brne Loop

dec Temp2
brne Loop

dec Temp3
brne Loop

ret
Раньше код занимал 11.6% памяти, сейчас 9.2%, мелочь, а приятно. Будет интересно посмотреть, насколько еще удастся ужать более прогрессивными методами, но это уже будет после их изучения, если не забуду, может и отпишусь здесь.
Реклама
Эиком - электронные компоненты и радиодетали
Мучитель микросхем
Аватара пользователя
Сообщения: 444
Зарегистрирован: Вс ноя 28, 2010 15:18:52
Откуда: Минск

Сообщение ANALOG »

Вот, посмотрите еще такой вариант:
Спойлер

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

.include "tn13Adef.inc"

.equ RED_DELAY    = 20
.equ YELLOW_DELAY = 6
.equ GREEN_DELAY  = 20
.equ BLINK_DELAY  = 2
.equ BLINK_COUNT  = 3   ; [1-255]

.equ RED    = 0         ; PB0
.equ YELLOW = 1         ; PB0
.equ GREEN  = 2         ; PB2

.def Temp   = R16
.def Temp1  = R17
.def Temp2  = R18
.def Time   = R19

.cseg

;****************************************************
;RESET:

ldi Temp,RamEnd
out SPL,Temp

ldi Temp, (1<<RED) | (1<<YELLOW) | (1<<GREEN)
out DDRB,Temp

Begin:
        ldi Temp, (1<<RED)
        out PortB, Temp
        ldi Time, RED_DELAY
        rcall Delay

        ldi Temp, (1<<RED) | (1<<YELLOW)
        out PortB, Temp
        ldi Time, YELLOW_DELAY
        rcall Delay

        ldi Temp, (1<<GREEN)
        out PortB, Temp
        ldi Time, BLINK_DELAY
        rcall Delay

        ldi Temp2, BLINK_COUNT
    Blink:
            ldi Temp, 0
            out PortB, Temp
            ldi Time, BLINK_DELAY
            rcall Delay

            ldi Temp, (1<<GREEN)
            out PortB, Temp
            ldi Time, BLINK_DELAY
            rcall Delay

            dec Temp2
            brne Blink

        ldi Temp, (1<<YELLOW)
        out PortB, Temp
        ldi Time, YWLLOW_DELAY
        rcall Delay

rjmp Begin

;****************************************************
;DELAY:

Delay:
        clr Temp
        clr Temp1
    Loop:
                dec Temp
                brne Loop
            dec Temp1
            brne Loop
        dec Time
        brne Loop
	ret
Не уверен, что тут кода получилось меньше, но если надо мигать зеленым больше, чем 2 раза, то будет меньше, т.к. мигание сделано в цикле (число миганий настраивается с помощью BLINK_COUNT) и не уверен что вообще работает, не проверял :)))
Ну и тут вам пример работы с директивой .equ и побитовыми сдвигами констант. Без прерываний думаю, тут уже ничего не оптимизируешь
Реклама
Потрогал лапой паяльник
Сообщения: 359
Зарегистрирован: Чт авг 08, 2013 01:06:54

Сообщение Пока_без_кота »

Спасибо за проделанную работу, буквально немного подправил и все завелось (замигало, засветилось).
Спойлер.include "tn13Adef.inc"

.equ RED_DELAY = 20
.equ YELLOW_DELAY = 6
.equ GREEN_DELAY = 20
.equ BLINK_DELAY = 2
.equ BLINK_COUNT = 3 ; [1-255]

.equ RED = 0 ; PB0
.equ YELLOW = 1 ; PB1
.equ GREEN = 2 ; PB2

.def Temp = R16
.def Temp1 = R17
.def Temp2 = R18
.def Time = R19

.cseg

;****************************************************
;RESET:

ldi Temp,RamEnd
out SPL,Temp

ldi Temp, (1<<RED) | (1<<YELLOW) | (1<<GREEN)
out DDRB,Temp

Begin:
ldi Temp, (1<<RED)
out PortB, Temp
ldi Time, RED_DELAY
rcall Delay

ldi Temp, (1<<RED) | (1<<YELLOW)
out PortB, Temp
ldi Time, YELLOW_DELAY
rcall Delay

ldi Temp, (1<<GREEN)
out PortB, Temp
ldi Time, GREEN_DELAY
rcall Delay

ldi Time, BLINK_DELAY
rcall Delay

ldi Temp2, BLINK_COUNT

Blink:
ldi Temp, 0
out PortB, Temp
ldi Time, BLINK_DELAY
rcall Delay

ldi Temp, (1<<GREEN)
out PortB, Temp
ldi Time, BLINK_DELAY
rcall Delay

dec Temp2
brne Blink

ldi Temp, (1<<YELLOW)
out PortB, Temp
ldi Time, YELLOW_DELAY
rcall Delay

rjmp Begin

;****************************************************
;DELAY:

Delay:
clr Temp
clr Temp1

Loop:
dec Temp
brne Loop

dec Temp1
brne Loop

dec Time
brne Loop

ret
Код занимает 8.4% памяти.
Фото получившегося устройства: Изображение
Реклама
Вымогатель припоя
Аватара пользователя
Сообщения: 577
Зарегистрирован: Ср июн 19, 2013 08:10:48
Откуда: Москва, СПб, Липецк, Рязань

Сообщение ИС-пытатель »

:))) ГЫ!
Чувак даже светофор смастерил! )) Красава! Далеко пойдешь с таким усердием! ;)
Потрогал лапой паяльник
Сообщения: 359
Зарегистрирован: Чт авг 08, 2013 01:06:54

Сообщение Пока_без_кота »

Спасибо. Ну смастериол, это конечно слишком громко сказанно, просто хотелось реализовать именно светофор (есть маленький ребенок, любит играться машинками), как-то гулял по улице и увидел на тротуаре разбитую детскую игрушку, в ней был этот пустой корпус от светофора, я поднял, и понял что это судьба меня уже ну просто коленкой в зад толкает на создание сего прибора, и вот сделал, ребенок очень доволен. Благодаря таким сайтам как этот, и людям как Вы (все кто здесь помогает) это становиться возможным, спасибо за это :))
Вымогатель припоя
Аватара пользователя
Сообщения: 577
Зарегистрирован: Ср июн 19, 2013 08:10:48
Откуда: Москва, СПб, Липецк, Рязань

Сообщение ИС-пытатель »

:oops: Спасибо! )
Я здесь тоже многому учусь, хотя уже и многое знаю. И я, кстати, тоже подбираю все, что плохо лежит из электроники.

P.S. К Вашему посту.
Если судьба бьет прямо в лоб - значит не возымели ее пинки в зад! (С. Ежи Лец)
Ответить

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