Sida 1 av 1

Tips på kodsnutt för att ta emot en sträng

Postat: 31 maj 2006, 16:59:47
av thepirateboy
Har någon nåt tips på en kodsnutt för att lagra en sträng med data som tas emot från uarten. Tex om jag skickar "hejsan" från ett terminalprogram från en PC vill jag lagra denna i en array i uC'n. Jag använder Atmega 128 och avr-gcc och har enablat interupt (ISR(USART0_RX_vect)). Att ta emot tecken fungerar bra men kommer inte riktigt på hur jag ska lagra en hel sträng.

Postat: 31 maj 2006, 18:16:27
av björn
Kan väl göra en teckenarray som du lägger dom mottagna tecknen i?

Postat: 31 maj 2006, 18:29:41
av thepirateboy
Ja jag har gjort det men jag antar att jag måste polla nån flagga för att att kunna ta emot ett tecken i taget och lägga in i arrayen.

Postat: 31 maj 2006, 19:21:10
av björn
Nej, i interrupten (för visst körde du interruptstyrt?) får du tecknet i UDR, så du lägger bara det som finns i UDR på "nästa lediga plats" i din array.

EDIT: lade till en liten kodsnutt som bör funka, se Atmels appnote avr306 för mera kod.

Kod: Markera allt

#pragma interrupt_handler twi_isr:18
void twi_isr(void)
{
 unsigned char data;
	 unsigned char tmphead;
 	 
 	 data = UDR;
 	 	 
	/* calculate buffer index */
	tmphead = ( UART_RxHead + 1 ) & UART_RX_BUFFER_MASK;
	UART_RxHead = tmphead; /* store new index */
	if ( tmphead == UART_RxTail )
		{
		/* ERROR! Receive buffer overflow */
		}
		
	UART_RxBuf[tmphead] = data; /* store received data in buffer */	
	
 	
}
EDIT2: observera att min interruptrutin är för iccavr, du får byta ut till gcc's namn på usartinterrupten.

Postat: 31 maj 2006, 20:30:48
av thepirateboy
Tack nu funkar det. Min tanke var om det gick att stanna i interruptet tills alla tecken var mottagna men det kanske inte går/är dumt? Vill lagra strängen i en tvådimensionell array (sSMS) så jag vill även öka index med ett när en sträng är mottagen, men det går väl att lösa på nåt annat vis.

Koden:

ISR(USART0_RX_vect)
{
sTemp[counter] = UDR0;
counter++;

strcpy(sSMS[0],sTemp);
numberOfSMS = 1;
}

Postat: 31 maj 2006, 20:41:36
av björn
Nej, jag tror bara usartbufferten kan hålla 8 bitar så du måste te ett tecken i taget.
Bra att jag kunde hjälpa iallafall :)

Postat: 31 maj 2006, 20:54:12
av cykze
Är du medveten om att strcpy(sSMS[0],sTemp) kräver att sTemp är nullterminerad? Dessutom verkar det lite onödigt att kopiera över hela strängen efter varje inläst tecken.

Postat: 31 maj 2006, 21:09:05
av thepirateboy
Att den måste vara nullterminerad visste jag inte men det låter ju logiskt nu när du säger det. Att den kopieras varje gång är jag medveten om, ville bara kolla om det funka. Om man nu vill kopiera och öka index när en sträng är mottagen, något tips på hur man kan göra. Jag kommer bara skicka en sträng då och då. Ska man sätta en "flagga" i interuptet som man kollar av då och då i huvudprogrammet eller hur göra?

Postat: 31 maj 2006, 21:12:15
av Icecap

Kod: Markera allt

typedef unsigned char byte;

#pragma interrupt_handler twi_isr:18
void twi_isr(void)
  {
  byte Data;
  static byte Index = 0;
  Data = UDR; // Read incoming char
  if(Index >= UART_RxTail)
    { // Trying to fill in too muck, flag for error
    /* ERROR! Receive buffer overflow */
    }
  else
    { // All is well, put in buffer
    UART_RxBuf[Index++] = data; // store received data in buffer
    UART_RxBuf[Index]     = 0; // Terminate string
    }
  } 
Denna gör att du måste antingen ha en kod för "ny sträng" eller flytta ut 'Index' (skip då 'static') och nolla den vid behov. Jag hoppas att din error-rutin är begränsat till att sätta en flagga bara.

Postat: 31 maj 2006, 21:28:03
av cykze
Det här borde väl göra vad du vill.

Kod: Markera allt

ISR(USART0_RX_vect)
{
    static uint8_t counter = 0;

    if (counter >= sizeof(sTemp))
    {
        // Bufferten full
    }
    else
    {
        sTemp[counter] = UDR0;

        if (sTemp[counter] == '\0')
        {
            strcpy(sSMS[numberOfSMS++], sTemp);
            counter = 0;
        }
        else
            counter++;
    }
}
edit: Koden förutsätter att texten som skickas via UART:en är nullterminerad. Startvärdet för numberOfSMS bör vara 0.

Postat: 31 maj 2006, 21:36:53
av thepirateboy
Nice, ska prova detta imorrn. :)

Postat: 31 maj 2006, 22:26:14
av sodjan
> Min tanke var om det gick att stanna i interruptet tills alla tecken var mottagna...

Generellt (oavsett om det är AVR, PIC eller något annan processor) är det
en dålig ide, om det inte är väldigt snabb kommunikation (alltså inget
som en UART klarar av).

En ISR ska inte göra mer än vad som absolut *måste* göras just i ISR'en...