Среда CodeVisionAVR C Compiler является, пожалуй, самой ходовой средой для программирования микроконтроллеров AVR, т.к. заточена именно под них. Проект можно создавать как с нуля, так и с помощью мастера кода (CodeWizardAVR). Для начинающего программиста среда подходит как никогда.
И так приступим.
Создать проект можно двумя способами: • С нуля, записывая в ручную все необходимые заголовочные файлы, функцию 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;
Создание проекта без 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.
Си программа в 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 ); }; }
|