уменьшение размера прошивки)
- Войдите на сайт для отправки комментариев
Пт, 02/03/2012 - 05:15
Очень хочется запихнуть проект в tiny13, у нее всего килобайт памяти. Пока выходит 1174 байта..
Чем можно заменить digitalRead на си? Пробовал bitRead(PORTB, X) - не работает. Есть ли возможность построить низкочастотный (100 - 500гц) ШИМ без analogWrite? Больно много кушает..
софтинка как то так смотрится
//cars lamp day light #define LAMP1 0 #define LAMP2 1 #define BLINK 2 #define ACC 3 #define BAD 4 #define MAX 100 //vars boolean state = false; long prt; long offtime; void setup() { DDRB = B00000011; PORTB = B00011100; } void loop() { if (prt < millis() - 100) { prt = millis(); if (!state && digitalRead(ACC)==LOW && digitalRead(BAD)!=LOW) { state = true; lamp_on(); } if (state) if (digitalRead(ACC)!=LOW || digitalRead(BAD)==LOW) { if (offtime > millis() - 5000) { state = false; lamp_off(); } else offtime = millis(); } } } void lamp_on() { /*for (int x=0; x <= MAX; x++) { analogWrite(LAMP1, x); analogWrite(LAMP2, x); delay(10); } */ bitSet(PORTB,LAMP1); bitSet(PORTB,LAMP2); } void lamp_off() { /*for (int x=MAX; x >= 0; x--) { analogWrite(LAMP1, x); analogWrite(LAMP2, x); delay(10); } */ bitClear(PORTB,LAMP1); bitClear(PORTB,LAMP2); }
1. Что-то не нашел у вас неработающий bitRead (ну хотя бы закомментаренный).
2. Что значит - "не работает"?
3. Чего "больно много кушает"?
Почитайте http://arduino.ru/Tutorial/Upravlenie_portami_cherez_registry
Не совсем ясно зачем вам вообще этот bitSet нужен
Ну и, естественно, не забываем перед тем как читать/писать для каждого пина выставить правильно режим.
Для чтения данных рекомендуется использовать не регистр PORTx, а другой - специально предназначенный для чтения - PINx (кстати, читать из него можно даже если соответствующий пин настроен как выход). Почитать об этом можно, например, здесь, либо - поподробнее - у diHALT'а.
Огромное спасибо! Это - именно то что мне надо было.
>Что-то не нашел у вас неработающий bitRead (ну хотя бы закомментаренный).
Сейчас там его нет, конечно. Пробовал вместо digitalRead конструкцию if bitRead(PORTB, 5) == 1
>Чего "больно много кушает"?
памяти )))
Комиксы у дихалта убили))
Есть ли возможность построить низкочастотный (100 - 500гц) ШИМ без analogWrite?
Теоретически возможно настроить на 122, 244, 488 Гц (при тактовой частоте процессора 16 МГц, на 488 Гц штатные ШИМы работают). Вам любая частота из этого диапазона подойдет или несколькими частотами оперировать хоцца?
да любая, мне лампочкой на 12в рулить, там от 100гц побарабану. Таймер? И инвертировать булевую?
Таймер на тини13/тини45 надо изучать..
Тактовая кстати 8мгц, камень - тини45/тини13 )
Покажите, пожалуйста, на примере этой конструкции:
if (PINB2 == LOW) компилится, но не срабатывает..
Ну, для tiny я ШИМ не настраивал, проверить свои мысли в железе не могу, так что давайте вместе.
Загружаем Datasheet (у меня - на ATtiny13), в разделе "Peripheral Features" читаем:
Для настройки ШИМ-функций одного из каналов таймера/счетчика (A или B) необходимо прежде всего выбрать режим работы таймера/счетчика (биты WGM2...WGM0 в регистрах TCCR0A и TCCR0B). Для необходимого нам Fast PWM эти биты необходимо установить в 3 или 7 - т.е. бит WGM2 (третий в регистре TCCR0B) на этапе первого запуска ШИМа не имеет значения (хотя и весьма важен - (табл. 11-3 в разделе 11.9.1 на стр. 72 моего даташита)).
Биты WGM1 и WGM0 - это соответственно первый и нулевой биты регистра TCCR0A. В этом же регистре седьмой и шестой биты (COM0A1 и COM0A0) отвечают за настройку выхода. Нам важно его включить - то есть любая комбинация, кроме 00 (табл. 11-3 в разделе 11.9.1 на стр. 70) . Пусть будет "11" ("Set OC0A on Compare Match, clear OC0A at TOP").
TCCR0A = 0xC3; //b11000011
Теперь биты регистра TCCR0B:
седьмой и шестой имеют значение лишь в не-ШИМ-режимах.
пятый и четвертый - не используются
третий - WGM2 - установим в 0, но возьмем на заметку для дальнейшей работы
три первых - настройка предделителя и источника тактового сигнала - запишем сюда максимальное значение для предделителя (самого медленного ШИМа) при работе от внутреннего тактового генератора (который и АЛУ тактирует).
TCCR0B = 0x17; //b00010101
TIMSK0 - регистр-маска прерываний. Не трогаем - я еще не программировал ШИМов, но по идее - при выполненных нами настройках, схема таймера/счетчика должна напрямую дергать ногу OCn. Что такое OCn? Пин, на который соответствующий ШИМ-канкл (A/B) выводит свой сигнал. В даташите на стр. 2 (раздел 1 - распиновка) видим, что дополнительная функция OC0A доступна на пине 5, а OC0B - на пине 6. К этому пину и подключаем нагрузку, которой необходимо управлять.
Итак:
Все? Нет - забыли задать скважность. В канале A за это отвечает регистр OCR0A. Диапазон значений от 0 (скважность 100%) до 255 (скважность 0%). Для теста устанавливаем какую-то постоянную величину в setup(), при программном управлении - меняем значение либо в любой момент (тогда могут получаться отдельные импульсы со случайной скважностью), либо в ISR (вот тут и получаем потенциальную коллизию с ардуиновской системой отсчета времени).
Окончательно:
Хотя, какое окончательно - это только начало бодания. :)
Дальше ваш ход.
Все понял, AVR студио стоит, протеус стоит, если что и тини13 лежит - будем пробовать )
Вечером, с работы прибуду - раз пять перечитаю и приступлю. Пост - в мемориз, однозначно (в смысле, в копилку знаний).
step962, по второму вопросу - как аналогично (PINB & B00000001) проверить на нужном выводе низкий уровень?
UPD возможно, !(PINB & B00000001)
Ну так
if(!(PINB & B00000001))
даст нужную проверку. Операцией "&" мы обнуляем все биты, кроме проверяемого, а дальше, если результат равен нулю, то имеем низкий уровень, если не равен - высокий.
Для одного бита можно писать
где x - номер проверяемого бита. Оно дидактичней как-то получается, а с учетом того, что в сях для мк определено море констант, обеспечивающих более удобный доступ к нужным битам регистров, то и тем более рекомендуемо.
Например, настройка упоминавшихся битов WG2-WG0 и предделителя (правда, не на ту конфигурацию, что рассматривалась ранее):
и все сразу так понятненько становится ;)
(в папке arduino сходить в hardware\tools\avr\avr\include\avr и ознакомиться с имеющимися там хидерами, например, с iom328p.h)
Спасибо, и правда, понятнее намного )))) И ведь сталкивался уже с таким применением побитовых операторов, не вспомнил вовремя ))
Мало времени на ардуино остается.. час вечером и попаять и пописать..
Не работает
Работает
ATTINY45 в протеусе. Замена PORTB на PINB ничего не меняет..
Не работает
Работает
А что такое BAD и ACC? В смысле - какие значения имеют эти константы? Скорее всего это номера пинов Ардуины. Предположим на секунду, что BAD равен 14. Или хотя бы 8.
Операция 1<<8 сдвигает биты в байте (порту) на 8 позиций влево, т.е. самый правый бит уходит за левую границу байта (порта). Что-то не сходится, правда? Может быть оперируя пинами мк напрямую, а не через функции Ардуино, и номера пинов брать атмеловские, а не ардуиновсие? Как вам такая идея? ;)
В общем - найдите картинку с распиновкой мк в соответствующей Ардуине и переведите BAD/ACC в номера битов соответствующих портов. Тот же 8-й пин - в PB0 (нулевой бит порта B), а 14-й (это он у нас 0-й аналоговый?)- в PC0 (нулевой бит порта C).
И будет вам счастье... Возможно.
ЗЫ: digitalRead и прочие analogWrite, прежде чем обратиться к физическому выводу мк, как раз этим самым ремаппингом и занимаются.
ACC=3, BAD=4.
http://www.atmel.com/Images/2586S.pdf
ACC=PB3, BAD=PB4
Совпадение пинов с ардуиновскими - плюс разработчикам кода аттини для ардуино )
в чем то другом дело..
pins_arduino.h
Ну, раз с константами по счастливой случайности все в порядке без ремаппинга, пробуем еще одну версию.
Если не ошибаюсь, в Arduino режим ввода/вывода пинов автоматически устанавливается на вывод. Если соответствующая библиотека в погоне за миниатюрностью кодов выключена, то состояние пина может оказаться не тем, что нам надо. Поэтому настроим пины PB3/PB4 на выход явно. Для этого в соответствующие биты регистра направления DDRx (в нашем случае DDRB) записываем единички (на всякий случай не трогая все остальные биты - поэтому через or):
DDRB |= b00011000;
Повторяем попытку.
ЗЫ: Тьфу ты блин. На вывод у нас 0-й и 1-й биты. 3-й и 4-й - на ввод. Выполняем настройку выводов в два присеста - сначала выводы, потом вводы:
DDRB |= b00000011;
DDRB &= ~b00011000; (то же самое, что и DDRB &= b11100111;)
Вообще я четко указываю состояние пинов и режим так:
DDRB = B00000011;
PORTB = B00011100;
0 и 1 - вывод ШИМ, 2,3,4 - входа, срабатывают по LOW.
Ну то есть видимо и не в этом дело..
Как обычно, если есть проблема, то самый лучший способ ее решения - по частям.
1-й вопрос: работает ли ШИМ? Проверить можно, подключив к соответствующему выводу светодиод.
2-й вопрос: правильно ли считываются состояния входов? проверяем периодическим выводом значения PINB в Serial.
Я тут между делом проверку ШИМа наваял:
Яркость штатного светодиода довольно плавно меняется туда-сюда - так что ШИМ настраивается. Конечно это второй таймер/счетчик, а не нулевой, но идеология у них идентичная, второй от нулевого по большому счету лишь наличием асинхронного режима отличается.
ШИМом займусь на днях, буду перечитывать и вникать в этот топик. вопрос как бы не срочный, на тестах analogWrite спасает - вопрос в "своем" шиме только чтобы уменьшить прошивку.
Больше сейчас зациклен на проверке состояния пинов. Сдается мне, на "стандартной" атмеге8 / 328 все будет работать, а на АтТини есть какой то нюанс..
Соберусь с силами попозже - буду пробовать, отпишусь. Спасибо!
В общем то, с ШИМом под аттини в иде непрошло. http://my.jetscreenshot.com/1474/20120309-idei-41kb
На всякий случай (вдруг не видели).
Ссылочка code.google.com/p/arduino-tiny/
реализация базовых arduino библиотек, под attinny.
Если не взять, то хоть "подсмотреть" в них. Ту же работу с PWM.
Да, не встречал. Точнее, работал с более ранней - точнее, другой веткой проекта.
Просто заработать - не заработало, буду подсматривать )
Ну. с учетом того, что ATtiny13 обладает одним-единственным таймером/счетчиком с номером 0, регистры типа TCCR2A, TIMSK2 и протчая (а также вектора прерываний с индексами "2") в соответствующем хидере не прописаны. Все двойки необходимо заменить нуликами. Поток ругани должен уменьшиться.
скомпилировалось
Догадался сам))))
Завелось. Но только..
http://my.jetscreenshot.com/1474/20120309-qbpo-82kb
похоже, при OCR0A = 0; у нас наоборот.. 100% ШИМ )
И теперь надо научится отключать таймер) Я так понимаю, TCCR0A = 0; его отключит?
Завелось. Но только..
http://my.jetscreenshot.com/1474/20120309-qbpo-82kb
похоже, при OCR0A = 0; у нас наоборот.. 100% ШИМ )
Очень торможу. Брал сигнал оссицилографу с затвора мосфета, он туда инвертированным приходит.
Фронта местами грустные конечно.. С МК - нормальные, с транзисторов - жуть..
И теперь надо научится отключать таймер) Я так понимаю, TCCR0A = 0; его отключит?
Нет, это его убьет. ;)
После такого насилия схема таймера/счетчика станет работать в свем простейшем - "нормальном" - режиме. Именно как таймер - каждые 256 (или 256*значение предделителя) будет происходить переполнение счетчика и генерация прерывания TOV0.
Чтобы отключить ШИМ по каналу A, достаточно обнулить 7-й и 6-й биты:
TCCR0A |= 0x3F;
При таком варианте отключения можно продолжать работать с ШИМом по каналу B (если он был настроен и использовался до этого).
Чтобы отключить прерывания - сбросить соответствующие биты регистра TIMSK0.
Вообще-то таймер очень живуч: чтобы остановить его полностью, придется перейти в такой режим энергопотребления, в котором останавливается осциллятор портов ввода/вывода ("ADC Noise Reduction" или - о ужас - "Power-Down"). Но во всех этих режимах останавливается и осциллятор ЦПУ - программа стоит и ждет пробуждения. А оно нам надо?
Правда, вход через черную дверь таки есть. И даже два.
1) Если перевести таймер на работу от внешнего источника тактового сигнала (CS2:CS0 в регистре TCCRB0 установить в 110 или 111), а потом выключить этот источник, то таймер замрет, а все остальные схемы микроконтроллера продолжат трудиться.
2) Если упомянутые биты сбросить полностью (CS2:CS0 = 000), то таймер перестанет принимать тактовый сигнал как от внутреннего осциллятора, так и от внешнего источника. Результат - остановка схемы.
Так что выбирайте, что больше всего подходит конкретной задаче.
Понял, спасибо! Я так понимаю, что ардуиновские millis и delay используют этот таймер? Ими пора прекратить пользоваться?
Научите еще как рассчитать частоту PWM (таймера?)
Научите еще как рассчитать частоту PWM (таймера?)
Ну это - в простейшем случае - как два пальца об асфальт.
Берем тактовую частоту микроконтроллера (если мы питаем таймер/счетчик от внутреннего осциллятора). Делим ее на запрограммированное нами значение предделителя, затем еще на 256 (разрядность счетчика). Получаем частоту PWM.
Например, минимальная частота PWM для стандартной ардуины:
16 МГц / 1024 (максимальное значение предделителя) / 256 = 61,03 Гц
А если предделитель на 128 настроен, то получаем 488 Гц - частоту ардуиновских ШИМ-ов.
понял
Суть расчета понял. Как правильно загнать нужное мне в регистры - не могу понять...
Частота МК 8 000 000
Надо что то около 10 000
8000000/4/256 = ~8кгц, нормально. Как мне задать делитель 4?
Если открыть даташит на ATtiny13 (ведь мы о ней говорим?), то в главе 11 можно вычитать, что прескалер в таймере этого камня может настраиваться на 1,8,64,256,1024. Четверки в этом списке нет...
Печально? Да. Но не смертельно.
Вспоминаем, что выбирая режим работы 3 (fast PWM), мы игнорировали еже один режим работы - 7. Который тоже fast PWM. Зачем два одинаковых режима? А они не совсем одинаковые. Если в режиме 3 сброс счетчика происходит при попытке добавить единицу к 255 (т.е. цикл 256 тиков), то в режиме 7 сброс счетчика происходит, когда его значение сравняется с значением в регистре OCRA.
Поэтому:
- если установлен режим 7 (т.е. дополнительно установлен бит 3 в регистре TCCR0B)
- если предделитель настроен на 8 (биты 2,1,0 в регистре TCCR0B усановлены в 010)
- в регистр OCR0A загружено значение 124
то получаем частоту на выходе не 4 кГц, а 8 (8000000/4/125).
А если в OCR0A загрузим значение 99, то получим 10 кГц: 8000000/8/100=10000
Предупреждаю сразу - я таймер с такими настройками еще не гонял. Предоставляю эту честь вам.
Еще одно замечание - использование этого режима (7) приводит к сужению диапазона изменения PWM-фактора: если в третьем режиме он может принимать значения 0-255, то в вышеприведенных примерах - 0-124 и 0-99 соответственно. Я полагаю, это не слишком тяжелая потеря?
>открыть даташит
Когда я приучусь это делать первым делом? ))))
>ATtiny13
Ну.. пока АтТини45 - в тринадцатую не влазит пока программа, все время не найду разобраться с множеством инфы о PINB
>в регистр OCR0A загружено значение 124
Я думал значение этого регистра - скважность..
Надеюсь, в даташите я найду ответ на вопрос - какие биты ставить для выбора нужного значения предделителя)
>в регистр OCR0A загружено значение 124
Я думал значение этого регистра - скважность..
Ну остаьте же мне право на ошибку!!! ;)
Как я уже упоминал, седьмым режимом еще не баловался, а скакание по нескольким страницам даташита, на которых разбросаны части полезной информации, необходимой для правильного запуска конкретного режима - это как за стадом коров идти. Чуть зазевался, и готово - взрыв.
опть))))
В принципе, задача моя - получить частоту, на которой лампочка не будет "петь", а то очень странно получается - фары вибрируют ;)
Поэтому заморачиваться в нестардартными режимами пока нет смысла - пока не опробованы стандартные. Не подскажете место в даташите где указано, какие биты включать для того или иного значения предделителя? навскидку не нашел, счас пару клиентов выпровожу - сяду искать детальнее..
Таблица 11-9 (стр. 73) даташита на ATtiny13 (в принципе все тиньки имеют 0-й таймер с примерно одинаковой структурой, так что, наверное, и для 45-ки будет то же самое).
Кстати, есть режим 2 - ШИМ с фазовой коррекцией. Если не вдаваться в подробности, его основное отличие от быстрого ШИМА - вдвое меньшая частота на выходе при тех же самых остальных настройках. То есть с его помощью 8 кГц тоже не получить, но вот 16 - пожалуйста (при предделителе, настроенном на 1).
Для начала попробую 4кгц. Итак, что мне стало ясно.
1) Нам нужен Fast PWM
2) Нам нужен предделитель 8
3) Скважность должна изменяться 0..255
Итак, FAST PWM включается
То есть надо установить в 3 или 7 регистры WGM0, WGM1, WGM2. Первые два находятся в регистре TCCR0A (0,1), последний в TCCR0B (3).
Так в 3 или 7? И что значит - "установить в 3", например?
Ответ явно есть тут: The counter counts from BOTTOM to TOP then restarts from BOTTOM.
TOP is defined as 0xFF when WGM0[2:0] = 3, and OCR0A when WGM0[2:0] = 7.
Но пока непонятен толком. Ладно, пропустим, воспользуемся ранее приведенным примером и начнем так:
TCCR0A = B00000011; //включили FAST PWM
TCCR0B пока не трогаем - нужый нам бит в нуле.
Теперь - предделитель. Нам нужен 8. Согласно таблице:
и
и
ставим так: TCCR0B = B00000010
---
ae[,kz ) правильно пока что?)
Также нам надо включить "выход" - на ноги? биты COM0A1 COM0A0
TCCR0A = B11000011;
Получается, чтобы включить обе нужные мне PWM ноги аттини
мне нужны только биты COMA[1..0]?
Похоже нет, чтобы включить пины PB1 и PB0 мне нужно заложить в регистр это: B11110011?
Все таки нужно: 11110011; ибо
Разрешение прерывания:
Осталось разобраться в этом:
И вспомнить, что в приведенном выше примере ШИМирования ноги 13 таймер у нас использовался только для вызова процедур, в которых ногами управляли "вручную". Что мне еще непонятно? назначение COM0A[1:0] and COM0B[1:0]
прекращаю - в голове бардак.. завтра выходной, после отсыпона почитаю еще даташит))))
Смешались в кучу кони, люди.. Комментирование блока
не привело в отключению ШИМа на ногах вышеуказанных) Правда - тинька регулярно виснет, переставая реагировать на свои сигнальные ноги. Резет все возвращает в норму. Может - помирает вже от экспериментов..
Пример инициализации для ATtiny:
Установка бита COM0A1 (при сброшенном COM0A0) активизирует пин OC0A (выход ШИМ-импульсов для канала A) в режиме "Clear OC0A on Compare Match" - низкий уровень на выходе будет присутствовать в период времени между значением, записанным в регистр OCR0A, и 255. И чем больше записанное в OCR0A значение, тем больше энергии получает внешнее устройство. А не наоборот, как в случае "11" (Для настройки канала B необходимо оперировать битами COM0B1 и COM0B0)
Установка битов WGM01 и WGM00 переводит оба (всегда оба - и A, и B) канала таймера/счетчика в режим работы "Fast PWM".
Установка бита CS00 (при сброшенных CS02, CS01) настраивает предделитель на работу без предделения ("clkI/O/(No prescaling)").
Опять-таки - для обоих каналов.
Все. Инструкция
DDRB |= 0x01;
конфигурирует нужный нам пин для вывода.
на всякий случай укажем
sei();
Должно заработать.
В TIMSK0 никаких битов устанавливать не надо - установленный в этом регистре бит естественным образом требует наличия процедуры обработки соответствующего прерывания. Это необходимо, если мы ШИМ "внутри производим и внутри же потребляем". Если же мы добиваемся чисто аппаратного управления внешним устройством без влияния на этот процесс АЛУ (пресловутая многопоточность), то - руки прочь от TIMSK0.
Еще.
Чтобы побыстрее запомнить какие биты чем рулят, следует помнить используемое соглашение о принятых означениях:
YYYxN - комбинация битов YYY оперирует настройками/данными канала x в таймере/счетчике N.
Поэтому все комбинации вида YYYN настраивают оба канала.
Все комбинации, в которых N не равен нулю, относятся к любым другим таймерам/счетчикам, но только не к нулевому (он же единственный в ATtiny13, а может быть и в 45 - не смотрел).
Также нам надо включить "выход" - на ноги? биты COM0A1 COM0A0
TCCR0A = B11000011;
Получается, чтобы включить обе нужные мне PWM ноги аттини
мне нужны только биты COMA[1..0]?
А это, похоже, таки отличие 45-й тиньки от 13-й. В ней два таймера? Видимо, все же придется подгрузить даташит и на этот камень.