_Надя 0 18 ноября, 2008 Опубликовано 18 ноября, 2008 · Жалоба Я по прерыванию таймера Т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 вызываю функцию обработки принятых данных. Заранее благодарю :) прошу прощения за много бкафф Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Aesthete Animus 0 18 ноября, 2008 Опубликовано 18 ноября, 2008 · Жалоба Сударыня, прошу Вас, покажите кусочек исходника с инициализацией. А лучше покажите его целиком. Это гораздо яснее нам скажет, что Вы делаете, нежели словесные описания. Вы, к примеру, могли напутать с прескаллером. Лично я обычно таймер инциализирую по-другому - об этом я уже неоднократно писал (прям любимая моя тема), например здесь http://electronix.ru/forum/index.php?showtopic=55363 SPI... Как инициализируете, не забыли ли про направление портов, как соедины девайсы (схема)? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_Надя 0 18 ноября, 2008 Опубликовано 18 ноября, 2008 · Жалоба Пр направление портов не забыла.... Как соединены - сейчас не могу схему кинуть..... 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 0 18 ноября, 2008 Опубликовано 18 ноября, 2008 · Жалоба Ну во-первых, Вы действительно задали неверный прескаллер, а именно - 128. Так что, код в этой строчке TCCR2=_BV(CS22)|_BV(CS20); // clk/1024 не соответствует комментарию к ней. Внимательно почитайте doc2466, страница 130. Собственно SPI. Во-первых, не надо его переинициализировать при каждой команде записи. Во-вторых, меня сильно смущает это строчка while(!(SPSR & (1<<SPIF))); У вас включен обрабочик SPI, следовательно, флаг SPIF сбрасывается аппаратно. Вполне возможно, что здесь у вас просто проваливается в вечный цикл. А вообще, пересмотрите общую структуру кода и оформление кода. У вас очень много голых чисел в исходнике, много таких мест, работы который вызывает опасение. у меня АЦП, запускается по прерыванию таймера Т0 Зачем это надо? Используйте Free Runing Mode Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
NullPointer 0 18 ноября, 2008 Опубликовано 18 ноября, 2008 · Жалоба while(!(SPSR & (1<<SPIF))); У вас включен обрабочик SPI, следовательно, флаг SPIF сбрасывается аппаратно. Вполне возможно, что здесь у вас просто проваливается в вечный цикл. Не-не-не-не! На этот while попадаем из ISR(ADC_vect). Интереснее зачем в ISR(SIG_SPI) есть строка "SPCR=0x40;", которая мастер отключает... да еще и вложенные прерывания разрешаются.. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Aesthete Animus 0 18 ноября, 2008 Опубликовано 18 ноября, 2008 · Жалоба Интереснее зачем в ISR(SIG_SPI) есть строка "SPCR=0x40;", которая мастер отключает... да еще и вложенные прерывания разрешаются.. Меня тоже сие удивило. А вообще, там много "интересных" строчек... :( Не-не-не-не! На этот while попадаем из ISR(ADC_vect). дададада, действительно... туплю... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_Надя 0 19 ноября, 2008 Опубликовано 19 ноября, 2008 · Жалоба хочу сказать что while(!(SPSR & (1<<SPIF))); что с этой строчкой что без нее одна фигня... про прескалер у меня так в книге написано, что эти коэффициенты соответствуют коффициенту 1024... SPI у меня так был настроен в другой программе где просто передавались данные - все работало. По крайней мере на порт выводило передаваемые данные. Спасибо за советы. пойду дальше разбираться. На вопросы отвечу позже - сейчас на работу убегаю. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_Надя 0 19 ноября, 2008 Опубликовано 19 ноября, 2008 (изменено) · Жалоба Спасибо всем за помощь :) Не судите строго - это первая программа, которую я пишу. До этого программированием не занималась. поэтому может что то быть криво косо не красиво, но мне сейчас важно что бы это работало. с таймером разобралась - все получилось. С SPI тоже все хорошо. видно что отсылается что принимается. конечно все это с учетом Ваших замечаний. Теперь возник еще один вопрос, никак не могу понять в чем же дело... я в пошаговом режиме просматриваю алгоритм - все отлично работает, если переменные val и adc2 имеют значения больше 0х80 - то все корректно работает, если меньше то там где не нужно в статус регистре устанавливаются флаги Н, S, V, C . Дальше идет неверное выполнение программы. я так понимаю, что это связано с отрицательными числами. Везде стараюсь сравнивать переменные одинаковых типов. Правда в этой программе приходится переменный val , adc2 присваивать числа, т.к. на самом деле в эти переменные записывается результат АЦП. Точнее в переменной val хранится результат АЦП а переменная adc2 - в нее пишется принятое по SPI значение. Может кто нибудь подскажет на что обратить внимание? и какие еще косяки бросились Вам в глаза в первом исходнике? Мне сейчас это важно. заранее благодарю :) #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(); } Изменено 19 ноября, 2008 пользователем _Надя Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
NullPointer 0 19 ноября, 2008 Опубликовано 19 ноября, 2008 · Жалоба Замените ненужные сложные конструкции типа if (A>=B) {} if (A<B) {} на вполне себе логичные и простые if(A>=B) {} else {} И стоит, пожалуй, внимательно посмотреть все ли переменные необходимо объявить как volatile. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_Надя 0 19 ноября, 2008 Опубликовано 19 ноября, 2008 · Жалоба Спасибо за совет :) В принципе и так и так меняла конструкции - легче не стало. В этой программе пожалуй и не стоит все переменные объявлять как volatile. А на что это влияет? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
mdmitry 0 20 ноября, 2008 Опубликовано 20 ноября, 2008 · Жалоба В этой программе пожалуй и не стоит все переменные объявлять как volatile. А на что это влияет? На работу оптимизатора компилятора. Керниган и Ричи, язык С. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_Надя 0 20 ноября, 2008 Опубликовано 20 ноября, 2008 · Жалоба Спасибо :) Разобралась. Все заработало. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться