Поиск по сайту

Результаты поиска по тегам 'avr'.

  • Поиск по тегам

    Введите теги через запятую.
  • Поиск по автору

Тип публикаций


Категории и разделы

  • Вопрос-Ответ. Для начинающих
    • Песочница (Q&A)
    • Дайте схему!
    • Школьникам и студентам
    • Начинающим
    • Паяльник TV
    • Обсуждение материалов с сайта
  • Радиоэлектроника для профессионалов
    • Световые эффекты и LED
    • Роботы и модели на ДУ-управлении
    • Автоматика
    • Самодельные устройства к компьютеру
    • Программное обеспечение
    • Автомобильная электроника
    • Системы охраны и наблюдения. Личная безопасность
    • Питание
    • Электрика
    • Промышленная электроника
    • Ремонт
    • Металлоискатели
    • Измерительная техника
    • Мастерская радиолюбителя
    • Сотовая связь
    • Спутниковое ТВ
    • КВ и УКВ радиосвязь
    • Жучки
    • Телефония и фрикинг
    • Высокое напряжение
    • Идеи и технологии будущего
    • Справочная радиоэлементов
    • Литература
    • Разное
  • Аудио
    • FAQ, Технологии и компоненты
    • Для начинающих
    • Источники звука
    • Предусилители, темброблоки, фильтры
    • Питание аудио аппаратуры
    • Усилители мощности
    • Акустические системы
    • Авто-аудио
    • Ламповая техника
    • Гитарное оборудование
    • Прочее
  • Микроконтроллеры
    • МК для начинающих
    • AVR
    • PIC
    • STM32
    • Arduino и Raspberry Pi
    • ПЛИС
    • Другие микроконтроллеры и семейства
    • Алгоритмы
    • Программаторы и отладочные модули
    • Периферия и внешние устройства
    • Разное
  • Товары и услуги
    • Коммерческие предложения
    • Продам-Отдам, Услуги
    • Куплю
    • Уголок потребителя
    • Вакансии и разовая работа
    • Наши обзоры и тесты
  • Разное
    • Конкурсы сайта с призами
    • Сайт Паяльник и форум
    • Курилка
    • Технический английский (English)
    • Наши проекты для Android и Web
    • FAQ (Архив)
    • Личные блоги
    • Корзина
    • Вопросы с VK
  • ATX->ЛБП Переделки
  • Юмор в youtube Киловольты юмора
  • Надежность и группы продавцов Радиолюбительская доска объявлений exDIY
  • разные темы Переделки

Блоги

Нет результатов для отображения.

Нет результатов для отображения.

Местоположения

  • Пользователи форума

Группа


ICQ


Skype


Интересы


Город


Сфера радиоэлектроники


Оборудование

Найдено 344 результата

  1. Добрый день! От товарища поступила просьба собрать на ардуино (либо изготовить плату на avr) детектор короткого замыкания. Есть у него на производстве ряд БП 12в 2квт и десяток потребителей на каждом, таких блоков порядка сотни, и поступила "хотелка" навесить на каждый БП ардуину (питание будет отдельное независимое) которая будет посылать по wifi уведомление когда будет возникать КЗ в блоке/потребителе (важна возможность определения именно КЗ). Опыта нет, первое что пришло в голову это: 1) мониторить потерю напряжения 12в на БП (при КЗ блок уходит в защиту) 2) при потере напряжения 12в подавать напряжение 3.3в от питания МК с управлением через ключ от ножки МК на "+" питания БП и переход на пп.3 3) ноль от БП подключить к АЦП МК и замерять: если 0в то все норм и КЗ нет (поломка блока без КЗ либо отключение от сети 220в), если на АЦП будет 3.3в то имеем КЗ и отправляем уведомление. Т.к. опыта схемотехники почти нет, прошу помощи по схеме в даже в мелочах
  2. Помогите правильно подобрать элементы. Ниже я опишу своё понимание точно, что нужно для этой схемы, если там будут ошибки поправьте меня. Мне нужна: 1) Источник питания на 5В 2) Светодиод 3) Резистор. Сопротивление завит от рабочего напряжение светодиода, а рассеивающая мощность от тока от источника. 4) Кнопка 5) Земля? 6) 2 конденсатора на 2 нф 7) Кварцовый генератор на 4 МГц Вопросы у меня насчет питания: 1) Что использовать как источник питания 2) Как подключать? Вижу куда + подключать, а куда -? 3) Как питается контроллер 4) Почему если подать в PB.0 единицу, светодиод потухнет?
  3. Есть ли жизнь на Марсе?

    Есть ли жизнь на Марсе, нет ли её там - науке это не известно. Наука пока не в курсе дела. Есть ли жизнь в экосистеме AVR? Или эти мамонты уже вымерли, уступив более теплокровным ARM? По-моему, для неленивого энтузиаста экосистема AVR предоставляет еще множество возможностей. Не смотря на 8 бит и достаточно скромные характеристики, жизнь там не только существует, но и довольно эффектно развивается. На видео - небольшая (как кредитка) игрушечка, реализованная на attiny85... Напомню: всего 6 ног, 8К flash и 512 байт RAM. Вот так-то...
  4. Проблема с TWI(I2C)

    Всем привет! Начал разбираться с протоколом TWI(I2C) на авр, а именно atmega 8. Почитал статьи на изиэлектроник, написал обработку на прерываниях(подсматривая в пример), чтобы вникнуть. Начал тестить в протеус иии... Неизвестная бага не дает мне покоя. Старт производит, адрес слэйва передает(с битом на запись), адрес нужной ячейки передает, а уже при записи пишет ерунду, все время одно и то же, первый 0x00, второй 0xff, потом стоп(стоп запланирован) и какие бы байты я не писал в обработчике, передает 2 одинаковых 00 и ff... Ошибок не выдает, я поставил флаг на ошибки(1 на ноге), в нужное подпрерывание попадает ровно столько раз, сколько надо(тое ставил флаги туда), да и ставил флаги в другие обработчики прерываний(в которые не надо попадать в данном случае), но все норм. Я скину сюда часть кода, эквиваленты, озу нужные, макрос на отправку, и обработчики прерываний, которые используются для отправки байтов. Пишите, если нужна будет доп информация. Кстати, все прогнал по трассировщику в студии, просто сделал rcall на нужную последовательность обработчиков .equ F_CPU = 8000;частота процессора .equ i2c_sarp = 0b00000000 // Start-Addr_R-Read-Stop Это режим простого чтения. Например из слейва или из епрома с текущего адреса .equ i2c_sawp = 0b10000000 // Start-Addr_W-Write-Stop Это режим простой записи. .equ i2c_sawsawp = 0b10000001 // Start-Addr_W-WrPageAdr-Write-Stop Это режим с предварительной записью нужного адреса страницы в 1 байт а потом запись .equ i2c_saw2sawp = 0b10000011 // Start-Addr_WrPageAdrH-WrPageAdrL-Write-Stop Это режим с предварительной записью нужного адреса страницы в 2 байт а потом запись .equ i2c_sawsarp = 0b00000001 // Start-Addr_W-WrPageAdr-rStart-Addr_R-Read-Stop Это режим с предварительной записью нужного адреса страницы в 1 байт а потом чтение .equ i2c_saw2sarp = 0b00000011 .DSEG ;"******" - нужно вносить изменения в основном цикле!!!!!! I2C_SlaveAdres: .byte 1;регистр с адресом слэйва****************** I2C_busy: .byte 1; байт флага занятости шины и2с 1-занято! 0-свободно! I2C_ERR: .byte 1;байт для ошибок I2C_DO: .byte 1;задание, читать или записывать, 2 байта адрес или 1?********** I2C_LOW_ADRES: .byte 1;младший байт адреса ячейки для чтения/записи(если адрес однобайтовый, то младший единственный)******** I2C_HIGH_ADRES: .byte 1;старший байт адреса ячейки для чтения/записи*************** I2C_KOL_BYTE: .byte 1; сколько байт нужно прочесть или записать? писать количетсво!!!!*********** I2C_BUFER: .byte 5; байты, которые хотим пропихнуть************* I2c_ADRES_BUFER_IN: .byte 2;младший и старший байты адреса начала буфера данных для приема!*************** I2C_ADRES_BUFER_OUT: .byte 2;младший и старший байты адреса начала буфера данных для отправки!**************** I2C_INDEX_DATA: .byte 1;размер смещения,т.е. сколько байт уже отправлено, вначале отправки должен ранвться 0! TWSI:;перрывание i2c PUSHF;р16 и sreg в стэк PUSH R17;в стек PUSH R18 PUSH R0;в стек PUSH R30;в стек PUSH R31;в стек CLR R0;нужен 0 LDI ZH,HIGH(TWI_TABLE);заносим в индексную пару адрес таблицы причины прерывания и2с LDI ZL,LOW(TWI_TABLE);и младший байт UIN R16,TWSR;кода прерывания в р16 LSR R16;сдвиг влево LSR R16;еще LSR R16;и еще ADD ZL,R16;прибавляем значение к адресу таблицы ICALL;переходим на причину прерывания POP R31;достаем из стека z пару POP R30; POP R0;р0 из стека POP R18 POP R17;р17 из стека POPF;достаем р16 и sreg RETI;выход из прерывания TWI_TABLE:;таблица прерываний RJMP TWI_0x00;0x00 Bus Fail Автобус сломался… эээ в смысле аппаратная ошибка шины. Например, внезапный старт посреди передачи бита. RJMP TWI_0x08;0x08 Start Был сделан старт. Теперь мы решаем что делать дальше, например послать адрес ведомого RJMP TWI_0x10;0x10 ReStart Был обнаружен повторный старт. Можно переключиться с записи на чтение или наоборот. От логики зависит. RJMP TWI_0x18;0x18 SLA+W+ACK Мы отправили адрес с битом записи, а в ответ получили ACK от ведомого. Значит можно продолжать. RJMP TWI_0x20;0x20 SLA+W+NACK Мы отправили адрес с битом записи, а нас послали NACK. Обидно, сгенерим ошибку или повторим еще раз. RJMP TWI_0x28;0x28 Byte+ACK Мы послали байт и получили подтверждение, что ведомый его принял. Продолжаем. RJMP TWI_0x30;0x30 Byte+NACK Мы послали байт, но подтверждение не получили. Видимо ведомый уже сыт по горло нашими подачками или он захлебнулся в данных. ;Либо его ВНЕЗАПНО посреди передачи данных украли инопланетяне. RJMP TWI_0x38;0x38 Collision А у нас тут клановые разборки — пришел другой мастер, ;по хамски нас перебил, да так, что мы от возмущения аж заткнулись. Ничего I’l be back! До встречи через n тактов! RJMP TWI_0x40;0x40 SLA+R+ACK Послали адрес с битом на чтение, а ведомый отозвался. Хорошо! Будем читать. RJMP TWI_0x48;0x48 SLA+R+NACK Крикнули в шину «Эй ты, с адресом ХХХ, почитай нам сказки» А в ответ «Иди NACK!» ;В смысле на запрос адреса с битом чтения никто не откликнулся. Видимо не хотят или заняты. Также может быть никого нет дома. RJMP TWI_0x50;0x50 Receive Byte Мы приняли байт. И думаем что бы ответить ведомому. ACK или NACK. RJMP TWI_0x58;0x58 Receive Byte+NACK Мы приняли байт от ведомого и сказали ему «иди NACK!» И он обиженый ушел, освободив шину. TWI_0x10: ;повторный старт TWI_0x08:;произвели старт! LDS R16,I2C_SlaveAdres;адрес слэйва LDS R17,I2C_DO;что нужно, запись или чтение? CPI R17,0 BRNE TWI_0x10_WR ORI R16,1<<0 TWI_0x10_WR: OUT TWDR,R16;отправляем адрес слейва по шине и2с OUTI TWCR,0<<TWEA|0<<TWSTA|0<<TWSTO|1<<TWEN|1<<TWIE|1<<TWINT ;флаг преывания, блок тви и разрешаем прерывания ;TWINT флаг прерывания ;TWEA 1-ACK, 0-NACK ;TWSTA 1-start, 0-no start ;TWSTO 1-stop ;TWEN блок TWI включен ;TWIE - разрешаем прерывания TWI RET;выход из подпрерывания TWI_0x18:;подтверждение после посылки байта адреса и бита записи LDS R16,I2C_DO;загружаем тех задание в регистр SBRS R16,0;проверяем, нужно ли нам только записать байт? если да, то переход БЕЗ АДРЕСОВ! RJMP TWI_0x18_sawp;чтение тут невозможно! т.к. на чтении будет другое подпрерывание SBRC R16,0;проверяем, а не нужно ли нам послать адрес ячейки? в которую хотим писать RJMP TWI_0x18_sawsawp;если нужно , то переход. Адрес ячейки состоит из одного байта! соответственно младшего ;если ничего не подошло, значит нужно отправить адрес состоящий из двух байт ;передачу начинаем со старшего байта, затем просто в тех задании поправим на пересылку оставшегося младшего байта LDS R17,I2C_HIGH_ADRES;загружаем старший байт ANDI R16,~(1<<0);обнуляем первый бит тех задания, тем самым переводим его на отправку еще одного байта адреса(младшего) STS I2C_DO,R16 OUT TWDR,R17;загружаем старший байт адреса в тви RET;выход из подпрерывания TWI_0x18_sawsawp:;ЭТО КЛОООООН!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Запись только младшего байта адреса LDS R17,I2C_LOW_ADRES;загружаем младший байт адреса ячейки слейва DEC R16;первращаем sawsawp/sawsarp в просто в sawp или sarp!!!, т.е. загружаем в задание только запись! нужный байт адреса мы уже отослали! теперь только запись/чтение STS I2C_DO,R16 ;закидываем в задания OUT TWDR,R17;загружаем адрес ячейки в тви для записи OUTI TWCR,0<<TWEA|0<<TWSTA|0<<TWSTO|1<<TWEN|1<<TWIE|1<<TWINT; передача младшего байта адреса! RET;выход из подпрерывания TWI_0x18_sawp:;ЭТО КЛОООООН!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! запись самих байтов ;(сюда я вставлял счетчик, сколько раз здесь бывает процессор, и все сходится) LDS R16,I2C_KOL_BYTE;считываем, сколько байт нам нужно записать???? LDS R18,I2C_INDEX_DATA;счетчик, сколько байт скинули CP R16,R18; кончились байты то? BREQ TWI_0x18_STOP;если да, то переход и СТОП!!!! говорим слейву: хватит братан, но передаем последний байт) LDS ZL,I2C_ADRES_BUFER_OUT //младший байт адреса буфера данных озу, откуда брать байты на отправку LDS ZH,I2C_ADRES_BUFER_OUT+1 //старший байт адреса буфера данных озу, откуда брать байты на отправку ADD ZL,R18;прибавляем к адресу количество байт, которые отправили ADC ZH,R0 INC R18;увеличиваем счетчик на 1 STS I2C_INDEX_DATA,R18;отправляем в озу LD R17,Z;берем один из.. байтов по адресу индексной пары ;(сюда я вставлял строчку LDI R17,1 но отправляет в итоге не одни 1, а опять таки 00 и ff) OUT TWDR,R17;отправляем в регистр для передачи OUTI TWCR,0<<TWEA|0<<TWSTA|0<<TWSTO|1<<TWEN|1<<TWIE|1<<TWINT ;передача очередного байта данных! RET;выход из подпрерывания TWI_0x18_STOP:;СТОПЭ братан слейв,наелся ты байтов, отдохни ЭТО КЛОООН!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! STS I2C_busy,R0;освобождаем линию тви OUTI TWCR,1<<TWEA|0<<TWSTA|1<<TWSTO|1<<TWEN|1<<TWIE|1<<TWINT ;запись ОКОНЧЕНА! RET;выход из подпрерывания TWI_0x28: LDS R16,I2C_DO;и так, м ыздесь потому что: 1-отправили адрес и нужна запись байтов в ячейки ;2- отправили адрес и нужно чтение и 3 - отправили старший байт памяти, нужно отправить младший. CPI R16,i2c_sawp;нужна запись? BREQ TWI_0x18_sawp;переход SBRC R16,0;нужно записать оставшийся младший байт? RJMP TWI_0x18_sawsawp;переход! ;а иначе повторный старт!!!! OUTI TWCR,1<<TWEA|1<<TWSTA|0<<TWSTO|1<<TWEN|1<<TWIE|1<<TWINT ;повторный старт, т.к. чтение! RET;выходи из подпрерывания .MACRO I2C_OUT;НУЖНО ПРЕДВАРИТЕЛЬНО ЗАКИНУТЬ ОТПРАВЛЯЕМЫЕ ДАННЫЕ В И2С БУФЕР!!! ;0-адрес слейва, младший байт = 0!!! ; 1-запись или чтение? если с адресом, то сколькибитный? ;2-младший байт адреса регистра слэйва ;3-старший байт адреса регистра слейва(если не нужен, то 0) ;4-сколько байт нужно записать, прочитать? ;5-какая скорость передачи нужна? ;6-откуда брать байты? CLR R16 STS I2C_INDEX_DATA,R16 LDI R16,1 STS I2C_BUSY,R16 OuTI I2C_SlaveAdres,@0 //OUTI TWAR,@0;заружаем адрес слэйва LDI R16,@1;загружаем задание STS I2C_DO,R16 .if @3>0x00 LDI ZL,LOW(@2);адрес регистра слэйва для приема/передачи LDI ZH,HIGH(@3) STS I2C_LOW_ADRES,ZL STS I2C_HIGH_ADRES,ZH .else LDI ZL,LOW(@2) STS I2C_LOW_ADRES,ZL .endif LDI R16,@4;загружаем значение количества байт для приема/передачи STS I2C_KOL_BYTE,R16 OUTI TWSR,0<<TWPS1|0<<TWPS0;предделитель 1 LDI R16,((F_CPU/@5)-16)/2;расчетскорости приема/передачи данных UOUT TWBR,R16 LDI ZL,LOW(@6) LDI ZH,HIGH(@6) STS I2C_ADRES_BUFER_OUT,ZL STS I2C_ADRES_BUFER_OUT+1,ZH OUTI TWCR,1<<TWINT|1<<TWEA|1<<TWSTA|0<<TWSTO|1<<TWEN|1<<TWIE;запуск! отправляем старт! ;TWINT флаг прерывания ;TWEA 1-ACK, 0-NACK ;TWSTA 1-start, 0-no start ;TWSTO 1-stop ;TWEN блок TWI включен ;TWIE - разрешаем прерывания TWI .ENDM Тело: OUTI I2C_BUFER,1 OUTI I2C_BUFER+1,2 I2C_OUT 0xA2,i2c_sawsawp,0x03,0,2,200,I2C_BUFER - сюда больше не вернется Main: зацикливание Rjmp main П.С. вот что пишет i2c debuger в протеусе: S A2 A 03 A 00 A FF A P
  5. Здравствуйте, только начал свой путь в программировании микроконтроллеров. Прошу советов в целом и ответов на вопросы в частности(они ниже). 1) Какие книги читать? По порядку от начального уровня и далее. Я сейчас читаю книгу Белова А. В. "Микроконтроллеры AVR. От азов программирования до создания практических устройств". 2) Какие программы использовать? В целом, не знаю какие вообще нужны программы для этого дела. Я сижу на Lunux, но могу и с вириальной машины запускать. 2.1) Можно ли для написания программы использовать C++? я немного знаю C, но сильно хуже чем C++. 3) Можно ли обойтись без покупки реальных схем и инструментов? Хотя бы по первой. Понятно дело, что если развиваться в этом направлении, то без этого не обойтись. Но есть ли такая программа в которой можно собрать схему, в ней в микроконтроллер загрузить программу и посмотреть как она работает?
  6. Здравствуйте, почитав ответы на предыдущий вопрос понял, что эффективнее всего будет изучать программирование МК купив себе этот самый МК. Но тогда возникает следующий вопрос: Что и где покупать ? Я неработающий студент, поэтому хотелось бы несильно дорого. Локация - Казань.
  7. Здравствуйте ! Я захотел поставить Bascom AVR на компьютер , но при установке возникли ошибки. Может у вас есть идея как помочь ?
  8. Как к схеме подключить батарею для питания схемы и usb разъём для зарядки батареи , а так же была возможность связи с пк через usb. И пожалуйста нарисуйте это на схеме что бы было видно как все подключено Схема
  9. Здравствуйте , я хотел прошить AVR программатором STK500 . Но оказалось , чтобы Bascom IDE прошивать им , необходим STK500.exe . Пожалуйста посмотрите , не лежит ли он где-нибудь у вас . Заранее спасибо
  10. USBASP программатор не рабтает

    Купил USBASP программатор с aliexpress. На нем стояла старая прошивка, т.к в khazama при прошивке выдавало ошибки но микроконтроллер прошивался и память считывалась (короче просто старая прошивка на нем). Потом решил перепрошить программатор через arduino. Прошивка успешно закачалась, но теперь программатор вообще отказывается работать. Кто сталкивался, помогите.
  11. Повторил схему опубликованную на сайте паяльник. http://forum.cxem.net/index.php?/blogs/entry/548-повторил-схему-клона-avr-jtag-ice/&do=getLastComment Схема заработала, но так и не смог её заставить работать из под CVAVR, заводится только из под Atmel Studio 4. Может быть кому ни будь удалось это сделать? Если да, то подскажите, как этого достичь?
  12. Повторил схему клона AVR JTAG ICE

    Наткнулся на схемку в сети AVR JTAG ICE и решил её повторить. Дабы не тратить время на изготовление печатной платы решил предварительно собрать сей девайс "на соплях", вернее на беспаечной плате. Вот так у меня это всё получилось. Залил прошивку из статьи собрал схему с процом который будет целевым, соединил всё с COM портом и начал пытаться запустить всё из под CVAVR. Не заработало. Тогда попробовал из под Atmel Studio 4 и у меня всё получилось. Следующим этапом решил попробовать будет ли это всё работать через USB. И оказалось, что да, работает вполне хорошо. Нужно ещё попробовать из под последней Atmel Studio, но пока не на чем. Мне она не нравится из-за своей громоздкости и поэтому я ей не пользуюсь. Можно резюмировать, что схема по ссылке вполне пригодная, но использование её ограничено софтом. Для не слишком требовательных юзеров вполне годится. Буду рад любым комментариям, если что-то непонятно, спрашивайте, отвечу на ваши вопросы. Все материалы из вышеуказанной статьи выкладываю здесь, если кто захочет повторить, пожалуйста. mc85_AVR-JTAG-ICE.zip
  13. Примеры Кода Для Avr

    Здесь будут помещаться различные примеры кода и прочего обсуждаемого в других темах. Также скидывайте сюда любую полезную информацию по AVR микроконтроллерам Он-лайн книга: "Книга по программированию микроконтроллеров AVR (ассемблер)" Atmel AVR4027: Tips and Tricks to Optimize Your C Code for 8-bit AVR Microcontrollers: Atmel AVR4027 (Оптимизация кода от Atmel).pdf
  14. Минималистическая RTOS

    В моём гнезде прибавление. В смысле, алгоритм вылупился. Не скажу, чтобы исключительно новый, вряд ли гениальный, но, мне кажется, заслуживающий внимания. Преамбула. Что мы понимаем под понятием "таймер"? Ну, не в смысле задатчика времени варки яиц всмятку, а в программировании? Это некая функция, которая "сама по себе" выполняется через заданные интервалы времени. Или же чуть иначе: функция выполнится через заданный интервал времени однократно. Наконец, и третья интерпретация тоже имеет место быть: таймер - это некий счетчик, который сам по себе считает, а мы можем время от времени поглядывать на его значение и принимать какие-то решения. Амбула. Как обычно реализуются таймеры в микроконтроллерном программировании? Безусловно, наиболее удобно - с задействованием аппаратных таймеров-счетчиков и прерываний от них. Существует вариант реализации и без этого, но сие удовольствие надо оставить пациентам более строгого режима лечения. С прерыванием от аппаратного таймера все понятно, но их количество (аппаратных счетчиков я имею ввиду) ограничено. И поэтому в общем случае используется модель "программных" таймеров на основе одного прерывания от аппаратного. Вот как, например, выглядит один из простейших вариантов: #define TIMER_CNT 5 static volatile uint8_t timer[TIMER_CNT]; // обработчик прерывания от таймера, вызывается каждую миллисекунду ISR(TIMER_vect){ for(uint8_t i=0; i<TIMER_CNT; i++){ if(timer[i]) timer[i]--; } } // вот так можно ограничить длительность цикла интервалом времени в 100 мс timer[0] = 100; while(timer[0]){ // что-то длительное if(какое-то-условие-неизвестно-когда-возникающее) break; } if(!timer[0]){ // из цикла вышли по таймауту } else { // из цикла вышли по условию } Вроде бы, все просто и понятно. И даже удобно. Я сам 100 раз так делал! Но есть и неприятности. Во-первых, надо постоянно следить за тем, какой "номер" таймера задействован в том или ином участке кода. Когда таймеров два или три - проблемы нет, а когда в разных функциях в разных модлях их по нескольку штук, можно и запутаться. Во-вторых, массив timer должен быть глобальным, что само по себе не страшно, но как-то не комильфо... В-третьих, сделать таймер не однобайтным, а двухбайтным, чтобы иметь возможность отсчитывать большие интервалы времени, уже так красиво не выйдет - следует обеспечивать атомарный доступ к значению счетчика... И главное: этот подход реализует только последний вариант таймера из числа рассмотренных в преамбуле, т.е. гибкость его ограничена. Путем нехитрых манипуляций можно заметно улучшить ситуацию. Хотя и несколько усложнив код: #include <util/atomic.h> #define TIMER_CNT 5 typedef uint8_t (*tmr_func)(void); typedef struct{ uint16_t counter; uint16_t duration; tmr_func func; } timer_t; static volatile timer_t timer[TIMER_CNT]; ISR(TIMER_vect){ for(uint8_t i=0; i<TIMER_CNT; i++){ if(timer[i].counter){ timer[i].counter--; if((timer[i].counter == 0) && (timer[i].func != NULL)) if(timer[i].func()) timer[i].counter = timer[i].duration; } } } void timer_start(uint8_t t, uint16_t duration, tmr_func f){ ATOMIC_BLOCK(ATOMIC_RESTORESTATE){ timer[t].counter = duration; timer[t].duration = duration; timer[t].func = f; } } uint8_t timer_out(uint8_t t){ ATOMIC_BLOCK(ATOMIC_RESTORESTATE){ return timer[t].counter == 0; } } // вот так можно заставить светодиоды мигать с разной частотой static uint8_t blink_led1(void){ PORTB ^= 1<<0; // светодиод на нулевой линии порта return 1; // для перезапуска функции } static uint8_t blink_led2(void){ PORTB ^= 1<<1; // светодиод на первой линии порта return 1; // для перезапуска функции } timer_start(0, 500, blink_led1); timer_start(0, 300, blink_led2); while(1){ // тут что-то делаем, а светодиоды тем временем мигают каждый по-своему } Разумеется, здесь уже и атомарность доступа к значению счетчика реализована (ценой вызова отдельной функции), и все вариаты из преамбулы тоже. Надеюсь, очевидно, что если переданная в таймер функция вернет 0, она больше не будет вызываться после того, как таймер истечет? Чем вам не RTOS в минимальном виде? Главное условие в применимости такого подхода - предельно быстрое исполнение таймерной функции. Но при использовании автоматов состояний этим способом можно решать большой спектр практических задач. Но проблема с "учетом" таймеров осталась. Да и если вы вдруг станете нуждаться в бОльшем количестве таймеров, чем TIMER_CNT, вам придется эту константу менять. И в случае, если вы модифицируете старый проект, и старое количество таймеров вам не нужно, то тоже надо это вручную менять. Мелочь, а неприятно. Хорошо было бы, если бы в любом месте кода описал свой отдельный static (т.е. невидимый другим) таймер, и пользуешься им. Не нужен -удалил его описание, и не пользуешься. А "система" сама заботится о том, чтобы таймер "тикал" или не "тикал", если не нужен. И обычно для этого используют возможности RTOS. Хотя... Хотя максимальное количество выделяемых RTOS таймеров позапросу пользователя тоже ограничено значением какой-то константы... Но и из этого исхода есть выход! Только об этом в следующий раз. Т.е. о самом главном я и не сказал...
  15. Я начинающий программист, пытаюсь программировать микроконтроллеры в среде АВР. У меня возник вопрос, вот например у нас есть двоичная система исчисления где 3 мы можем записать так: 00000011, однако чтобы подать логическую 1 на третий порт микроконтроллера мы должны сделать следующую запись PORTC=00000100, т е существует некая разница между названиями портов и системами исчисления, в таком случае как мне используя 16 ричную систему исчисления подать напряжение на какую либо ногу порта.Я знаю что данная запись 0х01 подает логическую 1 на 0 ногу, а данная запись 0х10 на 4 ногу ,ну а как быть дальше? Как подать напряжение на 5 ногу порта? Если я в чем то заблуждаюсь - поправьте, если чего то незнаю расскажите. Заранее благодарю.
  16. Поставил LUFA, следом абсолютно не нужный мне ASF. Но в упор не понимаю - как создать проект на базе этой библиотеки из студии? Приходится вручную копировать папку с заголовочниками LUFA, прописывать пути в makefile, лишние телодвижения по добавлению папки в свойства проекта. Если я это делаю всё вручную, то тогда для чего это расширение? Примеры я могу и так покрутить. ЗЫ - не слишком высокий скилл в юзании Atmel Studio/
  17. Здравия всем ! Пожалуйста помогите разобраться . Пытаюсь написать прошивку для Atmega8 на С в Atmel Studio 7.0 . Программка простая ( небольшая ) ... по сути - частотомер ( только для небольшого диапазона частот ... примерно - от нескольких Гц , до нескольких десятков кГц ) . Импульсы считать со входа T0 ( PD4 ) ...микр-ра Atmega8a ( 28 pin ) . Использовать TCNT1 (16 bit) . Полученное число выводить на Lcd - nokia5110 . Как я понимаю прерывания не нужны , алгоритм простой : 1) инициализация дисплея и счетчика 2) остановить (запретить счет) счетчик AVR - ( CS12,CS11,CS10-прописать нули ) 3) обнулить ( отчистить) буфер дисплея и счетчика ( AVR ) 3) запустить бесконечный цикл : а) разрешить считать импульсы с T0 ( PD4 ) - ( CS12,CS11,CS10-прописать единицы ) б) задать паузу ( надеюсь правильно рассчитал - 10 мсек ) в) запретить считать - ( CS12,CS11,CS10-прописать нули ) г) вывести полученное значение со счетчика на дисплей ( СИЛЬНО НЕ СМЕЙТЕСЬ ... Я НАЧИНАЮЩИЙ . с АЦП AVR разобрался удачно , собрал схемку в протеусе , написал прошивку , спаял ... все работает . а вот с таймером завис надолго . есть много примеров в инете , но все слишком навороченные для меня . запутался . ) вот примерно что получилось с таймером ... упрощал как мог ...в общим не получается . подскажите где косяк .(только просьба - без лишних наворотов и по возможности с комментариями ... задача - не повторить чужую программу ... а разобраться самому ) //Atmega8A #define F_CPU 8000000 #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> #include "n5110.h" void presets(){ Lcd_init(); Lcd_clear(); TCCR1B =0x00; TCNT1=0000; TCCR0 |= (1 << CS01); } int main(void) { presets(); while (1) { TCNT1=0000; TCCR1B|=(1<<CS12)|(1<<CS11)|(1<<CS10); _delay_ms(10); TCCR1B &=~(1<<CS12)|(1<<CS11)|(1<<CS10); Lcd_prints(5,2,FONT_1X,(TCNT1)PSTR("Hz")); // КОМПИЛЯТОР РУГАЕТСЯ НА ЭТУ СТРОЧКУ Lcd_update(); } }
  18. Коротенький "бип"

    Привет всем. Помогите с кодом, нужно озвучить нажатие кнопки, подключенной к порту PB0, то есть просто издать короткий "бип" одной частоты (примерно 1000 Гц) и длительностью примерно 0.2 секунды. Везде, где искал, сразу создают кучу нот, разные тона, используют прерывания, мне же надо только один короткий бип. Выполняться оно должно в теле цикла: while (1) { while(PINB&0b00000001); // ждем нажатия на кнопку на порте PB0 <вот здесь должен быть бип> п.с. забыл добавить - выполняться код будет на Attiny13a
  19. Как сделать устройство, выводящие на индикатор время, прошедшее с момента последней перезагрузки контроллера?
  20. Всем привет! Дано: Контроллер подсветки рабочей зоны кухни, реализованный на Tiny 13A. Светодиодная лента длиной 2,3 метра, led 5050, 120 светодиодов/метр. Принципиальная схема устройства ниже: Код прошивки: #include <tiny13.h> #include <delay.h> int triggered = 0; int ontimer = 0; void main(void) { // Input/Output Ports initialization // Port B initialization // Function: Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=Out DDRB=(0<<DDB5) | (0<<DDB4) | (0<<DDB3) | (0<<DDB2) | (0<<DDB1) | (1<<DDB0); // State: Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=0 PORTB=(0<<PORTB5) | (0<<PORTB4) | (0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0); // Timer/Counter 0 initialization // Clock source: System Clock // Clock value: 37,500 kHz // Mode: Fast PWM top=0xFF // OC0A output: Non-Inverted PWM // OC0B output: Disconnected // Timer Period: 6,8267 ms // Output Pulse(s): // OC0A Period: 6,8267 ms Width: 0 us TCCR0A=(1<<COM0A1) | (0<<COM0A0) | (0<<COM0B1) | (0<<COM0B0) | (1<<WGM01) | (1<<WGM00); TCCR0B=(0<<WGM02) | (1<<CS02) | (0<<CS01) | (0<<CS00); TCNT0=0x00; OCR0A=0x00; OCR0B=0x00; while (1) { if (PINB.1==1) { triggered = 1; ontimer = 60; }; if (ontimer > 0) { ontimer--; } else { triggered = 0; }; if (triggered) { if (OCR0A<255) { OCR0A++; }; } else { if (OCR0A>0) { OCR0A--; }; }; delay_ms(10); } } Возникшая проблема: Греется полевой транзистор при работе. Изначально поискав информацию на данную проблему, начал прикидывать. Смотрим график зависимости пропускаемого тока стока (ID )от приложенного напряжения затвор-сток (VGS), при температуре окруж. среды 25 градусов: ID = 14 А (2,3 метра светодиодной ленты не могут столько кушать, по крайней мере я такую не видел). Было предположение что частота переключения ШИМ высокая - отсюда транзистор в не определенном состоянии = нагрев. Рассчитал макс. частоту так: Rg = 100 Ом, Vgs = 5V Заряд затвора: Qiss = Ciss * Vgs = 1800pF * 5v = 9nC Скрость нарастания: S = Rgate * Qiss = 100Ohm * 9nC = 0.009mV*sec Время на открытие или закрытие транзистора: t=S / Vgs = 0.002mV*sec * 3.2v = 4.5uSec Период - это открытие + закрытие: T = t + t = 4.5uSec + 4.5uSec = 9uSec Максимальная частота переключения: F < 1 / T = 1 / 9uSec = 111KHz Ток через затвор (G) и цифровой выход Tiny 13A: I = Qiss / t = 2mA Максимальный выходной ток GPIO у Tiny 13A 40.0mA 2mA < 40.0mA Выставил частоту ШИМ на 37,5 кHz. Вуаля - при подключении 1м светодиодной ленты (тестировал на обрезке), нагрева нет. Но как только подключил все 2,3 метра - транзистор стал снова спустя время греться, аж дотронуться не возможно. Захотел померить ток, который потребляет 1 метр ленты, проверить продавца. Потребление 1 метра ленты оказалось вместо заявленных 600 мА, все 1,85 А, причем заметил странную вещь - ток начал возрастать спустя время на сотые доли и дошел до 1,9 А. Дальше ждать не стал. Режим амперметра в мультиметре сломался? Далее подумал что слишком большая мощность рассеивается на транзисторе. Если учесть то, что при открытом транзисторе, его переход можно представить в виде линейного резистора с маленькой величиной сопротивления, можно рассчитать рассеиваемую мощность на транзисторе: Смотрим сопротивление транзистора в открытом состоянии при VGS = 5В : RDS(on) = 0.18 Ом P1 = 1,9*1,9*0,18 = 0,65 Вт. (1 метр св.ленты). Раз мы взяли потребление 1 метра ленты 1, 9 А, тогда 2,3 метра потребляют = 4,4 А. (Теперь не уверен в своем мультиметре). P2=4.4*4.4*0.18 = 3.5 Ватт - довольно таки многовато я думаю. В общем: Правильно ли я делаю расчеты? Что упустил? Как снизить нагрев транзистора, без применения вентиляторов и здоровенных радиаторов? Есть вариант замены светодиодной ленты на что нибудь поменьше жрущее (60 светодиодов/ метр например), но в будущем еще много раз придется сталкиваться с полевиками, хотелось бы разобраться .
  21. AVR Studio 4

    Помогите написать простую задачку (для вас - простую, а я не шарю), на плате контроллера-конструнтора KIT-8515 нужно сделать вот это: "Пусть движковыми переключателями задаются два четырехзначных операнда. Напишите и протестируйте программу, при работе которой после нажатия кнопки 1 операнды складывались, а при нажатии кнопки 2 операнды вычитались, а результат операции выводился на светодиоды" Прикреплённый файл - начало задачки. Заранее благодарствую:) 123.rar
  22. Здравствуйте! Мне нужно измерить длительность импульса. Для этого сначала применял внешнее прерывание, а теперь перешел на режим захвата таймера в Atmega 328. Однако сейчас происходит странное: Через определенное таймер просто останавливается. Гугл результатов не дает, ни у кого захват таймера 1 не останавливается. Подскажите пожалуйста, что делать? Среда разработки CodeVisionAVR v3.12. Сейчас попробовал версию 3.3, толку нет. Не работает. Код максимально упростил, но по прежнему толку ноль. Переполнение таймера 0 так же работает отлично, до тех пор, пока что-то не произойдет с прерыванием по захвату. Как только что-то произошло - мк останавливается... Может немножко подождать, и увеличить значение счетчика current_timp еще на пару значений... Совсем не знаю что делать. interrupt [TIM1_OVF] void timer1_ovf_isr(void) { TCNT1H = 0x00; TCNT1L = 0x00; } // Timer1 input capture interrupt service routine interrupt [TIM1_CAPT] void timer1_capt_isr(void) { TCNT1H = 0x00; TCNT1L = 0x00; // Это уже уровень танцев с бубном "авось поможет" - не помогает. current_timp++; // Все упрощено до максимума. Мне бы он хоть количество периодов для начала... // } } // Прерывание по переполнению первого таймера interrupt [TIM0_OVF] void timer0_ovf_isr(void) { // Обнуление счетного регистра. TCNT0=0x00; counter ++; if (counter > 10) { lcd_clear(); sprintf(buffer,"%d us", current_timp); lcd_gotoxy(0,0); lcd_puts(buffer); counter = 0; } } // Главный цикл программы void main(void) { #pragma optsize- CLKPR=(1<<CLKPCE); CLKPR=(0<<CLKPCE) | (0<<CLKPS3) | (0<<CLKPS2) | (0<<CLKPS1) | (0<<CLKPS0); #ifdef _OPTIMIZE_SIZE_ #pragma optsize+ #endif // Port B initialization // Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In DDRB=(0<<DDB7) | (0<<DDB6) | (0<<DDB5) | (0<<DDB4) | (0<<DDB3) | (0<<DDB2) | (0<<DDB1) | (0<<DDB0); // State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T PORTB=(0<<PORTB7) | (0<<PORTB6) | (0<<PORTB5) | (0<<PORTB4) | (0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0); // Port C initialization // Function: Bit6=In Bit5=Out Bit4=Out Bit3=Out Bit2=Out Bit1=Out Bit0=Out DDRC=(0<<DDC6) | (1<<DDC5) | (1<<DDC4) | (1<<DDC3) | (1<<DDC2) | (1<<DDC1) | (1<<DDC0); // State: Bit6=T Bit5=1 Bit4=1 Bit3=1 Bit2=1 Bit1=1 Bit0=1 PORTC=(0<<PORTC6) | (1<<PORTC5) | (1<<PORTC4) | (1<<PORTC3) | (1<<PORTC2) | (1<<PORTC1) | (1<<PORTC0); // Port D initialization // Function: Bit7=Out Bit6=Out Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In DDRD=(1<<DDD7) | (1<<DDD6) | (0<<DDD5) | (0<<DDD4) | (0<<DDD3) | (0<<DDD2) | (0<<DDD1) | (0<<DDD0); // State: Bit7=1 Bit6=1 Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T PORTD=(1<<PORTD7) | (1<<PORTD6) | (0<<PORTD5) | (0<<PORTD4) | (0<<PORTD3) | (0<<PORTD2) | (0<<PORTD1) | (0<<PORTD0); // Делители таймера 0 рассчитаны таким образом , что его тактовая частота = 15,625 КГц. Расчет был на применение в схеме семисегментников, но с LCD индикатором будет информативнее. TCCR0A=(0<<COM0A1) | (0<<COM0A0) | (0<<COM0B1) | (0<<COM0B0) | (0<<WGM01) | (0<<WGM00); TCCR0B=(0<<WGM02) | (1<<CS02) | (0<<CS01) | (1<<CS00); TCNT0=0x00; OCR0A=0x00; OCR0B=0x00; // Настройка таймера 1 TCCR1A=(0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10); TCCR1B=(1<<ICNC1) | (1<<ICES1) | (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (0<<CS11) | (1<<CS10); TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; // Разрешение прерывания по переполнению таймера 0 TIMSK0=(0<<OCIE0B) | (0<<OCIE0A) | (1<<TOIE0); // Timer/Counter 1 Interrupt(s) initialization TIMSK1=(1<<ICIE1) | (0<<OCIE1B) | (0<<OCIE1A) | (1<<TOIE1);
  23. Чтение с eeprom по spi

    Всем привет! Подскажите, пожалуйста, как правильно считать данные с внешней eeprom по шине spi, в данном случае 25LC256. Написал код ссылаясь на даташит. Собрал схему в протеусе, подключил spi отладчик и вот что получил в итоге. Так же не могу проверить получается записать данные в память или нет. Весь код прикрепил. main.c
  24. Вот вы говорите: AVR слишком убоги, чтобы применять на них RTOS... А я рискнул... Сначала попытался рассмотреть имеющиеся варианты, чтобы сделать предварительные выводы. Поиск вываливает примерно с десяток готовых разработок RTOS разной степени крутости, из которых FreeRTOS, естественно, в лидерах. Однако, я оценил свои силы и решил, что вхождение в эту ОС для меня обернется большими сложностями, в основном, из-за большого количества возможностей API, и англоязычным их описанием. Ну не принимает душа русская языка аглицкого, даже со словарем и гуглопереводчиком в больших количествах. А из осей на великом и могучем нашлось только две: кооперативная OSA и присиплюсплюснатая ScmRTOS. Опять-таки из-за собственной ограниченности более современная и продвинутая ScmRTOS мне показалась недоступной - С++ пока что понимаю и принимаю исключительно в качестве наказания. Ну, собственно, и вышло, что начать и закончить поиск осей для AVR можно на OSA. Попробовал - получается. Не без скрипа, но работает. И даже увлекло меня это. Но вот что мне не понравилось в этом варианте. Главная особенность этой ОС, которую следует учитывать при работе (то есть при написании программ), это отсутствие сохранения контекста при переключении задач. Иными словами, если в текущей задаче вызывается сервис операционной системы, переключающий задачи, то все локальные переменные текущей задачи могу потерять свою актуальность. Это означает, в частности, запрет на вызов сервисов системы в циклах по счетчику (значение счетчика будет потеряно). И единственный способ решить эту проблему - вместо автоматических локальных переменных использовать static или вообще отказаться от локальных в пользу глобальных. Сами понимаете, это совсем не гуд. Вторая особенность этой ОС, это возможность вызывать сервисы ОС, преключающие задачи, только из тела самой задачи, но не в вызываемых из неё функций. То есть нельзя сделать функцию, например, ожидающую прием символа из USART при помощи системного сервиса OS_Wait, а затем вызывать эту функцию из разных задач, то есть поступать по аналогии с привычным "не-многозадачным" подходом. Вот представьте себе ситуацию: задачи формируют текстовые сообщения и выводят их в USART. Кажется логичным сделать функцию, которая занимается отправкой в USART строки посимвольно и использовать эту функцию во всех задачах - а нельзя! Более того, не смотря на то, что все задачи ПООЧЕРЕДНО формируют строки (ОС ведь кооперативная), каждая из задач должна иметь собственный промежуточный static-буфер для формирования своей строки - это ведь явно лишний расход памяти! При обычном подходе мы бы работали с локальным буфером в каждой функции, а локальный буфер, как известно, исчезал бы при выходе из функции... Наконец, архитектура этой ОС (под архитектурой я подразумеваю набор файлов-модулей и порядок работы с ними) такова, что почти все файлы инклюдятся друг в друга, что очень сильно нарушает модульный подход при программировании. Напомню, что модульный подход означает, в частности, возможность компиляции каждого Сишного файла отдельно от других сишных файтов. А в OSA системные сишники "вставляются" в один большой "общий" сишник, который затем и компилируется. В итоге я потратил немало времени, чтобы разобраться, как же настроить проект в Eclipse, чтобы можно было комфортно работать. Eclipse очень привык считать все сишники отдельными модулями проекта, и страстно стремится компилировать их отдельно. В общем, знакомство с OSA было увлекательным, недолгим, интересным, но разочаровывающим. Другие же ОС, найденные мной, были не кооперативными, а вытесняющими. Вытесняющие ОС имеют много преимуществ перед кооперативными, но один их недостаток сильно ограничивает применение на AVR: они весьма требовательны к объемам ОЗУ. Именно отсюда растут ноги у паникерских мнений, что AVR и "нормальная" RTOS - понятия несовместимые. И это на самом деле так, если мы говорим о микроконтроллерах младше (т.е. слабее) atmega32. Для справки: OSA вполне себе способна быть полезной не только на atmega8, но даже и на attiny2313! Но, к счастью для меня, не одной atmega32 ограничен мир AVR, и, кроме прочего, не ограничен и я сам. У меня в загашнике есть и at90can128, и даже atmega2560! И, спросил я себя, почему я должен переживать по поводу вытесняющей ОС при таких-то ресурсах? В at90can128 целых 4К ОЗУ, а уж flash-памяти по 8-битным меркам просто немеряно - 128К, а у монстра atmega2560 вдвое больше всего! Правда, если первый МК паять вполне комфортно (TQFP64), то второй без микроскопа уже сложно (TQFP100 c шагом выводов 0,5 мм). А тут еще у меня завалялась отладочная платка DVK90CAN1... Ну, вы поняли... Итак, решающим теперь для меня стал поиск максимально простой операционки - чтобы мне по силам. Их не так мало, как может показаться, но самой простой, по моему мнению, является YAVRTOS (скачать архив с исходниками, примерами и документацией можно по ссылке, но сайт автора уже не существует) - это практически такой же малоизвестный, как OSA, продукт примерно тех же времен (видимо, тогда было можно каждому мастерить свою собственную ОС с блекджеком и девушками низкой социальной ответственности). Не смотря на инглиш, эта ось оказалась мне по силам: всего два файла и с полтора десятка системных функций! За один вечер легко расщелкал все необходимое для первого старта. Плюсы этой RTOS перед OSA неоспоримы: не надо предпринимать практически никаких усилий по оформлению кода - пишется точно так же, как всегда, с локальными переменными, с вложенными вызовами функций и т.д. Разумеется, надо следить за общими ресурсами и блокировать к ним доступ, если необходимо - но это вообще всегда необходимо в многозадачных системах, и даже в ОSA частично так. Минусы, правда, тоже заметны: минимальное приложение, тупо мигающее двумя светодиодами (каждый в своей задаче) занимает почти 2К flash и порядка 400 байт ОЗУ. На просторах выбранного мной МК это даже и не заметно, но для atmega8 может быть близким к техническому пределу. YAVRTOS написана на 99,9% на Си (только сохранение/восстановление контекста реализовано в виде ассемблерной вставки из трех десятков push-pop), всего два файла (task.c и task.h) - все это явный плюс в плане изучения и модификации под себя, если надо (и если хватает ума). Косвенным плюсом (или минусом, если продолжать переживать о ресурсах) является массовое применение malloc в ядре ОС, а значит, и в пользовательском приложении уже вполне оправдано динамическое распределение памяти. И мой энтузиазм просто на взлете от первого опыта! Например, вот как выглядит код задачи и вспомогательных функций для извлечения точного времени из GPS-приемника, подключенному к USART1, и вывода этих показаний на стандартный вывод (stdout, связанный с USART0): const __flash char gps_msg[] = "RMC,"; #define GPS_MSG_SZ (sizeof(gps_msg)-1) // поллинг 1 символа от GPS static uint8_t get_char(void){ while(bit_is_clear(UCSR1A, RXC)) wait_for_increment_of(&tick, 1); return UDR1; } // получение 1 цифры из символа static uint8_t get_dig(void){ return (get_char() - '0'); } // собственно сама задача void p2p_usart(void *p){ uint8_t i; uint8_t h,m,s; while(1){ i = 0; // ждем прихода сообщения с точным временем while((i < GPS_MSG_SZ) && (get_char() == gps_msg[i])) i++; if(i == GPS_MSG_SZ){ // разбираем сообщение по символам h = get_dig()*10 + get_dig() + 3; // +3 - это часовой пояс h %= 24; m = get_dig()*10 + get_dig(); s = get_dig()*10 + get_dig(); // пропускаем сотые доли секунды get_char(); // '.' get_char(); // 's' get_char(); // 's' get_char(); // ',' // проверка корректности времени и его вывод if(get_char() == 'A'){ printf_P(PSTR("GPS Time %02d:%02d.%02d\r"),h,m,s); } else { printf_P(PSTR("No GPS, wait... \r")); } } } } Как видите, код крайне "тупой", то есть прямолинейный, как лом: сплошные ожидания и никакой заботы о том, что параллельно должно что-то еще работать. В моем случае просто мигают 2 светодиода - один с длительностью импульса/паузы в 500 тиков, а второй в 501 (кстати, 1 тик = 1 мс, тактовая частота МК = 8 МГц). Но вместо светодиодов может быть еще две (или сколько надо) аналогично прямолинейно написанных задач, и можно быть уверенным, что все будет работать! Приведу данные по итогам компиляции проекта, чтобы продемонстрировать израсходованные ресурсы: Не так уж и плохо, учитывая свободное применение printf. В активном режиме используется дополнительно 380 байт ОЗУ под стеки задач и ОС, т.е. примерно 10% всего объема - еще много остается. Есть, кроме YAVRTOS, и другие альтернативы, например, FemtoOS, которая поддерживает даже (!!!) attiny25, и при этом тоже является вытесняющей операционкой. Но она существенно "богаче" в плане API, и разобраться с нею будет посложнее, т.к. документирована она явно менее детально. Возможно, я и её попробую на вкус... И, скорее всего, теперь это станет для меня основным способом написания программ. RTOS позволяет сильно упростить себе жизнь. Имхо.
  25. Atmega и Bluetooth HC-05

    Здравствуйте. Делаю бегущую строку на AVR и драйверах max7219 по этой статье. Исходный код есть в конце статьи. Хотел бы доработать устройство чтобы можно было передавать сообщение через Bluetooth модуль HC-05 при помощи Bluetooth terminal. Сам знаю как это можно сделать, т.к. все примеры находил только под Arduino. Прошу помочь кто знает как это можно реализовать