Помогите студенту с I2C

Обсуждаем контроллеры компании Atmel.
Ответить
Родился
Сообщения: 4
Зарегистрирован: Пн май 02, 2016 12:39:36

Сообщение Lokost39 »

Здравствуйте) Суть в том что я пытаюсь связать по данному интерфейсу(I2C) несколько(3) ATMEGA8, ну пока что только 2. Я хочу что бы первый контроллер отправил данные второму, после чего второй отправил бы данные первому. От первого к ведомому все передается а вот от второго к первому проблема, бит подтверждения не приходит
пишу в codevision
код первого
Спойлер#include <mega8.h>

#include <delay.h>

// Alphanumeric LCD Module functions

#include <alcd.h>
#include <stdio.h>
#define FIRST_ADC_INPUT 0
#define LAST_ADC_INPUT 0
unsigned int adc_data[LAST_ADC_INPUT-FIRST_ADC_INPUT+1];
#define ADC_VREF_TYPE 0x40
#define ME_ADDR 0b00000101// адрес для обращения
#define HE_ADDR 0b00000010// адрес для отправки
// глобальные переменные
char data_twi;
unsigned char lcd_buffer[31];
char flag;
// functions
//чтение статуса
unsigned char twi_GetStatus(void)
{
unsigned char status;//переменная хранения
status = TWSR & 0xF8;//маска
return status;
}

char twi_init(void){
//
TWAR = ME_ADDR;
TWCR=(1<<TWEA)//разрешаем подтверждение
|(1<<TWEN)//включаем модуль TWI
|(1<<TWIE);//разрешаем прерывание
return 1;
}

// отправка команды СТАРТ
void I2C_StartCondition(void)
{
TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
while (!(TWCR & (1<<TWINT)));//ожидание установки бита TWIN
}

// отправка СТОП
void I2C_StopCondition(void)
{
TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
}

//отправка байта
void I2C_SendByte(unsigned char c)
{
TWDR = c;//загрузка значения в регистр данных
TWCR = (1<<TWINT)|(1<<TWEN);//начаало передачи байта данных
while (!(TWCR & (1<<TWINT)));//ожидание установки бита TWIN
}

//отправка SLA_W + байт данных
void I2C_SendPocket (unsigned char value)
{
I2C_StartCondition(); // генерируем условие СТАРТ
I2C_SendByte(HE_ADDR); //оправляем адрес устройства+бит запись
I2C_SendByte(value);//отправляем байт данных
I2C_StopCondition();//генерируем условие СТОП
}

// ADC interrupt service routine
// with auto input scanning
interrupt [ADC_INT] void adc_isr(void)
{
static unsigned char input_index=0;
// Read the AD conversion result
adc_data[input_index]=ADCW;
// Select next ADC input
if (++input_index > (LAST_ADC_INPUT-FIRST_ADC_INPUT))
input_index=0;
ADMUX=(FIRST_ADC_INPUT | (ADC_VREF_TYPE & 0xff))+input_index;
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// Start the AD conversion
ADCSRA|=0x40;
}

// Two Wire bus interrupt service routine
interrupt [TWI] void twi_isr(void)
{
// Place your code here
/* if(twi_GetStatus()==0x80){//пришли данные от ведущего
data_twi=TWDR;//читаем значение
flag = 1;
} */
data_twi=TWDR;//читаем значение
flag = 1;
TWCR|=(1<<TWEN);//сбрасываем флаг

}

/*
{
TWAR=ME_ADDR;// адрес для обращения
TWCR=(1<<TWEA)//разрешаем подтверждение
|(1<<TWEN)//включаем модуль TWI
|(1<<TWIE);//разрешаем прерывание
}
*/

// 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: Timer1 Stopped
// Mode: Normal top=0xFFFF
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 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: Timer2 Stopped
// Mode: Normal top=0xFF
// 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;

// USART initialization
// USART disabled
UCSRB=0x00;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;

// ADC initialization
// ADC Clock frequency: 125,000 kHz
// ADC Voltage Reference: AVCC pin
ADMUX=FIRST_ADC_INPUT | (ADC_VREF_TYPE & 0xff);
ADCSRA=0xCF;

// SPI initialization
// SPI disabled
SPCR=0x00;

// TWI initialization
// Bit Rate: 125,000 kHz
TWBR=0x38;
// Two Wire Bus Slave Address: 0x0
// General Call Recognition: Off
TWAR=0x00;
// Generate Acknowledge Pulse: Off
// TWI Interrupt: On
TWCR=0x05;
TWSR=0x00;

// Alphanumeric LCD initialization
// Connections specified in the
// Project|Configure|C Compiler|Libraries|Alphanumeric LCD menu:
// RS - PORTB Bit 0
// RD - PORTB Bit 1
// EN - PORTB Bit 2
// D4 - PORTB Bit 4
// D5 - PORTB Bit 5
// D6 - PORTB Bit 6
// D7 - PORTB Bit 7
// Characters/line: 8
lcd_init(8);

// Global enable interrupts
#asm("sei")
twi_init();
flag = 0;
//while(1){I2C_SendPocket (1); delay_ms(30);}
I2C_SendPocket (3);
while (1)
{
// Place your code here
while (flag == 0){}
delay_ms(30);
lcd_clear();
sprintf(lcd_buffer,"%i",data_twi);
lcd_puts(lcd_buffer);

I2C_SendPocket(3);
flag = 0;
}
}
код второго
Спойлер/*****************************************************
This program was produced by the
CodeWizardAVR V2.05.0 Professional
Automatic Program Generator
© Copyright 1998-2010 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project :
Version :
Date : 30.04.2016
Author :
Company :
Comments:


Chip type : ATmega8
Program type : Application
AVR Core Clock frequency: 16,000000 MHz
Memory model : Small
External RAM size : 0
Data Stack size : 256
*****************************************************/

#include <mega8.h>

#include <delay.h>

// Alphanumeric LCD Module functions

#include <alcd.h>
#include <stdio.h>
#define FIRST_ADC_INPUT 0
#define LAST_ADC_INPUT 0
unsigned int adc_data[LAST_ADC_INPUT-FIRST_ADC_INPUT+1];
#define ADC_VREF_TYPE 0x40
#define ME_ADDR 0b00000011// адрес для обращения
#define HE_ADDR 0b00000100// адрес для отправки
// глобальные переменные
char data_twi;
unsigned char lcd_buffer[31];
char flag;
// functions
//чтение статуса
unsigned char twi_GetStatus(void)
{
unsigned char status;//переменная хранения
status = TWSR & 0xF8;//маска
return status;
}

char twi_init(void){
//
TWAR = ME_ADDR;
TWCR=(1<<TWEA)//разрешаем подтверждение
|(1<<TWEN)//включаем модуль TWI
|(1<<TWIE);//разрешаем прерывание
return 1;
}

// отправка команды СТАРТ
void I2C_StartCondition(void)
{
TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
while (!(TWCR & (1<<TWINT)));//ожидание установки бита TWIN
}

// отправка СТОП
void I2C_StopCondition(void)
{
TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
}

//отправка байта
void I2C_SendByte(unsigned char c)
{
TWDR = c;//загрузка значения в регистр данных
TWCR = (1<<TWINT)|(1<<TWEN);//начаало передачи байта данных
while (!(TWCR & (1<<TWINT)));//ожидание установки бита TWIN
}

//отправка SLA_W + байт данных
void I2C_SendPocket (unsigned char value)
{
I2C_StartCondition(); // генерируем условие СТАРТ
I2C_SendByte(HE_ADDR); //оправляем адрес устройства+бит запись
I2C_SendByte(value);//отправляем байт данных
I2C_StopCondition();//генерируем условие СТОП
}

// ADC interrupt service routine
// with auto input scanning
interrupt [ADC_INT] void adc_isr(void)
{
static unsigned char input_index=0;
// Read the AD conversion result
adc_data[input_index]=ADCW;
// Select next ADC input
if (++input_index > (LAST_ADC_INPUT-FIRST_ADC_INPUT))
input_index=0;
ADMUX=(FIRST_ADC_INPUT | (ADC_VREF_TYPE & 0xff))+input_index;
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// Start the AD conversion
ADCSRA|=0x40;
}

// Two Wire bus interrupt service routine
interrupt [TWI] void twi_isr(void)
{
// Place your code here
/*if(twi_GetStatus()==0x80){//пришли данные от ведущего
data_twi=TWDR;//читаем значение
flag = 1;
} */
data_twi=TWDR;//читаем значение
flag = 1;
TWCR|=(1<<TWEN);//сбрасываем флаг

}

/*
{
TWAR=ME_ADDR;// адрес для обращения
TWCR=(1<<TWEA)//разрешаем подтверждение
|(1<<TWEN)//включаем модуль TWI
|(1<<TWIE);//разрешаем прерывание
}
*/

// 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: Timer1 Stopped
// Mode: Normal top=0xFFFF
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 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: Timer2 Stopped
// Mode: Normal top=0xFF
// 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;

// USART initialization
// USART disabled
UCSRB=0x00;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;

// ADC initialization
// ADC Clock frequency: 125,000 kHz
// ADC Voltage Reference: AVCC pin
ADMUX=FIRST_ADC_INPUT | (ADC_VREF_TYPE & 0xff);
ADCSRA=0xCF;

// SPI initialization
// SPI disabled
SPCR=0x00;

// TWI initialization
// Bit Rate: 125,000 kHz
TWBR=0x38;
// Two Wire Bus Slave Address: 0x0
// General Call Recognition: Off
TWAR=0x00;
// Generate Acknowledge Pulse: Off
// TWI Interrupt: On
TWCR=0x05;
TWSR=0x00;

// Alphanumeric LCD initialization
// Connections specified in the
// Project|Configure|C Compiler|Libraries|Alphanumeric LCD menu:
// RS - PORTB Bit 0
// RD - PORTB Bit 1
// EN - PORTB Bit 2
// D4 - PORTB Bit 4
// D5 - PORTB Bit 5
// D6 - PORTB Bit 6
// D7 - PORTB Bit 7
// Characters/line: 8
lcd_init(8);

// Global enable interrupts
#asm("sei")
twi_init();
flag = 0;
//I2C_SendPocket (9);

//delay_ms(100);
while (1)
{
// while(1){I2C_SendPocket (1); delay_ms(30);}

// Place your code here
while (flag == 0){}
delay_ms(30);
lcd_clear();
sprintf(lcd_buffer,"%i",data_twi);
lcd_puts(lcd_buffer);
twi_init();
I2C_SendPocket (1);
flag = 0;
}
}
Реклама
Потрогал лапой паяльник
Сообщения: 312
Зарегистрирован: Вс июл 29, 2012 16:25:39

Сообщение mas123 »

Lokost39 писал(а): От первого к ведомому все передается а вот от второго к первому проблема, бит подтверждения не приходит
Всё логично.
Селёдка иваси... Шина i2c работает по принципу "мастер инициирует обмен - ведомый отвечает".
А у тебя в коде ведомый пытается передать СТАРТ и т.п. Разумеется, мастер на это не поведется.
Реклама
Родился
Сообщения: 4
Зарегистрирован: Пн май 02, 2016 12:39:36

Сообщение Lokost39 »

Я понимаю что данная шина работает по принципу мастер-слуга.
А у тебя в коде ведомый пытается передать СТАРТ и т.п. Разумеется, мастер на это не поведется.
Т.е.? я команду СТОП подаю на мастере, что должно освободить шину как я понимаю. А после второй инициализирует новое подключение где он уже мастер. Или шина не позволяет делать такое.
Модератор
Аватара пользователя
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля

Сообщение Аlex »

https://www.yandex.ru/yandsearch?clid=9 ... 62194381.1
Просто море статей по этой шине. Лень читать ? :facepalm:
Реклама
Эиком - электронные компоненты и радиодетали
Встал на лапы
Аватара пользователя
Сообщения: 120
Зарегистрирован: Вс янв 10, 2016 17:27:08

Сообщение Муррчик »

Lokost39 писал(а):...Или шина не позволяет делать такое...
В этом вопросе, покамест высокие научные сообщества поделились надвое,
тем временем третьи вообще придумали 1-Wire, круче которого, пожалуй,
только RFID.

А нам, котам смертным, остаётся одно - не забывать, что МК легко может
быть мастером, но поведение ведомого он может лишь эмулировать, а
если нужен быстрый эффективный алгоритм, задача перемещается из
"студенческой" ближе куда-то к "нобелевской".

В любом случае придется понимать каждое событие в шине, отдельно
учитывать все опубликованные и растиражированные неточности и ошибки,
после чего, игнорируя чужие библиотеки, тупо писать на низком уровне своё,
для экономии отладочного времени...

Всё изложенное - ИМХО!
John O'Callaghan vs Neptune Project - Rhea (Chill Out Mix)
Реклама
Потрогал лапой паяльник
Сообщения: 312
Зарегистрирован: Вс июл 29, 2012 16:25:39

Сообщение mas123 »

Lokost39 писал(а):А после второй инициализирует новое подключение где он уже мастер. Или шина не позволяет делать такое.
I2C допускает наличие более одного МАСТЕРА, которые по очереди общаются с ВЕДОМЫМИ.
Но, у тебя же 1-е устройство как было сконфигурировано МАСТЕРОМ, так и осталось. А с какого перепугу МАСТЕР будет отвечать на призывные крики другого МАСТЕРА?
Муррчик писал(а):что МК легко может
быть мастером, но поведение ведомого он может лишь эмулировать,
В МК чаще всего встроен аппаратный модуль i2c, так почему же "эмуляция"?
Муррчик писал(а):понимать каждое событие в шине, отдельно
Зачем? В даташите хорошо описан регистр статуса, где будут выданы все ошибки.
Да и ошибок этих совсем немного: пара ошибок "такты/данные занулены", пара ошибок "не ответил"...
Муррчик писал(а):учитывать все опубликованные и растиражированные неточности и ошибки,
Впервые слышу, можно подробнее?
Установка правильных подтягивающих резисторов - за неточность не считаем, ибо их значения чётко указаны в даташите.
Муррчик писал(а):тупо писать на низком уровне своё,
Этого вообще не понимаю, зачем? С/С++ отлично справляются с работой (в МК или в "большом" процессоре).
Реклама
Друг Кота
Аватара пользователя
Сообщения: 6339
Зарегистрирован: Вт апр 24, 2007 07:45:40
Откуда: Minsk

Сообщение Jack_A »

Lokost39 писал(а): А после второй инициализирует новое подключение где он уже мастер. Или шина не позволяет делать такое.
Ведомому не нужно становится мастером. Передавая, он попрежнему остается слейвом, но мастер при приеме от ведомого передает только клоки по SCL, оставляя SDA в Z, поэтому слейв в этом случае рулит линией SDA . Возможна и мультимастерная конфигурация с арбитражем, но на мою думку это геморр на свою QO .
Изображение
Ответить

Вернуться в «AVR»