ATMega32 a DS18x20 - sháním funkční příklad včetně zapojení

Ahoj všem,

Už si vážně nevím rady, jak dál postupovat. Řeším propojení Atmega32 v DIP40 s teplotním čidlem DS18x20. Zkusil jsem snad vše, včetně skvělého dema od Martina Thomase, ale ne a ne to rozchodit. Čidla se mi vůbec nedetekují. Zkusil jsem:

  • různé porty na MCU

  • různé frekvence

  • 1 a více čidel na lince

  • pul lup rezistory pro čidlo externí i interní

  • DS18b20 i DS18s20 (rozdílné časování)

  • parazitní i externí napájení

    Nemám osciloskop, ale částečně ověřeno zapojení voltmetrem (jen zapojení, průběhy samozřejmě ne). Vše jsem zkusil v různých kombinacích, procesor žije (bliká mi ledka a odesílá se komunikace přes USART do počítače). Samotný MCU je v pořádku, čidla jsou také v pořádku (ověřeno digitempem pro PC). Už netuším, co by ještě mohlo být blbě, prošel jsem ručně hodnoty časování, využívám knihovnu delay, zkusil jsem různé optimalizace kódu, různá dema, programy apod. Ale prostě výsledek nula, čidlo se nedetekuje. Používám GCC a WinAVR.

Chci se proto zeptat, zda:

  • můžete ještě někdo něco jiného poradit, co bych mohl zkusit

  • zda nemáte funkční příklad včetně zapojení, nad kterým bych měl jistotu, že to opravdu někomu funguje.

    Díky.

:arrow_right: administrator: přejmenováno z "ATMega32 a DS18x20"

Čau, používam sice CV, ale snad ti to pomůže. Vše je v tom zipu :wink:
tep.zip (158 KB)

Díky, podívám se na to.

Tak to mi bohužel taky nefunguje. Ještě jsem našel toto, a to taky ne:(

[code]#define TX DDRA |= PA0;
#define RX DDRA &= ~PA0;
#define RXPIN PINA&PA0

// provede reset a test prezence ds-18b20 na sbernici
unsigned char ow_detect_presence(void) {
unsigned char out=1; // vychozi navratova hodnota
RX; // vychozi stav sbernice
_delay_us(1000); // pro ustaleni
TX; // bus low
_delay_us(480); // cas pro prikaz reset
RX; // uvolneni sbernice
_delay_us(70); // cekani na potvrzeni teplomerem
if(RXPIN) out=0; // pokud detekovana log.1, tak teplomer na sbernici neni
_delay_us(410); // pauza pred dalsi komunikaci
return out; // vrati stav 1=teplomer nalezen, 0=teplomer nenalezen
}

// posle na sbernici log.1
void ow_write_one(void) {
TX; // bus low
_delay_us(6); // pauza definujici log.1
RX; // uvolneni sbernice
_delay_us(64); // pauza pred dalsi komunikaci
}

// posle na sbernici log.0
void ow_write_zero(void) {
TX; // bus low
_delay_us(60); // pauza definujici log.0
RX; // uvolneni sbernice
_delay_us(10); // pauza pred dalsi komunikaci
}

// precte jeden bit ze sbernice
unsigned char ow_read_bit(void) {
unsigned char out=0; // vychozi navratova hodnota bitu
TX; // bus low
_delay_us(6); // pauza pro stav cteni
RX; // uvolneni sbernice
_delay_us(9); // pauza pro reakci teplomeru
if(RXPIN) out=1; // test stavu sbernice, vlastni cteni
_delay_us(55); // pauza pred dalsi komunikaci
return out; // prectena hodnota, 1 nebo 0
}

// odeslne na sbernici jeden byte. Odesila se prvni LSB
void ow_write_byte(unsigned char tosend) {
int n=8;
while(n–) {
if(tosend&1) ow_write_one(); else ow_write_zero();
tosend >>= 1;
}
}

// prijde ze sbernice jeden byte. Prijima jako prvni LSB.
unsigned char ow_read_byte(void) {
int n=8, out=0;
while(n–) {
out >>= 1; // bitovy posuv doprava
if(ow_read_bit()) out |= 0x80; // nastaveni nejvyssiho bitu na 1
}
return out;
}

// nacte teplotu z teplomeru a vrati ji ve formatu 1000+t*10
// priklad: 23.5°C = 1235, -10.5°C = 895
// tento format lze snadneji zpracovavat nez nejake floaty (zerou moc pameti)
unsigned int zmer(void) {
unsigned char data_lo, data_hi, desetiny;
signed char teplota;
unsigned int tmp = 0;
cli();
ow_detect_presence();
ow_write_byte(0xCC);
ow_write_byte(0x44);
_delay_ms(700);
ow_detect_presence();
ow_write_byte(0xCC);
ow_write_byte(0xBE);
data_lo=ow_read_byte(); // 1. byte scratchpadu teplomeru = spodni byte teploty
data_hi=ow_read_byte(); // 2. byte scratchpadu teplomeru = horni byte teploty
teplota = (data_lo & 0x0F0) >> 4 | (data_hi & 0x0F) << 4 ; // signed teplota
tmp = 10 * teplota + 1000;
desetiny = (data_lo & 0x0F) * 0.625;
if(tmp<1000) tmp -= desetiny; else tmp += desetiny;
if((tmp<700)||(tmp>2200)) tmp=0;
sei();
return tmp+28;
}[/code]

Nechápu, nyní jsem změnil pin na PD6 a ono to začalo fungovat!!! Jsem si jist, že jsem to řpedtím také zkoušel a nešlo to. Nicméně, je to nadějné. PORTA je v nějakém zvláštním režimu u atmega32?

Co je to tam na koci za šílenosti? Čidlo vrací přímo teplotu ve formátu int, jen 16x větší.
int tt = (scratchpad[1] << 8 ) | scratchpad[0];
viz. toto téma: https://forum.mcontrollers.com/t/multiplexovany-vystup-na-displej/167/1

to byl jen příklad, který jsem někde našel, práci s teplotou budu mít řešenou zcela jinak. Proč kruciš ale nefunguje ten porta? Nemusí se ještě něco přepnout, aby fungoval jako I/O? V Datasheetu jsem nic takového nenašel.

Na PORTA není nic, co by mělo bránit funkčnosti. Bit v PORTx musí být pro 1wire komunikaci v “0”. To je po resetu, ale program to může změnit. Pro jistotu na začátek přidej (PORTA &= ~(1<<PA0); )
Definice#define TX DDRA |= PA0; #define RX DDRA &= ~PA0; #define RXPIN PINA&PA0jsou samozřejmě blbě a fungují POUZE pro bit 0 (PA0, PB0…)
Edit: blbě, nefunguje to ani pro bity 0.
Správně to má být#define TX DDRA |= (1<<PA0) // bez středníků a se shiftem #define RX DDRA &= ~(1<<PA0) #define RXPIN (PINA & (1<<PA0))

Zkusím, díky. Nicméěn stejná konstrukce mi pro PD6 funguje. V prg se s portem A nijak nepracuje.

To tedy nechápu, jak to může pro PD6 pracovat.
Jelikož je PD6 definováno jako: #define PD6 6
tak po provedení DDRD |= PD6; je hodnota DDRD ORována s číslem šest, tedy výsledek je 0byyyyy11y, kde “y” je předchozí stav registru. Jinými slovy, jako výstupy jsou piny PD1 a PD2 (a případně některé další dle předchozího stavu). S pinem PD6 se neděje vůbec nic.

nemělo by být PD6 definováno jako 0x40?

Ve WinAVR není. Stačí se podívat do definičního soubou procesoru (najdeš ho v “external dependencies”).

to se podívám. ale ani to by to chování nevysvětlilo, chjo chjo…

funguje to, skvělé! díky.

Ahoj, když jsem zkoušel tento kód uvedený v Zaslal: 09 březen 2011, 1:07 , tak vrací teplotu jako by ob jednu zpětně. Tj. první změř vrátí nic/85, druhé vrátí to, co bylo v okamžiku předchozího volání změř atd… Přišel jsem na to náhodou - zahřál čidlo a měl jsem tam stejnou teplotu, jako předtím. Po delší době (minuta něco) jsem provedl další měření a byla tam ta vyšší teplota. Může mi někdo poradit, co je blbě? Díky.