#4 из чего состоит проект и что в файлах?

Август 17, 2008

Основы для первого проекта. Типы файлов и информация в них.

Простой проект состоит из одного файла с расширением .c .
Однако даже простой проект может содержать в себе много кода и этот код может быть универсальным.
Например я использую в проекте 2х строчный жк индикатор. А у вас его нет, но есть однострочный.

Что делать? Достаточно в одном файле изменить один параметр и пересобрать.
Это файл заголовка .h.
В этом файле определяются разные константы и макросы, а так же прототипы функций.
По моем мнению прототипы не нужны и не обязательны.
Они служат только для быстрого определения типов данных в функциях от третьих разработчиков.
Гцц вроде бы выдает только предупреждение об отсутствии прототипов.

Давайте разберем обычный .с файл.

На первом месте стоит комментарий с краткой информацией о проекте и данных автора.
Комментарии бывают 2х видов: однострочный и многострочный.
// однострочный

/* а это многострочный комментарий
и он начинается с одного слеша и звездочки,
а заканчивается наоборот
*/

На втором месте идут инклюды - команды препроцессора.
Стандартный инклюд любого проекта под гцц выглядит так:
# include <avr/ io.h>

Это значит, что препроцессор должен взять текст из файла io.h и поместить в главный файл проекта. И только потом он начинает проверять весь синтаксис.
Таких инклюдов может быть несколько и в разных .с файлах. Даже одинаковый заголовок может быть включен в каждый .с файл.
Инклюды есть 2х типов: родные и неродные.
Неродные - это как раз ваш .h, который должен лежать в папке проекта
Подключается он так:
#include "myheader.h"

Что есть в тех файлах и как оно выглядит?

#define LCD_IO_MODE 6 /* 6=6 PIN I/O, 2=2 PIN I/O, 3=I2C, 7=multi lcd */
#define LCD_AUTO_LINE_FEED 0 /* 1 = Auto line feed, 0 = no Auto line feed */
#define LCD_DELAY_TIME_US 100 /* THE TYPICAL TIME THE LCD NEEDS TO COMPLETE A COMMAND */
#define LCD_E_PULSE_WIDTH_US 1 /* THE E PULSE WIDTH IN MICROSECONDS >Timing is accurate)*/
#define LCD_DECIMAL_POINT '.' /* The decimal point punctuation mark char */

После инклюдов идут дефайны, которые уже показаны выше.
В простом проекте такие дефайны можно писать прям в .с файле.

После инклюдов идут глобальные переменные. Эти переменные могут быть доступны из главной функции или из обработчика прерываний.

Обработчики прерываний - следущая часть программы. Их может и не быть.

После них можно писать тела функций.
Или функции можно писать в самом низу, после главной функции.

Обработчик прерывания выглядит так:
INTERRUPT(SIG_OVERFLOW0)
{
.... код ....
}

Если инклюд был обязательным, то все выше перечисленные часть необязательно должны быть.
Обязательная часть любой программы - главная функция с названием main.
Эта функция не принимает параметров и не выдает результат. Посему тип данных будет void.

Записывается это так:
void main(void){
... код...
}

После последней скобки надо пропустить одну строку. С высоты 2008 года это выглядит смешно, а лет 10-20 назад это был стандарт.
Хотя это необязательно.

Вот так выглядит главный файл одного из проектов.

/* PLL synteza SAA1057, LCD display */

#include <avr/io.h> #include <avr/pgmspace.h> #include <avr/eeprom.h> #include "lcd_io.h" #include <avr/signal.h> #include <avr/interrupt.h>

#define DLEN_ON  sbi(PORTD,PD3) #define DATA_ON  sbi(PORTD,PD4) #define DLEN_OFF  cbi(PORTD,PD3) #define DATA_OFF  cbi(PORTD,PD4) #define CLK    {sbi(PORTD,PD2);delay(1);cbi(PORTD,PD2);} #define UP   ((PINB & 0x01)!=0x01) #define DOWN  ((PIND & 0x20)!=0x20) #define MENU  ((PIND & 0x40)!=0x40) #define sint  uint8_t

sint NTIM;   // casovac f = cca 20Hz; int OFREQ, FREQ; // frekvencia; sint up=0, down=0, menu=0, emenu=0, rmem=0, nmem = 0, mset=0;

void InitTimer0() {  TCNT0 = 0x3d;  TCCR0 = 5;    TIMSK |= _BV(TOIE0); }

void InitPorts() {  cbi(DDRB, DDB0);  sbi(DDRB, DDB6);  DDRD = 0x1F;   // (0<<DDD6) | (0<<DDD5) | (1<<DDD4) | (1<<DDD3) | (1<<DDD2);  cbi(PORTB, PB6); }

void PLL_SendW(unsigned int COMM) {  DATA_OFF;  DLEN_ON;  sint i;  CLK;  for (i=0; i<16; i++)  {   if (COMM & 0x8000) DATA_ON;    else DATA_OFF;   CLK;   COMM <<= 1;  }  DLEN_OFF;  clk(10); }

void clk(int c) {  int p;  for (p=0; p<c; p++) CLK; }

void InitPLL() {  clk(20);  PLL_SendW(0xCC00);  //delay(100);  PLL_SendW(0xCC00);  //delay(100);  //PLL_SendW(10700);  //delay(100);   }

void delay (int ms) {  sint i,j;  unsigned int l;  for (l=0; l<ms;l++) {   for (i=0; i<70; i++)    for(j=0; j<250;j++)     ;               }     };

INTERRUPT(SIG_OVERFLOW0) {  if UP up++; else up = 0;  if DOWN down++; else down = 0;  if MENU menu++; else menu = 0;    if (emenu) {   if (up==1) nmem++;   if (down==1) nmem--;   if (nmem<0) nmem=0;   if (nmem>4) nmem=4;   if (menu==0) emenu=2;   if ((menu==1) && (emenu==2)) {eeprom_write_word(2*nmem,FREQ); emenu=0; rmem=0; mset=1;}   lcd_gotoxy(12,1);   lcd_puts_P("M");   if (NTIM<10) lcd_puti(nmem,0);   else lcd_puts_P(" ");   }  else {  if ((menu==0) && (rmem==1)) {   if (++nmem > 4) nmem=0;   FREQ = eeprom_read_word(nmem*2);   rmem=0;   mset=1;   }  if (menu==1) {rmem=1;}  if (menu>=20) {emenu = 1; NTIM=0;}  if (up==1) {FREQ+=5; mset=0;}  if (up>=20) {FREQ+=10; mset=0;}  if (down==1) {FREQ-=5; mset=0;}  if (down>=20) {FREQ-=10; mset=0;}  if (FREQ<8800) {FREQ=8800; mset = 0;}  if (FREQ>10800) {FREQ=10800; mset = 0;}     if ((OFREQ!=FREQ) && (menu==0) && (up==0) && (down==0)) {   OFREQ=FREQ;   PLL_SendW(FREQ);  }     lcd_gotoxy(1,1);  if (FREQ<10000) lcd_puts_P(" ");  lcd_puti(FREQ,2);  lcd_puts_P(" MHz");  if (mset) {   lcd_puts_P(" M");   lcd_puti(nmem,0); }  else lcd_puts_P("   ");  }     if (++NTIM==20) {NTIM = 0;} }

 

void main() {  InitTimer0();  InitPorts();  InitPLL();  lcd_init();  lcd_clrscr();  lcd_gotoxy(0,0);  lcd_puts_P( " PLL SYNTHESIS\n" );  lcd_puts_P( " v1.0 by Dusan" );  delay(2000);   //while(1) {;}  FREQ = eeprom_read_word(nmem*2);  mset = 1; nmem=0;  lcd_gotoxy(0,1);  lcd_puts_P( "                " );  sei();  while(1) {;    } }

категория: учим мк avr

Comments (6)

 

  1. вы вот пишите

    цитата:
    "После них можно писать тела функций.
    Или функции можно писать в самом низу, после главной функции."

    но ведь в случае если мы будем писать тела ф-ций после main () то нам до главной ф-ции надо написать прототипы остальных ф-ций.

  2. меня давно мучает вопрос как правильно организовать многомодульную программу

    допустим у меня кроме основного модуля main.c есть еще два: saund.c и UART.c
    насколько я знаю, то в основном модуле я должен включить хидеры вышеупомянутых модулей
    но что я должен писать в этих хидерах ?

    • хедер необязателен для них
      чтобы компилятор видел другие части, они должны быти включены в проект и потом просто вызываеш функции этих модулей в главной функции
      возможно там будет ошибка при компиляции, тогда надо перед типом функций в модулях еще поставить extern
      например extern void uart();
      тогда компилятор будет знать, что это функция внешняя, но вроде бы это тоже устаревшее и некоторые компиляторы и так понимают что где и как

  3. а если мне надо, к примеру, из модуля saund вызвать ф-цию которая находится в модуле UART .
    как тогда быть ?

ответить

Авторизация только через loginza.

Yandex Google Вконтакте Mail.ru Twitter Loginza MyOpenID OpenID