Skip to content
Snippets Groups Projects
Commit 71236ca2 authored by Peter Gerwinski's avatar Peter Gerwinski
Browse files

Musterlösung 28.11.2019

parent a8ca1428
No related branches found
No related tags found
No related merge requests found
#include <stdio.h>
#include "dates.h"
int is_leap_year (int year)
{
if (year % 4 == 0)
if (year % 100 == 0)
if (year % 400 == 0)
return 1;
else
return 0;
else
return 1;
else
return 0;
}
int days_in_month (int month, int year)
{
if (month == 2)
if (is_leap_year (year))
return 29;
else
return 28;
else if (month == 4 || month == 6 || month == 9 || month == 11)
return 30;
else
return 31;
}
void date_print (date *d)
{
printf ("%02d.%02d.%04d", d->day, d->month, d->year);
}
int date_set (date *d, char day, char month, int year)
{
d->year = year;
if (month > 0 && month <= 12)
d->month = month;
else
return 0;
if (day > 0 && day <= days_in_month (month, year))
d->day = day;
else
return 0;
return 1;
}
void date_next (date *d)
{
d->day++;
if (d->day > days_in_month (d->month, d->year))
{
d->month++;
d->day = 1;
if (d->month > 12)
{
d->year++;
d->month = 1;
}
}
}
typedef struct
{
char day, month;
int year;
}
date;
extern void date_print (date *d);
extern int date_set (date *d, char day, char month, int year);
extern void date_next (date *d);
File added
% hp-musterloesung-20191128.pdf - Solutions to the Exercises on Low-Level Programming
% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019 Peter Gerwinski
%
% This document is free software: you can redistribute it and/or
% modify it either under the terms of the Creative Commons
% Attribution-ShareAlike 3.0 License, or under the terms of the
% GNU General Public License as published by the Free Software
% Foundation, either version 3 of the License, or (at your option)
% any later version.
%
% This document is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this document. If not, see <http://www.gnu.org/licenses/>.
%
% You should have received a copy of the Creative Commons
% Attribution-ShareAlike 3.0 Unported License along with this
% document. If not, see <http://creativecommons.org/licenses/>.
% README: Datum-Bibliothek, Text-Grafik-Bibliothek, LED-Blinkmuster
\documentclass[a4paper]{article}
\usepackage{pgscript}
\usepackage{sfmath}
\begin{document}
\section*{Hardwarenahe Programmierung\\
Musterlösung zu den Übungsaufgaben -- 28.\ November 2019}
\exercise{Datum-Bibliothek}
Zerlegen Sie die Datum-Bibliothek aus der Übungsaufgabe 2 vom 7.\,11.\,2019
in eine \file{.c}- und eine \file{.h}-Datei. \points{4}
Hinweis: Schreiben Sie zusätzlich ein Test-Programm.
\solution
Die Dateien \gitfile{hp}{20191128}{dates.c} und \gitfile{hp}{20191128}{dates.h} enthalten die Bibliothek,
die Datei \gitfile{hp}{20191128}{test-dates.c} ein Programm zum Testen der Bibliothek.
\exercise{Text-Grafik-Bibliothek}
Schreiben Sie eine Bibliothek für "`Text-Grafik"' mit folgenden Funktionen:\vspace*{-\medskipamount}
\begin{itemize}
\item
\lstinline|void clear (char c)|\\
Bildschirm auf Zeichen \lstinline|c| löschen,\\
also komplett mit diesem Zeichen (z.\,B.: Leerzeichen) füllen
\item
\lstinline|void put_point (int x, int y, char c)|\\
Punkt setzen (z.\,B.\ einen Stern (\lstinline{*}) an die Stelle $(x,y)$ "`malen"')
\item
\lstinline|char get_point (int x, int y)|\\
Punkt lesen
% \item
% \lstinline|void fill (int x, int y, char c, char o)|\\
% Fläche in der "`Farbe"' \lstinline|o|,
% die den Punkt \lstinline|(x, y)| enthält,
% mit der "`Farbe"' \lstinline|c| ausmalen
\item
\lstinline|void display (void)|\\
das Gezeichnete auf dem Bildschirm ausgeben
\end{itemize}
Hinweise:\vspace*{-\medskipamount}
\begin{itemize}
\item
Eine C-Bibliothek besteht aus (mindestens)
einer \file{.h}-Datei und einer \file{.c}-Datei.
\item
Verwenden Sie ein Array als "`Bildschirm"'.
Vor dem Aufruf der Funktion \lstinline|display()| ist nichts zu sehen;\\
alle Grafikoperationen erfolgen auf dem Array.
\item
Verwenden Sie Präprozessor-Konstante,
z.\,B.\ \lstinline{WIDTH} und \lstinline{HEIGHT},\\
um Höhe und Breite des "`Bildschirms"' festzulegen:
\begin{lstlisting}[gobble=8]
#define WIDTH 72
#define HEIGHT 24
\end{lstlisting}
\item
Schreiben Sie zusätzlich ein Test-Programm,
das alle Funktionen der Bibliothek benutzt,\\
um ein hübsches Bild (z.\,B.\ ein stilisiertes Gesicht -- "`Smiley"')
auszugeben.
\end{itemize}
\points{8}
\solution
Siehe die Dateien \gitfile{hp}{20191128}{textgraph.c} und \gitfile{hp}{20191128}{textgraph.h} (Bibliothek)
sowie \gitfile{hp}{20191128}{test-textgraph.c} (Test-Programm).
Diese Lösung erfüllt zusätzlich die Aufgabe,
bei fehlerhafter Benutzung (Koordinaten außerhalb des Zeichenbereichs)
eine sinnvolle Fehlermeldung auszugeben,
anstatt unkontrolliert Speicher zu überschreiben und abzustürzen.
Das Schlüsselwort \lstinline{static}
bei der Deklaration der Funktion \lstinline{check_coordinates()}
bedeutet, daß diese Funktion nur lokal (d.\,h.\ innerhalb der Bibliothek)
verwendet und insbesondere nicht nach außen
(d.\,h.\ für die Benutzung durch das Hauptprogramm) exportiert wird.
Dies dient dazu, nicht unnötig Bezeichner zu reservieren
(Vermeidung von "`Namensraumverschmutzung"').
Man beachte die Verwendung einfacher Anführungszeichen (Apostrophe)
bei der Angabe von \lstinline{char}-Kon"-stanten (\lstinline{'*'})
im Gegensatz zur Verwendung doppelter Anführungszeichen
bei der Angabe von String-Konstanten
(String = Array von \lstinline{char}s, abgeschlossen mit Null-Symbol).
Um das einfache Anführungszeichen selbst als \lstinline{char}-Konstante anzugeben,
ist ein vorangestellter Backslash erforderlich: \lstinline{'\''} ("`Escape-Sequenz"').
Entsprechendes gilt für die Verwendung doppelter Anführungszeichen
innerhalb von String-Konstanten:
\lstinline{printf ("Your name is: \"%s\"", name);}
\exercise{LED-Blinkmuster}
Wir betrachten das folgende Programm für einen ATmega32-Mikro-Controller
(Datei: \gitfile{hp}{20191128}{aufgabe-3.c}).
\begin{minipage}[t]{7cm}
\begin{lstlisting}[gobble=6]
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
uint8_t counter = 1;
uint8_t leds = 0;
ISR (TIMER0_COMP_vect)
{
if (counter == 0)
{
leds = (leds + 1) % 8;
PORTC = leds << 4;
}
counter++;
}
\end{lstlisting}
\end{minipage}\hfill\begin{minipage}[t]{8.5cm}
\begin{lstlisting}[gobble=6]
void init (void)
{
cli ();
TCCR0 = (1 << CS01) | (1 << CS00);
TIMSK = 1 << OCIE0;
sei ();
DDRC = 0x70;
}
int main (void)
{
init ();
while (1)
; /* do nothing */
return 0;
}
\end{lstlisting}
\end{minipage}
An die Bits Nr.\ 4, 5 und 6 des Output-Ports C des Mikro-Controllers sind LEDs angeschlossen.\\
Sobald das Programm läuft, blinken diese in charakteristischer Weise:
\begin{quote}
\newcommand{\tdn}[1]{\raisebox{-2pt}{#1}}
\begin{tabular}{|c|c|c|c|}\hline
\tdn{Phase} & \tdn{LED oben (rot)} & \tdn{LED Mitte (gelb)} & \tdn{LED unten (grün)} \\[2pt]\hline
1 & aus & aus & an \\\hline
2 & aus & an & aus \\\hline
3 & aus & an & an \\\hline
4 & an & aus & aus \\\hline
5 & an & aus & an \\\hline
6 & an & an & aus \\\hline
7 & an & an & an \\\hline
8 & aus & aus & aus \\\hline
\end{tabular}
\end{quote}
Jede Phase dauert etwas länger als eine halbe Sekunde.
Nach 8 Phasen wiederholt sich das Schema.
Erklären Sie das Verhalten des Programms anhand des Quelltextes:
\vspace{-\medskipamount}
\begin{itemize}\itemsep0pt
\item[(a)]
Wieso macht das Programm überhaupt etwas,
wenn doch das Hauptprogramm nach dem Initialisieren lediglich eine Endlosschleife ausführt,
in der \emph{nichts} passiert?
\points{1}
\item[(b)]
Wieso wird die Zeile \lstinline|PORTC = leds << 4;| überhaupt aufgerufen,
wenn dies doch nur unter der Bedingung \lstinline|counter == 0| passiert,
wobei die Variable \lstinline|counter| auf 1 initialisiert,
fortwährend erhöht und nirgendwo zurückgesetzt wird?
\points{2}
\item[(c)]
Wie kommt das oben beschriebene Blinkmuster zustande?
\points{2}
\item[(d)]
Wieso dauert eine Phase ungefähr eine halbe Sekunde?
\points{2}
\item[(e)]
Was bedeutet "`\lstinline|ISR (TIMER0_COMP_vect)|"'?
\points{1}
\end{itemize}
\goodbreak
Hinweis:
\vspace{-\medskipamount}
\begin{itemize}\itemsep0pt
\item
Die Funktion \lstinline|init()| sorgt dafür, daß der Timer-Interrupt Nr.\ 0 des Mikro-Controllers
etwa 488mal pro Sekunde aufgerufen wird.
Außerdem initialisiert sie die benötigten Bits an Port C als Output-Ports.
Sie selbst brauchen die Funktion \lstinline|init()| nicht weiter zu erklären.
\end{itemize}
\solution
\begin{itemize}\itemsep0pt
\item[(a)]
\textbf{Wieso macht das Programm überhaupt etwas,
wenn doch das Hauptprogramm nach dem Initialisieren lediglich eine Endlosschleife ausführt,
in der \emph{nichts} passiert?}
Das Blinken wird durch einen Interrupt-Handler implementiert.
Dieser wird nicht durch das Hauptprogramm,
sondern durch ein Hardware-Ereignis (hier: Uhr) aufgerufen.
\item[(b)]
\textbf{Wieso wird die Zeile \lstinline|PORTC = leds << 4;| überhaupt aufgerufen,
wenn dies doch nur unter der Bedingung \lstinline|counter == 0| passiert,
wobei die Variable \lstinline|counter| auf 1 initialisiert,
fortwährend erhöht und nirgendwo zurückgesetzt wird?}
Die vorzeichenlose 8-Bit-Variable \lstinline{counter} kann nur
Werte von 0 bis 255 annehmen; bei einem weiteren
INkrementieren springt sie wieder auf 0 (Überlauf),
und die \lstinline{if}-Bedingung ist erfüllt.
\item[(c)]
\textbf{Wie kommt das oben beschriebene Blinkmuster zustande?}
In jedem Aufruf des Interrupt-Handlers wird die Variable
\lstinline{leds} um 1 erhöht und anschließend modulo 8 genommen.
Sie durchläuft daher immer wieder die Zahlen von 0 bis 7.
Durch die Schiebeoperation \lstinline{leds << 4} werden die 3 Bits
der Variablen \lstinline{leds} an diejenigen Stellen im Byte
geschoben, an denen die LEDs an den Mikro-Controller
angeschlossen sind (Bits 4, 5 und 6).
Entsprechend durchläuft das Blinkmuster immer wieder
die Binärdarstellungen der Zahlen von 0 bis 7
(genauer: von 1 bis 7 und danach 0).
\item[(d)]
\textbf{Wieso dauert eine Phase ungefähr eine halbe Sekunde?}
Der Interrupt-Handler wird gemäß Hinweis 488mal pro Sekunde aufgerufen.
Bei jedem 256sten Aufruf ändert sich das LED-Muster.
Eine Phase dauert somit $\frac{256}{488} \approx 0.52$ Sekunden.
\item[(e)]
\textbf{Was bedeutet "`\lstinline|ISR (TIMER0_COMP_vect)|"'?}
Deklaration eines Interrupt-Handlers für den Timer-Interrupt Nr.\ 0
\end{itemize}
\end{document}
#include <stdio.h>
#include "dates.h"
void check (char day, char month, int year)
{
date d;
if (date_set (&d, day, month, year))
{
date_print (&d);
printf (" --> ");
date_next (&d);
date_print (&d);
printf ("\n");
}
else
printf ("%02d.%02d.%04d: invalid date\n", day, month, year);
}
int main (void)
{
check (6, 11, 2016);
check (29, 11, 2016);
check (30, 11, 2016);
check (31, 11, 2016);
check (29, 12, 2016);
check (30, 12, 2016);
check (31, 12, 2016);
check (28, 2, 2016);
check (29, 2, 2016);
check (30, 2, 2016);
check (28, 2, 2015);
check (29, 2, 2015);
check (30, 2, 2015);
check (31, 12, 2008);
check (28, 2, 2000);
check (29, 2, 2000);
check (30, 2, 2000);
check (28, 2, 1900);
check (29, 2, 1900);
check (30, 2, 1900);
return 0;
}
#include <stdio.h>
#include "textgraph.h"
int main (void)
{
clear (' ');
put_point (-5, 10, 'X');
for (int i = 17; i < 23; i++)
put_point (i, 5, '*');
put_point (15, 6, '*');
put_point (14, 7, '*');
put_point (13, 8, '*');
put_point (13, 9, '*');
put_point (14, 10, '*');
put_point (15, 11, '*');
for (int i = 17; i < 23; i++)
put_point (i, 12, '*');
put_point (24, 11, '*');
put_point (25, 10, '*');
put_point (26, 9, '*');
put_point (26, 8, '*');
put_point (25, 7, '*');
put_point (24, 6, '*');
put_point (18, 8, 'O');
put_point (21, 8, 'O');
put_point (17, 10, '`');
for (int i = 18; i < 22; i++)
put_point (i, 10, '-');
put_point (22, 10, '\'');
put_point (13, 42, 'Y');
printf ("get_point (%d, %d): '%c'\n", 13, 9, get_point (13, 9));
printf ("get_point (%d, %d): '%c'\n", 14, 9, get_point (14, 9));
printf ("get_point (%d, %d): '%c'\n", 94, 9, get_point (94, 9));
display ();
return 0;
}
#include <stdio.h>
#include "textgraph.h"
char buffer[HEIGHT][WIDTH];
void clear (char c)
{
for (int y = 0; y < HEIGHT; y++)
for (int x = 0; x < WIDTH; x++)
buffer[y][x] = c;
}
static int check_coordinates (int x, int y, char *function)
{
if (x >= 0 && x < WIDTH && y >= 0 && y < HEIGHT)
return 1;
else
{
fprintf (stderr, "coordinates (%d,%d) out of range in %s\n", x, y, function);
return 0;
}
}
void put_point (int x, int y, char c)
{
if (check_coordinates (x, y, "put_point"))
buffer[y][x] = c;
}
char get_point (int x, int y)
{
if (check_coordinates (x, y, "get_point"))
return buffer[y][x];
else
return 0;
}
void display (void)
{
for (int y = 0; y < HEIGHT; y++)
{
for (int x = 0; x < WIDTH; x++)
printf ("%c", buffer[y][x]);
printf ("\n");
}
}
#ifndef TEXTGRAPH_H
#define TEXTGRAPH_H
#define WIDTH 40
#define HEIGHT 20
extern void clear (char c);
extern void put_point (int x, int y, char c);
extern char get_point (int x, int y);
extern void display (void);
#endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment