Пр направление портов не забыла....
Как соединены - сейчас не могу схему кинуть.....
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 раза большую. с чем это связано?