I2C w C

To forum jest dla wszystkich pasjonatów mikrokontrolerów AVR Atmela. Wymiana doświadczeń i pomoc dla początkujących w pisaniu programów zarówno w C, Asemblerze jak i BASCOM. Zapraszam znawców tematu, aby pomogli wszystkim początkującym!
ODPOWIEDZ
Awatar użytkownika
Kulpina
Użytkownik
Posty: 2037
Rejestracja: 28 lip 2005, 16:57
Lokalizacja: Sanok
Kontakt:

I2C w C

Post autor: Kulpina » 14 gru 2009, 18:14

Piszę taki program:

Kod: Zaznacz cały

SIGNAL(SIG_OVERFLOW1)
{

TCNT1 = 25536;

i2cstart();
i2cwrite(0x9E);
i2cread(ACK);
i2cwrite(0xAA);
i2cread(ACK);
i2cstart();
i2cwrite(0x9F);
i2cread(ACK);
g_temp1 = i2cread(ACK);
g_temp2 = i2cread(NOACK);
i2cstop();


g_Wyswietlacz2[1] = g_temp1;
g_Wyswietlacz2[2] = g_temp2;
++g_Wyswietlacz1[5];

}
I nie wiem, czy to w nim jest błąd, czy jest jakiś problem od strony sprzętowej
to zmiennych g_temp1 i g_temp2 jest cały czas wpisywane 255...
Najbardziej denerwuje to, że już kiedyś taki program napisałem i działał od razu, a teraz w takim samym prototypie zmontowanym po raz drugi (stary program mi się zgubił :/) coś mi nie wychodzi...

Awatar użytkownika
Aro
Użytkownik
Posty: 677
Rejestracja: 30 paź 2006, 18:49
Lokalizacja: Świerczyniec | Wrocław
Kontakt:

Post autor: Aro » 14 gru 2009, 18:36

"taki program" - nie ma to jak komplet informacji, od razu wszystko wiadomo...

Zobacz sobie funkcje dla PCF8583, może trochę pomogą. Działa w 100%

Kod: Zaznacz cały

//I2C - PCF8583
#define SDAc   DDR(PORT_SDA) |=_BV(pinSDA);   PORT(PORT_SDA) &=~_BV(pinSDA);
#define SDAs   DDR(PORT_SDA) &=~_BV(pinSDA);     PORT(PORT_SDA) |=_BV(pinSDA);
#define SDAwe         PIN(PORT_SDA) &_BV(pinSDA)
#define SCLc   DDR(PORT_SCL) |=_BV(pinSCL); PORT(PORT_SCL) &=~_BV(pinSCL);
#define SCLs   DDR(PORT_SCL) &=~_BV(pinSCL); PORT(PORT_SCL) |=_BV(pinSCL);
#define SCLwe           PIN(PORT_SCL) &_BV(pinSCL)


void wait(void)
{
	_delay_loop_1(5);
}
void start_PCF(void) //bit startu
{
	SDAs;
	wait();
	SCLs;
	wait();
	SDAc;
	wait();
	SCLc;
}

void stop_PCF(void) //bit stopu
{
	SDAc;
	wait();
	SCLs;
	wait();
	SDAs;
	wait();
}

uint8_t write_PCF(uint8_t kod) //zapisz bajt
{
	uint8_t i;
	for(i=0;i<8;i++)
	{		//zamiast else lepiej zastosowac taka konstrukcję, pojawienie sie fałszywego stanu niczym nie grozi
		SDAs;    //koniecznie najpierw ustawienie lini SDA
		if(!(kod&0x80))SDAc;  //musi byc taka kolejnosc, najpierw SDAs, i w zaleznosci od warunku potem SDAc
		wait();
		SCLs;
		wait();
		SCLc;
		wait();
		kod<<=1;
	}
	SDAs;
	wait();
	SCLs;
	while(!(SCLwe));
	wait();
	i=SDAwe;
	SCLc;
	wait();
	return i;
}
		
uint8_t read_PCF(uint8_t ack) //odczytaj bajt
{
	uint8_t kod=0;
	uint8_t i;
	for(i=0;i<8;i++)
	{
		SCLc;
		wait();
		SCLs;
		wait();
		kod<<=1;
		if(SDAwe)kod|=1;
	}
	SCLc;
	SDAs;
	if(ack)SDAc;
	wait();
	SCLs;
	while(!(SCLwe));
	wait();
	SDAs;
	SCLc ;
	return kod;
}
//procedura zapisu zmiennej do rejestru PCF
void doPCF(uint8_t kod, uint8_t adr)
{
	start_PCF();
	write_PCF(0xa0);
	write_PCF(adr);
	write_PCF(kod);
	stop_PCF();
}
//procedura odczytu rejestru PCF do zmiennej
uint8_t _odPCF(uint8_t adr)
{
	uint8_t kod;
	start_PCF();
	write_PCF(0xa0);
	write_PCF(adr);
	start_PCF();
	write_PCF(0xa1);
	kod=read_PCF(0);
	stop_PCF();
	return kod;
}
Nawet rezystorów podciągających nie musisz używac.

Awatar użytkownika
Kulpina
Użytkownik
Posty: 2037
Rejestracja: 28 lip 2005, 16:57
Lokalizacja: Sanok
Kontakt:

Post autor: Kulpina » 14 gru 2009, 18:42

No tak, podałem tylko ten fragment, ale jeszcze mnie zastanawia, czy to i2cread ack ma być tak za każdym razem?

[ Dodano: 2009-12-14, 18:53 ]
niby działą, czyli program jest ok, tylko coś jakby niestyka...
bd kombinował, jeszcze ze sprzętem, ale czy nigdzie nie ma żadnego kursu/opisu i2c? Jak narazie trafiłem jedynie na przykłady, albo noty katalogowe...

snow
Użytkownik
Posty: 794
Rejestracja: 16 sty 2007, 3:44
Lokalizacja: lubelskie
Kontakt:

Post autor: snow » 14 gru 2009, 19:11

Cały sposób transmisji (kiedy ACK a kiedy nie) jest podany w nocie aplikacyjnej. Generalnie ACK trzeba wysyłać po odebraniu bajtu. ACK zawsze wysyła SLAVE po odebraniu danych. Master wysyła bajt i czeka na ACK od SLAVE'a, jeśli będzie ACK to znaczy że można wysłać kolejny bajt. Jak nie to znaczy że ma nic nie wysyłać. Zatem gdy adresujesz układ to wysyłasz mu bajt i musisz czekać na ACK (co potwierdza że SLAVE odebrał dane).

slawek55
Użytkownik
Posty: 475
Rejestracja: 16 sie 2005, 11:47
Lokalizacja: Szczecin

Post autor: slawek55 » 18 gru 2009, 11:55

Powiedz mi kiedy potrzebne jest powtórzenie sekwencji START?
Ostatnio zwróciłem uwagę na coś takiego. Jest program obsługo przetwornika
PCF8591 w jednym programie jest S-A-D-S-A1-D-D-D-P S-start, A-adres, P-stop
A w innym nie ma powtórzonego Start.
Dlaczego? Czy zawsze jest potrzebne powtórzenie startu?

snow
Użytkownik
Posty: 794
Rejestracja: 16 sty 2007, 3:44
Lokalizacja: lubelskie
Kontakt:

Post autor: snow » 18 gru 2009, 17:09

Dokumentacja o tym mówi kiedy start a kiedy nie.

Awatar użytkownika
radzio
Użytkownik
Posty: 573
Rejestracja: 07 gru 2004, 23:06
Lokalizacja: Sosnowiec
Kontakt:

Post autor: radzio » 19 gru 2009, 12:54

snow pisze:ACK zawsze wysyła SLAVE po odebraniu danych. Master wysyła bajt i czeka na ACK od SLAVE'a, jeśli będzie ACK to znaczy że można wysłać kolejny bajt.
Nie do końca tak. ACK zawsze wystawia odbiornik a odbiornikiem może być zarówno master jak i slave - są 4 główne tryby pracy :
- master nadajacy (np. w momencie nadawania adresu)
- master odbierający (np. w momencie odbierania danych odczytywanych z pamięci)
- slave nadający (np. eeprom wysyłający swoją zawartość)
- slave odbierający (np. eeprom odbierający swój adres, adres komórki pamięci, lub daną do zapisania).

Pogrubione wysyłają ACK, pozostałe odbierają ACK. Ponadto, sygnał ACK oznacza, iż odbiornik jest gotów do odebrania kolejnego bajtu danych - nie zawsze po stwierdzeniu ACK transmisja musi być kontynuowana - ACK sygnalizuje wyłącznie gotowość do odebrania danych.

Awatar użytkownika
Kulpina
Użytkownik
Posty: 2037
Rejestracja: 28 lip 2005, 16:57
Lokalizacja: Sanok
Kontakt:

Post autor: Kulpina » 19 gru 2009, 15:34

Mój program zadziałał w takiej wersji:
i2cstart();
i2cwrite(0x9E);
i2cwrite(0xAA);
i2cstart();
i2cwrite(0x9F);
g_temp1 = i2cread(NOACK);
i2cstop();

+ biblioteki ze strony radzia, polecam ;)

ODPOWIEDZ