background image

39

Programowanie

Elektronika dla Wszystkich

Dziœ zajmiemy siê czymœ, od czego zaczyna

siê wiêkszoœæ ksi¹¿ek o C dla „du¿ych kom-

puterów”. Dlaczego dopiero teraz? Wspomi-

na³em ju¿ o tym i napiszê raz jeszcze: mikro-

kontrolery  rz¹dz¹  siê  innymi  prawami  ni¿

stacje  robocze.  Tam  gdzie  w  stacji  roboczej

wystêpuje  BIOS  oraz  System  Operacyjny,

sprawiaj¹ce  razem,  ¿e  wypisanie  informacji

na  ekranie  jest  najprostsz¹  mo¿liw¹  rzecz¹,

tam w mikrokontrolerze... nie ma nic. Musie-

liœmy  po  kolei  nauczyæ  siê  podstawowych

operacji na rejestrach, dopiero póŸniej wspi-

naæ  siê  coraz  wy¿ej.  Szczêœliwie  rejestry

mamy ju¿ za sob¹. Dziœ na celu mamy dotar-

cie  do  funkcji  printf oraz  jej  bliskich  znajo-

mych. Dowiemy siê, jak realizowane s¹ ope-

racje strumieniowe – tak naturalne w du¿ych

maszynach.  Nie  bez  znaczenia  jest  fakt

powstania  nowej  p³ytki.  Funkcja  printf, bar-

dzo uniwersalna i o wielkich mo¿liwoœciach,

zajmuje stosunkowo du¿o pamiêci programu.

„Hello world”

Stwórzmy  folder  na  nowy  program.  Skopiuj

do  niego  plik  makefile.  Mo¿esz  wzi¹æ  go  z

poprzednich  programów  albo  te¿  bezpoœred-

nio z folderu C:\WinAVR\sample. W Program-

mers  Notepadzie  tworzymy  nowy  projekt.

Mo¿esz  nazwaæ  go  na  przyk³ad  helloworld.

Do projektu dodajemy plik makefile i zaczy-

namy jego edycjê. Niezbêdne zmiany zazna-

czone s¹ na rysunku 37.

Teraz zgodnie z wprowadzonymi zmiana-

mi tworzymy g³ówny plik programu o nazwie

main.c. Dodajemy  go  do  projektu  w  oknie

Programmers Notepada. W pliku tym wpisu-

jemy kod z listingu 52. Skompilowanie pro-

gramu przyniesie dwie niespodzianki:

1. Program zajmuje zaskakuj¹co du¿o miejsca

w pamiêci (u mnie ponad 1kB!).

2. Program w zasadzie nic nie robi, a raczej:

nie daje ¿adnych zewnêtrznych oznak dzia³ania.

Pierwszy problem zaskoczy³ mnie kiedyœ,

prawdopodobnie  tak  samo  jak  móg³  zasko-

czyæ teraz wiêkszoœæ Czytelników. Jego roz-

wi¹zanie  wymaga  nieco  „gimnastyki”.  Ze

wzglêdu  na  objêtoœæ  materia³u  poczekamy 

z tym do czêœci 8. Teraz przyjrzyjmy siê prob-

lemowi z nicnierobieniem naszego programu.

Pytanie podstawowe brzmi: gdzie proce-

sor  ma  wys³aæ  podany  mu  napis  „Hello

world!”? W typowym programie

komputerowym bêdzie to zwyk-

le konsola... Nasza p³ytka posia-

da  wyœwietlacz  LCD,  jednak

kompilator  nic  o  tym  nie  wie.

Posiada  tak¿e  port  szeregowy.

Wiele  kompilatorów  w³aœnie

port  szeregowy  uzna³oby  za

domyœlne  wyjœcie  dla  naszego

napisu. W AVR-GCC zosta³o to

rozwi¹zane  inaczej.  Domyœlnym

miejscem, gdzie dane bêd¹ wysy-

³ane,  bêdzie  pierwsze  otwarte

urz¹dzenie.  Zanim  przejdziesz

dalej, zajrzyj do ramki „ABC... C

– Jak dzia³aj¹ strumienie”.

W  ramach  kursu  nie  mieliœ-

my jeszcze okazji zaj¹æ siê por-

tem  szeregowym.  Zróbmy  to  teraz.  Zgodnie 

z  tym,  czego  nauczyliœmy  siê  do  tej  pory,

funkcje zwi¹zane z transmisj¹ danych umieœ-

cimy w oddzielnym module. Utwórz pliki rs.c

oraz  rs.h.  Pamiêtaj,  aby  do  pliku  makefile

dodaæ  nowy  plik  kodu  Ÿród³owego.  Przypo-

minam o tym na rysunku 38. Kod, jaki nale-

¿y wpisaæ w plik rs.c, znajduje siê na listingu

53. Nie ma w nim nic niezwyk³ego – w prak-

tyce przyk³ady takie mo¿na znaleŸæ w doku-

mentacji technicznej procesorów AVR.

Listing 54 pokazuje kod, który powinien

znaleŸæ siê w pliku nag³ówkowym. Deklaru-

jemy tutaj funkcje, które zdefiniowane zosta-

³y w pliku Ÿród³owym. Od tej chwili bêdzie-

my  mogli  swobodnie  u¿ywaæ  ich  wszêdzie

tam gdzie do³¹czymy plik rs.h.

Dodatkowo  w  naszym  nag³ówku  definu-

jemy  dwa  makra  pomocne  przy  obliczaniu

danej  wpisywanej  do  rejestru  UBRR,  która

wyznacza  prêdktoœæ  transmisji.  Makro

pomocnicze  RS_MAKE_UBRR  jest  przenie-

sieniem na C opisanego w dokumentacji spo-

sobu  obliczania  potrzebnej  wartoœci.  Sta³a

F_CPU  deklarowana  jest  z  poziomu  pliku

makefile.

Zwracam  Twoj¹  uwagê  na  fakt,  jak

wa¿ne  jest  otoczenie  nawiasami  obliczeñ

makra RS_MAKE_UBRR.  Wstaw  w  wy-

obraŸni zawarty w nim tekst – tak jak robi

to  preprocesor  –  w  miejscu  wyst¹pienia

jego  wywo³ania.  Zauwa¿,  co  sta³oby  siê,

gdyby  nawiasów  nie  by³o.  Szczególnie

widoczne jest to w miejscu, gdzie obliczo-

n¹ wartoœæ przesuwamy.

PP

PP

rr

rr

oo

oo

gg

gg

rr

rr

aa

aa

m

m

m

m

oo

oo

w

w

w

w

aa

aa

nn

nn

ii

ii

ee

ee

  

  

pp

pp

rr

rr

oo

oo

cc

cc

ee

ee

ss

ss

oo

oo

rr

rr

óó

óó

w

w

w

w

w

w

w

w

  

  

jj

jj

êê

êê

zz

zz

yy

yy

kk

kk

uu

uu

  

  

CC

CC

czêœæ 7

Rys. 37 Zmiany w pliku makefile

Listing 52 – wypisanie prostego tekstu

#include <avr\io.h>

#include <stdio.h>

iinntt

main((

vvooiidd

))

{{

puts((

„Hello world!”

));;

}}

Listing 53 – plik rs.c

#include <avr\io.h>

#include „rs.h”

iinntt

rs_put((

cchhaarr

znak))

{{

// Oczekiwanie a¿ bufor nadajnika jest pusty

wwhhiillee

((!!((

1

<<<<UDRE0 && UCSR0A)))) {}

UDR0 == znak;;

rreettuurrnn

0

;;

}}

iinntt

rs_get((

vvooiidd

))

{{

cchhaarr

znak;;

// Oczekiwanie na pojawienie siê danej

wwhhiillee

((!!((

1

<<<<RXC0 && UCSR0A)))) {}

znak == UDR0;;

rreettuurrnn

znak;;

}}

background image

Utwórz  teraz  ostatni  potrzebny  nam,

nowy  plik.  Zapisz  go  pod  nazw¹  harddef.h.

Tak  jak  robiliœmy  to  poprzednio,  zmieœcimy

w  nim  wszystkie  definicje  dotycz¹ce  czêœci

sprzêtowej. Za tak¹ mo¿emy uznaæ prêdkoœæ

transmisji. Mo¿e wydaje Ci siê to bezcelowe

–  tworzenie  nowego  pliku  dla  jednej  tylko

danej. Jednak trzeba wzi¹æ pod uwagê, ¿e pro-

gram mo¿e siê rozrastaæ. Najlepiej od pocz¹t-

ku  utrzymywaæ  w  nim  porz¹dek.  Zawartoœæ

wspomnianego pliku pokazuje listing 55.

Jeœli zaczynasz siê gubiæ w tym, co robi-

my, nie poddawaj siê teraz! Przed nami ostat-

nia prosta, która nada sens wszystkim naszym

dzia³aniom.  Listing  56  pokazuje  zmienion¹

funkcjê main. Teraz program po skompilowa-

niu  i  w³adowaniu  danych  do  procesora

zacznie  dzia³aæ  zgodnie  z  naszym  zamierze-

niem. Konieczne bêdzie pod³¹czenie p³ytki do

wolnego portu RS232 w naszym komputerze.

Do komunikacji wykorzystaæ mo¿na dowolny

program terminala. Mo¿e byæ to nawet termi-

nal  wbudowany  w  œrodowisko  BASCOM.

Transmisjê nale¿y skonfigurowaæ na:

Liczba bitów na sekundê: 4800

Bity danych: 8

Parzystoœæ: Brak

Bity stopu: 1

Rysunek 39 pokazuje efekt dzia³ania pro-

gramu.  Po  ka¿dym  zerowaniu

procesor  wyœle  kolejny  napis.

Zgodnie  z  dokumentacj¹,  funk-

cja  puts  dodaje  na  koniec  znak

nowej linii. Nie wprowadza jed-

nak  znaku  powrotu  karetki,  co

daje widoczny na rysunku

39 efekt. Nie ka¿dy termi-

nal  zinterpretuje  przesy³a-

ne dane w taki w³aœnie spo-

sób,  jednak  aby  zupe³nie

pozbyæ  siê  problemu,  mo-

¿emy napis zamieniæ na:

„Hello world!\r”

W ten sposób rêcznie dodamy przed

znakiem nowej linii znak powrotu karet-

ki  i  wszystkie  nowe  napisy  u³o¿¹  siê

jeden pod drugim.

Jaki to ma sens

Dobrze  wiêc...  utworzyliœmy,  zajmuj¹cy  po-

nad 1KB pamiêci, program wypisuj¹cy za po-

moc¹  portu  RS  ³adne  przywitanie.  Pocz¹tek

nie wypad³ nam zachwycaj¹co. Zmniejszanie

zajêtoœci pamiêci zwi¹zane bêdzie z tematem,

który  chcê  omówiæ  dopiero  w

kolejnej  czêœci.  Teraz  zajmijmy

siê poznaniem funkcji, która tak

naprawdê sprawia, ¿e biblioteka

stdio jest potê¿nym narzêdziem

Przeczytaj ramkê ABC... C –

printf, razem z do³¹czonymi do

niej  tabelkami.  Nie  wygl¹da  to

mo¿e  w  tej  chwili  najproœciej,

dlatego  te¿  proponujê  natych-

miast przejœæ do przyk³adu poka-

zanego  na  listingu  57. Jedyne,

co musisz zmieniæ, to zawartoœæ

funkcji  main.  Ze  wzglêdu  na

oszczêdnoœæ  miejsca  inicjacja

portu  szeregowego,  która  nie

uleg³a  zmianie,  zosta³a  wykrop-

kowana.

Dzia³anie  przyk³adowego

programu pokazuje rysunek 40.

Pobaw siê tym kodem. SprawdŸ,

"

Programowanie

Elektronika dla Wszystkich

ABC... C

Jak dzia³aj¹ strumienie?

Pamiêtasz, jak do tej pory obs³ugiwaliœmy napisy na

wyœwietlaczu  LCD?  Pisaliœmy  oddzielne  funkcje  do

wypisania  ³añcucha  znaków,  do  wypisania  liczby 

w formacie dziesiêtnym czy szesnastkowym.

Idea  funkcji  operuj¹cych  na  zasadzie  strumieni

zdejmuje z nas obowi¹zek tworzenia wszystkich prze-

kszta³ceñ. Wymaga od nas jedynie stworzenia funkcji

wypisuj¹cej oraz odczytuj¹cej jeden znak. Genialnoœæ

pomys³u pokazuje rysunek w ramce:

Funkcje get i put

Dwie  powy¿sze  funkcje  nie  s¹  dok³adnie  okreœlone

przez  standard  ANSI  C.  W  AVR-GCC musz¹  one

mieæ formê jak poni¿ej:

iinntt

put((

cchhaarr

znak))

iinntt

get((

vvooiidd

))

Funkcja put powinna zwracaæ 0, jeœli wysy³anie

znaku  przebieg³o  pomyœlnie,  w  innym  przypadku

zwracamy wartoœæ ujemn¹, co spowoduje przerwanie

dzia³ania  operuj¹cej  na  niej  funkcji  –  nawet  jeœli

wszystkie jej dane nie zosta³y wys³ane. Podobnie sytu-

acja  ma  siê  z  funkcj¹  get.  Tutaj  jednak  funkcja  nor-

malnie zwraca odebran¹ dan¹, gdy wyst¹pi b³¹d, nale-

¿y zwróciæ wartoœæ ujemn¹.

Inicjowanie urz¹dzenia

Zak³adaj¹c, ¿e posiadamy ju¿ gotowe funkcje put oraz

get, musimy jeszcze poinformowaæ funkcje z bibliote-

ki stdio o  tym,  ¿e  chcemy  w³aœnie  z  nich  korzystaæ.

Wykonujemy  to  za  pomoc¹  funkcji  fdevopen.  Jej

sk³adniê przedstawiam poni¿ej:

fdevopen((put,, get,,

0

));;

Ostatni parametr jest niewykorzystany i powinien

mieæ  zawsze  wartoœæ  0.  Po  wywo³aniu  jak  wy¿ej,

podane  funkcje  zostan¹  przyporz¹dkowane,  odpo-

wiednio,  domyœlnemu  wyjœciu  oraz  wejœciu.  Od  tej

chwili wywo³anie przyk³adowej funkcji puts listingu

52 da oczekiwany efekt przes³ania kolejnych znaków

‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘ ‘ ‘w’ ‘o’ ‘r’ ‘l’ ‘d’ ‘!’, kolejno do

funkcji putCo z kolei w niej bêdzie siê dzia³o z prze-

s³anymi  znakami,  to  ju¿  kwestia  naszych  potrzeb

i inwencji.

Listing 54 – plik rs.h

#ifndef RS_H_INCLUDED

#define RS_H_INCLUDED

#define RS_MAKE_UBRR(baud) (F_CPU/(baud*16l)-1)

#define RS_SET_BAUD(baud) \

{UBRR0H = (uint8_t)(RS_MAKE_UBRR(baud)>>8); \

UBRR0L = (uint8_t)RS_MAKE_UBRR(baud); }

iinntt

rs_put((

cchhaarr

znak));;

iinntt

rs_get((

vvooiidd

));;

#endif 

// RS_H_INCLUDED

Listing 55 – plik harddef.h

#ifndef HARDDEF_H_INCLUDED

#define HARDDEF_H_INCLUDED

#define DEF_BAUD 4800

#endif 

// HARDDEF_H_INCLUDED

Listing 55 – plik harddef.h

#ifndef HARDDEF_H_INCLUDED

#define HARDDEF_H_INCLUDED

#define DEF_BAUD 4800

#endif 

// HARDDEF_H_INCLUDED

Listing 56 – zmiany w pliku main umo¿liwiaj¹ce dzia³anie programu

#include <avr\io.h>

#include <stdio.h>

#include „rs.h”

#include „harddef.h”

iinntt

main((

vvooiidd

))

{{

////////////////////////////////////////////

// Inicjacja portu szeregowego

RS_SET_BAUD((DEF_BAUD));;

UCSR0C ==

1

<<<<URSEL0 ||

1

<<<<UCSZ01 ||

1

<<<<UCSZ00;;

UCSR0B ==

1

<<<<RXEN0 ||

1

<<<<TXEN0;;

UCSR0A ==

0

;;

// Koniec inicjacji

////////////////////////////////////////////

// Inicjacja funkcji domyœlnych strumieni io

fdevopen((rs_put,, rs_get,,

0

));;

puts((

„Hello world!“

));;

}}

Rys. 38 Dodanie pliku rs.c

Rys. 39 Efekt dzia³ania programu

background image

jakie  efekty  da

podanie  okreœlo-

nej szerokoœci lub

precyzji.  Wypró-

buj  ró¿ne  flagi.

Spróbuj  skorzys-

taæ  tak¿e  z  typów

‘s’ oraz ‘S’.

Poniewa¿  jest

to  doœæ  ciekawe,

proponujê Ci zapoznanie siê z rysunkiem 41,

który  pokazuje  ostatni  kod  uruchomiony  za

pomoc¹ programu AVRStudio. Spróbuj same-

mu przeprowadziæ pokazan¹ na nim symulac-

jê. Widzimy tutaj, w jaki sposób poszczegól-

ne  argumenty  s¹  przesy³ane  do  funkcji.

Widzimy,  ¿e  jest  to  jak  najbardziej  zgodne 

z opisem w ramce o naszej funkcji. Zauwa¿,

¿e w tym przypadku tak¿e parametr okreœlaj¹-

cy adres ³añcucha formatowania  przesy³any

jest przez stos. Informacja o tym znajduje siê

w dokumentacji do³¹czonej do WinAVR... nie

ma dla nas tak du¿ego znaczenia przesy³anie,

nieznanej nam wczeœniej, otwartej listy argu-

mentów.

Pamiêæ programu

Jeœli w którymœ momencie zada³eœ sobie pyta-

nie, dlaczego ci¹gle umieszczam ³añcuchy w

pamiêci danych, zamiast jak ju¿ pokazywaliœmy

"#

Programowanie

Elektronika dla Wszystkich

ABC... C

printf

Dowolnoœæ argumentów... jak to dzia³a?

Sk³adnia funkcji printf wygl¹da nastêpuj¹co:

iinntt

printf((

ccoonnsstt cchhaarr

fmt,,......))

Widoczne trzy kropki to nie ¿adne wprowadzone

przeze mnie uproszczenie. To doœæ ciekawa oraz ca³-

kowicie formalna cecha jêzyka C. Trzy kropki poja-

wiaj¹ siê zawsze za ostatnim argumentem. Nie mo¿na

za nimi umieœciæ jeszcze kolejnego, ustalonego argu-

mentu. Format, z jakim mamy tutaj do czynienia ozna-

cza,  ¿e  zaraz  za  parametrem  fmt mo¿emy  umieœciæ

dowoln¹ iloœæ dowolnych parametrów.

Pierwszym  parametr  nazywany  jest  z  angielska

„Format  String”,  co  mo¿na  t³umaczyæ  jako  ³añcuch

formatuj¹cy. W nim zawarte s¹ informacje, jakie para-

metry  zosta³y  wprowadzone  i  z  jego  pomoc¹  s¹  one

odzyskiwane. Sposób podawania odpowiednich infor-

macji pojawi siê za chwilê, teraz jednak skupmy siê na

reszcie argumentów.

Ka¿dy  kolejny  argument,  wpisany  w  miejsce

trzech  kropek,  jest  umieszczany  na  stosie.  Jednak

wrzucane  s¹  one  „od  ty³u”.  W  efekcie,  w  chwili

wywo³ania funkcji, pierwszy argument znajduje siê na

samym  szczycie  stosu  i  mo¿e  byæ  jako  pierwszy 

z  niego  zdjêty.  Zmienne  zdejmowane  bêd¹  od  naj-

m³odszego bajtu do najstarszego.

W ten sposób mo¿na do funkcji przekazaæ argu-

menty w objêtoœci ograniczonej jedynie pojemnoœci¹

pamiêci  przeznaczonej  na  stos.  Jest  to  niezwykle

wygodne w funkcji takiej jak printf, gdzie nie da siê

okreœliæ,  jakie  argumenty  bêd¹  potrzebne,  jednak 

z mo¿liwoœci tej trzeba korzystaæ bardzo ostro¿nie...

Ryzyko i wady rozwi¹zania

Osoby  obeznane  trochê  z  programowaniem  zdaj¹

sobie sprawê z tego, jak wa¿nym elementem jest stos.

Jakikolwiek b³¹d w przep³ywie informacji miêdzy sto-

sem  a  rejestrami  mo¿e  skutkowaæ  zawieszeniem  siê

ca³ego programu. Trzeba zdaæ sobie sprawê, ¿e o ile 

w przypadku zwyczajnych funkcji, z ustalonymi para-

metrami,  to  kompilator  dba  o  prawid³ow¹  obs³ugê

stosu, nie jest on w stanie pilnowaæ jego dzia³ania, gdy

korzystamy z otwartej listy argumentów. Gdy decydu-

jemy siê na takie dzia³anie, to na nas spoczywa odpo-

wiedzialnoœæ  za  prawid³owe  jego  funkcjonowanie.

Kompilator nie bêdzie tak¿e w stanie sprawdziæ, czy

podawane  argumenty  s¹  w³aœciwego  typu.  Bardzo

wa¿ne jest wiêc, aby podane argumenty zgadza³y siê 

z  tym,  co  deklarujemy  w  ³añcuchu  formatowania. 

W  innym  przypadku  funkcja  printf mo¿e  nie  zdj¹æ

wszystkich informacji ze stosu. Mo¿e tak¿e zdj¹æ ich

zbyt wiele. B³¹d stosu mo¿e spowodowaæ, ¿e dalej, do

rejestrów  wpisane  zostan¹  przypadkowe  dane. 

W skrajnym przypadku œmieci zostan¹ wprowadzone

do  licznika  rozkazów...  rozumiesz  na  pewno,  co  siê

wtedy stanie.

Oprócz  koniecznej  ostro¿noœci  trzeba  zwróciæ

uwagê  na  jeszcze  jedn¹  sprawê.  Jeœli  wywo³ywana

funkcja posiada jedynie sta³e

argumenty,  w  miarê  mo¿li-

woœci  s¹  one  umieszczane

bezpoœrednio  w  rejestrach.

Odpowiedni  podprogram  w

chwili  uruchomienia  zna

dok³adnie  typy  wszystkich

argumentów – ma je podane

niejako  „na  tacy”.  Jeœli  na-

tomiast wywo³ujemy funkcjê

z  otwart¹  list¹  parametrów,

wszystkie  one  musz¹  zostaæ

umieszczone  na  stosie.  Wy-

maga  to  dodatkowego  czasu

oraz kodu przed wywo³aniem

podprogramu.  Sam  podpro-

gram tak¿e musi byæ bardziej

rozbudowany.

Ogólnie,  jeœli  to  mo¿li-

we,  funkcji  tego  typu  raczej

siê  unika.  Czasami  jednak

jest to albo jedyne... albo naj-

lepsze  rozwi¹zanie  –  mimo

wszystkich wad.

Format

Wiemy ju¿ co i jak siê dzieje

w  naszej  funkcji.  Teraz  do-

wiemy  siê,  jak  j¹  wykorzys-

taæ.  Bardzo  wa¿ny  jest  ³añ-

cuch  formatuj¹cy.  To  w  nim

zawarta jest informacja o przekazanych paramet-

rach  oraz  o  sposobie,  w  jaki  zostan¹  one

wyœwietlone. Znaki z ³añcucha formatuj¹cego s¹

wysy³ane  bezpoœrednio  na  wyjœcie  do  chwili

natrafienia  na  znak  ‘%’.  Znaki  wystêpuj¹ce  za

nim  s¹  interpretowane  jako  informacja  o  kolej-

nym argumencie.

Rysunek  powy¿ej  pokazuje  format  opisu

argumentu  oraz  sposobu  jego  wyœwietlenia. 

Z  naszego  punktu  widzenia,  najwa¿niejsza  jest

informacja  o  typie  argumentu.  Oznaczenia  po-

szczególnych  typów  przedstawia  tabela  6.  Nie

sugeruj  siê  zbyt  mocno  podanymi  tam  typami

zmiennych.  Najwa¿niejsze  jest  zachowanie  ich

rozmiaru. Pod tym wzglêdem int oraz unsigned

int s¹ identyczne.

Przydatne flagi zamieœci³em w tabeli 7.

Nasz  kompilator  udostêpnia  tylko  jeden

modyfikator: ‘l’ oznaczaj¹cy, ¿e zamiast zmien-

nej typu int podajemy zmienn¹ typu long int.

Znaczenie precyzji oraz szerokoœci wyjaœnia

dodatkowa, niewielka ramka.

printf – pola precyzja oraz szerokoœæ

Znaczenie pola precyzji zmienia siê zale¿nie od typu.

Dla typów zmiennoprzecinkowych oznacza ono liczbê

miejsc  po  przecinku.  Dla  typów  numerycznych  –

minimaln¹ liczbê cyfr (dope³nienie zerami, niezale¿-

nie od flagi ‘ ‘). Dla ³añcuchów oznacza maksymaln¹

liczbê znaków, jaka ma zostaæ wypisana.

Jeœli d³ugoœæ napisu tworzonego przez dane prze-

kszta³cenie jest mniejsza ni¿ szerokoœæ, dodawane s¹

spacje, wzglêdnie zera (flaga ‘0’) po lewej lub prawej

(flaga  ‘-’)  stronie  napisu.  Parametr  ten  nigdy  nie

powoduje przyciêcia wyniku.

Rys. 40 Dzia³anie

programu 
z listingu 57

Tabela 6 – oznaczenia typów w ³añcuchu

formatowania

Tabela 7 – flagi w ³añcuchu formatowania

background image

sobie  –  w  pamiêci  programu...  Bardzo  siê 

z  tego  pytania  cieszê.  Jeœli  jeszcze  tego  nie

zrobi³eœ – popatrz na wynik symulacji. £añ-

cuch zajmuje cenn¹ pamiêæ RAM, jednoczeœ-

nie  do  jej  inicjacji  konieczna  jest  kopia

danych w pamiêci ROM.

Omawiane  funkcje,  tak  jak  wiêkszoœæ 

z  wystêpuj¹cych  w  AVR-GCC,  posiadaj¹

specjalne wersje z przyrostkiem _P. Zmodyfi-

kuj  poprzedni  program  zgodnie  z  listingiem

58.  Konieczne  bêdzie  dodanie  do  programu

nag³ówka  <avr\pgmspace.h>.  Efekt  zmiany

mo¿na zaobserwowaæ w symulacji na rysun-

ku 42. Od strony funkcjonalnej nie powinny

pojawiæ siê widoczne zmiany. 

Na identycznej zasadzie mo¿esz zmodyfi-

kowaæ pierwszy z programów.

Podsumowanie

Dziœ poznaliœmy bardzo wa¿n¹ funkcjê z bib-

lioteki  standardowej  C.  Wykorzystaliœmy  j¹ 

w jeden z najprostszych sposobów. Praktyka

jest jednak taka, ¿e w AVR-GCC, standardo-

we  funkcje  wejœcia/wyjœcia,  dzia³aj¹ce  na

domyœlnych  strumieniach  nie  zosta³y  dobrze

zoptymalizowane.  Musimy  liczyæ  siê  z  tym,

¿e jest to jednak narzêdzie darmowe i czasami

daje to odczuæ. Jest jednak szansa na poprawê

– mia³em okazjê testowaæ najnowsze bibliote-

ki i ich dzia³anie rzeczywiœcie zosta³o popra-

wione.  Jednak  dopóki  nie  powstanie  nowa

wersja  ca³ego  pakietu,  zmiana  bibliotek

wymaga  rêcznych  modyfikacji.  W  najbli¿-

szym  odcinku  bêdziemy  pracowaæ  na  stru-

mieniach innych ni¿ domyœlne – okazuje siê,

¿e funkcje te s¹ lepiej optymalizowane, jeœli

chodzi  o  rozmiar  kodu.  Dodatkowo  daje  to

mo¿liwoœæ  wykorzystania  tych  samych  pod-

programów  do  wysy³ania  danych  przez

RS232 czy na LCD, co sprawia, ¿e poznawa-

na biblioteka staje siê coraz ciekawsza.

Rados³aw Koppel

radoslaw.koppel@elportal.pl

"$

Programowanie

Elektronika dla Wszystkich

Rys. 41 – przesy³anie argumentów do funkcji printf

Rys. 42 Efekt umieszczenia ³añcucha formatowania w pamiêci programu

Listing 57 – wykorzystanie funkcji printf

iinntt

main((

vvooiidd

))

{{

iinntt

a ==

1234

;;

iinntt

b ==

0xff

;;

((......))

fdevopen((rs_put,, rs_get,,

0

));;

printf((

„a(%%d)=%d\r\n”

„a(%%x)=%x\r\n”

„a(%%X)=%X\r\n”

„b(%%#x)=%#x\r\n”

„b(%%o)=%o\r\n”

,,

a,, a,, a,, b,, b));;

}}

Listing 58 – wykorzystanie pamiêci programu 

dla ³añcucha formatowania

printf_P((PSTR((

„a(%%d)=%d\r\n”

„a(%%x)=%x\r\n”

„a(%%X)=%X\r\n”

„b(%%#x)=%#x\r\n”

„b(%%o)=%o\r\n”

)),,

a,, a,, a,, b,, b));;

R

 

E

 

K

 

L

 

A

 

M

 

A

Zastosowanie: Œrodek penetruj¹cy i smaru-

j¹cy,  przenikaj¹cy  rdzê,  wypieraj¹cy  wodê,

myj¹cy z brudu i kurzu

Opis: CRC 5-56 - wielofunkcyjny preparat dla

potrzeb  serwisowych.  Œrodek  penetruj¹cy  i

smaruj¹cy,  przenikaj¹cy  rdzê,  wypieraj¹cy

wodê,  myj¹cy  z  brudu  i  kurzu.  Sk³ada  siê  z

oleju  parafinowego,  organicznych  inhibitorów

korozji co pozwala na utworzenie bariery chro-

ni¹cej przed dostêpem wody i tlenu.

W³asnoœci:

n

szybko  penetruje,  wnikaj¹c  w  najmniejsze

pory,  szczeliny  w  rozwiniêtej  powierzchni-

dobre  w³asnoœci  smarne-  wypiera  wilgoæ 

z uk³adów elektrycznych i zap³onowych 

n

luzuje zardzewia³e po³¹czenia

n

tworzy  cienk¹  warstwê  ochronn¹,  przeciw-

dzia³aj¹ca korozji wywo³anej wp³ywami atmos-

ferycznymi

n

nie oddzia³uje z metalami i ich stopami

n

nie oddzia³uje z wiêkszoœci¹ plastików, gum,

powierzchni  lakierowanych  (w  razie  w¹tpli-

woœci - zalecany test technologiczny)

n

opakowania aerozolowe wyposa¿one s¹ w

zawór 360° dzia³ania oraz cienk¹ rurkê aplika-

cyjn¹.

n

Gaz  pêdny  -  niepalny  CO2  -  co  skutkuje

97% wykorzystaniem aktywnego preparatu 

Sposób u¿ycia:

n

Na³o¿yæ preparat i pozwoliæ na jego penet-

racjê

n

Dla  uruchomienia  zawilgoconego  silnika,

nanieœæ preparat na cewkê i przewody zap³onu

n

W przestrzeniach o trudnym dostêpie u¿yæ

rurki aplikacyjnej

n

W razie potrzeby CRC 5-56 mo¿na usun¹æ,

zmyæ  wykorzystuj¹c  CRC  Brakleen  lub  CRC

Quickkleen
Dane techniczne (bez gazu pêdnego)

Kolor . . . . . . . . . . . . . . . przeŸroczysta ciecz 

o lekko bursztynowym zabarwieniu

Ciê¿ar w³aœciwy (20°C) . . . . . . . . 0,82 g/cm

3

Punkt zamarzania . . . . . . . . . . . . . .  < -50°C

Punkt zap³onu . . . . . . . . . . . . . . . . . . .  78°C

Gruboœæ warstwy (24 godz., 20°C) . . . .  1-2u

Wydajnoœæ z 1l (20°C ) . . . . . . . . . . .  100m

2

Odpornoœæ termiczna . . . . . . . . . . . . .  120°C 

(150°C - nara¿enie chwilowe)

CRC 5−56 − wielofunkcyjny preparat dla potrzeb serwisowych

Zamówienia przyjmuje Dział Handlowy AVT, 01−939 Warszawa, ul. Burleska 9, tel. (22) 568 99 50, fax (22) 568 99 55, e−mail: handlowy@avt.pl

w w w. s k l e p . a v t . p l

200 ml

kod handlowy:

KON36

cena:

10 z³