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.
administrator: přejmenováno z "ATMega32 a DS18x20"
// 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?
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))
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.
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.