<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "/usr/share/sgml/docbook/dtd/xml/4.5/docbookx.dtd" [
<!ENTITY phl SYSTEM "author.xml">
<!ENTITY legal SYSTEM "legal.xml">
<!ENTITY sdcc_configure SYSTEM "sdcc_configure.xml">
<!ENTITY sdcc_version SYSTEM "sdcc_version.xml">
<!-- various urls --><!ENTITY url.sourceforge "<ulink url='http://www.sourceforge.net/'>
  SourceForge</ulink>">
<!ENTITY url.rute.fr "<ulink url='http://www.loligrub.be/contrib/tlepoint/BASE/version-internet.html'>Linux&nbsp;-
  Base d'administration pour le superutilisateur</ulink>">
<!ENTITY url.cygwin "<ulink url='http://www.cygwin.com/'>Cygwin</ulink>">
<!ENTITY url.wiki.bash "<ulink url='http://fr.wikipedia.org/wiki/Bash'><wordasword>shell</wordasword>&nbsp;<application>Bash</application></ulink>">
<!ENTITY url.wiki.make "<ulink url='http://fr.wikipedia.org/wiki/Make'><application>make</application></ulink>">
<!-- GNU/Linux urls --><!ENTITY url.debian "<ulink url='http://www.debian.org/'>
  Debian</ulink>">
<!ENTITY url.gpl "<ulink url='http://www.gnu.org/philosophy/license-list.html'>
  General Public License</ulink>">
<!-- GNU tools urls --><!ENTITY url.gcc "<ulink url='http://gcc.gnu.org/'>
  compilateur <application>gcc</application></ulink>">
<!ENTITY url.gdb "<ulink url='http://www.gnu.org/software/gdb/'>
  <wordasword>debugger</wordasword> <application>gdb</application></ulink>">
<!ENTITY url.make "<ulink url='http://www.gnu.org/software/make/'>
  <application>make</application></ulink>">
<!-- Windoze tools urls --><!ENTITY url.dev-cpp "<ulink url='http://www.bloodshed.net/devcpp.html'>
  Dev-Cpp</ulink>">
<!ENTITY url.tidownloader "<ulink url='http://www.ti.com/litv/zip/sbac018c'>
  Software for Programming the Flash Memory Using the Serial Port
  v1.3.4 (Rev. C) (sbac018c.zip, 2381 KB )</ulink>">
<!-- SDCC urls --><!ENTITY url.sdcc "<ulink url='http://sdcc.sf.net/'>
  SDCC&nbsp;-&nbsp;Small&nbsp;Device&nbsp;C&nbsp;Compiler</ulink>">
<!ENTITY url.sdccman "<ulink url='http://sdcc.sourceforge.net/doc/sdccman.pdf'>
  SDCC&nbsp;Compiler&nbsp;User&nbsp;Guide</ulink>">
<!-- MSC1210 urls --><!ENTITY url.msc1210evm "<ulink url='http://focus.ti.com/docs/toolsw/folders/print/msc1210evm.html'>
  Full EVM for use with the MSC1210</ulink>">
<!ENTITY url.msc1210.sbau101a "<ulink url='http://www.ti.com/litv/pdf/sbau101a'>
  MSC121x User's Guide (Rev. A)</ulink>">
<!ENTITY url.msc1210.sbaa109a "<ulink url='http://www.ti.com/litv/pdf/sbaa109a'>
  MSC12xx Programming with SDCC</ulink>">
<!ENTITY url.msc1210.sbaa085c "<ulink url='http://www.ti.com/litv/pdf/sbaa085c'>
  MSC1210 ROM Routines (Rev. C)</ulink>">
<!-- I2C urls --><!ENTITY url.i2c.spec "<ulink url='http://www.nxp.com/acrobat_download/literature/9398/39340011.pdf'>THE&nbsp;I²C-BUS&nbsp;SPECIFICATION&nbsp;VERSION&nbsp;2.1 JANUARY&nbsp;2000</ulink>">
<!ENTITY url.i2c.pcf8591 "<ulink url='http://www.nxp.com/acrobat_download/datasheets/PCF8591_6.pdf'>PCF8591&nbsp;8-bit&nbsp;A/D and&nbsp;D/A&nbsp;converter</ulink>">
<!-- source code urls --><!ENTITY url.msc1210.h "<ulink url='http://svn.sourceforge.net/viewvc/sdcc/trunk/sdcc/device/include/mcs51/msc1210.h?view=markup'>msc1210.h</ulink>">
<!ENTITY url.rom1210.asm "<ulink url='http://www.linux-france.org/prj/embedded/sources/rom1210.asm'>rom1210.asm</ulink>">
<!ENTITY url.rom1210.h "<ulink url='http://www.linux-france.org/prj/embedded/sources/rom1210.h'>rom1210.h</ulink>">
<!ENTITY url.ser_msc1210.h "<ulink url='http://www.linux-france.org/prj/embedded/sources/ser_msc1210.h'>ser_msc1210.h</ulink>">
<!ENTITY url.lcd_msc1210.h "<ulink url='http://www.linux-france.org/prj/embedded/sources/lcd_msc1210.h'>lcd_msc1210.h</ulink>">
<!ENTITY url.iut_msc1210.h "<ulink url='http://www.linux-france.org/prj/embedded/sources/iut_msc1210.h'>iut_msc1210.h</ulink>">
<!ENTITY url.hello_serial.c "<ulink url='http://www.linux-france.org/prj/embedded/sources/hello_serial.tar.bz2'>hello_serial.c</ulink>">
<!ENTITY url.makefile.tpl "<ulink url='http://www.linux-france.org/prj/embedded/sources/Makefile.tpl'>Makefile.tpl</ulink>">
<!ENTITY url.gcc_sizeof.tar.bz2 "<ulink url='http://www.linux-france.org/prj/embedded/sources/gcc_sizeof.tar.bz2'>gcc_sizeof.tar.bz2</ulink>">
<!ENTITY url.sdcc_sizeof.tar.bz2 "<ulink url='http://www.linux-france.org/prj/embedded/sources/sdcc_sizeof.tar.bz2'>sdcc_sizeof.tar.bz2</ulink>">
<!ENTITY url.gcc_fibonacci_single.tar.bz2 "<ulink url='http://www.linux-france.org/prj/embedded/sources/gcc_fibonacci_single.tar.bz2'>gcc_fibonacci_single.tar.bz2</ulink>">
<!ENTITY url.gcc_fibonacci_iterative.tar.bz2 "<ulink url='http://www.linux-france.org/prj/embedded/sources/gcc_fibonacci_iterative.tar.bz2'>gcc_fibonacci_iterative.tar.bz2</ulink>">
<!ENTITY url.sdcc_fibonacci_single.tar.bz2 "<ulink url='http://www.linux-france.org/prj/embedded/sources/sdcc_fibonacci_single.tar.bz2'>sdcc_fibonacci_single.tar.bz2</ulink>">
<!ENTITY url.sdcc_fibonacci_iterative.tar.bz2 "<ulink url='http://www.linux-france.org/prj/embedded/sources/sdcc_fibonacci_iterative.tar.bz2'>sdcc_fibonacci_iterative.tar.bz2</ulink>">
<!ENTITY url.gcc_stdio.tar.bz2 "<ulink url='http://www.linux-france.org/prj/embedded/sources/gcc_stdio.tar.bz2'>gcc_stdio.tar.bz2</ulink>">
<!ENTITY url.sdcc_stdio.tar.bz2 "<ulink url='http://www.linux-france.org/prj/embedded/sources/sdcc_stdio.tar.bz2'>sdcc_stdio.tar.bz2</ulink>">
<!ENTITY url.gcc_printf.tar.bz2 "<ulink url='http://www.linux-france.org/prj/embedded/sources/gcc_printf.tar.bz2'>gcc_printf.tar.bz2</ulink>">
<!ENTITY url.sdcc_printf.tar.bz2 "<ulink url='http://www.linux-france.org/prj/embedded/sources/sdcc_printf.tar.bz2'>sdcc_printf.tar.bz2</ulink>">
<!ENTITY url.hello_lcd.tar.bz2 "<ulink url='http://www.linux-france.org/prj/embedded/sources/hello_lcd.tar.bz2'>hello_lcd.tar.bz2</ulink>">
<!ENTITY url.sdcc_lcd_set_xy.tar.bz2 "<ulink url='http://www.linux-france.org/prj/embedded/sources/sdcc_lcd_set_xy.tar.bz2'>sdcc_lcd_set_xy.tar.bz2</ulink>">
<!ENTITY url.sdcc_switch.tar.bz2 "<ulink url='http://www.linux-france.org/prj/embedded/sources/sdcc_switch.tar.bz2'>sdcc_switch.tar.bz2</ulink>">
<!ENTITY url.sdcc_ttl_1bit.tar.bz2 "<ulink url='http://www.linux-france.org/prj/embedded/sources/sdcc_ttl_1bit.tar.bz2'>sdcc_ttl_1bit.tar.bz2</ulink>">
<!ENTITY url.sdcc_ttl_io_iut.tar.bz2 "<ulink url='http://www.linux-france.org/prj/embedded/sources/sdcc_ttl_io_iut.tar.bz2'>sdcc_ttl_io_iut.tar.bz2</ulink>">
<!ENTITY url.sdcc_port_timings.tar.bz2 "<ulink url='http://www.linux-france.org/prj/embedded/sources/sdcc_port_timings.tar.bz2'>sdcc_port_timings.tar.bz2</ulink>">
]>
<article id="sdcc_course" lang="fr">
<articleinfo>
  <title>Initiation au développement C sur microcontrôleur</title>
  <author>
<!-- $Id: author.xml 1045 2007-01-28 22:12:50Z latu $ -->
  <firstname>Philippe</firstname><surname>Latu</surname>
  <affiliation>
  <orgname>Linux France</orgname>
  <address><email>philippe.latu(at)linux-france.org</email></address>
  </affiliation>
</author>

  <abstract>
    <para>Ce support est une initiation au développement en Langage C sur les
    systèmes embarqués. Cette version s'appuie sur le microcontrôleur MSC1210
    de <trademark>Texas Instruments</trademark>. Le support est destiné aux
    débutants. On présente sommairement l'environnement système, les chaînes de
    développement, le Langage C et on illustre les applications classiques de
    ces systèmes spécialisés.</para>
    <para>Aujourd'hui, la grande majorité des étudiants ont l'habitude
    d'utiliser des systèmes informatiques sans se poser de questions sur la
    présence ou non d'un système d'exploitation qui prend en charge la gestion
    du temps processeur, de la mémoire et des périphériques. Ce document essaie
    d'illustrer les différences entre les deux contextes d'utilisation avec et
    sans noyau de système d'exploitation. Le maximum d'exemples de programmes
    sont présentés dans ces deux contextes.</para>
  </abstract>
  <revhistory>
    <revision>
    <revnumber role="rcs">$Revision: 1153 $</revnumber>
    <date role="rcs">$Date: 2007-06-14 14:25:15 +0200 (jeu, 14 jun 2007) $</date>
    <authorinitials role="rcs">$Author: latu $</authorinitials>
    <revremark>Année universitaire 2006-2007.</revremark>
    </revision>
  </revhistory>
  <keywordset>
    <keyword>sdcc</keyword>
    <keyword>langage C</keyword>
    <keyword>microcontrôleur</keyword>
    <keyword>msc1210</keyword>
    <keyword>msc1210.h</keyword>
    <keyword>rom1210.h</keyword>
    <keyword>rom1210.asm</keyword>
    <keyword>tidownloader</keyword>
  </keywordset>
</articleinfo>

<?custom-pagebreak?>
<sect1 id="sdcc_course.legal_meta">
  <title>Copyright et Licence</title>

<!-- $Id: legal.xml 1045 2007-01-28 22:12:50Z latu $ -->
<literallayout class="monospaced">Copyright (c)  2000,2007 Philippe Latu.
Permission is granted to copy, distribute and/or modify this 
document under the terms of the GNU Free Documentation License, 
Version 1.2 or any later version published by the Free Software
Foundation; with no Invariant Sections, no Front-Cover Texts, 
and no Back-Cover Texts. A copy of the license is included in 
the section entitled "GNU Free Documentation License".
</literallayout>

<literallayout class="monospaced">Copyright (c)  2000,2007 Philippe Latu.
Permission est accordée de copier, distribuer et/ou modifier ce
document selon les termes de la Licence de Documentation Libre GNU
(GNU Free Documentation License), version 1.2 ou toute version
ultérieure publiée par la Free Software Foundation ; sans
Sections Invariables ; sans Texte de Première de Couverture, et
sans Texte de Quatrième de Couverture. Une copie de
la présente Licence est incluse dans la section intitulée
« Licence de Documentation Libre GNU ».
</literallayout>

  <sect2 id="sdcc_course.meta">
    <title>Méta-information</title>
    <para>Cet article est écrit avec 
    <ulink url="http://www.docbook.org"><citetitle>DocBook</citetitle></ulink> XML
    sur un système
    <ulink url="http://www.debian.org"><citetitle>Debian GNU/Linux</citetitle></ulink>.
    Il est disponible en version imprimable aux formats PDF et PostScript :
    <ulink url="http://www.linux-france.org/prj/embedded/telechargement/sdcc_course.pdf">
    <literal>sdcc_course.pdf</literal></ulink>|
    <ulink url="http://www.linux-france.org/prj/embedded/telechargement/sdcc_course.ps.gz">
    <literal>sdcc_course.ps.gz</literal></ulink>.</para>
  </sect2>
</sect1>

<?custom-pagebreak?>
<sect1 id="sdcc_course.avant_propos">
  <title>Avant Propos</title>

<sect2 id="sdcc_course.avant_propos.unix">
  <title>C/C++ &amp; Unix</title>

<para>Le système d'exploitation Unix a été conçu au début des années 70. Le
Langage C a été développé parallèlement à la mise au point de ce système. Sa
première standardisation «de fait» a été publiée dans l'ouvrage de B.W.
KERNIGHAN et D.M. RITCHIE en 1978.</para>

<para>Même si l'évolution des Langages de programmation C puis C++ est liée à
la progression des systèmes Unix, ces langages sont universellement connus et
utilisés. On peut pratiquement affirmer qu'il n'existe pas de plate-forme
informatique actuelle sur laquelle il n'existe pas une chaîne de développement
C/C++.</para>

<para>Le Langage C a été conçu pour de multiples utilisations, il n'offre que
des structures de programme permettant l'ordonnancement séquentiel, des tests,
des boucles et des sous-programmes. Cet aspect, limité en apparence, garantit
la «portabilité» des codes sources écrits en C.</para>

<para>Dans le domaine des systèmes embarqués, le C est le langage de
programmation le plus répandu. Il convient parfaitement au développement des
pilotes de périphériques spécialisés tels que les convertisseurs
analogiques/numériques, les capteurs, etc. Les outils de développement modernes
possèdent des fonctions d'optimisation performantes et le recours au langage
assembleur est devenu inutile.</para>
</sect2>

<sect2 id="sdcc_course.avant_propos.prog">
  <title>Programmation procédurale ou orientée objet</title>

<para>Jusqu'à la fin des années 80, la seule méthode de programmation
utilisable était procédurale ou structurée. Cette approche consiste à
décomposer un problème complexe en un ensemble de tâches ou «procédures»
faciles à réaliser. Les données sont alors choisies en fonction des procédures
qui vont les manipuler.</para>

<para>En fait, cette méthodologie convient parfaitement aux logiciels écrits
par des informaticiens à l'usage des informaticiens.</para>

<para>Curieusement, le développement des outils informatiques à l'usage de non
spécialistes a considérablement augmenté la complexité des programmes. Ces
logiciels de plus en plus sophistiqués ont amené les concepteurs à changer de
démarche. Il est devenu indispensable de penser d'abord aux données et ensuite
aux actions que l'on doit réaliser avec.</para>

<para>Un autre aspect très important dans la conception est la réutilisation des
développements précédents. Ce principe d'héritage permet de construire des
composants logiciels avec des propriétés connues que l'on réutilise suivant ses
besoins. De tels composants peuvent même être complétés lors des évolutions des
applications.</para>

<para>Si la programmation orientée objet n'est pas largement utilisés dans
la mise au point des systèmes embarqués, certains de ses concepts ont été
repris avec succès. La surdéfinition et l'héritage se retrouvent très souvent
dans les développements d'interfaces spécialisées.</para>

<para>Comme le développement de pilotes de périphériques matériels est une
problématique assez éloignée de l'interface utilisateur, le recours à la
programmation orientée objet reste très limité dans ce domaine. Le noyau Linux
est un exemple caractéristique ; il est entièrement développé en Langage
C.</para>
</sect2>

<sect2 id="sdcc_course.avant_propos.ll">
  <title>Logiciels libres</title>

<para>Les évolutions des systèmes d'exploitation basés sur les principes d'Unix
et des langages de programmation C/C++ sont associés au développement de
l'Internet. Tous ces éléments utilisant un modèle de développement ouvert ont
favorisé l'émergence des logiciels libres.</para>

<para>De nombreux concepteurs ont produit des bibliothèques d'objets qu'ils ont
rendu libres d'utilisation à l'aide de la <ulink url="http://www.gnu.org/philosophy/license-list.html">
  General Public License</ulink>. Cette disponibilité
d'outils de très grande qualité a permis à d'autres concepteurs de fournir de
nouveaux outils et etc.</para>

<para>Ainsi, avec un minimum de coordination, on trouve aujourd'hui des
systèmes d'exploitation, des environnements graphiques, des chaînes de
développement et des suites d'applications de plus en plus performantes.</para>

<para>Les principaux outils utilisés dans le présent document sont issus de
projets de logiciels libres. La chaîne de développement <ulink url="http://sdcc.sf.net/">
  SDCC - Small Device C Compiler</ulink> pour
microcontrôleurs en est le meilleur exemple. Voir <xref linkend="sdcc_course.tools.sdcc"/>.</para>
</sect2>
</sect1>

<sect1 id="sdcc_course.dev_os">
  <title>Développement et Système</title>

<para>À l'heure actuelle, la majorité des chaînes de développement suivent le
modèle initié par les outils GNU au milieu des années 1980. Les principes sont
les suivants.</para>

<itemizedlist spacing="compact">
  <listitem>
  <para>Les outils de base comme le compilateur, l'éditeur de liens et le
  debugger, etc. sont des briques logicielles individuelles accessibles au
  niveau <xref linkend="sdcc_course.shell"/>. Ils disposent d'un grand nombre
  d'options ou de commandes permettant de répondre à pratiquement tous les
  besoins.</para>
  </listitem>
  <listitem>
  <para>Ils partagent avec le système d'exploitation de nombreuses
  bibliothèques telles que la ou bibliothèque standard du Langage C courament
  appelée <emphasis>libc</emphasis>. Les fonctions ou les appels systèmes
  fournis par cette bibliothèque sont supportés depuis plus de 25 ans. Elles
  ont donc été largement adoptées sur un très grand nombre de systèmes
  différents.</para>
  </listitem>
  <listitem>
  <para>Les interfaces de développement sont indépendantes des outils. Les
  environnements graphiques utilisateurs ne sont que des interfaces facilitant
  l'utilisation des jeux de commandes des outils GNU. Compte tenu du nombre et
  de la qualité de ces environnements, les développeurs se «composent» souvent
  une interface graphique à la carte.</para>
  </listitem>
</itemizedlist>

<para>Suivant le contexte de développement, les modes d'exploitation diffèrent.
Généralement, on distingue les ordinateurs cibles avec système d'exploitation tels
que les PCs et les ordinateurs cibles sans système d'exploitation comme les
systèmes embarqués qui utilisent des microcontrôleurs spécialisés.</para>

<sect2 id="sdcc_course.dev_os.with">
  <title>Ordinateur cible avec système d'exploitation</title>

<para>Ce contexte correspond aux enseignements «traditionnels» de
programmation. L'utilisateur dispose d'une interface graphique (voir <xref linkend="sdcc_course.tools.dev-cpp"/>) pour éditer, compiler et exécuter les programmes
(voir <xref linkend="sdcc_course.dev_cycle"/>).</para>

<para>En règle générale, lorsque le programme est exécuté sur une machine cible
avec système d'exploitation, les périphériques tels que le clavier, l'écran et
la souris sont toujours disponibles.</para>

<para>Cette situation «confortable» suppose plusieurs couches intermédiaires de
logiciel entre l'utilisateur et le matériel. L'ensemble de ces couches
intermédiaires s'appelle un système d'exploitation. L'image ci-dessous
représente les couches constituant un système d'exploitation.</para>

<mediaobject>
  <imageobject>
    <imagedata fileref="images/os.png" format="PNG" contentwidth="11.5cm" width="12cm"/>
  </imageobject>
  <textobject>
    <phrase>Les couches logicielles d'un système d'exploitation</phrase>
  </textobject>
  <caption>
    <para><ulink url="images/os.png">Les couches logicielles d'un système
    d'exploitation</ulink></para>
  </caption>
</mediaobject>

<variablelist>
  <varlistentry id="sdcc_course.bios">
  <term><acronym>BIOS</acronym></term>
  <term><wordasword>Basic Input Output System</wordasword></term>
  <listitem>
  <para>Ce logiciel ne fait pas vraiment partie du système d'exploitation. À la
  mise sous tension de l'équipement (PC ou autre), son rôle est de recenser les
  ressources matérielles disponibles : type de processeur, quantité de
  mémoire, nombre et type de périphériques de stockage, interfaces réseau,
  écran, clavier, etc. Une fois l'étape de recensement passée, les
  périphériques de stockage sont scrutés un à un à la recherche d'un code
  particulier qui permet le lancement du système d'exploitation.</para>
  </listitem>
  </varlistentry>
  <varlistentry id="sdcc_course.kernel">
  <term>Kernel</term>
  <term>noyau</term>
  <listitem>
  <para>Ce logiciel constitue le coeur du système d'exploitation. Il assure 3
  fonctions principales :</para>
    <variablelist>
      <varlistentry id="sdcc_course.kernel.io">
      <term>La gestion des entrées-sorties</term>
      <listitem>
      <para>Le noyau intègre ses propres fonctions de recensement des
      ressources matérielles. Il peut très bien ne tenir aucun compte des
      informations fournies par le <acronym>BIOS</acronym>. Le noyau doit
      posséder un pilote pour chaque périphérique d'entrée-sortie «présent»
      dans le système.</para>
      <para>Un noyau moderne doit aussi gérer l'ajout et le retrait de
      périphériques en cours de fonctionnement. On parle de branchement «à
      chaud» ou <wordasword>hotplug</wordasword>.</para>
      </listitem>
      </varlistentry>
      <varlistentry>
      <term>La gestion des accès mémoire</term>
      <listitem>
      <para>Un système peut intégrer différents types de mémoires dynamiques et
      le noyau doit gérer ces différents éléments comme un tout cohérent. Les
      programmes doivent accéder à ce «plan mémoire» de façon transparente en
      utilisant des segments alloués en fonction de leurs besoins.</para>
      <para>De plus, si le plan mémoire est partagé entre plusieurs programmes,
      le noyau doit utiliser un algorithme spécifique de planification et de
      distribution des accès entre ces programmes. On parle alors de système
      multi-tâches. <emphasis>Linux</emphasis> est un exemple caractéristique
      de ce type de noyau.</para>
      </listitem>
      </varlistentry>
      <varlistentry>
      <term>La gestion du temps processeur</term>
      <listitem>
      <para>Le temps du processeur doit être partagé entre les programmes comme
      le plan mémoire. On découpe donc ce temps processeur en tranches qui sont
      attribuées aux programmes à la demande.</para>
      <para>La fonction correspondante du noyau est appelée ordonnanceur ou
      <wordasword>scheduler</wordasword>. Sur un système moderne dans lequel
      les temps d'accès aux périphériques et les transmissions réseau sont
      suffisamment rapides, c'est l'ordonnanceur qui est le «maître» du temps.
      On peut le comparer à une horloge de réglage du rythme cardiaque d'un
      système.</para>
      </listitem>
      </varlistentry>
    </variablelist>
  </listitem>
  </varlistentry>
  <varlistentry id="sdcc_course.shell">
  <term>Shell</term>
  <listitem>
    <variablelist>
      <varlistentry id="sdcc_course.shell.console">
      <term>L'interface des commandes utilisateur</term>
      <listitem>
      <para>Un <wordasword>Shell</wordasword> permet à l'utilisateur du système
      de lancer des programmes ou commandes. On parle de commande lorsqu'il
      s'agit de «manipuler» le système : lister les fichiers d'un
      répertoire, afficher la quantité de mémoire disponible, etc.</para>
      <para>Sur les systèmes multi-tâches et multi-utilisateurs tels que
      GNU/Linux et *BSD, de nombreux <wordasword>Shells</wordasword> peuvent
      être actifs en même temps. À l'inverse, sur les systèmes mono-tâches
      hérités du DOS (<wordasword>Disk Operating System</wordasword>) de
      <trademark>Micro$oft</trademark>, on ne dispose que d'un
      <wordasword>Shell</wordasword> unique.</para>
      </listitem>
      </varlistentry>
      <varlistentry id="sdcc_course.shell.sequence">
      <term>Le séquencement entre le les programmes</term>
      <listitem>
      <para>Lorsque plusieurs programmes doivent être exécutés sur un même
      système, il est fréquent que ces programmes échangent des paramètres où
      se lancent en fonction d'actions réalisées par d'autres programmes.
      Lorsque l'on utilise une interface graphique et que l'on clique sur une
      fenêtre pour l'activer, on réalise une opération de ce type.</para>
      </listitem>
      </varlistentry>
    </variablelist>
  </listitem>
  </varlistentry>
  <varlistentry>
  <term>Application</term>
  <listitem>
  <para>À ce niveau on trouve généralement l'interface graphique utilisateur
  qui permet de réaliser les manipulations système de façon plus intuitives
  qu'au niveau <wordasword>Shell</wordasword>. À ce gestionnaire de fenêtres
  sont associées toutes les applications usuelles d'un système
  généraliste : navigation Web, traitement de textes, Environnement de
  développement intégré (comme <xref linkend="sdcc_course.tools.dev-cpp"/>), etc.</para>
  <para>C'est aussi à ce niveau que les programmes développés par nos soins
  sont exécutés.</para>
  </listitem>
  </varlistentry>
</variablelist>
</sect2>

<sect2 id="sdcc_course.dev_os.without">
  <title>Ordinateur cible sans système d'exploitation</title>

<para>Ce contexte correspond aux enseignements pratiques d'informatique
industrielle. Si l'utilisateur dispose d'une interface graphique de
développement intégrée, le logiciel développé doit être exécuté sur un système
spécialisé. On parle de système embarqué dédié à la réalisation de fonctions
spécifiques. Il est rare que ces systèmes disposent d'un écran et d'un
clavier.</para>

<para>Contrairement à la situation précédente avec système d'exploitation, les
conditions de développement sont moins «confortables». Ceci-dit, comme le
nombre de couches logicielles est nettement réduit, la description est plus
simple.</para>

<mediaobject>
  <imageobject>
    <imagedata fileref="images/eos.png" format="PNG" contentwidth="10.5cm" width="11cm"/>
  </imageobject>
  <textobject>
    <phrase>Les couches logicielles d'un système embarqué simple</phrase>
  </textobject>
  <caption>
    <para><ulink url="images/eos.png">Les couches logicielles d'un système
    embarqué simple</ulink></para>
  </caption>
</mediaobject>

<variablelist>
  <varlistentry id="sdcc_course.monitor">
  <term>Le moniteur</term>
  <listitem>
  <para>Le seul point commun entre le moniteur et le <acronym>BIOS</acronym> se
  situe au niveau du lancement de programme. Là où le <acronym>BIOS</acronym>
  identifie le code de lancement du système sur le premier secteur d'un
  périphérique, le moniteur identifie l'adresse de lancement d'une application
  dans le plan mémoire du microcontrôleur.</para>
  <para>Sur un système spécialisé avec microcontrôleur, la configuration
  matérielle est figée. Il est donc totalement inutile de procéder à un
  recensement des ressources du système.</para>
  <para>Le premier rôle d'un moniteur est d'assurer le téléchargement des
  programmes entre le système de développement (généralement un PC) et le
  système spécialisé (le microcontrôleur). Ce téléchargement est réalisé à
  l'aide une liaison série ou réseau.</para>
  <para>Les microcontrôleurs récents intègrent en plus du moniteur un ensemble
  de sous-programmes (<wordasword>routines</wordasword>) qui offrent des
  fonctions simples de pilotage de périphériques et de manipulations de la
  mémoire intégrée au composant.</para>
  </listitem>
  </varlistentry>
  <varlistentry>
  <term>Application</term>
  <listitem>
  <para>À ce niveau le microcontrôleur exécute le ou les programme(s)
  utilisateur. Comme on n'utilise pas de noyau, les programmes utilisateur
  doivent intégrer directement le pilotage des périphériques : liaison
  série, affichage LCD, conversion analogique/numérique, capteurs, etc.</para>
  </listitem>
  </varlistentry>
</variablelist>
</sect2>
</sect1>

<?custom-pagebreak?>
<sect1 id="sdcc_course.dev_cycle">
  <title>Cycle de développement</title>

<para>Si tous les programmes que vous avez à écrire fonctionnaient parfaitement
du premier coup le cycle de développement se résumerait aux 3 étapes
suivantes :</para> 

<orderedlist spacing="compact">
  <listitem>
  <para>Écrire le code source,</para>
  </listitem>
  <listitem>
  <para>le compiler,</para>
  </listitem>
  <listitem>
  <para>lancer le programme.</para>
  </listitem>
</orderedlist>

<para>Malheureusement, quelque soit le programme et quelque soit le niveau
d'expérience en programmation, on rencontre toujours des erreurs à chacune des
étapes énoncées ci-dessus. Le cycle de développement devient alors le
suivant :</para>

<mediaobject>
  <imageobject>
    <imagedata fileref="images/dev-cycle.png" format="PNG" contentwidth="11.5cm" width="12cm"/>
  </imageobject>
  <textobject>
    <phrase>Synoptique du cycle de développement</phrase>
  </textobject>
  <caption>
    <para><ulink url="images/dev-cycle.png">Synoptique du cycle de
    développement</ulink></para>
  </caption>
</mediaobject>
</sect1>

<?custom-pagebreak?>
<sect1 id="sdcc_course.hello">
  <title>Un premier programme : «Hello, World!»</title>

<para>Pour illustrer les contextes et le cycle de développement présentés
ci-avant, on prend un premier exemple de programme très connu : afficher
«Hello, World!» à l'écran.</para>

<para>La «mise au point» de ce programme simpliste sert aussi à prendre en main
les outils de la chaîne de développement.</para>

<sect2 id="sdcc_course.hello.source">
  <title>Codes source</title>

<para>Voici le code source du premier programme <filename>hello.c</filename>
sous sa forme «usuelle».</para>

<example id="sdcc_course.hello.source.gcc">
  <title>Affichage de la chaîne «Hello, World!» sur GNU/Linux avec GCC</title>
<screen width="80">#include &lt;stdio.h&gt; <co id="sdcc_course.hello.source.include"/>

int main() { <co id="sdcc_course.hello.source.main"/>

        printf ("Hello, World!\n"); <co id="sdcc_course.hello.source.printf"/>
        return 0; <co id="sdcc_course.hello.source.return"/>
}
</screen>
</example>

<calloutlist>
  <callout arearefs="sdcc_course.hello.source.include">
  <para><code>#include &lt;stdio.h&gt;</code> : inclusion des
  prototypes de sous-programmes de la bibliothèque standard d'entrée-sortie
  (<acronym>stdio</acronym> ou <wordasword>standard input
  output</wordasword>).</para>
  <para>D'une manière générale, pour que l'on puisse utiliser les fonctions
  d'une bibliothèque, il faut que les prototypes (ou en-têtes) de ces
  fonctions soient parcourus par le pré-processeur (voir <xref linkend="sdcc_course.dev_cycle"/>). Si cette condition est satisfaite, le
  pré-processeur «connaît» la liste des paramètres possibles d'une fonction et
  leurs types. Il peut ensuite contrôler que les appels à ces fonctions sont
  conformes.</para>
  <para>Cet exemple de programme utilise la fonction
  <function>printf</function> qui appartient à la bibliothèque
  <acronym>stdio</acronym>.</para>
  </callout>
  <callout arearefs="sdcc_course.hello.source.main">
  <para><code>int main() {</code> : début du programme principal.</para>
  <para>En C, le programme principal peut être assimilé à une «fonction comme
  les autres» à qui on peut passer des paramètres (entre les parenthèses)
  depuis le <xref linkend="sdcc_course.shell"/> et qui renvoie à ce même <xref linkend="sdcc_course.shell"/> une indication sur ses conditions d'exécution (un
  nombre entier).</para>
  <para>L'accolade <literal>'{'</literal> est le délimiteur de début des
  instructions du programme principal.</para>
  </callout>
  <callout arearefs="sdcc_course.hello.source.printf">
  <para><code>printf ("Hello, World!\n");</code> : appel de la fonction
  <function>printf</function> de la bibliothèque standard
  d'entrée-sortie.</para>
  <para>Une chaîne de caractères est délimitée par des guillemets et les
  caractères spécifiques sont précédés par <literal>'\'</literal>. On parle de
  caractères d'échappement. Dans cet exemple, <literal>'\n'</literal>
  correspond au saut de ligne.</para>
  <para>Les instructions sont séparées par le caractère
  <literal>';'</literal>.</para>
  </callout>
  <callout arearefs="sdcc_course.hello.source.return">
  <para><code>return 0;</code> : valeur renvoyée au système d'exploitation
  (via le <xref linkend="sdcc_course.shell"/>) en fin de programme.</para>
  <para>La valeur <literal>0</literal> correspond à une sortie «sans erreur» du
  programme.</para>
  <para>Cette instruction n'a de sens que lorsque le programme est exécuté via
  un système d'exploitation avec lequel il est possible d'échanger des
  informations.</para>
  </callout>
</calloutlist>

<para>Voici le code source du même premier programme
<filename>ser_hello.c</filename> sous sa forme «embarquée». Le code n'est pas
aussi simple que dans le cas précédent. Comme indiqué dans la <xref linkend="sdcc_course.dev_os.without"/> on ne dispose pas de noyau dans ce
contexte. Le programme doit donc intégrer le pilotage du périphérique
d'affichage. Ici, il s'agit de la liaison série qui est utilisée pour
«l'affichage» de la chaîne «Hello, World!».</para>

<mediaobject>
  <imageobject>
    <imagedata fileref="images/no_os_dev.png" format="PNG" contentwidth="11.5cm" width="12cm"/>
  </imageobject>
  <textobject>
    <phrase>Environnement de développement sur système embarqué</phrase>
  </textobject>
  <caption>
    <para><ulink url="images/no_os_dev.png">Environnement de développement sur
    système embarqué</ulink></para>
  </caption>
</mediaobject>

<para>Avec le synoptique ci-dessus, on développe (voir <xref linkend="sdcc_course.dev_cycle"/>) le programme sur le PC. Une fois que l'on a
obtenu le fichier contenant le code exécutable du programme, on le transfère
via la liaison série à l'aide du <link linkend="sdcc_course.monitor">moniteur</link>. Enfin, après avoir réinitialisé le
microcontrôleur en mode exécution, le programme utilisateur est lancé.</para>

<para>En mode exécution, le programme utilisateur peut piloter la liaison série
de façon complètement autonome si on lui fournit les sous-programmes
nécessaires. C'est le cas de l'exemple de code source ci-dessous.</para>

<example id="sdcc_course.hello.source.sdcc">
  <title>Affichage de la chaîne «Hello, World!» avec un microcontrôleur MSC1210
  &amp; SDCC</title>
<screen width="80">#include &lt;stdio.h&gt; <co id="sdcc_course.ser_hello.source.include"/>
#include &lt;msc1210.h&gt;
#include "ser_msc1210.h"

// (sur)définition du sous-programme putchar utilisé par printf
void putchar(char c) { <co id="sdcc_course.ser_hello.source.putchar"/>
  ser_putc(c);
  }

void main(void) { <co id="sdcc_course.ser_hello.source.main"/>

	// Appuyer sur &lt;Entrée&gt; pour ajuster automatiquement
	// le débit de la liaison 
        autobaud(); <co id="sdcc_course.ser_hello.source.autobaud"/>

        // Initialisations pour SDCC
	EA=1;

	// Affichage sur le terminal
        printf("Hello, World!"); <co id="sdcc_course.ser_hello.source.printf"/>
        putcr();

        while(1); <co id="sdcc_course.ser_hello.source.while1"/>
}
</screen>
</example>

<calloutlist>
  <callout arearefs="sdcc_course.ser_hello.source.include">
  <para>Comme indiqué dans le premier cas, les directives <code>#include</code>
  servent à inclure des définitions pour le pré-processeur. Dans le cas
  présent, 3 fichiers de définitions sont utilisés.</para>
  <itemizedlist spacing="compact">
    <listitem>
    <para><filename>stdio.h</filename> : fichier d'en-tête contenant les
    prototypes des fonctions d'entrées-sorties standard. Si ce fichier porte le
    même nom que celui donné dans le premier fichier source, le catalogue des
    sous-programmes mis à disposition sur un microcontrôleur est nettement
    réduit relativement au cas général d'une machine avec système
    d'exploitation.</para>
    <para>Dans le cas présent, ce fichier fournit le prototype de la fonction
    <function>printf</function> utilisée pour émettre la chaîne de caractères
    depuis le microcontrôleur sur la liaison série.</para>
    </listitem>
    <listitem>
    <para><filename>msc1210.h</filename> : fichier d'en-tête contenant les
    définitions des registres des microcontrôleurs de la famille
    <acronym>MSC12xx</acronym>.</para>
    </listitem>
    <listitem>
    <para><filename>ser_msc1210.h</filename> : fichier d'en-tête contenant
    les prototypes des sous-programmes intégrés dans la mémoire
    <acronym>ROM</acronym> du composant microcontrôleur. Dans cet exemple, ce
    sont les fonctions de pilotage de la liaison série qui sont utiles :
    <function>autobaud</function> et <function>ser_putc</function>.</para>
    <para>Le fait que ce fichier soit noté «entre guillemets» indique qu'il
    s'agit d'un fichier local qui n'est pas fourni avec la chaîne de
    développement. Voir le fichier <xref linkend="sdcc_course.soft.ser_msc1210.h"/>
    et la documentation <xref linkend="sdcc_course.docs.msc1210.rom.routines"/>
    sur ces fonctions intégrées.</para>
    </listitem>
  </itemizedlist>
  </callout>
  <callout arearefs="sdcc_course.ser_hello.source.putchar">
  <para><code>void putchar(char c);</code> : surdéfinition de la
  fonction d'affichage d'un caractère.</para>
  <para>Cette fonction fait «normalement» partie de la bibliothèque standard et
  son rôle est d'envoyer un caractère à l'écran. Dans le cas présent, on
  utilise une nouvelle définition de cette fonction. Son rôle est maintenant
  d'envoyer le caractère sur la liaison série. La fonction
  <function>tx_byte</function> fait partie de la bibliothèque intégrée du
  microcontrôleur. Sa définition est donnée dans le fichier d'en-tête
  <filename>rom1210.h</filename>. Voir <xref linkend="sdcc_course.docs.msc1210.rom.routines"/>.</para>
  <para>Le mot clé <code>void</code> signifie que la fonction ne renvoie aucun
  paramètre. Le paramètre d'entrée <code>c</code> est défini comme étant de
  type caractère (représenté sur un octet) par le mot clé
  <code>char</code>. Voir <xref linkend="sdcc_course.c_language.type"/></para>
  </callout>
  <callout arearefs="sdcc_course.ser_hello.source.main">
  <para><code>void main(void) {</code> : début du programme
  principal.</para>
  <para>Par différence avec le premier programme, on constate avec l'emploi des
  mots clé <code>void</code> qu'aucun paramètre n'est passé en entrée et
  qu'aucun paramètre n'est renvoyé en sortie. Ce codage est tout à fait normal
  dans un contexte sans système d'exploitation. Ce programme sera le seul
  exécuté sur le microcontrôleur. Il n'aura donc pas à échanger avec un autre
  logiciel.</para>
  </callout>
  <callout arearefs="sdcc_course.ser_hello.source.autobaud">
  <para><code>autobaud();</code> : appel de la fonction de détection
  automatique du débit sur la liaison série.</para>
  <para>Cette fonction est très pratique. Le programme reste en attente d'un
  appui sur la touche &lt;Entrée&gt; du système de développement (le PC) pour
  déterminer le débit de transmission en bauds. Sans cette «attente», le
  programme se lancerait directement après le <wordasword>reset</wordasword> du
  microcontrôleur ce qui est trop rapide si des manipulation sont à effectuer
  manuellement sur le système embarqué.</para>
  </callout>
  <callout arearefs="sdcc_course.ser_hello.source.printf">
  <para><code>printf("Hello World !");</code> : appel de la fonction
  <function>printf</function>.</para>
  <para>Cet appel de fonction se présente comme dans le cas du premier
  programme excepté pour le traitement du saut de ligne en fin de chaîne de
  caractères. Avec la liaison série, on est obligé d'envoyer deux caractères
  spécifiques : <literal>'\r'</literal> (retour chariot ou
  <wordasword>Carriage Return</wordasword> ou <acronym>CR</acronym>) pour
  renvoyer le curseur en début de ligne et <literal>'\n'</literal> (saut de
  ligne ou <wordasword>Line Feed</wordasword> ou <acronym>LF</acronym>) pour
  descendre le curseur d'une ligne. Cette opération est réalisée par l'appel à
  la fonction <function>putcr()</function>.</para>
  </callout>
  <callout arearefs="sdcc_course.ser_hello.source.while1">
  <para><code>while(1);</code> : boucle «d'attente» infinie.</para>
  <para>Comme le programme est la seule application en cours d'exécution sur le
  microcontrôleur, et qu'il n'y a plus d'opération à effectuer, on place le
  processeur dans un état d'attente infinie grâce à cette instruction de
  bouclage. C'est une technique usuelle qui permet de s'assurer que le
  processeur ne cherche pas à interpréter le contenu de la mémoire située après
  l'application utilisateur comme un programme.</para>
  </callout>
</calloutlist>
</sect2>

<sect2 id="sdcc_course.hello.with_os.xp">
  <title>Compilation &amp; exécution sur Windows XP</title>

<para>Ce contexte est décrit dans la <xref linkend="sdcc_course.dev_os.with"/>.</para>

<para>On distingue deux familles de systèmes d'exploitation : Windows et
GNU/Linux.</para>

<mediaobject>
  <imageobject>
    <imagedata fileref="images/xp.hello.png" format="PNG" contentwidth="11.5cm" width="12cm"/>
  </imageobject>
  <textobject>
    <phrase>Copie d'écran Dev-Cpp &amp; exécution Hello, World!</phrase>
  </textobject>
  <caption>
    <para><ulink url="images/xp.hello.png">Copie d'écran Dev-Cpp &amp;
    exécution Hello, World!</ulink></para>
  </caption>
</mediaobject>

<para>Pour que le résultat de l'exécution du programme soit «visible», on a
ajouté l'instruction <code>system("pause");</code> qui demande à
l'utilisateur d'appuyer sur une touche. Sans cette instruction, le <xref linkend="sdcc_course.shell"/> serait refermé dès la fin de l'exécution du
programme et le message ne serait pas visible.</para>
</sect2>

<sect2 id="sdcc_course.hello.with_os.linux">
  <title>Compilation &amp; exécution sur GNU/Linux</title>

<para>Les outils de la chaîne de développement sont installés par défaut avec
le système d'exploitation. On peut donc appeler directement le compilateur
<application>gcc</application> (voir <xref linkend="sdcc_course.tools.gcc"/>.</para>

<screen width="80">phil@b0x:~/src$ cat hello.c
#include &lt;stdio.h&gt;

int main() {

        printf ("Hello, World!\n");
        return 0;
}

phil@b0x:~/src$ gcc hello.c
phil@b0x:~/src$ ./a.out
Hello, World!
phil@b0x:~/src$
</screen>

<para>Dans ce contexte, on commence par ouvrir un nouveau <xref linkend="sdcc_course.shell"/> dans lequel on effectue toutes les opérations
individuelles : édition du code source, compilation et exécution.</para>
</sect2>

<sect2 id="sdcc_course.hello.msc1210.xp">
  <title>Compilation sur Windows &amp; exécution sur cible MSC1210</title>

<para>Ici, les programmes sont développés sur un <acronym>PC</acronym> et
exécutés sur la machine cible. C'est le contexte décrit dans la <xref linkend="sdcc_course.dev_os.without"/>.</para>

<para>Pour l'exemple de programme retenu, on choisit d'afficher la chaîne de
caractères sur le terminal du système de développement (ie. le
<acronym>PC</acronym>) via une liaison série.</para>

<variablelist>
  <varlistentry id="sdcc_course.hello.msc1210.xp.devel">
  <term>Outils de développement</term>
  <listitem>
  <para>Pour que la chaîne de développement <link linkend="sdcc_course.tools.sdcc">SDCC</link> soit plus facile à utiliser sur
  un système d'exploitation <trademark>Microsoft</trademark>, il est vivement
  conseillé de reconstituer un environnement de travail
  <wordasword>GNU/Linux-like</wordasword> à l'aide des outils
  <ulink url="http://www.cygwin.com/">Cygwin</ulink>.</para>

  <para>Une fois les outils <ulink url="http://www.cygwin.com/">Cygwin</ulink> installés, on dispose d'un
  <ulink url="http://fr.wikipedia.org/wiki/Bash"><wordasword>shell</wordasword> <application>Bash</application></ulink> et surtout de l'application de contrôle du compilateur
  <ulink url="http://fr.wikipedia.org/wiki/Make"><application>make</application></ulink> qui permet de gérer les dépendances entre les différents
  fichiers sources et en-têtes.</para>

  <para>Après avoir travaillé avec ces outils pendant «un certain temps», il ne
  restera plus qu'une dernière étape à franchir : abandonner le système
  <trademark>Microsoft</trademark> <wordasword>GNU/Linux-like</wordasword> au
  profit d'un véritable système <citetitle>GNU/Linux</citetitle>.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="sdcc_course.hello.msc1210.xp.compilation">
  <term>Compilation avec Windows XP</term>
  <listitem>
    <para>On appelle le compilateur <link linkend="sdcc_course.tools.sdcc">SDCC</link> à partir d'une console.</para>

<mediaobject>
  <imageobject>
    <imagedata fileref="images/sdcc.xp.hello.png" format="PNG" contentwidth="11.5cm" width="12cm"/>
  </imageobject>
  <textobject>
    <phrase>Copie d'écran compilation hello.c sur Windows XP avec SDCC</phrase>
  </textobject>
  <caption>
    <para><ulink url="images/sdcc.xp.hello.png">Copie d'écran compilation
    hello.c sur Windows XP avec SDCC</ulink></para>
  </caption>
</mediaobject>

    <para>Le fichier <filename>ser_hello.ihx</filename> contient le code
    exécutable du programme au format <wordasword>Intel Hex</wordasword>. Il
    s'agit d'un format texte <acronym>ASCII</acronym> de représentation du code
    machine du microcontrôleur utilisé pour le transfert du système de
    développement vers le système cible.</para>
    <para>Le fichier <filename>ser_hello.asm</filename> contient le code source
    du programme en langage assembleur. Une lecture rapide de ce fichier montre
    que les fonctions d'optimisation du compilateur ont été efficaces.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="sdcc_course.hello.msc1210.xp.make">
  <term>Utilisation d'un <wordasword>Makefile</wordasword></term>
  <listitem>
    <para>Pour faciliter les développements de programmes «plus complets» que
    cet exemple, un patron de <wordasword>Makefile</wordasword> est fourni avec
    les fichiers sources distribués avec ce document : <xref linkend="sdcc_course.soft.makefile"/>.</para>

    <para>Pour démarrer un nouveau développement, il suffit de copier ce patron
    dans un nouveau répertoire et d'affecter à la variable
    <varname>BASENAME</varname> le nom du nouveau fichier source en
    langage C.</para>

    <para>Ce patron de <wordasword>Makefile</wordasword> suppose que l'on
    utilise systématiquement la liaison série comme interface utilisateur. Il
    fait donc référence au fichiers sources et en-têtes qui permettent
    d'utiliser cette liaison série. Ces fichiers sont aussi présentés dans ce
    document à la <xref linkend="sdcc_course.soft.sdcc"/>.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="sdcc_course.hello.msc1210.xp.transfer">
  <term>Transfert du programme avec Windows XP</term>
  <listitem>
    <para><trademark>Texas Instruments</trademark> fournit un logiciel appelé
    <citetitle>TIDownloader</citetitle> qui pilote la liaison série entre le
    <acronym>PC</acronym> et le système embarqué. Ce logiciel sert à la fois au
    transfert du code du programme et aux tests d'exécution avec son
    terminal. Il est téléchargeable à l'adresse :
    <ulink url="http://www.ti.com/litv/zip/sbac018c">
  Software for Programming the Flash Memory Using the Serial Port
  v1.3.4 (Rev. C) (sbac018c.zip, 2381 KB )</ulink>.</para>

    <para>Il faut positionner l'interrupteur «vers le haut» pour accéder au
    moniteur intégré du microcontrôleur. Après un appui sur le bouton
    <wordasword>Reset</wordasword>, les opérations de transfert peuvent
    débuter.</para>

<mediaobject>
  <imageobject>
    <imagedata fileref="images/tidownload-select.png" format="PNG" contentwidth="11.5cm" width="12cm"/>
  </imageobject>
  <textobject>
    <phrase>Sélection du fichier ser_hello.ihx</phrase>
  </textobject>
  <caption>
    <para><ulink url="images/tidownload-select.png">Sélection du fichier
    <filename>ser_hello.ihx</filename></ulink></para>
  </caption>
</mediaobject>

<mediaobject>
  <imageobject>
    <imagedata fileref="images/tidownload-setup.png" format="PNG" contentwidth="11.5cm" width="12cm"/>
  </imageobject>
  <textobject>
    <phrase>Paramétrage de la liaison série pour le transfert</phrase>
  </textobject>
  <caption>
    <para><ulink url="images/tidownload-setup.png">Paramétrage de la liaison
    série pour le transfert</ulink></para>
  </caption>
</mediaobject>

<mediaobject>
  <imageobject>
    <imagedata fileref="images/tidownload-upload.png" format="PNG" contentwidth="11.5cm" width="12cm"/>
  </imageobject>
  <textobject>
    <phrase>Transfert du code du programme vers le système cible</phrase>
  </textobject>
  <caption>
    <para><ulink url="images/tidownload-upload.png">Transfert du code du
    programme vers le système cible</ulink></para>
  </caption>
</mediaobject>
  </listitem>
  </varlistentry>
  <varlistentry id="sdcc_course.hello.msc1210.xp.run">
  <term>Exécution du programme depuis Windows XP</term>
  <listitem>
    <para>Une fois le transfert achevé, on positionne l'interrupteur «vers le
    bas» et on appuie sur le bouton <wordasword>Reset</wordasword> pour lancer
    le programme.</para>

<mediaobject>
  <imageobject>
    <imagedata fileref="images/tidownload-run.png" format="PNG" contentwidth="11.5cm" width="12cm"/>
  </imageobject>
  <textobject>
    <phrase>Exécution du programme</phrase>
  </textobject>
  <caption>
    <para><ulink url="images/tidownload-run.png">Exécution du
    programme</ulink></para>
  </caption>
</mediaobject>
  </listitem>
  </varlistentry>
</variablelist>
</sect2>

<sect2 id="sdcc_course.hello.msc1210.linux">
  <title>Compilation sur GNU/Linux &amp; exécution sur cible MSC1210</title>

<para>Ce contexte est identique au précédent. Les programmes sont développés
sur une machine avec un système <citetitle>GNU/Linux</citetitle> et exécutés
sur le microcontrôleur du système cible. Ces conditions sont décrites dans la
<xref linkend="sdcc_course.dev_os.without"/>.</para>

<para>Relativement à la section précédente, il est inutile d'installer des
outils supplémentaires pour mettre en oeuvre la chaîne de développement <link linkend="sdcc_course.tools.sdcc">SDCC</link> puisque les applications telles
que le <wordasword>shell</wordasword> <application>bash</application> et
<application>make</application> sont systématiquement fournies avec les
distributions <citetitle>GNU/Linux</citetitle>.</para>

<para>Pour l'exemple de programme retenu, on choisit d'afficher la chaîne de
caractères sur le terminal du système de développement (ie. le
<acronym>PC</acronym>) via une liaison série.</para>

<variablelist>
  <varlistentry id="sdcc_course.hello.msc1210.linux.compilation">
  <term>Compilation avec GNU/Linux</term>
  <listitem>
    <para>L'appel du compilateur est identique entre les deux systèmes. Les
    formats de fichiers sont aussi identiques. Le code exécutable du programme
    est contenu dans le fichier <filename>ser_hello.ihx</filename>.</para>
    
<screen width="80">$ sdcc ser_hello.c

$ ll
total 144K
-rw-r--r-- 1 phil phil 8.4K Apr 19 22:19 ser_hello.asm
-rw-r--r-- 1 phil phil  466 Apr 18 21:38 ser_hello.c
-rw-r--r-- 1 phil phil  12K Apr 19 22:19 ser_hello.ihx
-rw-r--r-- 1 phil phil  193 Apr 19 22:19 ser_hello.lnk
-rw-r--r-- 1 phil phil  22K Apr 19 22:19 ser_hello.lst
-rw-r--r-- 1 phil phil  14K Apr 19 22:19 ser_hello.map
-rw-r--r-- 1 phil phil 1.1K Apr 19 22:19 ser_hello.mem
-rw-r--r-- 1 phil phil 3.7K Apr 19 22:19 ser_hello.rel
-rw-r--r-- 1 phil phil  22K Apr 19 22:19 ser_hello.rst
-rw-r--r-- 1 phil phil  37K Apr 19 22:19 ser_hello.sym
</screen>
  </listitem>
  </varlistentry>

  <varlistentry id="sdcc_course.hello.msc1210.linux.make">
  <term>Utilisation d'un <wordasword>Makefile</wordasword></term>
  <listitem>
    <para>Pour faciliter les développements de programmes «plus complets» que
    cet exemple, un patron de <wordasword>Makefile</wordasword> est fourni avec
    les fichiers sources distribués avec ce document : <xref linkend="sdcc_course.soft.makefile"/>.</para>

    <para>Pour démarrer un nouveau développement, il suffit de copier ce patron
    dans un nouveau répertoire et d'affecter à la variable
    <varname>BASENAME</varname> le nom du nouveau fichier source en
    langage C.</para>

    <para>Ce patron de <wordasword>Makefile</wordasword> suppose que l'on
    utilise systématiquement la liaison série comme interface utilisateur. Il
    fait donc référence au fichiers sources et en-têtes qui permettent
    d'utiliser cette liaison série. Ces fichiers sont aussi présentés dans ce
    document à la <xref linkend="sdcc_course.soft.sdcc"/>.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="sdcc_course.hello.msc1210.linux.transfer">
  <term>Transfert du programme avec GNU/Linux</term>
  <listitem>
    <para>Pour effectuer le transfert de fichier en mode ASCII entre le PC de
    développement et le microcontrôleur, on utilise une application appelée
    <application>minicom</application> sur les systèmes GNU/Linux.</para>
    <para>À partir d'un <wordasword>Shell</wordasword>, on appelle
    <application>minicom</application> avec les options :</para>
    <itemizedlist spacing="compact">
      <listitem>
      <para><option>-o</option> pour désactiver le dialogue
      <citetitle>Hayes</citetitle> entre les équipements connectés sur la
      liaison série.</para>
      </listitem>
      <listitem>
      <para><option>-8</option> pour pouvoir utiliser les codes
      <acronym>ASCII</acronym> sur 8 bits.</para>
      </listitem>
    </itemizedlist>

<screen width="80">$ minicom -o -m -8
</screen>

    <para>Le paramétrage de la liaison se fait avec les options
    suivantes :</para>

<screen width="80">A - Serial Device         : /dev/ttyS0
B - Lockfile Location     : /var/lock
C - Callin Program        :
D - Callout Program       :
E - Bps/Par/Bits          : 19200 8N1
F - Hardware Flow Control : No
G - Software Flow Control : No
</screen>

    <para>Il est important de désactiver le contrôle matériel de flux pour que
    la fonction de détection automatique du débit puisse s'exécuter
    normalement.</para>

    <para>Il faut positionner l'interrupteur «vers le haut» pour accéder au
    moniteur intégré du microcontrôleur. Après un appui sur le bouton
    <wordasword>Reset</wordasword>, on doit obtenir l'invite de commande
    suivante :</para>

<screen width="80">MSC1210 Ver:000305F10
&gt;
</screen>
    
    <para>Il faut effacer le contenu de la mémoire du microcontrôleur avant de
    procéder au transfert. La séquence à saisir est la suivante :</para>

<screen width="80">&gt;M0000 ok
&gt;M8000 ok
&gt;E
&gt;L

</screen>

    <para>On peut ensuite lancer le transfert de fichier en mode
    <acronym>ASCII</acronym> après avoir sélectionné le fichier
    <filename>ser_hello.ihx</filename> :</para>

<screen width="80">+---------[ascii upload - Press CTRL-C to quit]---------+
|.......................................................|
|7.8 Kbytes transferred at 1991 CPS.....................|
|.......................................................|
|.......................................................|
|11.5 Kbytes transferred at 1962 CPS... Done.           |
|                                                       |
| READY: press any key to continue...   
</screen>
  </listitem>
  </varlistentry>
  <varlistentry id="sdcc_course.hello.msc1210.linux.run">
  <term>Exécution du programme depuis GNU/Linux</term>
  <listitem>
    <para>Une fois le transfert achevé, on positionne l'interrupteur «vers le
    bas» et on appuie sur le bouton <wordasword>Reset</wordasword> pour lancer
    le programme.</para>

    <para>On obtient alors un affichage de la chaîne de caractères «tant
    attendue» sur le terminal du <acronym>PC</acronym> de développement.</para>

<screen width="80">MSC1210 Ver:000305F10
&gt;M0000 ok
&gt;M8000 ok
&gt;E
&gt;T
&gt;
&gt;Hello World !

</screen>
  </listitem>
  </varlistentry>
</variablelist>
</sect2>
</sect1>

<?custom-pagebreak?>
<sect1 id="sdcc_course.msc12xx">
  <title>Caractéristiques des microcontrôleurs de la famille MSC12xx</title>

<para>Les composants de la famille MSC12xx reprennent les caractéristiques
usuelles d'un microcontrôleur :</para>

<itemizedlist spacing="compact">
  <listitem>
  <para>des fonctions de conversion analogique numérique,</para>
  </listitem>
  <listitem>
  <para>un coeur «amélioré» de la famille <trademark>Intel</trademark>
  <citetitle>MCS51</citetitle>,</para>
  </listitem>
  <listitem>
  <para>de la mémoire de type <acronym>RAM</acronym> et de type
  <acronym>FLASH</acronym>,</para>
  </listitem>
  <listitem>
  <para>des périphériques logiques performants.</para>
  </listitem>
</itemizedlist>

<para>Le coeur <citetitle>MCS51</citetitle> «amélioré» comprend deux pointeurs
de données et exécute la plupart des instructions trois fois plus vite qu'un
coeur 8051 standard. Avec une vitesse d'exécution plus grande, ce composant est
utilisable avec un grand nombre d'applications qui réclament des performances
en fréquence.</para>

<para>La liste des documents de référence sur cette famille de microcontrôleurs
est donnée à la <xref linkend="sdcc_course.docs.msc12xx"/>.</para>

</sect1>

<?custom-pagebreak?>
<sect1 id="sdcc_course.c_language">
  <title>Éléments de Langage C</title>

<para>Cette section présente succinctement les éléments essentiels du Langage C
en donnant un maximum d'exemples adaptés au développement sur système
spécialisé.</para>

<para>On utilise un exemple de programme presque aussi connu que le très fameux
<link linkend="sdcc_course.hello">«Hello, World!»</link> ; le calcul des nombres
de Fibonacci. On commence par présenter le listing complet, puis on détaille
les éléments de la syntaxe du Langage C.</para>

<para>Le même programme est présenté sous plusieurs formes
différentes en fonction du contexte de développement.</para>

<example id="gcc_fibonacci_single">
  <title>Calcul des nombres de Fibonacci sur GNU/Linux avec GCC</title>
<programlisting width="80">01: /* $Id: gcc_fibonacci_single.c 1129 2007-05-07 15:07:52Z latu $
02:  * Un programme simple pour calculer les n premiers nombres de Fibonacci */
03: 
04: #include &lt;stdio.h&gt;
05: #include &lt;stdlib.h&gt;
06: 
07: #define MAX_FIB 49
08: 
09: main() {
10: 
11:   int n, i;
12:   unsigned int nombrePrecedent, nombreCourant, fibonacci;
13:   
14: 
15:   printf("Saisir le nombre de calculs de Fibonacci(n) :\n");  
16:   scanf("%d", &amp;n);
17:   if (n &gt;= MAX_FIB) {
18:     printf("Fibonacci(%d) depasse la capacite d'un mot de 32 bits\n", n); 
19:     exit(1);
20:     }
21: 
22:   nombrePrecedent = 0;
23:   nombreCourant = 1;
24:   for (i = 0; i &lt; n; i++) {
25:      if (i &gt; 1) {
26:         fibonacci = nombrePrecedent + nombreCourant;
27:         nombrePrecedent = nombreCourant;
28:         nombreCourant = fibonacci;
29:         printf("Fibonacci (%d) = %u\n", i, fibonacci);
30:      }
31:      else
32:         printf("Fibonacci (%d) = %u\n", i, i);
33:   }
34: }
</programlisting>
</example>

<para>Voici un exemple d'exécution du programme <xref linkend="sdcc_course.soft.gcc_fibonacci_single"/> :</para>

<screen width="80">$ ./gcc_fibonacci_single.out
Saisir le nombre de calculs de Fibonacci(n) :
11
Fibonacci (0) = 0
Fibonacci (1) = 1
Fibonacci (2) = 1
Fibonacci (3) = 2
Fibonacci (4) = 3
Fibonacci (5) = 5
Fibonacci (6) = 8
Fibonacci (7) = 13
Fibonacci (8) = 21
Fibonacci (9) = 34
Fibonacci (10) = 55
</screen>

<para>Comme dans le cas du <link linkend="sdcc_course.hello">premier programme
présenté</link>, le code source du programme destiné au microcontrôleur MSC1210
inclut le pilotage de l'interface série. Dans ce contexte de développement, on
ne dispose pas de système d'exploitation.</para>

<example id="sdcc_fibonacci_single">
  <title>Calcul des nombres de Fibonacci sur microcontrôleur MSC1210 avec
  SDCC</title>
<programlisting width="80">01: #include &lt;stdio.h&gt;
02: #include &lt;stdlib.h&gt;
03: #include &lt;msc1210.h&gt;
04: #include "ser_msc1210.h"
05: 
06: #define MAX_FIB 49
07: 
08: // surdefinition du sous-programme putchar
09: void putchar(char c) {
10:    ser_putc(c);
11:   }
12: 
13: void main(void) {
14: 
15:    unsigned char s[3] = {'\0','\0','\0'};
16:    int n, i;
17:    unsigned long nombrePrecedent, nombreCourant, fibonacci;
18: 
19:    // Appuyer sur &lt;Entree&gt; pour ajuster automatiquement
20:    // le debit de la liaison
21:    autobaud();
22:    EA=1;
23: 
24:    do {
25:       printf("Saisir le nombre de calculs de Fibonacci :\r\n");
26:       ser_gets_echo(s, 2);
27:       n = atoi(s);
28:       if (n &gt;= MAX_FIB)
29:          printf("\nFibonacci(%d) depasse la capacite d'un mot de 32 bits\r\n", n);
30:    } while (n &gt;= MAX_FIB);
31: 
32:    printf("\r\n\n");
33:    nombrePrecedent = 0;
34:    nombreCourant = 1;
35:    for (i = 0; i &lt; n; i++) {
36:       if (i &gt; 1) {
37:          fibonacci = nombrePrecedent + nombreCourant;
38:          nombrePrecedent = nombreCourant;
39:          nombreCourant = fibonacci;
40:          printf("Fibonacci (%d) = %lu\r\n", i, fibonacci);
41:       }
42:       else
43:          printf("Fibonacci (%d) = %d\r\n", i, i);
44:    }
45:    while(1);
46: }
</programlisting>
</example>

<para>Voici un exemple de résultat d'exécution du programme <xref linkend="sdcc_course.soft.sdcc_fibonacci_single"/> :</para>

<screen width="80">MSC1210 Ver:000305F10
&gt;M0000 ok
&gt;M8000 ok
&gt;E
&gt;Saisir le nombre de calculs de Fibonacci :
11

Fibonacci (0) = 0
Fibonacci (1) = 1
Fibonacci (2) = 1
Fibonacci (3) = 2
Fibonacci (4) = 3
Fibonacci (5) = 5
Fibonacci (6) = 8
Fibonacci (7) = 13
Fibonacci (8) = 21
Fibonacci (9) = 34
Fibonacci (10) = 55
</screen>

<sect2 id="sdcc_course.c_language.delimiters">
  <title>Délimiteurs</title>

<para>Généralités sur les <emphasis>délimiteurs</emphasis> de syntaxe
du Langage C des exemples ci-dessus :</para>

<variablelist>
  <varlistentry>
  <term>Les commentaires</term>
  <listitem>
  <para>Ils sont repérés par deux <wordasword>slashes</wordasword>
  (<code>//</code>) si le texte du commentaire ne comprend qu'une seule ligne.
  Ils sont délimités entre les balises <code>/*</code> et <code>*/</code> si le
  texte du commentaire comprend plusieurs lignes.</para>
  <itemizedlist spacing="compact">
    <listitem>
    <para><xref linkend="gcc_fibonacci_single"/> : les lignes 1 et 2
    correspondent à un même commentaire.</para>
    </listitem>
    <listitem>
    <para><xref linkend="sdcc_fibonacci_single"/> : les lignes 8, 19
    et 20 sont des commentaires sur une ligne unique.</para>
    </listitem>
  </itemizedlist>
  </listitem>
  </varlistentry>
  <varlistentry>
  <term>Les directives du préprocesseur</term>
  <listitem>
  <para>Elles sont repérées par le caractère <emphasis>dièse</emphasis> en
  début de ligne :</para>

<programlisting width="80"> #include &lt;stdio.h&gt;
 #define TRUE	1
</programlisting>

  <para>Ces directives ne sont pas considérées comme faisant partie du code.
  Elles ne sont donc pas délimitées comme des instructions «classiques».</para>
  <itemizedlist spacing="compact">
    <listitem>
    <para><xref linkend="gcc_fibonacci_single"/> : lignes 4, 5 et 7.</para>
    </listitem>
    <listitem>
    <para><xref linkend="sdcc_fibonacci_single"/> : lignes 1 à 4 puis
    6.</para>
    </listitem>
  </itemizedlist>
  </listitem>
  </varlistentry>
  <varlistentry>
  <term>Les instructions</term>
  <listitem>
  <para>Elles sont séparées par le caractère
  <emphasis>point-virgule</emphasis> :</para>

<programlisting width="80"> printf ("Hello,");
 printf (" World!");
</programlisting>

  <para>Dans les deux exemples de référence ci-dessus, on relève que toutes les
  instructions (déclarations de variables, opérations, etc.) sont délimitées
  par des caractères ';' à l'exception des directives du préprocesseur.</para>
  </listitem>
  </varlistentry>
  <varlistentry>
  <term>Les groupes d'instructions</term>
  <listitem>
  <para>Ils sont délimités par les caractères <emphasis>accolades</emphasis>
  ouvertes et fermées :</para>

<programlisting width="80"> while(1) {
 	printf ("Hello,");
	printf (" World!");
 }
</programlisting>

  <itemizedlist spacing="compact">
    <listitem>
    <para><xref linkend="gcc_fibonacci_single"/> : les lignes 9 et 34
    contiennent les accolades qui délimitent le début et la fin du programme
    principal.</para>
    </listitem>
    <listitem>
    <para><xref linkend="sdcc_fibonacci_single"/> : les lignes 24 et 30
    délimitent le groupe d'instructions qui doivent être répétées tant que le
    test <code>(n &gt;= MAX_FIB)</code> n'est pas satisfait.</para>
    </listitem>
  </itemizedlist>
  </listitem>
  </varlistentry>
</variablelist>
</sect2>

<sect2 id="sdcc_course.c_language.data">
  <title>Représentation des données</title>

<para>En programmation, les données manipulées sont appelées
<emphasis>variables</emphasis> ou <emphasis>constantes</emphasis>.</para>

<para>Une <emphasis>variable</emphasis> sert au stockage d'une information en
vue de sa réutilisation dans le programme principal et|ou un
sous-programme.</para>

<para>Du point de vue gestion de la mémoire (<acronym>RAM</acronym>
ou <wordasword>Random Access Memory</wordasword>), une variable est une zone
mémoire réservée et «étiquetée» avec le nom de cette variable.</para>

<para>Sur une machine avec système d'exploitation, la phase de
<emphasis>déclaration</emphasis> d'une variable correspond à une demande de
réservation mémoire au gestionnaire de mémoire virtuelle du noyau. Ce
gestionnaire doit gérer au mieux ces demandes en fonction des programmes actifs
sur le système.</para>

<para>Sur un système spécialisé, c'est au développeur de gérer «manuellement»
son espace mémoire. Il n'existe aucune protection contre le débordement de la
capacité mémoire.</para>

<para>Du point de vue syntaxique, il existe certaines restrictions dans
l'emploi des noms de variables et de constantes. Les caractères de ponctuation
ne sont pas utilisables. Le caractère «souligné»
(<wordasword>underscore</wordasword>) est considéré comme une lettre ; il est
beaucoup utilisé par le préprocesseur.</para>

<warning>
<para>En Langage C, les majuscules et les minuscules sont traitées
différemment. On utilise généralement les majuscules pour les définitions de
constantes et les minuscules pour les variables.</para>
</warning>

<para>Suivant la génération du compilateur utilisé, le nombre de caractère pris
en compte pour les noms de variables est plus ou moins limité. Historiquement,
cette limite était fixée à 8 bien que l'on puisse en utiliser davantage dans le
code source.</para>

<para>Dans les deux exemples ci-dessus, on trouve les déclarations des
variables après l'accolade de début de programme principal (fonction
<function>main()</function>).</para>

<itemizedlist spacing="compact">
  <listitem>
  <para><xref linkend="gcc_fibonacci_single"/> : lignes 11 et 12.</para>
  </listitem>
  <listitem>
  <para><xref linkend="sdcc_fibonacci_single"/> : lignes 15 à 17.</para>
  </listitem>
</itemizedlist>
</sect2>

<sect2 id="sdcc_course.c_language.type">
  <title>Types de représentation des données</title>

<para>Pour représenter les données à manipuler on distingue différents
<emphasis>types</emphasis> élémentaires définis dans la syntaxe du langage de
programmation. La table ci-dessous donne une liste complète de ces
types.</para>

<table id="sdcc_course.c_language.type.table" pgwide="1" frame="all">
  <title>Types élémentaires du Langage C</title>
  <tgroup cols="2" align="left" colsep="1" rowsep="1">
    <colspec colnum="1" colwidth="1*"/>
    <colspec colnum="2" colwidth="4*"/>
  <thead>
    <row>
    <entry>Type de donnée</entry>
    <entry>syntaxe C</entry>
    </row>
  </thead>
  <tbody>
    <row>
    <entry>rien ou vide</entry>
    <entry><literal>void</literal></entry>
    </row>
    <row>
    <entry>caractère</entry>
    <entry><literal>char</literal></entry>
    </row>
    <row>
    <entry>nombre entier court</entry>
    <entry><literal>short</literal></entry>
    </row>
    <row>
    <entry>nombre entier</entry>
    <entry><literal>int</literal></entry>
    </row>
    <row>
    <entry>nombre entier long</entry>
    <entry><literal>long</literal></entry>
    </row>
    <row>
    <entry>nombre entier long double</entry>
    <entry><literal>long long</literal></entry>
    </row>
    <row>
    <entry>nombre réel</entry>
    <entry><literal>float</literal></entry>
    </row>
    <row>
    <entry>nombre réel double</entry>
    <entry><literal>double</literal></entry>
    </row>
    <row>
    <entry>nombre réel long double</entry>
    <entry><literal>long double</literal></entry>
    </row>
  </tbody>
  </tgroup>
</table>

<para>À la lecture de la table ci-dessus, on constate que le langage C n'offre
pas de type booléen. Pour autant, la valeur entière <code>0</code> correspond à
l'état <emphasis>faux</emphasis> et toutes les autres valeurs entières
correspondent à l'état <emphasis>vrai</emphasis>. La technique usuelle pour
représenter les deux états booléens consiste à définir deux constantes. Voir
<xref linkend="sdcc_course.c_language.const"/>.</para>

<para>En Langage C, si les noms de types sont toujours les mêmes,
leurs formats diffèrent suivant les chaînes de développement et les processeurs
utilisés. Les deux exemples ci-dessous illustrent ces différences.</para>

<para>Dans le cas de la chaîne de développement <acronym>GNU</acronym> utilisée
sur <acronym>PC</acronym>, il est possible de représenter de très grands
nombres réels sur 12 octets soit 96 bits. À l'inverse, il n'est pas possible de
représenter une donnée sur moins d'un octet.</para>

<para>Voici le résultat d'un programme utilisant la fonction
<function>sizeof</function> pour chacun des types donnés dans la liste
ci-dessus. Le code source de ce programme est disponible à l'adresse :
<ulink url="http://www.linux-france.org/prj/embedded/sources/gcc_sizeof.tar.bz2">gcc_sizeof.tar.bz2</ulink>.</para>

<example id="sdcc_course.c_language.type.gcc_example">
  <title>Formats des types supportés par GCC</title>
<screen width="80">Dimension de chaque type en octets :
'char'          :       1
'unsigned char' :       1
'short'         :       2
'int'           :       4
'long'          :       4
'long long'     :       8
'float'         :       4
'double'        :       8
'long double'   :       12
</screen>
</example>

<para>Dans le cas du compilateur <acronym>SDCC</acronym> et du microcontrôleur
cible <acronym>MSC1210</acronym>, il n'est pas possible d'utiliser des nombres
réels au delà de la représentation simple sur 4 octets. La plus petite unité
représentée est le bit même si l'appel à la fonction
<function>sizeof</function> pour ce type produit un résultat surprenant  1
octet pour 1 bit.</para>

<para>Comme avec la chaîne de développement <acronym>GNU/GCC</acronym>, voici
le résultat d'un programme utilisant la fonction <function>sizeof</function>
pour chacun des types donnés dans la liste ci-dessus. Le code source de ce
programme est disponible à l'adresse : <ulink url="http://www.linux-france.org/prj/embedded/sources/sdcc_sizeof.tar.bz2">sdcc_sizeof.tar.bz2</ulink>.</para>

<example id="sdcc_course.c_language.type.sdcc_example">
  <title>Formats des types supportés par SDCC</title>
<screen width="80">&gt;Dimension de chaque type en octets :
'char'          :       1
'unsigned char' :       1
'short'         :       2
'int'           :       2
'long'          :       4
'long long'     :       4
'float'         :       4
Attention ! le type bit existe :
'bit'           :       1
</screen>
</example>

<itemizedlist spacing="compact">
  <listitem>
  <para><xref linkend="gcc_fibonacci_single"/> : lignes 11 et 12. Ce
  programme est limité au calcul des nombres de Fibonacci qui ne dépassent pas
  la capacité d'un entier représenté sur 32 bits (soit 4 octets). On utilise
  donc le type <code>int</code> dans le code source du programme.</para>
  </listitem>
  <listitem>
  <para><xref linkend="sdcc_fibonacci_single"/> : ligne 16 et 17. Ce
  programme est aussi limité à une représentation des nombres entiers sur 32
  bits. Avec le compilateur <acronym>SDCC</acronym>, c'est le type
  <code>long</code> qui est utilisé dans le code source du programme pour
  répondre au critère de calcul.</para>
  </listitem>
</itemizedlist>
</sect2>

<sect2 id="sdcc_course.c_language.const">
  <title>Constantes</title>

<para>Une constante est une valeur particulière que l'on utilise tout au long
du programme. Si cette valeur doit être modifiée, il est préférable de n'avoir
qu'une seule ligne à éditer. En terme de maintenabilité du code source,
l'utilisation de constantes est très avantageux. De plus, l'utilisation d'une
représentation littérale d'une valeur numérique particulière permet de gagner en
lisibilité.</para>

<para>En informatique industrielle, on fait un usage «massif» des constantes.
En effet tous les registres et les adresses de pilotage des périphériques
spécialisés sont représentés à l'aide de constantes. Si ce mode de
représentation n'existait pas, on ne pourrait utiliser que des valeurs
hexadécimales. Les difficultés de développement des programmes seraient
beaucoup plus importantes du fait des confusions possibles entre des valeurs
voisines.</para>

<para>En Langage C, les constantes sont en fait des directives destinées au
préprocesseur. En effet, comme le rôle du préprocesseur est d'analyser la
syntaxe du code source d'un programme, il peut se charger de substituer toutes
les occurrences des constantes par leurs valeurs numériques avant de passer à la
compilation proprement dite.</para>

<para>Cette technique est très avantageuse puisque l'utilisation des constante
ne nécessite aucune réservation en mémoire.</para>

<para>Les deux exemples de programmes montrent la même constante
<code>MAX_FIB</code> déclarée à l'aide de la directive <code>#define</code>.
Cette constante correspond aux rang maximum du nombre de Fibonacci que l'on
peut représenter sur 32 bits.</para>

<warning>
  <para>Il faut noter qu'une directive de préprocesseur n'est pas instruction
  du langage C. C'est la raison pour laquelle on n'utilise pas le caractère ';'
  comme délimiteur. Cette absence de délimitation ne pose pas de difficulté
  dans la mesure où on ne peut trouver qu'une directive par ligne.</para>
</warning>

<itemizedlist spacing="compact">
  <listitem>
  <para><xref linkend="gcc_fibonacci_single"/> : ligne 7.</para>
  </listitem>
  <listitem>
  <para><xref linkend="sdcc_fibonacci_single"/> : ligne 6.</para>
  </listitem>
</itemizedlist>

<para>Dans les exemples «rituels» de définition de constantes on trouve les
deux états booléens :</para>

<screen width="80">#define FALSE 0
#define TRUE 1
</screen>

<para>Le fichier d'en-tête standard <filename>limits.h</filename> est un
exemple caractéristique de liste de définitions de constantes. Ce fichier
contient les définitions des valeurs entières maximales pour chaque type connu.
Voici un extrait du fichier fourni avec la chaîne
<acronym>GNU/GCC</acronym> :</para>

<screen width="80">/* Number of bits in a `char'.  */
#  define CHAR_BIT      8

/* Minimum and maximum values a `signed char' can hold.  */
#  define SCHAR_MIN     (-128)
#  define SCHAR_MAX     127

/* Maximum value an `unsigned char' can hold.  (Minimum is 0.)  */
#  define UCHAR_MAX     255

/* Minimum and maximum values a `char' can hold.  */
#  ifdef __CHAR_UNSIGNED__
#   define CHAR_MIN     0
#   define CHAR_MAX     UCHAR_MAX
#  else
#   define CHAR_MIN     SCHAR_MIN
#   define CHAR_MAX     SCHAR_MAX
#  endif

/* Minimum and maximum values a `signed short int' can hold.  */
#  define SHRT_MIN      (-32768)
#  define SHRT_MAX      32767

/* Maximum value an `unsigned short int' can hold.  (Minimum is 0.)  */
#  define USHRT_MAX     65535

/* Minimum and maximum values a `signed int' can hold.  */
#  define INT_MIN       (-INT_MAX - 1)
#  define INT_MAX       2147483647

/* Maximum value an `unsigned int' can hold.  (Minimum is 0.)  */
#  define UINT_MAX      4294967295U
</screen>
</sect2>

<sect2 id="sdcc_course.c_language.calc_operator">
  <title>Opérateurs de calcul</title>

<para>On retrouve les opérateurs usuels en Langage C : <code>+</code>,
<code>-</code>, <code>*</code> et <code>/</code>. À cette liste, il faut
ajouter les éléments propres aux calculs en Langage C.</para>

<variablelist>
  <varlistentry id="sdcc_course.c_language.calc_operator.modulo">
  <term>Opérateur modulo</term>
  <term><code>%</code></term>
  <listitem>
  <para>Cet opérateur, noté <code>%</code>, renvoie le reste de la division
  entre 2 entiers. Par
  exemple : <code>24 % 9 = 6</code></para>
  </listitem>
  </varlistentry>

  <varlistentry id="sdcc_course.c_language.calc_operator.incdec">
  <term>Opérateurs d'incrémentation et de décrémentation</term>
  <term><code>++</code> et <code>--</code></term>
  <listitem>
  <para>Pour ajouter une unité à une variable, on utilise l'opérateur
  d'incrémentation <code>++</code>. Pour soustraire une unité à une variable,
  on utilise l'opérateur de décrémentation <code>--</code>.</para>
  <para>La position de l'opérateur, à la gauche ou à la droite du nom de
  variable à une signification particulière. Dans l'expression
  <code>'while (++n &lt; 10)'</code>, la variable <code>n</code>
  sera incrémentée <emphasis>avant</emphasis> d'être comparée à
  <code>10</code>. À l'inverse, dans l'expression
  <code>'while (n++ &lt; 10)'</code>, la variable <code>n</code>
  est comparée à <code>10</code> avant d'être incrémentée.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="sdcc_course.c_language.calc_operator.affect">
  <term>Opérateurs et expressions d'affectation</term>
  <listitem>
  <para>En Langage C, on peut appliquer la règle suivante sur les 2 expressions
  e1 et e2 :
  <code>'(e1) = (e1) (opérateur) (e2)'</code> est
  équivalent à <code>'(e1) (opérateur)= (e2)'</code>. Tous les
  opérateurs usuels de calculs sont utilisables avec cette règle. Ainsi,
  <code>i = i + 2;</code> est équivalent à
  <code>i += 2;</code>.</para>
  </listitem>
  </varlistentry>
</variablelist>

<itemizedlist spacing="compact">
  <listitem>
  <para><xref linkend="gcc_fibonacci_single"/> : à la ligne 24, on trouve
  un opérateur d'incrémentation du compteur des calculs à effectuer.</para>
  </listitem>
  <listitem>
  <para><xref linkend="sdcc_fibonacci_single"/> : à la ligne 35, on
  retrouve le même opérateur d'incrémentation.</para>
  </listitem>
</itemizedlist>
</sect2>

<sect2 id="sdcc_course.c_language.relational_operators">
  <title>Opérateurs relationnels</title>

<para>Ces opérateurs évaluent une condition sur des nombres entiers ou réels et
renvoient une valeur booléenne <code>0</code> ou <code>1</code>.</para>

<table id="sdcc_course.c_language.calc_operator.relational.table" pgwide="1" frame="all">
  <title>Opérateurs relationnels</title>
  <tgroup cols="2" align="left" colsep="1" rowsep="1">
    <colspec colnum="1" colwidth="1*"/>
    <colspec colnum="2" colwidth="4*"/>
  <thead>
    <row>
    <entry>Symbole</entry>
    <entry>Opérateur|Condition</entry>
    </row>
  </thead>
  <tbody>
    <row>
    <entry><code>==</code></entry>
    <entry>égalité</entry>
    </row>
    <row>
    <entry><code>!=</code></entry>
    <entry>différence</entry>
    </row>
    <row>
    <entry><code>&gt;</code></entry>
    <entry>supérieur à</entry>
    </row>
    <row>
    <entry><code>&lt;</code></entry>
    <entry>inférieur à</entry>
    </row>
    <row>
    <entry><code>&gt;=</code></entry>
    <entry>supérieur ou égal à</entry>
    </row>
    <row>
    <entry><code>&lt;=</code></entry>
    <entry>inférieur ou égal à</entry>
    </row>
  </tbody>
  </tgroup>
</table>

<itemizedlist spacing="compact">
  <listitem>
  <para><xref linkend="gcc_fibonacci_single"/> : lignes 17, 24 et 25. Ces
  opérateurs relationnels sont utilisés pour évaluer une condition sur des
  valeurs entières dans les calculs.</para>
  </listitem>
  <listitem>
  <para><xref linkend="sdcc_fibonacci_single"/> : lignes 28, 30, 35 et 36.
  Comme dans le cas précédent, on évalue une condition sur des valeurs
  entières.</para>
  </listitem>
</itemizedlist>
</sect2>

<sect2 id="sdcc_course.c_language.logical_operators">
  <title>Opérateurs logiques de bits</title>

<table id="sdcc_course.c_language.logical_operators.table" pgwide="1" frame="all">
  <title>Opérateurs logiques de bits</title>
  <tgroup cols="2" align="left" colsep="1" rowsep="1">
    <colspec colnum="1" colwidth="1*"/>
    <colspec colnum="2" colwidth="4*"/>
  <thead>
    <row>
    <entry>Symbole</entry>
    <entry>Opérateur</entry>
    </row>
  </thead>
  <tbody>
    <row>
    <entry><code>&amp;</code></entry>
    <entry><literal>ET</literal></entry>
    </row>
    <row>
    <entry><code>|</code></entry>
    <entry><literal>OU</literal> (inclusif)</entry>
    </row>
    <row>
    <entry><code>^</code></entry>
    <entry><literal>OU</literal> (exclusif)</entry>
    </row>
    <row>
    <entry><code>&lt;&lt;</code></entry>
    <entry>décalage à gauche avec remplissage par 0</entry>
    </row>
    <row>
    <entry><code>&gt;&gt;</code></entry>
    <entry>décalage à gauche avec remplissage par 0</entry>
    </row>
    <row>
    <entry><code>~</code></entry>
    <entry>négation binaire ou complément à 1</entry>
    </row>
  </tbody>
  </tgroup>
</table>
</sect2>

<sect2 id="sdcc_course.c_language.if-else">
  <title>Instruction de test if-else</title>

<para>On utilise l'instruction <code>if-else</code> pour prendre des
décisions. Sa forme générale est  :</para>

<programlisting width="80"> if ( expression )
    instruction1;
 else
    instruction2;
</programlisting>

<para>Si l'<emphasis>expression</emphasis> est vraie, c'est l'instruction 1 qui
est exécutée ; sinon c'est l'instruction 2. Les instructions 1 et 2 peuvent
correspondre à des groupes délimités par des caractères <code>{</code> et
<code>}</code>. La partie <emphasis>else</emphasis> est optionnelle. Si
l'instruction 2 n'existe pas, on n'utilise pas ce mot clé.</para>

<important id="sdcc_course.c_language.if-else.important">
  <title>Une condition fausse vaut toujours 0</title>
  <para>Si la condition codée dans l'<emphasis>expression</emphasis> n'est pas
  vérifiée (est fausse) c'est la valeur numérique 0 qui est renvoyée. Pour
  toutes les autres valeurs renvoyées par l'<emphasis>expression</emphasis>, la
  condition est considérée comme vérifiée (est vraie).</para>

  <para>En langage C, il est très fréquent d'utiliser directement les valeurs
  numériques dans les instructions <code>if-else</code> sans coder
  explicitement la condition dans l'expression. De nombreux exemples de ce mode
  de codage ont été volontairement placés dans les exemples de programmes
  fournis dans le présent document.</para>
</important>

<itemizedlist spacing="compact">
  <listitem>
  <para><xref linkend="gcc_fibonacci_single"/> : les lignes 17 à 20
  permettent de contrôler que l'utilisateur a bien saisi un nombre de calculs
  compatible avec la représentation sur 32 bits du résultat. Si l'utilisateur
  saisit une valeur supérieure à la constante <code>MAX_FIB</code>, on affiche
  le message d'erreur à la console et l'exécution du programme s'arrête. Les
  deux instructions à traiter si l'expression est vraie sont encadrées par des
  accolades.</para>
  <para>Les lignes 25 à 30 montrent que l'on effectue le calcul des nombres de
  Fibonacci pour les valeurs de la variable <code>i</code> strictement
  supérieures à 1. Si cette condition n'est pas respectée, on affiche
  directement le numéro du calcul comme résultat.</para>
  </listitem>
  <listitem>
  <para><xref linkend="sdcc_fibonacci_single"/> : les lignes 28 et 30
  permettent de contrôler que l'utilisateur a bien saisi un nombre de calculs
  dont les résultats sont correctement représentés sur 32 bits. Dans ce cas, on
  se contente d'afficher le message d'erreur. On n'utilise pas d'accolades de
  délimitation de groupe d'instructions.</para>
  <para>Comme dans la version GNU/GCC, les lignes 36 à 41 montrent que l'on
  effectue le calcul des nombres de Fibonacci pour les valeurs de la variable
  <code>i</code> strictement supérieures à 1.</para>
  </listitem>
</itemizedlist>
</sect2>

<sect2 id="sdcc_course.c_language.switch">
  <title>Instructions de choix multiples : switch &amp; if-else-if</title>

<para>Le traitement des choix multiples peut devenir compliqué lorsque
l'imbrication des blocs d'instructions entre instructions <code>if-else</code>
augmente. C'est pour cette raison qu'une syntaxe particulière à été
introduite : l'instruction <code>switch</code> dont le synoptique est le
suivant.</para>

<programlisting width="80">switch (expression) {
	case Valeur1:
		// Instructions
		break;
	case Valeur2:
		// Instructions
		break;
	...
	case ValeurN:
		// Instructions
		break;
	default:
		// Instructions
}</programlisting>

<para>Le cas classique d'utilisation de l'instruction <code>switch</code>
consiste à programmer un menu à choix multiples. La variable à tester est de
type simple puisqu'il s'agit d'un caractère. Le programme <xref linkend="sdcc_course.soft.sdcc_switch"/> illustre justement l'utilisation d'un
menu suivi d'un test à choix multiples.</para> 

<para>Cette structure est très pratique lorsque le résultat de l'expression est
de type simple.	Lorsque l'on doit évaluer non pas une valeur mais une plage de
valeurs, il devient alors plus pratique de retenir un codage du type
suivant.</para>

<programlisting width="80">  if (condition1) {
	// Instructions
  }
  else if (condition2) {
	// Instructions
  }
  else if (condition3) {
	// Instructions
  }
  // autres conditions
  else {
	// Instructions
  }
</programlisting>
</sect2>

<sect2 id="sdcc_course.c_language.loops">
  <title>Instructions de boucles : for, while, do-while</title>

<para>Dès lors qu'une ou plusieurs instructions doivent être répétées, on
utilise les instructions de boucles disponibles avec le Langage C.</para>

<para>Indépendemment du langage de programmation utilisé, il existe des règles
dans l'emploi des boucles.</para>

<orderedlist numeration="arabic">
  <listitem>
  <para>On emploie la boucle <emphasis>pour</emphasis> (<code>for</code>)
  lorsque l'on connaît le nombre d'itérations (ie. le nombre de fois où le
  traitement doit être répété dans la boucle).</para>
  </listitem>
  <listitem>
  <para>On emploie la boucle <emphasis>répéter jusqu'à</emphasis>
  (<code>do-while</code>) lorsque le corps de la boucle doit être exécuté au
  moins une fois.</para>
  </listitem>
  <listitem>
  <para>On emploie la boucle <emphasis>tant que</emphasis> (<code>while</code>)
  lorsque le corps de la boucle peut ne pas être exécuté.</para>
  </listitem>
</orderedlist>

<sect3 id="sdcc_course.c_language.loops.for">
  <title>Syntaxe de la boucle pour (for)</title>

<para>La boucle <emphasis>pour</emphasis> (<code>for</code>) en C/C++ comprend
3 champs distincts : l'initialisation, le test de sortie et
l'incrémentation.</para>

<programlisting width="80">  for (initialisation; test; incrémentation ) {
  	// Instructions
  }
</programlisting>

<para>Les 3 champs définis ci-dessus peuvent être composés à l'aide de
n'importe quelle expression C/C++ valide. Ce mode de construction des boucles
pour est une originalité importante du C/C++. Il faut cependant être vigilant
lors du choix des expressions placées dans ces champs. Un codage trop compact
(avec des appels multiples de fonctions par exemple) et|ou des opérations sur
des variables sans relations sont très pénalisant pour la mise au point des
programmes.</para>

<itemizedlist spacing="compact">
  <listitem>
  <para><xref linkend="gcc_fibonacci_single"/> : lignes 24 à 30. On trouve
  ici un exemple de boucle pour servant à compter le nombre de calculs à
  effectuer. La variable <code>i</code> sert au comptage. Elle est initialisée
  à <code>0</code> dans le premier champ. Le comptage se poursuit tant que la
  variable <code>i</code> est strictement inférieur au nombre n. À chaque
  «tour» la variable <code>i</code> est incrémentée.</para>
  </listitem>
  <listitem>
  <para><xref linkend="sdcc_fibonacci_single"/> : lignes 35 à 41. On
  retrouve une syntaxe identique à l'exemple précédent.</para>
  </listitem>
</itemizedlist>
</sect3>

<sect3 id="sdcc_course.c_language.loops.do-while">
  <title>Syntaxe de la boucle répéter jusqu'à (do-while)</title>

<para>Conformément à la règle énoncée ci-dessus, le test est effectué après une
première exécution du corps de la boucle <emphasis>répéter jusqu'à</emphasis>
(<code>do-while</code>).</para>

<programlisting width="80">  do {
  	// Instructions
  } while (test);
</programlisting>

<para>Comme dans le cas de la boucle précédente, la condition testée peut être
composée à l'aide de n'importe quelle expression C/C++ valide. Il est donc
préférable de limiter la complexité de cette expression pour faciliter la mise
au point des programmes.</para>

<itemizedlist spacing="compact">
  <listitem>
  <para><xref linkend="sdcc_fibonacci_single"/> : lignes 24 à 30. Ici, la
  saisie du nombre de calculs à effectuer dans la suite du programme est
  répétée tant que la valeur est supérieure ou égale à la limite
  <code>MAX_FIB</code>. La limite <code>MAX_FIB</code> correspond au maximum
  pour lequel le calcul du nombre de Fibonacci est représentable sur 32
  bits.</para>
  </listitem>
</itemizedlist>
</sect3>

<sect3 id="sdcc_course.c_language.loops.while">
  <title>Syntaxe de la boucle tant que (while)</title>

<para>Conformément à la règle énoncée ci-dessus, le test est effectué avant que
le corps de la boucle <emphasis>tant que</emphasis> (<code>while</code>) ne
soit exécuté.</para>

<programlisting width="80">  while (test) {
         // Instructions
  }
</programlisting>

<para>Une fois encore ! attention à l'expression de test.</para>

<itemizedlist spacing="compact">
  <listitem>
  <para><xref linkend="gcc_stdio"/> : lignes 7 et 8. On trouve ici un
  exemple de boucle tant que servant à reproduire à la console le caractère
  saisi au clavier tant que celui-ci est différent du code
  <acronym>ASCII</acronym> <code>EOF</code>. On remarque que la boucle ne
  comprend qu'une seule instruction <function>putchar(c)</function>. C'est la
  raison pour laquelle les accolades ne sont pas nécessaires. Voir <xref linkend="sdcc_course.c_language.delimiters"/>.</para>
  </listitem>
  <listitem>
  <para><xref linkend="sdcc_stdio"/> : lignes 24 à 28. On retrouve le même
  traitement que dans l'exemple précédent. On a simplement ajouté un test
  nécessaire au saut le ligne lors d'un appui sur la touche
  <code>Entrée</code>.</para>
  </listitem>
</itemizedlist>
</sect3>
</sect2>

<sect2 id="sdcc_course.c_language.functions">
  <title>Sous-programmes</title>

<para>La démarche classique de construction d'un programme informatique veut
que l'on découpe un problème complexe en sous-ensembles plus faciles à traiter.
Du point de vue du codage, cette démarche se traduit par l'utilisation de
sous-programmes correspondant à ces sous-ensembles.</para>

<para>La réutilisation de code est un autre argument pour l'emploi des
sous-programmes. Si un même traitement doit être répété à plusieurs reprises
dans un programme, il est préférable de le placer dans un sous-programme qui
sera appelé autant de fois que nécessaire.</para>

<para>Enfin, le recours aux sous-programmes doit faciliter la lecture et la
mise au point des programmes. Un jeu de sous-programmes bien écrit et
compréhensible par un grand nombre de programmeurs peut être réutilisé sous
forme de <emphasis>bibliothèque</emphasis>.</para>

<para>La bibliothèque <systemitem>glibc</systemitem> est probablement l'exemple
le plus emblématique de bibliothèque partagée. Elle est disponible avec la
totalité des chaînes de développement en Langage C sur tous les systèmes
d'exploitation et pour presque tous les processeurs.</para>

<para>Les fonctions <function>getchar</function>, <function>putchar</function>,
<function>printf</function> et <function>atoi</function> sont quelques exemples
de sous-programmes partagés à l'aide de la bibliothèque
<systemitem>glibc</systemitem>. On les retrouve dans les programmes
d'illustration présentés dans ce document.</para>

<example id="gcc_fibonacci_iterative">
  <title>Utilisation d'un sous-programme dans le calcul des nombres de
  Fibonacci</title>
<programlisting width="80">01: #include &lt;stdio.h&gt;
02: #include &lt;stdlib.h&gt;
03: 
04: #define MAX_FIB 49
05: 
06: unsigned long iterative_fibonacci(unsigned long f) {
07: 
08:    unsigned long nombrePrecedent = 0, nombreCourant = 1, fibonacci = 0;
09:    int i;
10: 
11:    if (f &gt; 1 )
12:       for (i = 1; i &lt; f; i++) {
13:          fibonacci = nombrePrecedent + nombreCourant;
14:          nombrePrecedent = nombreCourant;
15:          nombreCourant = fibonacci;
16:       }
17:    else
18:       fibonacci = f;
19: 
20:    return fibonacci;
21: }
22: 
23: main() {
24: 
25:    int n, i;
26: 
27:    printf("Saisir le nombre de calculs de Fibonacci(n) :\n");  
28:    scanf("%d", &amp;n);
29:    if (n &gt;= MAX_FIB) {
30:       printf("Fibonacci(%d) depasse la capacite d'un mot de 32 bits\n", n); 
31:       exit(1);
32:    }
33: 
34:    for (i = 0; i &lt; n; i++)
35:       printf("Fibonacci (%d) = %lu\r\n", i, iterative_fibonacci(i));
36: }
</programlisting>

<para>On retrouve des résultats identiques aux précédents avec le programme <xref linkend="sdcc_course.soft.gcc_fibonacci_iterative"/>.</para>
</example>

<example id="sdcc_fibonacci_iterative">
  <title>Utilisation d'un sous-programme dans le calcul des nombres de
  Fibonacci sur la cible MSC1210</title>
<programlisting width="80">01: #include &lt;msc1210.h&gt;
02: #include "ser_msc1210.h"
03: #include &lt;stdio.h&gt;
04: #include &lt;stdlib.h&gt;
05: 
06: #define MAX_FIB 49
07: 
08: // surdefinition du sous-programme putchar
09: void putchar(char c) {
10:    ser_putc(c);
11:   }
12: 
13: unsigned long iterative_fibonacci(unsigned long f) {
14: 
15:    unsigned long nombrePrecedent = 0, nombreCourant = 1, fibonacci = 0;
16:    int i;
17: 
18:    if (f &gt; 1 )
19:       for (i = 1; i &lt; f; i++) {
20:          fibonacci = nombrePrecedent + nombreCourant;
21:          nombrePrecedent = nombreCourant;
22:          nombreCourant = fibonacci;
23:       }
24:    else
25:       fibonacci = f;
26: 
27:    return fibonacci;
28: }
29: 
30: void main(void) {
31: 
32:    unsigned char s[3] = {'\0','\0','\0'};
33:    int n, i;
34: 
35:    // Appuyer sur &lt;Entree&gt; pour ajuster automatiquement
36:    // le debit de la liaison
37:    autobaud();
38:    EA=1;
39: 
40:    do {
41:       printf("Saisir le nombre de calculs de Fibonacci :\r\n");
42:       ser_gets_echo(s, 2);
43:       n = atoi(s);
44:       if (n &gt;= MAX_FIB)
45:          printf("\nFibonacci(%d) depasse la capacite d'un mot de 32 bits\r\n", n);
46:    } while (n &gt;= MAX_FIB);
47: 
48:    printf("\r\n\n");
49:    for (i = 0; i &lt; n; i++)
50:       printf("Fibonacci (%d) = %lu\r\n", i, iterative_fibonacci(i));
51: 
52:    while(1);
53: }
</programlisting>

<para>On retrouve aussi des résultats identiques aux précédents avec le programme <xref linkend="sdcc_course.soft.sdcc_fibonacci_iterative"/>.</para>

<screen width="80">MSC1210 Ver:000305F10
&gt;M0000 ok
&gt;M8000 ok
&gt;E
&gt;T
&gt;
&gt;Saisir le nombre de calculs de Fibonacci :
11

Fibonacci (0) = 0
Fibonacci (1) = 1
Fibonacci (2) = 1
Fibonacci (3) = 2
Fibonacci (4) = 3
Fibonacci (5) = 5
Fibonacci (6) = 8
Fibonacci (7) = 13
Fibonacci (8) = 21
Fibonacci (9) = 34
Fibonacci (10) = 55
</screen>
</example>

<itemizedlist spacing="compact">
  <listitem>
  <para><xref linkend="gcc_fibonacci_iterative"/> : Dans le programme
  principal (<code>main()</code>), à la ligne 35, on trouve l'appel au
  sous-programme <code>iterative_fibonacci(i)</code>. La variable
  <code>i</code> est passée comme paramètre d'entrée lors de l'appel au
  sous-programme.</para>
  <para>Entre les lignes 6 et 21, on trouve le sous-programme
  <code><function>iterative_fibonacci</function>(<varname>i</varname>)</code>.
  La ligne 6 correspond au prototype du sous-programme : c'est là que l'on
  désigne le nom du sous-programme ainsi que les types des paramètres d'entrée
  et de sortie. Dans l'exemple, les paramètres échangés sont de type
  <code>unsigned long</code>.</para>
  </listitem>
  <listitem>
  <para><xref linkend="sdcc_fibonacci_iterative"/> : On retrouve les mêmes
  éléments que dans le cas précédent. Le sous-programme
  <code><function>iterative_fibonacci</function>(<varname>i</varname>)</code>
  est appelé au niveau de la ligne 50. Ce sous-programme est défini entre les
  lignes 13 et 28. Les paramètres échangés sont du même type entre les deux
  programmes.</para>
  </listitem>
</itemizedlist>
</sect2>
</sect1>

<?custom-pagebreak?>
<sect1 id="sdcc_course.stdio">
  <title>Entrées et sorties standard : fonctions getchar &amp; putchar</title>

<sect2 id="sdcc_course.stdio.os">
  <title>Avec Système d'exploitation</title>
<variablelist>
  <varlistentry id="sdcc_course.c_language.stdio.stdin">
  <term>Entrée standard</term>
  <term>Fonction <function>getchar</function></term>
  <term>Flux <systemitem>stdin</systemitem></term>
  <listitem>
<para>Le mécanisme d'entrée le plus simple consiste à lire un caractère
provenant de <emphasis>l'entrée standard</emphasis>. Suivant le contexte, cette
entrée standard peut prendre différente formes.</para>

<para>Sur un ordinateur, les caractères sont généralement lus à partir d'un
clavier. Ils peuvent cependant provenir de différents «canaux» : fichiers,
redirections de flux ou opérations de séquencement entre les programmes de la
couche <xref linkend="sdcc_course.shell"/> (<wordasword>pipes</wordasword> ou
tubes).</para>

<para>Sur un système embarqué les caractères peuvent provenir des même canaux.
Sans système d'exploitation, la liste des canaux est limitée aux interfaces
disponibles. Dans les exemples présentés dans ce document, c'est la liaison
série qui sert le plus souvent de flux d'entrée standard.</para>

<para>Par principe, la fonction <function>getchar</function> transmet au
programme appelant le caractère suivant de la file d'entrée à chaque
appel.</para>
  </listitem>
  </varlistentry>
  <varlistentry id="sdcc_course.c_language.stdio.stdout">
  <term>Sortie standard</term>
  <term>Fonction <function>putchar</function></term>
  <term>Flux <systemitem>stdout</systemitem></term>
  <listitem>
<para>Par analogie avec le cas de l'entrée standard, le mécanisme le plus simple
consiste à émettre un caractère vers la <emphasis>sortie standard</emphasis>.
Suivant le contexte cette sortie standard peut aussi prendre différentes
formes.</para>

<para>Sur un ordinateur, les caractères sont émis par défaut vers le terminal
(ie. la fenêtre du <xref linkend="sdcc_course.shell"/> courant). Comme pour toute
manipulation au niveau <xref linkend="sdcc_course.shell"/>, les opérations de
séquencement, de redirection et les tubes sont utilisables. Voir les exemples
d'exécution ci-après.</para>
  </listitem>
  </varlistentry>
</variablelist>

<para>Ces mécanismes d'entrées-sorties standard ont été définis avec les systèmes
d'exploitation UNIX au début des années 70. On les retrouve aujourd'hui sur la
totalité des systèmes d'exploitation contemporains. Les files d'attentes des
caractères issus de l'écran, du clavier, des fichiers stockés sur tous types de
supports, etc. sont appelés <emphasis>flux d'entrées-sorties</emphasis>
(<wordasword>input-output streams</wordasword>). Des flux standards ont été
définis ; chacun étant dédié à un «pseudo-périphérique».</para>

<itemizedlist spacing="compact">
  <listitem>
  <para><systemitem>stdin</systemitem> : flux d'entrée ; généralement le
  clavier,</para>
  </listitem>
  <listitem>
  <para><systemitem>stdout</systemitem> : flux de sortie ; généralement
  l'écran,</para>
  </listitem>
  <listitem>
  <para><systemitem>stderr</systemitem> : flux d'erreurs vers lequel sont
  redirigés tous les messages d'erreurs lors de l'exécution d'un
  programme,</para>
  </listitem>
  <listitem>
  <para><systemitem>stdprn</systemitem> : flux d'impression ; généralement
  le port parallèle,</para>
  </listitem>
  <listitem>
  <para><systemitem>stdaux</systemitem> : flux auxiliaire ; généralement
  le port série.</para>
  </listitem>
</itemizedlist>

<mediaobject>
  <imageobject>
    <imagedata fileref="images/os_stdio.png" format="PNG" contentwidth="11.5cm" width="12cm"/>
  </imageobject>
  <textobject>
    <phrase>Flux d'entrées-sorties standard et système d'exploitation</phrase>
  </textobject>
  <caption>
    <para><ulink url="images/os_stdio.png">Flux d'entrées-sorties standard et
    système d'exploitation</ulink></para>
  </caption>
</mediaobject>

<para>Voici un exemple simple de programme utilisant les flux d'entrées-sorties
standard via les fonctions <function>getchar</function> et
<function>putchar</function>. Ce programme recopie les caractères reçus sur le
flux d'entrée <systemitem>stdin</systemitem> vers le flux de sortie
<systemitem>stdout</systemitem>. Cette copie se poursuit tant que le caractère
saisi est différent du code <acronym>ASCII</acronym> de délimitation de fin de
fichier <keycode>EOF</keycode> (code obtenu en appuyant simultanément sur les
touches <keycode>Ctrl + D</keycode>).</para>

<example id="gcc_stdio">
  <title>Utilisation des fonctions <function>getchar</function> &amp;
  <function>putchar</function> avec GCC</title>
<programlisting width="80">01: #include &lt;stdio.h&gt;
02: 
03: int main() {
04: 
05:    char c;
06: 
07:    while ((c = getchar()) != EOF)
08:       putchar(c);
09:    
10:    return 0;
11: }
</programlisting>
</example>

<para>L'exemple d'exécution du programme ci-dessous montre que l'opération de
transfert d'un flux vers l'autre est séquencée par le caractère de saut de
ligne <keycode>\n</keycode>. Le flux d'entrée se «remplit» tant qu'aucun appui
sur la touche <keycode>Entrée</keycode> n'intervient. Dès que le code
<acronym>ASCII</acronym> du saut de ligne entre dans le flux d'entrée standard,
son contenu est transféré au programme utilisateur via l'appel à la fonction
<function>getchar</function>.</para>

<para>Les appels à la fonction <function>putchar</function> suivent le même
fonctionnement vis-à-vis du flux de sortie standard.</para>

<para>Voici un exemple d'exécution du programme <xref linkend="sdcc_course.soft.gcc_stdio"/> :</para>

<screen width="80">$ ./gcc_stdio.out
test
test
123
123
</screen>

<para>Voici deux autres exemples d'exécution du même programme en utilisant les
opérations de séquencement entre les programmes offertes par le <xref linkend="sdcc_course.shell"/>.</para>

<itemizedlist spacing="compact">
  <listitem>
  <para>On commence par créer un fichier <filename>test.txt</filename> à l'aide
  de la commande <command>cat</command>. Tous les caractères saisis au clavier
  sont <emphasis>redirigés</emphasis> vers le fichier. L'opération s'arrête
  avec la saisie du code <acronym>ASCII</acronym> <keycode>EOF</keycode>
  (<keycode>Ctrl + D</keycode>).</para>
  </listitem>
  <listitem>
  <para>Le programme est exécuté avec une nouvelle redirection :
  <userinput>./stdio &lt;test.txt</userinput>. Avec cette redirection, le
  contenu du fichier <filename>test.txt</filename> se substitue au flux
  d'entrée standard <systemitem>stdin</systemitem>.</para>
  </listitem>
  <listitem>
  <para>Le programme est à nouveau exécuté en utilisant un
  <emphasis>tube</emphasis> (<wordasword>pipe</wordasword>). En fait, deux
  programmes sont exécutés : <userinput>cat test.txt</userinput> et
  <userinput>stdio</userinput>. Le premier à pour but d'afficher le contenu du
  fichier texte sur le flux de sortie standard <systemitem>stdout</systemitem>
  (ie. la console). Le fonctionnement du second programme a déjà été décrit
  ci-dessus. L'utilisation du <emphasis>tube</emphasis> permet de transférer la
  sortie du premier programme vers l'entrée du second.</para>
  </listitem>
</itemizedlist>

<screen width="80">phil@b0x:~/src$ cat &gt;test.txt
Fichier texte
exemple
phil@b0x:~/src$ ./stdio &lt;test.txt
Fichier texte
exemple
phil@b0x:~/src$ cat test.txt | ./stdio
Fichier texte
exemple
</screen>

<para>Pour plus de détails sur les manipulations à la console, voir <xref linkend="sdcc_course.docs.rute.fr"/>.</para>
</sect2>

<sect2 id="sdcc_course.stdio.msc1210">
  <title>Sans système d'exploitation &amp; cible MSC1210</title>

<mediaobject>
  <imageobject>
    <imagedata fileref="images/no_os_stdio.png" format="PNG" contentwidth="11.5cm" width="12cm"/>
  </imageobject>
  <textobject>
    <phrase>Flux d'entrées-sorties standard sans système d'exploitation</phrase>
  </textobject>
  <caption>
    <para><ulink url="images/no_os_stdio.png">Flux d'entrées-sorties standard
    sans système d'exploitation</ulink></para>
  </caption>
</mediaobject>

<para>Voici maintenant le même exemple simple de programme utilisant les flux
d'entrées-sorties standard sur un système spécialisé. Dans ce contexte sans
système d'exploitation, on ne dispose pas de définition des flux
<systemitem>stdin</systemitem> et <systemitem>stdout</systemitem> entre le
noyau et le <xref linkend="sdcc_course.shell"/>. On continue cependant à
utiliser les fonctions <function>getchar</function> et
<systemitem>putchar</systemitem>.</para>

<para>La technique usuelle sur les systèmes spécialisés consiste à donner une
nouvelle définition de ces deux fonctions en désignant explicitement le canal
de réception et d'émission des caractères. Dans l'exemple, c'est la liaison
série entre le <acronym>PC</acronym> de développement et le système
spécialisé qui sert à faire transiter les caractères dans les deux
sens.</para>

<example id="sdcc_stdio">
  <title>Utilisation des fonctions <function>getchar</function> &amp;
  <function>putchar</function> sur microcontrôleur MSC120 avec SDCC</title>
<programlisting width="80">01: #include &lt;stdio.h&gt;
02: #include &lt;msc1210.h&gt;
03: #include "ser_msc1210.h"
04: 
05: #define EOF 0x04
06: #define CR  0x0d
07: 
08: char getchar(void) {
09:   return ser_getc();
10: }
11: 
12: void putchar(char c) {
13:   ser_putc(c);
14: }
15: 
16: void main(void) {
17: 
18:    char c;
19: 
20:    // Press &lt;Enter&gt; for auto baudrate adjust
21:    autobaud();
22:    EA=1;
23: 
24:    while ((c = getchar()) != EOF) {
25:       if (c == CR)
26:          putcr();
27:       putchar(c);
28:    }
29:    putcr();
30:    putchar('!');
31:    putcr();
32: 
33:    while (1);
34: }
</programlisting>
</example>

<para>Comme on l'a déjà indiqué, il n'existe pas de couche Shell dans ce
contexte. On ne dispose donc pas d'opération de séquencement entre programmes
puisque cet exemple est le seul programme exécuté par le microcontrôleur.</para>

<para>Voici un exemple d'exécution du programme <xref linkend="sdcc_course.soft.sdcc_stdio"/> :</para>

<screen width="80">MSC1210 Ver:000305F10
&gt;M0000 ok
&gt;M8000 ok
&gt;E
&gt;T
&gt;
&gt;azerty
123

!
</screen>

<itemizedlist spacing="compact">
  <listitem>
  <para><xref linkend="gcc_fibonacci_single"/> : ce programme ne fait pas
  directement appel aux fonctions <function>getchar</function> et
  <function>putchar</function>. Il utilise plutôt les fonctions
  d'entrées-sorties formatées décrites ci-après.</para>
  </listitem>
  <listitem>
  <para><xref linkend="sdcc_fibonacci_single"/> : lignes 11 à 13. La
  liaison série étant utilisée comme canal d'entrée-sortie standard, on définit
  la fonction <function>putchar</function> en conséquence. Cette définition est
  ensuite réutilisée pour les sorties formatées lors des appels à la fonction
  <function>printf</function> : lignes 27, 31, 34, 42 et 45. Pour la
  saisie du nombre de calcul, la fonction <function>ser_gets_echo</function>
  est définie dans le fichier d'en-tête
  <xref linkend="sdcc_course.soft.ser_msc1210.h"/>.</para>
  </listitem>
</itemizedlist>
</sect2>
</sect1>

<?custom-pagebreak?>
<sect1 id="sdcc_course.formatted_io">
  <title>Entrées et sorties formatées : fonctions scanf &amp;
  printf</title>

<sect2 id="sdcc_course.formatted_io.defintions">
  <title>Définitions générales</title>

<para>Les flux d'entrées-sorties standards sont limités aux manipulations sur
des caractères codés en <acronym>ASCII</acronym>. Cette limitation est très
contraignante lorsque l'on cherche à formater l'affichage de valeurs
numériques. C'est pour dépasser ces contraintes que l'on a introduit deux
fonctions dédiées à la «traduction» entre valeurs numériques et chaînes de
caractères. La fonction <function>printf</function> sert à formater les sorties
sur le flux <systemitem>stdout</systemitem> et la fonction
<function>scanf</function> sert à formater les entrées reçues sur le flux
<systemitem>stdin</systemitem>.</para>

<para>Les prototypes génériques de ces deux fonctions se présentent sous la
forme :</para>

<programlisting width="80">scanf(control, arg1, arg2, ...)
printf(control, arg1, arg2, ...)
</programlisting>

<itemizedlist spacing="compact">
  <listitem>
  <para><option>control</option> est une chaîne de caractère qui sert à mettre
  en forme les arguments. Cette chaîne peut contenir des caractères
  «ordinaires» qui sont recopiés directement depuis ou vers le flux
  d'entrée-sortie standard et des formats de conversion positionnés dans la
  chaîne à l'aide du caractère balise <code>%</code> suivi du format
  choisi.</para>
  </listitem>
  <listitem>
  <para>Les arguments <option>arg1, arg2, ...</option>, doivent correspondre à
  chaque caractère <code>%</code> placé dans la chaîne
  <option>control</option>.</para>
  </listitem>
</itemizedlist>

<para>Le caractère <code>%</code> est une balise de positionnement suivie d'une
spécification de traduction dont le prototype est :
<option>%[indicateur][largeur][.precision][modification]type</option>.</para>

<itemizedlist spacing="compact">
  <listitem>
  <para>Tous les champs notés entre crochets sont optionnels.</para>
  </listitem>
  <listitem>
  <para>Spécifications du champ obligatoire <option>type</option> :</para>

<table id="sdcc_course.formatted_io.conversion_types" pgwide="1" frame="all">
  <title>Types de conversion</title>
  <tgroup cols="2" align="left" colsep="1" rowsep="1">
    <colspec colnum="1" colwidth="1*"/>
    <colspec colnum="2" colwidth="4*"/>
  <thead>
    <row>
    <entry><option>type</option></entry>
    <entry>signification</entry>
    </row>
  </thead>
  <tbody>
    <row>
    <entry><code>%c</code></entry>
    <entry>caractère</entry>
    </row>
    <row>
    <entry><code>%s</code></entry>
    <entry>chaîne de caractères</entry>
    </row>
    <row>
    <entry><code>%d</code></entry>
    <entry>nombre entier en décimal</entry>
    </row>
    <row>
    <entry><code>%e</code></entry>
    <entry>nombre réel sous la forme mantisse/exposant
    <code>[-]m.nnnnnne[+|-]xx</code></entry>
    </row>
    <row>
    <entry><code>%E</code></entry>
    <entry>nombre réel sous la forme mantisse/exposant en majuscule
    <code>[-]m.nnnnnnE[+|-]xx</code></entry>
    </row>
    <row>
    <entry><code>%f</code></entry>
    <entry>nombre réel sous la forme <code>[-]mmm.nnnnnn</code></entry>
    </row>
    <row>
    <entry><code>%g</code></entry>
    <entry>nombre réel sous la forme la plus courte entre les types
    <code>%e</code> et <code>%f</code></entry>
    </row>
    <row>
    <entry><code>%G</code></entry>
    <entry>nombre réel sous la forme la plus courte entre les types
    <code>%E</code> et <code>%f</code></entry>
    </row>
    <row>
    <entry><code>%o</code></entry>
    <entry>nombre entier en octal</entry>
    </row>
    <row>
    <entry><code>%p</code></entry>
    <entry>pointeur ou adresse de la valeur numérique</entry>
    </row>
    <row>
    <entry><code>%u</code></entry>
    <entry>nombre entier non signé en décimal</entry>
    </row>
    <row>
    <entry><code>%x</code></entry>
    <entry>nombre entier en hexadécimal</entry>
    </row>
    <row>
    <entry><code>%X</code></entry>
    <entry>nombre entier en hexadécimal ; lettres affichées en
    majuscules</entry>
    </row>
  </tbody>
  </tgroup>
</table>
  </listitem>
  <listitem>
  <para>Spécifications du champ optionnel
  <option>[indicateur]</option> :</para>

<table id="sdcc_course.formatted_io.flag" pgwide="1" frame="all">
  <title>Indicateur d'affichage</title>
  <tgroup cols="2" align="left" colsep="1" rowsep="1">
    <colspec colnum="1" colwidth="1*"/>
    <colspec colnum="2" colwidth="4*"/>
  <thead>
    <row>
    <entry><option>[indicateur]</option></entry>
    <entry>signification</entry>
    </row>
  </thead>
  <tbody>
    <row>
    <entry><code>-</code></entry>
    <entry>alignement à gauche pour la largeur donnée</entry>
    </row>
    <row>
    <entry><code>+</code></entry>
    <entry>affichage forcé du signe de la valeur numérique</entry>
    </row>
    <row>
    <entry><code>espace</code></entry>
    <entry>insertion d'un caractère d'espacement si la valeur numérique est
    positive</entry>
    </row>
    <row>
    <entry morerows="2" valign="middle"><code>#</code></entry>
    <entry>affichage précédé de <code>0</code>, <code>0x</code> ou
    <code>0X</code> avec les types respectifs <code>o</code>, <code>x</code> ou
    <code>X</code></entry>
    </row>
    <row>
    <entry>force l'affichage du point décimal avec les types <code>e</code>,
    <code>E</code> et <code>f</code> même si la partie décimale ne contient que
    des zéros</entry>
    </row>
    <row>
    <entry>force l'affichage du point décimal avec les types <code>g</code>
    et <code>G</code> sans supprimer les zéros inutiles</entry>
    </row>
  </tbody>
  </tgroup>
</table>
  </listitem>
  <listitem>
  <para>Spécifications du champ optionnel
  <option>[largeur]</option> :</para>

<table id="sdcc_course.formatted_io.width" pgwide="1" frame="all">
  <title>Largeur de l'affichage</title>
  <tgroup cols="2" align="left" colsep="1" rowsep="1">
    <colspec colnum="1" colwidth="1*"/>
    <colspec colnum="2" colwidth="4*"/>
  <thead>
    <row>
    <entry><option>[largeur]</option></entry>
    <entry>signification</entry>
    </row>
  </thead>
  <tbody>
    <row>
    <entry>nombre</entry>
    <entry>nombre minimum de caractères à afficher ; ajout de caractères
    d'espacement si la valeur est plus «courte» que l'affichage demandé</entry>
    </row>
    <row>
    <entry><code>0</code>nombre</entry>
    <entry>idem ci-dessus ; ajout de caractères <code>0</code> si la valeur est
    plus «courte» que l'affichage demandé</entry>
    </row>
    <row>
    <entry><code>*</code>nombre</entry>
    <entry>la largeur n'est pas spécifiée dans la chaîne
    <option>control</option> mais par un entier précédent l'argument à
    afficher</entry>
    </row>
  </tbody>
  </tgroup>
</table>
  </listitem>
  <listitem>
  <para>Spécifications du champ optionnel
  <option>[precision]</option> :</para>

<table id="sdcc_course.formatted_io.precision" pgwide="1" frame="all">
  <title>Precision de l'affichage</title>
  <tgroup cols="2" align="left" colsep="1" rowsep="1">
    <colspec colnum="1" colwidth="1*"/>
    <colspec colnum="2" colwidth="4*"/>
  <thead>
    <row>
    <entry><option>[precision]</option></entry>
    <entry>signification</entry>
    </row>
  </thead>
  <tbody>
    <row>
    <entry morerows="4" valign="middle"><code>.</code>nombre</entry>
    <entry>pour les types <code>d</code>, <code>i</code>, <code>o</code>,
    <code>u</code>, <code>x</code> et <code>X</code> : nombre minimum de
    chiffres décimaux à afficher ; ajout de caractères d'espacement si la
    valeur est plus «courte» que l'affichage demandé</entry>
    </row>
    <row>
    <entry>pour les types <code>e</code>, <code>E</code> et
    <code>f</code> : nombre de chiffres à afficher après le point
    décimal</entry>
    </row>
    <row>
    <entry>pour les types <code>g</code> et <code>G</code> : nombre
    maximum de chiffres significatifs à afficher</entry>
    </row>
    <row>
    <entry>pour le type <code>s</code> : nombre maximum de caractères à
    afficher</entry>
    </row>
    <row>
    <entry>pour le type <code>c</code> : pas d'effet</entry>
    </row>
  </tbody>
  </tgroup>
</table>
  </listitem>
  <listitem>
  <para>Spécifications du champ optionnel
  <option>[modification]</option> :</para>

<table id="sdcc_course.formatted_io.modifier" pgwide="1" frame="all">
  <title>Modification de l'affichage</title>
  <tgroup cols="2" align="left" colsep="1" rowsep="1">
    <colspec colnum="1" colwidth="1*"/>
    <colspec colnum="2" colwidth="4*"/>
  <thead>
    <row>
    <entry><option>[modification]</option></entry>
    <entry>signification</entry>
    </row>
  </thead>
  <tbody>
    <row>
    <entry><code>h</code></entry>
    <entry>argument traité comme un entier court
    (<wordasword>short</wordasword>)</entry>
    </row>
    <row>
    <entry><code>l</code></entry>
    <entry>argument traité comme un entier long pour les types entiers
    (<wordasword>long</wordasword>) ou comme un réel double pour les types
    réels (<wordasword>double</wordasword>)</entry>
    </row>
    <row>
    <entry><code>L</code></entry>
    <entry>argument traité comme un réel <wordasword>long
    double</wordasword></entry>
    </row>
  </tbody>
  </tgroup>
</table>
  </listitem>
</itemizedlist>

<para>Voici deux programmes d'illustration de sorties formatées avec la fonction
<function>printf</function>. Le premier bénéficie du jeu de définitions complet
sur GNU/Linux. Le second, exécuté sur un microcontrôleur
<acronym>MSC1210</acronym> et compilé avec <link linkend="sdcc_course.tools.sdcc">SDCC</link>, ne dispose que d'un jeu de
définitions de formats plus restreint.</para>
</sect2>

<sect2 id="sdcc_course.formatted_io.gcc">
  <title>Exemple avec GCC</title>

<example id="stdio_gcc_printf">
  <title>Sorties formatées avec <function>printf</function> sur GNU/Linux avec
  GCC</title>
<programlisting width="80">01: /* $Id: gcc_printf.c 1129 2007-05-07 15:07:52Z latu $ */
02: 
03: #include &lt;stdio.h&gt;
04: 
05: #define M_PI  3.14159265358979323846  /* pi */
06: 
07: #define YEAR 2007
08: 
09: int main() {
10: 
11:    printf ("Caracteres : %c %c %c %c\n", 'a', 65, 0x30, '0');
12:    printf ("Entiers : %d %ld\n", YEAR, 650000);
13:    printf ("Affichage avec espaces : |%10d|\n", YEAR);
14:    printf ("Affichage avec zeros : |%010d|\n", YEAR);
15:    printf ("Differentes bases : %d %x %o %#x %#o \n", 100, 100, 100, 100, 100);
16:    printf ("Reels : |%4.2f| |%+.4e| |%E|\n", M_PI, M_PI*YEAR, M_PI);
17:    printf ("Largeur en argument : |%*d|\n", 5, 10);
18:    printf ("%s\n", "Debian GNU/Linux");
19:    return 0;
20: }
</programlisting>

<para>Voici un exemple d'exécution du programme <xref linkend="sdcc_course.soft.gcc_printf"/> :</para>

<screen width="80">$ ./gcc_printf.out
Caracteres : a A 0 0
Entiers : 2007 650000
Affichage avec espaces : |      2007|
Affichage avec zeros : |0000002007|
Differentes bases : 100 64 144 0x64 0144
Reels : |3.14| |+6.3052e+03| |3.141593E+00|
Largeur en argument : |   10|
Debian GNU/Linux
</screen>
</example>
</sect2>

<sect2 id="sdcc_course.formatted_io.sdcc">
  <title>Exemple avec SDCC sur cible MSC1210</title>

<para>Par défaut, le support des nombres réels est désactivé dans la chaîne de
développement <acronym>SDCC</acronym>. Il est nécessaire de passer par une
recompilation manuelle des outils de compilation pour obtenir le résultat
ci-dessous. Voir <xref linkend="sdcc_course.tools.sdcc"/>.</para>

<example id="stdio_sdcc_printf">
  <title>Sorties formatées avec <function>printf</function> sur un
  microcontrôleur MSC1210 avec SDCC</title>
<programlisting width="80">01: #define YEAR 2007
02: 
03: void putchar(char c) {
04:    ser_putc(c);
05: }
06: 
07: int main() {
08: 
09:    autobaud();
10:    EA = 1;
11: 
12:    printf ("Caracteres : %c %c %c %c\n\r", 'a', 65, 0x30, '0');
13:    printf ("Entiers : %d %ld\n\r", YEAR, 650000);
14:    printf ("Affichage avec espaces : |%10d|\n\r", YEAR);
15:    printf ("Affichage avec zeros : |%010d|\n\r", YEAR);
16:    printf ("Differentes bases : %d %x %o %#x %#o \n\r", 100, 100, 100, 100, 100);
17:    printf ("Reels : |%f| |%+.4f| |%e|\n\r", M_PI, M_PI*YEAR, M_PI);
18:    printf ("Largeur en argument : |%*d|\n\r", 5, 10);
19:    printf ("%s\n\r", "Debian GNU/Linux");
20:    return 0;
21: }
</programlisting>

<para>Voici un exemple d'exécution du programme <xref linkend="sdcc_course.soft.sdcc_printf"/> :</para>

<screen width="80">MSC1210 Ver:000305F10
&gt;M0000 ok
&gt;M8000 ok
&gt;E
&gt;T
&gt;
&gt;Caracteres : a A 0 0
Entiers : 2007 650000
Affichage avec espaces : |      2007|
Affichage avec zeros : |0000002007|
Differentes bases : 100 64 144 #x #o
Reels : |3.141593| |+6305.1762| |E|
Largeur en argument : |*d|
Debian GNU/Linux
</screen>
</example>

<para>La copie d'écran ci-dessus montre que toutes les options de formatage des
sorties ne sont pas supportées par la bibliothèque standard implantée dans la
chaîne de développement <acronym>SDCC</acronym>. C'est une situation classique,
sachant qu'un système spécialisé n'est pas fait pour réaliser une interface
utilisateur.</para>
</sect2>

<sect2 id="sdcc_course.formatted_io.special_chars">
  <title>Utilisation des caractères spéciaux</title>

<table id="sdcc_course.formatted_io.special_chars_table" pgwide="1" frame="all">
  <title>Caractères spéciaux</title>
  <tgroup cols="2" align="left" colsep="1" rowsep="1">
    <colspec colnum="1" colwidth="1*"/>
    <colspec colnum="2" colwidth="4*"/>
  <thead>
    <row>
    <entry>Séquence d'échappement</entry>
    <entry>signification</entry>
    </row>
  </thead>
  <tbody>
    <row>
    <entry>%%</entry>
    <entry>affichage du caractère '%'</entry>
    </row>
    <row>
    <entry>\0</entry>
    <entry>caractère <wordasword>null</wordasword> ; valeur 0, délimiteur de
    fin de chaîne de caractères</entry>
    </row>
    <row>
    <entry>\a</entry>
    <entry>alerte ; <wordasword>beep</wordasword> système</entry>
    </row>
    <row>
    <entry>\b</entry>
    <entry><wordasword>backspace</wordasword> ; déplacement du curseur d'un
    caractère en arrière</entry>
    </row>
    <row>
    <entry>\f</entry>
    <entry><wordasword>form feed</wordasword> ; saut de page</entry>
    </row>
    <row>
    <entry>\n</entry>
    <entry><wordasword>new line</wordasword> ; saut de ligne</entry>
    </row>
    <row>
    <entry>\r</entry>
    <entry><wordasword>carriage return</wordasword> ; retour chariot</entry>
    </row>
    <row>
    <entry>\t</entry>
    <entry>tabulation horizontale</entry>
    </row>
    <row>
    <entry>\v</entry>
    <entry>tabulation verticale</entry>
    </row>
    <row>
    <entry>\\</entry>
    <entry>affichage du caractère <code>'\'</code></entry>
    </row>
    <row>
    <entry>\'</entry>
    <entry>affichage du caractère <code>'''</code></entry>
    </row>
    <row>
    <entry>\"</entry>
    <entry>affichage du caractère <code>'"'</code></entry>
    </row>
    <row>
    <entry>\Onn</entry>
    <entry>affichage de la valeur <code>nn</code> en octal</entry>
    </row>
    <row>
    <entry>\Xnn</entry>
    <entry>affichage de la valeur <code>nn</code> en hexadécimal</entry>
    </row>
  </tbody>
  </tgroup>
</table>
</sect2>
</sect1>

<?custom-pagebreak?>
<sect1 id="sdcc_course.lcd">
  <title>Gestion d'un afficheur à cristaux liquides (LCD)</title>

  <para>L'utilisation d'un afficheur à cristaux liquides ou
  <acronym>LCD</acronym> est assez courante sur les systèmes embarqués. C'est
  un écran de faible dimension employé pour informer l'utilisateur sur l'état
  du système ou pour afficher les mesures effectuées par différents
  capteurs.</para>

  <para>Il existe un standard très populaire qui permet de gérer les
  communications avec la grande majorité des modèles d'afficheurs
  <acronym>LCD</acronym> quelque soit le fabricant. Ce standard est connu sous
  le le nom <citetitle>HD44780U</citetitle>. Ce nom correspond au contrôleur
  qui reçoit les données du microcontrôleur et qui les communique directement
  avec l'afficheur à cristaux liquides.</para>

<sect2 id="sdcc_course.lcd.HD44780U">
  <title>Caractéristiques d'un afficheur du type HD44780U</title>

  <para>La standard <citetitle>HD44780U</citetitle> utilise 3 signaux de
  contrôle ainsi que 4 ou 8 lignes d'entrée-sortie pour le bus de données.
  L'utilisateur peut choisir si l'afficheur à cristaux liquides doit
  fonctionner avec un bus de données de 4 bits ou un bus de données de 8 bits.
  Si un bus de données de 4 bits est utilisé l'afficheur <acronym>LCD</acronym>
  utilise un total de 7 lignes (3 signaux de contrôle plus les 4 lignes pour le
  bus de données). Si un bus de données de 8 bits est utilisé l'afficheur
  <acronym>LCD</acronym> utilise un total de 11 lignes (3 signaux de contrôle
  plus les 8 lignes pour le bus de données).</para>

  <para>Les trois signaux de contrôle sont appelés :
  <acronym>EN</acronym>, <acronym>RS</acronym> et <acronym>RW</acronym>.</para>

  <variablelist>
    <varlistentry id="sdcc_course.lcd.HD44780U.EN">
      <term><acronym>EN</acronym></term>
      <term><wordasword>enable</wordasword></term>
      <listitem>
      <para>Le signal <wordasword>enable</wordasword> est utilisé pour indiquer
      à l'afficheur à cristaux liquides qu'on va lui envoyer des données. Pour
      envoyer des données à l'afficheur, le programme doit s'assurer que le
      signal est au niveau bas (<code>0</code>) avant de faire évoluer les deux
      autres signaux de contrôle et de placer des données sur le bus de
      données. Quand l'ensemble des autres lignes sont correctement
      positionnées, le signal <acronym>EN</acronym> doit être placé au niveau
      haut (<code>1</code>) et il faut attendre un temps minimum requis par le
      composant (ce temps varie d'un afficheur à l'autre) avant de le placer au
      niveau bas (<code>0</code>) à nouveau.</para>
      </listitem>
    </varlistentry>
    <varlistentry id="sdcc_course.lcd.HD44780U.RS">
      <term><acronym>RS</acronym></term>
      <term><wordasword>register select</wordasword></term>
      <listitem>
      <para>Le signal <wordasword>register select</wordasword> est utilisé pour
      distinguer les instructions de commande des données à afficher. Si on
      place <acronym>RS</acronym> au niveau bas (<code>0</code>), les données
      sont traitées comme une commande ou instruction spéciale (effacer
      l'écran, positionner le curseur de position, etc.). Si on place
      <acronym>RS</acronym> au niveau haut (<code>1</code>), les données
      envoyées sont des caractères que l'écran doit afficher.</para>
      </listitem>
    </varlistentry>
    <varlistentry id="sdcc_course.lcd.HD44780U.RW">
      <term><acronym>RW</acronym></term>
      <term><wordasword>read/write</wordasword></term>
      <listitem>
      <para>Le signal <wordasword>read/write</wordasword> est utilisé pour
      distinguer si les informations sur le bus de données sont lues ou
      écrites. Si on place le signal <acronym>RW</acronym> au niveau haut
      (<code>1</code>), le programme interroge l'afficheur à cristaux liquides
      sur son état (<wordasword>Get LCD status</wordasword>). Dans tous les
      autres cas des commandes sont écrites. Ainsi, le signal
      <acronym>RW</acronym> sera presque toujours au niveau bas.</para>
      </listitem>
    </varlistentry>
  </variablelist>
</sect2>

<sect2 id="sdcc_course.lcd.sdcc">
  <title>Utilisation d'un afficheur LCD avec SDCC sur cible MSC1210</title>

<para>Le premier exemple reprend le programme <link linkend="sdcc_course.hello">«Hello, World!»</link> en utilisant l'afficheur
<acronym>LCD</acronym> comme écran.</para>

<example id="sdcc_hello_lcd">
  <title>Programme «Hello, World!» sur afficheur LCD</title>
<programlisting width="80">01: #include &lt;stdio.h&gt;
02: #include &lt;msc1210.h&gt;
03: #include "ser_msc1210.h"
04: #include "lcd_msc1210.h"
05: 
06: void putchar(char c) {
07:    if (print2lcd)
08:       lcd_putc(c);
09:    else
10:       ser_putc(c);
11: }
12: 
13: void main(void) {
14: 
15:    // Appuyer sur &lt;Entrée&gt; pour ajuster
16:    // automatiquement le (débit|baudrate)
17:    autobaud();
18: 
19:    // Initialisations pour SDCC
20:    EA=1;
21: 
22:    print2lcd = 0;
23: 
24:    // initialisation de l'afficheur LCD
25:    lcd_init();
26: 
27:    // effacement de l'écran
28:    lcd_clear();
29: 
30:    // positionnement du curseur dans 
31:    // le coin supérieur gauche
32:    lcd_home();
33: 
34:    print2lcd = 1;
35:    printf("Hello, World !");
36: 
37:    // Affichage du même message 
38:    // sur la console
39:    print2lcd = 0;
40:    printf("Hello, World!");
41:    putcr();
42: 
43:    while(1);
44: }
</programlisting>

<para>Voici le résultat de l'exécution du programme <xref linkend="sdcc_course.soft.hello_lcd"/> :</para>

<mediaobject>
  <imageobject>
    <imagedata fileref="images/hello_lcd.png" format="PNG" contentwidth="8.5cm" width="9cm"/>
  </imageobject>
  <textobject>
    <phrase>Programme «Hello, World!» sur afficheur LCD</phrase>
  </textobject>
  <caption>
    <para><ulink url="images/hello_lcd.png">Programme «Hello, World!» sur
    afficheur LCD</ulink></para>
  </caption>
</mediaobject>
</example>

<para>Le second exemple illustre le positionnement du curseur d'affichage sur
l'écran à cristaux liquides.</para>

<para>Le modèle d'écran à cristaux liquides utilisé dans les exemples suivants
dispose de 4 lignes de 20 caractères. Chaque caractère alphanumérique est
accessible via une adresse définie dans le plan ci-dessous. On remarque que les
adresses de chaque ligne ne sont pas consécutives ; ce qui n'est pas des plus
pratique pour gérer le positionnement du curseur d'affichage.</para>

<screen width="80">ligne 0 : 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13
ligne 1 : 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53
ligne 2 : 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27
ligne 3 : 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67
</screen>


<example id="sdcc_lcd_set_xy">
  <title>Programme de positionnement du curseur sur un afficheur LCD</title>
<programlisting width="80">01: #include &lt;stdio.h&gt;
02: #include &lt;stdlib.h&gt;
03: #include &lt;msc1210.h&gt;
04: 