Главная > AVR, Just life > Еще немного о мигании светодиодом

Еще немного о мигании светодиодом

Вот тут вот один товарищ хвалился, как ловко он уместил классическое мигание диодом в 24 байта. Он молодец.

На самом деле, такое диодомигание занимает не более 12 байт.

Он там правильно заметил, что для задания задержек надо использовать таймеры. Только вот таймеров в ATtiny15 не два, а три. Да, все забыли про watchdog.

Мигаем диодом в 12 байт — классическое одногерцовое мигание:

 

1| .include "tn15def.inc"
2| 
3|     LDI R16,(1<<WDE) | (1<<WDP2) | (1<<WDP1)
4|     OUT WDTCR,R16
5|     OUT DDRB,R16
6|     COM R17
7|     OUT PORTB,R17
8| L:  RJMP L

 

Для справок нам может понадобиться даташит на ATtiny15.

Как работает этот код:

— строчки 3 и 4: включаем watchdog и настраиваем его срабатывать примерно каждую секунду;

— строчка 5: в R16 у нас уже есть несколько подходящих единиц, запихиваем их в DDRB, чтобы не пропадали зря;

— строчка 6: по-умолчанию после включения во всех РОН нули, однако при «горячем» сбросе содержимое РОН не меняется; ну вот и вычитаем содержимое R17, которое осталось с предыдущего цикла работы, из значения 0xFF;

— строчка 7: выводим в порт измененное значение;

— строчка 8: зависаем в цикле до сброса по watchdog’у.

 

В отличие от исходного решения, здесь нет надежды на авось — прерывания просто не используются, так что место, предназначенное для обработчиков, используется совершенно легитимно (использование этого места при отключенных прерываниях прямо разрешено даташитом).

Кстати, после диодомигания до сброса остается целая вечность — почти секунда. Так что при желании там можно и что-нибудь полезное поделать. Ну там, DS18B20 опросить да результат в EEPROM записать, или еще что…

 

AVRASM: AVR macro assembler 2.1.42 (build 1796 Sep 15 2009 10:48:36)
Copyright (C) 1995-2009 ATMEL Corporation

ATtiny15 memory use summary [bytes]:
Segment   Begin    End      Code   Data   Used    Size   Use%
---------------------------------------------------------------
[.cseg] 0x000000 0x00000c     12      0     12    1024   1.2%
[.dseg] 0x000000 0x000060      0      0      0       0      -
[.eseg] 0x000000 0x000000      0      0      0      64   0.0%

Assembly complete, 0 errors. 0 warnings

 

Вот так, 12 байт.

Для полноты картины, HEX:

 

:020000020000FC
:0C0000000EE001BD07BB109518BBFFCF40
:00000001FF

 

Можно олдскульно руками переписать в блокнот, сохранить с расширением .hex и зашить в МК.

И что бы там ни говорили в комментариях к статье по ссылке, упихивать невпихуемое полезно, это развивает алгоритмическую мысль. А то, действительно, нынче телефоны (!) работают меньше дня на батареях, которых лет десять назад хватило бы на месяц…

Рубрики:AVR, Just life
  1. Роман
    03/02/2015 в 03:10

    ЗЫ: простой пример для чего это может понадобиться когда используется один код для работы с датчиками DHT11 когда каждый датчик подключен к отдельному выводу МК

    • YS
      03/02/2015 в 16:13

      Я проверил в симуляторе — работает.

      
      
      #include <avr/io.h>
      #include <stdint.h>
      
      volatile uint16_t port_addr;
      volatile uint8_t port_value;
      
      #define WRITE_PORT(PORT, VALUE)       (*((volatile uint8_t *)(PORT)))=(VALUE)
      
      void main(void)
      {
        port_addr=(uint16_t)(&PORTB);
      
        port_value=10;
      
        WRITE_PORT(port_addr,port_value);
      
        port_value=0;
      
        while (1)
        {
        }
      }
      

      Дизассемблер:

      
      
      @0000002B: main
      ---- test.c ---------------------------------------------------------------------------------
      10:       {
      +0000002B:   E285        LDI       R24,0x25       Load immediate
      +0000002C:   E090        LDI       R25,0x00       Load immediate
      +0000002D:   93900102    STS       0x0102,R25     Store direct to data space
      +0000002F:   93800101    STS       0x0101,R24     Store direct to data space
      13:         port_value=10;
      +00000031:   E08A        LDI       R24,0x0A       Load immediate
      +00000032:   93800100    STS       0x0100,R24     Store direct to data space
      15:         WRITE_PORT(port_addr,port_value);
      +00000034:   91E00101    LDS       R30,0x0101     Load direct from data space
      +00000036:   91F00102    LDS       R31,0x0102     Load direct from data space
      +00000038:   91800100    LDS       R24,0x0100     Load direct from data space
      +0000003A:   8380        STD       Z+0,R24        Store indirect with displacement
      17:         port_value=0;
      +0000003B:   92100100    STS       0x0100,R1      Store direct to data space
      +0000003D:   CFFF        RJMP      PC-0x0000      Relative jump
      17:         port_value=0;
      +0000003E:   94F8        CLI                      Global Interrupt Disable
      +0000003F:   CFFF        RJMP      PC-0x0000      Relative jump
      
      • Роман
        03/02/2015 в 21:55

        а ну да, регистры же мемори мэппед…

        • Роман
          03/02/2015 в 22:07

          хм а накой тогда там отдельные инструкции in и out ???

          • YS
            04/02/2015 в 12:08

            Во-первых, я подозреваю, что это пережиток прошлого (оставлено для совместимости). OUT налагает ограничение на максимальное значение адреса, и в новых контроллерах часть периферии просто недоступна через OUT — надо использовать STD/STS.

            Даташит, страница 8 раздел 5:

            «For I/O Registers located in extended I/O map, “IN”, “OUT”, “SBIS”, “SBIC”, “CBI”, and “SBI” instructions must be replaced with instructions that allow access to extended I/O. Typically “LDS” and “STS” combined with “SBRS”, “SBRC”, “SBR”, and “CBR”.»

            Это адреса с 0x0060 по 0x00FF. Посмотреть можно на странице 19, картинка 8-3.

            И еще, страница 346, примечание 4 под таблицей с адресами регистров:

            «When using the I/O specific commands IN and OUT, the I/O addresses 0x00 — 0x3F must be used. When addressing I/O Registers as data space using LD and ST instructions, 0x20 must be added to these addresses. The Atmel ATmega48/88/168 is a complex microcontroller with more peripheral units than can be supported within the 64 location reserved in Opcode for the IN and OUT instructions. For the Extended I/O space from 0x60 — 0xFF in SRAM, only the ST/STS/STD and LD/LDS/LDD instructions can be used.»

            Во-вторых, OUT выполняется на один такт быстрее.

  2. Роман
    03/02/2015 в 03:07

    немного не в тему, но фанатам асма понравится:
    как сделать в atmega запись в произвольный порт?
    т.е. чтобы в программе было не

    PORTx = CONST;

    а что-то типа
    int port, val; // т.е. и порт (адрес) и его значение это некие переменные которые могут меняться во время выполнения
    ….

    write_port(port, val);

    ???
    единственный вариант который приходит в голову это самомодифицирующийся код!?
    может кто набросает?

    • YS
      03/02/2015 в 15:59

      По-моему, должно прокатить просто

      *((volatile uint8_t *)(port))=val;

      Разве только возможны проблемы за счет того, что там Гарвардская архитектура, но я думаю, что с вероятностью 99% компилятор разберется, какую инструкцию ставить и все будет работать.

      P.S.

      Вот за что я люблю Си — так это за элементарность приведения типов.

  3. Ононим
    08/11/2014 в 02:56

    Понимаю, что некрофил, но вроде загоняя в регистр PINB единицы, выводы настроенные как выход будут инвестироваться каждый раз. tiny15 относительно новая же и такой финт у неё должен быть, или путаю? Можно сократить программу на одну команду.

    • YS
      08/11/2014 в 16:25

      А чего некрофил-то? Рукописи не горят.🙂

      Я в курсе такой возможности и смотрел в ДШ. ATtiny15 такого не поддерживает, в отличие от серии ATmega. Но в ATmega некоторые нужные команды занимают по два слова, сводя выигрыш в размере на нет. Не все так просто.🙂

      • Vga
        08/11/2014 в 18:09

        С применением некоторых хаков программу на атмеге можно ужать до 2 байт. Правда, на самом деле она будет использовать все те FF-ки, что лежат в флеше, так что в некотором роде программа будет на все 4-8-16кб, что есть в МК. Но исходного кода только одна команда.
        Ну и даже если не пользоваться недокументированными возможностями и хаками, а также содержимым стертого флеша, программа на атмега48 укладывается то ли в 2, то ли в 3 команды — 4 или 6 байт соответственно.

  4. Vga
    01/11/2014 в 16:52

    P.S. Что до телефона с месяцем автономной работы (в спячке, разумеется) — они давно есть. Скажем, Philips Xenium, обычный телефон с батарейкой на 2Ач.

  5. ACE
    28/10/2014 в 22:40

    Резет от вотчдога в качестве цикла — это зачёт, я бы не догадался до такого🙂 Это как другая религия, для меня жизни после резета нет, а тут прям перерождение после смерти и продолжение работы.
    2Vga: Думаю YS имел ввиду то, что раньше мобилы жили с аккумом 500-600-700 мАч до недели, а сейчас с аккумами 2000-2500-3000 мАч должны жить месяц, но увы.

    • Vga
      29/10/2014 в 01:54

      На самом деле на эту тему мы с YS’ом плотно пообщались в скайпе, и понял я его вполне правильно🙂
      Ну и я бы сказал, что старые телефоны эту неделю в ждущем режиме висели, а нынешние — тянут день постоянного активного использования с включенным вайфаем и экраном. Это все же разные вещи и старые телефоны в активном режиме держали даже меньше.

    • YS
      29/10/2014 в 20:36

      Рад что понравилось. Мне тоже кажется, что цикл с ресетом смотрится свежо.🙂

      По идее, это ведь можно использовать и в каких-то практически ценных разработках — получается 90% надежность, даже если программа где-то случайно (единоразово, например, из-за помехи) повиснет (опрос датчика?), то катастрофичного зависания не случится, т.к. следующий цикл работы все равно начнется со сброса.

      Да, мы общались с Vga в Скайпе. Я говорил о том, что при нынешнем прогрессе аккумов и элементной базы телефоны и правда могли бы работать месяцами, если бы, во-первых, код был аккуратнее, а, во-вторых, производители не стеснялись добавить лишние 5 мм к толщине корпуса. Представляете, какой емкости батарею можно было бы уместить в тот же Galaxy, увеличив его толщину всего на 5 мм? Но это же не модно, лучше заставлять заряжаться каждый вечер.

      Ну и отдельный пламенный привет разработчикам горе-телефонов (и планшетов) с Андроидом, имеющих привычку зачем-то включаться примерно каждые полчаса, при этом иногда зависая со 100% загрузкой процессора.

      • Vga
        01/11/2014 в 16:49

        Я бы таки посмотрел, как ты перепишешь код, чтобы браузер с полной поддержкой HTML5, CSS3 и какой-там-последний-JS работал на современной батарейке месяц (да, это именно то, что должен делать смартфон, а вовсе не звонки и валяние в спячке). И не тормозил притом.
        Толщина — уже ближе, но такой аппарат будет сложнее носить и держать — он станет заметно тяжелей.

        Мне тоже кажется, что цикл с ресетом смотрится свежо.

        Это только кажется. Я такое уже встречал. Довольно удобный метод для сбережения батарейки — глушим все SLEEP’ом, периодически просыпаемся по вотчдогу, проверяем есть ли ввод и если нету — падаем обратно.

  6. Vga
    15/10/2014 в 11:03

    Что-то я не видел телефонов, которые работали бы месяц на одном заряде. Именно работали. И даже в режиме ожидания весьма немногие столько протянут. Ну так и мой ведроид в режиме ожидания 2 недели держит, а моя предыдущая нокия — всего неделю.

  1. No trackbacks yet.

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s