Итак приступим. Создать проект можно двумя способами:
- С нуля, записывая в ручную все необходимые заголовочные файлы, функцию main, конфигурирование портов и т.д.
- Использование мастера кода (CodeWizardAVR). Очень хороший и приемлемый вариант, но в процессе работы мастера формируется большое количество ненужного кода, который впоследствии приходиться редактировать.
Ниже приведен программный код сформированный мастером кода. Вкладки остаются без изменений кроме Chip:
Все управляющие элементы окна CodeWizardAVR позволяют настроить параметры создаваемой заготовки программы.
/*****************************************************
This program was produced by the
CodeWizardAVR V1.25.3 Professional
Automatic Program Generator
© Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com
Project :
Version :
Date : 12.11.2009
Author : skiff
Company : Programming Cu
Comments:
Chip type : ATmega8
Program type : Application
Clock frequency : 4,000000 MHz
Memory model : Small
External SRAM size : 0
Data Stack size : 256
*****************************************************/
#include <mega8.h>
// declare your global variables here
void main(void)
{
// declare your local variables here
// Input/Output Ports initialization
// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTB=0x00;
DDRB=0x00;
// Port C initialization
// Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTC=0x00;
DDRC=0x00;
// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTD=0x00;
DDRD=0x00;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
TCCR0=0x00;
TCNT0=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
MCUCR=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x00;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;
while (1)
{
// Place your code here
};
}
Как видно, много пустого кода, который приходиться удалять. Вообще в действительности CodeWizardAVR помогает создавать код, не занимаясь ручным набором. Приведу программный код сгенерированный CodeWizardAVR, где будет использована вкладка USART – включим работу передатчика, разрешим обработчик прерывания по окончанию передачи:
/************************************************/
/************************************************/
#include <mega8.h>
#define RXB8 1
#define TXB8 0
#define UPE 2
#define OVR 3
#define FE 4
#define UDRE 5
#define RXC 7
#define FRAMING_ERROR (1<<FE)
#define PARITY_ERROR (1<<UPE)
#define DATA_OVERRUN (1<<OVR)
#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE (1<<RXC)
// USART Transmitter buffer
#define TX_BUFFER_SIZE 8
char tx_buffer[TX_BUFFER_SIZE];
#if TX_BUFFER_SIZE<256
unsigned char tx_wr_index,tx_rd_index,tx_counter;
#else
unsigned int tx_wr_index,tx_rd_index,tx_counter;
#endif
// USART Transmitter interrupt service routine
interrupt [USART_TXC] void usart_tx_isr(void)
{
if(tx_counter)
{
—tx_counter;
UDR=tx_buffer[tx_rd_index];
if(++tx_rd_index == TX_BUFFER_SIZE) tx_rd_index=0;
};
}
#ifndef _DEBUG_TERMINAL_IO_
// Write a character to the USART Transmitter buffer
#define _ALTERNATE_PUTCHAR_
#pragma used+
void putchar(char c)
{
while(tx_counter == TX_BUFFER_SIZE);
#asm(«cli»)
if(tx_counter || ((UCSRA & DATA_REGISTER_EMPTY)==0))
{
tx_buffer[tx_wr_index]=c;
if(++tx_wr_index == TX_BUFFER_SIZE) tx_wr_index=0;
++tx_counter;
}
else
UDR=c;
#asm(«sei»)
}
#pragma used-
#endif
// Standard Input/Output functions
#include <stdio.h>
// Declare your global variables here
void main(void)
{
// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: Off
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud rate: 9600
UCSRA=0x00;
UCSRB=0x48;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x19;
// Global enable interrupts
#asm(«sei»)
while(1)
{
// Place your code here
};
}
Лишний код был удален, оставлен только необходимый. Как видно мастер создал довольно объемный код, который особо и не хотелось вводить вручную.
Вдаваться в подробности сгенерированного кода не буду, лишь опишу самую малость. Здесь видим директиву препроцессора #define, которая служит для замены часто использующихся констант, ключевых слов, операторов или выражений некоторыми идентификаторами:
#define RXB8 1
#define TXB8 0
#define UPE 2
#define OVR 3
. . . . .
Использование аргументов с #define – макроопределения:
#define PARITY_ERROR (1<<UPE)
#define DATA_OVERRUN (1<<OVR)
#define DATA_REGISTER_EMPTY (1<<UDRE)
. . . . . .
Обработчик прерывания по завершению передачи:
interrupt [USART_TXC] void usart_tx_isr(void)
{
// некоторый программный код для обработчика
}
Инициализация модуля USART:
UCSRA=0x00;
UCSRB=0x48;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x19;
Разрешение глобального прерывания:
#asm(«sei»)
Объявление переменных для хранения значений:
unsigned char tx_wr_index,tx_rd_index,tx_counter;
unsigned int tx_wr_index,tx_rd_index,tx_counter;
Стандартные типы данных языка С
|
Название |
Тип |
Диапазон |
Шестнадцатеричный диапазон |
Размер, бит |
char |
символ |
-128 … 127 |
-0x80 … 0x7F |
8 |
|
unsigned char |
Беззнаковый символ или логическое значение |
0 … 255
True, False |
0x00 … 0xFF |
8 |
|
Unsigned int |
Беззнаковое число |
0 … 65535 |
0x0000 … 0xFFFF |
16 |
|
Long int |
Длинное целое |
-2147483648… 2147483647 |
-80000000…7FFFFFFF |
32 |
|
int |
Целое число |
-32768…32767 |
-8000…7FFF |
16 |
|
Unsigned Long int
|
Беззнаковое длинное целое |
0…4294967295 |
0…FFFFFFFF |
32 |
|
float |
Вещественное число |
-+1,175*10-38… -+3,402*1038 |
— |
32 |
Создадим проект без CodeWizardAVR.
Запускаем приложение CodeVisionAVR C Compiler. Если открылся какой-либо проект, то его закрываем: File -> Close Project.
На панели инструментов нажимаем по значку — create new file или в меню File -> New.
В форме create new project выбираем Project (проект), на предложение создать код с помощью мастера – жмем кнопочку No.
Сохраняем проект как Prog1.
Выбираем микроконтроллер, определяем частоту кварца и, нажимаем OK:
Список File Output Format(s) определяет, какие файлы будут созданы при компиляции проекта. Наиболее интересны два файла: откомпилированный файл HEX, который «зашивается» в микроконтроллер и откомпилированный файл COF, который можно открыть в среде AVR studio и с помощью симулятора проанализировать работу программы.
Снова выбираем File -> New и File Type -> Source (Исходный текст программы). Появилось пустое окно кода, сохраняем его как Prog1.c.
Открываем окно Configure Project и на вкладке Files добавляем ранее сохраненный файл Prog1.c:
Теперь в окне кода набираем любой необходимый код (соблюдая синтаксис языка), в зависимости от решаемой задачи:
Компилируемпроект, для выявления всевозможных ошибок и предупреждений компилятора. В процессе компиляции создается исходный файл ассемблера Prog1.asm, который можно открыв редактором просмотреть и ввести необходимые изменения. На стадии компиляции файлы COF, ROM, HEX, EEP не создаются.
Выполняем окончательную сборку проекта , при этом создаются готовые к употреблению файлы COF, ROM, HEX, EEP.
Если создается проект с помощью мастера кода (CodeWizardAVR), после необходимых установок на вкладках (USART, ADC, работа с термодатчиком и т.д.), то в меню file мастера выбираем Generate, Save and Exit, и выполняем необходимые сохранения! Посмотреть предварительно какой код создаст мастер, можно выбрав в меню file командную строчку Program Preview!
Си программа CodeVisionAVR начинается с директивы #include — включает в текст программы содержимое указанного файла (заголовочный файл), содержащий прототипы библиотечных функций:
#include <mega8.h>
Заголовочный файл header на atmega8, содержащий символьные мнемоники всей архитектуры микроконтроллера – (адреса портов, счетчиков, аналого-цифрового преобразователя, приемопередатчика и т.д.):
sfrb UBRRL=9;
sfrb UCSRB=0xa;
sfrb UCSRA=0xb;
sfrb UDR=0xc;
sfrb SPCR=0xd;
sfrb SPSR=0xe;
sfrb SPDR=0xf;
sfrb PIND=0x10;
sfrb DDRD=0x11;
sfrb PORTD=0x12;
. . . . .
Векторы прерываний:
#define EXT_INT0 2
#define EXT_INT1 3
#define TIM2_COMP 4
#define TIM2_OVF 5
#define TIM1_CAPT 6
#define TIM1_COMPA 7
#define TIM1_COMPB 8
#define TIM1_OVF 9
#define TIM0_OVF 10
. . . . .
Заголовочных файлов может быть столько, сколько нужно для выполнения программной задачи:
#include <mega8.h>
#include <LCD.h>
#include <ds18b20.h>
#include <delay.h>
#include <stdio.h>
#include <1wire.h>
После заголовочных файлов может быть указано необходимое число директив препроцессора #define для определения символьных и строковых констант, и макроопределений:
#define time 50
#define uart_RxD 2
#define lightcontrol_off PORTB.2=0
#define lightcontrol_on PORTB.2=1
#define protection PORTD=0x2f;PORTC=0x20;\ символ переноса
PORTB=0xed;
Список некоторых заголовочных файлов, использующихся в среде CodeVisionAVR:
assert.h — диагностика программ
ctype.h — преобразование и проверка символов
float.h — работа с вещественными данными
limits.h — предельные значения целочисленных данных
math.h — математические вычисления
setjump.h — возможности нелокальных переходов
stdarg.h — поддержка переменного числа параметров
stddef.h — дополнительные определения
stdio.h — средства ввода-вывода
stdlib.h — функции общего назначения (работа с памятью)
string.h — работа со строками символов
Программа начинается с функции main – основная функция, с которой начинается выполнение всей программой процедуры, состоящей из множества функций.
Функция — это основные модули программы, написанные на языке Си. В круглых скобках в общем случае содержится информация, передаваемая этой функцией.
void main(void)
{
/* тело функции. Последовательность операторов */
}
Из основной функции main можно вызывать другие функции. Данные функции не принимают аргументы и не возвращают результат:
void structs(void)
{
/* список операторов */
/* вызов других функций */
}
void main(void)
{
/* список операторов */
structs(); /* функция не принимает аргументы и не возвращает результат */
/* список операторов */
}
Функция, которая имеет список аргументов и возвращает результат:
Int structs(int a,int b)
{
int c;
c=a/(100*2)-b*10; /* математическое вычисление */
return c; /* значение результата присваивается функции */
}
int main()
{
int a=100, b=50;
int result;
result=structs(a,b);
. . . . .
}
Небольшой код «светодиодной моргалки» как пример записи программы в среде CodeVisionAVR C Compiler:
#include <mega8.h>
#include <delay.h>
#define dl 300 /* директива заменит dl на значение 300 */
void main(void)
{
DDRD=0x01; /* разряд PD0 на вывод */
while(1) /* бесконечный цикл */
{
PORTD.0=1; /* разряд PD0 в лог.1 */
Delay_ms(dl); /* задерживаем на значение dl, мс */
PORTD.0=0; /* разряд PD0 в лог.0 */
Delay_ms(dl);
};
}
1 Комментарий
чтоб вам всю жизнь читать код с таким форматированием