diff --git a/20211115/hp-musterloesung-20211115.pdf b/20211115/hp-musterloesung-20211115.pdf
index df7200de50936fd484c8353512876f910317bf5b..b62059f04deb28163701faba47ad57e36117fca6 100644
Binary files a/20211115/hp-musterloesung-20211115.pdf and b/20211115/hp-musterloesung-20211115.pdf differ
diff --git a/20211115/hp-musterloesung-20211115.tex b/20211115/hp-musterloesung-20211115.tex
index c9dc97835ada978af0da32a80219a01c97e8257d..74b71ae076fc762cc6451a408dbd1c7a1beb9788 100644
--- a/20211115/hp-musterloesung-20211115.tex
+++ b/20211115/hp-musterloesung-20211115.tex
@@ -29,7 +29,7 @@
 \begin{document}
 
   \section*{Hardwarenahe Programmierung\\
-            Musterlösung zu den Übungsaufgaben -- l5.\ November 2021}
+            Musterlösung zu den Übungsaufgaben -- 15.\ November 2021}
 
   \exercise{Zahlensysteme}
 
diff --git a/20211115/hp-uebung-20211115.tex b/20211115/hp-uebung-20211115.tex
index 5bf88f85f23462397d24d1d4d784909bdfcdd852..b95fb80eac13e1765c80769a830ac6507471891a 100644
--- a/20211115/hp-uebung-20211115.tex
+++ b/20211115/hp-uebung-20211115.tex
@@ -20,7 +20,7 @@
 % Attribution-ShareAlike 3.0 Unported License along with this
 % document.  If not, see <http://creativecommons.org/licenses/>.
 
-% README: Zahlensysteme, Mikrocontroller, Einfügen in Strings (Ergänzung)
+% README: Zahlensysteme, Mikrocontroller, Einfügen in Strings
 
 \documentclass[a4paper]{article}
 
diff --git a/20211122/Makefile b/20211122/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..7ae33df99f68fcf460324cfbb008f3f7a3863638
--- /dev/null
+++ b/20211122/Makefile
@@ -0,0 +1,8 @@
+%.elf: %.c
+	avr-gcc -Wall -Os -mmcu=atmega328p $< -o $@
+
+%.hex: %.elf
+	avr-objcopy -O ihex $< $@
+
+download:
+	./download.sh
diff --git a/20211122/aufgabe-2.c b/20211122/aufgabe-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..d0b065941fbc0082bf867d872527299dca97b98f
--- /dev/null
+++ b/20211122/aufgabe-2.c
@@ -0,0 +1,18 @@
+#include <string.h>
+
+int fun_1 (char *s)
+{
+  int x = 0;
+  for (int i = 0; i < strlen (s); i++)
+    x += s[i];
+  return x;
+}
+
+int fun_2 (char *s)
+{
+  int i = 0, x = 0;
+  int len = strlen (s);
+  while (i < len)
+    x += s[i++];
+  return x;
+}
diff --git a/20211122/aufgabe-3.c b/20211122/aufgabe-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..4c95eb6ad4881c904448309c6b7c46fa101cc109
--- /dev/null
+++ b/20211122/aufgabe-3.c
@@ -0,0 +1,33 @@
+#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++;
+}
+
+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;
+}
diff --git a/20211122/blink-0.c b/20211122/blink-0.c
new file mode 100644
index 0000000000000000000000000000000000000000..b0022c681fd1482ed0a6d9fded7bb0a54699de32
--- /dev/null
+++ b/20211122/blink-0.c
@@ -0,0 +1,9 @@
+#include <avr/io.h>
+
+int main (void)
+{
+  DDRD = 0x40;   /* binär: 0100 0000 */
+  PORTD = 0x40;  /* binär: 0100 0000 */
+  while (1);
+  return 0;
+}
diff --git a/20211122/blink-0a.c b/20211122/blink-0a.c
new file mode 100644
index 0000000000000000000000000000000000000000..45e90fe4568e357cc9342a0d7369be6312a83e64
--- /dev/null
+++ b/20211122/blink-0a.c
@@ -0,0 +1,9 @@
+#include <avr/io.h>
+
+int main (void)
+{
+  DDRD = 0xff;   /* binär: 1111 1111 */
+  PORTD = 0x40;  /* binär: 0100 0000 */
+  while (1);
+  return 0;
+}
diff --git a/20211122/blink-1.c b/20211122/blink-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..6d28dce84f94375094c98479c30a54ace1b2a9d9
--- /dev/null
+++ b/20211122/blink-1.c
@@ -0,0 +1,18 @@
+#include <avr/io.h>
+
+#define F_CPU 16000000l
+#include <util/delay.h>
+
+int main (void)
+{
+  DDRD = 0x01;
+  PORTD |= 0x01;
+  while (1)
+    {
+      _delay_ms (500);
+      PORTD &= ~0x01;
+      _delay_ms (500);
+      PORTD |= 0x01;
+    }
+  return 0;
+}
diff --git a/20211122/blink-2.c b/20211122/blink-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..9389b19b1bf46d5ca90bac823e3f94269fe02878
--- /dev/null
+++ b/20211122/blink-2.c
@@ -0,0 +1,16 @@
+#include <avr/io.h>
+
+#define F_CPU 16000000l
+#include <util/delay.h>
+
+int main (void)
+{
+  DDRD = 0x02;  /* binär: 0000 0010 */
+  PORTD = 0x02;
+  while (1)
+    {
+      _delay_ms (250);
+      PORTD ^= 0x02;
+    }
+  return 0;
+}
diff --git a/20211122/blink-2a.c b/20211122/blink-2a.c
new file mode 100644
index 0000000000000000000000000000000000000000..a226654a35eb061364dab1cf6a035eb6c5dd4df0
--- /dev/null
+++ b/20211122/blink-2a.c
@@ -0,0 +1,16 @@
+#include <avr/io.h>
+
+#define F_CPU 16000000l
+#include <util/delay.h>
+
+int main (void)
+{
+  DDRD = 0x02;  /* binär: 0000 0010 */
+  PORTD = 0x02;
+  while (1)
+    {
+      _delay_ms (500);
+      PORTD = PORTD ^ 0x02;
+    }
+  return 0;
+}
diff --git a/20211122/blink-2b.c b/20211122/blink-2b.c
new file mode 100644
index 0000000000000000000000000000000000000000..90ed36c2f976050b898458e3efd6b818ecf8e775
--- /dev/null
+++ b/20211122/blink-2b.c
@@ -0,0 +1,16 @@
+#include <avr/io.h>
+
+#define F_CPU 16000000l
+#include <util/delay.h>
+
+int main (void)
+{
+  DDRB = 1 << 5;
+  PORTB = 1 << 5;
+  while (1)
+    {
+      _delay_ms (500);
+      PORTB ^= 1 << 5;
+    }
+  return 0;
+}
diff --git a/20211122/blink-3.c b/20211122/blink-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..5268e7977f0f2a99b2005a81a2fa7560dfea481f
--- /dev/null
+++ b/20211122/blink-3.c
@@ -0,0 +1,17 @@
+#include <avr/io.h>
+
+#define F_CPU 16000000
+#include <util/delay.h>
+
+int main (void)
+{
+  DDRD = 0x01;
+  PORTD = 0x01;
+  while (1)
+    {
+      while ((PIND & 0x02) == 0)
+        ; /* just wait */
+      PORTD ^= 0x01;
+    }
+  return 0;
+}
diff --git a/20211122/blink-4.c b/20211122/blink-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..ceafab6b1e7462497fde98b7a12e72cc34132bbe
--- /dev/null
+++ b/20211122/blink-4.c
@@ -0,0 +1,18 @@
+#include <avr/io.h>
+
+#define F_CPU 16000000
+#include <util/delay.h>
+
+int main (void)
+{
+  DDRD = 0x01;   /* binär: 0000 0001 */
+  PORTD = 0x01;  /*                ^ Ouptut */
+  while (1)      /*               ^ Input   */
+    {
+      while ((PIND & 0x02) == 0)  /* binär: 0000 0010 */
+        ; /* just wait */
+      PORTD ^= 0x01;
+      _delay_ms (200);
+    }
+  return 0;
+}
diff --git a/20211122/download.sh b/20211122/download.sh
new file mode 100755
index 0000000000000000000000000000000000000000..770c3b5dca74ac09778be055c9d6f5adb0df293b
--- /dev/null
+++ b/20211122/download.sh
@@ -0,0 +1,3 @@
+port=$(ls -rt /dev/ttyACM* | tail -1)
+echo avrdude -P $port -c arduino -p m328p -U flash:w:$(ls -rt *.hex | tail -1)
+avrdude -P $port -c arduino -p m328p -U flash:w:$(ls -rt *.hex | tail -1) 2>/dev/null
diff --git a/20211122/hp-20211122.pdf b/20211122/hp-20211122.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..029ba1ad0d26847b158f81dd269a40877254922d
Binary files /dev/null and b/20211122/hp-20211122.pdf differ
diff --git a/20211122/hp-20211122.tex b/20211122/hp-20211122.tex
new file mode 100644
index 0000000000000000000000000000000000000000..ba182dc0a57ff755f298d6d05545e1c535073b78
--- /dev/null
+++ b/20211122/hp-20211122.tex
@@ -0,0 +1,890 @@
+% hp-20211122.pdf - Lecture Slides on Low-Level Programming
+% Copyright (C) 2012, 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021  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: I/O-Ports, Interrupts
+
+\documentclass[10pt,t]{beamer}
+
+\usepackage{pgslides}
+\usepackage{pdftricks}
+\usepackage{tikz}
+
+\begin{psinputs}
+  \usepackage[utf8]{inputenc}
+  \usepackage[german]{babel}
+  \usepackage[T1]{fontenc}
+  \usepackage{helvet}
+  \renewcommand*\familydefault{\sfdefault}
+  \usepackage{pstricks,pst-grad}
+\end{psinputs}
+
+\title{Hardwarenahe Programmierung}
+\author{Prof.\ Dr.\ rer.\ nat.\ Peter Gerwinski}
+\date{22.\ November 2021}
+
+\begin{document}
+
+\maketitleframe
+
+\nosectionnonumber{\inserttitle}
+
+\begin{frame}
+
+  \shownosectionnonumber
+
+  \begin{itemize}
+    \item[\textbf{1}] \textbf{Einführung}
+      \hfill\makebox(0,0)[br]{\raisebox{2.25ex}{\url{https://gitlab.cvh-server.de/pgerwinski/hp.git}}}
+    \item[\textbf{2}] \textbf{Einführung in C}
+    \item[\textbf{3}] \textbf{Bibliotheken}
+    \item[\textbf{4}] \textbf{Hardwarenahe Programmierung}
+      \begin{itemize}
+        \item[4.1] Bit-Operationen
+        \color{medgreen}
+        \item[4.2] I/O-Ports
+        \color{red}
+        \item[4.3] Interrupts
+        \item[4.4] volatile-Variable
+        \item[4.6] Byte-Reihenfolge -- Endianness
+        \item[4.7] Binärdarstellung negativer Zahlen
+        \item[4.8] Speicherausrichtung -- Alignment
+      \end{itemize}
+    \item[\textbf{5}] \textbf{Algorithmen}
+    \item[\textbf{\dots}]
+%    \item[\textbf{4}] \textbf{Hardwarenahe Programmierung}
+%    \item[\textbf{5}] \textbf{Algorithmen}
+%    \item[\textbf{6}] \textbf{Ergänzungen und Ausblicke}
+  \end{itemize}
+  \vspace*{-1cm}
+
+\end{frame}
+
+\setcounter{section}{4}
+\section{Hardwarenahe Programmierung}
+\subsection{Bit-Operationen}
+\subsubsection{Zahlensysteme}
+
+\begin{frame}[fragile]
+
+  \showsection
+  \vspace*{-\smallskipamount}
+  \showsubsection
+  \vspace*{-\medskipamount}
+  \showsubsubsection
+
+  \begin{tabular}{rlrl}
+    Basis & Name & Beispiel & Anwendung \\[\smallskipamount]
+      2 & Binärsystem & 1\,0000\,0011 & Bit-Operationen \\
+      8 & Oktalsystem & \lstinline,0403, & Dateizugriffsrechte (Unix) \\
+     10 & Dezimalsystem & \lstinline,259, & Alltag \\
+     16 & Hexadezimalsystem & \lstinline,0x103, & Bit-Operationen \\
+    256 & (keiner gebräuchlich) & 0.0.1.3 & IP-Adressen (IPv4)
+  \end{tabular}
+
+  \bigskip
+
+  \begin{itemize}
+    \item
+      Computer rechnen im Binärsystem.
+    \item
+      Für viele Anwendungen (z.\,B.\ I/O-Ports, Grafik, \dots) ist es notwendig,\\
+      Bits in Zahlen einzeln ansprechen zu können.
+  \end{itemize}
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsubsection
+
+  \begin{tabular}{rlrlrc}
+    \qquad 000 & \bf 0 \hspace*{1.5cm} & 0000 & \bf 0 & \quad 1000 & \bf 8\\
+           001 & \bf 1                 & 0001 & \bf 1 &       1001 & \bf 9\\
+           010 & \bf 2                 & 0010 & \bf 2 &       1010 & \bf A\\
+           011 & \bf 3                 & 0011 & \bf 3 &       1011 & \bf B\\[\smallskipamount]
+           100 & \bf 4                 & 0100 & \bf 4 &       1100 & \bf C\\
+           101 & \bf 5                 & 0101 & \bf 5 &       1101 & \bf D\\
+           110 & \bf 6                 & 0110 & \bf 6 &       1110 & \bf E\\
+           111 & \bf 7                 & 0111 & \bf 7 &       1111 & \bf F\\
+  \end{tabular}
+
+  \medskip
+
+  \begin{itemize}
+    \item
+      Oktal- und Hexadezimalzahlen lassen sich ziffernweise\\
+      in Binär-Zahlen umrechnen.
+    \item
+      Hexadezimalzahlen sind eine Kurzschreibweise für Binärzahlen,\\
+      gruppiert zu jeweils 4 Bits.
+    \item
+      Oktalzahlen sind eine Kurzschreibweise für Binärzahlen,\\
+      gruppiert zu jeweils 3 Bits.
+    \item
+      Trotz Taschenrechner u.\,ä.\ lohnt es sich,\\
+      die o.\,a.\ Umrechnungstabelle \textbf{auswendig} zu kennen.
+  \end{itemize}
+
+\end{frame}
+
+\subsubsection{Bit-Operationen in C}
+
+\begin{frame}[fragile]
+
+  \showsubsubsection
+
+  \begin{tabular}{lll}
+    C-Operator     & Verknüpfung              & Anwendung                \\[\smallskipamount]
+    \lstinline,&,  & Und                      & Bits gezielt löschen     \\
+    \lstinline,|,  & Oder                     & Bits gezielt setzen      \\
+    \lstinline,^,  & Exklusiv-Oder            & Bits gezielt invertieren \\
+    \lstinline,~,  & Nicht                    & Alle Bits invertieren    \\[\smallskipamount]
+    \lstinline,<<, & Verschiebung nach links  & Maske generieren         \\
+    \lstinline,>>, & Verschiebung nach rechts & Bits isolieren
+  \end{tabular}
+
+  \bigskip
+
+  Numerierung der Bits: von rechts ab 0
+
+  \medskip
+
+  \begin{tabular}{ll}
+    Bit Nr.\ 3 auf 1 setzen: &
+    \lstinline,a |= 1 << 3;, \\
+    Bit Nr.\ 4 auf 0 setzen: &
+    \lstinline,a &= ~(1 << 4);, \\
+    Bit Nr.\ 0 invertieren: &
+    \lstinline,a ^= 1 << 0;,
+  \end{tabular}
+
+  \smallskip
+
+  ~~Abfrage, ob Bit Nr.\ 1 gesetzt ist:\quad
+  \lstinline{if (a & (1 << 1))}
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsubsection
+
+  C-Datentypen für Bit-Operationen:
+  \smallskip\par
+  \lstinline{#include <stdint.h>}
+  \medskip\par
+  \begin{tabular}{lllll}
+                    & 8 Bit & 16 Bit & 32 Bit & 64 Bit \\
+    mit Vorzeichen  & \lstinline,int8_t,
+                    & \lstinline,int16_t,
+                    & \lstinline,int32_t,
+                    & \lstinline,int64_t, \\
+    ohne Vorzeichen & \lstinline,uint8_t,
+                    & \lstinline,uint16_t,
+                    & \lstinline,uint32_t,
+                    & \lstinline,uint64_t,
+  \end{tabular}
+
+  \bigskip
+  \bigskip
+
+  Ausgabe:
+  \smallskip\par
+  \begin{lstlisting}
+    #include <stdio.h>
+    #include <stdint.h>
+    #include <inttypes.h>
+    ...
+    uint64_t x = 42;
+    printf ("Die Antwort lautet: %" PRIu64 "\n", x);
+  \end{lstlisting}
+
+\end{frame}
+
+\subsection{I/O-Ports}
+
+\begin{frame}[fragile]
+
+%  \showsection
+  \showsubsection
+  \vspace*{-1.5\medskipamount}
+  {\large\textbf{\color{structure}5.3\quad Interrupts}}
+
+  \bigskip
+
+  Kommunikation mit externen Geräten
+
+  \bigskip
+
+  \begin{center}
+    \includegraphics{io-ports-and-interrupts.pdf}
+  \end{center}
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsection
+
+  In Output-Port schreiben = Aktoren ansteuern
+
+  Beispiel: LED
+
+  \medskip
+
+  \begin{lstlisting}
+    #include <avr/io.h>
+    ...
+    DDRC = 0x70;
+    PORTC = 0x40;
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \put(3,0.67){\begin{minipage}{3cm}
+                \color{red}%
+                binär: 0111\,0000\\
+                binär: 0100\,0000
+              \end{minipage}}
+    \put(10,0.67){\makebox(0,0)[r]{\color{red}Herstellerspezifisch!}}
+  \end{picture}
+
+  \bigskip
+
+  \lstinline{DDR} = Data Direction Register\\
+  Bit = 1 für Output-Port\\
+  Bit = 0 für Input-Port
+
+  \bigskip
+
+  \emph{Details: siehe Datenblatt und Schaltplan}
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsection
+
+  Aus Input-Port lesen = Sensoren abfragen
+
+  Beispiel: Taster
+
+  \medskip
+
+  \begin{lstlisting}
+    #include <avr/io.h>
+    ...
+    DDRC = 0xfd;
+    while ((PINC & 0x02) == 0)
+      ; /* just wait */
+  \end{lstlisting}
+  \begin{picture}(0,0)(-1.5,-0.42)
+    \put(3,0.67){\begin{minipage}{3cm}
+                \color{red}%
+                binär: 1111\,1101\\
+                binär: 0000\,0010
+              \end{minipage}}
+    \put(10,0.67){\makebox(0,0)[r]{\color{red}Herstellerspezifisch!}}
+  \end{picture}
+
+  \bigskip
+
+  \lstinline{DDR} = Data Direction Register\\
+  Bit = 1 für Output-Port\\
+  Bit = 0 für Input-Port
+
+  \bigskip
+
+  \emph{Details: siehe Datenblatt und Schaltplan}
+  
+  \bigskip
+
+  Praktikumsaufgabe: Druckknopfampel
+
+\end{frame}
+
+\subsection{Interrupts}
+
+\begin{frame}[fragile]
+
+  \showsubsection
+
+  Externes Gerät ruft (per Stromsignal) Unterprogramm auf
+
+  Zeiger hinterlegen: "`Interrupt-Vektor"'
+
+  Beispiel: eingebaute Uhr\hfill
+  \makebox(0,0)[tr]{%
+    \only<1->{\begin{minipage}[t]{4.7cm}
+        \vspace*{-0.3cm}%
+        statt Zählschleife (\lstinline{_delay_ms}):\\
+        Hauptprogramm kann\\
+        andere Dinge tun
+      \end{minipage}}%
+    }
+
+  \medskip
+
+  \begin{lstlisting}
+    #include <avr/interrupt.h>
+
+    ...
+
+
+    ISR (TIMER0B_COMP_vect)
+    {
+      PORTD ^= 0x40;
+    }
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(1.9,3.1){\makebox(0,0)[tr]{\tikz{\draw[-latex](0,0)--(-1.4,-1.0);}}}
+    \put(2.0,3.2){\makebox(0,0)[l]{"`Dies ist ein Interrupt-Handler."'}}
+    \put(2.3,2.6){\makebox(0,0)[tr]{\tikz{\draw[-latex](0,0)--(-0.6,-0.55);}}}
+    \put(2.4,2.6){\makebox(0,0)[l]{Interrupt-Vektor darauf zeigen lassen}}
+  \end{picture}
+
+  Initialisierung über spezielle Ports:
+  \lstinline{TCCR0B}, \lstinline{TIMSK0}
+
+  \bigskip
+
+  \emph{Details: siehe Datenblatt und Schaltplan}
+
+  \vspace*{-2.5cm}\hfill
+  {\color{red}Herstellerspezifisch!}%
+  \hspace*{1cm}
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsection
+
+  Externes Gerät ruft (per Stromsignal) Unterprogramm auf
+
+  Zeiger hinterlegen: "`Interrupt-Vektor"'
+
+  Beispiel: Taster\hfill
+  \makebox(0,0)[tr]{%
+    \begin{minipage}[t]{4.7cm}
+      \vspace*{-0.3cm}%
+      statt \newterm{Busy Waiting\/}:\\
+      Hauptprogramm kann\\
+      andere Dinge tun
+    \end{minipage}}
+
+  \medskip
+
+  \begin{lstlisting}
+    #include <avr/interrupt.h>
+    ...
+
+    ISR (INT0_vect)
+    {
+      PORTD ^= 0x40;
+    }
+  \end{lstlisting}
+
+  \medskip
+
+  Initialisierung über spezielle Ports:
+  \lstinline{EICRA}, \lstinline{EIMSK}
+
+  \bigskip
+
+  \emph{Details: siehe Datenblatt und Schaltplan}
+
+  \vspace*{-2.5cm}\hfill
+  {\color{red}Herstellerspezifisch!}%
+  \hspace*{1cm}
+
+\end{frame}
+
+\subsection{volatile-Variable}
+
+\begin{frame}[fragile]
+
+  \showsubsection
+
+  Externes Gerät ruft (per Stromsignal) Unterprogramm auf
+
+  Zeiger hinterlegen: "`Interrupt-Vektor"'
+
+  Beispiel: Taster
+
+  \vspace*{-2.5pt}
+
+  \begin{minipage}[t]{5cm}
+    \begin{onlyenv}<1>
+      \begin{lstlisting}[gobble=8]
+        ¡#include <avr/interrupt.h>
+        ...
+
+        uint8_t key_pressed = 0;
+
+        ISR (INT0_vect)
+        {
+          key_pressed = 1;
+        }¿
+      \end{lstlisting}
+    \end{onlyenv}
+    \begin{onlyenv}<2>
+      \begin{lstlisting}[gobble=8]
+        ¡#include <avr/interrupt.h>
+        ...
+
+        volatile uint8_t key_pressed = 0;
+
+        ISR (INT0_vect)
+        {
+          key_pressed = 1;
+        }¿
+      \end{lstlisting}
+    \end{onlyenv}
+  \end{minipage}\hfill
+  \begin{minipage}[t]{6cm}
+    \begin{lstlisting}[gobble=6]
+      ¡int main (void)
+      {
+        ...
+
+        while (1)
+          {
+            while (!key_pressed)
+              ;  /* just wait */
+            PORTD ^= 0x40;
+            key_pressed = 0;
+          }
+        return 0;
+      }¿
+    \end{lstlisting}
+  \end{minipage}
+
+  \pause
+  \begin{picture}(0,0)
+    \color{red}
+    \put(10.3,4.0){\makebox(0,0)[b]{\begin{minipage}{6cm}
+        \begin{center}
+          \textbf{volatile}:\\
+          Speicherzugriff\\
+          nicht wegoptimieren
+        \end{center}
+      \end{minipage}}}
+    \put(10.3,3.95){\makebox(0,0)[tr]{\tikz{\draw[-latex](0,0)--(-0.5,-0.9);}}}
+  \end{picture}
+
+\end{frame}
+
+\iffalse
+
+\begin{frame}[fragile]
+
+  \showsubsection
+
+  Was ist eigentlich \lstinline{PORTD}?
+
+  \bigskip
+  \pause
+
+  \lstinline[style=cmd]{avr-gcc -Wall -Os -mmcu=atmega328p blink-3.c -E}
+
+  \bigskip
+  \pause
+  \lstinline{PORTD = 0x01;}\\
+  \textarrow\quad
+  \lstinline[style=terminal]{(*(volatile uint8_t *)((0x0B) + 0x20)) = 0x01;}\\
+  \pause
+  \begin{picture}(0,2)(0,-1.7)
+    \color{red}
+    \put(5.75,0.3){$\underbrace{\rule{2.95cm}{0pt}}_{\mbox{Zahl: \lstinline|0x2B|}}$}
+    \pause
+    \put(1.55,0.3){$\underbrace{\rule{4.0cm}{0pt}}_{\mbox{\shortstack[t]{Umwandlung in Zeiger\\
+      auf \lstinline|volatile uint8_t|}}}$}
+    \pause
+    \put(1.32,-1){\makebox(0,0)[b]{\tikz{\draw[-latex](0,0)--(0,1.3)}}}
+    \put(1.12,-1.1){\makebox(0,0)[tl]{Dereferenzierung des Zeigers}}
+  \end{picture}
+
+  \pause
+  \textarrow\quad
+  \lstinline|volatile uint8_t|-Variable an Speicheradresse \lstinline|0x2B|
+
+  \pause
+  \bigskip
+  \bigskip
+
+  \textarrow\quad
+  \lstinline|PORTA = PORTB = PORTC = PORTD = 0| ist eine schlechte Idee.
+
+\end{frame}
+
+\fi
+
+\subsection{Byte-Reihenfolge -- Endianness}
+\subsubsection{Konzept}
+
+\begin{frame}[fragile]
+
+  \showsubsection
+  \showsubsubsection
+
+  Eine Zahl geht über mehrere Speicherzellen.\\
+  Beispiel: 16-Bit-Zahl in 2 8-Bit-Speicherzellen
+
+  \smallskip
+
+  Welche Bits liegen wo?
+
+  \pause
+  \bigskip
+
+  $1027 = 1024 + 2 + 1 = 0000\,0100\,0000\,0011_2 = 0403_{16}$
+
+  \pause
+  \bigskip
+  Speicherzellen:
+
+  \medskip
+  \begin{tabular}{|c|c|l}\cline{1-2}
+    \raisebox{-0.25ex}{04} & \raisebox{-0.25ex}{03} & \strut Big-Endian "`großes Ende zuerst"' \\\cline{1-2}
+    \multicolumn{2}{c}{} & \pause für Menschen leichter lesbar \pause \\
+    \multicolumn{3}{c}{} \\[-5pt]\cline{1-2}
+    \raisebox{-0.25ex}{03} & \raisebox{-0.25ex}{04} & \strut Little-Endian "`kleines Ende zuerst"' \\\cline{1-2}
+    \multicolumn{2}{c}{} & \pause bei Additionen effizienter
+  \end{tabular}
+
+  \pause
+  \medskip
+  \textarrow\ Geschmackssache
+  \pause\\
+  \quad\textbf{\dots\ außer bei Datenaustausch!}
+
+%  \pause
+%  \bigskip
+%
+%  Aber: nicht verwechseln! \qquad $0304_{16} = 772$
+
+\end{frame}
+
+\begin{frame}
+
+  \showsubsection
+  \showsubsubsection
+
+  Eine Zahl geht über mehrere Speicherzellen.\\
+  Beispiel: 16-Bit-Zahl in 2 8-Bit-Speicherzellen
+
+  \smallskip
+
+  Welche Bits liegen wo?
+
+  \medskip
+
+  \textarrow\ Geschmackssache\\
+  \textbf{\dots\ außer bei Datenaustausch!}
+
+  \begin{itemize}
+    \item
+      Dateiformate
+    \item
+      Datenübertragung
+  \end{itemize}
+
+\end{frame}
+
+\subsubsection{Dateiformate}
+
+\begin{frame}
+
+  \showsubsection
+  \showsubsubsection
+
+  Audio-Formate: Reihenfolge der Bytes in 16- und 32-Bit-Zahlen
+  \begin{itemize}
+    \item
+      RIFF-WAVE-Dateien (\file{.wav}): Little-Endian
+    \item
+      Au-Dateien (\file{.au}): Big-Endian
+    \pause
+    \item
+      ältere AIFF-Dateien (\file{.aiff}): Big-Endian
+    \item
+      neuere AIFF-Dateien (\file{.aiff}): Little-Endian
+  \end{itemize}
+
+  \pause
+  \bigskip
+
+  Grafik-Formate: Reihenfolge der Bits in den Bytes
+  \begin{itemize}
+    \item
+      PBM-Dateien: Big-Endian\only<4->{, MSB first}
+    \item
+      XBM-Dateien: Little-Endian\only<4->{, LSB first}
+  \end{itemize}
+  \only<4->{MSB/LSB = most/least significant bit}
+
+\end{frame}
+
+\subsubsection{Datenübertragung}
+
+\begin{frame}
+
+  \showsubsection
+  \showsubsubsection
+
+  \begin{itemize}
+    \item
+      RS-232 (serielle Schnittstelle): LSB first
+    \item
+      I$^2$C: MSB first
+    \item
+      USB: beides
+    \pause
+    \medskip
+    \item
+      Ethernet: LSB first
+    \item
+      TCP/IP (Internet): Big-Endian
+  \end{itemize}
+
+\end{frame}
+
+\subsection{Binärdarstellung negativer Zahlen}
+
+\begin{frame}[fragile]
+
+  \showsubsection
+
+  Speicher ist begrenzt!\\
+  \textarrow\ feste Anzahl von Bits
+
+  \medskip
+
+  8-Bit-Zahlen ohne Vorzeichen: \lstinline{uint8_t}\\
+  \textarrow\ Zahlenwerte von \lstinline{0x00} bis \lstinline{0xff} = 0 bis 255\\
+  \pause
+  \textarrow\ 255 + 1 = 0
+
+  \pause
+  \medskip
+
+  8-Bit-Zahlen mit Vorzeichen: \lstinline{int8_t}\\
+  \lstinline{0xff} = 255 ist die "`natürliche"' Schreibweise für $-1$.\\
+  \pause
+  \textarrow\ Zweierkomplement
+
+  \pause
+  \medskip
+
+  Oberstes Bit = 1: negativ\\
+  Oberstes Bit = 0: positiv\\
+  \textarrow\ 127 + 1 = $-128$
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsection
+
+  Speicher ist begrenzt!\\
+  \textarrow\ feste Anzahl von Bits
+
+  \medskip
+
+  16-Bit-Zahlen ohne Vorzeichen:
+  \lstinline{uint16_t}\hfill\lstinline{uint8_t}\\
+  \textarrow\ Zahlenwerte von \lstinline{0x0000} bis \lstinline{0xffff}
+  = 0 bis 65535\hfill 0 bis 255\\
+  \textarrow\ 65535 + 1 = 0\hfill 255 + 1 = 0
+
+  \medskip
+
+  16-Bit-Zahlen mit Vorzeichen:
+  \lstinline{int16_t}\hfill\lstinline{int8_t}\\
+  \lstinline{0xffff} = 66535 ist die "`natürliche"' Schreibweise für $-1$.\hfill
+  \lstinline{0xff} = 255 = $-1$\\
+  \textarrow\ Zweierkomplement
+
+  \medskip
+
+  Oberstes Bit = 1: negativ\\
+  Oberstes Bit = 0: positiv\\
+  \textarrow\ 32767 + 1 = $-32768$
+
+  \bigskip
+  Literatur: \url{http://xkcd.com/571/}
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsection
+
+  Frage: \emph{Für welche Zahl steht der Speicherinhalt\,
+  \raisebox{2pt}{%
+    \tabcolsep0.25em
+    \begin{tabular}{|c|c|}\hline
+      \rule{0pt}{11pt}a3 & 90 \\\hline
+    \end{tabular}}
+  (hexadezimal)?}
+  
+  \pause
+  \smallskip
+  Antwort: \emph{Das kommt darauf an.} ;--)
+
+  \pause
+  \medskip
+  Little-Endian:
+
+  \smallskip
+
+  \begin{tabular}{lrl}
+    als \lstinline,int8_t,: & $-93$ & (nur erstes Byte)\\
+    als \lstinline,uint8_t,: & $163$ & (nur erstes Byte)\\
+    als \lstinline,int16_t,: & $-28509$\\
+    als \lstinline,uint16_t,: & $37027$\\
+    \lstinline,int32_t, oder größer: & $37027$
+      & (zusätzliche Bytes mit Nullen aufgefüllt)
+  \end{tabular}
+
+  \pause
+  \medskip
+  Big-Endian:
+
+  \smallskip
+
+  \begin{tabular}{lrl}
+    als \lstinline,int8_t,:   & $-93$ & (nur erstes Byte)\\
+    als \lstinline,uint8_t,:  & $163$ & (nur erstes Byte)\\
+    als \lstinline,int16_t,:  & $-23664$\\
+    als \lstinline,uint16_t,: & $41872$\\ als \lstinline,int32_t,:  & $-1550843904$ & (zusätzliche Bytes\\
+    als \lstinline,uint32_t,: & $2744123392$  & mit Nullen aufgefüllt)\\
+    als \lstinline,int64_t,:  & $-6660823848880963584$\\
+    als \lstinline,uint64_t,: & $11785920224828588032$\\
+  \end{tabular}
+
+  \vspace*{-1cm}
+
+\end{frame}
+
+\subsection{Speicherausrichtung -- Alignment}
+
+\begin{frame}[fragile]
+
+  \showsubsection
+
+  \begin{lstlisting}
+    #include <stdint.h>
+
+    uint8_t a;
+    uint16_t b;
+    uint8_t c;
+  \end{lstlisting}
+
+  \pause
+  \bigskip
+
+  Speicheradresse durch 2 teilbar -- "`16-Bit-Alignment"'
+  \begin{itemize}
+    \item
+      2-Byte-Operation: effizienter
+    \pause
+    \item
+      \dots\ oder sogar nur dann erlaubt
+    \pause
+    \arrowitem
+      Compiler optimiert Speicherausrichtung
+  \end{itemize}
+
+  \medskip
+
+  \pause
+  \begin{minipage}{3cm}
+    \begin{lstlisting}[gobble=6]
+      ¡uint8_t a;
+      uint8_t dummy;
+      uint16_t b;
+      uint8_t c;¿
+    \end{lstlisting}
+  \end{minipage}
+  \pause
+  \begin{minipage}{3cm}
+    \begin{lstlisting}[gobble=6]
+      ¡uint8_t a;
+      uint8_t c;
+      uint16_t b;¿
+    \end{lstlisting}
+  \end{minipage}
+
+  \pause
+  \vspace{-1.75cm}
+  \strut\hfill
+  \begin{minipage}{6.5cm}
+    Fazit:
+    \begin{itemize}
+      \item
+        \textbf{Adressen von Variablen\\
+        sind systemabhängig}
+      \item
+        Bei Definition von Datenformaten\\
+        Alignment beachten \textarrow\ effizienter
+    \end{itemize}
+  \end{minipage}
+
+\end{frame}
+
+\nosectionnonumber{\inserttitle}
+
+\begin{frame}
+
+  \shownosectionnonumber
+
+  \begin{itemize}
+    \item[\textbf{1}] \textbf{Einführung}
+      \hfill\makebox(0,0)[br]{\raisebox{2.25ex}{\url{https://gitlab.cvh-server.de/pgerwinski/hp}}}
+    \item[\textbf{2}] \textbf{Einführung in C}
+      \begin{itemize}
+        \vspace*{-\smallskipamount}
+        \item[\dots]
+        \item[2.14] Parameter des Hauptprogramms
+        \item[2.15] String-Operationen
+      \end{itemize}
+    \item[\textbf{3}] \textbf{Bibliotheken}
+    \item[\textbf{4}] \textbf{Hardwarenahe Programmierung}
+      \begin{itemize}
+        \item[4.1] Bit-Operationen
+        \color{medgreen}
+        \item[4.2] I/O-Ports
+        \item[4.3] Interrupts
+        \item[4.4] volatile-Variable
+        \color{red}
+        \item[4.6] Byte-Reihenfolge -- Endianness
+        \item[4.7] Binärdarstellung negativer Zahlen
+        \item[4.8] Speicherausrichtung -- Alignment
+      \end{itemize}
+    \item[\textbf{5}] \textbf{Algorithmen}
+    \item[\textbf{\dots}]
+  \end{itemize}
+
+\end{frame}
+
+\end{document}
diff --git a/20211122/hp-musterloesung-20211122.pdf b/20211122/hp-musterloesung-20211122.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..0569714886f2c558e6bd0d2dbdc16a9b6b66008c
Binary files /dev/null and b/20211122/hp-musterloesung-20211122.pdf differ
diff --git a/20211122/hp-musterloesung-20211122.tex b/20211122/hp-musterloesung-20211122.tex
new file mode 100644
index 0000000000000000000000000000000000000000..7e8d77398c4ef19de65c13e1152f7934a81bce85
--- /dev/null
+++ b/20211122/hp-musterloesung-20211122.tex
@@ -0,0 +1,447 @@
+% hp-musterloesung-20211115.pdf - Solutions to the Exercises on Low-Level Programming
+% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021  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: Ausgabe von Hexadezimalzahlen, Einfügen in Strings, LED-Blinkmuster
+
+\documentclass[a4paper]{article}
+
+\usepackage{pgscript}
+
+\begin{document}
+
+  \section*{Hardwarenahe Programmierung\\
+            Musterlösung zu den Übungsaufgaben -- 22.\ November 2021}
+
+  \exercise{Ausgabe von Hexadezimalzahlen}
+
+  Schreiben Sie eine Funktion \lstinline{void print_hex (uint32_t x)},
+  die eine gegebene vorzeichenlose 32-Bit-Ganzzahl \lstinline{x}
+  als Hexadezimalzahl ausgibt.
+  (Der Datentyp \lstinline{uint32_t} ist mit \lstinline{#include <stdint.h>} verfügbar.)
+
+  Verwenden Sie dafür \emph{nicht\/} \lstinline{printf()} mit
+  der Formatspezifikation \lstinline{%x} als fertige Lösung,
+  sondern programmieren Sie die nötige Ausgabe selbst.
+  (Für Tests ist \lstinline{%x} hingegen erlaubt und sicherlich nützlich.)
+
+  Die Verwendung von \lstinline{printf()}
+  mit anderen Formatspezifikationen wie z.\,B.\ \lstinline{%d}
+  oder \lstinline{%c} oder \lstinline{%s} ist hingegen zulässig.
+
+  \points{8}
+
+  (Hinweis für die Klausur: Abgabe auf Datenträger ist erlaubt und erwünscht,
+  aber nicht zwingend.)
+
+  \solution
+
+  Um die Ziffern von \lstinline{x} zur Basis 16 zu isolieren,
+  berechnen wir \lstinline{x % 16} (modulo 16 = Rest bei Division durch 16)
+  und dividieren anschließend \lstinline{x} durch 16,
+  solange bis \lstinline{x} den Wert 0 erreicht.
+
+  Wenn wir die auf diese Weise ermittelten Ziffern direkt ausgeben,
+  sind sie \emph{Little-Endian}, erscheinen also in umgekehrter Reihenfolge.
+  Die Datei \gitfile{hp}{2021ws/20211122}{loesung-1-1.c} setzt diesen Zwischenschritt um.
+
+  Die Ausgabe der Ziffern erfolgt in \gitfile{hp}{2021ws/20211122}{loesung-1-1.c}
+  über \lstinline{printf ("%d")}
+  für die Ziffern 0 bis 9. Für die darüberliegenden Ziffern
+  wird der Buchstabe \lstinline{a} um die Ziffer abzüglich 10 inkrementiert
+  und der erhaltene Wert mit \lstinline{printf ("%c")} als Zeichen ausgegeben.
+
+  Um die umgekehrte Reihenfolge zu beheben,
+  speichern wir die Ziffern von \lstinline{x}
+  in einem Array \lstinline{digits[]} zwischen
+  und geben sie anschließend in einer zweiten Schleife
+  in umgekehrter Reihenfolge aus (siehe \gitfile{hp}{2021ws/20211122}{loesung-1-2.c}).
+  Da wir wissen, daß \lstinline{x} eine 32-Bit-Zahl ist
+  und daher höchstens 8 Hexadezimalziffern haben kann,
+  ist 8 eine sinnvolle Länge für das Ziffern-Array \lstinline{digits[8]}.
+
+  Nun sind die Ziffern in der richtigen Reihenfolge,
+  aber wir erhalten zusätzlich zu den eigentlichen Ziffern führende Nullen.
+  Da in der Aufgabenstellung nicht von führenden Nullen die Rede war,
+  sind diese nicht verboten; \gitfile{hp}{2021ws/20211122}{loesung-1-2.c} ist daher
+  eine richtige Lösung der Aufgabe.
+
+  \breath
+
+  Wenn wir die führenden Nullen vermeiden wollen,
+  können wir die \lstinline{for}-Schleifen durch \lstinline{while}-Schleifen ersetzen.
+  Die erste Schleife zählt hoch, solange \lstinline{x} ungleich 0 ist;
+  die zweite zählt von dem erreichten Wert aus wieder herunter
+  -- siehe \gitfile{hp}{2021ws/20211122}{loesung-1-3.c}.
+  Da wir wissen, daß die Zahl \lstinline{x} höchstens 32 Bit,
+  also höchstens 8 Hexadezimalziffern hat,
+  wissen wir, daß \lstinline{i} höchstens den Wert 8 erreichen kann,
+  das Array also nicht überlaufen wird.
+
+  Man beachte, daß der Array-Index nach der ersten Schleife "`um einen zu hoch"' ist.
+  In der zweiten Schleife muß daher \emph{zuerst\/} der Index dekrementiert werden.
+  Erst danach darf ein Zugriff auf \lstinline{digit[i]} erfolgen.
+
+  \breath
+
+  Alternativ können wir auch mitschreiben,
+  ob bereits eine Ziffer ungleich Null ausgegeben wurde,
+  und andernfalls die Ausgabe von Null-Ziffern unterdrücken
+  -- siehe \gitfile{hp}{2021ws/20211122}{loesung-1-4.c}.
+
+  \breath
+
+  Weitere Möglichkeiten ergeben sich, wenn man bedenkt,
+  daß eine Hexadezimalziffer genau einer Gruppe von vier Binärziffern entspricht.
+  Eine Bitverschiebung um 4 nach rechts
+  ist daher dasselbe wie eine Division durch 16,
+  und eine Und-Verknüpfung mit 15$_{10}$ = f$_{16}$ = 1111$_2$
+  ist dasselbe wie die Operation Modulo 16.
+  Die Datei \gitfile{hp}{2021ws/20211122}{loesung-1-5.c} ist eine in dieser Weise abgewandelte Variante
+  von \gitfile{hp}{2021ws/20211122}{loesung-1-3.c}.
+
+  Mit dieser Methode kann man nicht nur auf die jeweils unterste Ziffer,
+  sondern auf alle Ziffern direkt zugreifen.
+  Damit ist kein Array als zusätzlicher Speicher mehr nötig.
+  Die Datei \gitfile{hp}{2021ws/20211122}{loesung-1-6.c} setzt dies auf einfache Weise um.
+  Sie gibt wieder führende Nullen mit aus,
+  ist aber trotzdem eine weitere richtige Lösung der Aufgabe.
+
+  Die führenden Nullen ließen sich auf die gleiche Weise vermeiden
+  wie in \gitfile{hp}{2021ws/20211122}{loesung-1-4.c}.
+
+  Die Bitverschiebungsmethode hat den Vorteil,
+  daß kein zusätzliches Array benötigt wird.
+  Auch wird die als Parameter übergebene Zahl \lstinline{x} nicht verändert,
+  was bei größeren Zahlen, die über Zeiger übergeben werden, von Vorteil sein kann.
+  Demgegenüber steht der Nachteil,
+  daß diese Methode nur für eine ganze Anzahl von Bits funktioniert,
+  also für Basen, die Zweierpotenzen sind (z.\,B.\ 2, 8, 16, 256).
+  Für alle anderen Basen (z.\,B.\ 10) eignet sich nur die Methode
+  mit Division und Modulo-Operation.
+
+  \exercise{Länge von Strings}
+
+  Strings werden in der Programmiersprache C durch Zeiger auf \lstinline{char}-Variable realisiert.
+
+  Beispiel: \lstinline{char *hello_world = "Hello, world!\n"}
+
+  Die Systembibliothek stellt eine Funktion \lstinline{strlen()} zur Ermittlung der Länge von Strings\\
+  zur Verfügung (\lstinline{#include <string.h>}).
+
+  \begin{itemize}
+    \item[(a)]
+      Auf welche Weise ist die Länge eines Strings gekennzeichnet?
+      \points{1}
+    \item[(b)]
+      Wie lang ist die Beispiel-String-Konstante \lstinline{"Hello, world!\n"},
+      und wieviel Speicherplatz belegt sie?\\
+      \points{2}
+    \item[(c)]
+      Schreiben Sie eine eigene Funktion \lstinline{int strlen (char *s)},
+      die die Länge eines Strings zurückgibt.\\
+      \points{3}
+  \end{itemize}
+
+  Wir betrachten nun die folgenden Funktionen (Datei: \gitfile{hp}{2021ws/20211122}{aufgabe-2.c}):
+  \begin{center}
+    \begin{minipage}{8cm}
+      \begin{lstlisting}[gobble=8]
+        int fun_1 (char *s)
+        {
+          int x = 0;
+          for (int i = 0; i < strlen (s); i++)
+            x += s[i];
+          return x;
+        }
+      \end{lstlisting}
+    \end{minipage}%
+    \begin{minipage}{6cm}
+      \vspace*{-1cm}
+      \begin{lstlisting}[gobble=8]
+        int fun_2 (char *s)
+        {
+          int i = 0, x = 0;
+          int len = strlen (s);
+          while (i < len)
+            x += s[i++];
+          return x;
+        }
+      \end{lstlisting}
+      \vspace*{-1cm}
+    \end{minipage}
+  \end{center}
+  \begin{itemize}
+    \item[(d)]
+      Was bewirken die beiden Funktionen?
+      \points{2}
+    \item[(e)]
+%      Von welcher Ordnung (Landau-Symbol) sind die beiden Funktionen
+%      hinsichtlich der Anzahl ihrer Zugriffe auf die Zeichen im String -- und warum?
+%      Sie dürfen für \lstinline{strlen()} Ihre eigene Version der Funktion voraussetzen.
+%       \points 3
+%    \item[(f)]
+      Schreiben Sie eine eigene Funktion,
+      die dieselbe Aufgabe erledigt wie \lstinline{fun_2()},\\
+      nur effizienter.
+      \points{4}
+  \end{itemize}
+
+  \solution
+
+  \begin{itemize}
+    \item[(a)]
+      \textbf{Auf welche Weise ist die Länge eines Strings gekennzeichnet?}
+
+      Ein String ist ein Array von \lstinline{char}s.
+      Nach den eigentlichen Zeichen des Strings enthält das Array
+      \textbf{ein Null-Symbol} (Zeichen mit Zahlenwert 0,
+      nicht zu verwechseln mit der Ziffer \lstinline{'0'}) als Ende-Markierung.
+      Die Länge eines Strings ist die Anzahl der Zeichen
+      \emph{vor\/} diesem Symbol.
+
+    \item[(b)]
+      {\bf Wie lang ist die Beispiel-String-Konstante \lstinline{"Hello, world!\n"},
+      und wieviel Speicherplatz belegt sie?}
+
+      Sie ist 14 Zeichen lang (\lstinline{'\n'} ist nur 1 Zeichen;
+      das Null-Symbol, das das Ende markiert, zählt hier nicht mit)
+      und belegt Speicherplatz für 15 Zeichen
+      (15 Bytes -- einschließlich Null-Symbol / Ende-Markierung).
+
+    \item[(c)]
+      \textbf{Schreiben Sie eine eigene Funktion \lstinline{int strlen (char *s)},
+      die die Länge eines Strings zurückgibt.}
+
+      Siehe die Dateien \gitfile{hp}{2021ws/20211122}{loesung-2c-1.c} (mit Array-Index)
+      und \gitfile{hp}{2021ws/20211122}{loesung-2c-2.c} (mit Zeiger-Arithmetik).
+      Beide Lösungen sind korrekt und arbeiten gleich schnell.
+
+      Die Warnung \lstinline[style=terminal]{conflicting types for built-in function "strlen"}
+      kann normalerweise ignoriert werden;
+      auf manchen Systemen (z.\,B.\ MinGW) hat jedoch die eingebaute Funktion \lstinline{strlen()}
+      beim Linken Vorrang vor der selbstgeschriebenen,
+      so daß die selbstgeschriebene Funktion nie aufgerufen wird.
+      In solchen Fällen ist es zulässig, die selbstgeschriebene Funktion
+      anders zu nennen (z.\,B.\ \lstinline{my_strlen()}).
+
+    \item[(d)]
+      \textbf{Was bewirken die beiden Funktionen?}
+
+      Beide addieren die Zahlenwerte der im String enthaltenen Zeichen
+      und geben die Summe als Funktionsergebnis zurück.
+
+      Im Falle des Test-Strings \lstinline{"Hello, world!\n"}
+      lautet der Rückgabewert 1171 (siehe \gitfile{hp}{2021ws/20211122}{loesung-2d-1.c} und \gitfile{hp}{2021ws/20211122}{loesung-2d-2.c}).
+
+    \item[(e)]
+%      \textbf{Von welcher Ordnung (Landau-Symbol) sind die beiden Funktionen
+%      hinsichtlich der Anzahl ihrer Zugriffe auf die Zeichen im String -- und warum?
+%      Sie dürfen für \lstinline{strlen()} Ihre eigene Version der Funktion voraussetzen.}
+%
+%      Vorüberlegung: \lstinline{strlen()} greift in einer Schleife
+%      auf alle Zeichen des Strings der Länge $n$ zu,
+%      hat also $\mathcal{O}(n)$.
+%
+%      \lstinline{fun_1()} ruft in jedem Schleifendurchlauf
+%      (zum Prüfen der \lstinline{while}-Bedingung) einmal \lstinline{strlen()} auf
+%      und greift anschließend auf ein Zeichen des Strings zu,
+%      hat also $\mathcal{O}\bigl(n\cdot(n+1)\bigr) = \mathcal{O}(n^2)$.
+%
+%      \lstinline{fun_2()} ruft einmalig \lstinline{strlen()} auf
+%      und greift anschließend in einer Schleife auf alle Zeichen des Strings zu,
+%      hat also $\mathcal{O}(n+n) = \mathcal{O}(n)$.
+%
+%    \item[(f)]
+      \textbf{Schreiben Sie eine eigene Funktion,
+      die dieselbe Aufgabe erledigt wie \lstinline{fun_2()},
+      nur effizienter.}
+
+      Die Funktion wird effizienter,
+      wenn man auf den Aufruf von \lstinline{strlen()} verzichtet
+      und stattdessen die Ende-Prüfung in derselben Schleife vornimmt,
+      in der man auch die Zahlenwerte der Zeichen des Strings aufsummiert.
+
+      Die Funktion \lstinline{fun_3()} in der Datei \gitfile{hp}{2021ws/20211122}{loesung-2e-1.c}
+      realisiert dies mit einem Array-Index,
+      Die Funktion \lstinline{fun_4()} in der Datei \gitfile{hp}{2021ws/20211122}{loesung-2e-2.c}
+      mit Zeiger-Arithmetik.
+      Beide Lösungen sind korrekt und arbeiten gleich schnell.
+
+%      \textbf{Bemerkung:} Die effizientere Version der Funktion
+%      arbeitet doppelt so schnell wie die ursprüngliche,
+%      hat aber ebenfalls die Ordnung $\mathcal{O}(n)$.
+
+  \end{itemize}
+
+  \exercise{LED-Blinkmuster}
+
+  Wir betrachten das folgende Programm für einen ATmega32-Mikro-Controller
+  (Datei: \gitfile{hp}{2021ws/20211122}{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}
diff --git a/20211122/hp-uebung-20211122.pdf b/20211122/hp-uebung-20211122.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..46601e585d752ed9fc18b0a632beecfa0cb9735f
Binary files /dev/null and b/20211122/hp-uebung-20211122.pdf differ
diff --git a/20211122/hp-uebung-20211122.tex b/20211122/hp-uebung-20211122.tex
new file mode 100644
index 0000000000000000000000000000000000000000..6e031dd149fdd13f3f11954d86f618491c988053
--- /dev/null
+++ b/20211122/hp-uebung-20211122.tex
@@ -0,0 +1,236 @@
+% hp-uebung-20211122.pdf - Exercises on Low-Level Programming
+% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021  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: Ausgabe von Hexadezimalzahlen, Einfügen in Strings, LED-Blinkmuster
+
+\documentclass[a4paper]{article}
+
+\usepackage{pgscript}
+
+\begin{document}
+
+%  \thispagestyle{empty}
+
+  \section*{Hardwarenahe Programmierung\\
+            Übungsaufgaben -- 22.\ November 2021}
+
+  Diese Übung enthält Punkteangaben wie in einer Klausur.
+  Um zu "`bestehen"', müssen Sie innerhalb von 80 Minuten
+  unter Verwendung ausschließlich zugelassener Hilfsmittel
+  14 Punkte (von insgesamt \totalpoints) erreichen.
+
+  \exercise{Ausgabe von Hexadezimalzahlen}
+
+  Schreiben Sie eine Funktion \lstinline{void print_hex (uint32_t x)},
+  die eine gegebene vorzeichenlose 32-Bit-Ganzzahl \lstinline{x}
+  als Hexadezimalzahl ausgibt.
+  (Der Datentyp \lstinline{uint32_t} ist mit \lstinline{#include <stdint.h>} verfügbar.)
+
+  Verwenden Sie dafür \emph{nicht\/} \lstinline{printf()} mit
+  der Formatspezifikation \lstinline{%x} als fertige Lösung,
+  sondern programmieren Sie die nötige Ausgabe selbst.
+  (Für Tests ist \lstinline{%x} hingegen erlaubt und sicherlich nützlich.)
+
+  Die Verwendung von \lstinline{printf()}
+  mit anderen Formatspezifikationen wie z.\,B.\ \lstinline{%d}
+  oder \lstinline{%c} oder \lstinline{%s} ist hingegen zulässig.
+
+  \points{8}
+
+  (Hinweis für die Klausur: Abgabe auf Datenträger ist erlaubt und erwünscht,
+  aber nicht zwingend.)
+
+  \exercise{Länge von Strings}
+
+  Strings werden in der Programmiersprache C durch Zeiger auf \lstinline{char}-Variable realisiert.
+
+  Beispiel: \lstinline{char *hello_world = "Hello, world!\n"}
+
+  Die Systembibliothek stellt eine Funktion \lstinline{strlen()} zur Ermittlung der Länge von Strings\\
+  zur Verfügung (\lstinline{#include <string.h>}).
+
+  \begin{itemize}
+    \item[(a)]
+      Auf welche Weise ist die Länge eines Strings gekennzeichnet?
+      \points{1}
+    \item[(b)]
+      Wie lang ist die Beispiel-String-Konstante \lstinline{"Hello, world!\n"},
+      und wieviel Speicherplatz belegt sie?\\
+      \points{2}
+    \item[(c)]
+      Schreiben Sie eine eigene Funktion \lstinline{int strlen (char *s)},
+      die die Länge eines Strings zurückgibt.\\
+      \points{3}
+  \end{itemize}
+
+  Wir betrachten nun die folgenden Funktionen (Datei: \gitfile{hp}{2021ws/20211121}{aufgabe-2.c}):
+  \begin{center}
+    \begin{minipage}{8cm}
+      \begin{lstlisting}[gobble=8]
+        int fun_1 (char *s)
+        {
+          int x = 0;
+          for (int i = 0; i < strlen (s); i++)
+            x += s[i];
+          return x;
+        }
+      \end{lstlisting}
+    \end{minipage}%
+    \begin{minipage}{6cm}
+      \vspace*{-1cm}
+      \begin{lstlisting}[gobble=8]
+        int fun_2 (char *s)
+        {
+          int i = 0, x = 0;
+          int len = strlen (s);
+          while (i < len)
+            x += s[i++];
+          return x;
+        }
+      \end{lstlisting}
+      \vspace*{-1cm}
+    \end{minipage}
+  \end{center}
+  \begin{itemize}
+    \item[(d)]
+      Was bewirken die beiden Funktionen?
+      \points{2}
+    \item[(e)]
+%      Von welcher Ordnung (Landau-Symbol) sind die beiden Funktionen
+%      hinsichtlich der Anzahl ihrer Zugriffe auf die Zeichen im String -- und warum?
+%      Sie dürfen für \lstinline{strlen()} Ihre eigene Version der Funktion voraussetzen.
+%       \points 3
+%    \item[(f)]
+      Schreiben Sie eine eigene Funktion,
+      die dieselbe Aufgabe erledigt wie \lstinline{fun_2()},\\
+      nur effizienter.
+      \points{4}
+  \end{itemize}
+
+  \exercise{LED-Blinkmuster}
+
+  Wir betrachten das folgende Programm für einen ATmega32-Mikro-Controller
+  (Datei: \gitfile{hp}{2021ws/20211121}{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{enumerate}[\quad(a)]
+    \item
+      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
+      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
+      Wie kommt das oben beschriebene Blinkmuster zustande?
+      \points{2}
+    \item
+      Wieso dauert eine Phase ungefähr eine halbe Sekunde?
+      \points{2}
+    \item
+      Was bedeutet "`\lstinline|ISR (TIMER0_COMP_vect)|"'?
+      \points{1}
+  \end{enumerate}
+
+  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}
+
+  \begin{flushright}
+    \textit{Viel Erfolg!}
+  \end{flushright}
+
+  \makeatletter
+    \immediate\write\@mainaux{\string\gdef\string\totalpoints{\arabic{points}}}
+  \makeatother
+
+\end{document}
diff --git a/20211122/io-ports-and-interrupts.pdf b/20211122/io-ports-and-interrupts.pdf
new file mode 120000
index 0000000000000000000000000000000000000000..bcd46f7afb35605b20bdb05637e6de0a039893ec
--- /dev/null
+++ b/20211122/io-ports-and-interrupts.pdf
@@ -0,0 +1 @@
+../common/io-ports-and-interrupts.pdf
\ No newline at end of file
diff --git a/20211122/loesung-1-1.c b/20211122/loesung-1-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..98b2f03f19d21aa2a794fef1f3f98feff95f5142
--- /dev/null
+++ b/20211122/loesung-1-1.c
@@ -0,0 +1,22 @@
+#include <stdio.h>
+#include <stdint.h>
+
+void print_hex (uint32_t x)
+{
+  while (x)
+    {
+      int digit = x % 16;
+      if (digit < 10)
+        printf ("%d", digit);
+      else
+        printf ("%c", 'a' + digit - 10);
+      x /= 16;
+    }
+}
+
+int main (void)
+{
+  print_hex (0xcafe42);
+  printf ("\n");
+  return 0;
+}
diff --git a/20211122/loesung-1-2.c b/20211122/loesung-1-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..35aa3b3aea6fc8faaa55c7d5382f0a8de9282aee
--- /dev/null
+++ b/20211122/loesung-1-2.c
@@ -0,0 +1,26 @@
+#include <stdio.h>
+#include <stdint.h>
+
+void print_hex (uint32_t x)
+{
+  char digit[8];
+  for (int i = 0; i < 8; i++)
+    {
+      digit[i] = x % 16;
+      x /= 16;
+    }
+  for (int i = 7; i >= 0; i--)
+    {
+      if (digit[i] < 10)
+        printf ("%d", digit[i]);
+      else
+        printf ("%c", 'a' + digit[i] - 10);
+    }
+}
+
+int main (void)
+{
+  print_hex (0xcafe42);
+  printf ("\n");
+  return 0;
+}
diff --git a/20211122/loesung-1-3.c b/20211122/loesung-1-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..2462f2b537896722d8d1774a5d47f374ee5ef7fa
--- /dev/null
+++ b/20211122/loesung-1-3.c
@@ -0,0 +1,29 @@
+#include <stdio.h>
+#include <stdint.h>
+
+void print_hex (uint32_t x)
+{
+  char digit[8];
+  int i = 0;
+  while (x)
+    {
+      digit[i] = x % 16;
+      x /= 16;
+      i++;
+    }
+  while (i > 0)
+    {
+      i--;
+      if (digit[i] < 10)
+        printf ("%d", digit[i]);
+      else
+        printf ("%c", 'a' + digit[i] - 10);
+    }
+}
+
+int main (void)
+{
+  print_hex (0xcafe42);
+  printf ("\n");
+  return 0;
+}
diff --git a/20211122/loesung-1-4.c b/20211122/loesung-1-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..5083dcb865c86beafd43ce3e8837510b13cbe850
--- /dev/null
+++ b/20211122/loesung-1-4.c
@@ -0,0 +1,31 @@
+#include <stdio.h>
+#include <stdint.h>
+
+void print_hex (uint32_t x)
+{
+  char digit[8];
+  for (int i = 0; i < 8; i++)
+    {
+      digit[i] = x % 16;
+      x /= 16;
+    }
+  int printing = 0;
+  for (int i = 7; i >= 0; i--)
+    {
+      if (printing || digit[i] != 0)
+        {
+          printing = 1;
+          if (digit[i] < 10)
+            printf ("%d", digit[i]);
+          else
+            printf ("%c", 'a' + digit[i] - 10);
+        }
+    }
+}
+
+int main (void)
+{
+  print_hex (0xcafe42);
+  printf ("\n");
+  return 0;
+}
diff --git a/20211122/loesung-1-5.c b/20211122/loesung-1-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..e3446edb4a40348ac14da420f344c208f8916f7e
--- /dev/null
+++ b/20211122/loesung-1-5.c
@@ -0,0 +1,29 @@
+#include <stdio.h>
+#include <stdint.h>
+
+void print_hex (uint32_t x)
+{
+  char digit[8];
+  int i = 0;
+  while (x)
+    {
+      digit[i] = x & 0x0000000f;
+      x >>= 4;
+      i++;
+    }
+  while (i > 0)
+    {
+      i--;
+      if (digit[i] < 10)
+        printf ("%d", digit[i]);
+      else
+        printf ("%c", 'a' + digit[i] - 10);
+    }
+}
+
+int main (void)
+{
+  print_hex (0xcafe42);
+  printf ("\n");
+  return 0;
+}
diff --git a/20211122/loesung-1-6.c b/20211122/loesung-1-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..7b8e8e1a9d7285b8a1e02ff1a91310f1dc02ed5b
--- /dev/null
+++ b/20211122/loesung-1-6.c
@@ -0,0 +1,23 @@
+#include <stdio.h>
+#include <stdint.h>
+
+void print_hex (uint32_t x)
+{
+  int i = 32;
+  while (i > 0)
+    {
+      i -= 4;
+      int digit = (x >> i) & 0x0000000f;
+      if (digit < 10)
+        printf ("%d", digit);
+      else
+        printf ("%c", 'a' + digit - 10);
+    }
+}
+
+int main (void)
+{
+  print_hex (0xcafe42);
+  printf ("\n");
+  return 0;
+}
diff --git a/20211122/loesung-2.c b/20211122/loesung-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..85abfcf3e1e4bacf454acd10f6832b757a64ac35
--- /dev/null
+++ b/20211122/loesung-2.c
@@ -0,0 +1,18 @@
+#include <stdio.h>
+#include <string.h>
+
+void insert_into_string (char src, char *target, int pos)
+{
+  int len = strlen (target);
+  for (int i = len; i >= pos; i--)
+    target[i + 1] = target[i];
+  target[pos] = src;
+}
+
+int main (void)
+{
+  char test[100] = "Hochshule Bochum";
+  insert_into_string ('c', test, 5);
+  printf ("%s\n", test);
+  return 0;
+}
diff --git a/20211122/loesung-2c-1.c b/20211122/loesung-2c-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..69ddd0e4e749f6ca31bfa3d4f929c333648ef6ea
--- /dev/null
+++ b/20211122/loesung-2c-1.c
@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+int strlen (char *s)
+{
+  int l = 0;
+  while (s[l])
+    l++;
+  return l;
+}
+
+int main (void)
+{
+  printf ("%d\n", strlen ("Hello, world!\n"));
+  return 0;
+}
diff --git a/20211122/loesung-2c-2.c b/20211122/loesung-2c-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..e783c474e485e80d08a6e86f8ae6e179f5a294f4
--- /dev/null
+++ b/20211122/loesung-2c-2.c
@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+int strlen (char *s)
+{
+  char *s0 = s;
+  while (*s)
+    s++;
+  return s - s0;
+}
+
+int main (void)
+{
+  printf ("%d\n", strlen ("Hello, world!\n"));
+  return 0;
+}
diff --git a/20211122/loesung-2d-1.c b/20211122/loesung-2d-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..57521382c21fb743c6f5f5c65320bc4ac9360b1a
--- /dev/null
+++ b/20211122/loesung-2d-1.c
@@ -0,0 +1,34 @@
+
+#include <stdio.h>
+
+int strlen (char *s)
+{
+  int l = 0;
+  while (s[l])
+    l++;
+  return l;
+}
+
+int fun_1 (char *s)
+{
+  int x = 0;
+  for (int i = 0; i < strlen (s); i++)
+    x += s[i];
+  return x;
+}
+
+int fun_2 (char *s)
+{
+  int i = 0, x = 0;
+  int len = strlen (s);
+  while (i < len)
+    x += s[i++];
+  return x;
+}
+
+int main (void)
+{
+  printf ("%d\n", fun_1 ("Hello, world!\n"));
+  printf ("%d\n", fun_2 ("Hello, world!\n"));
+  return 0;
+}
diff --git a/20211122/loesung-2d-2.c b/20211122/loesung-2d-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..5f3f0961129aa16fc9c4510ae21bb77b69913b12
--- /dev/null
+++ b/20211122/loesung-2d-2.c
@@ -0,0 +1,34 @@
+
+#include <stdio.h>
+
+int strlen (char *s)
+{
+  char *s0 = s;
+  while (*s)
+    s++;
+  return s - s0;
+}
+
+int fun_1 (char *s)
+{
+  int x = 0;
+  for (int i = 0; i < strlen (s); i++)
+    x += s[i];
+  return x;
+}
+
+int fun_2 (char *s)
+{
+  int i = 0, x = 0;
+  int len = strlen (s);
+  while (i < len)
+    x += s[i++];
+  return x;
+}
+
+int main (void)
+{
+  printf ("%d\n", fun_1 ("Hello, world!\n"));
+  printf ("%d\n", fun_2 ("Hello, world!\n"));
+  return 0;
+}
diff --git a/20211122/loesung-2e-1.c b/20211122/loesung-2e-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..74f5add0c5f62cccb8f817d40f860893f496db11
--- /dev/null
+++ b/20211122/loesung-2e-1.c
@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+int fun_3 (char *s)
+{
+  int i = 0, x = 0;
+  while (s[i])
+    x += s[i++];
+  return x;
+}
+
+int main (void)
+{
+  printf ("%d\n", fun_3 ("Hello, world!\n"));
+  return 0;
+}
diff --git a/20211122/loesung-2e-2.c b/20211122/loesung-2e-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..b223d2d17c261d7cf1373a8379def8911a45ccb7
--- /dev/null
+++ b/20211122/loesung-2e-2.c
@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+int fun_4 (char *s)
+{
+  int x = 0;
+  while (*s)
+    x += *s++;
+  return x;
+}
+
+int main (void)
+{
+  printf ("%d\n", fun_4 ("Hello, world!\n"));
+  return 0;
+}
diff --git a/20211122/logo-hochschule-bochum-cvh-text-v2.pdf b/20211122/logo-hochschule-bochum-cvh-text-v2.pdf
new file mode 120000
index 0000000000000000000000000000000000000000..4aa99b8f81061aca6dcaf43eed2d9efef40555f8
--- /dev/null
+++ b/20211122/logo-hochschule-bochum-cvh-text-v2.pdf
@@ -0,0 +1 @@
+../common/logo-hochschule-bochum-cvh-text-v2.pdf
\ No newline at end of file
diff --git a/20211122/logo-hochschule-bochum.pdf b/20211122/logo-hochschule-bochum.pdf
new file mode 120000
index 0000000000000000000000000000000000000000..b6b9491e370e499c9276918182cdb82cb311bcd1
--- /dev/null
+++ b/20211122/logo-hochschule-bochum.pdf
@@ -0,0 +1 @@
+../common/logo-hochschule-bochum.pdf
\ No newline at end of file
diff --git a/20211122/pgscript.sty b/20211122/pgscript.sty
new file mode 120000
index 0000000000000000000000000000000000000000..95c888478c99ea7fda0fd11ccf669ae91be7178b
--- /dev/null
+++ b/20211122/pgscript.sty
@@ -0,0 +1 @@
+../common/pgscript.sty
\ No newline at end of file
diff --git a/20211122/pgslides.sty b/20211122/pgslides.sty
new file mode 120000
index 0000000000000000000000000000000000000000..5be1416f4216f076aa268901f52a15d775e43f64
--- /dev/null
+++ b/20211122/pgslides.sty
@@ -0,0 +1 @@
+../common/pgslides.sty
\ No newline at end of file
diff --git a/README.md b/README.md
index 496ea72b5b42cea1ee8913a9670d37e4b4545f50..93225d529b18636d0f5f055b42be021d8dc67904 100644
--- a/README.md
+++ b/README.md
@@ -22,7 +22,8 @@ Vortragsfolien und Beispiele:
  * [18.10.2021: Einführung in C: Arrays und Strings, Strukturen](https://gitlab.cvh-server.de/pgerwinski/hp/raw/2021ws/20211018/hp-20211018.pdf) [**(Beispiele)**](https://gitlab.cvh-server.de/pgerwinski/hp/tree/2021ws/20211018/)
  * [25.10.2021: Einführung in C: Arrays und Strings und Zeichen, Strukturen, Dateien und Fehlerbehandlung](https://gitlab.cvh-server.de/pgerwinski/hp/raw/2021ws/20211025/hp-20211025.pdf) [**(Beispiele)**](https://gitlab.cvh-server.de/pgerwinski/hp/tree/2021ws/20211025/)
  * [08.11.2021: Parameter des Hauptprogramms, String-Operationen, Bit-Operationen, I/O-Ports](https://gitlab.cvh-server.de/pgerwinski/hp/raw/2021ws/20211108/hp-20211108.pdf) [**(Beispiele)**](https://gitlab.cvh-server.de/pgerwinski/hp/tree/2021ws/20211108/)
- * [15.11.2021: I/O-Ports, Interrupts](https://gitlab.cvh-server.de/pgerwinski/hp/raw/2021ws/20211115/hp-20211115.pdf) [**(Beispiele)**](https://gitlab.cvh-server.de/pgerwinski/hp/tree/2021ws/20211115/)
+ * [15.11.2021: I/O-Ports](https://gitlab.cvh-server.de/pgerwinski/hp/raw/2021ws/20211115/hp-20211115.pdf) [**(Beispiele)**](https://gitlab.cvh-server.de/pgerwinski/hp/tree/2021ws/20211115/)
+ * [22.11.2021: I/O-Ports, Interrupts](https://gitlab.cvh-server.de/pgerwinski/hp/raw/2021ws/20211122/hp-20211122.pdf) [**(Beispiele)**](https://gitlab.cvh-server.de/pgerwinski/hp/tree/2021ws/20211122/)
  * [alle in 1 Datei](https://gitlab.cvh-server.de/pgerwinski/hp/raw/2021ws/hp-slides-2021ws.pdf)
 
 Übungsaufgaben:
@@ -32,7 +33,8 @@ Vortragsfolien und Beispiele:
  * [18.10.2021: Seltsame Programme, Kalender-Berechnung](https://gitlab.cvh-server.de/pgerwinski/hp/raw/2021ws/20211018/hp-uebung-20211018.pdf)
  * [25.10.2021: Strings, Programm analysieren, fehlerhaftes Primzahl-Programm](https://gitlab.cvh-server.de/pgerwinski/hp/raw/2021ws/20211025/hp-uebung-20211025.pdf)
  * [08.11.2021: Arrays mit Zahlen, Datum-Bibliothek](https://gitlab.cvh-server.de/pgerwinski/hp/raw/2021ws/20211108/hp-uebung-20211108.pdf)
- * [15.11.2021: Zahlensysteme, Mikrocontroller, Einfügen in Strings (Ergänzung)](https://gitlab.cvh-server.de/pgerwinski/hp/raw/2021ws/20211115/hp-uebung-20211115.pdf)
+ * [15.11.2021: Zahlensysteme, Mikrocontroller, Einfügen in Strings](https://gitlab.cvh-server.de/pgerwinski/hp/raw/2021ws/20211115/hp-uebung-20211115.pdf)
+ * [22.11.2021: Ausgabe von Hexadezimalzahlen, Einfügen in Strings, LED-Blinkmuster](https://gitlab.cvh-server.de/pgerwinski/hp/raw/2021ws/20211122/hp-uebung-20211122.pdf)
 
 Musterlösungen:
 ---------------
@@ -41,6 +43,7 @@ Musterlösungen:
  * [25.10.2021: Strings, Programm analysieren, fehlerhaftes Primzahl-Programm](https://gitlab.cvh-server.de/pgerwinski/hp/raw/2021ws/20211025/hp-musterloesung-20211025.pdf)
  * [08.11.2021: Arrays mit Zahlen, Datum-Bibliothek](https://gitlab.cvh-server.de/pgerwinski/hp/raw/2021ws/20211108/hp-musterloesung-20211108.pdf)
  * [15.11.2021: Zahlensysteme, Mikrocontroller, Einfügen in Strings](https://gitlab.cvh-server.de/pgerwinski/hp/raw/2021ws/20211115/hp-musterloesung-20211115.pdf)
+ * [22.11.2021: Ausgabe von Hexadezimalzahlen, Einfügen in Strings, LED-Blinkmuster](https://gitlab.cvh-server.de/pgerwinski/hp/raw/2021ws/20211122/hp-musterloesung-20211122.pdf)
 
 Tafelbilder:
 ------------
diff --git a/hp-slides-2021ws.pdf b/hp-slides-2021ws.pdf
index e6892010ce91be1cafd3621c238bcbaf11fff821..7e50ab34a5d1e358c88372581d7a338486146a8b 100644
Binary files a/hp-slides-2021ws.pdf and b/hp-slides-2021ws.pdf differ
diff --git a/hp-slides-2021ws.tex b/hp-slides-2021ws.tex
index cfd6bb634dd89821a8d4c9c39f78ae50fad24711..08153151954859c4133dff7c20e5c2370513b217 100644
--- a/hp-slides-2021ws.tex
+++ b/hp-slides-2021ws.tex
@@ -20,6 +20,8 @@
   \includepdf[pages=-]{20211025/hp-20211025.pdf}
   \pdfbookmark[1]{08.11.2021: Parameter des Hauptprogramms, String-Operationen, Bit-Operationen, I/O-Ports}{20211108}
   \includepdf[pages=-]{20211108/hp-20211108.pdf}
-  \pdfbookmark[1]{15.11.2021: I/O-Ports, Interrupts}{20211115}
+  \pdfbookmark[1]{15.11.2021: I/O-Ports}{20211115}
   \includepdf[pages=-]{20211115/hp-20211115.pdf}
+  \pdfbookmark[1]{22.11.2021: I/O-Ports, Interrupts}{20211122}
+  \includepdf[pages=-]{20211122/hp-20211122.pdf}
 \end{document}