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

Vorbereitung 22.11.2021

parent f43d22d7
No related branches found
No related tags found
No related merge requests found
Showing
with 1520 additions and 2 deletions
No preview for this file type
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
\begin{document} \begin{document}
\section*{Hardwarenahe Programmierung\\ \section*{Hardwarenahe Programmierung\\
Musterlösung zu den Übungsaufgaben -- l5.\ November 2021} Musterlösung zu den Übungsaufgaben -- 15.\ November 2021}
\exercise{Zahlensysteme} \exercise{Zahlensysteme}
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
% Attribution-ShareAlike 3.0 Unported License along with this % Attribution-ShareAlike 3.0 Unported License along with this
% document. If not, see <http://creativecommons.org/licenses/>. % 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} \documentclass[a4paper]{article}
......
%.elf: %.c
avr-gcc -Wall -Os -mmcu=atmega328p $< -o $@
%.hex: %.elf
avr-objcopy -O ihex $< $@
download:
./download.sh
#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;
}
#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;
}
#include <avr/io.h>
int main (void)
{
DDRD = 0x40; /* binär: 0100 0000 */
PORTD = 0x40; /* binär: 0100 0000 */
while (1);
return 0;
}
#include <avr/io.h>
int main (void)
{
DDRD = 0xff; /* binär: 1111 1111 */
PORTD = 0x40; /* binär: 0100 0000 */
while (1);
return 0;
}
#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;
}
#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;
}
#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;
}
#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;
}
#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;
}
#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;
}
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
File added
% 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}
File added
% 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}
File added
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment