Witam
Temat być może pojawia się po raz wtóry, ale poprzednie tematy nie rozwiązały problemu.
Chcę wykonać prosty zegarek cyfrowy oparty na uC ATMEGA8(L) oraz wyświetlaczu LCD 2x24.
Wszystko chodzi bez zarzutów, gdyby nie fakt złego odliczania czasu przez mój uC.
Otóż mój ATMEGA8 pracuje z kwarcem zewnętrznym 8MHz + dwa kondensatory ceramiczne 22pF (zostały poprawnie zmienione bity CKSEL 3 ... 1 oraz SUT 1, 0 w Fuse Bits).
Dotychczas uC pracował na wewnętrznym oscylatorze 1MHz, gdzie również źle odmierzał czas za pomocą poniższej funkcji, lecz w poprzednich moich programach na uC nie miało to takiego znaczenia; teraz ma
.
Oto dotychczasowy kod na opóźnianie (odliczanie czasu):
Mimo, że z kodu wynika że dioda LED powinna mrugać co jedną sekundę (czas zapalenia diody LED również wynosi jedną sekundę), w rzeczywistości dioda mruga znacznie szybciej.
Szczerze przyznam, że nie wiem o co chodzi i co robią poniższe linie powyższego kodu :
Co to za obliczenia ?? Dlaczego jest F_CPU + 500000 i podzielone przez 1000000-to jest chyba częstotliwość pracy uC .. ??
Dlaczego do argumentu przekazywanego dodawane jest 3 ;|, dzielone przez 5 i mnożone razy ilość cykli na sekundę...czyli to co wyżej ...??
Domyślam się, że to jest część assemblerowska oparta na Watch Dogu, w celu uzyskania jakiegoś wymuszenia w opóźnieniu czasu....??
Korzystałem z gotowej biblioteki WinAVR delay.h, gdzie funkcja opóźniania wygląda następująco:
Ta funkcja również źle odlicza czas w układzie uC z kwarcem.
Nie bardzo wiem jak zrobić poprawne odmierzanie czasu. Już próbowałem "na pałę" zmieniać niektóre wartości w wyżej wymienionych funkcjach, ale "na pałę" to sobie nożna zmieniać ....;d.
Jeśli ktoś wie jak zrobić funkcję dobrego odmierzania czasu na uC ATMEGA8, to prosiłbym o pomoc w tym zagadnieniu.
Temat być może pojawia się po raz wtóry, ale poprzednie tematy nie rozwiązały problemu.
Chcę wykonać prosty zegarek cyfrowy oparty na uC ATMEGA8(L) oraz wyświetlaczu LCD 2x24.
Wszystko chodzi bez zarzutów, gdyby nie fakt złego odliczania czasu przez mój uC.
Otóż mój ATMEGA8 pracuje z kwarcem zewnętrznym 8MHz + dwa kondensatory ceramiczne 22pF (zostały poprawnie zmienione bity CKSEL 3 ... 1 oraz SUT 1, 0 w Fuse Bits).
Dotychczas uC pracował na wewnętrznym oscylatorze 1MHz, gdzie również źle odmierzał czas za pomocą poniższej funkcji, lecz w poprzednich moich programach na uC nie miało to takiego znaczenia; teraz ma
Oto dotychczasowy kod na opóźnianie (odliczanie czasu):
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#define F_CPU 1000000 // 1MHz zegar procesora -> częstotliwość kwarcu
#define CYCLES_PER_US ((F_CPU+500000)/1000000) // cpu cykli na mikrosekunde
#define LED_ON sbi(DDRB,PB1);sbi(PORTB,PB1)
#define LED_OFF sbi(DDRB,PB1);cbi(PORTB,PB1)
void delay(unsigned int us) // opóźnienie w mikrosekundach us -> delay
{
unsigned int delay_loops;
register unsigned int i;
delay_loops = (us+3)/5*CYCLES_PER_US; // +3 for rounding up (dirty)
for (i=0; i < delay_loops; i++) {};
}
void delayms(unsigned int ms) // opóźnienie w milisekundach ms -> delayms
{
unsigned int i;
for (i=0;i<ms;i++)
{
delay(999);
asm volatile ("WDR"::);
}
int main (void)
{
for (;;)
{
LED_ON;
delayms (1000);
LED_OFF;
delayms (1000);
}
}
Mimo, że z kodu wynika że dioda LED powinna mrugać co jedną sekundę (czas zapalenia diody LED również wynosi jedną sekundę), w rzeczywistości dioda mruga znacznie szybciej.
Szczerze przyznam, że nie wiem o co chodzi i co robią poniższe linie powyższego kodu :
#define CYCLES_PER_US ((F_CPU+500000)/1000000) // cpu cykli na mikrosekundeCo to za obliczenia ?? Dlaczego jest F_CPU + 500000 i podzielone przez 1000000-to jest chyba częstotliwość pracy uC .. ??
delay_loops = (us+3)/5*CYCLES_PER_US; // +3 for rounding up (dirty)Dlaczego do argumentu przekazywanego dodawane jest 3 ;|, dzielone przez 5 i mnożone razy ilość cykli na sekundę...czyli to co wyżej ...??
asm volatile ("WDR"::);Domyślam się, że to jest część assemblerowska oparta na Watch Dogu, w celu uzyskania jakiegoś wymuszenia w opóźnieniu czasu....??
Korzystałem z gotowej biblioteki WinAVR delay.h, gdzie funkcja opóźniania wygląda następująco:
static inline void _delay_loop_1(uint8_t __count) __attribute__((always_inline));
static inline void _delay_loop_2(uint16_t __count) __attribute__((always_inline));
static inline void _delay_us(double __us) __attribute__((always_inline));
static inline void _delay_ms(double __ms) __attribute__((always_inline));
void
_delay_loop_1(uint8_t __count)
{
__asm__ volatile (
"1: dec %0" "\n\t"
"brne 1b"
: "=r" (__count)
: "0" (__count)
);
}
void
_delay_loop_2(uint16_t __count)
{
__asm__ volatile (
"1: sbiw %0,1" "\n\t"
"brne 1b"
: "=w" (__count)
: "0" (__count)
);
}
#ifndef F_CPU
/* prevent compiler error by supplying a default */
# warning "F_CPU not defined for <util/delay.h>"
# define F_CPU 1000000UL
#endif
void
_delay_us(double __us)
{
uint8_t __ticks;
double __tmp = ((F_CPU) / 3e6) * __us;
if (__tmp < 1.0)
__ticks = 1;
else if (__tmp > 255)
__ticks = 0; /* i.e. 256 */
else
__ticks = (uint8_t)__tmp;
_delay_loop_1(__ticks);
}
void
_delay_ms(double __ms)
{
uint16_t __ticks;
double __tmp = ((F_CPU) / 4e3) * __ms;
if (__tmp < 1.0)
__ticks = 1;
else if (__tmp > 65535)
__ticks = 0; /* i.e. 65536 */
else
__ticks = (uint16_t)__tmp;
_delay_loop_2(__ticks);
}Ta funkcja również źle odlicza czas w układzie uC z kwarcem.
Nie bardzo wiem jak zrobić poprawne odmierzanie czasu. Już próbowałem "na pałę" zmieniać niektóre wartości w wyżej wymienionych funkcjach, ale "na pałę" to sobie nożna zmieniać ....;d.
Jeśli ktoś wie jak zrobić funkcję dobrego odmierzania czasu na uC ATMEGA8, to prosiłbym o pomoc w tym zagadnieniu.