EEPROM_ReadNBytes()
-
Description: This function is used to Read N-bytes of data from specified EEPROM_address.
- EEPROM_ReadByte() func is called to read a byte at a time.
- Source(RAM) and destination(EEPROM) address are incremented each time.
- NoOfBytes is Decemented after a byte is read.
- Above Operation is carried out till all the bytes are read(NoOfBytes!=0).
- I/P Arguments:
- int,—>eeprom_address from where the N-bytes is to be read.
- char*—>Pointer into which the N-bytes of data is to be read.
- char —> Number of bytes to be Read
Return value : none
void EEPROM_ReadNBytes(unsigned int EepromAddr, unsigned char *RamAddr, char NoOfBytes) { while(NoOfBytes != ) { *RamAddr = EEPROM_ReadByte(EepromAddr);//Read a byte from EEPROM to RAM EepromAddr++; //Incerement the Eeprom Address RamAddr++; //Increment the RAM Address NoOfBytes--; //Decrement NoOfBytes after Reading each Byte } }
AQUA RTOS
Статусы задач AQUA RTOS
OSTS_UNDEFINEOSTS_STOPготова к исполнениюOSTS_READYOSTS_RUNOSTS_STOP, OSTS_READY, OSTS_DELAY, OSTS_WAIT, OSTS_PAUSEOSTS_DELAY задержкуOSTS_WAIT ожидают семафора, события или сообщенияOSTS_STOP OSTS_PAUSEDOSTS_STOPOSTS_READYOSTS_PAUSE
OS_
OS_сервисOS_сервисTask OS_InitTaskOS_Init OS_сервис OS_сервисTask
Семафоры
ждать освобождениясвободенготова OSTS_READY
создатьOS_CreateBSemaphorehBSemOSERR_BSEM_MAX_REACHEDOS_WaitBSemaphore | OS_WaitBSemaphoreTaskждать освобождения семафораhBSemOS_BusyBSemaphore OS_FreeBSemaphore hBSem занят свободен
События
ожидать некоторое событиесигналить готова к исполнениюOSTS_READY
- прерывание;
- возникновение ошибки;
- освобождение ресурса (иногда для этого удобнее использовать семафор);
- изменение состояния линии ввода-вывода или нажатие клавиши на клавиатуре;
- прием или посылка символа по RS-232;
- передача информации от одной части приложения к другой (см. тж. сообщения).
создатьOS_CreateEventhEventOSERR_EVENT_MAX_REACHEDhEventOS_WaitEventтаймаутомOS_WaitEventTOготова к исполнениюOS_TIMEOUTСигналить OS_SignalEventготова к исполнению
Сообщения
тему сообщенияOS_CreateMessagehTopicOSERR_TOPIC_MAX_REACHEDhTopicOS_WaitMessageждать сообщения по теме hTopicOS_WaitMessageTO OS_WaitEventTO OS_SendMessagewordуказатель на строкуvarptr
OS_WaitMessagewordOS_GetMessage OS_PeekMessage OS_GetMessageStringOS_PeekMessageString
BASIC
Старинный язык первоначального обучения программированию, в настоящее время в основном сохранился в виде реализации Visual BASIC от Microsoft. Используется он и для программирования микроконтроллеров. Реализаций этого языка гораздо больше, чем того же Pascal. Связано это в первую очередь с простотой языка. BASIC часто выбирают разработчики программно-аппаратных платформ, нацеленных на упрощенную разработку электронных устройств. Можно назвать такие проекты, как PICAXE, Amicus18, microBASIC и некоторые другие. Недостатком BASIC является плохая структурированность кода. Этот язык не стоит выбирать для первоначального изучения с целью дальнейшего перехода на С/С++. Программирование микроконтроллеров на BASIC можно рекомендовать любителям, не нацеленным на создание, в основном, простых устройств.
' Пример программы на ProtonBASIC' Мигание светодиодом на PORTB.0 Amicus18. While 1 = 1 ' Начало бесконечного цикла High RB0 ' Включить PortB.0 DelayMS 500 ' Задержка полсекунды Low RB0 ' Выключить PortB.0 DelayMS 500 ' Задержка полсекунды Wend ' Закрытие цикла
Сроки обучения
Арифметические операции работают с регистрами R0 – R31, но не непосредственно с ОЗУ, и занимают один тактовый цикл, за исключением умножения и сложения по всему слову (ADIW и SBIW), которые занимают два цикла.
Доступ к ОЗУ и пространству ввода-вывода можно получить только путем копирования в регистры или из них. Косвенный доступ (включая необязательный постинкремент, прединкремент или постоянное смещение) возможен через регистры X, Y и Z. Все обращения к ОЗУ занимают два тактовых цикла. Перемещение между регистрами и вводом-выводом — один цикл. Перемещение восьми или шестнадцати битовых данных между регистрами или константой в регистр также составляет один цикл. Чтение памяти программ (LPM) занимает три цикла.
Объявление переменных
Переменные в языке С объявляют в операторе описания. Оператор описания состоит из спецификации типа и списка имён переменных, разделённых запятой. В конце обязательно ставится точка с запятой.
Объявление переменной имеет следующий формат:
спецификатор_типа идентификатор …
Модификаторы — ключевые слова signed, unsigned, short, long.Спецификатор типа — ключевое слово char или int, определяющее тип объявляемой переменной.Идентификатор — имя переменной.
Примеры объявления переменных: char s;int x, y, z;unsigned long long t;
Инициализация значения переменной при объявлении
Язык С в отличие от многих других языков программирования позволяет при объявлении переменной сразу ее проинициализировать, то есть присвоить ей начальное значение, что, конечно же, удобно для экономии кода программы. Выглядит это, к примеру, следующим образом:
int a = 100;
С помощью данной записи мы объявляем переменную a целого типа и сразу же в нее записываем число 100.
При этом желательно для улучшения читабельности программы не смешивать инициализируемые переменные и просто объявляемые в одной строке.
AVR проекты
Для сложных проектов с большим количеством входов/выходов вам предоставлены микроконтроллеры AVR семейства Mega и AVR xmega, которые выпускаются в корпусах от 44 до 100 выводов и имеют до 1024 кб Flash памяти, а скорость их работы – до 32 миллионов операций в секунду.
Практически все модели имеют возможность генерировать ШИМ, встроенный АЦП и ЦАП.
Миллионы радиолюбителей разрабатывают интересные проекты на AVR – это самое популярное семейство МК, о них написано очень много книг на русском и других языках мира.
Интересно. Для прошивки нужен программатор, один из самых распространённых – это AVRISP MKII, который вы легко можете сделать из своей Arduino.
Популярность семейства АВР поддерживается на высоком уровне уже много лет, в последние 10 лет интерес к ним подогревает проект Arduino – плата для простого входа в мир цифровой электроники.
Нельзя быть чуть-чуть беременным
Объектно-ориентированное программирование подразумевает наличие в программе классов, взаимодействующих между собой. Взаимодействие выражается зависимостью одних классов от других. И здесь проявляется суть заголовка: чтобы передать в класс A в качестве параметра шаблонный класс B со статическими методами, то класс B тоже необходимо делать шаблонным и так далее по всей цепочке.
Например, USART как минимум зависит от своих регистров, тогда объявление соответствующего класса будет выглядеть приблизительно следующим образом (код, связанный с объявлением регистров, взят отсюда, чтобы была связность статей, спасибо @lamerok за крутые материалы и примеры. Сам я пока на использование созданных им оберток не перешел, но планирую.):
С регистрами разобрались, чтобы объявить конкретный экземпляр UART, необходимо специализировать шаблон
Вроде бы все здорово, однако на самом деле конкретный интерфейс USART имеет иные зависимости:
-
Регистр тактирования (RCC_APB2).
-
Номер прерывания.
-
Набор возможных выводов (Tx и Rx).
-
Dma (Tx и Rx).
И один из четырех принципов ООП — инкапсуляция — намекает на то, что всё перечисленное тоже следует внести в параметры класса. Например, добавим регистр тактирования
Теперь включение тактирования модуля инкапсулировано в его инициализацию. Можно заметить, что в случае многократного вызова метода Init каждый раз будет производиться лишняя операция чтения/записи в регистра RCC_ARB2, но часто ли такое встречается в реальности?
Добавление всех параметров во-первых, позволяет инкапсулировать обязательные вызовы, а также продолжает линию строгого контроля типов. Например, в уроках по тому же USART обычно предлагается инициализировать используемые выводы
Этот код похож на выборы президента: можно, конечно, попробовать указать иные значения, все скомпилируется, но работать не будет. Указание списка возможных пинов позволяет обнаружить попытку использования недоступной линии еще на этапе компиляции:
Если при настройке USART вызвать метод SelectTxRxPins с аргументом, которого нет в списке, прошивка не скомпилируется из-за условия в static_assert.
Таким образом, я считаю, что применения шаблонов C++ заслуживают не только регистры и GPIO, а вообще вся периферия и даже драйверы устройств, использующих интерфейсы микроконтроллера.
Объявление экземпляров классов, как обычно, осуществляется объявлением нового типа:
Общая структура программы на Си и функция main()
Структура программы:
1. Директивы (#include)
2. Функция main();
3. Описание локальных переменных (в языке «С» лок. переменные должны идти перед инструкциями, но в С++ рекомендуется объявлять переменные в месте их использования).
4. Исполняемые инструкции.
5. Оператор завершения: return 0; (хотя компилятор Си сам добавляет return 0; автоматически) — под ОС.
Функция main()
В программе должна быть ровно одна функция main().
-1) программа под управлением ОС.
В стандарте описано всего две перегруженных функции main:
Не правильно писать main(void), т. к. ОС передает некоторые параметры.
При этом ф-ция main() должна возвращать некоторые значение — код возврата, передаваемый операционной системе, с помощью оператора return.
-2) программа для микроконтроллера:
Здесь пишется main(void), т.к. ОС там нет.
Как и какие микроконтроллеры будем программировать?
Вопрос «как будем программировать» состоит из двух пунктов. Под программированием понимаются процессы написания программы и прошивания.
Писать текст программы на СИ мы будем в программе MPLAB IDE. Я не знаю, сколько прошло времени от момента написания этих строк, до момента вашего прочтения, но уверен что версия MPLAB IDE описываемая здесь уже устарела. У меня MPLAB IDE v8.30 и именно её мы будем здесь рассматривать. Я знаю, что уже выпущена версия v8.40, но я не стал обновляться, т.к. изменения в новой версии для меня не будут критичны. Я советую вам сначала освоить по самоучителю v8.30, а затем интуитивно разобрать юзерские полезности в более старших версиях. Откуда скачивать? С официального сайта Microchip из архива программ. Вы должны понимать, что термин «устаревшая версия MPLAB IDE» не относится к языку программирования и не является препятствием для вашего обучения.
Что касается пункта «прошивания», то для этого необходимо изучить материал с этой страницы сайта.
Потребуется компилятор. Компилятор – это программа, позволяющая компилировать (переводить текст) с языка программирования в машинные коды, т.е. в прошивку. MPLAB содержит компилятор Ассемблера. Строго говоря, язык Ассемблера, это машинные коды представленные в виде словесных команд. Для компиляции с языка Си нам потребуется HI-TECH PICC Compiler 9.50. Т.к. «правильный» компилятор стоит денег, в Интернете есть демо-версия с ограниченным объемом выходного кода (совсем правильное здесь). Необходимо отметить, что в комплекте с MPLAB IDE v8.30 идёт PICC Compiler 9.60PL5. Но он также имеет ограничения Omniscient Code Generation not available in Lite mode.
О сайте. Электронные устройства и модели, обучение и консультация, документация и средства разработки. Принимаем на реализацию проекты, услуги, идеи. Возмездная помощь.
Здесь может быть ваша реклама
Понравилась конструкция, но не можете собрать?Обращайтесь, мы удовлетворим ваши запросы и пожелания! Напишите нам письмо.
Препроцессор, директивы
Код обрабатывается препроцессором перед тем, как поступить на вход компилятора.
(C++ не рекомендует исп-ть препроцессор и предлагает более безопасный путь)
Директивы — команды препроцессора. Начинаются с символа # (заканчиваются переводом строки)
Основные стандартные хэдер-файлы:
stdio.h — ф-ции ввода/вывода
stdlib.h — функции стандартной библиотеки (STL)
math.h — математические функции
limits.h и float.h — системно-зависимые значения
ctype.h , string.h , time.h , stdarg.h , locale.h — другие стандартные заголовочные файлы
conio.h — нестандартные функции работы с консолью
Макроопределения
В С++ (в отличии от С) константные переменные можно использовать для определения размера массива (позволяет избавиться от использования #define):
Макросы и встраиваемые функции — сравнение:
— результат тот же, но 2-ой вариант более современный для с++ (и удобнее).
Список инструкций
Инструкции представляют собой одно 16-битное слово, за исключением тех, которые включают 16-битный или 22-битный адрес, которые занимают два слова.
Есть два типа условных переходов: переходы к адресу и пропуски. Условные переходы (BRxx) могут проверять флаг ALU и переходить по указанному адресу. Пропуск (SBxx) проверки произвольного бита в регистре или вводе / выводе и пропуск следующей инструкции, если проверка верна.
В следующих:
- Rd и Rr — регистры в диапазоне R0 – R31.
- Rdh и Rrh — это регистры в диапазоне R16 – R31 (высокая половина).
- Rdq и Rrq — регистры в диапазоне R16 – R23 (одна четверть файла регистров).
- Rp — это регистровая пара R25: R24, R27: R26 (X), R29: R28 (Y) или R31: R30 (Z)
- XYZ — это регистр указателя, либо X, либо Y, либо Z
- YZ — это регистр указателя, либо Y, либо Z
- s — номер бита в регистре состояния (0 = C, 1 = Z и т. д., см. список выше)
- b — номер бита в регистре общего назначения или в регистре ввода-вывода (0 = наименее значимый, 7 = наиболее значимый)
- K6 — это 6-битовая постоянная без знака непосредственного действия (диапазон: 0–63).
- K8 — это 8-битовая непосредственная константа; поскольку он используется только в 8-битных операциях, его подпись не имеет значения
- IO5 — это 5-битный адрес ввода-вывода, покрывающий побитово-адресную часть адресного пространства ввода-вывода, то есть нижнюю половину (диапазон: 0–31).
- IO6 — это 6-битный адрес ввода-вывода, охватывающий все адресное пространство ввода-вывода (диапазон: 0–63).
- D16 — это 16-битный адрес данных размером 64 КиБ ; в частях с пространством данных более 64 КБ, содержимое сегментного регистра RAMPD добавляется в начало
- P22 — это 22-битный адрес программы, покрывающий 2 22 16-битных слова (т.е. 8 MiB )
- S7 и S12 являются 7-бит (соответственно 12-разрядных) подписали смещения, в единицах слов, относительно адреса программы , хранящейся в счетчике программы
Арифметика | Бит и другие | Перевод | Прыгать | Ветка | Вызов |
---|---|---|---|---|---|
ADD Rd, Rr ADC Rd, Rr ADIW Rp+1:Rp, K6 SUB Rd, Rr SUBI Rdh, K8 SBC Rd, Rr SBCI Rdh, K8 SBIW Rp+1:Rp, K6 INC Rd DEC Rd AND Rd, Rr ANDI Rdh, K8 OR Rd, Rr ORI Rdh, K8 COM Rd NEG Rd CP Rd, Rr CPC Rd, Rr CPI Rdh, K8 SWAP Rd LSR Rd ROR Rd ASR Rd MUL Rd, Rr MULS Rdh, Rrh MULSU Rdq, Rrq FMUL Rdq, Rrq FMULS Rdq, Rrq FMULSU Rdq, Rrq |
BSET s BCLR s SBI IO5, b CBI IO5, b BST Rd, b BLD Rd, b NOP BREAK SLEEP WDR |
MOV Rd, Rr MOVW Rd+1:Rd, Rr+1:Rr IN Rd, IO6 OUT IO6, Rr PUSH Rr POP Rr LDI Rdh, K8 LDS Rd, D16 LD Rd, X LDD Rd, YZ+K6 LD Rd, -XYZ LD Rd, XYZ+ STS D16, Rr ST X, Rr STD YZ+K6, Rr ST -XYZ, Rr ST XYZ+, Rr LPM LPM Rd, Z LPM Rd, Z+ ELPM ELPM Rd, Z ELPM Rd, Z+ SPM |
RJMP S12 IJMP EIJMP JMP P22 |
CPSE Rd, Rr SBRC Rr, b SBRS Rr, b SBIC IO5, b SBIS IO5, b BRBC s, S7 BRBS s, S7 |
RCALL S12 ICALL EICALL CALL P22 RET RETI |
LCD_ScrollMessage()
-
Description :This function scrolls the given message on the first line.»»
- 16 chars are displayed at atime.
- Pointer is incremented to skip a char each time to give the illusion of moving chars.
- If the chars are less than 16, then the BlankSpaces are displayed.
- I/P Arguments: char *msg_ptr (msg_ptr -> pointer to the string to be scrolled)
- Return value : none
void LCD_ScrollMessage(char *msg_ptr) { unsigned char i,j; LCD_CmdWrite(0x0c); //Disable the Cursor for(i=;msg_ptri;i++) //Loop to display the complete string { //each time 16 chars are displayed and //pointer is incremented to point to next char LCD_GoToLineOne(); //Move the Cursor to first line for(j=;j<LCDMaxChars && msg_ptri+j;j++) //loop to Display first 16 Chars LCD_DataWrite(msg_ptri+j); //or till Null char for(j=j; j<LCDMaxChars; j++) //If the chars are below 16 LCD_DataWrite(BlankSpace); //then display blank spaces _delay_ms(500); } LCD_CmdWrite(0x0E); //Enable the Cursor }
____________________________________________________________________
Нам нужен бесконечный цикл. Помещаем наши строчки PORTC = 0; __delay_cycles(4000000); PORTC = 255; __delay_cycles(4000000);внутрь бесконечного цикла, и вот что в итоге должно получиться://первая прога на Си для AVR#include <ioavr.h>#include <intrinsics.h>int main(void){ DDRC = 255; while(1){ PORTC = 0; __delay_cycles(4000000); PORTC = 255; __delay_cycles(4000000); } return 0;} Если у вас другой результат – пройдитесь снова по тексту. Может, я что-то полохо объяснил, может, вы что-то плохо поняли. Кликаем Make на панели с кнопками (можно нажать F7). Если все сделано правильно, IAR откомпилирует и соберет проект, а внизу откроется окно Messages, в котором будет написано:…..Total number of errors: 0Total number of warnings: 1 Все прошло без ошибок, но компилер выдал warning — statement is unreachable. Ничего страшного – он просто сообщает нам, что функция main() никогда не возвратит значение. Просто у нас в программе бесконечный цикл и микроконтроллер при работе никогда не дойдет до строчки return 0. Ищем папку проекта на жестком диске. Там, в директории Release лежит файл прошивки led.hex. Грузим в микроконтроллер… Светодиод заморгал? Отлично. А теперь легко проверить правильно ли работает наша программа. Берем механические часы и смотрим, моргает ли светодиод в такт с секундной стрелкой. У меня моргает, а у вас?
Функции пользователя
тип имя_функции (параметры) {тело функции}
Пример:
return x; — возврат значения
return; — немедленный выход из функции
тип = void — означает, что функция не возвращает значения.
аргументы = void — означает, что функция не получает никаких аргументов.
В конце функции-процедуры return можно не дописать (компилятор добавить автоматически)
1) по значению — копирование содержимого аргумента в формальный параметр
Пример:
Прототип функции:
исп-ся для определение типа возвращаемого значения, а также типа и числа аргументов. Обычно помещается в начале программы или в h-файлах.
Пример: double pow (double, double); // названия аргументов можно не указывать.
func(…) — если многоточие в прототипе, то кол-во аргументов не считается.
Указатели на функции:
Указатель на функцию — это адрес точки входа в соответствующую функцию.
где pf — указатель на функцию, *pf — сама функция, а (*pf)(x) — обращение к этой функции.
Пример:
Можно также использовать массив указателей на функции:
При вызове функции в программый стек помещаются (в следующем порядке):
— 1) аргументы функции
— 2) адрес возврата (из функции)
— 3) локальные переменные
Какую литературу читать о микроконтроллерах AVR для начинающих?
Для обучения молодых специалистов написаны горы литературы, давайте рассмотрим некоторые из них:
Евстифеев А.В. «Микроконтроллеры AVR семейства Mega». В книге подробно рассмотрена архитектура микроконтроллера. Описано назначение всех регистров и таймеров, а также их режимы работы. Изучена работа интерфейсов связи с внешним миром SPI и т. д. Система команд раскрыта для понимания радиолюбителю среднего уровня
Материал книги «Микроконтроллеры avr семейства mega: руководство пользователя» поможет изучить структуру чипа и назначение каждого из его узлов, что, безусловно, важно для любого программиста микроконтроллеров.
Белов А.В. – «Микроконтроллеры AVR в радиолюбительской практике»
Как видно из названия, эта книга, в большей степени, посвящена практической стороне работы с микроконтроллерами. Подробно рассмотрен ставший классическим микроконтроллер ATiny2313, а также многие схемы для сборки.
Хартов В.Я. «Микроконтроллеры AVR. Практикум для начинающих». Поможет разобраться в AVR studio 4, а также стартовом наборе STK Вы научитесь работать с последовательными и параллельными интерфейсами, такими как UART, I2C и SPI. Книга «Микроконтроллеры AVR. Практикум для начинающих» написана преподавателем МГТУ им. Н.Э.Баумана и используется там для изучения этой темы.
Изучение этого семейства микроконтроллеров помогло начать работать и разрабатывать проекты многим любителям электроники. Стоит начинать именно с популярного семейства, чтобы всегда иметь доступ к морю информации.
Среди радиолюбителей начального уровня есть только один конкурент AVR – PIC микроконтроллеры.
EEPROM_WriteString()
-
Description: This function is used to Write a String at specified EEPROM_address.
- EEPROM_WriteByte() function is called to write a byte at a time.
- Source(RAM) and destination(EEPOM) address are incremented each time.
- Above Operation is carried out till Null char is identified.
- I/P Arguments:
- int,—>eeprom_address where the String is to be written.
- char*—>Pointer to String which has to be written.
Return value : none
NOTE: Null char is also written into the eeprom.
void EEPROM_WriteString(unsigned int eeprom_address, unsigned char * source_address) { do { EEPROM_WriteByte(eeprom_address,*source_address); //Write a byte from RAM to EEPROM source_address++; //Increment the RAM Address eeprom_address++; //Increment the Eeprom Address } while(*(source_address-1) !=); }
ADC_StartConversion()
- Description :This function does the ADC conversioin for the Selected Channel and returns the converted 10bit result
- I/P Arguments: char(channel number)
- Return value : int(10 bit ADC result)
unsigned int ADC_StartConversion(unsigned char channel) { ADMUX=channel; _delay_ms(5); ADCSRA=0xc1; while((ADCSRA & (1<<ADIF)==); return(ADCW); }
LCD_8_bit Mode
AVR LCD library for 8-bit mode
- Filename: lcd_8_bit.c
- Controller: Atmega Family(8,16,32,64,128)
- Oscillator: 11.0592 MHz
- Author: XploreLabz
- website: www.xplorelabz.com
Note:
- Pin connection for LCD display in 8-bit mode is as shown below.By default the LCD is connected to PORTB(databus) and PORTD(controlbus).
- The code can be modified to connect the LCD to any of the PORTs by changing the «#define».
- io.h contains the defnition of all ports and SFRs delay.h contains the in built delay routines(us and ms routines).
#include <avr\io.h> #include <util\delay.h> #include "lcd.h" #define databus_direction DDRC // LCD databus Direction Configuration #define controlbus_direction DDRD // LCD Control bus Direction Configuration #define databus PORTC // LCD databus connected to PORTB #define control_bus PORTD // LCD Control bus connected to PORTD #define rs 5 // Register select pin connected 6th bit(D5) Control bus #define rw 6 // Read Write pin connected to 7th bit(D6) Control bus #define en 7 // Enable pin connected to 8th bit(D7) Control bus /* 16x2 LCD Specification */ #define LCDMaxLines 2 #define LCDMaxChars 16 #define LineOne 0x80 #define LineTwo 0xc0 #define BlankSpace ' '
Первый год
- код продолжал оставаться кодом на C. Отсюда вытекают следующие достоинства:
- проще контролировать «объекты», поскольку несложно проследить кто и где что вызывает и в какой последовательности (за исключением прерываний, но о них не в этой статье);
- для хранения «указателя на объект» достаточно запомнить возвращенный fd;
- если «объект» был удален, то при попытке его использовать вы получите соответствующую ошибку в возвращаемом значении функции;
- абстракция таких объектов над использовавшимся там HAL-ом позволяла писать настраиваемые под задачу из собственной структуры инициализации объекты (а в случае недостачи функционала HAL-а можно было прятать обращение к регистрам внутри «объектов»).
- если кто-то удалил «объект», а потом создал новый другого типа, то может случиться так, что новый получит fd старого и дальнейшее поведение будет не определено. Данное поведение можно было бы легко изменить ценой небольшого расхода памяти под связанный список вместо использования массива имеющего «ключ-значение» (массив по каждому индексу fd хранил указатель на структуру объекта).
- невозможно было статически разметить память под «глобальные объекты». Так как в большинстве приложений «объекты» создавались единожды и далее не удалялись, то это выглядело как «костыль». Тут можно было бы при создании объекта передавать указатель на его внутреннюю структуру, выделенную статически при компоновке, но это бы еще больше запутало код инициализации и нарушало бы инкапсуляцию.
Схема
Построение схемы довольно простое и может быть выполнено с использованием большинства методов построения схем, включая макет, картон, монтажную плату и печатную плату.
Схема в этом проекте показывает использование простой цепи регулятора мощности (с использованием 7805), которую обеспечивает устройство ATMEGA 5В, но оказывается, что программатор USBASP обеспечивает приблизительно 3,3 В. Несмотря на это, лучше обеспечить внешнее питание, чтобы USBASP не потреблял слишком много тока из любого USB-порта.
Программатор USBASP, который я купил, также шел с конвертером, который преобразует 10-контактный разъем в более удобный 6-контактный программный разъем. Тем не менее, header использует двухрядный шаг 2,54 мм, что означает, что он не может быть подключен к макету. Чтобы обойти это, я просто подключил разъем к проводам, которые соединяются с различными пинами на макете.
Бесконечные циклы
Бесконечный цикл в языке программирования С можно осуществить как с помощью цикла «для» (for), так и с помощью цикла «пока» (while). Синтаксис подобных циклов выглядит следующим образом.
for(;;){// тело_цикла}
или
while (1){// тело_цикла}
Чаще применяется способ с циклом типа while – он более нагляден. Выйти из подобных циклов можно единственным образом – применив рассмотренный в предыдущем разделе оператор break.
Бесконечные циклы находят широкое распространение в программах для микроконтроллеров, потому что данные программы должны, как правило, работать постоянно до тех пор, пока устройство не обесточат. Много примеров подобных программ вы можете найти на нашем сайте в рубрике «схемы и устройства на микроконтроллерах AVR».
Регистры процессора
Имеется 32 8-битных регистра общего назначения, R0 – R31. Все арифметические и логические операции работают с этими регистрами; только инструкции загрузки и хранения обращаются к ОЗУ.
Ограниченное количество инструкций работает с 16-битными парами регистров. Регистр с младшим номером пары содержит младшие значащие биты и должен быть четным. Последние три пары регистров используются как регистры-указатели для адресации памяти. Они известны как X (R27: R26), Y (R29: R28) и Z (R31: R30). Режимы адресации постинкремент и прединкремент поддерживаются всеми тремя. Y и Z также поддерживают шестибитное положительное смещение.
Команды, которые разрешают немедленное значение, ограничены регистрами R16 – R31 (8-битные операции) или парами регистров R25: R24 – R31: R30 (16-битные операции ADIW и SBIW). Некоторые варианты операции MUL ограничены восемью регистрами, с R16 по R23.
Регистры специального назначения
Помимо этих 32 регистров общего назначения, ЦП имеет несколько регистров специального назначения:
- ПК: 16- или 22-битный счетчик программ
- SP: 8- или 16-битный указатель стека
- SREG: 8-битный регистр состояния
- RAMPX, RAMPY, RAMPZ, RAMPD и EIND: 8-битные сегментные регистры, которые добавляются к 16-битным адресам для формирования 24-битных адресов; доступен только в частях с большими адресными пространствами.
Биты состояния
Биты регистра состояния:
- C Флаг переноски . Это флаг заимствования при вычитании. В и инструкциях не не изменить флаг переноса, так что они могут быть использованы для перебора многобайтных арифметических операций.
- Z нулевой флаг . Устанавливается в 1, когда арифметический результат равен нулю.
- N Отрицательный флаг . Устанавливается в копию самого старшего бита арифметического результата.
- V Флаг переполнения . Устанавливается при переполнении дополнения до двух.
- S Знак флага. Уникальный для AVR, это всегда N⊕V, и это верный признак сравнения.
- H Флаг полупереноса . Это внутренний перенос из дополнений и используется для поддержки арифметики BCD .
- T Битовая копия. Этот бит используется в специальных инструкциях по загрузке и хранению битов.
- I Флаг прерывания . Устанавливается, когда разрешены прерывания.
Программирование микроконтроллеров pic на языке c
Теперь, наконец-то займемся делом после устанровок программ. Пора написать первую простенькую программу для микроконтроллера. Пережде чем мы начнем ее писать, надо поговорить о том, а какой МК мы будем использовать.
Я могу предложить хорошо зарекомендовавший себя МК PIC16F877. Он включает в себя практически все мыслимые и немыслимые интерфейсы и технологии (за исключением, пожалуй, только USB) и очень неплох по рабочим характеристикам:
Итак, с МК определились. В файлах к этой статье можно найти полный справочник по этому МК. Что покупать теперь понятно, но пока дайвайте все же напишем программу, что бы было понятно что с ней дальше делать и как ее «зашить» в этот МК.
В выпавшем списке доступных МК выбираем PIC16F877. Нажимаем Далее.
Здесь надо выбрать компилятор, который будет обрабатывать код нашей программы. Обязательно надо выбрать пункт HI-TECH PICC Toolsuite в выпадающем списке Active Toolsuite. Это тот самый компилятор языка Си, который мы установили в прошлой стаье. Нажимаем Далее.
Здесь можно добавить к проекту какие-либо готовые файлы, но нам пока такая возможность не нужна. Жмем Далее.
Тут я думаю все понятно. Нажимаем Готово.
Теперь помещаем ниже следующий код в открытое окно файла проекта TestPIC.c (весь проект целиком можно найти в файлах к этой статье).
Наверное Вам интересно, что будет результатом работы этого кода. Будет происходить следующее: к МК подключаются 8 светодиодов. При включении питания, светодиоды начнут мигать в виде «волны» (это лучше видеть, благо осталось нет так уж и много). Рассмотрим поподробнее сам код.
Что они означают? Давайте по порядку.
KEYPAD_GetKey()
-
Description:This function waits till a key is pressed and returns its ASCII Value
- Wait till the previous key is released..
- Wait for the new key press.
- Scan all the rows one at a time for the pressed key.
- Decode the key pressed depending on ROW-COL combination and returns its ASCII value.
- I/P Arguments: none
- Return value : char—> ASCII value of the Key Pressed
unsigned char KEYPAD_GetKey() { unsigned char key; KEYPAD_WaitForKeyRelease(); // Wait for the previous key release _delay_ms(1); KEYPAD_WaitForKeyPress(); // Wait for the new key press key = KEYPAD_ScanKey(); // Scan for the key pressed. switch(key) // Decode the key { case 0xe7 key='0'; break; case 0xeb key='1'; break; case 0xed key='2'; break; case 0xee key='3'; break; case 0xd7 key='4'; break; case 0xdb key='5'; break; case 0xdd key='6'; break; case 0xde key='7'; break; case 0xb7 key='8'; break; case 0xbb key='9'; break; case 0xbd key='A'; break; case 0xbe key='B'; break; case 0x77 key='C'; break; case 0x7b key='D'; break; case 0x7d key='E'; break; case 0x7e key='F'; break; default key='z'; } return(key); // Return the key }
UART
AVR UART library for Serial Communication for 9600 baud rate at 11.0592Mhz
- Filename: uart.c
- Controller: Atmega8/16/32/128
- Oscillator: 11.0592 MHz
- Author: XploreLabz
- website: www.xplorelabz.com
#include<avr/io.h>
LCD_GoToXY()
- Description :This function moves the Cursor to specified position
-
I/P Arguments: char row,char col
- row -> line number(line1=0, line2=1),For 2line LCD the I/P argument should be either 0 or 1.
- col -> char number.For 16-char LCD the I/P argument should be betwen 0-15.
- Return value : none
void LCD_GoToXY(char row, char col) { char pos; if(row<LCDMaxLines) { pos= LineOne | (row << 6); // take the line number //row0->pos=0x80 row1->pos=0xc0 if(col<LCDMaxChars) pos= pos+col; //take the char number //now pos points to the given XY pos LCD_CmdWrite(pos); // Move the Cursor to specified Position } }
Вступление
Идея использования шаблонов языка C++ для программирования контроллеров не является чем-то новым, в сети доступно большое количество материалов. Кратко напомню основные преимущества: перенос значительной части ошибок из runtime в compile-time за счет строгого контроля типов, а также приближение к объектно-ориентированному подходу, близкий и удобный многим, без необходимости хранения полей в статическом классе (все поля являются шаблонными параметрами). Однако стоит заметить, что практически все авторы по большому счету ограничиваются в своих работах примерами на работу с регистрами и портами ввода-вывода. В своей статье я хочу продолжить эти идеи.