Skocz do zawartości

Problem z wyświetleniem napięcia z przetwornika PCF8591(I2C)


razors

Pomocna odpowiedź

Witam

Jak już widzicie po tytule nie mogę uzyskać poprawnego wyniku z przetwornika zewnętrznego PCF8591 połączonego z mikrokontrolerem (Atmega16-8Mhz pod piny SCL i SDA) poprzez programowe I2C. Już nie mam pomysłów co może być źle, w czym tkwi haczyk. Wszystko wydaje się być dobrze podłączone, program kompiluje się bez błędów. Kod sprawdziłem już na milion sposobów. Jedyne co uzyskuje na wyświetlaczu to dziwne wyniki napięcia zmienianego potencjometrem 5kOhm z 0 do 5V, a mianowicie:

0 - 1,28V ->> na wyświetlaczu liczba 028

1,28 - 1,92 ->> na wyświetlaczu liczba 128

1,92 - 2,24 ->> 192

2,24 - 2,40 ->> 224

2,4 - 2,48 ->> 240

2,48 - 2,52 ->> 248

....

2,55 - 5 ->> 255

Napięcie Vref na przetworniku mam ustawione na 2,56V co powinno mi dać regulacje 5V od 0 do 255 cyfrowo co 0,01V analogowo. Niestety nie uzyskuje tego wyniku, ale wręcz obniżony do połowy i o bardzo dziwnych kwantach (które jak można zauważyć zwiększają się o pomniejszoną liczbę potęgi 2 bo np. 224 -192=32 a juz 240 - 224 = 16 itd. ). Może ktoś wie w czym problem ?🙁

Poniżej kod obsługi programowego I2C:

//----------------------------------------------------------------------------------------
//Ustawienie i zerowanie wyjscia danych
static inline void i2c_sdasetddr(void)
{
DDR(I2C_SDAPORT) |= 1<<I2C_SDA;
}

static inline void i2c_sdasetport(void)
{
PORT(I2C_SDAPORT) |= 1<<I2C_SDA;
}

static inline void i2c_sdaclearddr(void)
{
DDR(I2C_SDAPORT) &= ~(1<<I2C_SDA);

}

static inline void i2c_sdaclearport(void)
{
PORT(I2C_SDAPORT) &= ~(1<<I2C_SDA);
}

//----------------------------------------------------------------------------------------
//Pobieranie danej z wyprowadzenia portu

static inline uint8_t i2c_sdaget(void)
{
return PIN(I2C_SDAPORT) & (1<<I2C_SDA);
}

//----------------------------------------------------------------------------------------
//Zerowanie i ustawianie zegara
static inline void i2c_sclsetport(void)
{
PORT(I2C_SCLPORT) |= 1<<I2C_SCL;
}

static inline void i2c_sclclearport(void)
{
PORT(I2C_SCLPORT) &= ~(1<<I2C_SCL);
}

static inline void i2c_sclsetddr(void)
{
DDR(I2C_SCLPORT) |= 1<<I2C_SCL;
}

static inline void i2c_sclclearddr(void)
{
DDR(I2C_SCLPORT) &= ~(1<<I2C_SCL);
}

//----------------------------------------------------------------------------------------
//Funkcja startujaca transmisje

void i2c(void)
{
//jesli start bez stop
i2c_sdaclearport();
i2c_hdelay();
i2c_sclsetport();
i2c_hdelay();
i2c_sdasetport();
i2c_hdelay();
}

//----------------------------------------------------------------------------------------
//Funkcja wysylajaca dane

uint8_t i2c_send(uint8_t data)
{
uint8_t n=9;



do
{
	i2c_sclclearport();
	if(data & 0x80)
	{
		i2c_sdasetport();
	}
	else
	{
		i2c_sdaclearport();
	}
	data <<= 1;
	i2c_hdelay();
	i2c_sclsetport();
	i2c_hdelay();
}
while(--n);
i2c_sclclearport();
return n;
}
//----------------------------------------------------------------------------------------
//Funkcja pobierajaca dane

uint8_t i2c_get(uint8_t ack)
{
unsigned char n=8, temp=0;

i2c_sdasetport();
i2c_sdaclearddr();

do
{
	i2c_hdelay();
	i2c_sclsetport();
	i2c_hdelay();
	temp <<=1;
	if(i2c_sdaget())
	{
		temp++;
		i2c_sclclearport();
	}
}
while(--n);
//ack
if(ack)
{
	i2c_sdasetport();
	i2c_hdelay();
	i2c_sclsetport();
	i2c_hdelay();
	i2c_sclclearport();
}

return temp;
}

i fragment pętli głównej:

nt main(void)
{
//inicjalizacja portow
DDR(LCD_DPORT) |= 1<<LCD_LIGHT | 1<<LCD_E | 1<<LCD_RS | 0x0F<<LCD_D4; //wyjscia pod LCD
DDR(I2C_SDAPORT) |= 1<<I2C_SCL;
PORT(LCD_DPORT) |= 1<<I2C_SDA | 1<<I2C_SCL;

//przygotowanie wyswietlacza
lcd_init();
lcd_cls();
PORTD |= 1<<LCD_LIGHT;

//lcd_str_P((prog_char*)PSTR("Dane z AC/CA I0:"));
lcd_command(LCDC_DDA | 64);

//konfiguracja prztwornika
i2c();//koniec konfiguracji

//----------------------------------------------------------------------------------------

//pobieranie danych
for(;;)
{
	lcd_command(LCDC_DDA |64);
	//odczyt danych
	i2c();
}

//return 0;
}

Dodam może jeszcze, że PCF8591 jest raczej podłączony jak należy.

1,2,3,4 przez R1M do masy a i na 1 napięcie z potencjometru.

5,6,7,8,12,13 do masy

9 do sda 10 do scl

11 w powietrzu

14 Vref uzyskane z dzielnika i układu TL431

15 5V

link do przetwornika

Prosiłbym o wszelaką pomoc

Link do komentarza
Share on other sites

No właśnie nie jest wszystko podłączone jak należy. Dajesz na Vref 2,56V a chcesz mierzyć napięcie z zakresu od 0 do Vref+2,5V co jest fizycznie niemożliwe. W każdym przetworniku ADC można mierzyć napięcie w zakresie od 0 do Vref, więc jeśli jeszcze nie uszkodziłeś przetwornika ADC, to wyświetlane wyniki są prawidłowe, ponieważ 255 jest wtedy gdy na wejściu przetwornika napięcie jest równe Vref plus/minus błąd czyli około 2,56V.

Link do komentarza
Share on other sites

       //bajt adresowy, dzieki niemu odczytamy wartosc przetwornika na kanale 0
       i2c_send(0x91); 

0x91 oznacza odczyt z AIN1, a chyba chodziło Ci o AIN0, czyli 0x90.

  • Pomogłeś! 1
Link do komentarza
Share on other sites

sabre, masz racje, ale właśnie nawet dla Vrefmax= 5V =Vdd przetwornik pokazuje napięcia dla całego zakresu lecz dalej w sposób jaki wam zaprezentowałem, chodzi mi o to, że nie uzyskuje na wyświetlaczu innych wyników niż 028, 128,192 ... itd, a chciałbym widzieć te zmianę co 1 co jest oczywiste ... napięcie ref. zmieniłem gdyż początkowo myślałem że w tym tkwi błąd ...

Elvis, kod jest dobry w tym kawałku, możliwe że mam zły komentarz i to Cię zmyliło, ale

//bajt adresowy, dzieki niemu odczytamy wartosc przetwornika na kanale 0
i2c_send(0x91); 

ten kawałek kodu odpowiada za połączenie z moim przetwornikiem i danie mu do zrozumienia (ta właśnie 1 zamiast 0) żeby zaczął nadawać do mikrokontrolera, a dane które ma wysyłać są z jego wewnętrznego rejestru DAC data register w którym przechowuje wyniki z kanału AIN0, bo jak zauważysz wcześniej wysłałem do niego bajt kontrolny

//konfiguracja prztwornika
   i2c_start();
   //bajt adresowy, dzieki niemu zapiszemy bajt kontrolny w przetworniku
   i2c_send(0x90);//przy zwartych A0,A1,A2 mamy 90; podlaczajac pod te piny 1 zmieniamy adres przetwornika
   //bajt kontrolny
   i2c_send(0x00);//przechowywany w rejestrze przetwornika - np. kontrloluje przelaczaenie wejsc ac

który określił kanał AIN0

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Racja, spieszę się trochę do roboty, ale problem mnie zaciekawił. Zobacz jeszcze ten fragment kodu:

       i2c_sclsetport();
...
       if(i2c_sdaget())
       {
           temp++;
           i2c_sclclearport();
       }
   } 

Na linie zegara (SCL) dajesz 0 tylko jeśli odebrałeś 1.

i2c_sclclearport(); powinno być poza if-em

  • Lubię! 1
Link do komentarza
Share on other sites

sabre, masz racje, ale właśnie nawet dla Vrefmax= 5V =Vdd przetwornik pokazuje napięcia dla całego zakresu lecz dalej w sposób jaki wam zaprezentowałem, chodzi mi o to, że nie uzyskuje na wyświetlaczu innych wyników niż 028, 128,192 ... itd, a chciałbym widzieć te zmianę co 1 co jest oczywiste ... napięcie ref. zmieniłem gdyż początkowo myślałem że w tym tkwi błąd ...

Zmierz napięcie na nóżce Vref podczas tego pomiaru, usunąłeś wszystko co jest podłączone do Vref i podłączyłeś do 5V?

  • Lubię! 1
Link do komentarza
Share on other sites

dzięki elvis 🙂 ... pomogles ! ... znalazłeś to czego nie mogłem się dopatrzeć 🙂 ... teraz działa pięknie 🙂

Link do komentarza
Share on other sites

Jak już pomagam, to jeszcze jedna uwaga. Trochę źle obsługujesz i2c. Powinieneś mieć wyjście OC (open-colector). Jeśli procesor go nie ma, to zamiast wystawiać 1 na pin należy przełączać linię w tryb wejścia (zewnętrzny rezystor/pull-up sam ustawi logiczne 1).

Chodzi o to, że jak wystawisz na procesorze 1, a PCF wystawi 0 (np. wysyłając ACK) to powstaje zwarcie. Jeśli wyjście jest OC, to nie ma problemu.

Link do komentarza
Share on other sites

moim założeniem było głównie wykonanie układu bez podciągania zewnętrznych rezystorów a tylko na wewnętrznych, ale zrobiłem tak jak mówisz i dodałem 2x po R4,7K i zaprzestałem podciągania stanu wysokiego wewnętrznymi rezystorami

Link do komentarza
Share on other sites

Witam, mam bardzo podobny problem z pcf8591

otóż podłączenia mam wykonane tak:

Vss-GND

Vdd-VCC

A0-A1-A2-GND

Vref-VCC

AGnd-GND

EXT-GND

SDA i SCL do uP (atmega1280 na sprzętowym TWI)

program, którym odczytuję wartości wygląda tak:

$regfile = "m1280def.dat"
$lib "i2c_twi.lbx"
$crystal = 11059200
$hwstack = 100
$swstack = 120
$framesize = 100
Dim Trf(8) As Byte , Ot As Byte , Incs As Bit , Tmp As Byte

Config Sda = Portd.1
Config Scl = Portd.0
I2cinit
Twbr = 12
Twsr = 0

$lib "glcd.lib"
Config Graphlcd = 240 * 64 , Dataport = Porte , Controlport = Porth , Ce = 0 , Cd = 1 , Wr = 2 , Rd = 3 , Reset = 4 , Fs = 5 , Mode = 6
Cursor Off
Cls
Ot = 0
Incs = 1
Tmp = &B01000000
Tmp = &B00000000
Do
Trf(1) = Tmp
Trf(2) = Ot
Trf(3) = Ot
'I2csend &B10010000 , Trf(1) , 3
Trf(1) = Tmp + 0
Trf(3) = Tmp + 1
Trf(5) = Tmp + 2
Trf(7) = Tmp + 3
I2creceive &B10010000 , Trf(1) , 1 , 2
'I2creceive &B10010000 , Trf(3) , 1 , 2
'I2creceive &B10010000 , Trf(5) , 1 , 2
'I2creceive &B10010000 , Trf(7) , 1 , 2
Locate 1 , 1
Lcd "I0: " ; Trf(2) ; "   "
Locate 2 , 1
Lcd "I1: " ; Trf(4) ; "   "
Locate 3 , 1
Lcd "I2: " ; Trf(6) ; "   "
Locate 4 , 1
Lcd "I3: " ; Trf(8) ; "   "
Locate 6 , 1
Lcd "O0: " ; Ot ; "   "
Waitms 250
If Incs = 1 Then
Incr Ot
If Ot = 255 Then Incs = 0
Else
Decr Ot
If Ot = 0 Then Incs = 1
End If

Loop

interesuje mnie tylko wartość I0

niestety przy regulacji wejścia ain0 potencjometrem 100k wynik na wyświetlaczu "skacze" co 16 (mam wartości: 0, 16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 108, 224, 240). Napięcie na vref wynosi 5V, jest stabilne, układ zasilany z zasilacza stabilizowanego, w obwód przy układzie wpięty między vcc a gnd kondensator ceramiczny 100nF. Dlaczego więc całość nie działa tak jak powinna? testowałem to na dwóch układach i efekt zawsze ten sam...

Z góry dziękuję za pomoc w tej sprawie

Link do komentarza
Share on other sites

nie, nie mam bo korzystam ze sprzętowego TWI, które automatycznie podciąga odpowiednie linie (jeśli bym podpiął rezystory przy TWI to wtedy właśnie magistrala przestałaby działać)

Poza tym przetwornik d/a działa bez zarzutów z pełną rozdzielczością 8-bitów

Link do komentarza
Share on other sites

Nie znalazłem w całym helpie informacji, aby podczas korzystania ze sprzętowego TWI rezystory nie były wymagane, wręcz odwrotnie, gdzieś czytałem, że bez tych rezystorów żadne TWI w bascomie nie ruszy.

Link do komentarza
Share on other sites

programowe i2c owszem, nie ruszy, ale jak ustaliłem doświadczalnie (na zegarze pcf8563 i tym samym uP) sprzętowe TWI przestaje działać po podpięciu rezystorów 4k7, tymczasem programowe i2c wymaga tych rezystorów. Zresztą problem nie tkwi w magistrali raczej, bo inne urządzenia działają na niej bez problemu (m. in. w.w zegar, pamięć eeprom, sterownik LCD)

Jutro jeszcze raz spróbuję dać te pull-upy, bo może ten pcf8591 jest jakiś dziwny, ale mówię wam, że na 90% nie w magistrali problem, bo z tym uporałem się już parę lat temu i co do podciągania linii też dostawałem sprzeczne informacje, dlatego wykonałem doświadczenia, które jednoznacznie określiły co i jak ma działać...

Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.