Forum Elektronika
audio radio telewizja cyfrówka okablowanie

∑ temat został odczytany 2153 razy ¬


ZAREJESTRUJ SIĘ I ZALOGUJ NA FORUM, TO NIC NIE KOSZTUJE!
PO ZALOGOWANIU BĘDZIESZ MÓGŁ ZOBACZYĆ WYPOWIEDZI SPECJALISTÓW I WYŁĄCZYĆ REKLAMY

ELEKTRONIKA | Różne
Czujnik temp. program, szyna I2C, problemy... 
Wyślij odpowiedź [powiadom znajomego]    
Autor "Czujnik temp. program, szyna I2C, problemy..."   
 
cristof_w
 Wysłana - 25 maj 2007 20:45        | zgłoś naruszenie regulaminu

Witam. Już od pewnego czasu męczę się z czujnikiem temperatury przez I2C.Program składa się z 3 głównych rzeczy:
obsługa wyswietlacza LCD, obsługa I2C i funkcja wyświetlająca "na zrozumiały tekst" temperaturę na wyświetlaczu. czy jest tutaj ktoś kto mógłby "żucić" na to okiem i fachowo ocenić? Może nawet dałby radę pomóc i doprowadzić program do końcowej realizacji. Jeżeli tak, to wtedy chętnie zapodam kod źródłowy. Zaznaczam, że cały czas się uczę C i mam z tym jeszcze sporo problemów wciąż.Pozdrawiam.

______________________________
 
Cristof

 
el_bart
 Wysłana - 25 maj 2007 21:07      [zgłoszenie naruszenia]

trzeba bylo od razu kod wstawic - jak ktos bedzie wiedzial, to pomoze. :)

C znam raczej dosc dobrze ale na PC - na uC (8051 konkretnie) tylko liznalem. w kazdym razie wstawiaj kod - bedziemy myslec. :)

Zmieniony przez - el_bart w dniu 2007-05-25 21:08:39
_______________________________
 
[baszerr.org]

 
cristof_w
 Wysłana - 26 maj 2007 06:16      [zgłoszenie naruszenia]

To gitara :) Siedzę nad tym już sporo i nic...poprostu nie mam głowy do C, a chciałbym...Dzięki el_bart za odpowiedź, kiedyś już raz mnie pomogłeś, może teraz też dasz radę :) Teraz szczegóły...wyświetlacz LCD 2x16, czujnik temperatury mcp9801/9801, szyna I2C. Program można podzielić na 3 etapy: obsługa wyświetlacza LCD(sprawdzone oddzielnie, działa),obsługa szyny I2C (pisałem na podstawie not aplikacyjnych, nie mam 100% pewności czy jest dobrze) i funkcja przekonwertująca na "zrozumiały język" z I2C na wyświetlacz LCD (tego nie pisałem osobiście i nie rozumiem tego w 100%). Problem jet w tym, że nie działa, cały czas wyświetla się 0Stopni (na LCD). I teraz nie wiem...czy sknociłem coś w I2C czy też znajomy pomieszał coś w tej funkcji wyświetlajacej temperaturę. Moje umiejętności z C nie potrafią tego stwierdzić...mam nadzieję, że program jest w miarę czytelny. Będę bardzo wdzięczny jeżeli ktoś spróbuje rozwikłać ten problem. Co więcej, może macie jakieś pomysły odnośnie dobrej literatury do tego?
Pozdrawiam.
#include <8051.h> // kwarc 6 MHz srodowisko M-IDE programator ISPPROG
#include <stdio.h>

// definiowanie portow wyswietlacza LCD
#define PORT P1 //deklaracja portu
#define RS P1_2 //deklaracja bitow sterujacych
#define E P1_3

// definiowanie porotw I2C
#define SDA P0_0 // definiowanie sygnalow
#define SCL P0_1 // polaczenia I2C

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//LCD
void Delay2(unsigned int k)
{
unsigned int i,j;
for (j=0;j<k;j++)
for (i=0; i<=296;i++);
}


void WriteToLcd(char X) //zapis bajtu do LCD
{ //schemat kasiazkowy
E = 1;
PORT /= 0xF0;
PORT &= (X / 0x0F);
E = 0;
E = 1;
X <<= 4;
PORT /= 0xF0;
PORT &= (X / 0x0F);
E = 0;
Delay2(1);
}

void WriteCommand(char X) //zapis bajtu do rejestru
{
RS = 0;
WriteToLcd(X);
}

void WriteChar(char X)
{
RS = 1;
/*E = 1; */
WriteToLcd(X);
}

void LcdClrScr(void) //czyszczenie ekranu
{
WriteCommand(0x01);
}


void LcdInit(void) //inicjalizacja w trybie 4 bity
{ //schemat ksiazkowy
char i;
Delay2(15);
PORT = 0x0F;
for (i = 0; i<3; i++)
{
E = 1;
PORT &= 0x3F;
E = 0;
Delay2(5);
}
E = 1;
PORT &= 0x2F;
E = 0;
Delay2(1);
WriteCommand(0x28);
WriteCommand(0x08);
WriteCommand(0x01);
WriteCommand(0x06);
WriteCommand(0x0C);
}

void WriteText(char *S)//wyswietla tekst
{ //od aktualnego polozenia kursora
while(*S)
{
WriteChar(*S);
S++;
}
}

////////////////////////////////////////////////////////////////////////////////////////////////
// wyswietlenie znak pod adres
void lcd_wysw(unsigned char adres,unsigned char d)
{
WriteCommand(adres / 0x80);
WriteChar(d);
}

// wyswietlenie ciagu pod adres
void lcd_ciag(unsigned char adres,unsigned char ilosc,char *ciag)
{
unsigned char i =0;
WriteCommand(adres / 0x80);
for ( i =0 ; i < ilosc; i++)
{
WriteChar(ciag );
}
}

// wyswietlenie inta do maks 9999 tekstowo
void lcd_wyswint(unsigned char adres,unsigned int liczba)
{
unsigned int i;

if (liczba > 9999) i = 9999;
else i = liczba;

WriteCommand(adres / 0x80);

if (liczba > 999)
{
WriteChar((unsigned char)(i / 1000) / 0x30);
i = i % (unsigned int)(1000);
}
else WriteChar(' ');
if (liczba > 99)
{
WriteChar((unsigned char)(i / 100) / 0x30);
i = i % (unsigned int)(100);
}
else WriteChar(' ');
if (liczba > 9)
{
WriteChar((unsigned char)(i / 10) / 0x30);
i = i % (unsigned int)(10);
}
else WriteChar(' ');

// tu trzeba by dodac wyswietlanie kropki chyba
WriteChar((unsigned char)(i & 0x0f) / 0x30);
}


////////////////////////////////////////////////////////////////////////////////////////////////////////

//I2C
void Delay(unsigned int k)
{
unsigned int i,j;
for (j=0;j<k;j++)
for (i=0; i<=296;i++);
}


//start
void Start(void)
{
SDA=1;
SCL=1;
Delay(1);
SDA=0;
Delay(1);
SCL=0;
}

//stop
bit Stop(void)
{
SDA=0;
Delay(1);
SCL=1;
Delay(1);
SDA=1;
Delay(1);
return (~SDA);

}

//Odczyt bajtu z magistrali I2C
unsigned char I2C_Read(bit ack)
{
unsigned char bitCount=8,temp;

SDA=1;
do
{
Delay(1);
SCL=1;
Delay(1);
temp<<=1;
if (SDA) temp++;
SCL=0;
} while(--bitCount);
SDA=ack;
Delay(1);
SCL=1;
Delay(1);
SCL=0;
return (temp);
}

//Wysylanie slowa na magistrale I2C
bit I2C_Send(unsigned char byte)
{
unsigned char bitCount=9;
bit temp;

do
{
SCL=0;
SDA=byte & 0x80;

byte = (byte<<1) +1;
Delay(1);
SCL=1;
Delay(1);
} while(--bitCount);

temp=SDA;
SCL=0;
return (temp);
}


// funkcja do odczytu temeperatury - chyba lepiej bo wtedy latwiej w mainie to umiesci
unsigned int i2c_tempodczyt(void)
{
unsigned char lsb, msb;
unsigned int i;

Start();
I2C_Send(0x92);
I2C_Send(0x00);
Start();
I2C_Send(0x93);
lsb = I2C_Read(0);
msb= I2C_Read(1);
Stop();
i = (unsigned int)(msb);
i *= (unsigned int)(256);
i += (unsigned int)(lsb);
return i;

}





/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void main(void) //program glowny
{
unsigned long l;
unsigned int i;
bit znak;

//LCD
LcdInit();



while (1)
{
// glowna petla programu


i = i2c_tempodczyt();

// sprawdzanie znaku odczytanej wartosci ( najstarszy bit = 1 to wartosc
//ujemna
if (i & 0x8000)
{
// jest minus
znak = 1; // ustawia znak ze jest minus
// obliczenie moduly z wartosci ujemnej w u2 ( negacja i zwiekszenie o
//jeden )
i ^= 0x7fff;
i += 1;
} else znak = 0;

l = (unsigned long)(i);

// - to gdy dokladnosc do 0,1 stopnia tylko wtedy trzeba bu dodac do
//wyswietlania zeby wstawial kropke przed ostatnia liczba
/*
l = (unsigned long)(i) * 10UL;
*/

l /= (unsigned long)(256);
if (l > 9999ul ) l = 9999ul ;
//else i = (unsigned int)(l);

// wyswietla znak
if (znak) lcd_wysw(1,'-');
else lcd_wysw(1,' ');
// wyswietla liczbe
lcd_wyswint(2,(unsigned int)(l));
WriteText("Stopni");
Delay2(50);



}


}




_______________________________
 
Cristof

 
el_bart
 Wysłana - 26 maj 2007 10:43      [zgłoszenie naruszenia]

no coz - kompilatora w glowie nie mam a kod zawiera sporo szczegolow sprzetowych (a schematu tez nie posaidam ;)).

na pierwsze spojrzenie nie podobaja mi sie f-cje odpowiadajace za oczekiwanie (btw: jaka jest roznica miedzy Delay() a Delay2() ?). zauwaz, ze 8051 to maszyna 8-bitowa! jezeli wiec pracujesz na wartosciach>8-bitow (int) to oznacza, ze kompilator musi to przetlumaczyc na jakas wewnetrzna reprentacje i kazde dodwanie, odejmowanie, etc zajmuje n-cyki zegarowych. tutaj (przy wyliczaniu opoznien) wazne sa 2 rzeczy:
1) jakim kwarcem taktujesz uklad?
2) czy '51 ktorej uzywasz potrzebuje 12 cykli zegara na 1 cykl maszynowy, czy mniej?
dlatego wlasnie pisalem, ze prawdopodobnie masz problem z odliczaniem czasu. sprobuj zrobic eksperyment: uzywajac f-cji Delay() ustaw opoznienie na np: 2-3 sekundy i niech uklad mruga jakas lampka co ten ustalony czas i ze stoperem sprawdz, czy rzeczywiscie trwa to tyle ile powinno - jezeli gdzies sie walnales to wyjdzie tutaj (np: dostaniesz mruganie co 4,8,10 sekund...).
jeszcze 4 :) uwagi do czasu:
1) jak potrzebujesz miec pewnosc, ze kawalek kodu wykona sie w okreslonym czasie to praktycznie wylacznie asembler - C sie tu nie sprawdza...
2) sprawdz czy przypadkiem srodowisko, w ktorym piszesz nie udostepnia f-cji do opoznien (nie wiem czy sie to nazywalo przypadkiem delay()...) - to jest typowy problem przy pisaniu kodu wiec jest malo prawdopodobne, zeby nie bylo tego w zadnej bibliotece.
3) kiedys robilem sterownik na uC do serw - po 3 dniach debugowania i experymentowania okazalo sie, ze kwarc jest uszkodzony i daje jakies z dupy wziete taktowanie - sprawdz i to, bo glupie bledy sa najtrudniejsze do zauwazenia!
4) moze warto zastanowic sie nad wykorzystaniem timer'ow?

kolejna sprawa: uzywasz czesto dzielenia calkowito liczbowego na zmiennych bajtowych, dzielac je przez dosc duze wartosci (np: 0xF0) - efektem tego moze byc w zasadzie tylko 0 albo 1. nie wiem czy zawsze o to Ci chodzilo.

w kodzie pojawia sie tez masa pohardcodowanych wartosci. poniewaz to jest uzadzenie wbudowane, nie ma co szalec z podprocedurami, ale zwykle makro:
#define ADDRESS2BLABLA(add) ((add)/0x0F) // konewrtuje podany adres do postaci blabla
...
adresik=ADDRESS2BLABLA(adresik);
bedzie o stokroc czytelniejsze niz:
add/=0x0F;
z jakas magiczna wartoscia w srodq, zas efektywnsc identyczna.

uwazaj tez z konstrukcjami postaci:
(unsigned char)(i / 1000) / 0x30
z kompilatorami roznie bywa - moze sie zdazyc, ze jeden najpierw podzieli a potem calosc przekonwertuje na uchar'a a drugi moze zrobic odwrotnie. jak cos jest nie pewne, lub malo czytelne zawsze lepiej dodac nawias:
(unsigned char)( (i / 1000) / 0x30 )
i sprawa jest jasna a kompilator ma jednoznacznie powiedziane co ma z tym zrobic.

czytelnosc jest naprawde wazna. porownaj:
unsigned int i2c_tempodczyt(void)
{
unsigned char lsb, msb;
unsigned int i;

Start();
I2C_Send(0x92);
I2C_Send(0x00);
Start();
I2C_Send(0x93);
lsb = I2C_Read(0);
msb= I2C_Read(1);
Stop();
i = (unsigned int)(msb);
i *= (unsigned int)(256);
i += (unsigned int)(lsb);
return i;

}

z czyms takim:
#define I2C_CMD_COSTAM1 0x92
#define I2C_CMD_COSTAM2 0x00
#define I2C_CMD_COSTAM3 0x93
#define I2C_NO_ACK 0
#define I2C_SEND_ACK 1
unsigned int i2c_read_temp(void)
{
unsigned char lsb, msb;

// switch to initial state (czy tez co innego to robi w przypadku tego czujnika)
i2c_begin();
i2c_send(I2C_CMD_COSTAM1);
i2c_send(I2C_CMD_COSTAM2);
// send temp. read request (j/w)
i2c_begin();
i2c_send(I2C_CMD_COSTAM3);
// read temperature (2 bytes)
lsb = i2c_read(I2C_NO_ACK);
msb = i2c_read(I2C_SEND_ACK);
// signal end of transmition
i2c_end();

// return result:
return msb*256+lsb;
}

komentarze i stale to nie ozdobniki - to sie poprostu lepiej czyta i widac od razu co to robi - nie trzeba sie zastanawiac nad szczegolami: liczy sie koncept.

no - to chyba bedzie tyle. ;) daj znac, jak Ci poszly experymenty z czasem i postaraj sie ten kod doprowadzic do pozadq - bedzie Ci wtedy latwiej bledy znajdowac. :)
_______________________________
 
[baszerr.org]

 
cristof_w
 Wysłana - 27 maj 2007 21:26      [zgłoszenie naruszenia]

No witam. Właśnie wszystko odczytałem. Teraz będę analizować i zobaczymy co z tego będzie. Napewno dam znać, będę eksperymentować. Dziękuję. Pozdrawiam.
_______________________________
 
Cristof

 
el_bart
 Wysłana - 28 maj 2007 08:54      [zgłoszenie naruszenia]

no wiec powodzenia i czekamy na wyniki. :)
_______________________________
 
[baszerr.org]

 
cristof_w
 Wysłana - 28 maj 2007 16:55      [zgłoszenie naruszenia]

Więc wziąłem się do poprawek i dalszej kombinacji. Według Twoich sugestii zacząłem od funkcji Delay.
I tak.
Funkcji Delay() w programie, którego kod źródłowy powyżej przedstawiłem, jest wykorzystywana do wyświetlacza LCD. Nie wiem tylko, nigdzie nie mogę doczytać, jak długie ma być to opóźnienie.
Jednakże napotkałem pewien problem przy wyliczeniach.Chcę to zrobić przy użyciu Timera. Ale po kolei...
W tym projekcie używam kwarcu 6Mhz. W innym używałem 11.0592 MHz i nie miałem żadnych problemów z wyliczeniami.
Dla kwarcu 11.0592 MHz (timer 16 bitowy jest):
Najdłuższy odmierzany czas to : (12*65536)/11.0592 co daje 0.071s.
częstotliwość wynikająca z wewnętrznego podziału i będąca podstawą do wyznaczenia cyklu maszynowego to : 11.0592Mhz/12 co daje 921600.
Jezeli 921600 podziele przez np. 46080 to uzyskam 20Hz co daje 0,05 sekundy, co bardzo się przydaje przy do późniejszego odmierzania czasu.
następnie wartość 46080 zamieniam na szesnastkową co daje B400 i od FFFF odejmuje B400, uzyskując przy tym 4BFF. wartość 0x4B później używam przy Timerze a wartość 0,05s służy jako podstawa do odpowiedniego dobierania czasu, jakiego potrzeba (opóxnienia czyli Delay).
Jednakże w żadne sposób nie mogę, używając tego samego toku myślenia, postąpić w przypadku kwarcu 6Mhz, gdyż odmierzany czas to (12*65536)/6Mhz co daje 0.131 sekundy iw żadne sposób nie mogę dobrać tak czestotliwości abym mógl ją przemnażac, gdyż zawsze wychdzoi poza TIMER , po zamianie na szesnastkowy kod zawsze jest przepełenienie.
Np.
6Mhz/12= 500000
I teraz trzeba dobrać taką częstotliwość, żeby móc ją póxniej przemnażać.
Wynik z dzielenia zaminić na szesnastkowy i odjąć od FFFF.
Mam nadzieję, że udało mnie się wyjaśnić w czym tkwi problem. I nie wiem kurcze jak sobie z tym poradzić.
P.S.
Dla kwarcu 11.0592 didoa świeci tak jak powinna. Pozdrawiam.

_______________________________
 
Cristof

 
cristof_w
 Wysłana - 29 maj 2007 08:31      [zgłoszenie naruszenia]

Namieszałem...sprostowanie.
Da się :) tylko trzeba z rana trzeźwioej myśleć :)
Więc tak:
kwarc 6Mhz, najdłuższy odliczany czas to 12*65536/6Mhz to 0,131 s
Częstotliwość wynikająca z wewnętrznego podziału to : 6Mhz/12 = 500000
Jeżel ipodziele to przez 50000 ( amoge, gdyz pojemność timera przekracza tę wartość) to wtedy uzyskam 10Hz, czyli 0,1 sekundy. Zamieniam liczbę 50000 na szesnastkową i otrzymuję C350. Od wartoości FFFF odejmuję tę wartość i otrzymuję wtedy wartość 3CAF, co wpisuję do rejestra Timerów.
Czyli wszystko dobrze i wszystko się zgadza...a nie działa prawidłwoo, walnięty kwarc?
A oto testowy kawałek programu:

#include <8051.h>
#include <stdio.h>

#define PortLED P2_5

void Delay (unsigned int time)
{
unsigned char i;
for (i=0; i<10; i++) //10 oznacza 1 sekunde, 10*0.1

{
TH1 = 0x3CAF;
TL0 = 0;
TR1 = 1;
while (!TF1);

TF1 = 0;
}
TR1 = 0;
}
void Delay2 (unsigned int tim)
{
unsigned char j;
for (j=0; j<50; j++) //50 oznacza 5 sekund, 50*0.01

{
TH1 = 0x3CAF;
TL0 = 0;
TR1 = 1;
while (!TF1);

TF1 = 0;
}
TR1 = 0;
}

void main(void)
{
TMOD = 0x10;

while (1)
{
PortLED = 1;
Delay(1);
PortLED = 0;
Delay2(1);
}
}

Jakieś sugestie? :)
Pozdrawiam.

Edit:
Działa, ale gdy wstawie do rejstru wartość C350 zamiast 3CAF. Jak można to wytłumaczyć?
No ale grunt, że działa. teraz pytanie tylko, jak duże powinno być takie opóźnienie w programie ? Nie wiem tego i nigdize nie potrafię tego doczytać.
Zmieniony przez - cristof_w w dniu 2007-05-29 08:32:43

Zmieniony przez - cristof_w w dniu 2007-05-29 08:38:04
_______________________________
 
Cristof

 
el_bart
 Wysłana - 29 maj 2007 20:34      [zgłoszenie naruszenia]

a czy wpisywanie nie powinno wygladac tak:
TH1 = 0x3C;
TL1 = 0xAF;
?
ogolnie Twoj tok rozumowania jest poprawny - pewnie masz jakis glupi blad. sprawdz dokladnie, jaki tryb pracy ustawiles timerowi (moze 13-bitowy?), etc...

btw: w obu f-cjach Delay masz ten sam kod powielony - jak trafia Ci sie koniecznosc "copy&paste" to prawie na pewno trzeba nie co przeorganizowac kod.

co do samego I2C, to niestety nie pomoge Ci - nie mam w tej chwili czasu przedzierac sie przez specyfikacje (choc jest to dobrze opisane w paru ksiazkach) a nie znam jej na pamieci... ;)
_______________________________
 
[baszerr.org]

 
cristof_w
 Wysłana - 29 maj 2007 21:05      [zgłoszenie naruszenia]

Więc tak. Timer jest 16-bitowy na pewno, świadczy o tym
TMOD=0x10;
Natomiast chyba jest błąd tutaj:
TL0=0; powinno chyba być raczej TL1=0;
Chwilowo tego nie sprawdzę, mały problem sprzętowy, mój własnej roboty układ dydaktyczny odmówił współpracy, szukam przyczyny, pewnie się skubany wkurzył, że tak go ostatnio wykorzystuje dużo :)))
I jeszcze jedno.zakładając, że dojdę do ładu z tymi opóźnienieami, to jakie musi być to opóxnienie, wykorzystywnae tutaj np. przy LCD? Kilka milisekund?
Pozdrawiam.


_______________________________
 
Cristof

 
cristof_w
 Wysłana - 29 maj 2007 21:05      [zgłoszenie naruszenia]

Więc tak. Timer jest 16-bitowy na pewno, świadczy o tym
TMOD=0x10;
Natomiast chyba jest błąd tutaj:
TL0=0; powinno chyba być raczej TL1=0;
Chwilowo tego nie sprawdzę, mały problem sprzętowy, mój własnej roboty układ dydaktyczny odmówił współpracy, szukam przyczyny, pewnie się skubany wkurzył, że tak go ostatnio wykorzystuje dużo :)))
I jeszcze jedno.zakładając, że dojdę do ładu z tymi opóźnienieami, to jakie musi być to opóxnienie, wykorzystywnae tutaj np. przy LCD? Kilka milisekund?
Pozdrawiam.


_______________________________
 
Cristof

[Powiadom mnie, jeśli ktoś odpowie na ten artykuł.]


Odpowiedzi jest na 2 strony.   | następną
 
Wybierz stronę:  
Przegląd tygodnia | Wyślij odpowiedź

Czujnik temp. program, szyna I2C, problemy...

Strony: 1 2
 

 
Polecamy: urządzenia spawalnicze | MŚ w Piłce Nożnej - RPA 2010 | Forum | Komputery | Nauka | pomysł na biznes

wersja lo-fi


Pozycjonowanie i optymalizacje zapewnia Agencja Interaktywna

Copyright 2000 - 2010 KULTURYSTYKA.PL
 
Powered by Pazdan ForKat 4.0