danrok Opublikowano 29 Maja 2009 Zgłoś Opublikowano 29 Maja 2009 Witam, tym razem mam trochę inny problem. Z przerwaniami timera. Chce napisać program, który co 10ms będzie mi generował przerwanie. Wszedłem więc na stronkę: http://www.et06.dk/atmega_timers/ i wpisałem częstotliwość procesora 1 [MHz] i częstotliwość timera 10 [Hz]. Ustawiłem sobie prescaller na 8 i według tabeli wartość rejestru TCNT1 powinna wynosić: 0x30D4. Po skompilowaniu i przerzuceniu programu do ATmegi przerwania owszem, generują się, lecz ich częstotliwość na oko, wynosi jakieś 2 [Hz]. Nie wiem, czy to jest błąd jakiś? Mógłby ktoś zerknąć? ;************************************************************************;* Program główny *;************************************************************************.INCLUDE "m16def.inc"; dolaczenie biblioteki dla atmega32;deklaracja stalych w programie.EQU K_DIODY = DDRA; rejestr kierunku diody.EQU O_DIODY = PORTA; rejestr wyjscia diody.EQU SYS_FREQ = 1; czestotliwosc pracy procesora.DEF ARG1_1 = R20; argument lewy.DEF ARG1_2 = R21; starszy bit.DEF ARG2_1 = R22; mlodszy bit arg prawego.DEF ARG2_2 = R23; starszy bit.DSEG; DANA w pamięci SRAM.ORG 0x0060; poczatek SRAMKlaw_inf: .BYTE 1; bajtowa zmienna wczytanej liczby.CSEG.ORG 0 jmp Reset; inicjalizacja .ORG INT0addr; przerwanie jmp Odczyt_klawiatury; odczytanie co klikniete.ORG OC0addr; jmp DiodaReset: ;inicjalizacja ldi R17, high(RAMEND); ldi R16, low(RAMEND); out SPH,R17; out SPL,R16; wskaznik stosu ldi R16,0xFF; out K_DIODY,R16; diody w tryb wyjsciowy rcall Ini_klawiatury; inicjalizacja wyswietlacza i klawiatury matrycowej rcall Ini_LCD; clr R16; sts Klaw_inf, R16; sei; odblokowanie przerwan clr ARG1_1 clr ARG1_2 clr ARG2_1 clr ARG2_2 ldi ARG2_1, 1 ldi ARG2_2, 0Petla: ; pętla główna programu lds R16, Klaw_inf; odczyt zmiennej z SRAM sbrs R16, 7rjmp Petla lds R16, Klaw_inf cbr R16, 1<<7 cpi R16, 1 breq Ini_Timer rjmp PetlaIni_Timer: push R16 ldi R17, 1<<CS11 out TCCR1B, R17 ldi R19, 0xD4 out TCNT1L, R19 ldi R19, 0x30 out TCNT1H, R19 ldi R16, 1<<TOV1 out TIFR, R17 ldi R17, 1<<TOIE1 out TIMSK, R17 pop R16rjmp Koniec Dioda: ldi R30, 1 ldi R31, 0 ldi R19,0b11111111 out O_DIODY, R19 ldi R16, 1 rcall Czekaj_ms ldi R19, 0b00000000 out O_DIODY, R19 add ARG1_1, R30 adc ARG1_2, R31; inc ARG1_1; rcall Czysc_LCD; rcall WypiszretiKoniec: lds R16, Klaw_inf sbrc R16,7 rjmp Koniecrjmp Petla.include "wait.inc".include "lcd.inc".include "klawiatura.inc".include "czekaj_us.inc".include "operacje.inc" Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
Gość <account_deleted> Opublikowano 29 Maja 2009 Zgłoś Opublikowano 29 Maja 2009 Na dzień dobry widać 2 błędy: 1. ładujesz do timera wartość 0x30D4 - ok, tyle że trzeba to zrobić w przerwaniu, najlepiej zaraz na początku, żeby utrzymać stałą częstotliwość. Ponadto powinno się tą liczbę skorygować o czas wywołania przerwania, chociaż przy sterowaniu LEDami nie jest to super ważne. 2. powyższe jednak to tylko wierzchołek problemu - podstawowy błąd to nie zapisanie zawrtości rejestru SR oraz innych używanych w przerwaniu - może to całkowicie skaszanić skoki warunkowe, wyniki obliczeń a nawet spowodować zwis programu w tle. Przerwanie w normalnych warunkach ma być niewidoczne - rejestry na stos i z powrotem panie kolego ;) Całkowicie inna sprawa: czy na pewno prawidłowo ustawiłeś "fusy" dla procka? Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
danrok Opublikowano 29 Maja 2009 Zgłoś Opublikowano 29 Maja 2009 (edytowane) Ok, dzięki, zmieniłem troszkę program na taki: ;************************************************************************;* Program główny *;************************************************************************.INCLUDE "m16def.inc"; dolaczenie biblioteki dla atmega32;deklaracja stalych w programie.EQU K_DIODY = DDRA; rejestr kierunku diody.EQU O_DIODY = PORTA; rejestr wyjscia diody.EQU SYS_FREQ = 1; czestotliwosc pracy procesora.DEF ARG1_1 = R20; argument lewy.DEF ARG1_2 = R21; starszy bit.DEF ARG2_1 = R22; mlodszy bit arg prawego.DEF ARG2_2 = R23; starszy bit.DSEG; DANA w pamięci SRAM.ORG 0x0060; poczatek SRAMKlaw_inf: .BYTE 1; bajtowa zmienna wczytanej liczby.CSEG.ORG 0 jmp Reset; inicjalizacja .ORG INT0addr; przerwanie jmp Odczyt_klawiatury; odczytanie co klikniete.ORG OC0addr; jmp DiodaReset:;inicjalizacja ldi R17, high(RAMEND); ldi R16, low(RAMEND); out SPH,R17; out SPL,R16; wskaznik stosu ldi R16,0xFF; out K_DIODY,R16; diody w tryb wyjsciowy rcall Ini_klawiatury; inicjalizacja wyswietlacza i klawiatury matrycowej rcall Ini_LCD; rcall Ini_Timer clr R16; sts Klaw_inf, R16; sei; odblokowanie przerwan clr ARG1_1 clr ARG1_2 clr ARG2_1 clr ARG2_2 ldi ARG2_1, 1 ldi ARG2_2, 0Petla: ; pętla główna programu lds R16, Klaw_inf; odczyt zmiennej z SRAM; sbrs R16, 7rjmp Petla lds R16, Klaw_inf cbr R16, 1<<7 cpi R16, 1 breq Ini_Timer rjmp PetlaIni_Timer: push R16 ldi R17, 1<<CS11 out TCCR1B, R17 ldi R19, 0xD4 out TCNT1L, R19 ldi R19, 0x30 out TCNT1H, R19 ldi R16, 1<<TOV1 out TIFR, R17 ldi R17, 1<<TOIE1 out TIMSK, R17 pop R16ret Dioda: push R16; umieszczanie na stosie zawartości rej. R16, push R17; rejestru R17, push ZL; rejestru R30, push ZH; rejestru R31, in R16, SREG push R16 ldi R30, 1 ldi R31, 0 ldi R19,0b11111111 out O_DIODY, R19 ldi R16, 1 rcall Czekaj_ms ldi R19, 0b00000000 out O_DIODY, R19 add ARG1_1, R30 adc ARG1_2, R31; inc ARG1_1; rcall Czysc_LCD; rcall Wypisz pop R16; ściąganie ze stosu zawartości rej. SREG, out SREG, R16 pop ZH; rejestru R31, pop ZL; rejestru R30, pop R17; rejestru R17, pop R16; oraz rejestru R16 retiKoniec: lds R16, Klaw_inf sbrc R16,7 rjmp Koniecrjmp Petla.include "wait.inc".include "lcd.inc".include "klawiatura.inc".include "czekaj_us.inc".include "operacje.inc" Niewiele to jednak zmieniło, gdyż dalej uzyskuję 2Hz, zamiast 10. EDIT: FUSE jest prawidłowo ustawione. Zgodnie z książką :) Dziwne, po zmianie prescalera na 1 i wpisaniu do TCN1 wartości 0x2710 przerwanie generuje się co 1/10sekundy. Gdy chcę mieć 1kHz, według strony wpisuję 0x3E8, co nie zmienia nic... Może są jakieś ograniczenia, czy coś? Sam nie wiem o co chodzi. Ma ktoś pomysł? Edytowane 29 Maja 2009 przez danrok Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
Gość <account_deleted> Opublikowano 29 Maja 2009 Zgłoś Opublikowano 29 Maja 2009 (edytowane) Jeśli chcesz uzyskać generator określonej cząstotliwości, to trzeba przeładowywać stan licznika w przerwaniu, ponieważ inaczej ciężko przewidzieć ile czasu upłynie pomiędzy kolejnymi update'ami licznika. W tym konkretnym przypadku przerwanie powinno wyglądać jakoś tak: ... in R16, SREG push R16 ldi R19, 0x30 ;ponowne ustawienie czasu do kolejnego przerwania (uwaga: atomic write! ) out TCNT1H, R19 ldi R19, 0xD4 out TCNT1L, R19... pop R16 out SREG, R16...Jeśli ustawiasz timer poza przerwaniem, to może dojść do takiej sytuacji, że zapisujesz 0x30D4 przed wystąpieniem przepełnienia - czyli timer znów liczy od tej wartości i nie generuje przerwania. ;------------------------- Jednak o ile powyższe jest jak najbardziej prawdziwe, to nie jest bezpośrednią przyczyną, znalazłem jeszcze jeden błąd: Używasz Timer1 w trybie Normal, co oznacza, że TOP=0xFFFF. 1/10Hz = 100ms prescaler: 1/8*1000000=125000 T1clk/s 100ms=12500 T1clk TCNT1(100ms) = 0x10000-12500 = 65536-12500 = 53036 -> TCNT1=0xC2FC, natomiast dla 0x30D4 timer odlicza 53036 T1clk, czyli: 1/[(1/125000)*53036] = 2.35688966Hz ! ;) ! tip odnośnie rejestrów: ATmel ma rejestrów pod dostatkiem -> dobrze jest przeznaczyć kilka z nich tylko dla przerwań - dzięki temu nie trzeba wyrzucać ich na stos - szybszy i prostszy kod ;) tip2: polecam także korzystanie z low() & high(), co znacznie ułatwia życie, f.e. : ldi R19, high(53036) ;---- out TCNT1H, R19 ldi R19, low(53036) out TCNT1L, R19 Edytowane 29 Maja 2009 przez tomazzi Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
danrok Opublikowano 30 Maja 2009 Zgłoś Opublikowano 30 Maja 2009 To też nie zdało egzaminu. Ok, napisze jak ja to liczę, może znajdziemy razem błąd: Procesor ma częstotliwość 4MHz. Czyli 4000 000 cykli/sekunde. Wynika z tego, że 1 cykl zajmuje mu 0,25us. Chcę odmierzać czas powiedzmy co 10ms. Czyli 10ms/0,25us = 4 000 i to wstawiam do TCNT1? Aha, prescaler ustawiony na 1:1 powiedzmy, dla ułatwienia. Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
Gość <account_deleted> Opublikowano 30 Maja 2009 Zgłoś Opublikowano 30 Maja 2009 Patrz na przykład wyżej: w trybie Normal Timer liczy w górę, do wartości TOP (0xFFFF). Przerwanie jest generowane na przepełnieniu, czyli gdy TCNT1 zmienia wartość z 0xFFFF na 0x0000. Jeśli więc chcesz wygenerować przerwanie po 4000T1clk, to wpisujesz wartość 0x10000-4000 bo tyle brakuje do przepełnienia ;) Sprawdź program w symulatorze - masz licznik impulsów clk, co pozwola sprawdzić poprawność koniguracji/kodu Niestety nie można wprost zmierzyć aktualnej częstotliwości zegara procesora (jedynie Tiny13 ma taką możliwość) jednak jest prosta metoda pośrednia: piszesz pętle trwającą f.e 10mln imulsów i sygnalizujesz koniec np. zgaszeniem diody. Czas mierzysz stoperem i przeliczasz. Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
danrok Opublikowano 30 Maja 2009 Zgłoś Opublikowano 30 Maja 2009 (edytowane) Ah, fakt fakt ;) Chyba byłem jeszcze zaspany. Dzisiaj spróbuję to wykonać i dam znać jak poszło :) Dzięki z góry:) EDIT: Dzięki, wstawiłem tam tę wartość co obliczyłem i faktycznie jest co 10ms. Muszę dokładniej czytać dokumentację:) Dzięki jeszcze raz @tomazzi. EDIT2: Na następny ogień idzie TWI, albo hmm ... jeszcze coś wymyślę ;) Macie jakieś pomysły na rozwijające programy na zestawie ZL3AVR? ;) Może obsługa RS232? Edytowane 30 Maja 2009 przez danrok Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
Gość <account_deleted> Opublikowano 30 Maja 2009 Zgłoś Opublikowano 30 Maja 2009 TWI/I2C masz sprzętowe - nic ciekawego imo :rolleyes: ciekawsze będzie na pewno 1-Wire (softwareowe) ;) ... tu drobna uwaga: to co można znaleźć np. na elektrodzie to najgorsze z możliwych rozwiązań - cokolwiek byś nie napisał będzie lepsze... btw, poza ekstremalnymi przypadkami funkcje typu wait_ms to marnowanie prądu (bo można położyć procka spać) lub mocy obliczeniowej (bo można w tym czasie zrobić coś innego) - gaszenie i zapalanie diody można zrobić całkowicie na przerwaniach. Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
danrok Opublikowano 30 Maja 2009 Zgłoś Opublikowano 30 Maja 2009 Hmm, no tak, wiem, że to w ogóle nie jest wydajne i tak się nie pisze, ale to pierwsze programy w asm są ;) O tym spaniu procesora już czytałem co nieco. Wydaje się to być użyteczne :) Zastanawia mnie jednak jedna rzecz. Jak fizycznie w procesorze realizowane jest przerwanie? Wszędzie można przeczytać, że to nie obciąża procesora, ale przecież musi on conajmniej porównywać stan licznika z przerwaniem. A co jeśli chodzi o przerwanie zewnętrzne, musi monitorować stan wejścia na tym pinie i to pewnie też zabiera moc obliczeniową. Jak to w końcu jest? Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
Gość <account_deleted> Opublikowano 30 Maja 2009 Zgłoś Opublikowano 30 Maja 2009 Przerwanie jak najbardziej obciąża procesor - przecierz jest wykonywany dodatkowy kod a sam proces generacji zabiera trochę czasu. Istnieje też pojęcie "powodzi przerwań" - IRQ Flood, które oznacza że wykonywane są tylko przerwania np. na skutek awarii hw, błędu w programie itp. Są różne poziomy uśpienia - różne zachowania procka, ale ogólnie patent polega na tym, że wyłączane są niektóre (większość) funkcjonalnych bloków CPU, dzięki czemu zmniejsza się pobór energii ale jednocześnie procek nadal ma możliwość śledzenia tego co się dzieje dookoła. Fizycznie odbywa się to najczęściej poprzez wyłączenie zegara dla określonych bloków CPU - co jest wystarczające, ponieważ bez zegara płyną tylko prądy upływnościowe na poziomie 10^-9A. Dokumentacja do AVR jest dość lakoniczna w tym temacie, ale jest wszysko co potrzeba do napisania softu ;) Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
danrok Opublikowano 31 Maja 2009 Zgłoś Opublikowano 31 Maja 2009 Aha, no dobra, to czytałem o tym trochę, muszę doczytać jeszcze jak to jest z obudzaniem takiego śpiocha. Mam jeszcze jedno pytanie. Mianowicie, czy programy które piszę są w miarę uniwersalne? Tzn czy przeniesienie ich na inną ATmegę, powiedzmy 16, będzie wiązało się z przepisywaniem całości kodu, czy drobnych zmian stylistycznych? Często to jest właśnie wymieniane jako minus języka Assebler? Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
Gość <account_deleted> Opublikowano 31 Maja 2009 Zgłoś Opublikowano 31 Maja 2009 ... czy programy które piszę są w miarę uniwersalne? Tzn czy przeniesienie ich na inną ATmegę, powiedzmy 16, będzie wiązało się z przepisywaniem całości kodu, czy drobnych zmian stylistycznych? Często to jest właśnie wymieniane jako minus języka Assebler?Pozwolę sobie być uszczypliwy: ludzie którzy mówią że assembler jest mało portowalny, nieczytelny czy trudny w debugowaniu to cieniasy, którzy nigdy nic nie napisali w asm, albo jeśli już, to przepisali bez zrozumienia kawałek kodu z książki :lol: Ja napisałem w asm kilka systemów opracyjych, parę modeli matematycznych różnych obiektów i inne takie - jakoś nie narzekam... wręcz przeciwnie. Każdy kod pójdzie na każdym AVR, oczywićsie z uwzględnieniem różnic w dostępnym hw, liście instrukci oraz rozmiarze RAM/Flash/EEprom. Akurat ATmega16 i 32 różnią się o ile pamiętam tylko ilością pamięci - więc nie ma praktycznie żadnych problemów. Aby uczynić źródło maksymalnie uniwersalne należy w części deklaracyjnej stworzyć aliasy także dla zasobów sprzętowych - dzięki temu ew. modyfikacja trwa 10s ;) f.e. zamiast TCNT1 deklarujesz IO_Timer1 (H&L) Każda funkcja powinna mieć lokalne aliasy rejestrów (def/undef) - dzięki czemu jest łatwo portowalna do innego projektu lub do makra. Poza tym właśnie: makrodefinicje - jest to ogromne ułatwienie - można rozszerzać listę "rozkazów" CPU (np. LDIW, PUSHW, DIVU, itp) albo stworzyć zestawik funkcji który pozwoli pisać niemal tak łatwo i szybko jak w Basicu/C. Oprócz tego przy większych projektach przydają się funkcje operujące na predefiniowanych datatype - coś jak new() w C. Każdy programista robi to po swojemu, ale najczęściej wykorzystuje się do tego jeden ze wskaźników (X,Y,Z) + tablicę offsetów. Przykładowy datatajp dla sensora 1-wire - jak jest ich więcej niż 2-4, to jest wręcz niezbędny do życia ;) .dseg.overlap;thermal sensor, 1-Wire.org 0x0000 m1Wts_ID: .byte 1;ID number m1Wts_portPIN: .byte 1;port pin for connection - bit mask m1Wts_snSTATUS: .byte 1;sensor state.equ b1W_sstEnabled =7 ;sensor enabled, link ok.equ b1W_sstIDpass =6 ;sensor passed power-on ID check.equ b1W_sstPresence =5 ;presence pulse ok..equ b1W_sstLinkGND =4 ;data wire grounded: CRC=0 & data=0.equ b1W_sstComFault =3 ;com. fault (CRC or no response from slave).equ b1W_sstUseSubstVal=2 ;when sensor/link permament damage detected use substitute value as 'current reading'.equ b1W_sstPout =1 ;Bus-powered operation request/active;.equ b1W_sstDtaToRcv =0 ;receive data related to cmd - cleared if done m1Wts_CorrOffset: .byte 2;sensor tuning: offset m1Wts_CorrGain: .byte 2;sensor tuning: gain m1Wts_SubstVal: .byte 2;substitute value reported when link or sensor fails m1Wts_ROMID_FC: .byte 1;ROM ID: family code m1Wts_ROMID_SN: .byte 6;ROM ID: serial number m1Wts_ROMID_CRC: .byte 1;ROM ID: CRC m1Wts_spT: .byte 2;scratch pad: Temperature m1Wts_spTH: .byte 1;scratch pad: Thigh alarm thd m1Wts_spTL: .byte 1;scratch pad: Tlow alarm thd m1Wts_spCFG: .byte 1;scratch pad: sensor config shadow m1Wts_spRes: .byte 3;scratch pad: reserve m1Wts_spCRC: .byte 1;scratch pad: scratch pad CRC_1Wts_sizeof: .byte 0.nooverlap ... i w ten sposób próbuję nakłonić Cię do spróbowania 1-Wire :) pozdro. Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
danrok Opublikowano 1 Czerwca 2009 Zgłoś Opublikowano 1 Czerwca 2009 Naprawdę nieźle to wygląda, nie wiem czy sobie poradzę z 1-Wire, ale spróbuję, a jakby coś to będę zakładał milion tematów ;) Masz gdzieś może swoje kody udostępnione? Ciężko mi cokolwiek fajnego znaleźć w necie, żeby poczytać i nabrać takiej wprawy jak powinno się pisać w assemblerze, żeby się nie pogubić. W przypadku kalkulatora tak było, w końcu nie wiedziałem już których rejestrów używam w danej procedurze, których nie, generalnie tragedia. Zauważyłem właśnie, że pisząc sobie procedurki, np do wyświetlenia bajtu na LCD później często gęsto jej używałem, co przypomina mi trochę C :) Długo już programujesz w asm, że takie rzeczy skomplikowane piszesz? ;) Kolejną rzeczą jest, napisałeś, że ATmega32 ma dużo pamięci. Ja podczas pisania kalkulatora korzystałem tylko z rejestrów Rxx, przez co wydało mi się, że tej pamięci ciągle mi brakuje, bo w dwóch rejestrach trzymam ARG1, w dwóch ARG2, jakieś kopie jeszcze itd i zostaje mi kilka rejestrów, a nie wszystkie procedury mogą działać na pełnej palecie rejestrów, dużo z nich na xx>16. Pewnie to przez brak doświadczenia:) Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
Gość <account_deleted> Opublikowano 1 Czerwca 2009 Zgłoś Opublikowano 1 Czerwca 2009 W przypadku kalkulatora tak było, w końcu nie wiedziałem już których rejestrów używam w danej procedurze, których nie, generalnie tragedia. Zauważyłem właśnie, że pisząc sobie procedurki, np do wyświetlenia bajtu na LCD później często gęsto jej używałem, co przypomina mi trochę C :) Kolejną rzeczą jest, napisałeś, że ATmega32 ma dużo pamięci. Ja podczas pisania kalkulatora korzystałem tylko z rejestrów Rxx, przez co wydało mi się, że tej pamięci ciągle mi brakuje, bo w dwóch rejestrach trzymam ARG1, w dwóch ARG2, jakieś kopie jeszcze itd i zostaje mi kilka rejestrów, a nie wszystkie procedury mogą działać na pełnej palecie rejestrów, dużo z nich na xx>16. Czyste C to tak na prawdę asm, w którym wszystkio zostało zastąpine aliasami ;) Dopiero takie rozwinięcia jak klasy dają absurdalny poziom abstrakcji :lol: Ale co innego chciałem powiedzieć: używaj symboli/aliasów gdzie się da - i nie żałuj literek - nazwy powinny być jasne i najlepiej "strukturalne" np. w poprzednim datatajpie są takie prefixy: m1Wts = memory+1-wire+thermal_sensor, b1Wts=bit+..., r1Wts oznaczałoby rejestr, c=constant (stała -> daje to dużą przejrzystość i łatwo zapamiętać. rcall to nic innego jak wywołanie funkcji w C - compilatory C robią dokładnie to samo, tylko trochę śmiecia dodają od siebie przez co jest gorzej. Rejestry to poprostu zmienne - ponieważ ich ilość jest skończona (32) to w przypadku większych projektów trzeba poprostu zrzucać ich zawartość do RAMu (albo na stos - zależnie od konkretnej sytuacji) Zrzucenie rejestru do RAM to banał (sts, std, push) znacznie ważniejsze jest jasne zdefiniowanie struktur do przechowywania danych, dzięki czemu odwołujesz się do nich poprzez nazwy symboliczne: np: LOAD Z,first_1W_sensor ;(load to macro, z=adres bazowy struktury w RAM) ldd tmp,z+m1Wts_ROMID_FC ;(tmp= jakiś rejestr lokalny w funkcji, adresowanie pośrednie: Z-pointer + offset ) ps. kodów nigdzie nie udostępniam, ale jak będziesz potrzebował, to pomogę ;) Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...
danrok Opublikowano 1 Czerwca 2009 Zgłoś Opublikowano 1 Czerwca 2009 No dobra, dzięki wielkie ;) Szkoda, że nie udostępniasz kodów, bo bym podpatrzył :) Co do 1-Wire to zabiorę się jak tylko skończe sesję :) Czyli w czwartek :) Pozdrawiam ;) Cytuj Udostępnij tę odpowiedź Odnośnik do odpowiedzi Udostępnij na innych stronach Więcej opcji udostępniania...