Краткая справка по языку си (для микроконтроллеров)

Содержание

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
       }
}

EEPROM_WriteByte()

  • Description:This function is used to write the data at specified EEPROM_address.
    • Wait till previous write operation is completed(ie wait till EEWE becomes zero).
    • Load the eeprom address into EEAR at which the data has to be stored.
    • Load the data into EEDR which has to be stored in Eeprom.
    • Set the EEMWE(Eeprom Master Write Enable) and within four clock cycles.
    • set EEWE(Eeprom Write Enable) to trigger the Eeprom Write Opeartion.
  • I/P Arguments: int,char—>eeprom_address at which eeprom_data is to be written.
  • Return value : none
 
 
void EEPROM_WriteByte(unsigned int eeprom_Address, unsigned char eeprom_Data)
{
  while(EECR & (1<<EEWE));   // Wait for completion of previous write, EEWE will be
                             // cleared by hardware once Eeprom write is completed  
 
    EEAR = eeprom_Address;  //Load the eeprom adddress and data
    EEDR = eeprom_Data;                  
 
    EECR |= (1<<EEMWE);    // Write logical one to EEMWE 
 
    EECR |= (1<<EEWE);     // Start eeprom write by setting EEWE
}

I2C_Read()

  • Description :This fun is used to receive a byte on SDA line using I2C protocol.
    • 8bit data is received bit-by-bit each clock and finally packed into Byte.
    • MSB(bit) is received first and LSB(bit) is received at last.
  • I/P Arguments: char: Acknowledgement for the Ninth clock cycle.
  • Return value : Unsigned char(received byte)

unsigned char I2C_Read(unsigned char ack)
{
 TWCR = ((1<< TWINT) | (1<<TWEN) | (ack<<TWEA));
   while ( !(TWCR & (1 <<TWINT)));
   return TWDR;
}

RTC_DS1307

                                        DS1307  library
  • Filename: DS1307.c
  • Controller: Atmega8/16/32/128
  • Oscillator: 11.0592 MHz
  • Author: XploreLabz
  • website: www.xplorelabz.com
#include <avr\io.h>
#include <util\delay.h> 
 
#include "ds1307.h"
#include "i2c.h"
  • Below values are fixed and should not be changed.
  • Refer Ds1307 DataSheet for more info
#define DS1307_ID 0xD0     // DS1307 ID
 
#define SEC_ADDRESS   0x00 // Address to access Ds1307 SEC register
#define DATE_ADDRESS  0x04 // Address to access Ds1307 DATE register
#define CONTROL 0x07       // Address to access Ds1307 CONTROL register

KEYPAD_WaitForKeyPress()

  • Description  : This function waits till a new key is pressed.
    • All the ROW lines are pulled low.
    • Column Lines are read to check the key press.
    • If any Key is pressed then corresponding Column Line goes low.
    • Wait for Some time and perform the above operation to ensure the True Key Press before decoding the KEY.
  • I/P Arguments:none
  • Return value : none
void KEYPAD_WaitForKeyPress()
{
  unsigned char key;
  do
   {
	 do
      {
	   ROW=0x0f;	   // Pull the ROW lines to low and Column lines high.
	   key=COL & 0x0F;   // Read the Columns, to check the key press
	  }while(key==0x0f); // Wait till the Key is pressed,
			         // if a Key is pressed the corresponding Column line go low
 
	   _delay_ms(1);		  // Wait for some time(debounce Time);
 
	   ROW=0x0f;		  // After debounce time, perform the above operation
	   key=COL & 0x0F;	  // to ensure the Key press.
 
	}while(key==0x0f);
 
 }

Disclaimer:

The libraries have been tested for Atmega16 on different development boards. We strongly believe that the library works on any Atmega boards. However, Xplore Labz disclaims any kind of hardware failure resulting out of usage of libraries, directly or indirectly. Documentation may be subject to change without prior notice.

The usage of tools and software demonstrated in the document are for educational purpose only, all rights pertaining to these belong to the respective owners. Users must ensure license terms are adhered to, for any use of the demonstrated software.

GNU GENERAL PUBLIC LICENSE:
The library code in this document is licensed under GNU General Public License (GPL) Copyright (C) 2012.
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
Since the library is licensed free of charge, there is no warranty for the libraries and the entire risk of the quality and performance is with the user.

Errors and omissions should be reported to feedback@xplorelabz.com

ADC

                                   Avr ADC library
  • Filename: adc.c
  • Controller: Atmega8/16/32/128
  • Oscillator: 11.0592 MHz
  • Author: XploreLabz
  • website: www.xplorelabz.com
  • Reference:Atmega32 dataSheet
#include<avr/io.h>
#include <util/delay.h>
#include "adc.h"

Год четвертый и пятый

  • все объекты глобальные и включают ссылки друг на друга на этапе компиляции (согласно архитектуре проекта);
  • всем объектам выделена память на этапе компоновки;
  • по объекту класса на каждый пин;
  • объект, инкапсулирующий все пины для их инициализации одним методом;
  • объект контроля RCC, который инкапсулирует все объекты, которые находятся на аппаратных шинах;
  • проект конвертера CAN<->RS485 по протоколу заказчика содержит под 60 объектов;
  • в случае, если что-то на так на уровне HAL-а или класса какого-то объекта, то приходится не просто «исправлять проблему», а еще и думать, как ее исправить так, чтобы это исправление работало на всех возможных конфигурациях данного модуля;
  • используемые шаблоны и constexpr невозможно просчитать до просмотра map, asm и bin файлов конечной прошивки (или запуска отладки в микроконтроллере);
  • в случае ошибки в шаблоне выходит сообщение длиной с треть конфигурации проекта от GCC. Прочитать и понять из него что-то — отдельное достижение.

Массивы в Си

Массив в ОЗУ занимает непрерывный блок (без разрывов).

В C/C++ нумерация массива начинается с нуля: a — 1-ый элемент, a — последний. В Си нет контроля выхода за пределы массива! Типичный цикл:

В С нет встроенной поддержки динамических массивов, но есть ф-ции управления динам. памятью.

— Одномерный массив: тип имя_массива ;

тогда общее число байт = sizeof(тип)*размер

— Многомерный массив: тип имя_массива …;

— с инициализацией: тип имя_массива … = {список значений};

пр.:

тоже самое что:

В случае инициализации можно не указывать размер массива (посчитает автоматически):

(строка — это массив типа char)

Индексация указателей:

Имя массива есть адрес первого элемента массива!!! Примеры:

Обращение по указателями быстрее, чем по индексации массивов, в случае последовательного доступа к массиву. Если же обращение случайным образом, то лучше использовать индексацию.

Пример.

Передача массивов в функции.

Два способа:

1) с индексированием:

2) с помощью указателя:

3) комбинированные варианты:

ОДНАКО между указателями и массивами есть 2 большие разницы:

— имя массива есть указатель-константа, т. е. нельзя изменить его значение;

— при определении массива под него резервируется блок памяти.

Указатель можно настроить на блок памяти 2-мя способами:

— под ранее выделенный блок памяти;

— выделить память динамически из кучи (выделяется ына этапе выполнения программы).

Динамические массивы

Создание динамического массива (использует свободную память, называемую кучей). Функции библиотеки

(здесь size_t — тип для измерения размера памяти для данной платформы).

void *malloc (size_t число_байт); — выделение памяти и возврат указателя типа void*; возвращает NULL в случае ошибки.

void *сalloc (size_t кол-во_блоков, size_t число_байт); — выделяет nitems*size байт и кроме того выполняется очистка памяти (обнуление).

void *realloc( void *block, size_t newsize ); — изменяет первоначальный размер выделенного блока (при необходимости осуществляется перенос данных в новое место в памяти).

void free (void *p); — возвращает выделенную память в кучу, где p — указатель на блок (важно, чтобы этот указатель был таким же как при выделении памяти! поэтому его желательно сделать const).

Пример:

Замечание про C++:

С++ (в отличии от С) не поддерживает автоматического преобразования типов. Поэтому в С++ надо:

В С++ рекомендуется использовать new.

Строки как массивы

Примеры:

Здесь p — указатель на константную строку. Сама строка хранится в сигменте данных (read only). Слово const защищает от попытки записать в что-то в эту строку (иначе возможна ошибка при выполнении).

LCD_DataWrite()

  • Description:This function sends a character to be displayed on LCD in the following steps.
    • step1: Send the higher nibble of the character to LCD.
    • step2: Select the Data Register by making RS high.
    • step3: Select Write operation making RW low.
    • step4: Send a High-to-Low pulse on Enable PIN with some delay_us.
    • step5: wait for some time
    • step6: Send the lower nibble of the character to LCD.
    • step7: Select the Data Register by making RS high.
    • step8: Select Write operation making RW low.
    • step9: Send a High-to-Low pulse on Enable PIN with some delay_us.
  • Function name: LCD_DataWrite()
  • I/P Arguments: ASCII value of the char to be displayed.
  • Return value : none
void LCD_DataWrite( char dat)
{
    databus=(dat & 0xf0);	  // Send the Higher Nibble of the Data to LCD
    control_bus |=1<<rs;	  // Select the Data Register by pulling RS HIGH
    control_bus &=~(1<<rw);	  // Select the Write Operation  by pulling RW LOW
    control_bus |=1<<en;	  // Send a High-to-Low Pusle at Enable Pin
	_delay_us(1);
    control_bus &=~(1<<en);
    _delay_us(10);
 
   databus=((dat <<4) & 0xf0); // Send the Lower Nibble of the Data to LCD
    control_bus |=1<<rs;	   // Select the Data Register by pulling RS HIGH
    control_bus &=~(1<<rw);	   // Select the Write Operation  by pulling RW LOW
    control_bus |=1<<en;	   // Send a High-to-Low Pusle at Enable Pin
	_delay_us(1);
    control_bus &=~(1<<en);
    _delay_ms(1);
 
}

Keypad

                       Avr 4x4 Keypad Library
  • Filename: keypad.c
  • Controller:Atmega8/16/32/128
  • Oscillator: 11.0592 MHz
  • Author: XploreLabz
  • website: www.xplorelabz.com

Note:

  • Rows are connected to lower 4-bits of PORTC
  • Cols are connected to higher 4-bits of PORTC
#include <avr\io.h>
#include <util\delay.h>
#include "keypad.h"
#include "lcd.h"
#define RowColDirection DDRB //Data Direction Configuration for keypad
#define ROW PORTB            //Lower four bits of PORTC are used as ROWs
#define COL PINB            //Higher four bits of PORTC are used as COLs

Общие сведения о портах микроконтроллеров AVR

Порты микроконтроллеров AVR — это устройства ввода/вывода, позволяющие микроконтроллеру передавать или принимать данные. Стандартный порт микроконтроллера AVR содержит восемь разрядов данных, которые могут передаваться или приниматься параллельно. Ножки микроконтроллера также называют пинами, контактами или выводами. Порты обозначаются латинскими буквами А, В, С и т.д. Количество портов зависит от конкретной модели микроконтроллера.

Kонфигурирование каждой линии порта (задание направления передачи данных) может быть произведено программно в любой момент времени. Входные буферы портов построены по схеме триггера Шмитта. Для линий, сконфигурированных как входные, также имеется возможность подключения внутреннего подтягивающего резистора сопротивлением 35…120 кОм между входом и проводом питания. Kроме того, если вывод (вход) с подключенным внутренним подтягивающим резистором подключить к общему проводу, он может служить источником тока.

Обращение к портам производится через регистры ввода/вывода, причем под каждый порт в адресном пространстве ввода/вывода за-резервировано по 3 адреса. По этим адресам размещаются три регистра: регистр данных порта PORTx, регистр направления данных DDRx и регистр выводов порта PINx. Разряды этих регистров имеют названия: Px7…Px0 — для регистров PORTx, DDx7…DDx0 — для регистров DDRx и PINx7…PINx0 — для регистров PINx.

Действительные названия регистров (и их разрядов) получаются подстановкой названия порта вместо символа «x», соответственно для порта A ре¬гистры называются PORTA, DDRA, PINA, для порта B — PORTB, DDRB, PINB и т.д.

Следует заметить, что «регистры» PINx на самом деле регистрами не являются, по этим адресам осуществляется доступ к физическим значениям сигналов на выводах порта. Поэтому они доступны только для чтения, тогда как регистры PORTx и DDRx доступны и для чтения, и для записи.

Таким образом, запись в порт означает запись требуемого состояния для каждого вывода порта в соответствующий регистр данных порта PORTx. А чтение состояния порта выполняется чтением либо регистра данных порта PORTx, либо регистра выводов порта PINx. При чтении регистра выводов порта PINx происходит считывание логических уровней сигналов, присутствующих на выводах порта. А при чтении регистра данных порта PORTx происходит считывание данных, находящихся в регистре-защелке порта – это справедливо как для входных, так и для выходных контактов.

Любой порт микроконтроллера AVR можно сконфигурировать как вход или как выход. Для этой цели используется регистр DDRx. На вход или выход можно сконфигурировать сразу весь порт или только отдельный его вывод (контакт, пин).

Регистр DDRx определяет, является тот или иной вывод порта входом или выходом. Если некоторый разряд регистра DDRx содержит логическую единицу, то соответствующий вывод порта сконфигурирован как выход, в противном случае — как вход. Буква x в данном случае должна обозначать имя порта, с которым вы работаете. Таким образом, для порта A это будет регистр DDRA, для порта B — регистр DDRB и т. д.

Операции и операторы

Оператор (инструкция, англ. statement) — это единица выполнения программы.

В языке Си любое выражение, заканчивающееся символом «точка с запятой» (;), является оператором.

Фигурные скобки { } — это составной оператор.

Например,

Кроме того { } является отдельным блоком и в нем можно определять локальные переменные.

; — пустой оператор.

Операции:

— Арифметические операторы: — + * / %

— Инкрименты и декрименты: ++a, —a, a++, a— (могут выполняться быстрее)

— Операторы сравнения (отн-ний): > >=

— Логические операторы: && || ! (возвращают 1 или 0)

— Битовые операторы: & | ^ ~ >>

— Оператор ?: x ? y : z, напр.: r = 10>9 ? 100 : 200

sizeof — унарный оператор для вычисления размера переменной или типа

, — оператор запятая (последовательное вычисление): a = (b=3, b+2);

Порядок выполнения операторов:

— Унарные операторы выполняются справа-налево.

— Бинарные выполняются слева-направо.

— Присваивание выполняется справа-налево.

Порядок можно менять с помощью скобок!

Примеры:

Выражение а + b + c интерпретируется как (а + b) + с.

sizeof() — возвращает длину в байтах переменной или типа; sizeof(int); sizeof(a);

sizeof выражение; — само выражение не вычисляется.

Оператор запятая:

левая сторона оператора вычисляется как void и не выдаёт значения, переменной x присвается значение выражения в правой стороне, т.е. y+1.

Структуры, объединения, перечисления

Структуры (struct)

Описание (объявление структуры:

Определение структры, т. е. выделение памяти:

Можно, но не рекомендуется (для больших проектов) совмещать описание и определение переменных:

Можно создать псевдоним

и затем писать короче:

Или сразу с псевдонимом:

Определение с инициализацией:

Доступ к элементам структуры — с помощью операции точка (.):

Указатель на структуру:

Доступ через указатель с помощью операции ( -> ):

Битовые поля

Битовое поле — это специальный тип структуры, который определяет, какой будет длина в битах каждого элемента структуры.

В С битовое поле может рассматриваться:

— как целое со знаком — signed int (по умолчанию просто int),

— или без знака — unsigned int.

Битовые поля длиной 1 должны объявляться как unsigned, поскольку 1 бит не может иметь знака.

Пример:

Объединения (union)

Предназначены для хранения нескольких переменных разных типов в (точнее совпадает адрес начала):

Здесь выделяется 4 байта под pw, символ ch помещается в байт номер 0, int занимает 4 байта.

Перечисления (enum)

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

По умолчанию, целые значения присваиваются элементам перечисления в возрастающем порядке, начиная с нуля. Имя не обязательно. Пример:

Выбор языка программирования и среды разработки для программирования

Честно говоря, выбор языка программирования и среды разработки вопрос очень ответственный, навязывать кому-то свои предпочтения и что-то советовать дело довольно-таки трудное.
Давайте попробуем подойти к этому выбору не предвзято, чисто с практической стороны.
1. Существует два основных языка программирования микроконтроллеров — Ассемблер (язык низкого уровня) и Си (язык высокого уровня).
Если мы хотим программировать микроконтроллеры используя полностью все их возможности (а мы это хотим), то необходимо изучать эти два языка.
2. Среда разработки для программирования микроконтроллеров.
Тут выбор большой и очень много мнений. Поэтому можно сказать: «Каждая лягушка хвалит свое болото». Мне, к примеру, очень нравится малораспространенная графическая среда разработки «Algorithm Builder», и «квакать» о ее преимуществах перед другими программами я могу очень долго. Но будем делать выбор, как было сказано выше, не предвзято и практично.
Микроконтроллеры AVR выпускает фирма Atmel, она же предоставляет в наше распоряжение бесплатную среду программирования «Atmel Studio» (бывшая AVR Studio). На ней мы и остановимся.
Интегральная среда разработки (IDE — Integrated development environment) Atmel Studio позволит нам:
— писать программы как на Ассемблере, так и на Си (Почему на Си. Программа «Atmel Studio» позволяет писать программы на трех языках (О чем мы и погорим в первой статье), но есть одно но: программы на Си++ мы рассматривать не будем, по одной причине, и в следующей статье я расскажу об этом
— отладить программу
— перевести программу в машинный код (откомпилировать)
— записать программу в микроконтроллер

Все, выбор мы сделали:

Теперь осталось выполнить два пункта:
1. Обзавестись каким-нибудь стартовым набором (для начала хватит и микроконтроллера ATmega8, нескольких светодиодов, пары кнопок и сопротивлений к ним).
2. Установить (именно установить, а не скачать, и с регистрацией) с официального сайта Atmel (http://www.atmel.com/ru/) программу Atmel Studio.
Программировать микроконтроллеры мы будем с использованием программатора USBASP.
Отдельной статьи по Atmel Studio я писать не буду, будем изучать ее постепенно, по мере надобности и в связке со статьями по устройству и программированию микроконтроллеров.

3. Я добавил в набор очень нужную вещь, она Вам в дальнйшем очень пригодится — USB-TTL преобразователь (конвертер). Почему пригодится:
— русифицируя программу мы установили «Visual Studio-2015», кто не русифицировал программу — установите последнюю версию «Visual Studio», мы не только будем изучать базовую программу «Atmel Studio». К сожалению, на сегодняшний день только программа 2015 года позволяет перейти на русский язык в «Atmel Studio», но а мы с Вами, в «Visual Studio», будем создавать оболочки для работу с МК.

Следующие статьи

Основы программирования микроконтроллеров AVRУстройство и программирование микроконтроллеров AVR в среде Atmel Studio на языках Ассемблер и Си
Published by: Мир микроконтроллеров

Date Published: 10/01/2016

Переменные

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

Определяя для переменной имя мы как бы называем этим же именем и область памяти, куда впоследствии в программе будут записываться значения переменной. С целью улучшения читаемости программы желательно использовать осмысленные названия переменных.

В языке С (Си) к именам переменных предъявляются следующие требования:

  • можно использовать строчные и прописные буквы, цифры и символ подчёркивания (в С имеет статус буквы);
  • первым символом в имени переменной обязательно должна быть буква;
  • не допускается использование пробелов в имени переменной;
  • длина имени переменной не ограничена;
  • имя переменной не должно совпадать с зарезервированными ключевыми словами языка Си;
  • заглавные и строчные буквы в именах переменных различаются, к примеру, переменные a и A – это разные переменные.

Список зарезервированных ключевых слов (которые нельзя использовать в качестве имен переменных), приведен на следующем рисунке.

Чтобы начать пользоваться переменной она обязательно должна быть объявлена. Обычно объявления переменных производятся в начале функций (хороший стиль), но также можно производить их объявление в любом месте тела функции.

При объявлении переменной вы обязательно должны указать ее тип. В зависимости от типа переменной компилятор резервирует ей место в памяти. Наиболее часто используемыми типами данных в языке Си для микроконтроллеров AVR являются char (символьный тип) и int (целочисленный тип).

Циклы типа «для» (for)

Циклы типа «для» (for) применяются в ситуациях, в которых заранее известно количество повторений цикла. Поэтому в составе подобного цикла всегда есть так называемый «счетчик повторений» или «переменная цикла». Пример использования цикла for в языке представлен на следующем рисунке.

В данном примере тело цикла повторится столько раз, сколько значений «пробежит» переменная цикла i от своего начального значения, задаваемого операцией присваивания i = a, до конечного значения, задаваемого условием i < b. Изменение переменной i определяется условием присваивания вида i = i + c. Но чаще всего в циклах типа for в языке С переменная цикла изменяется за одно повторение цикла на +1 или -1, поэтому используется запись вида i++ (инкремент переменной цикла) или i— (декремент переменной цикла). В рассмотренном примере при i = b цикл завершается и выполняется оператор, следующий за закрывающей скобкой цикла.

Рассмотрим пример цикла for, приведенный на следующем рисунке.

В этом примере на первом шаге цикла переменная i будет равна 1, перед вторым шагом произойдет ее увеличение на 1 в результате инкремента (i++) и она станет равной 2. На третьем шаге значение переменной цикла i будет равно 3. И так до тех пор, пока на пятом шаге цикла она не станет равной 5. В результате следующей операции инкрементирования (i++) переменная цикла получит значение 6, но условие i <= 5 уже не будет истинным, поэтому цикл завершится. Таким образом, тело цикла будет выполнено 5 раз.

Язык С допускает инициализацию переменной цикла в его оглавлении как показано на следующем рисунке.

Но начинающим лучше производить инициализацию переменной цикла в начале функции вместе с остальными инициализируемыми переменными – более подробно читайте об этом в статье про переменные в языке С.

Усовершенствуем программу управления миганием светодиода, рассмотренную в статье про программирование портов микроконтроллеров AVR, с помощью цикла типа «для» (for). Заставим светодиод мигать 10 раз.

Пример подобной программы представлен на следующем рисунке.

DS1307_GetTime()

  • Description  :This function is used to get the Time(hh,mm,ss) from Ds1307 RTC.
    • Ds1307 ic is enabled by sending the DS1307 id on the I2C bus.
    • After selecting DS1307, select the RAM address 0x00 to point to sec.
    • Get Sec, MIN, Hour one after the other.
    • Stop the I2c communication.
  • I/P Arguments: char *,char *,char *—>pointers to get the hh,mm,ss.
  • Return value : none
void DS1307_GetTime(unsigned char *h_ptr,unsigned char *m_ptr,unsigned char *s_ptr)
{
     I2C_Start();             // Start I2C communication
 
	I2C_Write(DS1307_ID);	 // connect to DS1307 by sending its ID on I2c Bus
	I2C_Write(SEC_ADDRESS); // Request Sec RAM address at 00H
 
     I2C_Stop();			// Stop I2C communication after selecting Sec Register
 
    I2C_Start();		        // Start I2C communication
    I2C_Write(0xD1);	        // connect to DS1307( under Read mode)
                                //by sending its ID on I2c Bus
 
  *s_ptr = I2C_Read(1);      // read second and return Positive ACK
  *m_ptr = I2C_Read(1); 	// read minute and return Positive ACK
  *h_ptr = I2C_Read();      // read hour and return Negative/No ACK
 
  I2C_Stop();		       // Stop I2C communication after reading the Time
 }

Пример реального приложения под AQUA RTOS

Управляемый событиями подход

  • контроль и управление нагревателем – ControlHeater()
  • индикация наличия и выбора напитков – ShowGoods()
  • прием монет/купюр и их суммирование – AcceptMoney()
  • опрос кнопок – ScanKeys()
  • выдача сдачи – MakeChange()
  • отпуск напитка – ReleaseCoffee()
  • защита от вандализма – Alarm()

ControlHeater()ShowGoods()ScanKeys()AcceptMoney() ScanKeys(),MakeChange ()ReleaseCoffee()ReleaseCoffee()Alarm()

ReleaseCoffee()

ReleaseCoffeebCoffeeSelection ReleaseCoffee() wItem OS_GetMessage ReleaseCoffee()

ShowGoods()ReleaseCoffee()

ReleaseCoffee() Release wItembGoodsReliased

OS_InitTask

OS_ResumeTask

OS_ResumeTask

Создание первого проекта

Следующая задача состоит в том, чтобы создать проект на основе AVR микроконтроллера и протестировать схему, компилятор и программатор.

Сначала перейдите в: Файл -> Создать -> Проект (англ. File -> New -> Project) и в открывшемся окне выберите: Исполняемый проект GCC C (англ. GCC C Executable Project), а в текстовом поле Имя (англ. Name) дайте любое название вашему проекту.

Следующее окно, которое должно появиться, — это окно выбора устройства. Из списка выберите Atmega168. Насколько мне известно, это окно не имеет никакого смысла, так как мы все равно передаем имя устройства в AVRDUDE вручную (пока я не могу найти способ заставить Atmel Studio 7 автоматически отправлять имя устройства в AVRDUDE через аргументы).

Результатом должен стать файл main.c, содержащий код нашей программы, который будет запускать AVR. Однако сгенерированный код ничего не делает, поэтому замените все содержимое файла main.c с помощью приведенной ниже программы (обязательно сохраните файл после ввода нового кода).

#define F_CPU 800000UL // Я использую кристалл 8 МГц

#include <avr/io.h>
#include <avr/delay.h>

int main(void){
	DDRD = 0xFF; // Сделать порт D портом выхода

	while(1){
		PORTD = 0xFF;
		_delay_ms(1000);
		PORTD = 0x00;
		_delay_ms(1000);
	}
}

Теперь пришло время скомпилировать код и загрузить его на устройство AVR. Первый шаг — убедиться, что наш проект использует компилятор WINAVR. Щелкните правой кнопкой мыши проект и выберите «Дополнительно» (англ. — Advanced) в окне свойств.

В окне «Дополнительно» убедитесь, что в поле «Набор инструментов» (англ. — Toolchain Flavour) выбран WINAVR.

Сохраните проект и скомпилируйте его, нажав: Build -> Build Solution (или нажав F7). Если все идет по плану, в окне вывода должно появиться следующее сообщение:

Build succeeded.

========== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ==========

Это означает, что наш проект успешно скомпилирован и готов к передаче на наш чип. Чтобы запрограммировать устройство, убедитесь, что USBASP подключен как к ПК, так и к цепи Atmega, к цепи подано питание и что к микросхеме подключен кристалл (в случае, если микросхема была настроена для использования внешнего кристалла).

Затем, после всего этого, нажмите: Инструменты -> USBASP (англ. Tools -> USBASP), и все будет работать автоматически.

Если все хорошо, светодиод в вашей цепи должен начать мигать. Ниже приведен вывод AVRDUDE в Atmel Studio 7, показывающий, как выглядит успешная программа.

avrdude.exe: warning: cannot set sck period. please check for usbasp firmware update.
avrdude.exe: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.01s

avrdude.exe: Device signature = 0x1e9406
avrdude.exe: NOTE: FLASH memory has been specified, an erase cycle will be performed
             To disable this feature, specify the -D option.
avrdude.exe: erasing chip
avrdude.exe: warning: cannot set sck period. please check for usbasp firmware update.
avrdude.exe: reading input file "0x26"
avrdude.exe: writing lfuse (1 bytes):

Writing | ################################################## | 100% 0.00s

avrdude.exe: 1 bytes of lfuse written
avrdude.exe: verifying lfuse memory against 0x26:
avrdude.exe: load data lfuse data from input file 0x26:
avrdude.exe: input file 0x26 contains 1 bytes
avrdude.exe: reading on-chip lfuse data:

Reading | ################################################## | 100% 0.00s

avrdude.exe: verifying ...
avrdude.exe: 1 bytes of lfuse verified
avrdude.exe: reading input file "c:\users\robinlaptop\Documents\Atmel Studio\7.0\OurFirstAVR\OurFirstAVR\Debug\OurFirstAVR.hex"
avrdude.exe: writing flash (184 bytes):

Writing | ################################################## | 100% 0.11s

avrdude.exe: 184 bytes of flash written
avrdude.exe: verifying flash memory against c:\users\robinlaptop\Documents\Atmel Studio\7.0\OurFirstAVR\OurFirstAVR\Debug\OurFirstAVR.hex:
avrdude.exe: load data flash data from input file c:\users\robinlaptop\Documents\Atmel Studio\7.0\OurFirstAVR\OurFirstAVR\Debug\OurFirstAVR.hex:
avrdude.exe: input file c:\users\robinlaptop\Documents\Atmel Studio\7.0\OurFirstAVR\OurFirstAVR\Debug\OurFirstAVR.hex contains 184 bytes
avrdude.exe: reading on-chip flash data:

Reading | ################################################## | 100% 0.10s

avrdude.exe: verifying ...
avrdude.exe: 184 bytes of flash verified

avrdude.exe: safemode: Fuses OK

avrdude.exe done.  Thank you.

Заключение

Выбор того или иного языка программирования зависит от множества факторов. В первую очередь необходимо определиться с типом решаемых задач и необходимым качеством кода. Если не требуется разработка объемных и сложных программ, то можно использовать практически любой язык. Для обеспечения компактности кода подойдет Ассемблер, а если ставятся серьезные задачи, то альтернативы С/С++ практически нет. Также необходимо учитывать доступность компилятора. В некоторых случаях, реализация языка может вообще отсутствовать, или предлагаться за солидные деньги. В итоге самым универсальным решением можно назвать связку Ассемблера и  C/C++.

You have no rights to post comments