Příklad použití STREAMu pro UART

Už chvíli mne štvalo, že nedokážu pro MCU použít takové standardní funkce jako printf. ***/
Po konzultaci s googlem jsem si z prstu vycucal tady toto.
Vím, že existují vymakanější knihovny,
já to však psal pro začátečníky s minimem znalostí MCU.
Musí se však aspoň trochu vyznat v Céčku.
Navrhováno pro MCU ATMEGA16, ATMEGA32, ATMEGA64, …
tedy pro 2 UARTy, ale bez problému to lze předělat.

[code]//**************************************************
// ***** HEADER FILE : UART_routines.h ******
//**************************************************

#ifndef UART_ROUTINES_H
#define UART_ROUTINES_H

#ifndef F_CPU
#define F_CPU 12000000.0 //Zadej správnou frekvenci krystalu (MCU)
#endif

#define UART0_DISABLE UCSR0B = 0x00
#define UART1_DISABLE UCSR1B = 0x00

FILE *u0;
FILE *u1;

int UART0ReadChar(FILE* unused);
int UART1ReadChar(FILE* unused);
int UART0PutChar( char data , FILE* unused);
int UART1PutChar( char data , FILE* unused);
void uart0_init(float);
void uart1_init(float);

#endif
[/code]

[code]//**************************************************
// ***** SOURCE FILE : UART_routines.c ******
//**************************************************
#include <stdio.h>
#include “UART_routines.h”
#include <avr/io.h>

//
/
Inicializace UART0 /
/
/
void uart0_init(float Baudrate)
{
unsigned int BAUD;

UART0_DISABLE;
UCSR0C = (2<<UMSEL0) | (3 << UCSZ00);
if (Baudrate > 57600.0)
{
UCSR0A = (1<<U2X0);
BAUD = (F_CPU / (8.0 * Baudrate))-0.5;
UBRR0L = BAUD;
UBRR0H = (BAUD >> 8);
}
else
{
UCSR0A = 0x00;
BAUD = (F_CPU / (16.0 * Baudrate))-0.5;
UBRR0L = BAUD;
UBRR0H = (BAUD >> 8);
}
UCSR0B = (1 << RXEN0) | (1 << TXEN0) ;

#if defined( AVR_LIBC_VERSION )
u0 = fdevopen( UART0PutChar, UART0ReadChar );
#else
u0 = fdevopen( UART0PutChar, UART0ReadChar, 0 );
#endif

}

//
/
Inicializace UART1 /
/
/
void uart1_init(float Baudrate)
{
unsigned int BAUD;

UART1_DISABLE;
UCSR1C = (2<<UMSEL1)|(3<<UCSZ10);
if (Baudrate >= 57600.0)
{
UCSR1A = (1<<U2X1);
BAUD = (F_CPU / (8.0 * Baudrate))-0.5;
UBRR1L = BAUD;
UBRR1H = (BAUD >> 8);
}
else
{
UCSR1A = 0x00;
BAUD = (F_CPU / (16.0 * Baudrate))-0.5;
UBRR1L = BAUD;
UBRR1H = (BAUD >> 8);
}

UCSR1B = (1 << TXEN1) | (1 << RXEN1);

#if defined( AVR_LIBC_VERSION )
u1 = fdevopen( UART1PutChar, UART1ReadChar );
#else
u1 = fdevopen( UART1PutChar, UART1ReadChar, 0 );
#endif
}

//**************************************************
//Function to receive a single byte
//*************************************************

int UART1ReadChar(FILE* unused)
{
unsigned char c;
loop_until_bit_is_set (UCSR1A,RXC1); // Wait untill a char is received
c = UDR1;
int a;
for (a=0;a<100;a++) {}
return c;

}

int UART0ReadChar(FILE* unused)
{
unsigned char c;
loop_until_bit_is_set (UCSR0A,RXC0); // Wait untill a char is received
c = UDR0;
int a;
for (a=0;a<100;a++) {}
return c;
}

//***************************************************
//Function to transmit a single byte
//***************************************************
int UART1PutChar( char data , FILE* unused)
{
loop_until_bit_is_set(UCSR1A, UDRE1);
UDR1 = data;
return 0;
}

int UART0PutChar( char data , FILE* unused)
{
loop_until_bit_is_set(UCSR0A, UDRE0);
UDR0 = data;
return 0;
}
[/code]

/**************************************************************************/
/**************************************************************************/
/***	Už chvíli mne štvalo, že nedokážu pro MCU použít				***/
/***	takové standardní funkce jako printf.							***/
/***	Po konzultaci s googlem jsem si z prstu vycucal					***/
/***			 tady toto.												***/
/***	Vím, že existují vymakanější knihovny,							***/
/***	já to však psal pro začátečníky s minimem znalostí MCU.			***/
/***	Musí se však aspoň trochu vyznat v Céčku.						***/
/***																	***/
/***	Navrhováno pro MCU ATMEGA16, ATMEGA32, ATMEGA64, ...			***/
/**************************************************************************/
/**************************************************************************/

 #include <avr/io.h>
 #include <stdio.h>
 #include <avr/pgmspace.h>

 #include "UART_routines.h"		

/**************************************************************************/
/***	Přednadstavení portů											***/
/**************************************************************************/ 
void static __inline__ port_init(void)
{
PORTA = 0xFF;	//na všechny piny pull-up
DDRA  = 0x00;
PORTB = 0xFF;
DDRB  = 0x00; 
PORTC = 0xFF;
DDRC  = 0x00;
PORTD = 0xFF;
DDRD  = 0x00;
PORTE = 0xFF;
DDRE  = 0x00;
PORTF = 0xFF;
DDRF  = 0x00;
PORTG = 0xFF;
DDRG  = 0x00;
}

/**************************************************************************/
/***	Kompletní inicializace											***/
/**************************************************************************/
void init_devices(void)
{
 MCUCR = 0x00;
 EIMSK = 0x00;		
 EICRB = 0x00;
 EICRA = 0x00;
 TIMSK = 0x00;
 port_init();

 uart0_init(4800);		//Tyto funkce mají poměrně primitivní výpočet
 						//Před zadáním nějakého numera se v datasheetu
						//přesvěčte, zda to procesor vůbec zvládne

 uart1_init(115000);
}

/**************************************************************************/
/**************************************************************************/
/***	Tělo programu													***/
/**************************************************************************/
/**************************************************************************/
int main(void)
{
char NMEA[83];
unsigned int Count = 0;

init_devices();
fprintf_P(u1,PSTR("Start programu.\r\n"));		//Zaslat hlášku na UART1

while (1)										// Do nekonečna
	{
	fscanf(u0,"%s", NMEA);						//Čte string z UART0
	fprintf(u1,"%d.....%s\r\n", Count++,NMEA);	//a okamžitě ji pošle na UART1
	}
}

Šikovnější človíčky jistě napadne, že se to dá překopat a rozšířit pro SPI, TWI atd.

kolko zozralo pameti a ramky pouzitie stdio ???

Nejsem si jistý, jak by se to dalo jednoduše zjistit.
Celý program však zabírá 7746B a trvale obsadí 44B ramky.

:arrow_right: administrator: příspěvek byl upraven
Předchozí příspěvky se necitují.

Právě jsem si vytvořil obdobný program, který provádí v podstatě to samé,
ale bez knihovny stdio.h.

Tento program zabírá 3930B a trvale obsadí 20B ramky.

Takže knihovna stdio přidá zhruba 4kB programu.

To není úplně přesné.
Samotné includování knihovny žádný kód nepřidá.
Ten se zvětší teprve podle toho, které funkce z této knihovny použijeme.

Udělal jsem test, jak roste kód s přidáváním funkcí.

[code]int main(void)
{
long L1=123456;
static char tempstr[20];

uart_init();
stdout = &mystdout;
// 210 bajtů kódu
printf(“Hello, world!\r\n”); // 338
printf("%ld \r\n",L1); // 1786

printf_P(PSTR(“Zadej text\r\n”)); // 1880
scanf ("%s",tempstr); // 3444
printf("\r\n%s\r\n",tempstr); // 3472

for(;:wink:
{

}

}[/code]