Я не раз и не два говорил, что изучение МК надо начинать с ассемблера. Этому был посвящен целый курс на сайте (правда он не очень последовательный, но постепенно я его причесываю до адекватного вида) . Да, это сложно, результат будет не в первый день, но зато ты научишься понимать что происходит у тебя в контроллере. Будешь знать как это работает, а не по обезьяньий копировать чужие исходники и пытаться понять почему оно вдруг перестало работать. Кроме того, Си намного проще натворить быдлокода, который вылезет вилами в самый неподходящий момент.
К сожалению все хотят результат немедленно. Поэтому я решил пойти с другой стороны — сделать обучалку по Си, но с показом его нижнего белья. Хороший программист-эмбеддер всегда крепко держит свою железку за шкварник, не давая ей ни шагу ступить без разрешения. Так что будет вначале Си код, потом то что родил компилятор и как все это работает на самом деле :)
С другой стороны у Си сильная сторона это переносимость кода. Если, конечно, писать все правильно. Разделяя алгоритмы работы и их железные реализации в разные части проекта. Тогда для переноса алгоритма в другой МК достаточно будет переписать только интерфейсный слой, где прописано все обращение к железу, а весь рабочий код оставить как есть. И, конечно же, читаемость. Сишный исходник проще понять с первого взгляда (хотя.. мне, например, уже пофигу на что фтыкать — хоть си, хоть асм :) ), но, опять же, если правильно все написать. Этим моментам я тоже буду уделять внимание.
В качестве подопытной железки на которой будет ставиться львинная доля всех примеров будет моя отладочная плата PinBoard.
Дальше все будет разжевано буквально по шагам для старта с полного нуля.
Выбор компилятора и установка среды
Для AVR существует множество разных компиляторов Си:
В первую очередь это IAR AVR C — почти однозначно признается лучшим компилятором для AVR, т.к. сам контроллер создавался тесном сотрудничистве Atmel и спецов из IAR. Но за все приходится платить. И этот компилятор мало того, что является дорогущим коммерческим софтом, так еще обладает такой прорвой настроек, что просто взять и скомпилить в нем это надо постраться. У меня с ним правда не срослось дружбы, проект загнивал на странных ошибках на этапе линковки (позже выяснил, что это был кривой кряк).
Вторым идет WinAVR GCC — мощный оптимизирующий компилятор. Полный опенсорц, кроссплатформенный, в общем, все радости жизни. Еще он отлично интегрируется в AVR Studio позволяя вести отладку прямо там, что адски удобно. В общем, я выбрал его.
Также есть CodeVision AVR C — очень популярный компилятор. Стал популярен в связи со своей простотой. Рабочую программу в нем получить можно уже через несколько минут — мастер стартового кода этом сильно способствует, штампуя стандартыне инициализации всяких уартов. Честно говоря, я как то с подозрением к нему отношусь — как то раз приходилось дизасмить прогу написаную этим компилером, каша какая то а не код получалась. Жуткое количество ненужных телодвижений и операций, что выливалось в неслабый обьем кода и медленное быстродействие. Впрочем, возможно тут была ошибка в ДНК писавшего исходную прошивку. Плюс он хочет денег. Не так много как IAR, но ощутимо. А в деморежиме дает писать не более чем 2кб кода.
Кряк конечно есть, но если уж воровать, так миллион, в смысле IAR :)
Еще есть Image Craft AVR C и MicroC от микроэлектроники. Ни тем ни другим пользоваться не приходилось, но вот SWG очень уж нахваливает MicroPascal, мол жутко удобная среда программирования и библиотеки. Думаю MicroC не хуже будет, но тоже платный.
Как я уже сказал, я выбра WinAVR по трем причинам: халявный, интегрируется в AVR Studio и под него написана просто прорва готового кода на все случаи жизни.
Так что качай себе инсталяху WinAVR с
Cоздание проекта
Итак, студия поставлена, Си прикручен, пора бы и попробовать что нибудь запрограммировать. Начнем с простого, самого простого. Запускай студию, выбирай там новый проект, в качестве компилятора AVR GCC и вписывай название проекта.
![]() |
Также не забудь поставить галочу Create Folder, чтобы у тебя все сложилось в одной директории. Ну и укажи место Location, где будет лежать проект. Указывай по короткому пути, что то вроде C:\AVR\ Как показывает практика, чем короче путь тем лучше — меньше проблем при компиляции и линковке проектов.
Проц у меня в Pinboard по дефолту ATmega16, поэтому выбираю его. Те же у кого в PinBoard стоит Mega32 (по спец заказу ставил некторым :) ) выбирают, соответственно ее.
![]() |
Открывается рабочее поле с пустым *.c файлом.
Теперь не помешает настроить отображение путей в закладках студии. Для этого слазь по адресу:
Меню Tools — Options — General — FileTabs и выбираем в выпадающем списке «Filename Only». Иначе работать будет невозможно — на вкладке будет полный путь файла и на экране будет не более двух трех вкладок.
Настройка проекта
Вообще, классическим считается создание make файла в котором бы были описаны все зависимости. И это, наверное, правильно. Но мне, выросшему на полностью интегрированных IDE вроде uVision или AVR Studio этот подход является глубоко чуждым. Поэтому буду делать по своему, все средствами студии.
Тыкай в кнопку с шестеренкой.
![]() |
Это настройки твоего проекта, а точнее настройки автоматической генерации make файла. На первой странице надо всего лишь вписать частоту на которой будет работать твой МК. Это зависит от фьюз битов, так что считаем что частота у нас 8000000Гц.
Также обрати внимание на строку оптимизации. Сейчас там стоит -Os это оптимизация по размеру. Пока оставь как есть, потом можешь попробовать поиграться с этим параметром. -O0 это отстутсвие оптимизации вообще.
Следующим шагом будет настройка путей. Первым делом добавь туда директорию твоего проекта — будешь туда подкладывать сторонние библиотеки. В списке появится путь «.\»
Make файл сгенерирован, его ты можешь поглядеть в папке default в своем проекте, просто пробегись глазами, посмотри что там есть.
![]() |
На этом пока все. Жми везде ОК и переходи в исходник.
Постановка задачи
Чистый лист так и подмывает воплотить какую нибудь хитрую задумку, так как банальное мигание диодом уже не вставляет. Давай уж сразу брать быка за рога и реализуем связь с компом — это первым делом что я делаю.
Работать будет так:
При приходе по COM порту единички (код 0х31) будем зажигать диодик, а при приходе нуля (код 0х30) гасить. Причем сделано будет все на прерываниях, а фоновой задачей будет мигание другого диода. Простенько и со смыслом.
Собираем схему
Нам надо соединить модуль USB-USART конвертера с выводами USART микроконтроллера. Для этого берем перемычку из двух проводков и накидывам на штырьки крест накрест. То есть Rx контроллера соединяем с Tx конвертера, а Tx конвертера с Rx контроллера.
![]() |
Кроме того, через USART мы теперь сможем достучаться до загрузчика (Pinboard идет с уже прошитым загрузчиком) и прошить наш контроллер не используя программатор.
Также накинем джамперы, соединяющие LED1 и LED2. Тем самым мы подключим светодиоды LED1 и LED2 к выводам PD4 и PD5 соотверственно.
![]() |
Получится, в итоге вот такая схема:
Подключение остальных выводов, питания, сброса не рассматриваю, оно стандартное
Сразу оговорюсь, что я не буду углубляться конкретно в описание самого языка Си. Для этого существует просто колоссальное количество материала, начиная от классики «Язык программирования Си» от K&R и заканчивая разными методичками.
Одна такая метода нашлась у меня в загашнике, я когда то именно по ней изучал этот язык. Там все кратко, понятно и по делу. Я ее постепенно верстаю и перестаскиваю на свой сайт.
Там правда еще не все главы перенесены, но, думаю, это ненадолго.
Вряд ли я опишу лучше, поэтому из учебного курса, вместо подробного разьяснения сишных тонкостей, я буду просто давать прямые линки на отдельные страницы этой методички.
Добавляем библиотеки.
Первым делом мы добавляем нужные библиотеки и заголовки с определениями. Ведь Си это универсальный язык и ему надо обьяснить что мы работаем именно с AVR, так что вписывай в исходник строку:
1 | #include <avr/io.h> |
Этот файл находится в папке WinAVR и в нем содержится описание всех регистров и портов контроллера. Причем там все хитро, с привязкой к конкретному контроллеру, который передается компилятором через make файл в параметре MCU и на основании этой переменной в твой проект подключается заголовочный файл с описанием адресов всех портов и регистров именно на этот контроллер. Во как! Без него тоже можно, но тогда ты не сможешь использовать символические имена регистров вроде SREG или UDR и придется помнить адрес каждого вроде «0xC1», а это голову сломать.
Сама же команда #include <имя файла> позволяет добавить в твой проект содержимое любого текстового файла, например, файл с описанием функций или кусок другого кода. А чтобы директива могла этот файл найти мы и указывали пути к нашему проекту (директория WinAVR там уже по дефолту прописана).
Главная функция.
Программа на языке Си вся состоит из функций. Они могут быть вложенными и вызываться друг из друга в любом порядке и разными способами. Каждая функция имеет три обязательных параметра:
- Возвращаемое значение, например, sin(x) возвращает значение синуса икс. Как в математике, короче.
- Передаваемые параметры, тот самый икс.
- Тело функции.
Все значения передаваемые и возвращаемые обязаны быть какого либо типа, в зависимости от данных.
Любая программа на Си должна содержать функцию main как точку входа в главную прогрмму, иначе это нифига не Си :). По наличию main в чужом исходнике из миллиона файлов можно понять, что это и есть головная часть программы откуда начинается все. Вот и зададим:
1 2 3 4 5 | int main(void) { return 0; } |
Все, первая простейшая программа написана, не беда что она ничего не делает, мы же только начали.
Разберем что же мы сделали.
int это тип данных которая функция main возвращает. Узнать подробней о типах данных
Конечно, в микроконтроллере main ничего вернуть в принципе не может и по идее должна быть void main(void), но GCC изначально заточен на PC и там программа может вернуть значение операционной системе по завершении. Поэтому GCC на void main(void) ругается Warning’ом.
Это не ошибка, работать будет, но я не люблю варнинги.
void это тип данных которые мы передаем в функцию, в данном случае main также не может ничего принять извне, поэтом void — пустышка. Заглушка, применяется тогда когда не надо ничего передавать или возвращать.
Вот такие вот { } фигурные скобочки это программный блок, в данном случае тело функции main, там будет распологаться код.
return — это возвращаемое значение, которое функция main отдаст при завершении, поскольку у нас int, то есть число то вернуть мы должны число. Хотя это все равно не имеет смысла, т.к. на микроконтроллере из main нам выходить разве что в никуда. Я возвращаю нуль. Ибо нефиг. А компилятор обычно умный и на этот случай код не генерит.
Хотя, если извратиться, то из main на МК выйти можно — например вывалиться в секцию бутлоадера и исполнить ее, но тут уже потребуется низкоуровневое ковыряние прошивки, чтобы подправить адреса перехода. Ниже ты сам увидишь и поймешь как это сделать. Зачем? Вот это уже другой вопрос, в 99.999% случаев это нафиг не надо :)
Сделали, поехали дальше. Добавим переменную, она нам не особо нужна и без нужны вводить переменные не стоит, но мы же учимся. Если переменные добавляются внутри тела функции — то они локальные и существуют только в этой функции. Когда из функции выходишь эти переменные удаляются, а память ОЗУ отдается под более важные нужды. Подробней о локальных и глобальных переменных, а также времени жизни оных.
1 2 3 4 5 6 | int main(void) { unsigned char i; return 0; } |
unsigned значит беззнаковый. Дело в том, что в двоичном представлении у нас старший бит отводится под знак, а значит в один байт (char) влазит число +127/-128, но если знак отбросить то влезет уже от 0 до 255. Обычно знак не нужен. Так что unsigned.
i — это всего лишь имя переменной. Не более того.
Теперь надо проинициализировать порты и UART. Конечно, можно взять и подключить библиотеку и вызвать какой нибудь UartInit(9600); но тогда ты не узнаешь что же произошло на самом деле.
Делаем так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | int main(void) { unsigned char i; #define XTAL 8000000L #define baudrate 9600L #define bauddivider (XTAL/(16*baudrate)-1) #define HI(x) ((x)>>8) #define LO(x) ((x)& 0xFF) UBRRL = LO(bauddivider); UBRRH = HI(bauddivider); UCSRA = 0; UCSRB = 1<<RXEN|1<<TXEN|1<<RXCIE|0<<TXCIE; UCSRC = 1<<URSEL|1<<UCSZ0|1<<UCSZ1; } |
Страшна? На самом деле реалного кода тут всего пять последних строк. Все что #define это макроязык препроцессора. Почти та же ботва, что и в Ассемблере, но синтаксис несколько иной.
Они облегчат твои рутинные операции по вычислении нужных коэффициентов. В первой строке мы говорим что вместо XTAL можно смело подставлять 8000000, а L— указание типа, мол long — это тактовая частота процессора. То же самое baudrate — частота передачи данных по UART.
bauddivider уже сложней, вместо него будет подставлятся выражение вычисленное по формуле из двух предыдущих.
Ну, а LO и HI из этого результата возьмут младший и старший байты, т.к. в один байт оно явно может не влезть. В HI делается сдвиг икса (входной параметр макроса) восемь раз в вправо, в результате от него останется только старший байт. А в LO мы делаем побитовое И с числом 00FF, в результате останется только младший байт.
Так что все что сделано как #define можно смело выкинуть, а нужные числа подсчитать на калькуляторе и сразу же вписать их в строки UBBRL = …. и UBBRH = …..
Можно. Но! Делать этого КАТЕГОРИЧЕСКИ НЕЛЬЗЯ!
Работать будет и так и эдак, но у тебя в программе появятся так называемые магические числа — значения взятые непонятно откуда и непонятно зачем и если ты через пару лет откроешь такой проект то понять что это за значения будет чертовски трудно. Да и сейчас, захочешь ты изменить скорость, или поменяешь частоту кварца и все придется пересчитывать заново, а так поменял пару циферок в коде и все само. В общем, если не хочешь прослыть быдлокодером, то делай код таким, чтобы он легко читался, был понятен и легко модифицировался.
Дальше все просто:
Все эти «UBRRL и Со» это регистры конфигурации UART передатчика с помощью которого мы будем общаться с миром. И сейчас мы присвоили им нужные значения, настроив на нужную скорость и нужный режим.
Запись вида 1<<RXEN Означает следующее: взять 1 и поставить ее на место RXEN в байте. RXEN это 4й бит регистра UCSRB, так что 1<<RXEN образует двоичное число 00010000, TXEN — это 3й бит, а 1<<TXEN даст 00001000. Одиночная «|» это побитовое ИЛИ, так что 00010000 | 00001000 = 00011000. Таким же образом выставляются и добавляются в общуюу кучу остальные необходимые биты конфигурации. В итоге, собраное число записывается в UCSRB. Подробней расписано в даташите на МК в разделе USART. Так что не отвлекаемся на технические детали.
Готово, пора бы посмотреть что получилось. Жми на компиляцию и запуск эмуляции (Ctrl+F7).
Отладка
Пробежали всякие прогресс бары, студия переменилась и возле входа в функцию main появилась желтая стрелочка. Это то где процессор в текущий момент, а симуляция на паузе.
![]() |
Пора сделать ШАГ! Нажми F11!
Видишь стрелочка сразу же скакнула на вторую строку, на UBRRH = HI(bauddivider);
![]() |
Дело в том, что изначально, на самом деле, она стояла на строке UBRRL = LO(bauddivider); Ведь то что у нас в define это не код, а просто предварительные вычисления, вот симулятор немного и затупил. Но теперь он осознал, первая инструкция выполнена и если ты залезешь в дерево I/O View, в раздел USART и поглядишь там на байт UBBRL то увидишь, что там значение то уже есть! 0х33.
![]() |
Сделай еще один шаг. Погляди как изменится содержимое другого регистра. Так прошагай их все, обрати внимание на то, что все указаные биты выставляются как я тебе и говорил, причем выставляются одновременно для всего байта. Дальше Return дело не пойдет — программа кончилась.
Вскрытие
Теперь сбрось симуляцию в ноль. Нажми там Reset (Shift+F5). Открывай дизассемблированный листинг, сейчас ты увидишь что происходит в контроллере в самом деле. View -> Disassembler. И не ЫЫАААА!!! Ассемблер!!! УЖОС!!! А НАДО. Чтобы потом, когда что то пойдет не так, не тупил в код и не задавал ламерских вопросах на форумах, а сразу же лез в потроха и смотрел где у тебя затык. Ничего там страшного нет.
Вначале будет ботва из серии:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | +00000000: 940C002A JMP 0x0000002A Jump +00000002: 940C0034 JMP 0x00000034 Jump +00000004: 940C0034 JMP 0x00000034 Jump +00000006: 940C0034 JMP 0x00000034 Jump +00000008: 940C0034 JMP 0x00000034 Jump +0000000A: 940C0034 JMP 0x00000034 Jump +0000000C: 940C0034 JMP 0x00000034 Jump +0000000E: 940C0034 JMP 0x00000034 Jump +00000010: 940C0034 JMP 0x00000034 Jump +00000012: 940C0034 JMP 0x00000034 Jump +00000014: 940C0034 JMP 0x00000034 Jump +00000016: 940C0034 JMP 0x00000034 Jump +00000018: 940C0034 JMP 0x00000034 Jump +0000001A: 940C0034 JMP 0x00000034 Jump +0000001C: 940C0034 JMP 0x00000034 Jump +0000001E: 940C0034 JMP 0x00000034 Jump +00000020: 940C0034 JMP 0x00000034 Jump +00000022: 940C0034 JMP 0x00000034 Jump +00000024: 940C0034 JMP 0x00000034 Jump +00000026: 940C0034 JMP 0x00000034 Jump +00000028: 940C0034 JMP 0x00000034 Jump |
Это таблица векторов прерываний. К ней мы еще вернемся, пока же просто посмотри и запомни, что она есть. Первая колонка — адрес ячейки флеша в которой лежит команда, вторая код команды третья мнемоника команды, та самая ассемблерная инструкция, третья операнды команды. Ну и автоматический коммент.
Так вот, если ты посмотришь, то тут сплошные переходы. А код команды JMP четырех байтный, в нем содержится адрес перехода, записанный задом наперед — младший байт по младшему адресу и код команды перехода 940C
Дальше идет предварительные приготовления, Си без них не может.
1 | +0000002A: 2411 CLR R1 Clear Register |
Обнуление регистра R1
1 | +0000002B: BE1F OUT 0x3F,R1 Out to I/O location |
Запись этого нуля по адресу 0x3F, Если ты поглядишь в колонку I/O view, то ты увидишь что адрес 0x3F это адрес регистра SREG — флагового регистра контроллера. Т.е. мы обнуляем SREG, чтобы запустить программу на нулевых условиях.
1 2 3 4 | +0000002C: E5CF LDI R28,0x5F Load immediate +0000002D: E0D4 LDI R29,0x04 Load immediate +0000002E: BFDE OUT 0x3E,R29 Out to I/O location +0000002F: BFCD OUT 0x3D,R28 Out to I/O location |
Это загрузка указателя стека. Напрямую грузить в I/O регистры нельзя, только через промежуточный регистр. Поэтому сначала LDI в промежуточный, а потом оттуда OUT в I/O. О стеке я тоже еще расскажу подробней. Пока же знай, что это такая динамическая область памяти, висит в конце ОЗУ и хранит в себе адреса и промежуточные переменные. Вот сейчас мы указали на то, откуда у нас будет начинаться стек.
1 | +00000030: 940E0036 CALL 0x00000036 Call subroutine |
Вот тут, собственно, идет переход к функции main. А через три команды как раз начинается Main. И переход идет через CALL, с сохранением адреса в стеке. При этом бездарно просерается два байта ОЗУ, а их всего 1024. =) Низачот! Впрочем, что то мне подсказывает, что обьявление main как inline int main(void) решит эту проблему, но не пробовал. Можешь сам проверить.
1 | +00000032: 940C0041 JMP 0x00000041 Jump |
Прыжок в сааааамый конец программы, а там у нас запрет прерываний и зацикливание наглухо само на себя:
1 2 | +00000041: 94F8 CLI Global Interrupt Disable +00000042: CFFF RJMP PC-0x0000 Relative jump |
Это на случай непредвиденых обстоятельств, например выхода из функции main. Из такого зацикливания контроллер можно вывести либо аппаратным сбросом, либо, что вероятней, сбросом от сторожевой собаки — watchdog. Ну или, как я говорил выше, подправить это мест в хекс редакторе и ускакать куда нам душе угодно. Также обрати внимание на то, что бывает два типа переходов JMP и RJMP первый это прямой переход по адресу. Он занимает четыре байта и может сделать прямой переход по всей области памяти. Второй тип перехода — RJMP — относительный. Его команда занимает два байта, но переход он делает от текущего положения (адреса) на 1024 шага вперед или назад. И в его параметрах указывается смещение от текущей точки. Используется чаще, т.к. занимает в два раза меньше места во флеше, а длинные прееходы нужны редко.
1 | +00000034: 940C0000 JMP 0x00000000 Jump |
А это прыжок в самое начало кода. Перезагрузка своего рода. Можешь проверить, все вектора прыгают сюда. Из этого вывод — если ты сейчас разрешишь прерывания (они по дефолту запрещены) и у тебя прерывание пройзойдет, а обработчика нет, то будет программный сброс — программу кинет в самое начало.
Функция main. Все аналогично, даже можно и не описывать. Посмотри только что в регистры заносится уже вычисленное число. Препроцессор компилятора рулит!!! Так что никаких «магических» чисел!
1 2 3 4 5 6 7 8 9 10 11 12 | +00000036: E383 LDI R24,0x33 Load immediate +00000037: B989 OUT 0x09,R24 Out to I/O location 15: UBRRH = HI(bauddivider); +00000038: BC10 OUT 0x20,R1 Out to I/O location 16: UCSRA = 0; +00000039: B81B OUT 0x0B,R1 Out to I/O location 17: UCSRB = 1<<RXEN|1<<TXEN|1<<RXCIE|0<<TXCIE; +0000003A: E988 LDI R24,0x98 Load immediate +0000003B: B98A OUT 0x0A,R24 Out to I/O location 18: UCSRC = 1<<URSEL|1<<UCSZ0|1<<UCSZ1; +0000003C: E886 LDI R24,0x86 Load immediate +0000003D: BD80 OUT 0x20,R24 Out to I/O location |
А вот тут косяк:
1 2 3 | +0000003E: E080 LDI R24,0x00 Load immediate +0000003F: E090 LDI R25,0x00 Load immediate +00000040: 9508 RET Subroutine return |
Спрашивается, для чего это компилятор добавляет такую ботву? А это не что иное, как Return 0, функцию то мы определили как int main(void) вот и просрали еще целых четыре байта не пойми на что :) А если сделать void main(void) то останется только RET, но появится варнинг, что мол у нас функция main ничего не возвращает. В общем, поступай как хошь :)
Сложно? Вроде бы нет. Пощелкай пошаговое исполнение в режиме дизассемблера и позырь как процессор выполняет отдельные инструкции, что при этом происходит с регистрами. Как происходит перемещение по командам и итоговое зацикливание.
Продолжение следует через пару дней …
А пока вот тебе готовый проект с тем, что есть сейчас
Offtop:
Alexei78 сварганил плагинчик для файрфокса облегчающий навигацию по моему сайту и форуму.
Обсуждение и скачивание, а также спасибы автору сего плагина в его теме на форуме
Спасибо за материал, весьма актульно. Пиши еще ;)
«Одиночная “|” это побитовое и, так что 00010000 | 00001000 = 00011000»
А не ИЛИ?
очипятка походу, в результате то верно
Вообще то | это именно побитовое OR
Так в чем прикол? 10 OR 01 = 11
Если б было И — то было бы 00
Кстати бывает не побитовое ИЛИ/И?
Конечно бывает. && или ||
Бывает еще логические.
Си хорош, я уже писал. Но на асме как-то читабельнее что ли, не могу обьяснить :). Я процессор ЧУВСТВУЮ. Вообще пора завязывать с АВР-ками ;). Надо помацать что-нить другое.
Си — хороший язык для плохих программ. А чтоб в нем было легче запутаться есть перегруженные функции, области определения переменных, неинициализированные переменные… для того чтоб просто подрыгать ногами контроллера, использование си необосновано.
И даже если приходится работать со строками, делать вычисление с плавающей запятой — гораздо интереснее это сделать на ассемблере. Никакой оргазм не сравниться с результатом долгой плодотворной работы.
Кроме того, никто не запрещает написанные единожды библиотеки таскать с собой из проэкта в проэкт.
«Си — хороший язык для плохих программ.»
Глупости пишете,молодой человек. Не так уж на свете много плохих ЯП, как много плохих реализаций. Плюс, не надо забывать, что в любом проекте есть такие вещи, как бюджет и сроки. Читайте Йордона «Путь камикадзе».
По поводу хорошего языка — это не мое личное мнение. Думаю вы не вникли в суть самой фразы.
«Си — инструмент, острый, как бритва: с его помощью можно создать и элегантную программу, и кровавое месиво» (Керниган). Я просто немного перефразировал.
Фраза потеряла свой первоначальный смысл. Любым хорошим инструментом можно сделать что-то стоящее, а можно и нанести себе травму. Именно это и хотел сказать автор.
Предлагаю консенсус, что каждой вещи — свое место.
На асме запутаться еще на порядок проще
Вот потому то я ценю комментарии. Например такие как, у DI Halt-а. Уникальные, запоминающиеся, понятные. А три килобайта кода просмотренные через год после написания больше напоминают мне китайскую граммоту и разбираться в них приходится практически заново.
Кроме того использование макровозможностей языка тоже очень помогает читабельности.
Грамотно написаная прога даже на асме не нуждается в комментариях! А кашу можно устроить и на си и никакие коменты тут не помогут.
Я многие свои проги, сделаные для себя, на асме, вообще никак не комментирую. Однако возвращаясь к ним через пол года-год четко помню что там и как работало.
А у меня комменты в коде если и встречаются, то содержат все тот же код :) И ничего, все понятно. Мне, по крайней мере)
> Грамотно написаная прога даже на асме не нуждается в комментариях!
Достаточно опасное заблуждение. Вероятно, оно простительно при программировании микроконтроллера с 1024 байтами памяти, но при создании большого проекта, включающего в себя множество аппаратно-зависимых частей (под совершенно разные платформы), да ещё и такого, над которым работает команда из более, чем 2 человек, уже в обязательном порядке требует четкого документирования кода.
А подход некоторых программистов, изложенный тобой, часто ведёт к катастрофическим последствиям в виде срыва сроков сдачи проекта.
Ну я не ставлю это в аксиому ессесно. Комменты нужны. Я к тому, что правильно написаный код сам по себе неплохо понятен.
>так что считаем что частота у нас 80000000Гц.<
Нолик по-моему лишний.
Не удалось мне в IAR сделать main встраиваемой. Это какой-то вопрос философии С.
С другой стороны, какой смысл использовать С в проектах, где на счету каждый байт.
Язык программирования S :)
Запили плиз методичку в PDF, чтоб ее скачать мона было.
DI HALT — огромный респект за обучалку по Си, степень с которой ты разжевываешь материал и приближаешь его к практике просто поразительная.
> Если переменные добавляются внутри тела функции — то они локальные и существуют только в этой функции
тут более обще: если переменные объявлены внутри блока ограниченного {}, они существуют внутри этого блока:
int main()
{
int TEST = 1;
{
int TEST = 2;
/* point_1 */
}
/* point_2 */
return 0;
}
будет ли ругаться компилер — проверьте :)
это наводит на такие извраты (хотя как посмотреть), типа локальных функций:
int main()
{
int foo(int v)
{
return v*v;
}
int r = foo(2);
return 0;
}
И ещё, я тут писал уже: http://hatred.homelinux.net/wiki/zhurnal:2009-10-02_13.44_0b00100100,
у gcc, и у gcc-avr в частности (и как полагается в WinAVR gcc тоже), есть удобная форма
представления бинарных констант: 0b11000110, по аналогии 0xFF для шестнадцатиричных систем.
А как у локальных функций с прожорливостью стека? И где она вообще распологается в коде? Прям в теле текущей функции?
А в виде ассемблерного кода они никаких отличий не несут :)
вот исходный вариант, фунции отличаются только именами и областью видимости:
— cut —
int bar(int f)
{
return f*f;
}
int main()
{
int foo(int v)
{
return v*v;
}
int r = foo(2);
r = bar(r);
return 0;
}
— cut —
все стороннее не инклужу, пока — за ненадобностью.
вот это код после обработки avr-gcc -S -mmcu=attiny2313 test.c:
— cut —
.file «test.c»
__SREG__ = 0x3f
__SP_H__ = 0x3e
__SP_L__ = 0x3d
__tmp_reg__ = 0
__zero_reg__ = 1
.global __do_copy_data
.global __do_clear_bss
.text
.global bar
.type bar, @function
bar:
push r29
push r28
rcall .
in r28,__SP_L__
in r29,__SP_H__
/* prologue: function */
/* frame size = 2 */
std Y+2,r25
std Y+1,r24
ldd r24,Y+1
ldd r25,Y+2
ldd r18,Y+1
ldd r19,Y+2
movw r22,r18
rcall __mulhi3
/* epilogue start */
pop __tmp_reg__
pop __tmp_reg__
pop r28
pop r29
ret
.size bar, .-bar
.type foo.1195, @function
foo.1195:
push r29
push r28
rcall .
in r28,__SP_L__
in r29,__SP_H__
/* prologue: function */
/* frame size = 2 */
std Y+2,r25
std Y+1,r24
ldd r24,Y+1
ldd r25,Y+2
ldd r18,Y+1
ldd r19,Y+2
movw r22,r18
rcall __mulhi3
/* epilogue start */
pop __tmp_reg__
pop __tmp_reg__
pop r28
pop r29
ret
.size foo.1195, .-foo.1195
.global main
.type main, @function
main:
push r29
push r28
rcall .
in r28,__SP_L__
in r29,__SP_H__
/* prologue: function */
/* frame size = 2 */
ldi r24,lo8(2)
ldi r25,hi8(2)
rcall foo.1195
std Y+2,r25
std Y+1,r24
ldd r24,Y+1
ldd r25,Y+2
rcall bar
std Y+2,r25
std Y+1,r24
ldi r24,lo8(0)
ldi r25,hi8(0)
/* epilogue start */
pop __tmp_reg__
pop __tmp_reg__
pop r28
pop r29
ret
.size main, .-main
— cut —
Оптимизация не включена, т.е. -O0, иначе он вообще там кода почти не оставляет, но это и правильно, и логично. Кстати, gcc -S — бывает полезно посмотреть, как там компилятор думает, и как он может наоптимиздить.
в общем, по коду — разницы никакой, поэтому, когда нужно ограничить область видимости, при проектировании, может оказаться полезным.
Красиво можно писать і на html
int main()
{
int foo(int v)
{
return v*v;
}
int r = foo(2);
return 0;
}
Что это за хак? Нельзя внутри одной ф-ции определить другую.
Ну да согласно ISO C такое нельзя, об том говорит avr-gcc -pedantic
а подробнее читать тут: http://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html
и давайте с категоричными заявлениями полегче? :)
Спасибо за ссылку.
Там вообще много интересного, 0b — тоже расширение gcc, правда если планируется другим компилером потом делать бинарник — придется или условную компиляцию делать или…
лучше как написал автор: UCSRB=(1<<RXEN), чем так UCSRB=0b00010000.
Первая команда будет всегда будет выполнена правильно, а вторая зависит от разрядности.
у автора талант объяснять сложные вещи простым языком. Таких бы как он, да в школу и институты, и на выходе мы бы получили огромное количество талантливых, увлеченных и обученных детей, вместо менеджеров с высшим образованием. :(
+миллион… а кроме всего прочего, взрослых людей, как я, всю жизнь живших в IT «высокого уровня», на твердую «4» знающих физику, умеющих паять, хлебнувших современного регионального высшего образования и подавившихся… вдруг ставших эмбеддерами:-))) Полгода назад я еще только с огромным интересом читал статьи Ди, ставил WinAVR, спотыкался о 16-ричные числа, тыркался в Протеус, пытался собирать что-то на макетке(УЖОС!)… Сейчас прохожу этап тестирования первого условно-коммерческого девайса(полный цикл разработки, от пустого экрана WINAVR до прототипа(ЛУТ, SSOP28+SOIC8+1206)), разорился на минидрель от СТ, станцию Lukey702, сделал сам PinBoard по доке от Ди(первая поделка ЛУТ-ом). Это я к чему? Да к тому, что мне уже почти 30, а КАК БЫ ЭТО УВЛЕКЛО смышленого 10-12 летнего пацана? А у нас по телеку Дом-2 и прочая гомосятина, дети растут — смотреть страшно… А я в 6-8 классах приходил со школы, а по телеку показывали телеуроки по физике, химии, ин. языкам… Сказать по правде, наверное именно этому я обязан своей тягой к знаниям, к новому… И если бы такие люди, как Ди, смогли бы объединиться против разрушения мозгов будущего поколения, было бы реально здорово…
проблема в том, что мало кто задумывается о том, что обучение можно поставить на коммерческие рельсы не только посредством платы за академический час, а иными способами. Поэтому то и желающий сеять разумное доброе вечное мало.
А всего то надо — взять и сделать что то легкое для понимания, интересное и поддерживать это. Посещаемость и своя аудитория в несколько тысяч человек возникнут уже через год, если не бросать и уже через год это будет отбивать на той же рекламе по деньгам на нормальную зарплату того же преподавателя. Но ты не будешь связан ни начальством, ни учебными планами, ни какими либо другими рамками — чистое творчество.
Воистину так… Только вот для того, чтобы организовать кружок радиоэлектроники, надо пройти не одну бюрократическую инстанцию(наверное, не стоит спорить, что кружок проще для восприятия 10-12-летнего товарисча, чем инет(если, конечно, дома у папы малолетнего товарисча не стоИт прокся, которая пускает дитятко только к «хорошим» ресурсам, и то, желательно с фильтром матерного:-)))))) Что касаемо ак. часов и т.п. — тут мое мнение таково: существующая система образования изжила себя на 100%(учился 2 курса без троек, в итоге понял, что новых знаний получаю минимум, зато плачУ — оочень некисло… и в основном эти деньги идут на благосостояние ректоров и Ко)… Одна из причин, почему я поднял эту тему здесь и сейчас — через полгода мне предпожительно нужно будет начать заниматься воспитанием маленького человека:-) И Я реально боюсь нынешней школы и ВУЗов… А воспитать и обучить самому — тоже крайне тяжко…
Полгода прошло. Уже воспитываеш? ;)
Ага, слоги разные учим:-))) Когда писАл прошлый пост, еще не знал даже, кто будет — в итоге получилась девочка — а это по моим представлениям, посложнее будет чем мальчик — чуть недоглядел, и на тебе гламурное кисо:-))) Плюс еще специфика приграничного города — кругом шальные бабки, крайне низкий уровень культуры, в итоге полное б…ство. Очень хочется к следующему году заработать хоть на какую-то лачужку с участком за городом — имхо, там лучше и проще воспитывать, поближе к природе, земле, и прочим патриархальным ценностям. А как в голове устаканится разумное-доброе-вечное — можно и эмбеддера начинать воспитывать — в огороде куча объектов для автоматизации:-)
Есть пара замечаний.
«Любая программа на Си должна содержать функцию main, иначе это нифига не Си :)»
Не совсем так. Может и не содержать, если это модуль, который потом обрабатывается препроцессором, компилируется, а код потом уже добавляется линкером. То есть, main — точка входа в _основную_ программу.
«#include »
Это ни разу не библиотека, а файл, содержащий прототипы функций и макроопределения. Библиотеки имеют имя, заканчивающееся на a., so.
спс. пофиксю.
Кстати макроопределения #define лучше делать в самом начале файла, а не внутри функций.
Это традиция :) Автору явно куда близок ассемблер, чем «кроссплатформенный ассемблер» :)
Вообще, когда я пишу на си, то все подобные макроопределения у меня всегда вынесенеы в HAL.h , просто тут я до этого момента еще не дошел :)
Поэтому да, пишу в ассемблерном стиле.
Спасибо автору! Как начинающему, интересно почитать изложенное, если на простом, доступном языке. Вот бы документацию потом к IAR-у 5.2 где нить достать, желательно на русском.
Вместо 1<<RXEN полезно использовать _BV(RXEN) определенную в sfr_defs.h
Те же яйца только выглядят непонятно.
Вот-вот! :) Что ещё за _BV ? Ни C99, ни POSIX про такую хрень ничего не знают.
Мало того, в дефайнах этот бв все равно вырождется в 1<<x
Естественно, что вырождается. Но поскольку вся библиотека, идущая с WinAVR’ом написана с использованием _BV (как, впрочем, и сторонний код — достаточно погуглить), не вижу смысла не использовать ее. Общий стиль он зачастую многого стоит.
> #define XTAL 8000000L
выбросить строку, а вместо
> #define bauddivider (XTAL/(16*baudrate)-1)
написать
#define bauddivider (F_CPU/(16*baudrate)-1)
дело в том что частоту камня Вы уже указали в make файле, непонятно зачем плодить макросы с одним значением под разными именами
а если по теме, то писать на С — это удобно, понятно, современно и т.д. Поэтому всех призываю: Пишите на С ! http://www.youtube.com/watch?v=XHosLhPEN3k
:)
Да, знаю. Об этом дальше сказано. Просто сам оригинальный макрос расчета был мною скопирован из ассеблерного файла, а там у меня принято обозначение хстал.
Эх… Когда уже будем МК программить на с++(С + ООП + куча разных фишек)?:)
Когда у МК будет памяти не меньше 128мб и флеша пару гигабайт.
avr-g++ :-D
кстати посмотри, в WinAVR (плять скачаю уже, хоть какие там исполнимые файлы есть посмотрю), должен быть.
код получается несколько больше, нннооооо на порядки 128мб не выходит никак.
В топку паравоза по мотивам соседней темы, про ардуино — там именно C++ и многие средства стандартной библиотеки сделаны именно классами (типа Serial и LCD).
PS сам на C++ пишу только гуй когда нужно
PPS существовала шутка: что будет если ядро линукс переписать на C++ — Windows!
Хотелось бы, чтобы никогда. :) Иначе и туда понабежит куча малообразованых индо-китайцев-недоучек, которые ничерта не понимают в программировании, но хорошо умеют всё подряд «инкапсулировать» и «наследовать». :)
Пошли обсуждения и вопросы как чего и где компилится. Это бессмысленно без указания конкретного компилятора. Вспомните про i++ + i++. Язык языком, а компилятор компилятором..
по моему явно были указаны компилятор WinAVR
Отличная статья!!!
Первый раз взглянул что компилятор компилит! -)))
Вопрос, почему похожие варанты копилятся по разному:
==========установка бита — всего одна команда
36: ACSR |= (1<<ACBG);
+00000029: 9A46 SBI 0x08,6 Set bit in I/O register
==========то же самое — аж 3 команды
47: GIMSK |= (1<<PCIE); //разреш. прер. от PCI для Tiny13
+0000002A: B78B IN R24,0x3B In from I/O location
+0000002B: 6280 ORI R24,0x20 Logical OR with immediate
+0000002C: BF8B OUT 0x3B,R24 Out to I/O location
==========аналогично — 1 команда
48: PCMSK |= 0b00010000; //прер. возн. при изм. вывода PCINT4
+0000002D: 9AAC SBI 0x15,4 Set bit in I/O register
==========теперь — 2!!!!!
49: TCCR0A = 0b00000010; //установка режима — сброс по соапад.
+0000002E: E082 LDI R24,0x02 Load immediate
+0000002F: BD8F OUT 0x2F,R24 Out to I/O location
Почему так по разному получается?
Заранее спасибо!!!
в первом случае адрес регистра ACSR=0x08 поэтому до него может дотянутся команда SBI (она работает в поле от 0 до 0х1F)
Во втором случае у нас адрес уже 0x3B, что уже значительно дальше. ПОэтому доступ только через IN OUT, а поскольку нам надо изменить всего один бит из байта, то делаем чтение, по маске накладываем 1 и пихаем байт на место — три команды.
Во втором случае нам надо записать два бита — поэтому грузим непосредственно число и загружаем его по адресу.
Компилятор тут молодец, не сделал ни одного лишнего движения.
Спасибо! Просто и доходчиво!
Вот только не понял где в последнем случае меняем ДВА бита?
49: TCCR0A = 0b00000010; //установка режима — сброс по соапад.
+0000002E: E082 LDI R24,0×02 Load immediate
+0000002F: BD8F OUT 0×2F,R24 Out to I/O location
Вроде только одну единичку ставим?
Хотя…. ведь целый байт пишем!!
А, я просто посмотрел на позицию. Да, тут мы явно пишем целый байт.
Попробуй указать как TCCR0A |=1<<WGM11;
и посмотри какой будет код. Будет три команды.
Потому как там мы явно перезаписываем весь байт. А в этом случае явно меняем только один бит, остальные не трогая.
Да действительно, получается 3 команды!!!!
50: TCCR0A |=1<<WGM01;
+0000014A: B58F IN R24,0x2F In from I/O location
+0000014B: 6082 ORI R24,0x02 Logical OR with immediate
+0000014C: BD8F OUT 0x2F,R24 Out to I/O location
Но ведь предыдущие 2 команды и эти 3 команды выполняется разное количество тактов? И не факт, что эти три, выполняются дольше чем «те» две?
У авр каждая команда выполняется за такт. Только некоторые переходы за два. Так что три команды это дольше чем две :)
Спасибо!!!
Было бы интересно в следующих выпусках этой серии увидеть какие-нибудь базовые (общие) рекомендации по оптимизации кода. Ведь одну и ту же операцию можно реализовать разными методами!
Попробую сформулировать.
У меня такой вопрос.Каким драйвером осуществляется вывод данных на USB со стороны кампа?
FTDI USB-COM
Тоесть это хардварный преобразователь USBCOM?
http://eu.mouser.com/ftdiusbcomplus/
Да
Козырь твой оригинальность. Белый цвет на белом фоне не использовал никто.
s44.radikal.ru/i106/0911/90/5a06b4db4782.png
Вообщет там черная шапка еще. У тебя видимо что то не догрузилось.
Спасибо за ответ. Всё догрузилось. Просто у меня почти всегда выключен javascript (это вырубает всю рекламу и большинство ненужных свистелок-перделок) и автоматическая загрузка картинок. Не люблю во время чтения отвлекаться на всякие летающие и порхающие хреновины. Жаль что при этом меню не видно.
Так это Опера твоя глючит!!!! У меня все нормально!!!!
Мне приложить скрины из других браузеров, умеющих отключать картинки?
DI HALT очень большое спасибо за статью. Понравилась. Есть к вам большая просьба написать статью в продолжение этой темы про работу с программой WinAVR и её библиотеки. Я работаю с CodeVision AVR но все рекомендуют переходить на WinAVR так как он делает более компактный и оптимальный код. А толкового самоучителя по этой программе нету.
Еще будет, хочу сделать полный курс по WinAVR.
План примерно такой:
Вводная, общие сведения (три четыре части)
Принципы построения алгоритмов (суперцикл, флаговый автомат, RTOS)
Основы отладки, отладочные приемы. Поиск багов.
Постепенный разбор всех либ под WinAVR начиная от простейших, вроде LCD и до USB или Эзернета.
Думаю нетолько я буду ждать с нетерпением эти статьи. Заранее огромное спасибо.
По поводу UCSRB = 1<<RXEN… Есть же еще конструкция UCSRB |= 1<<RXEN, дабы не изменять остальные биты. А так же для новичков есть &= ~ для установки нужного бита в 0.
Да, по поводу WinAVR. Вот в хелпе к нему, например, есть разъяснение как взять элемент массива. Так вот из-за того самого портирования gcc на АВР и введения кучи всяких макроопределений делается это не совсем так, как кажется на первый взгляд :) И наверное в том же хелпе ещё много подобных разъяснений. Так вот по поводу реализации таких казалось бы простых вещей хотелось бы узнать по-больше
В смысле? как помню ,берется также как и везде. Или имеется ввиду массив в ПЗУ?
Автору огромное спасибо за труд!
Побольше примеров на АСМЕ для этой платки, и полностью поддерживаю мысль, что нужно сначало освоить ассемблер, а уже потом (возможно многим и не понадобиться) изучать Си.
ИМХО — быстро незначит лучше!
На асме -весь прошлый материал сайта. Впрочем, новый тоже будет. Хотя мне сейчас бы надо материалу по Си надавать, чтобы была база под построение новой системы.
DI, а не подскажешь, как сделать разноцветную подсветку синтаксиса? А то у меня менее цветасто(( http://s54.radikal.ru/i143/0911/73/bdfa01b07c5c.png
Версия студии 4.17
Невнимательно сначала прочитал… А можно сделать подсветку в студии как в Visual Studio ?
У меня в студии также. Тебе мало? а то что на сайте это уже средства хтмл :)
Жаль что остановились на «1.4.12. Оператор goto» в «Язык программирования С. Справочник»
Скоро выложу остальные части. Кстати, попробуй выделить любой кусок текста оттуда и погуглить. Наверняка есть где нибудь в инете эта метода.
Какая-то фигня… Установил студию, прикрутил к ней Си, в оболочке проделал все процедуры (давил на шестеренку, выбирал каталоги, нажимал на «Ок») — Make-файл не создается. В папке проекта (D:\ПРОЕКТЫ\Микроконтроллеры\3) появились два файла: 3.aps и 3.c, и пустая папка default. Make-файла нет. Соответственно, компиляция не идет.
Make-файл создается автоматически? Есть возможность создать его какой-то кнопкой/пунктом_меню в оболочке? Что не сделано или сделано не так?
Версия студии:
AVR Studio 4.17.666
GUI Version 4, 17, 0, 655
AVR Simulator 1, 0, 2, 1
ATMEGA16 247
Operating System
Major 5
Minor 1
PlatformID 2
Build 2600
Service Pack 2
Plugins:
AvrPluginAvrAsmObject 1, 0, 0, 47
AvrPluginavrgccplugin 1, 0, 0, 11
Stk500Dll 1, 0, 1, 13
У меня мейк создался автоматически. Может ты по ошибке галочку не туда воткнул или еще что?
По каким путям ставил студию и WinAVR?
Студия C:\Program Files\Atmel\AVR Tools
Си C:\WinAVR
в Опции Custom Options галка в WinAVR стоит, в поле avr-gcc C:\WinAVR\bin\avr-gcc.exe, в поле make C:\WinAVR\utils\bin\make.exe
Аналогично. А что пишет? какие нибудь ошибки говорит при попытке скомпилить?
make: Makefile: No such file or directory
make: *** No rule to make target `Makefile’. Stop.
Build failed with 2 errors and 0 warnings…
make: Makefile: No such file or directory
make: *** No rule to make target `Makefile’. Stop.
Build failed with 2 errors and 0 warnings…
Мда, мрак. Ничего не понять. Попробуй там создать пустой мейк файл. У Тебя директорию дефаулт оно уже сделало?
А что в Сишном файле у тебя?
Еще раз вышел и заново зашел, указал директорию проекта \4
В ней после нажатия Ок в шестеренке появились 4.aps и 4.c
Директория default не создалась…
В сишном файле:
#include
int main(void)
{
unsigned char i;
#define XTAL 8000000L
#define baudrate 9600L
#define bauddivider (XTAL/(16*baudrate)-1)
#define HI(x) ((x)>>8)
#define LO(x) ((x)& 0xFF)
UBRRL = LO(bauddivider);
UBRRH = HI(bauddivider);
UCSRA = 0;
UCSRB = 1<<RXEN|1<<TXEN|1<<RXCIE|0<<TXCIE;
UCSRC = 1<<URSEL|1<<UCSZ0|1<<UCSZ1;
return 0;
}
ПОпробуй открыть мой проект, из файла.
В окне Message
Loaded plugin STK500
Loaded plugin AVR GCC
Loaded partfile: C:\Program Files\Atmel\AVR Tools\PartDescriptionFiles\ATmega16.xml
почему нет сообщения о загрузке plugin-компоненты make?
его не должно быть?
Это не плугин компонента, это консольная утилитка которую аврстудия вызывает для сборки проекта.
Столкнулся с такой же проблемой. Она (AVR-Studio) не находит makefile если в пути к нему присутствуют русские символы.
решение просто: в makefile не использовать кириллицу
Студия не создает Makefile. т.е. при создании проекта makefile должен создаваться (если выключена опция использования внешнего makefile-а), а он не создается… создал проект в корне диска D: — не помогло…
Стоп! Записал текст проги и запустил компиляцию — ругнулось кучей ошибок, но после этого создался и makefile и default директория… идем дальше
В итоге имею такую картину в окне сообщений:
avr-gcc -I»D:\4\5\.» -mmcu=atmega16 -Wall -gdwarf-2 -std=gnu99 -DF_CPU=8000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT 5.o -MF dep/5.o.d -c ../5.c
../5.c: In function ‘main’:
../5.c:4: warning: unused variable ‘i’
Build succeeded with 1 Warnings…
Победа будет за нами…
Должен появиться кекс!
В итоге имею такую картину в окне сообщений:
Да, нормалек, все фурычит. Сейчас взад верну студию 4.17 и WinAVR последний и еще раз проверю. Спасибо за присутствие :-)
Все вернул, проверил, работает. НО. Первый прогон компилятора все равно сопровождается руганью. Повторно компилирую — все ОК
make: `7.o’ is up to date.
Build succeeded with 0 Warnings…
А тебе надо грохнуть все обьектники в папке дефолт.
И еще, сноси нахер эту 17ю версию. Глючное говно. Мне тут с фронта сообщили прикольную вещь — она на меге88 криво инициализирует стек. Т.е. тупо в регистр SP (в эмуляции) ничего записать нельзя, а это сам понимаешь пиздец высшей категории. Не зря билд 666
ШО, ОПЯТЬ???!!! :-)
да, про 666 я тоже отметил…
ладно, пока пусть работает, до первого косяка.
насчет объектных файлов — заново все определяю, создаю новый проект, текст программы копирую через буфер обмена, первый раз компилирую (жму alt+F7) — ругается на отсутствие makefile-а, директории default и еще на что-то. повторно, тут же, компилирую (жму alt+F7) — все ок. вот что характерно…
А у тебя оно в переменные среды прописалось? ПРоверь. Там должна быть куча путей на аврлиб
Это куда ОНО должно прописаться? Где эти переменные среды?
Мой компьютер-Свойства-Дополнительно-Переменные среды.
Там в переменной Path «C:\WinAVR\bin;C:\WinAVR\utils\bin;%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem;D:\3dsmax5\backburner2\;C:\Program Files\Common Files\Autodesk Shared\;C:\Program Files\Pico Technology\PicoScope6\»
Тут для всех прог, в том числе и для винавр.
Еще должны быть переменные
AVRLIB = C:\Program Files\AVRlib (у тебя скорей всего будет другой путь)
Переменная PATH есть, в ней C:\WinAVR\bin;C:\WinAVR\utils\bin;%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem;C:\Program Files\Samsung\Samsung PC Studio 3\
а вот переменной AVRLIB -нет совсем…
в какой раздел добавлять переменную AVRLIB — в переменные среды пользователя или системные переменные? и путь — он где, в составе студии или WinAVR-а?
Стоп, аврлиб это проксиконовская либа. Ее в стандартной поставке WinAVR нет. Поэтому добавив ее ничего не изменится. Тут что то другое… может криво встало? В каком порядке ставил все?
Сначала студию, потом WinAVR.
Тоже подумал, что где-то кривизна, переустановил студию, заменил 4.17 на 4.16, предположив, что может быть какая-нибудь бага в новой версии — не помогло.
Посмотри у себя в меню Tools\Plug-in Manager, у меня там есть Make? У меня три строки — ассемблер, AVR GCC, STK500
У меня 5, но это дело не меняет — другие два протеус и редактор векторов для асма.
Про переменные среды уточни, о чем речь?
Каким образом можно подключить WinAVR к AVR Studio 4 как plugin? Plug-in manager студии, WinAVR не видит.
В этой статье первым рекомендуется ставить AVR Studio, а в статье http://easyelectronics.ru/avr-studio-likbez.html#more-116 наоборот…
В принципе без разницы что ставить в каком порядке. Студия сама видит winavr и цепляет ее плагином, а winavr же сама видит студию и сразу же там тоже прописывается. Но надежней работает если сначала ставить студию, а потом накручивать winavr.
Все у меня делалось автоматом и никаких телодвижений делать не приходилось.
Project Options -> Custom Options — External Tools — check box — Use WinAVR где автоматом прописались пути к avr-gcc.exe и make.exe. Это имелось ввиду под словами «видеть winavr»?
Нет даже это я не делал.
Видеть winavr означает что студия сама каким то образом определяет что на компе стоит winavr и узнает пути к нему (либо через PATH либо через реестр, хз) и сама ее правильно везде прописывает.
Я тоже руками не прописывал. После установки AVR Studio и WinAVR пути сами прописались. Меня ввело в заблуждение слово «plugin». Полез в Plug-in Manager студии, а там WinAVR нет, там AVR-ский компилятор, потому и задал вопрос.
Спасибо.
У меня там AVR GCC написано. Производитель пишет что Atmel, но это winavr и есть
Ди, прикрепи к этой статье метку «С». А то она только к последующим частям прикреплена. Не сразу нашёл.
Посоветуйте пожалуйста какую книгу можно почитать по программированию на Си для atmega.
Описание синтаксиса языка не особо важно так как Си знаю, хотелось бы что бы было описание функций, констант/определений и были примеры программирования на Си для atmega.
Да нет их почти. У меня в разделе Книги лежит парочка, но они очень уж вялые.
Cпасибо за „Учебный Курс. Программирование на Си,“ но нельза бы от слов перейти к делу и продолжить,и то чего нет на других строницах(везде «учёба» заключаеться в описании моргании свет.диода и таймера переписанниго друг у друга )да побольше коментариев, а то мы думаем что если мы это знаем то и все должны это уже знать-лучше повториться-повторения мать учения.
Конечно будет. По приезду думаю дать ликбез по указателям, потом по архитектуре. И только потом диодиком помигать :)
День добрый.
Есть вопрос по поводу #define.
Например:
#define a 8
#define b 10
#define c a/b
Какого типа будет переменная с? и что в ней будет лежать?
ну во первых это не переменная, а макроопределение. А лежать в ней скорей всего будет целая часть от деления. Хотя я точно не помню какой дефолтный формат числа в макросах. Но тип можно указывать после. Например
#define a 8UL
То есть, что бы у меня переменная «с» была Float, надо написать:
#define a 8.0F
#define b 10.0F
#define c a/b
Или я думаю не в том направлении? =(
PS Макроопределение тоже должно иметь тип )
Да прмерно так. надо только синтаксис уточнить, я не помню точно.
Макроопределение на то и макроопределение, чтобы не иметь типа :)
Исторически, это очень древний костыль, который работает за счёт ТЕКСТОВЫХ подстановок. То есть тупо сначала подставляются в текст все дефайны, а потом уже полученный текст компилируется.
в итоге тип выражения (и не только) зависит от контекста. К примеру:
#define a 8
#define b 10
#define c a/b
char i = c * 3;
Развернётся в
char i = 8/10 * 3;
Что в итоге даст 0 (целочисленное деление 8 / 10 — результат целый, меньше 1, значит 0).
В то время как
i = 3 * c;
Даст
i = 3 * 8/10;
И в итоге 2 (3 * 8 = 24, 24 / 10 = 2).
Макросы — штука весьма полезная, но как раз из-за их «тупого» поведения многие советуют от них воздерживаться. Не думаю, что на микроконтроллерах можно без них обойтись без ущерба, но во всяком случае, с ними надо обращаться осторожно.
PS Для самостоятельного изучения предлагаю постичь разницу между
#define c a+b
и
#define c (a+b)
в контексте, скажем
d = 3 * c;
А после изучения всегда заключать макросы в скобки (как, кстати, сделано в данной статье). Это не избавит от всех граблей, но сильно облегчит жизнь.
Достаточно так:
#define a 8.
#define b 10.
#define c a/b
Точка является указанием, что число не целое и нужны вычисления с плавающей запятой. Если точек нет, то число — целое и «мерин разрубленный пополам — это не пол мерина, а ноль меринов».
Очень понравился курс. Но обязательно нужно продолжение.
Как писать прерывание в AVRSTUDIO4
По моему я указывал как описывать прерывание. Причем неоднократно.
Очень понравился курс. Но обязательно нужно продолжение.
Как писать прерывание в AVRSTUDIO4
Я сделал простейший эксперимент: Написал прогу моргания светодиодом в ИАРе в АВРстудио4 и в Ошоне для меги16 код на Ошоне
в 2 раза меньше. Поэтому делаю вывод ИАР и АВРстудио зело избыточны!
что за ошон?
В два раза меньше код или хекс? Попробуй написать не моргание светодиодом, а приоритетный диспетчер и посмотри на разницу в размерах хекса.
Ошон — это OshonSoft там есть Picsimulator, Pic18simulator Pic12simulator
AVRsimulator http://www.oshonsoft.com
я на нём много прог написал.Очень простая и понятная штука хотя на английском.Один общий язык что пики, что авры и главное без глюков.
Симулятор прямо в пакете. Написал-проверил.
Недостатки конечно есть нет знаковых представлений чисел,таймеры авр
не симулируются.
Аааа еще одна тупиковая ветвь эволюции :)
Как это «WinAVR и цепляется к студии в виде плагина»? У меня после установки WinAVR он со студией никак не связан. Кнопки с шестерёнкой не появилось.
А должна. Видимо что то где-то не прописалось при установке
Ладно, попробую переустановить.
Попутно есть ещё вопрос. Я устанавливал AVRStudio на разных компьютерах, на одном возникла такая фигня: создаём проект, выбираем AVR Simulator, в левой колонке ищем тип AVR — нужен ATMega8 и оказывается, что его выбрать нельзя, он прописан бледно серым цветом. Если перенести на этот комп готовый проект для мега8 то отладчик запускаться не будет. На других машинах с отладкой для мега8 всё в порядке. Это имеет какое-то разумное объяснение или тоже мистика?
В комментах кто то тоже на это жаловался. Дается мне тоже из серии глюков.
Посоветуйте пожалуйста книжечку по программированию на С для АВР от А до Я там где более детально описана теория, но не слишком много лишнего. (ну так ориентировочно страниц до 300)
Кроме Керниган и Ритчи Язык программирования Си не встречал таких :) А под си именно на АВР вообще ни одной толковой книжки.
на авр именно ни одной толковой или вообще ни одной? если первое, то на сколько они плохие?
У меня в разделе Книги есть одна. Пожалуй единственная на русском. Была еще одна на английском, но названиен не вспомню.
Неправда, есть :)
1. Empbedded C programming and the Atmel AVR, second edition.
2. Pardue WinAVR C programming for AVR microcontrollers.
Если интересует просто язык безотносительно контроллеров, то рекомендую Побельского и Фомина — «Язык программирования C».
делаю все пошагово как описано в статье (создание проекта)
не генерируется make файл. пути настраиваю — списке появится путь “.\” , но в папке default ничего не появляется.
загадка) кто-нить сталкивался с такой проблемой?
Создавай проекты в корневом каталоге диска.
Путь к проекту не должен содержать русских букв.
Пути короткие? что пишет в ошибках?
путь такой — C:\AVR_work\C_1
латиницей
все, вопрос снят.
глюк такого характера:
не генерируется make файл. пути настраиваю — списке появится путь “.\” , но в папке default ничего не появляется. даже если нажать «обновить». соответственно и при компиляции ругань
Но!
при закрытии Студии с сохранением проекта — туда прописывается все что надо. и при следующем открытии проекта и компиляции — усе проходит как надо без воплей Студии «Где файлы!?!»
видимо WinAVR как то криво к Студии прикрутилась
хотя странно все это, странно
> Поэтому GCC на void main(void) ругается Warning’ом.
Чтобы этого не происходило, используйте -ffreestanding
Хочу прочитать два байта из ОЗУ термодатчика DS18B20, делаю это в цикле. Почему-то переменная temp1 не меняется, всегда остаётся нулём. Не могу найти ошибку в цикле.
short temp1;
short tmp;
int i;
for (i=0;i<16;i++)
{
DDR_DQ |= 0x08; //пин на выход
PORT_DQ &= 0xF7;
_delay_us(5);
DDR_DQ &= 0xF7; //пин на вход
_delay_us(10);
tmp = PIN_DQ;
if ((tmp&(1<<3)) == 0) // если не установлен 3 бит переменной tmp
{
temp1 <<= 1;
}
else {
temp1 +=1;
temp1 <<= 1;
}
_delay_us(45);
}
Может в тайм слот не попадаешь?
К автору статей.
Я являюсь новичком в вопросах работы с микроконтроллерами. Главным образом потому что потребность в них возникает довольно редко. Когда впервые возникла потребность что-то напрограммировать и залить в камень (с год-полтора назад), узнал от товарища об этом сайте и буквально за пару дней наваял простенькую программку, всё было предельно просто и понятно, всё заработало: и порты, и таймеры, и ШИМы…. От прочитанного материала оставалось ощущение просто экстаза. Всё легко, последовательно, просто. Писал на АСМе.
Теперь снова возникла необходимость — сейчас ваяю цифровой одометр. Увы, курс сильно изменился… И так, двояко… Уже пятый день сидел жевал АСМ-овую часть курса. Курс явно углубился, но если бы не кое-какие знания, со многим точно не разобрался бы! Часто сильно не хватает примеров кода. Не хватает подобия статьи «Первая программа» или как-то так, где просто были бы описаны основные команды, операторы, как забрасывать большие числа в регистры, как понимать и пользоваться установкой, смещением битов через угловые скобки, как курить даташит в конце концов и много другого, базового….
Прошу понять меня правильно, этот коммент родил с точки зрения обывателя, чтобы курс по части АСМа, возможно, стал лучше, а никак не для выражения какого-то недовольства. Раньше, действительно, он читался легче. Сподвигло, кстати, прочтение этой статьи, где всё разжёвано и в рот положено — глотать легко и приятно.
По части асма так он и не менялся. Некоторые статьи были дополнены и переписаны на атмега16 только и всего.
Единственно, я довольно сильно перелопатил хронологию статей. Т.е. сильно поменялся их порядок. Основную теорию я стараюсь вынести вперед, а практику и примеры потом.
Приветствую.
DI, в каком порядке всетаки корректнее устанавливать ВинАВР и Студию? В статье «AVR Studio ликбез» ты говорил:
«рекомендую скачать GCC aka WinAVR и установить ее ДО студии, туда же, поближе к корню. Тогда студия подхватит ее в качестве своего плагина. Если поставить после, то тоже, может быть подхватит, но возможны проблемы.»
А в этой статье — наоборот:
«Так что качай себе инсталяху WinAVR с официального источника и AVR Studio. Далее вначале ставится студия, потом, сверху, накатывается WinAVR и цепляется к студии в виде плагина.»
И еще вопрос — планируешь ли ты возобновить (закончить :)) работу над своим «Язык программирования С. Справочник»? А то там, начиная с раздела 1.5 Функции — идет возврат к содежимому справочника.
Ставил и так и эдак. Ставилось всегда ОК. так что думаю похрену.
Надо допилить, но все руки не доходят. А вообще эта методичка довольно легко гуглится. Скопируй любой кусок текста оттуда и нагугли.
Не знаю почему кому то нравится писать на С… Для меня дык самые лучшие языки это асм и Algorithm Builder…. Буилдер хотя бы из за того что в данный момент занят переводом важных мне процедур с С и асма на буилдер и из асма это делается за пару сек, а с С надо прыгать с бубном…. На буилдере кстати нормальную прогу без знания асма написать проблематично, только поделки типа мигания светодиодом…
PS: Видимо я программер старой закалки — я программировал раньше в асме под 8086 и Z80…
На АБ дальше AVR не упрыгаешь. А на Си смена МК без взрыва мозга занимает ну день два. Мне чтобы пересесть на STM32 потребовалось пару часов.
АБ есть только под авр. Так что какой бы он удобный ни был — он ограничен со всех сторон. Плюс его разрабатывает один человек. Представь, что завтра с Громовым что то случится. Где окажется АБ? Будете изучать дружно СИ?
Нет я при переходе на другой кристалл все равно буду стараться учить асм, СИ это крайний случай… А если даже что и случится с Громовым то АБ некто у AVRщиков не заберет :)
Полный файл методички по С в формате ms word 2003
http://www.sendspace.com/file/hg6aam
Кстати, попробовал спасти те самые два байта на вызов main’а.
Ни фига не вышло =(
Ни inline, ни уровни оптимизации, ни другие попавшиеся под руку опции не спасают. Вставляет RCALL, хоть ты тресни :(
Привет. Подскажи как настроить цветовое оформление в окне дизассемблера? а то там всё просто серое, без подсветки, в редакторе подсветка нормальная.
ХЗ, не заморачивался.
Привет)) Помогите плз раскурить проблему в Си, а она такова: студия не хочет комплить ничего, что хоть как-то связано с задержками(паузами). На либу ругается, хз на что, что-то там expretion ‘=’ token. Читал про это в одной из частей по курсу авр, и так и не понял, как это устраняется. Я так понял это какая-то бага с присвоением. А прога-то детская, проще только… пустой маин и ретёрн 0;
Code:
#define F_CPU 8000000UL
#include
#include
#include
int main(void)
{
DDRD = 0xFF;
While(1=1)
{
PORTD = 0b11111111;
_delay_ms(200);
PORTD = 0b00000000;
_delay_ms(200);
}
}
Типа аццкая прога мигания чем-либо)) Пытаюсь подучить ассемблер по учебному курсу AVR от DI, все суточные трапезы теперь, вместо сопровождения фильмами, сопровождаются втыканием в ассем. Подтверждаются все цитаты DI: можно и башкой апстену, и вынести моск напрочь, а в моем случае, похоже, после 7 или 8 части все извилины сплелись в дичайшую косищу, и как это теперь расплетать я хз_) Ну а поскольку год назад преподавали С в универе, а после этого С#, то все же решил сначала хоть чего-то добиться на сях, а потом уже плотно курить смысл происходящего. Вобщем скажите, как это сцукО_о заставить работать)))
Оптимизацию включи. Либа дилай не работает без нее корректно.
Так включена вроде -Os
А попробуй 0b1111111 заменить на его хекс представление.
Или скомпилить любой из моих примеров, он то уж точно должен компилиться.
У меня другие тоже комплилятся, где сцукодилаев нету(( Лень писать новую функцию тормоза, к тому же она тут 100% зачОтнее написана, чем тот велосипед из грабель, который я изобрету
Вот бля(( Все инклуды похерились, забылся, не посмотрел где пишу)) ну там были либы
avr/io.h
avr/iom16.h
util/delay.h
материт студия либу с задежками
Доброго дня. Подскажите, что делать с такой ошибкой…
«avr-objcopy: ‘Test2.elf’: No such file»
его действительно нет пробовал локально искать, и соответсвенно HEX не создается
Делал все вродь по описанию.
Похоже у тебя не стоит AVR Toolchain или WinAVR
может ли мешать рядом установленная Сутдия5 ?
WinAVR стоит, как проверить Toolchain
а может WinAVR не привязана к студии ?
У меня не мешала, и вообще у студии5 встроен уже тулчейн.
Студия 4.19? Она не понимает WinAVR и надо качать с сайта атмела AVR Toolchain (тот же WinAVR но под крылом атмел)
Спасибо за помощь. Буду разбираться. Пока снес обе версии студио и тулчан и переинсталил заново 4 студию и тулчан, єто проблема ушла.
Всем привет. Не могли бы подсказать как настроить AVR Studio, либо как-то изменить код(хотя он полностью идентичен коду из этой статьи), чтобы компилятор не маялся вот такой вот ерундой:
UBRRL = LOW(UBRR);
LDI R30,0x29 Load immediate
LDI R31,0x00 Load immediate
LDI R24,0x33 Load immediate
STD Z+0,R24 Store indirect with displacement
И вот так вот с каждой записью константы в регистр I/O. Не понимаю зачем использовать в данном случае косвенную загрузку, когда можно просто ограничится командой OUT?
-Os не помогает?
Кстати, какой МК? У него эти регистры часом не memory mapped?
Все спасибо большое…Os помогла
уваэаемы DI Halt, скачайте пожалуйста до конца методу по Си, или хотя бы название дайте чтоб в инете найти :)
P.S. » Там правда еще не все главы перенесены, но, думаю, это ненадолго.»
название я сам не знаю оно у меня в виде файлов лежало на винте. Попробуйте нагуглить кусок текста оттуда, думаю найдете.
http://easyelectronics.ru/repository.php?act=view&id=77
можете проверить?
попытался написать эти буфера на Си
ногами не бить — на Си пишу впервые в жизни
Работает?
нет
Протрассируй в студии, прям по си коду, отключив оптимизацию, чтобы шло по тексту строка в строку. Вместо прерываний сделай просто функцию, вызывая ее несколько раз ,словно у тебя срабатывает прерывание. В качестве входного параметра передавай какой нибудь байт и клади его как будто это UDR. Заодно посмотришь где оно вносится в буфер и где теряется. По крайней мере будет ясно где косяк в алгоритме самого буфера или в инициализации железа.
всё это проделано уже
косяк конкретно в строке BUFF_IN[IN_PTR_S]= UDR
переменную пихал — регистры и озу по нулям
а вот константу захавал. сделал BUFF_IN[IN_PTR_S]= 15
съело и обработало
Так, а что показывает дизассемблер конкретно в этом месте?
Ну и переменные буфера и указателей начал-концов должн быть глобальными. Иначе при выходе из функции их грохнет.
то есть? они и так глобальные.
насколько я понял из справочника то если переменная объявлена вне функции то автоматически глобальна.
в Ртосе я объявил переменные сразу за строкой
#include
#include EERTOS.h
Да, все верно.
вроде даже как работает но есть проблема того что буфер Tx шлёт на +1 байт больше чем надо.
подробности по ссылке
http://forum.easyelectronics.ru/viewtopic.php?f=14&t=8372&p=146977#p146977
только начал изучать Си и уже понял — язык говно! нету интуитивности!
что непонятного в строке BUFF_IN[IN_PTR_S]= UDR?!?!?
Не помню кто, но на форуме была сказана одна умная вещь.
Си с микроконтроллерами надо изучать отлично зная либо микроконтроллер либо си. Не зная ни того ни другого будет лажа.
А интуитивности в нем нет, это довольно низкоуровневый язык. В этом его прелесть.
А почему ссылка битая?
http://easyelectronics.ru/file/yazyk-programmirovaniya-s-spravochnik/163
бросает на содержание
Просто нет этого раздела.
http://citforum.ru/programming/c/dir.shtml
Спасибо — помогает
Здравствуйте все, я только начал заниматься программаторами и микроконтроллерами (буквально вчера собрал программатор), так что если сморожу какую чушь…
Вообщем сварганил вот такой код:
#define F_CPU 16000000UL
#include
#include
int main(void)
{
DDRB = 0xFF;
while(1)
{
for(int i = 1; i <= 128; i *= 2)
{
PORTB = ~i;
_delay_loop_2(300000);
}
}
return 0;
}
Пытаюсь его скомпилировать и мне вылазит два варнинга и две ошибки:
c:\program files\atmel\avr tools\avr toolchain\bin\../lib/gcc/avr/4.5.1/../../../../avr/include/avr/io.h:480:6: warning: #warning "device type not defined"
../anmul.c:7:5: error: 'DDRB' undeclared (first use in this function)
../anmul.c:12:13: error: 'PORTB' undeclared (first use in this function)
../anmul.c:13:13: warning: large integer implicitly truncated to unsigned type
Помогите плиз кто может
я использовал симулятор atmega8a
include почему-то не отображаются (наверно html принял их за теги) вообщем я подключаю avr/io.h и util/delay.h
А для кого выше поля коммента есть вот это «Вставить большой кусок кода (откроется в новом окне)» ???
извините… не заметил
DI привет. Слушай нужна твоя консультация. Работаю в avrstudio5.1. Нарыл библиотеку для подключения LCD дисплея. Состоит из двух файлов lib_lcd.h и lib_lcd.c. Сказано на сайте что нужно подключить хидер #include «lcd_lib.h» и усе. Так и сделал. При компиляции файл lib_lcd.c естественно не цепляется к проекту. Так вот вопрос что нужно сделать что его подцепить к проекту? Положить в директорию проекта и указать где то в студии путь к этому проекту? Как указано выше в статье? http://shurikss123.xe0.ru/index.php/home/electro/mikro/10-id10
Надо в сам проект добавить .с файлы в раздел sources и h файл в разделе hiders, чтобы они были в дереве проекта, ну и в сам исходник добавить #include «lcd_lib.h»
Извини DI не совсем понял. Эти разделы sources и hiders где находятся? В самой программе студии или это нужно искать папки в C:\Program Files\Atmel? В AVRstudio_5.1 эти разделы пока не нашел.
В свойствах проекта. В студии. Не знаю как в пятой, а в 4й студии (а также в CoIDE, Keil и тыды это стандарт) есть этакое дерево проекта, где указаны все файлы и зависимости. Вот туда их надо добавить. Иначе по одному только инклюднику студия их не найдет. Там же нет путей в которых сишник искать ничего.
Еще пока не нашел куда засунуть этот файл *.с Но думаю скоро найду. И еще попутно вопрос, какой командой в СИ сбрасывается WATCHDOG.
подлкючаешь avr/wdr.h
и wdt_reset(); Ну или
__asm__ __volatile__ («wdr»);
О наконец то нашел как добавлять сторонние библиотеки. Это так просто одним щелчком мыши в нужном месте. А три дня убил на поиски этого места. Когда вставил сразу все срослось.
Господа, подскажите пожалуйста…
Пишу програмку на Си под 32Мегу… Программа получается объемная, ну очень объемная. Прокрутил в начало листинга посмотрел как называется функция, пока прокрутил обратно — снова забыл… Простыня еще та получается…
Подскажите как разбить программу на несколько файлов. Если можно, хотелось бы вынести отдельно инициализацию, отдельно обработку прерываний, отдельно некоторые функции. Причем эти файлы должны быть прикручены только к данному проекту…
Заранее спасибо…
Спасибо большое DI HALT , ты нормально объясняешь в статьях , доступно . Как хочется порой не ковырять в интернетах и не грузить мозг гигабайтами пусто-порожней писанины и рассуждений о регистрах,байтах ,АЛУ и прочей ерунды. Пиши пожалуйста так-же доступно.И по возможности ещё вариант книг для тех кто не хочет учить-а хочет писать проги! Я уверен ты напишешь всё на доступном русском языке по английским правилам ( со 100% повторяемостью примеров!).
Успехов тебе !
при компиляции выдает такую ошибку:make: Makefile: No such file or directory
подскажите в чем может быть проблема?
Зачем надо было инициализировать UART, если мы просто выставляем значения в PINы?
Шоб был. УАРТ это пожалуй вторая по популярности и необходимости вещь после портов.
я хочу на учится писать командные коды для МК
с чего начат, с языка Си или сразу с АВР студио ? какую мне из двух выучит?
Начните сначала с изучения инструментария. Разберитесь чем язык программирования отличается от IDE. Авр Студия это IDE
Привет, подскажи как максимально атмегу328 погрузить в режим сна, чтобы по внешнему int1 прерыванию просыпалась и тратила минимум энергии батареек.
Build failed… No build tools defined (не определены инструменты сборки) . Вообщем я новичок. При первой же компиляции кода ctrl+f7 выдало такое вот сообщение, подскажите пожалуйста автор, что не так?
Build failed… No build tools defined.
Объясни пожалуйста, как исправить эту ошибку?
Здравствуйте, пытаюсь осилить Си для программирования AVR. Пытаясь разобраться с кодом не понимаю почему в начале программы стоит не «main», а вот это:
void recoding(void) {
}
Гугл ответа не дал
А это точно чистый си? А не какой-нибудь фреймоврк вроде ардуино? Возможно майн где то зарыт, может даже в библиотеках, а код который вы смотрите это некие подключаемые модули. Которые из этого майна вызываются.
До чего этот С гадкий, так туго в голову лезет, как будто его не человек, а инопланетянин придумал. Нет ничего попроще для программирования, например, PICов ?
Pic basic. Pic pascal. Но все равно потом придётся учить си ;)
Господа, скиньте ссылку на уроки по AVR на ассамблере на этом ресурсе, никак не могу найти(
http://easyelectronics.ru/tag/assembler/page/2 и крутить в самый низ )