Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Помогите разобраться с таймером и SPI для мега 16
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > MCS51, AVR, PIC, STM8, 8bit
_Надя
Я по прерыванию таймера Т2 формирую импульсы длительностью 8 мс…. Т.е. через каждые 8мс должно наступать прерывание. К примеру я по 10 прерыванию устанавливаю бит а по 11 сбрасываю его. Импульс же должен получиться 8 мс, а у меня всего 1 мс. В чем может быть причина?
МK тактируется от внутренней RC цепочки частотой 8 мгц. Коэффициент деления для Т2 беру 1024. Получаем 8 000 000/1024=7812,5 1/7812.5=0,000128. Далее для формирования импульса длительностью 8 мс делю 0,008/0,000128=63. Получается, что Т2 до переполнения должен просчитать 63 раза. Записываю в счетный регистр число 255-63=192 или С0. Вот собственно и все. Может я где то в расчетах ошиблась?

Второй вопрос по SPI:
Почему-то у меня на плате выводы SPI MISO, MOSI соединены через резистор 4,7 кОм. Я соединяю их напрямую перемычкой длиной примерно 8 см. У меня такое ощущение что мой SPI срабатывает от помехи. Хочу увидеть какие данные шлют друг другу мк и ничего не могу увидеть. Может причина в настройках?
Если не лень, посмотрите алгоритм, пожалуйста... Ну что я делаю не так?
Для мастер
На выводе SS высокий уровень. Инициализирую SPI:
Включаю SPI, разрешаю прерывания., режим мастер, частота CLK 125 кГц.
На вывод SS Slave подаю 0 в SPDR загружаю данные.
В прерывании считываю принятые данные от Slave вызываю функцию обработки принятых данных.

Для Slave
Инициализирую SPI: Включаю SPI, разрешаю прерывания.
В SPDR загружаю данные.
В прерывании считываю принятые данные от Master вызываю функцию обработки принятых данных.

Заранее благодарю smile.gif
прошу прощения за много бкафф
Aesthete Animus
Сударыня, прошу Вас, покажите кусочек исходника с инициализацией. А лучше покажите его целиком. Это гораздо яснее нам скажет, что Вы делаете, нежели словесные описания. Вы, к примеру, могли напутать с прескаллером. Лично я обычно таймер инциализирую по-другому - об этом я уже неоднократно писал (прям любимая моя тема), например здесь
http://electronix.ru/forum/index.php?showtopic=55363

SPI... Как инициализируете, не забыли ли про направление портов, как соедины девайсы (схема)?
_Надя
Пр направление портов не забыла....
Как соединены - сейчас не могу схему кинуть.....
SPI как писала выше соединяю перемычками, т.к. почему то у меня на плате выводы SPIежду сосбой соединены через резистор 4,7 К. эта плата досталась мне от другого разработчика.
Исходник у меня большой.... как мне кажется. но вот, смотрите:
Код
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include <avr/eeprom.h>
#include <util/delay.h>

// port definitions
/*
PA0 AIN        adc            in
PA1 AGND    adc            in
PA2 Uref/2     adc            in
PA3 TST        adc            in
PA4    AGND      adc            in
PA5    AGND      adc            in
PA6    AGND      adc            in
PA7    AGND      adc            in

PB0 F_CONTROL              out
PB1 P_OUT                  out
PB2 P_OUT1                 out
PB3 P_relays            out
PB4    SS        spi start    out
PB5    MOSI    spi            out    
PB6    MISO    spi            in
PB7    SCK        spi            out

PC0                     out
PC1                     out
PC2 LED1.1    dual led    out
PC3 LED1.2    dual led    out
PC4    Zap1                out
PC5    Zap2                out
PC6    PGOOD    test        in          
PC7                        out

PD0 N_relays            out
PD1  TEST                out
PD2                     in
PD3                     in
PD4    SYNC3    sync        out
PD5    SYNC4    sync        out
PD6    MODE    cfg            in        1 - first, 0 - second
PD7    SNU                    out
*/



// global defines
#define uchar unsigned char
#define ushort unsigned short

// Установка, сброс и инвертирование бита в регистрах
#define SET_B(x) |= (1<<x) // Установить бит
#define CLR_B(x) &=~(1<<x) // Очистить бит
#define INV_B(x) ^=(1<<x) // Инверитровать бит
// x - номер бита в регистре


// init_ports

#define F_CONTROL   PB0
#define P_OUT          PB1
#define P_OUT1         PB2
#define P_relays     PB3
#define SLED1        PC2
#define SLED2        PC3
#define Zap1        PC4
#define Zap2        PC5
#define SNU         PD7
#define TEST        PD1
#define N_relays    PD0


#define CPU_CLK                8000000
#define ADC_BUFFER_SIZE     255 //Размер  массива для рез-та АЦП
#define ADC_STOP_STEP        255//Кол-во  шагов АЦП
#define EEA_LEVEL             0
#define EEA_LEVELDELTA        1
#define EEA_LEVEL_OFF       18
#define EEA_LEVELDELTA_OFF    5
#define STATUS1_ON        PORTC|=_BV(SLED1)
#define STATUS1_OFF        PORTC&=~_BV(SLED1)
#define FCONTROL_ON      PORTB|=_BV(F_CONTROL)
#define FCONTROL_OFF     PORTB&=~_BV(F_CONTROL)
#define POUT_ON          PORTB|=_BV(P_OUT)
#define POUT_OFF        PORTB&=~_BV(P_OUT)
#define POUT1_ON          PORTB|=_BV(P_OUT1)
#define POUT1_OFF        PORTB&=~_BV(P_OUT1)
#define SNU_ON          PORTD|=_BV(SNU)
#define SNU_OFF            PORTD&=~_BV(SNU)
#define Zap1_ON         PORTD|=_BV(Zap1)
#define Zap1_OFF        PORTD&=~_BV(Zap1)
#define Zap2_ON         PORTD|=_BV(Zap2)
#define Zap2_OFF        PORTD&=~_BV(Zap2)
#define P_rel_ON         PORTD|=_BV(P_relays)
#define P_rel_OFF        PORTD&=~_BV(P_relays)
#define N_rel_ON         PORTD|=_BV(N_relays)
#define N_rel_OFF        PORTD&=~_BV(N_relays)

// global variables

volatile signed char result[ADC_BUFFER_SIZE];      //преобразов. массив знач. АЦП
volatile signed char adc_buffer[ADC_BUFFER_SIZE]; // Массив значений АЦП
volatile signed char val;                   //Максимальное значение в массиве
volatile signed char  val8;                 //Переменная для анализа уровня
volatile signed char adc_delta;             //Разница значений между двумя АЦП
volatile signed char adc2;                  //Принятый рез-т АЦП
volatile signed char level;
volatile signed char level_delta;
volatile signed char dop1;
volatile signed char dop2;
volatile signed char max_val;
volatile uchar leveloff;
volatile uchar level_deltaoff;
volatile uchar adc_counter;                 //Счетчик АЦП преобразов.
volatile uchar cnt_T2;                  //Счетчик периодов таймера Т2
volatile uchar cnt_isrt2;               //Счетчик прерываний таймера t2
uchar eeprom_addr;
uchar data_slave;                           //переменная для считыв. принятых данных
uchar n;                                // Переменная для подсчета числа импульсов


//functions
void filter ();
void analyze();
void spi_mastertransmit();
void analyze_transmit();
void test_transmit();

//Инициализация портов
void init_pio()      
{ DDRA=0;
  DDRB=0xBF;
  DDRC=0xBF;
  DDRD=0xB3;
  PORTB=0x10;                    // откл.Slave по  выводу SS
  PORTC=0x30;
  PORTD=0x01;
}

void read_cfg()
{
eeprom_write_byte(0,0x93); //Порог включения
eeprom_write_byte(1,0x00);
eeprom_write_byte(18,0x74); //Порог выключения
eeprom_write_byte(5,0x00);
//read
level=eeprom_read_byte(EEA_LEVEL);
  level_delta=eeprom_read_byte(EEA_LEVELDELTA);
  leveloff=eeprom_read_byte(EEA_LEVEL_OFF);
  level_deltaoff=eeprom_read_byte(EEA_LEVELDELTA_OFF);
}

// инициализация таймера
void init_timers()              
{TCCR0=_BV(CS02)|_BV(CS00);     // clk/1024
TCNT0=0xFC;                     // частота ацп 2 кГц
TCCR2=_BV(CS22)|_BV(CS20);      // clk/1024
TCNT2=0xC0;
TIMSK=_BV(TOIE0)|_BV(TOIE2);               //Флаг разр.прерыв. по  переполнению таймера
}


// Инициализация SPI
// init SPI                    
void init_SPI()
{
SPCR=_BV(SPIE)|_BV(SPE)| _BV(MSTR)|_BV(SPR1); //вкл.SPI,разр.прерыв., реж.мастер
PORTB CLR_B(4);
//PORTB=0;
//sei();                                      //Вкл. Slave по  выводу SS
}

//Инициализация АЦП
// init ADC                    
void init_adc()
{ADCSRA=_BV(ADEN)|_BV(ADATE)|_BV(ADIE)|_BV(ADPS2)|_BV(ADPS1);//Вкл.АЦП,реж. работы по  таймеру,разр. прерыв от  компаратора, clk/64
ADMUX=_BV(ADLAR);     //Выравнивание рез-та по  левой границе
SFIOR=0x80;           // Запуск АЦП по  прерыванию  таймера Т0
//sei();
}

// Timer0    прерывание по  таймеру                      
ISR(TIMER0_OVF_vect)
{ TCNT0=0xFC;
  ADCSRA|=0x40;//start ADC
}

// Timer2    прерывание по  таймеру формирование сигналов запуска    
ISR(TIMER2_OVF_vect)
{ TCNT2=0xC0;
cnt_isrt2++;
if (cnt_isrt2==0x96) PORTC CLR_B(4); // начало зап1
if (cnt_isrt2==0x97)
{  PORTC SET_B(4);                    // конец зап1          
   PORTC CLR_B(5);}                  // начало зап2
if (cnt_isrt2==0x98) PORTC SET_B(5);  // конец зап2
if (cnt_isrt2==0xC8)
{cnt_T2++;                     //конец одного  периода
cnt_isrt2=0;}                  // Обнуление счетчика прерываний
if (cnt_T2==0x03){
    if (n<0x01)
     {PORTB SET_B(3);   //Запуск поляризованного реле
       n++;             // Считаем количество импульсов
     }
   }
if (cnt_T2>=0x04) PORTD CLR_B(0);   // Конец запуска нейтрального  реле
if (cnt_T2==0x04)
{  PORTB CLR_B(3);                 // Конец запуска поляризованного  реле
  cnt_T2=0;                    // обнуление счетчика периодов
  }
}




// ADC  Прерывание по  окончанию АЦП
ISR(ADC_vect)
{ uchar c;
  //ADCSRA |= _BV(ADIF);         // clear flag
  //ADCSRA|=0x40;
  //loop_until_bit_is_set(ADCSRA,ADIF);
  //ADCSRA |= _BV(ADIF);        // clear flag
  c=ADCL;
  c=ADCH;                   // Результат АЦП
  adc_buffer[adc_counter]=c;// Массив данных АЦП
  adc_counter++;            //Увел-е на 1 счетчтка АЦП
    if(adc_counter>=ADC_STOP_STEP) //Если АЦП закончено начинаем фильтровать
   {adc_counter=0;
   filter();
    }
}

void filter () // Сглаживаем синусоиду
{ uchar i;
  const char porog=0x0F; // Значение порога 0,24В
for(i=0;i<ADC_STOP_STEP;i++)
{
result[i]=(adc_buffer[i]+adc_buffer[i+1])/2;
if (result[i]>porog) adc_buffer[i]=result[i];} // Берем значения больше порога
analyze();
}

// analyze data
void analyze()
{ uchar i;
  val=0;
  //uchar val8;
  max_val=0;
  for(i=0;i<ADC_STOP_STEP-1;i++)
{  if(adc_buffer[i]>max_val) max_val=adc_buffer[i]; //Ищем наибольшее значение
  }
  val8=max_val;
  val=val8;         // Максимальное значение в массиве
  //analyze_transmit();
  spi_mastertransmit();
}

// analyze_transmit анализ  принятых данных
void analyze_transmit()
{ dop1=0x05;  // Допустимое. значение 5
  dop2=0x00;  // Допустимое значение 0
  adc_delta=val-adc2; // Определение разницы измеренного  и принятого значения АЦП
if (adc_delta>dop1) val8=adc2; //Если разница положительная используем принятое значение АЦП
else
  {adc_delta=adc2-val; // Если отриц.,вычисляем положительную разницу
  val8=val;            // используем измеренное значение
  }

    if (adc_delta>dop2) // Если разница больше допустимого
    { STATUS1_OFF;      //Выкл. индик.
      FCONTROL_OFF;       //Выкл. контр. частоту
      POUT_OFF;           //Выкл. фронт ключ
      //POUT1_ON;           //Вкл. тыл. ключ
    SNU_OFF;
      return;
    }
  else
  if (adc_delta<dop2)   //Если разница меньше допустимого -  анализ порога
  {
          if(val8>(level-level_delta)) //если больше порога
        { STATUS1_ON;      //Вкл. индик
           FCONTROL_ON;     //Вкл. контр. частоту
          POUT_ON;         //Вкл. Вкл. фронт. кл.
        //POUT1_OFF;       //Выкл. тыл.  ключа
        SNU_ON;          //Вкл. сигнала наличия уровня
        test_transmit();
     }
  
              else         // если меньше порога
  //if (val<(leveloff-level_deltaoff))
            {    STATUS1_OFF;  //Выкл. индик.
              FCONTROL_OFF; //Выкл. контр. частоту
              POUT_OFF;     //Выкл. фронт ключ
             //POUT1_ON;    //Вкл. тыл. ключ
              SNU_OFF;      //Выкл. сигнала наличия уровня
           }
   }
}


void spi_mastertransmit() // Передача макс. значения массива по SPI
{init_SPI();
SPDR=val;
while(!(SPSR & (1<<SPIF)));
{};
return SPDR;
}

ISR (SIG_SPI)
{
adc2=SPDR;
SPCR=0x40;                 // Прием макс. значения массива по SPI
analyze_transmit();
sei();
}

// test_transmit() вывод  на вых тест рез-та АЦП
void test_transmit()
{ signed char res1;
  signed char res2;
  int i;
  for (i=0; i<8;i++)
  {
    res1=val8>>i;
    res2=res1&01;
    if (res2==1)
    PORTD SET_B(1);
    else
    PORTD CLR_B(1);
    
  }
}

int main(void)
{  
   init_pio();
   read_cfg();
   init_adc();
   init_timers();
   ACSR=0x80;     // Выкл. аналог.  компаратора
   sei();         // Разрешение прерываний
   while (1);
   }

Это для мастера, для слэйва тоже самое, разница только в настрйках SpI и портаВ

Для слэйва:
настройки портов
Код
//Инициализация портов
void init_pio()      
{ DDRA=0;
  DDRB=0x4F;
  DDRC=0xBF;
  DDRD=0xB3;
  PORTB=0x00;                    // откл.Slave по  выводу SS
  PORTC=0x30;
  PORTD=0x01;
}


Настройка SPI
Код
// Инициализация SPI
// init SPI                    
void init_SPI()
{
SPCR=_BV(SPIE)|_BV(SPE)|_BV(SPIF)|_BV(SPR1); //вкл.SPI,разр.прерыв., реж.мастер                                //Вкл. Slave по  выводу SS
//sei();
}


Передача данных по Spi
Код
void spi_mastertransmit()  // Передача макс. значения массива по SPI
{
init_SPI();
SPDR=val;
while(!(SPSR & (1<<SPIF)));
}

ISR (SIG_SPI)
{
adc2=SPDR;                // Прием макс. значения массива по SPI
analyze_transmit();

}


да. вот еще вопросик возник... в AVR Studio когда я просматриваю программу в пошаговом режиме там можно заметить время между прерываниями... так вот у меня АЦП, запускается по прерыванию таймера Т0 через каждые 0,5 мс а в AVR Studio я наблюдаю величину в 2 раза большую. с чем это связано?
Aesthete Animus
Ну во-первых, Вы действительно задали неверный прескаллер, а именно - 128. Так что, код в этой строчке
Код
TCCR2=_BV(CS22)|_BV(CS20);      // clk/1024

не соответствует комментарию к ней. Внимательно почитайте doc2466, страница 130.

Собственно SPI. Во-первых, не надо его переинициализировать при каждой команде записи. Во-вторых, меня сильно смущает это строчка
Код
while(!(SPSR & (1<<SPIF)));

У вас включен обрабочик SPI, следовательно, флаг SPIF сбрасывается аппаратно. Вполне возможно, что здесь у вас просто проваливается в вечный цикл.

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

Цитата
у меня АЦП, запускается по прерыванию таймера Т0

Зачем это надо? Используйте Free Runing Mode
SysRq
Цитата(Aesthete Animus @ Nov 19 2008, 00:39) *
Код
while(!(SPSR & (1<<SPIF)));

У вас включен обрабочик SPI, следовательно, флаг SPIF сбрасывается аппаратно. Вполне возможно, что здесь у вас просто проваливается в вечный цикл.

Не-не-не-не! На этот while попадаем из ISR(ADC_vect).

Интереснее зачем в ISR(SIG_SPI) есть строка "SPCR=0x40;", которая мастер отключает... да еще и вложенные прерывания разрешаются..
Aesthete Animus
Цитата(SysRq @ Nov 19 2008, 01:15) *
Интереснее зачем в ISR(SIG_SPI) есть строка "SPCR=0x40;", которая мастер отключает... да еще и вложенные прерывания разрешаются..

Меня тоже сие удивило. А вообще, там много "интересных" строчек... sad.gif

Цитата(SysRq @ Nov 19 2008, 01:15) *
Не-не-не-не! На этот while попадаем из ISR(ADC_vect).

дададада, действительно... туплю...
_Надя
хочу сказать что
Код
while(!(SPSR & (1<<SPIF)));
что с этой строчкой что без нее одна фигня...
про прескалер у меня так в книге написано, что эти коэффициенты соответствуют коффициенту 1024...
SPI у меня так был настроен в другой программе где просто передавались данные - все работало.
По крайней мере на порт выводило передаваемые данные. Спасибо за советы. пойду дальше разбираться. На вопросы отвечу позже - сейчас на работу убегаю.
_Надя
Спасибо всем за помощь smile.gif
Не судите строго - это первая программа, которую я пишу. До этого программированием не занималась. поэтому может что то быть криво косо не красиво, но мне сейчас важно что бы это работало.
с таймером разобралась - все получилось.
С SPI тоже все хорошо. видно что отсылается что принимается. конечно все это с учетом Ваших замечаний.
Теперь возник еще один вопрос, никак не могу понять в чем же дело...
я в пошаговом режиме просматриваю алгоритм - все отлично работает, если переменные val и adc2 имеют значения больше 0х80 - то все корректно работает, если меньше то там где не нужно в статус регистре устанавливаются флаги Н, S, V, C . Дальше идет неверное выполнение программы. я так понимаю, что это связано с отрицательными числами. Везде стараюсь сравнивать переменные одинаковых типов. Правда в этой программе приходится переменный val , adc2 присваивать числа, т.к. на самом деле в эти переменные записывается результат АЦП. Точнее в переменной val хранится результат АЦП а переменная adc2 - в нее пишется принятое по SPI значение. Может кто нибудь подскажет на что обратить внимание? и какие еще косяки бросились Вам в глаза в первом исходнике? Мне сейчас это важно. заранее благодарю smile.gif
Код
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include <avr/eeprom.h>
#include <util/delay.h>


// global defines
#define uchar unsigned char
#define ushort unsigned short


// init_ports

#define F_CONTROL   PB0
#define P_OUT          PB1
#define P_OUT1         PB2
#define P_relays     PB3
#define SLED1        PC2
#define SLED2        PC3
#define Zap1        PC4
#define Zap2        PC5
#define SNU         PD7
#define TEST        PD1
#define N_relays    PD0


#define CPU_CLK                8000000
#define STATUS1_ON        PORTC|=_BV(SLED1)
#define STATUS1_OFF        PORTC&=~_BV(SLED1)
#define FCONTROL_ON      PORTB|=_BV(F_CONTROL)
#define FCONTROL_OFF     PORTB&=~_BV(F_CONTROL)
#define POUT_ON          PORTB|=_BV(P_OUT)
#define POUT_OFF        PORTB&=~_BV(P_OUT)
#define POUT1_ON          PORTB|=_BV(P_OUT1)
#define POUT1_OFF        PORTB&=~_BV(P_OUT1)
#define SNU_ON          PORTD|=_BV(SNU)
#define SNU_OFF            PORTD&=~_BV(SNU)


// global variables


volatile signed char val;                   //Максимальное значение в массиве
volatile signed char val8;                 //Переменная для анализа уровня
volatile signed char adc_delta;             //Разница значений между двумя АЦП
volatile signed char adc2;                  //Принятый рез-т АЦП
volatile uchar level;
volatile signed char leveloff;
volatile signed char dop1;
volatile signed char dop2;
volatile signed char n;
volatile signed char t;
uchar eeprom_addr;
uchar adc_addr;

//functions

void analyze_transmit();


//Инициализация портов
void init_pio()      
{ DDRA=0;
  DDRB=0xBF;
  DDRC=0xBF;
  DDRD=0xB3;
  PORTB=0x10;                    // откл.Slave по  выводу SS
  PORTC=0x30;
  PORTD=0x01;
}


// read cfg from eeprom

#define EEA_LEVEL           0
#define EEA_LEVEL_OFF   1

void read_cfg()
{eeprom_addr=0;
  adc_addr=0;
eeprom_write_byte(0,0xBB); //Порог включения
eeprom_write_byte(1,0x74); //Порог выключения
//read
level=eeprom_read_byte(EEA_LEVEL);
leveloff=eeprom_read_byte(EEA_LEVEL_OFF);
}

// analyze_transmit анализ  принятых данных
void analyze_transmit()
{
dop1=0x00;  // Допустимое. значение 5
  dop2=0x01;  // Допустимое значение 0
  val=0x0F;
  adc2=0F;
  adc_delta=val-adc2; // Определение разницы измеренного  и принятого значения АЦП
if (adc_delta>=dop1) val8=adc2; //Если разница положительная используем принятое значение АЦП
if (adc_delta<dop1)
  {adc_delta=adc2-val; // Если отриц.,вычисляем положительную разницу
  val8=val;            // используем измеренное значение
  }

    if (adc_delta>dop2) // Если разница больше допустимого
    { STATUS1_OFF;      //Выкл. индик.
      FCONTROL_OFF;       //Выкл. контр. частоту
      POUT_OFF;           //Выкл. фронт ключ
      //POUT1_ON;           //Вкл. тыл. ключ
    SNU_OFF;
      return;
    }
  
  if(adc_delta<=dop2) {     //Если разница меньше допустимого -  анализ порога    
  if (val8>=level)             //если больше порога                                // Здесь  устанавливаются флаги H,C,N Статус регистр
        { STATUS1_ON;      //Вкл. индик
           FCONTROL_ON;     //Вкл. контр. частоту
          POUT_ON;         //Вкл. Вкл. фронт. кл.
        //POUT1_OFF;       //Выкл. тыл.  ключа
        SNU_ON;          //Вкл. сигнала наличия уровня
       }
     }
  
  else {            // если меньше порога
    if (val8<leveloff)
            {    STATUS1_OFF;  //Выкл. индик.
              FCONTROL_OFF; //Выкл. контр. частоту
              POUT_OFF;     //Выкл. фронт ключ
             //POUT1_ON;    //Вкл. тыл. ключ
              SNU_OFF;      //Выкл. сигнала наличия уровня
           }
   } }



int main(void)
{  
   init_pio();
   read_cfg();
   while (1)
   analyze_transmit();
   }
SysRq
Замените ненужные сложные конструкции типа
Код
if (A>=B) {}
if (A<B) {}
на вполне себе логичные и простые
Код
if(A>=B) {}
else {}


И стоит, пожалуй, внимательно посмотреть все ли переменные необходимо объявить как volatile.
_Надя
Спасибо за совет smile.gif

В принципе и так и так меняла конструкции - легче не стало. В этой программе пожалуй и не стоит все переменные объявлять как volatile. А на что это влияет?
mdmitry
Цитата(_Надя @ Nov 19 2008, 20:34) *
В этой программе пожалуй и не стоит все переменные объявлять как volatile. А на что это влияет?

На работу оптимизатора компилятора. Керниган и Ричи, язык С.
_Надя
Спасибо smile.gif Разобралась. Все заработало.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.