PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Delay mittels Timer



Spurius
13.02.2006, 14:05
Hallo,
ich versuche in folgendem Code eine Delay-funktion zu realisieren.
Leider funktioniert es nicht wirklich, kann vllt. von euch jemand erkennen, warum nicht im Sekundentakt gesendet wird, sondern viel schneller?


#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>

volatile uint8_t count;

void init_usart(void)
{
UBRRL |= 0b01100111;
UCSRB = (1<<TXEN) | (1<<RXEN);
UCSRC = (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0);
}

void send_char(unsigned char s)
{
while (!(UCSRA & (1<<UDRE)));
UDR = s;
}

void send_string(char *s)
{
while(*s != '\0')
{
send_char(*s);
s++;
}
}

void waitms(uint16_t s)
{

uint16_t i;
uint8_t j;
TCCR0 |= (1<<CS01) | (1<<CS00); //Vorteiler 64
TIMSK |= (1<<TOIE0);

for(i=0;i<s;i++)
{
TCNT0 = 6; // Timer auf 6 vorladen, da (16000000/64)^-1 = 0.000004s
} // -> 1ms = 0.000004s*250

TIMSK |= (0<<TOIE0);
}

SIGNAL(SIG_OVERFLOW0)
{
count++;
TCNT0 = 6;
}

int main(void)
{
sei();
unsigned int i;
char a = "108:158#13#10";
i = 0;
init_usart();
do
{
send_string(a);
waitms(1000);
}
while (i == 0);
}



Gruß
Spurius

SprinterSB
13.02.2006, 14:58
Versuch mal sowas:



#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>

volatile uint8_t count;

void init_usart(void)
{
UBRRL |= 0b01100111;
UCSRB = (1<<TXEN) | (1<<RXEN);
UCSRC = (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0);
}

void send_char (unsigned char s)
{
while (!(UCSRA & (1<<UDRE)));
UDR = s;
}

void send_string (char *s)
{
while (*s++)
send_char(*s);
}

void init_timer0()
{
TCCR0 = (1<<CS01) | (1<<CS00); //Vorteiler 64
TIMSK |= (1<<TOIE0);
}

void waitms (uint16_t s)
{
while (s--)
{
uint16_t cnt;

cli();
count = 0;
TCNT0 = 6;

do
{
cli();
cnt = count;
sei();
}
while (cnt < 1000);
}
}

SIGNAL (SIG_OVERFLOW0)
{
TCNT0 = 6;
count++;
}

char a[] = "108:158#13#10";

int main(void)
{
init_usart();
init_timer0();

sei();

while (1)
{
send_string (a);
waitms (1000);
}
}

Spurius
13.02.2006, 15:06
Hi,
bei deiner Version wird nur einmal gesendet :?:
Was ist bei mir denn konkret falsch? Hab ich nen Logikfehler oder eher was C-Spezifisches?

SprinterSB
13.02.2006, 15:21
Sorry, count muss uint16_t sein, nicht uint8_t (zählt bis 1000). Und in der Schleife muss es heissen while(*s) { foo (*s++); }

Was bei dir konkret inkorrekt ist, ist schwer zu fprmulieren. Es geht eben nicht so. Interrupts hast du inaktiv und setzt in der Schleife nur s mal TCNT0 auf 6. Da müsste noch das Flag aus TIFR abgefrage/gelöscht werden, heisst glaub TOV0 oder so.

super_castle
13.02.2006, 18:36
nimm diese hier, delay_us_(...) und delay_ms_(...):

#define delay_us_(us) _delayFourCycles_( ( ( 1*(F_CPU/4000) )*us)/2005)

static inline void _delayFourCycles_(uint16_t z)
{
uint16_t i;

for (i=0; i<z; i++)
asm volatile("nop");
}

static inline void delay_ms_(uint16_t z)
{
uint16_t i;

for (i=0; i<z; i++)
delay_us_(999);
}

Spurius
13.02.2006, 18:40
Hallo,
danke für eure Hilfe, ich habs jetzt so gelöst:


#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>

volatile uint8_t count = 0;

void init_usart(void)
{
UBRRL |= 0b01100111;
UCSRB = (1<<TXEN) | (1<<RXEN);
UCSRC = (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0);
}

void send_char(unsigned char s)
{
while (!(UCSRA & (1<<UDRE)));
UDR = s;
}

void send_string(char *s)
{
while(*s != '\0')
{
send_char(*s);
s++;
}
}

void waitms(uint16_t s)
{

uint16_t i;
uint8_t j;
TCCR0 |= (1<<CS01) | (1<<CS00); //Vorteiler 64
TIMSK |= (1<<TOIE0);

for(i=0;i<s;i++)
{
count = 0;
TCNT0 = 6; // Timer auf 6 vorladen, da (16000000/64)^-1 = 0.000004s
while(count != 1)
{}

} // -> 1ms = 0.000004s*250

TIMSK |= (0<<TOIE0);
}

SIGNAL(SIG_OVERFLOW0)
{
count = 1;
}

int main(void)
{
sei();
unsigned int i;
char a = "Hallo Welt";
i = 0;
init_usart();
do
{
send_string(a);
waitms(1000);
}
while (i == 0);
}

Gruß
Spurius