Hello World - med ATmega
ATmega328P.pdf ( Register summary on p 428 )
Eftersom seriekommunikationen med terminalfönstret
är ett mycket användbart felsökningshjälpmedel,
så det är viktigt att utveckla kod för seriekommunikation med processorn.

Figuren visar ett förenklat blockschema över ATmega processorns USART.
Den verkliga kretsen är ändå mer komplex och den beskrivs detaljerat i processorns datablad.
Vi begränsar oss här till att initiera och använda USART för enkel kommunikation med Arduinos terminalfönster.
Blockschemats USART har tre kontrollregister UCSR0A, UCSR0B, UCSR0C, där man gör de inställningar som styr enheten. Registrens bitar har egna namn, och vi kommer att behöva använda bitarna med beteckningarna RXEN0 TXEN0 (i UCSRB), RXC0 (i UCSRA), UDRE (i UCSRA), UCSZ01 UCSZ00 (i UCSRC).
Inställningen av dataöverföringshastigheten, Baude rate, görs med 16-bitars registret UBRR.
En vanlig överföringshastighet är 9600.
Databladet anger en formel för att räkna ut vilket tal som ska läggas i UBRR registret
(UBRR består av två 8 bitsregister men registerparet kan laddas direkt som ett 16 bitarstal).

Med bitarna RXEN0 och TXEN0 slår man på mottagardelen och sändardelen, och med bitparet UCSZ01 UCSZ00 ställer man in arbetssättet - vårt fall asynkront 8 bitar.
void init_uart( void )
{
UCSR0B |= (1 << ( RXEN0 )) | (1 << ( TXEN0 )); // Transmitter on, Reciever on
UCSR0C |= (1 << ( UCSZ01 )) | (1 << ( UCSZ00 )); // Mode: 8 bit asynk
UBRR0 = 103; // Baud prescaler 103 -> 9600 Baud
}
Man hämtar mottagna tecken i UDR(Reciever) registret. Detta är "dubbelbuffrat" så upp till två tecken kan finnas att läsa. Biten RXC0 (i UCSR0A) är 1 när minst ett tecken finns tillgängligt. Som funktionen getchar_uart() nedan är skriven så är den blockerande - så länge inget tecken inkommer så väntar vi här.
unsigned char getchar_uart( void )
{
unsigned char ch;
// wait until a byte is ready to read
while( ( UCSR0A & (1 << ( RXC0 )) ) == 0 ){}
// grab the byte from the serial port
ch = UDR0;
return ch;
}
Man lämnar tecken för sändning till UDR(Transmitter) registret. Sändarenheten är redo för detta när biten UDRE0 (i UCSR0A) är 1.
void putchar_uart( unsigned char ch )
{
// wait until the port is ready to be written to
while( ( UCSR0A & ( (1 << ( UDRE0 )) ) == 0 ){}
// write the byte to the serial port
UDR0 = ch;
}
![]()
Man kan pröva att getchar_uart() och putchar_uart() fungerar genom att köra ett eko-program. Det man skriver i terminalfönstret ska då ekas tillbaka från Arduinokortet!
echo.txt
(for Arduino store code as: echo\echo.ino)
ATmega processorn har en Harvard arkitektur. RAM minnet består av ett litet antal General Purpose Register (GPU), och programminnet består av ett separat större flash minne. Programspråket C är egentligen framtaget för datorer med von Newman arkitektur som karaktäriseras av att allt minne är gemensamt.
unsigned char buffer[20]; const unsigned char hello[] = "hello world";
Den första deklarationen innebär att buffer blir en array med 20 st GPU register.
Registren kan indexeras (tex, 5:e elementet som buffer[4] ) eller nås med pekare
( tex, 5:e elementet som *(buffer+4) ).
Den andra deklarationen är en strängkonstant.
Det är vanligt att man behöver lagra olika sådana förutbestämda (= konstanta) meddelanden som ska skrivas
ut vid olika tillfällen i programmet.
Strängkonstanter lagras initialt i programminnet,
men för att kunna sedan indexeras eller nås med pekare så kommer de att kopieras över till
GPU register vid programmets start.
Problemet med detta är att GPU registren ofta är så få att de förmodligen behövs bättre till annat!
För att inte slösa med RAM så behöver man kunna lagra konstanter direkt i programminnet,
och man behöver kunna nå dem där utan att de först kopieras över till RAM.
Man har löst detta problem genom att utöka AVR kompilatorn med ett antal makron och funktioner för detta.
De finns med i includefilen pgmspace.h.
#include <avr/pgmspace.h> const unsigned char FlashString[] PROGMEM = "This is a string held completely in flash memory.";
Vill man skriva ut en strängkonstant, utan att den först kopieras till RAM, måste man använda makron för "pekare" till programminnet. Funktionen string_out_uart_P() tar en sådan "pekare" till programminnet som argument. Den har fått ett funktionsnamn som slutar på _P för att ange detta. Många av C:s strängfunktioner för AVR finns att tillgå i två varianter, en för pekare till RAM och en för "pekare" till programminne (_P).
string_out_uart_P( FlashString );
void string_out_uart_P( const unsigned char * string ) // use for strings in program memory
{
while ( pgm_read_byte( string ) != 0x00 )
putchar_uart( pgm_read_byte( string ++) );
}
string_out_uart("Hello World\r\n"); // Warning! this string will be copied to RAM registers at program start
void string_out_uart( unsigned char * string ) // use for strings in RAM
{
while (* string != '\0')
putchar_uart(*string ++);
}
![]()

helloworld.txt
(for Arduino store code as: helloworld\helloworld.ino)Programmet helloworld visar hur man kan använda olika lagringssätt och olika utskriftsfunktioner för strängar i RAM och i programminne.
Detta programexempel använder "Windows style" för ny rad, både return och newline tecken.
William Sandqvist william@kth.se