Приветствую Вас, Гость! Регистрация RSS

Суббота, 22.07.2017
Главная » Статьи » Cтатьи

CodeVisionAVR. Первый проект для микроконтроллера AVR

Среда CodeVisionAVR C Compiler является, пожалуй, самой ходовой средой для программирования микроконтроллеров AVR, т.к. заточена именно под них. Проект можно создавать как с нуля, так и с помощью мастера кода (CodeWizardAVR). Для начинающего программиста среда подходит как никогда.

null

И так приступим.

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


Ниже приведен программный код сформированный мастером кода. Вкладки остаются без изменений кроме Chip:

null

Все управляющие элементы окна 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:

null

Теперь в окне кода набираем любой необходимый код (соблюдая синтаксис языка), в зависимости от решаемой задачи:

Компилируем проект , для выявления всевозможных ошибок и предупреждений компилятора. В процессе компиляции создается исходный файл ассемблера 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 );
 
  };
 
}





Категория: Cтатьи | Добавил: Автор (02.05.2010)
Просмотров: 32276 | Комментарии: 8 | Теги: обработчик прерывания, вкладка USART, переменная, Среда codevisionavr, проект, файл hex, #include, мастер кода, компиляция, Header | Рейтинг: 3.0/2
Всего комментариев: 8
1  
очень хорошо

2  
Стараюсь happy

3  
Статья полезная!
Только - "Как видно, много пустого кода, который приходиться удалять.
".
Если не секрет, то что удаляете из начального кода? smile
И ещё. Очень рекомендую начинающим (и не только) найти ICC AVR. Любой версии. Там генератор начального кода, в некоторых местах, повеселее будет. Установочные значения для таймеров очень удобно подбирать.

4  
В ICC AVR я работал, хоть и не продолжительное время, ИМХО, мне он как-то не очень понравился. Тут вопрос в другом - кому что понравилось, тот в том и работает biggrin
А ещё я уважаю среду IAR Systems Embedded Workbench For AVR

5  
Скачал CodeVision AVR 2.05.0 может здесь что-то перекомпилировать пока не разобрался , что и как.
НАРОД как в CodeVision AVR 2.05.0 перекомпилировать фаил TIMER.asm что-бы и изменился фаил hen ( проект Таймер на AT90S2313) но у меня есть только тиньки 2313 вот и ж. sad
Вместо .include «2313def.inc» написал .include «tn2313def.inc»вывоы исповил 16 на минус cbi PORTB,4 написал sbi PORTB,4 . Пробовал к4ак у вас перекомпилировать ваил hen. не меняется .Нужна помощь.

6  
А как фьюзы рос читать какие ставить???? для SinaProg

7  
Напишите подробно, доступно для чего #asm("sei"), #asm("cli").

Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]