<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
	<id>https://www.mikrocontroller.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=130.75.30.51</id>
	<title>Mikrocontroller.net - Benutzerbeiträge [de]</title>
	<link rel="self" type="application/atom+xml" href="https://www.mikrocontroller.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=130.75.30.51"/>
	<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/articles/Spezial:Beitr%C3%A4ge/130.75.30.51"/>
	<updated>2026-04-10T14:41:50Z</updated>
	<subtitle>Benutzerbeiträge</subtitle>
	<generator>MediaWiki 1.39.7</generator>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=MSP430&amp;diff=94007</id>
		<title>MSP430</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=MSP430&amp;diff=94007"/>
		<updated>2016-09-18T17:02:31Z</updated>

		<summary type="html">&lt;p&gt;130.75.30.51: /* Links */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Der MSP430 ist ein 16 Bit-Mikrocontroller von Texas Instruments (TI). Er wurde speziell für eine geringe Stromaufnahme entwickelt, so dass er besonders für batteriebetriebene Geräte geeignet ist. Es gibt verschiedene Typen mit 1-256 kB [[Flash-ROM]], 128-18432 Byte [[RAM]], teilweise mit Hardware-Multiplizierer, [[UART]], [[AD-Wandler]] oder LCD-Treiber, die meisten im [[SMD]]-Package mit 20 bis &amp;gt;100 Pins. Einige neuere aus der MSP430F2xxx-Serie gibt es auch im DIP-Package (Bezeichnung: MSPxxxx &#039;&#039;&#039;-N&#039;&#039;&#039;). Der [http://www.mikrocontroller.net/part/MSP430F1121 MSP430F1121] zum Beispiel hat 4kB [[Flash-ROM]], 256B [[RAM]], 2 [[Timer]] und steckt in einem SO-20 Gehäuse. &lt;br /&gt;
&lt;br /&gt;
== Entwicklungshardware ==&lt;br /&gt;
&lt;br /&gt;
[[Datei:launchpad-lcd.jpg|thumb|right|250px|Das &#039;&#039;Launchpad&#039;&#039; (ca. 10€) enthält neben dem per USB ansprechbaren Programmer auch das &amp;quot;Spy bi Wire&amp;quot; Interface, mit dem der µC in der Schaltung emuliert werden kann (in Circuit emulation).]]&lt;br /&gt;
&lt;br /&gt;
Für den schnellen Einstieg stellt TI mehrere Entwicklungssysteme mit USB Schnittstelle zur Verfügung. Beliebt ist, auf Grund des günstigen Preises, vor allem das [http://processors.wiki.ti.com/index.php/MSP430_LaunchPad_%28MSP-EXP430G2%29 MSP430 Launchpad]. Es gibt jedoch noch andere wie z.B. das [http://focus.ti.com/docs/toolsw/folders/print/ez430-f2013.html MSP430 USB Stick Development Tool].&lt;br /&gt;
&lt;br /&gt;
Das Launchpad besitzt einen integrierten JTAG-Programmer, dessen Pins über Jumper herausgeführt sind. So kann man auch Controller direkt im Breadboard programmieren. Es können dadurch auch Controller programmiert werden, die nicht in den 20-Pin PDIP-Sockel passen, wie z.B. die MSP430F-Serie.&lt;br /&gt;
&lt;br /&gt;
Weitere Adapterplatinen und [[JTAG]]-Programmer für MSP430-Controller bekommt man bei [http://olimex.com/dev/ Olimex (Bulgarien)], in Deutschland  bei [http://elmicro.com/catalog/mcu/msp430/ Elektronikladen] oder [http://www.watterott.com/de/Boards-Kits/MSP430 Watterott].&lt;br /&gt;
&lt;br /&gt;
Einen einfachen Schaltplan für den [[JTAG]]-Programmer von TI bzw. Olimex gibt es [[Media:MSP430-JTAG-programmer.pdf|hier]]. Die Spannungsversorgung kommt im Gegensatz zum Original allerdings nicht vom Drucker-Port sondern muss extern (am besten vom MSP430 Board) bereitgestellt werden.&lt;br /&gt;
&lt;br /&gt;
Neben der JTAG-Programmierung bieten die MSP430-Controller auch die Möglichkeit, die Firmware über einen [[Bootloader]] einzuspielen. Die dafür erforderliche Hardware wird in der Application Note [http://focus.ti.com/docs/mcu/catalog/resources/appnoteabstract.jhtml?familyId=342&amp;amp;abstractName=slaa096d SLAA096d] von Texas Instruments beschrieben.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Launchpad&#039;&#039; Bezugsquellen: [https://estore.ti.com/MSP-EXP430G2-MSP430-LaunchPad-Value-Line-Development-kit-P2031.aspx] [https://hbe-shop.de/ENTWICKLUNGSKIT-MSP430LAUNCHPAD-Typ-MSP-EXP430G2] [http://search.digikey.com/scripts/DkSearch/dksus.dll?PName?Name=296-27570-ND] [http://www.watterott.com/de/MSP430-LaunchPad-MSP-EXP430G2] [https://www.ssl-id.de/b-redemann.de/catalog/product_info.php?products_id=151]&lt;br /&gt;
&lt;br /&gt;
=== Stromversorgung ===&lt;br /&gt;
&lt;br /&gt;
Der MSP430 benötigt meistens eine Spannung zwischen 1,8 und 3,6 V. Es gibt einige wenige Derivate, die mit 0.9V auskommen (z.B. MSP430L092). Einfach erzeugen kann man diese z.&amp;amp;nbsp;B. mit der folgenden Schaltung:&lt;br /&gt;
&lt;br /&gt;
https://www.mikrocontroller.net/images/lm317.png&lt;br /&gt;
&lt;br /&gt;
An den Eingang wird ein Steckernetzteil angeschlossen, die Ausgangsspannung lässt sich über das Potentiometer P1 einstellen.&lt;br /&gt;
Benutzt man für P1 einen 500Ω-Typ, kann man die Spannung in einem Bereich von 1,2 Volt und knapp 3,6 Volt einstellen. Dann kann man den MSP430 nicht durch zu hohe Versorgungsspannungen zerstören.&lt;br /&gt;
&lt;br /&gt;
Für den Batteriebetrieb eines MSP430 gibt es von TI eine fertige Lösung mit wenig Peripherie: [http://focus.ti.com/docs/prod/folders/print/tps61221.html TPS61221]&lt;br /&gt;
&lt;br /&gt;
Schaltung für 3,3V Versorgung: [http://focus.ti.com/lit/an/slva336/slva336.pdf]&lt;br /&gt;
&lt;br /&gt;
Die neue Generation mit USB, MSP430F55xx, enthält bereits einen Längsregler von 5 V auf 3,3 V für den Betrieb an der USB-Speisespannung.&lt;br /&gt;
Die Minimalausstattung für die Erstinbetriebnahme ist ein Quarz (bspw. 12 MHz), ein Widerstand 1,5 kΩ und eine Drahtbrücke.&lt;br /&gt;
&lt;br /&gt;
https://www-user.tu-chemnitz.de/~ygu/mb-iwp/Schrittmotorsteuerung/MSP430V1.jpg&lt;br /&gt;
&lt;br /&gt;
== Programmieren und Debuggen ==&lt;br /&gt;
Zum Füllen des internen Flash-Programmspeichers und zum Verfolgen des Programmablaufs stehen üblicherweise drei Schnittstellen zur Verfügung:&lt;br /&gt;
&lt;br /&gt;
* Der Bootloader (seriell oder USB)&lt;br /&gt;
* Das JTAG-Interface&lt;br /&gt;
* Der Spy-bi-Wire-Anschluss&lt;br /&gt;
&lt;br /&gt;
=== Bootloader (Seriell oder USB) ===&lt;br /&gt;
Wer fehlerarm programmieren kann und für jedwede Hilfsadapter zu geizig ist, benutzt am besten den eingebauten Bootloader. Dies ist auch der günstigste Weg bei der Serienfertigung.&lt;br /&gt;
&lt;br /&gt;
Zur Nutzung des seriellen Bootloaders ist es am günstigsten, [http://www.tu-chemnitz.de/~heha/iwp/Piezomess/Seriell wenn die fertige Schaltung sowieso eine serielle Schnittstelle vorsieht]. Ungünstigerweise „hört“ der Bootloader nicht auf RxD und TxD, sondern zumeist auf P1.1 und P2.2 (siehe jeweiliges Datenblatt!). Daher behilft man sich mit festen oder trennbaren Brücken zwischen P1.1 und TxD sowie P2.2 und RxD.&lt;br /&gt;
Von den SubD-Pins 1+4+6 geht man via Serienwiderstand bspw. 33 kΩ auf /RESET,&lt;br /&gt;
von den SubD-Pins 7+8 ebenso via 33 kΩ auf TCK, fertig ist der On-Board-Programmieradapter.&lt;br /&gt;
&lt;br /&gt;
Richtig debuggen kann man mit der seriellen Schnittstelle nicht.&lt;br /&gt;
&lt;br /&gt;
MSP430 mit USB-Schnittstelle haben &#039;&#039;keinen&#039;&#039; seriellen Bootloader. Dieser ist durch den USB-Bootloader ersetzt worden. Zu seiner Verwendung werden keine ominösen Brücken verwendet; der USB-Anschluss (den wohl jede Anwendungsschaltung mit MSP430F55xx haben wird) ist sofort zum Herunterladen der Firmware geeignet. Clevererweise meldet sich der Bootloader als HID-Gerät, das erspart den Treiber (genau genommen gibt es extra für Firmware-Updates eine eigene USB-Geräteklasse). Zum Füllen des Flash steht von Texas Instruments eine Software mit Quelltext zur Verfügung. Leider ist die API der DLL wenig brauchbar, und das Programm schluckt keine .HEX-Dateien (wie sonst üblich), sondern TI-spezifische .TXT-Dateien. Eine alternative Software für Windows gibt es [http://www-user.tu-chemnitz.de/~heha/hs_freeware/msp430-usbbsl.zip von Henrik Haftmann].&lt;br /&gt;
&lt;br /&gt;
=== JTAG ===&lt;br /&gt;
Komfortabel und dennoch preisgünstig ist der JTAG-Anschluss. Leider benötigt dieser mindestens 5 Kontakte und damit Platz auf der Schaltung. Anschluss-Adapter für den Parallelport sind leicht zu bekommen und beinhalten im einfachsten Fall nur Schutzwiderstände. Wer keinen Parallelport hat, benötigt teurere aber komfortable USB-JTAG-Adapter.&lt;br /&gt;
&lt;br /&gt;
=== Spy-Bi-Wire ===&lt;br /&gt;
Die TI-Erfindung Spy-Bi-Wire kommt mit nur 2 Leitungen aus. Hier sind nur spezielle USB-Adapter bekannt, die vom Hersteller zu beziehen und closed-source sind. Auf TI-Entwicklungsplatinen ist dieser Umsetzer bereits als ein weiterer Chip aufgelötet. Eine Liste möglicher Adapter ist z.B. [[http://de.wikipedia.org/wiki/Msp430#Liste_der_FETs.2C_sehr_unvollst.C3.A4ndig hier]] einsehbar.&lt;br /&gt;
Die verfügbaren Adapter variieren teils sehr stark in ihrem Preis aber auch in ihrer Leistungsfähigkeit.&lt;br /&gt;
&lt;br /&gt;
Die kostengünstigste Lösung ist es, ein MSP430 Launchpad als USB-Programmieradapter zu verwenden. Das Launchpad ist ein kleines Entwicklungsboard von TI und kann bei Farnell bereits für unter 10 Euro bezogen werden. Die Spy-Bi-Wire Anschlüsse (RST &amp;amp; TEST) können einfach an J2, J3 oder J4 abgenommen und an den zu programmierenden MSP430 angeschlossen werden. Zu beachten ist nur, das man den auf dem Board eingesetzten MSP430 heraus nimmt. Siehe [http://www.ti.com/lit/ug/slau318d/slau318d.pdf Launchpad Userguide/SLAU318]&lt;br /&gt;
&lt;br /&gt;
Ein genereller Nachteil bei Spy-Bi-Wire ist die zum Teil erheblich reduzierte Geschwindigkeit bei der Datenübertragung. Dies liegt v.a. daran, dass die Daten, die vorher bei JTAG über 3 Leitungen übertragen wurden (TMS, TDI, TDO) nun über eine gemeinsame bidirektionale Leitung laufen. Es gibt jedoch auch Tools die diesen Nachteil weitestgehend ausgleichen können.&lt;br /&gt;
&lt;br /&gt;
Es bleibt daher zu überlegen, ob es nicht sinnvoll ist, lieber einen Chip in einem etwas größeren Gehäuse mit mehr Pins zu verwenden und dafür JTAG zu nutzen. v.a. in Sachen Selbstbaudebugger ist dies sinnvoll.&lt;br /&gt;
&lt;br /&gt;
== Dokumentation ==&lt;br /&gt;
&lt;br /&gt;
* TI&#039;s Website: http://www.msp430.com &lt;br /&gt;
*:Für jede MSP430 Familie (z.&amp;amp;nbsp;B. MSP430F1xxx) gibt es ein generelles &amp;quot;datasheet&amp;quot;    und einen detailierten &amp;quot;user guide&amp;quot;. Die im user guide verwendeten   Registerbezeichnungen (Ports, SFRs, etc.) findet man auch bei den meisten   Compilern wieder.&lt;br /&gt;
&lt;br /&gt;
* Buch: Mikrocontrollertechnik Am Beispiel der MSP430-Familie&lt;br /&gt;
*:Dieses Lehrbuch führt in die Grundlagen der Mikrorechentechnik ein. Es beschreibt sehr detailliert den Aufbau, die Funktion und die Handhabung von Mikrocontrollern am Beispiel des MSP430F1232. Programmbeispiele sind in Assembler und C enthalten. Ideal für Einsteiger mit geringen technischen Vorkenntnissen. Autor: Matthias Sturm ISBN 3-446-21800-9, Hanser Verlag&lt;br /&gt;
&lt;br /&gt;
* Buch: [http://www.medit.hia.rwth-aachen.de/aw/cms/medit/Themen/publikationen/buecher/~tic/msp430/?lang=de Das MSP430 Mikrocontroller Buch]&lt;br /&gt;
*: ... sagt u.a.: &amp;quot;Dieses Buch eröffnet einen schrittweisen Einstieg in die Welt der Mikrocontrollerprogrammierung und führt mit ausführlichen Anwendungsbeispielen in die Fähigkeiten dieser außergewöhnlichen Prozessorfamilie ein. Jede Komponente des Prozessors wird ausführlich erklärt und deren Funktion in kleinen Beispielprogrammen gleich umgesetzt. Abgerundet wird jedes Kapitel mit einigen Übungsaufgaben. So entsteht neben dem eigentlichen Lerneffekt gleichzeitig eine Referenzbibliothek von Funktionsmodulen, die später in eigenen Anwendungen leicht weiterverwendet werden können.&amp;quot;&lt;br /&gt;
*: Autoren: Marian Walter und Stefan Tappertzhofen; ISBN 978-3-89576-236-9, Elektor Verlag&lt;br /&gt;
&lt;br /&gt;
* Egel project page website: http://noforth.bitbucket.org/site/egel%20for%20launchpad.html&lt;br /&gt;
*: This page takes you by the hand in learning how the MSP430 hardware works. It does try to help you understand how the TI-documention works. Loads of examples from simple I/O to I2C and use of the low power modes. Finally some apllication examples like building your own cloning BSL or walking biped robot.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
=== TI Code Composer Studio ===&lt;br /&gt;
Die Eclipse-basierte Entwicklungsumgebung von TI ist für Linux und Windows verfügbar. Enthalten sind sowohl eine auf 16 kB Codegröße beschränkte Version des TI-eigenen Compilers, als auch ein GCC-basierter Compiler ohne Codegrößenbeschränkung.&lt;br /&gt;
&lt;br /&gt;
* [http://www.ti.com/tool/ccstudio-msp430 Produktseite]&lt;br /&gt;
&lt;br /&gt;
===MSPGCC===&lt;br /&gt;
&lt;br /&gt;
Mittlerweile (Stand 2014) gibt es von TI selbst einen neuen GCC-basierten Compiler für MSP430, welcher komplett neu entwickelt wurde [http://www.mail-archive.com/mspgcc-users@lists.sourceforge.net/msg11305.html], und in das Code Composer Studio seit Version 6 integriert ist.&lt;br /&gt;
* [http://www.ti.com/tool/msp430-gcc-opensource GCC - Open Source Compiler for MSP430 Microcontrollers]&lt;br /&gt;
&lt;br /&gt;
Die folgenden Informationen beziehen sich auf ältere, nicht von TI unterstütze GCC-Versionen, und sind möglicherweise veraltet:&lt;br /&gt;
* Direkt mit Eclipse 3.6 Helios compilieren und debuggen [[MSP430_eclipse_helios_mspgcc4_gdb-proxy|Anleitung]] (06/2010)&lt;br /&gt;
* [http://msp430.ms.funpic.de/doku.php?id=msp430:entwicklungumgebung Eclipse+mspgcc+GDB-Proxy] (03/2009)&lt;br /&gt;
* [http://www.mikrocontroller.net/articles/Eclipse_und_MSPGCC_unter_Windows Eclipse und MSPGCC unter Windows] (03/2009)&lt;br /&gt;
* [http://matthias-hartmann.blogspot.com/ Use Eclipse and mspgcc - the easy way] (Windows 02/2009).&lt;br /&gt;
* [http://www.mikrocontroller.net/Eclipse%20und%20MSPGCC/ Eclipse und MSPGCC] (Windows 03/2006)&lt;br /&gt;
* [http://kurt.on.ufanet.ru/ MSPFET - FREE MSP430 flash programming utility] (Windows)&lt;br /&gt;
* [http://xgoat.com/wp/2009/03/25/fetproxy-an-open-source-replacement-for-msp430-gdbproxy/ FetProxy - Ein funktionierender Open-Source-Ersatz für msp430-gdbproxy] (Unix, Linux)&lt;br /&gt;
* [http://osx-launchpad.blogspot.com/ - Komplettpaket für Mac OS X](11/2011)&lt;br /&gt;
&lt;br /&gt;
===Energia===&lt;br /&gt;
Diese auf der Arduino IDE basierende Entwicklungsumgebung bietet die gleiche Nutzererfahrung für MSP430-Boards, die von der Entwicklung für Arduino-Boards bekannt ist. Es werden fortlaufend Verbesserungen vorgenommen.&lt;br /&gt;
&lt;br /&gt;
* [http://energia.nu/ Energia-Webseite]&lt;br /&gt;
&lt;br /&gt;
===MSPDebug===&lt;br /&gt;
MSPDebug ist ein Programmier/- Debugwerkzeug für den [[MSP430]], ähnlich wie avrdude für die [[AVR]]s. Es beinhaltet auch einen gdb-server um in eclipse oder direkt mit msp430-gdb zu debuggen.&lt;br /&gt;
&lt;br /&gt;
Momentan (0.21) unterstütze Programmer/Debugger (aus der Hilfe übernommen):&lt;br /&gt;
* ez430-RF2500 z.B. der Programmieradapter von der ez430-Chronos&lt;br /&gt;
* Olimex MSP-JTAG-TINY / ISO&lt;br /&gt;
* Launchpad&lt;br /&gt;
* GoodFET&lt;br /&gt;
* TI FET430UIF und Kompatible (z.B. eZ430)&lt;br /&gt;
* TI FET430UIF bootloader&lt;br /&gt;
* Flash Bootloader&lt;br /&gt;
&lt;br /&gt;
Er läuft unter Linux, *BSD, OS/X und Windows.&lt;br /&gt;
&lt;br /&gt;
Weblinks:&lt;br /&gt;
* [http://mspdebug.sourceforge.net/ Projekthomepage bei Sourceforge]&lt;br /&gt;
* [http://aur.archlinux.org/packages.php?ID=37648 AUR-Paket für Arch Linux]&lt;br /&gt;
* [http://packages.debian.org/search?suite=all&amp;amp;searchon=names&amp;amp;keywords=mspdebug Pakete für Debian Linux]&lt;br /&gt;
&lt;br /&gt;
===MSP430 Instruction Set Simulator===&lt;br /&gt;
&lt;br /&gt;
Die Firma Lauterbach bietet unter der Artikelnummer LA-8815 einen Instruction Set Simulator für den MSP430 an. Die Demoversion ist zur Evaluierung kostenlos. Einschränkungen bestehen in der Anzahl der zu ladenen Debugsymbole, was jedoch für die meisten (teils auch kleineren) Hobbyanwendungen kein Problem darstellen sollte. &lt;br /&gt;
Der Simulator unterstützt alle gängigen MSP430 Derivate, d.h. beide Instruction Sets (16bit/20bit CPUs).&lt;br /&gt;
Der Simulator lädt alle gängigen Debugformate, wie die des IAR Compilers, des Code Composer Studios von TI oder des freien Tools MSPGCC.&lt;br /&gt;
&lt;br /&gt;
Zum Simulator gäbe es entsprechende zugehörige Debugtools für den MSP430, die käuflich zu erwerben sind.&lt;br /&gt;
&lt;br /&gt;
[[Datei:msp430_sim_la8815.jpg|thumb|130px| MSP430 Simulator]]&lt;br /&gt;
&lt;br /&gt;
Der Screenshot zeigt ein Beispiel mit Quellcode (HLL/ASM mixed), Register/Stack Fenster, Breakpoint-Konfiguration, Variablenansicht, Stackframe und Darstellung des anfänglichen RAM Inhalts.&lt;br /&gt;
&lt;br /&gt;
* Weblinks:&lt;br /&gt;
** [http://www.lauterbach.com/frames.html?dwnload.html Downloadarea mit MSP430 Simulator]&lt;br /&gt;
&lt;br /&gt;
===MSP430 Forth===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Mecrisp&#039;&#039;&#039; ist eine Forth-Implementation, die direkt im Microcontroller läuft und über eine serielle Schnittstelle angesprochen wird. Momentan werden die Chips MSP430F2274 und MSP430G2553 unterstützt.&lt;br /&gt;
&lt;br /&gt;
Weblinks:&lt;br /&gt;
* [http://mecrisp.sourceforge.net/ Projekthomepage bei Sourceforge]&lt;br /&gt;
* [http://forth-ev.de/article.php/20120219114103966 mecrisp - nativ forth für MSP430] auf forth-ev.de&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CamelForth/430&#039;&#039;&#039; ist ein ANSI Standard Forth für die Texas Instruments MSP430 Mikrocontroller-Familie. CamelForth sollte mit jedem MSP430, der wenigstens 512B RAM, 8K ROM und einen USART hat, funktionieren.&lt;br /&gt;
&lt;br /&gt;
Weblinks:&lt;br /&gt;
* [http://www.camelforth.com/page.php?8 CamelForth/430]&lt;br /&gt;
* [http://forth-ev.de/article.php/20120101180840139 CF430FR - CamelForth für TI MSP430FR5739] auf forth-ev.de&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4E4th&#039;&#039;&#039; ist kleines Forth das auf dem Texas Instruments LaunchPad läuft. Es steckt in der MCU MSP430G2553. Du kommunizierst mit dem 4E4th mit Hilfe eines Zeilen Editors der über einen Terminal Emulator betrieben wird. 4E4th basiert auf der MSP430 CamelForth version 0.3 von B. J. Rodriguez, welches er für das TI Tini430 board mit dem MSP430F1611 geschrieben hatte. Es ist ein ANS Forth, und belegt knapp 8K im FLASH der MSP430G2553 MCU (0xE000-0xFFFF). Weitere 8K (0xC000-0xDFFF) sind frei für eigene Experimente. 4E4th ist, wie das CamelForth auch, freie Software (GNU General Public License). &lt;br /&gt;
&lt;br /&gt;
Weblinks:&lt;br /&gt;
* [http://forth-ev.de/index.php?topic=launchpad 4E4th auf dem LaunchPad] auf forth-ev.de&lt;br /&gt;
* [http://www.forth-ev.de/wiki/doku.php/projects:4e4th:start 4e4th im forth-ev.de Wiki]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Datei:noforth.jpg|mini|zentriert|150px|]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;noForth&#039;&#039;&#039; Is an interactive 16-bit stand-alone forth for MSP430.&lt;br /&gt;
Authors: Albert Nijhof &amp;amp; Willem Ouwerkerk.&lt;br /&gt;
&lt;br /&gt;
Last update 22 april 2016: We made noForth still more robust and we made some space saving internal changes, the kernel takes less space and compiling a program is even more space efficient now. This is nice especially for the smaller 16kB processors.&lt;br /&gt;
&lt;br /&gt;
noForth C,V comes in two basic variants:&lt;br /&gt;
* noForth C, Compact, for the smaller 16kB flash processors.&lt;br /&gt;
* noForth V, with Vocabularies, for larger flash memories. &lt;br /&gt;
&lt;br /&gt;
New:&lt;br /&gt;
* Low Power noForth for MSP430G2553 boards. In Low Power noForth all &#039;wait-loops&#039; are replaced with &#039;sleep-until-interrupted&#039; which relatively saves a lot of energy. Low power noForth is marked with a dash: noForth C- and noForth V-.&lt;br /&gt;
* noForth for msp-exp430fr5969 experimenter board&lt;br /&gt;
* noForth for MSP430G2553 egel kit &lt;br /&gt;
&lt;br /&gt;
[[Datei:egeltje1.jpg|thumb|130px|Egel]]&lt;br /&gt;
&lt;br /&gt;
Weblinks: &lt;br /&gt;
* [http://home.hccnet.nl/anij/nof/noforth.html noForth homepage, binary&#039;s and sources]&lt;br /&gt;
* [http://noforth.bitbucket.org/site/egel%20for%20launchpad.html Egel project for MSP430]&lt;br /&gt;
&lt;br /&gt;
=== Weitere Kommerzielle Compiler für MSP430 ===&lt;br /&gt;
* [http://www.imagecraft.com/devtools_MSP430.html ICC430] (45-Tage Demo; wird nach Ablauf auf 4 kByte Codegröße beschränkt)&lt;br /&gt;
* [http://www.rowley.co.uk/msp430/index.htm CrossWorks for MSP430] (30-Tage-Testversion nach Registrierung)&lt;br /&gt;
* [http://www.quadravox.com/AQ430.htm Quadravox AQ430]&lt;br /&gt;
* [http://www.iar.com/Products/IAR-Embedded-Workbench/TI-MSP430/ IAR Embedded Workbench for MSP430] (30-Tage-Testversion; Freie auf 4 kByte (MSP430) oder 8 kByte (MSP430X) Codegröße beschränkte &amp;quot;KickStart&amp;quot;-Edition)&lt;br /&gt;
&lt;br /&gt;
== Beispielanwendungen ==&lt;br /&gt;
&lt;br /&gt;
* Mathar.Com: Auf http://www.mathar.com gibt es ein paar Beispiele (in C), was man so alles mit dem MSP430 anstellen kann. Dort hat der Autor einige Anwendungen näher erläutert. Angefangen mit simplen Aufgaben wie LEDs leuchten lassen geht es weiter über eine LCD- und GLCD-Ansteuerung (HD44780- und KS0108-kompatibel) sowie einigen Beispielen zur Verwendung des integrierten A/D-Wandlers, des USARTs, des Timers und vielem mehr ... Als weitere Codebeispiele sind dort auch eine I2C-Softwareimplementation und eine CAN-Library für den MSP430 zu finden.&lt;br /&gt;
* Examples Ordner der freien Toolchain MSPGCC: Der &amp;quot;examples&amp;quot;-Ordner bzw. &amp;quot;checkout&amp;quot; aus dem CVS vom [[MSPGCC]] ist auch sehr umfangreich: http://mspgcc.cvs.sourceforge.net/mspgcc/examples/&lt;br /&gt;
* Codebeispiele auf Mikrokontroller.net: Einige [[MSP430 Codebeispiele]] finden sich auch hier in der Artikelsammlung.&lt;br /&gt;
* uIP Port auf Mikrokontroller.net: Der Port des TCP/IP Stacks von Adam Dunkels [[MSP430_uIP_Port|uIP 1.0 für den MSP430 findet sich hier]].&lt;br /&gt;
* Launchpad interne Temp. Messung mit ADC und Anzeige auf LCD: C Codebeispiel für Launchpad mit IAR Kickstartcompiler, interner ADc und LCD Ansteuerung. Vergleich Atmel 8 Bit AVR Controller und mit MSP Familie: [http://www.mikrocontroller.net/topic/222015#new]&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [http://www.mikrocontroller.net/forum/1/msp430 Beiträge zum MSP430 im Mikrocontroller.net Forum]&lt;br /&gt;
* [http://mspgcc.sourceforge.net/manual/c68.html An introduction to the TI MSP430 low-power microcontrollers]&lt;br /&gt;
* [http://tinymicros.com/embedded/MSP430/ The MSP430 Bugspray Database] - umfangreiche Datenbank für Bugs in MSP430-Controllern&lt;br /&gt;
* [http://www.mathar.com www.mathar.com] - Tutorial für Einsteiger und Fortgeschrittene: LCD, ADC, USART, I2C, CAN Programmierung in C&lt;br /&gt;
* [http://cnx.org/lenses/TexasInstruments/MSP430 Connexions - Texas Instruments MSP430] Tutorial (speziell für eZ430)&lt;br /&gt;
* [http://msp430.info MSP430.info] - Portalseite für MSP430; Info, Projekte, Paper, Entwicklungstools...&lt;br /&gt;
* [http://groups.yahoo.com/group/msp430 Yahoo group MSP430] - lebhaftes Forum mit vielen MSP430-Experten&lt;br /&gt;
* [http://www.thomas-wedemeyer.de/elektronik/msp430/msp430.html Thomas Wedemeyer&#039;s MSP430-Seiten] - Kleine Beispiel Applikationen und Tips zur Nutzung von MSPGCC mit der Dev-C++ Entwicklungsumgebung&lt;br /&gt;
* [http://homepage.hispeed.ch/py430/mspgcc/ msp430-gdb und Eclipse] - Eine Anleitung von Chris Liechti&lt;br /&gt;
* [http://passworld.co.jp/index.php?lang=GB&amp;amp;lieu=GPS MSP430 GPS] - [http://passworld.co.jp/index.php?lang=GB&amp;amp;lieu=Oximeter MSP430 Puls-Oximeter]&lt;br /&gt;
* [http://passworld.co.jp/ForumMSP430 MSP430 Forum]&lt;br /&gt;
* [http://develissimo.net/de/msp430entwicklung.html MSPGCC + Eclipse + msp430-gdbproxy / Linux / Debian / Ubuntu] - Anleitung / Tutorial zur Installation der MSPGCC Toolchain + Eclipse + msp430-gdbproxy für Linux / Debian / Ubuntu Lang=Deutsch und Englisch leider geht der link nicht mehr&lt;br /&gt;
* [http://www.sinelabore.com SinelaboreRT] - Generierung von Zustandsmaschinen in C speziell für kleine Low-Power Plattformen.&lt;br /&gt;
* [http://www.state-machine.com/msp430/ QP Framework for MSP430] - state machine Laufzeitumgebung ([http://www.state-machine.com/licensing/index.php dual licensed commercial/GPL2])&lt;br /&gt;
* [http://msp430.funpic.de msp430.funpic.de] - Wiki zum MSP430&lt;br /&gt;
* [http://mspsci.blogspot.com/2010/07/tutorial-01-getting-started.html Scientific Instruments Using the TI MSP430] - Tutorial speziell zum TI Launchpad.&lt;br /&gt;
* [http://43oh.com/ Four-Three-Oh!] - MSP430 News und Forum (en)&lt;br /&gt;
* [http://www.youtube.com/watch?v=9zfIatWxkG8&amp;amp;feature=relmfu Beispielvideo] - by JL (God of Mathfire)&lt;br /&gt;
* [http://opencores.org/project,openmsp430 openMSP430] - MSP430 als Softcore im FPGA (Verilog)&lt;br /&gt;
* [http://opencores.org/project,NEO430 NEO430] - sehr kleines MSP430-kompatibles SoC als Softcore im FPGA (VHDL)&lt;br /&gt;
&lt;br /&gt;
== Bezugsquellen  ==&lt;br /&gt;
=== Evaluation Boards ===&lt;br /&gt;
* [http://www.mikrocontroller.net/link/reichelt/msp430 reichelt.de]&lt;br /&gt;
* [http://thinkembedded.ch/MSP430:::10.html thinkembedded.ch]&lt;br /&gt;
* [http://www.sander-electronic.de/es0015.html sander-electronic]&lt;br /&gt;
* [http://ch.farnell.com/texas-instruments/ez430-rf2500/board-kit-fuer-msp430/dp/1382267 farnell.com]&lt;br /&gt;
* [http://www.ti.com/tool/msp-exp430g2 TI.com - Als Student mit Hochschulmailadresse für 10$ Versandkostenfrei]&lt;br /&gt;
* [https://www.ssl-id.de/b-redemann.de/catalog/product_info.php?cPath=51&amp;amp;products_id=205 b-redemann.de]&lt;br /&gt;
* [https://www.tindie.com/stores/Willem_O/ MSP430-EXP430G alternatives and expansion boards/kits.]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Mikrocontroller]]&lt;br /&gt;
[[Kategorie:MSP430| ]]&lt;/div&gt;</summary>
		<author><name>130.75.30.51</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Diskussion:Soft-PWM&amp;diff=91327</id>
		<title>Diskussion:Soft-PWM</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Diskussion:Soft-PWM&amp;diff=91327"/>
		<updated>2016-01-13T13:59:16Z</updated>

		<summary type="html">&lt;p&gt;130.75.30.51: /* Noch schnellere Implementierung ohne Compare Register */ Code-Formatierung gefixt&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Vielleicht wärs nicht schlecht auch noch drauf hinzuweise, dass man duch ein einfaches bit-reverse die Schaltfrequenz auf die Timer-Zykluszeit hochbringen kann... Damit ist dann das obligatorische Filtern viel einfacher...&lt;br /&gt;
&lt;br /&gt;
Ich hab leider keinen passenden Link gefunden der das illustriert aber mann man ja recht einfach nachprüfen...&lt;br /&gt;
&lt;br /&gt;
Den Zählerwert mit dieser Tabelle &lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
static const unsigned char BitReverseTable256[] = &lt;br /&gt;
{&lt;br /&gt;
  0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, &lt;br /&gt;
  0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, &lt;br /&gt;
  0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, &lt;br /&gt;
  0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, &lt;br /&gt;
  0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, &lt;br /&gt;
  0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,&lt;br /&gt;
  0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, &lt;br /&gt;
  0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,&lt;br /&gt;
  0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,&lt;br /&gt;
  0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, &lt;br /&gt;
  0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,&lt;br /&gt;
  0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,&lt;br /&gt;
  0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, &lt;br /&gt;
  0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,&lt;br /&gt;
  0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, &lt;br /&gt;
  0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
und dann vergleicht man eigentlich BitReverseTable256[ZÄHLERWERT] mit dem eingestellten PWM-Wert...&lt;br /&gt;
&lt;br /&gt;
Wenn man jetzt z.b 50% dutycycle betrachtet erkennt man schon ganz deutlich die Verbesserung:&lt;br /&gt;
bei jedem Vergleich wird getoggelt!&lt;br /&gt;
&lt;br /&gt;
Warum kein einziger Controller den ich kenne sowas macht versteh ich nicht...&lt;br /&gt;
&lt;br /&gt;
Derzeit bastle ich an einer einfachen Motorsteuerung und da wird eben ein DC-Motor per PWM vergewaltigt.&lt;br /&gt;
Software-PWM deshalb weil ich den Timer sowieso zur Zeitmessung verwende..&lt;br /&gt;
Mit dieser Methode hab&#039; ich jetzt eine Schaltfrequenz am Motor von 14kHz :)&lt;br /&gt;
&lt;br /&gt;
73&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&amp;gt;Vielleicht wärs nicht schlecht auch noch drauf hinzuweise, dass man duch ein &amp;gt;einfaches bit-reverse die Schaltfrequenz auf die Timer-Zykluszeit hochbringen &amp;gt;kann... Damit ist dann das obligatorische Filtern viel einfacher...&lt;br /&gt;
&lt;br /&gt;
Das nennt sich Puls-DICHTE-Modulation&lt;br /&gt;
&lt;br /&gt;
&amp;gt;Wenn man jetzt z.b 50% dutycycle betrachtet erkennt man schon ganz deutlich die &amp;gt;Verbesserung:&lt;br /&gt;
&amp;gt;bei jedem Vergleich wird getoggelt!&lt;br /&gt;
&lt;br /&gt;
Fast.&lt;br /&gt;
&lt;br /&gt;
&amp;gt;Warum kein einziger Controller den ich kenne sowas macht versteh ich nicht...&lt;br /&gt;
&lt;br /&gt;
Für PWM/PDM zur Erzeugung von Referenzspannungen für ADC, whatever ist das ganz nützlich. Aber . . .&lt;br /&gt;
&lt;br /&gt;
&amp;gt;Derzeit bastle ich an einer einfachen Motorsteuerung und da wird eben ein &amp;gt;DC-Motor per PWM vergewaltigt.&lt;br /&gt;
&amp;gt;Software-PWM deshalb weil ich den Timer sowieso zur Zeitmessung verwende..&lt;br /&gt;
&amp;gt;Mit dieser Methode hab&#039; ich jetzt eine Schaltfrequenz am Motor von 14kHz :)&lt;br /&gt;
&lt;br /&gt;
Eben für Leistungsendstufen ist das quasi unbrauchbar, weil dann die Schaltverluste zu hoch werden, weil zu oft geschaltet wird.&lt;br /&gt;
&lt;br /&gt;
MFG&lt;br /&gt;
Falk&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
Die Schaltverluste sollten eigentlich mit guten FETs und relativ wenig Strom nicht gravierend sein...&lt;br /&gt;
&lt;br /&gt;
Das einzige was bäse ist beim schnellen Schalten ist das EMV-Problem...&lt;br /&gt;
&lt;br /&gt;
Auf jedenfall rennt bei mir der Motor so sauberer... also viel konstanteres Moment.&lt;br /&gt;
Vor allem wenn er langsam über eine Rampe hochläuft merkt man das...&lt;br /&gt;
&lt;br /&gt;
73&lt;br /&gt;
--[[Benutzer:Hans|Hans]] 16:58, 10. Jan. 2008 (CET)&lt;br /&gt;
----&lt;br /&gt;
[http://www.mikrocontroller.net/attachment/18048/binratemultiplier.png Binratemultiplier]&lt;br /&gt;
Ich glaube da wird auch irgendwie Bitreverse gemacht, das höchstwertige Bit liegt an der niederwertigsten Stelle an&lt;br /&gt;
73 de DB1UQ&lt;br /&gt;
&lt;br /&gt;
== Intelligenter Lösungsansatz auf Atmega128 ==&lt;br /&gt;
&lt;br /&gt;
Guten Tag, &lt;br /&gt;
&lt;br /&gt;
ich finde es wirklich toll, daß sich jemand mal den Kopf zerbricht und so eine leistungsstarke Software PWM programmiert. Nur wurde diese Software mal auf anderen µC getestet als dem Atmega32? Ich habe es jetzt auf einem 128er und nem 64er Versucht. Bei beiden zerbröselt es einem die PWM, wenn man die Kanäle mit bestimmten Werten fütter, wie z.B. 200,0,100,30,0 usw. Da kommt dann nichts sinnvolles mehr raus. Ist die Frage ob das eine Einstellungssache für die anderen µC ist, oder ein genereller Softwarefehler. Habe leider gerade keinen 32er zur Hand, sonst würde ich das mal selber testen.&lt;br /&gt;
&lt;br /&gt;
== Noch schnellere Implementierung ohne Compare Register ==&lt;br /&gt;
Hallo,&lt;br /&gt;
&lt;br /&gt;
ich habe teils mit Hilfestellung dieses Artikels ein PWM für einen Timer ohne Compare Register implementiert. Das PWM wurde Trailing Edge implementiert. Ein Compare-Register habe ich bei dem verwendeten Timer schlichtweg nicht zur Verfügung. Ebenso verwende ich keine Multiplikationen und Divisionen, da ATtinys diese nicht vernünftiger Zeit berechnen.&lt;br /&gt;
&lt;br /&gt;
Der ISR-Aufruf braucht bei mir nur 25-28 Taktzyklen (-75%). Die update-Funktion benötigt zwischen 34 (1 Kanal) und 1300 (max. 8 Kanäle) Taktzyklen (-28%). Insgesamt ist der Code mit 562 Bytes auch kompakter (-42%).&lt;br /&gt;
&lt;br /&gt;
Mein Controller läuft dabei mit 8 MHz und generiert mit einem 8-Bit Timer eine 8-Bit PWM mit einer Frequenz von 122 Hz auf einem Port (8 Kanäle). Zu Testzwecken fade ich die LEDs im main-Loop.&lt;br /&gt;
&lt;br /&gt;
Ich habe auch noch eine den Code für einen zusätzlichen Port integriert, aber der skaliert in der update-Funktion sehr schlecht und müsste daher ggf. überarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *&lt;br /&gt;
     * 8-Bit Trailing Edge Soft PWM for AVR2 Architecture                        *&lt;br /&gt;
     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *&lt;br /&gt;
     * This Soft-PWM implementation uses one 8 bit timer without the need of a   *&lt;br /&gt;
     * compare mode. It controls up to 8 channels on one port or 16 channels on  *&lt;br /&gt;
     * two ports and can easily be extended to more output ports.                */&lt;br /&gt;
&lt;br /&gt;
    #define F_CPU                  8000000         // 8 MHz&lt;br /&gt;
&lt;br /&gt;
    #include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
    #include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    /* PWM Timer Settings                                                        *&lt;br /&gt;
     * timer = timer1;  mode = 8 bit normal;  clock = clk/256 (31.25kHz);        *&lt;br /&gt;
     * overflow interrupt enabled (approx. 122/s)                                */&lt;br /&gt;
    #define PWM_TIMER_OVF_vect     TIMER1_OVF_vect&lt;br /&gt;
    #define PWM_TCNT               TCNT1&lt;br /&gt;
    #define PWM_TIMER_SETUP        { TCCR1A = 0; \&lt;br /&gt;
                                     TCCR1B = 1&amp;lt;&amp;lt;CS13 | 1&amp;lt;&amp;lt;CS10 | 1&amp;lt;&amp;lt;PSR1; \&lt;br /&gt;
                                     TIMSK |= 1&amp;lt;&amp;lt;TOIE1; }&lt;br /&gt;
    /* PWM Output Port Settings                                                  *&lt;br /&gt;
     * The first `PWM_CHANNEL_COUNT` lines of `PWM_PORT` are used.               */&lt;br /&gt;
    #define PWM_PORT               PORTA&lt;br /&gt;
    #define PWM_DDR                DDRA&lt;br /&gt;
    #define PWM_CHANNEL_COUNT      8&lt;br /&gt;
    //#define PWM_TWO_PORTS                        // use a second PWM port&lt;br /&gt;
    #define PWM_PORT_2             PORTB&lt;br /&gt;
    #define PWM_DDR_2              PORTB&lt;br /&gt;
    #define PWM_CHANNEL_COUNT_2    8&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    #define PWM_FULL_CHANNEL_COUNT  PWM_CHANNEL_COUNT&lt;br /&gt;
    #ifdef PWM_TWO_PORTS&lt;br /&gt;
      #define PWM_FULL_CHANNEL_COUNT  ( PWM_CHANNEL_COUNT + PWM_CHANNEL_COUNT_2 )&lt;br /&gt;
    #endif&lt;br /&gt;
&lt;br /&gt;
    typedef struct {&lt;br /&gt;
      uint8_t mask;                // port mask&lt;br /&gt;
      #ifdef PWM_TWO_PORTS&lt;br /&gt;
        uint8_t mask_2;&lt;br /&gt;
      #endif&lt;br /&gt;
      uint8_t value;               // delay or pulse width&lt;br /&gt;
    } PWM_Slot;&lt;br /&gt;
&lt;br /&gt;
    // PWM timer value vector&lt;br /&gt;
    // two vectors and pointers for seamless reconfiguration&lt;br /&gt;
    PWM_Slot pwm_slots_a[ PWM_FULL_CHANNEL_COUNT + 1 ];&lt;br /&gt;
    PWM_Slot pwm_slots_b[ PWM_FULL_CHANNEL_COUNT + 1 ];&lt;br /&gt;
    PWM_Slot *pwm_slots_isr = pwm_slots_a;&lt;br /&gt;
    PWM_Slot *pwm_slots_config = pwm_slots_b;&lt;br /&gt;
&lt;br /&gt;
    volatile uint8_t pwm_current_isr_slot;&lt;br /&gt;
&lt;br /&gt;
    ISR( PWM_TIMER_OVF_vect )&lt;br /&gt;
    {/* This is the interrupt routine for the PWM timer overflow.  It generates  *&lt;br /&gt;
      * trailing edge Soft PWM.  All channels are set to zero at the start of a  *&lt;br /&gt;
      * cycle.  The `value` property of a pwm_slots_isr item contains the timer  *&lt;br /&gt;
      * start value for delaying the next slot.  The `mask` property holds the   *&lt;br /&gt;
      * port mask.                                                               *&lt;br /&gt;
      * Size optimized code executes this function in the following ammount of   *&lt;br /&gt;
      * clock cycles (port mask change)/(restart): 28/25 for a single port and   *&lt;br /&gt;
      * 58/57 for two ports. 2-3 additional clock cycles per port could be saved *&lt;br /&gt;
      * by assigning the whole port to mask resp. 0 and precalculating the full  *&lt;br /&gt;
      * mask. That way all other output lines would be assigned as well!         */&lt;br /&gt;
      uint8_t local_number = pwm_current_isr_slot;&lt;br /&gt;
      PWM_Slot current_slot = pwm_slots_isr[local_number];&lt;br /&gt;
      PWM_TCNT = current_slot.value;&lt;br /&gt;
      if( current_slot.mask ){&lt;br /&gt;
        PWM_PORT |= current_slot.mask;&lt;br /&gt;
        #ifdef PWM_TWO_PORTS&lt;br /&gt;
          PWM_PORT_2 |= current_slot.mask_2;&lt;br /&gt;
        #endif&lt;br /&gt;
        pwm_current_isr_slot = local_number + 1;&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
        PWM_PORT &amp;amp;= 0xFF&amp;lt;&amp;lt;PWM_CHANNEL_COUNT;&lt;br /&gt;
        #ifdef PWM_TWO_PORTS&lt;br /&gt;
          PWM_PORT_2 &amp;amp;= 0xFF&amp;lt;&amp;lt;PWM_CHANNEL_COUNT_2;&lt;br /&gt;
        #endif&lt;br /&gt;
        pwm_current_isr_slot = 0;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    void update_pwm( void )&lt;br /&gt;
    {/* This function replaces the PWM ISR parameters at the start of a PWM      *&lt;br /&gt;
      * cycle.                                                                   */&lt;br /&gt;
      PWM_Slot *pwm_slots_ptr = pwm_slots_isr;&lt;br /&gt;
&lt;br /&gt;
      // wait for pwm_current_isr_slot to switch to zero&lt;br /&gt;
      if(pwm_slots_isr[0].mask)&lt;br /&gt;
        while(pwm_current_isr_slot == 0)&lt;br /&gt;
          {}&lt;br /&gt;
      while(pwm_current_isr_slot)&lt;br /&gt;
        {}&lt;br /&gt;
&lt;br /&gt;
      // shift pwm_slots_isr pointer;&lt;br /&gt;
      cli();&lt;br /&gt;
      pwm_slots_isr = pwm_slots_config;&lt;br /&gt;
      sei();&lt;br /&gt;
      pwm_slots_config = pwm_slots_ptr;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    void set_pwm( PWM_Slot *channel )&lt;br /&gt;
    {/* This function writes propper PWM isr parameters into pwm_slots_config.   *&lt;br /&gt;
      * For a single port it scales with a about 160 clock cycles per channel.   *&lt;br /&gt;
      * For two ports it scales worse (maybe 500 clock cycles per channel). IT   *&lt;br /&gt;
      * should be possible to improove this by using some pointer arithmetic and *&lt;br /&gt;
      * a smarter sorting alogrithm in that case.                                */&lt;br /&gt;
      uint8_t pwmslots = PWM_FULL_CHANNEL_COUNT;&lt;br /&gt;
      &lt;br /&gt;
      // sort channels from max to min PWM width&lt;br /&gt;
      for( uint8_t i = 0; i &amp;lt; pwmslots; i++ ){&lt;br /&gt;
        // search channel of maximal value&lt;br /&gt;
        uint8_t max_channel = i;&lt;br /&gt;
        uint8_t max_value = channel[i].value;&lt;br /&gt;
        for( uint8_t j = i; j &amp;lt; pwmslots; j++ ){&lt;br /&gt;
          if( max_value &amp;lt; channel[j].value){&lt;br /&gt;
            max_value = channel[j].value;&lt;br /&gt;
            max_channel = j;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        // Merge channels if value is equal to previous.&lt;br /&gt;
        if( i &amp;amp;&amp;amp; ( max_value == channel[ i - 1 ].value )){&lt;br /&gt;
          pwmslots--;&lt;br /&gt;
          channel[i - 1].mask |= channel[max_channel].mask;&lt;br /&gt;
          #ifdef PWM_TWO_PORTS &lt;br /&gt;
            channel[i - 1].mask_2 |= channel[max_channel].mask_2;&lt;br /&gt;
          #endif&lt;br /&gt;
          channel[max_channel] = channel[pwmslots];&lt;br /&gt;
          i--;&lt;br /&gt;
        }&lt;br /&gt;
        // Else move channel of maximal value to index `i`.&lt;br /&gt;
        else if( max_channel != i ){&lt;br /&gt;
          PWM_Slot tmp = channel[max_channel];&lt;br /&gt;
          channel[max_channel] = channel[i];&lt;br /&gt;
          channel[i] = tmp;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
      // skip channels with a PWM width of zero&lt;br /&gt;
      if( channel[ pwmslots - 1 ].value == 0)&lt;br /&gt;
        pwmslots--;&lt;br /&gt;
      &lt;br /&gt;
      // write values into pwm_slots_config&lt;br /&gt;
      // pwm_slot[pwmslots] is black time before first/longest slot&lt;br /&gt;
      pwm_slots_config[pwmslots].mask = 0;&lt;br /&gt;
      #ifdef PWM_TWO_PORTS&lt;br /&gt;
        pwm_slots_config[pwmslots].mask_2 = 0;&lt;br /&gt;
      #endif&lt;br /&gt;
      pwm_slots_config[pwmslots].value = channel[0].value;&lt;br /&gt;
      uint8_t following = 0;&lt;br /&gt;
      for(uint8_t i = pwmslots; i;){&lt;br /&gt;
        i--;&lt;br /&gt;
        // pwm_slot[n].mask: port mask for the n^th PWM width&lt;br /&gt;
        pwm_slots_config[i].mask = channel[i].mask;&lt;br /&gt;
        #ifdef PWM_TWO_PORTS&lt;br /&gt;
          pwm_slots_config[i].mask_2 = channel[i].mask_2;&lt;br /&gt;
        #endif&lt;br /&gt;
        // pwm_slot[n].value: delay between n^th and n+1^st up-flank&lt;br /&gt;
        pwm_slots_config[i].value = following - channel[i].value;&lt;br /&gt;
        following = channel[i].value;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    void initialize_pwm( void )&lt;br /&gt;
    {/*  This function initialized the Soft-PWM.                                 */&lt;br /&gt;
      // set data direction register for PWM port&lt;br /&gt;
      PWM_DDR |= ~( 0xFF&amp;lt;&amp;lt;PWM_CHANNEL_COUNT );&lt;br /&gt;
      #ifdef PWM_TWO_PORTS&lt;br /&gt;
        PWM_DDR_2 |= ~( 0xFF&amp;lt;&amp;lt;PWM_CHANNEL_COUNT_2 );&lt;br /&gt;
      #endif&lt;br /&gt;
      // setup timer and activate overflow interrupt&lt;br /&gt;
      PWM_TIMER_SETUP&lt;br /&gt;
&lt;br /&gt;
      // initialize PWM timer value vector&lt;br /&gt;
      pwm_slots_a[0].mask = 0;&lt;br /&gt;
      #ifdef PWM_TWO_PORTS&lt;br /&gt;
        pwm_slots_a[0].mask_2 = 0;&lt;br /&gt;
      #endif&lt;br /&gt;
      pwm_slots_a[0].value = -1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    int main( void )&lt;br /&gt;
    { /* Main program function                                                   */&lt;br /&gt;
      uint8_t val; // fading counter&lt;br /&gt;
      initialize_pwm();&lt;br /&gt;
&lt;br /&gt;
      while(1){&lt;br /&gt;
        // fade over the PWM channels&lt;br /&gt;
        PWM_Slot channel[PWM_FULL_CHANNEL_COUNT];&lt;br /&gt;
        for( uint8_t i=0; i &amp;lt; PWM_FULL_CHANNEL_COUNT; i++ ){&lt;br /&gt;
          #ifdef PWM_TWO_PORTS&lt;br /&gt;
            if( i &amp;lt; PWM_CHANNEL_COUNT){&lt;br /&gt;
              channel[i].mask = 1&amp;lt;&amp;lt;i;&lt;br /&gt;
              channel[i].mask_2 = 0;&lt;br /&gt;
            }&lt;br /&gt;
            else{&lt;br /&gt;
              channel[i].mask = 0;&lt;br /&gt;
              channel[i].mask_2 = 1&amp;lt;&amp;lt;(i - PWM_CHANNEL_COUNT);&lt;br /&gt;
            }&lt;br /&gt;
          #else&lt;br /&gt;
            channel[i].mask = 1&amp;lt;&amp;lt;i;&lt;br /&gt;
          #endif&lt;br /&gt;
          // shift phase each channel&lt;br /&gt;
          channel[i].value = val + i * ((1&amp;lt;&amp;lt;8) / PWM_FULL_CHANNEL_COUNT - 1);&lt;br /&gt;
          // fade up-down (0, .., 127, 127, .., 0)&lt;br /&gt;
          if( channel[i].value &amp;amp; 1&amp;lt;&amp;lt;7 )&lt;br /&gt;
            channel[i].value = 255 - channel[i].value;&lt;br /&gt;
        }&lt;br /&gt;
        set_pwm(channel);&lt;br /&gt;
        update_pwm();&lt;br /&gt;
&lt;br /&gt;
        &lt;br /&gt;
        // increase fading counter (0, 1, .., 255, 0, ..)&lt;br /&gt;
        val++;&lt;br /&gt;
        _delay_ms(10);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Fußnoten ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>130.75.30.51</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_Schieberegister&amp;diff=86915</id>
		<title>AVR-Tutorial: Schieberegister</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_Schieberegister&amp;diff=86915"/>
		<updated>2015-01-28T16:38:24Z</updated>

		<summary type="html">&lt;p&gt;130.75.30.51: Passenderer Begriff...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ab und an stellt sich folgendes Problem: Man würde wesentlich mehr Ausgangspins oder Eingangspins benötigen als der [[Mikrocontroller]] zur Verfügung stellt. Ein möglicher Ausweg ist eine Porterweiterung mit einem Schieberegister. Zwei beliebte Schieberegister sind beispielsweise der 74xx595 bzw. der 74xx165.&lt;br /&gt;
&lt;br /&gt;
== Porterweiterung für Ausgänge ==&lt;br /&gt;
&lt;br /&gt;
Um neue Ausgangspins zu gewinnen kann der [[74xx | 74xx595]] verwendet werden. Dabei handelt es sich um ein &#039;&#039;8-Bit 3-state Serial-in/Serial-out or Parallel-Out Schieberegister mit einem Ausgangsregister und einem asynchronen Reset&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Hinter dieser kompliziert anmutenden Beschreibung verbirgt sich eine einfache Funktionalität: Das Schieberegister besteht aus zwei Funktionseinheiten: Dem eigentlichen Schieberegister und dem Ausgangsregister. In das Schieberegister können die Daten seriell hineingetaktet werden und durch ein bestimmtes Signal werden die Daten des Schieberegisters in das Ausgangsregister übernommen und können von dort auf die Ausgangspins geschaltet werden.&lt;br /&gt;
&lt;br /&gt;
Im Einzelnen bedeuten die Begriffe:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
{| {{Tabelle}}&lt;br /&gt;
|-  style=&amp;quot;background-color:#ffddcc&amp;quot;&lt;br /&gt;
! Begriff || Erklärung&lt;br /&gt;
|-&lt;br /&gt;
||8-Bit&lt;br /&gt;
|align=&amp;quot;left&amp;quot;| Acht Ausgangs[[Bit|bit]]s&lt;br /&gt;
|-&lt;br /&gt;
||3-state&lt;br /&gt;
|align=&amp;quot;left&amp;quot;| Die acht Registerausgänge können drei Zustände, Low, High und High-Impedanz annehmen.&amp;lt;BR&amp;gt;Siehe [[Ausgangsstufen Logik-ICs]]&lt;br /&gt;
|-&lt;br /&gt;
||Serial-in&lt;br /&gt;
|align=&amp;quot;left&amp;quot;| Serieller Eingang des Schieberegisters&lt;br /&gt;
|-&lt;br /&gt;
||Serial-out&lt;br /&gt;
|align=&amp;quot;left&amp;quot;| Serieller Ausgang des Schieberegisters&lt;br /&gt;
|-&lt;br /&gt;
||Parallel-Out&lt;br /&gt;
|align=&amp;quot;left&amp;quot;| Parallele Ausgänge des Ausgangsregisters&lt;br /&gt;
|-&lt;br /&gt;
||Schieberegister&lt;br /&gt;
|align=&amp;quot;left&amp;quot;| Serielle Daten werden durch den Baustein durchgeschoben&lt;br /&gt;
|-&lt;br /&gt;
|Ausgangsregister&lt;br /&gt;
|align=&amp;quot;left&amp;quot;| Ein Speicher, welcher die Daten des Schieberegisters zwischenspeichern kann.&amp;lt;BR&amp;gt;Dieses besteht aus acht [[FlipFlop]]s.&lt;br /&gt;
|-&lt;br /&gt;
|Asynchroner Reset&lt;br /&gt;
|align=&amp;quot;left&amp;quot;| Die Daten im Schieberegister können asynchron zurückgesetzt werden.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Aufbau 74xx595 ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:74xx595-1.png|framed|center|Pinbelegung eines 595]]&lt;br /&gt;
&lt;br /&gt;
Hinweis: Die Benennung der Pins in den Datenblättern verschiedener Hersteller unterscheidet sich zum Teil. Die Funktionen der Pins sind jedoch gleich. &lt;br /&gt;
&lt;br /&gt;
Achtung: Es gibt auch noch einen IC von TI mit eingebauten Treibern 50 V 150 mA, den TPIC6B595, der hat 20 Pins und eine abweichende Pinbelegung http://www.ti.com/product/tpic6b595&lt;br /&gt;
&lt;br /&gt;
==== HC oder HCT? ====&lt;br /&gt;
&lt;br /&gt;
[ACHTUNG: HIER STEHT VIEL MÜLL BEZUEGLICH DER SCHALTSCHWELLEN !!!&lt;br /&gt;
Schaltschwellen von HC, HCT, AHCT, etc. lassen sich im jeweiligen Datenblatt nachschlagen:&lt;br /&gt;
 V_IH --&amp;gt; HIGH-level input voltage&lt;br /&gt;
 V_IL --&amp;gt; LOW-level input voltage&lt;br /&gt;
&lt;br /&gt;
74AHCT595 kann direkt von Low-Voltage MCUs angesteuert werden (2V minimum)&lt;br /&gt;
bei HC/HCT etc liegt die High Schaltschwelle bei 3,5V (minimum)&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
Mal gibt es 74&#039;&#039;&#039;HC&#039;&#039;&#039;595, mal 74&#039;&#039;&#039;HCT&#039;&#039;&#039;595.&lt;br /&gt;
Diese beiden Typen unterscheiden sich nur bei der Festlegung der Schaltschwelle an Eingangspins:&lt;br /&gt;
* HC: Schaltschwelle = halbe Betriebsspannung&lt;br /&gt;
* HCT: Schaltschwelle TTL-kompatibel bei 1,4 V&lt;br /&gt;
Es gibt auch 74LS595. In der modernen CMOS-Welt sollte man sich Low-Power-Schottky (= bipolar = Ruhestrom fressend) nicht mehr antun.&lt;br /&gt;
&lt;br /&gt;
Im allgemeinen kann man alle Typen gleichermaßen verwenden und nimmt einfach den billigsten oder verfügbarsten. Nur beim Übergang zu echtem TTL oder verschiedenen Speisespannungen für Mikrocontroller und Portexpander wird es interessant.&lt;br /&gt;
&lt;br /&gt;
Ein häufiges Szenario ist ein Mikrocontroller mit 3-V-Speisung (etwa ein ARM7 oder MSP430). Dann kann man mit einem 74&#039;&#039;&#039;HCT&#039;&#039;&#039;595, an 5 V betrieben, echte 5-V-Ausgänge und die Pegelkonvertierung dazu haben.&lt;br /&gt;
74&#039;&#039;&#039;HC&#039;&#039;&#039;595 funktionieren hier nur mit Glück, und bei noch geringerer Speisespannung des Controllers — etwa 2,5 V — gar nicht.&lt;br /&gt;
&lt;br /&gt;
=== Pinbelegung 74xx595 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
{| {{Tabelle}}&lt;br /&gt;
|-  style=&amp;quot;background-color:#ffddcc&amp;quot;&lt;br /&gt;
! DIL Pin-Nummer || Funktion || Dieses Tutorial || Motorola / ON Semi || Philips / NXP         || Fairchild     || SGS|| Texas Instruments&lt;br /&gt;
|-&lt;br /&gt;
|  1 || Ausgang B           || QB || Q&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;  || Q&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;   || Q&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;  || QB|| Q&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;  &lt;br /&gt;
|-&lt;br /&gt;
|  2 || Ausgang C           || QC || Q&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;  || Q&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;   || Q&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;  || QC|| Q&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;  &lt;br /&gt;
|-&lt;br /&gt;
|  3 || Ausgang D           || QD || Q&amp;lt;sub&amp;gt;D&amp;lt;/sub&amp;gt;  || Q&amp;lt;sub&amp;gt;3&amp;lt;/sub&amp;gt;   || Q&amp;lt;sub&amp;gt;D&amp;lt;/sub&amp;gt;  || QD|| Q&amp;lt;sub&amp;gt;D&amp;lt;/sub&amp;gt;  &lt;br /&gt;
|-&lt;br /&gt;
|  4 || Ausgang E           || QE || Q&amp;lt;sub&amp;gt;E&amp;lt;/sub&amp;gt;  || Q&amp;lt;sub&amp;gt;4&amp;lt;/sub&amp;gt;   || Q&amp;lt;sub&amp;gt;E&amp;lt;/sub&amp;gt;  || QE|| Q&amp;lt;sub&amp;gt;E&amp;lt;/sub&amp;gt;  &lt;br /&gt;
|-&lt;br /&gt;
|  5 || Ausgang F           || QF || Q&amp;lt;sub&amp;gt;F&amp;lt;/sub&amp;gt;  || Q&amp;lt;sub&amp;gt;5&amp;lt;/sub&amp;gt;   || Q&amp;lt;sub&amp;gt;F&amp;lt;/sub&amp;gt;  || QF|| Q&amp;lt;sub&amp;gt;F&amp;lt;/sub&amp;gt;  &lt;br /&gt;
|-&lt;br /&gt;
|  6 || Ausgang G           || QG || Q&amp;lt;sub&amp;gt;G&amp;lt;/sub&amp;gt;  || Q&amp;lt;sub&amp;gt;6&amp;lt;/sub&amp;gt;   || Q&amp;lt;sub&amp;gt;G&amp;lt;/sub&amp;gt;  || QG|| Q&amp;lt;sub&amp;gt;G&amp;lt;/sub&amp;gt;  &lt;br /&gt;
|-&lt;br /&gt;
|  7 || Ausgang H           || QH || Q&amp;lt;sub&amp;gt;H&amp;lt;/sub&amp;gt;  || Q&amp;lt;sub&amp;gt;7&amp;lt;/sub&amp;gt;   || Q&amp;lt;sub&amp;gt;H&amp;lt;/sub&amp;gt;  || QH|| Q&amp;lt;sub&amp;gt;H&amp;lt;/sub&amp;gt;  &lt;br /&gt;
|-&lt;br /&gt;
|  8 || Masse, 0 V || [nicht dargestellt] || GND            || GND             || GND             || GND|| GND&lt;br /&gt;
|-&lt;br /&gt;
|  9 || Serieller Ausgang || QH* || SQ&amp;lt;sub&amp;gt;H&amp;lt;/sub&amp;gt; || Q&amp;lt;sub&amp;gt;7&amp;lt;/sub&amp;gt;´  ||Q&#039;&amp;lt;sub&amp;gt;H&amp;lt;/sub&amp;gt;  ||  QH´||Q&amp;lt;sub&amp;gt;H&#039;&amp;lt;/sub&amp;gt;  &lt;br /&gt;
|-&lt;br /&gt;
| 10 || Reset für Schieberegister             || SCL || RESET          || /MR             || /SCLR        || /SCLR || /SRCLR&lt;br /&gt;
|-&lt;br /&gt;
| 11 || Schiebetakt        || SCK || SHIFT CLOCK    || SH&amp;lt;sub&amp;gt;CP&amp;lt;/sub&amp;gt; || SCK          || SCK || SRCLK&lt;br /&gt;
|-&lt;br /&gt;
| 12 || Speichertakt        || RCK || LATCH CLOCK    || ST&amp;lt;sub&amp;gt;CP&amp;lt;/sub&amp;gt; || RCK          || RCK || RCLK&lt;br /&gt;
|-&lt;br /&gt;
| 13 || Ausgangssteuerung      || G || OUTPUT ENABLE  || /OE             || /G           || /G || /OE&lt;br /&gt;
|-&lt;br /&gt;
| 14 || Serieller Dateneingang  || SER || A              || D&amp;lt;sub&amp;gt;S&amp;lt;/sub&amp;gt;   || SER          || SI || SER&lt;br /&gt;
|-&lt;br /&gt;
| 15 || Ausgang A           || QA || Q&amp;lt;sub&amp;gt;A&amp;lt;/sub&amp;gt;  || Q&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt;   || Q&amp;lt;sub&amp;gt;A&amp;lt;/sub&amp;gt;  || QA|| Q&amp;lt;sub&amp;gt;A&amp;lt;/sub&amp;gt;  &lt;br /&gt;
|-&lt;br /&gt;
| 16 || Betriebsspannung || [nicht dargestellt] || V&amp;lt;sub&amp;gt;CC&amp;lt;/sub&amp;gt; || V&amp;lt;sub&amp;gt;CC&amp;lt;/sub&amp;gt;  || V&amp;lt;sub&amp;gt;CC&amp;lt;/sub&amp;gt;  || V&amp;lt;sub&amp;gt;CC&amp;lt;/sub&amp;gt;|| V&amp;lt;sub&amp;gt;CC&amp;lt;/sub&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Baustein besteht aus zwei Einheiten:&lt;br /&gt;
* dem Schieberegister&lt;br /&gt;
* dem Ausgangsregister&lt;br /&gt;
&lt;br /&gt;
Im Schieberegister werden die einzelnen Bits durchgeschoben. Mit jeder positiven Taktflanke(LOW -&amp;gt; HIGH) an &#039;&#039;&#039;SCK&#039;&#039;&#039; wird eine Schiebeoperation durchgeführt.&lt;br /&gt;
&lt;br /&gt;
Das Ausgangsregister hat die Aufgabe die Ausgangspins des Bausteins anzusteuern. Durch dieses Ausgangsregister ist es möglich, die Schiebeoperationen im Hintergrund durchzuführen, ohne dass IC Pins ihren Wert ändern. Erst wenn die Schiebeoperation abgeschlossen ist, wird der aktuelle Zustand der Schieberegisterkette durch einen Puls an &#039;&#039;&#039;RCK&#039;&#039;&#039; in das Ausgangsregister übernommen.&lt;br /&gt;
&lt;br /&gt;
===Funktionsweise===&lt;br /&gt;
&lt;br /&gt;
Am Eingang &#039;&#039;&#039;SER&#039;&#039;&#039; (Pin 14) wird das gewünschte nächste Datum (0 oder 1) angelegt. Durch einen positiven Puls an &#039;&#039;&#039;SCK&#039;&#039;&#039; (Pin 11) wird der momentan an &#039;&#039;&#039;SER&#039;&#039;&#039; anliegende Wert als neuer Wert für Bit 0, das unterste Bit des Schieberegisters, übernommen. Gleichzeitig werden alle anderen Bits im Schieberegister um eine Stelle verschoben: Das Bit 6 wird ins Bit 7 übernommen, Bit 5 ins Bit 6, Bit 4 ins Bit 5, etc. sodass das Bit 0 zur Aufnahme des &#039;&#039;&#039;SER&#039;&#039;&#039; Bits frei wird.&lt;br /&gt;
&lt;br /&gt;
[[Bild:74xx595-2.png|center]]&lt;br /&gt;
&lt;br /&gt;
Eine Sonderstellung nimmt das ursprüngliche Bit 7 ein. Dieses Bit steht direkt auch am Ausgang &#039;&#039;&#039;QH*&#039;&#039;&#039; (Pin 9) zur Verfügung. Dadurch ist es möglich an ein Schieberegister einen weiteren Baustein 74xxx595 anzuschließen und so beliebig viele Schieberegister hintereinander zu schalten (kaskadieren). Auf diese Art lassen sich Schieberegister mit beliebig vielen Stufen aufbauen.&lt;br /&gt;
&lt;br /&gt;
Wurde das Schieberegister mit den Daten gefüllt, so wird mit einem LOW-HIGH Puls am Pin 12, &#039;&#039;&#039;RCK&#039;&#039;&#039; der Inhalt des Schieberegisters in das Ausgangsregister übernommen.&lt;br /&gt;
&lt;br /&gt;
[[Bild:74xx595-3.png|center]]&lt;br /&gt;
&lt;br /&gt;
Mit dem Eingang &#039;&#039;&#039;G&#039;&#039;&#039; (Pin 13) kann das Ausgangsregister freigegeben werden. Liegt &#039;&#039;&#039;G&#039;&#039;&#039; auf 0, so führen die Ausgänge &#039;&#039;&#039;QA&#039;&#039;&#039; bis &#039;&#039;&#039;QH&#039;&#039;&#039; entsprechende Pegel. Liegt &#039;&#039;&#039;G&#039;&#039;&#039; auf 1, so schalten die Ausgänge &#039;&#039;&#039;QA&#039;&#039;&#039; bis &#039;&#039;&#039;QH&#039;&#039;&#039; auf [[Ausgangsstufen Logik-ICs |Tristate]]. D.h. sie treiben aktiv weder LOW oder HIGH, sondern sind hochohmig wie ein Eingang und nehmen jeden Pegel an, der ihnen von außen aufgezwungen wird.&lt;br /&gt;
&lt;br /&gt;
Bleibt nur noch der Eingang &#039;&#039;&#039;SCL&#039;&#039;&#039;(Pin 10). Mit ihm kann das Schieberegister im Baustein gelöscht, also auf eine definierte 0, gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Die Ansteuerung eines 74xxx595 Schieberegisters gestaltet sich sehr einfach. Im Grunde gibt es 2 Möglichkeiten:&lt;br /&gt;
* Mittels [[SPI]] kann der [[AVR]] das Schieberegister direkt und autark ansteuern. Das ist sehr schnell und verbraucht nur wenig CPU-Leistung&lt;br /&gt;
* Sind die entsprechenden SPI-Pins am AVR nicht frei, so ist auch eine softwaremäßige Ansteuerung des Schieberegisters mit einfachen Mitteln durchführbar.&lt;br /&gt;
&lt;br /&gt;
=== Ansteuerung per Software===&lt;br /&gt;
&lt;br /&gt;
[[Bild:Mega8-595.gif|framed|right|Anschluss eines 595]]&lt;br /&gt;
Für eine komplette Softwarelösung kann das Schieberegister an jede beliebige Port-Pin Kombination angeschlossen werden. Wir wählen die Pins &#039;&#039;&#039;PB0&#039;&#039;&#039;, &#039;&#039;&#039;PB1&#039;&#039;&#039;, &#039;&#039;&#039;PB2&#039;&#039;&#039; und &#039;&#039;&#039;PB3&#039;&#039;&#039; um dort die Schieberegisteranschlüsse &#039;&#039;&#039;SER&#039;&#039;&#039;, &#039;&#039;&#039;SCK&#039;&#039;&#039;, &#039;&#039;&#039;SCL&#039;&#039;&#039; und &#039;&#039;&#039;RCK&#039;&#039;&#039; anzuschließen. Des Weiteren muss das Schieberegister mit Spannung versorgt werden, auch wenn das rechts im Bild nicht eingezeichnet ist. Pin 16 muss auf +5V und Pin 8 auf GND geschaltet werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Programmierung gestaltet sich dann nach folgendem Schema: Die 8 Bits eines Bytes werden nacheinander an den Ausgang &#039;&#039;&#039;PB0&#039;&#039;&#039; (&#039;&#039;&#039;SER&#039;&#039;&#039;) ausgegeben. Durch Generierung eines Pulses 0-1-0 an Pin &#039;&#039;&#039;PB1&#039;&#039;&#039; (&#039;&#039;&#039;SCK&#039;&#039;&#039;) übernimmt das Schieberegister nacheinander die einzelnen Bits. Dabei ist zu beachten, dass die Ausgabe mit dem höherwertigen Bit beginnen muss, denn dieses Bit wandert ja am weitesten zur Stelle &#039;&#039;&#039;QH&#039;&#039;&#039;. Sind alle 8 Bits ausgegeben, so wird durch einen weiteren 0-1-0 Impuls am Pin &#039;&#039;&#039;PB3&#039;&#039;&#039; (&#039;&#039;&#039;RCK&#039;&#039;&#039;) der Inhalt der Schieberegisterbits 0 bis 7 in die Ausgaberegister &#039;&#039;&#039;QA&#039;&#039;&#039; bis &#039;&#039;&#039;QH&#039;&#039;&#039; übernommen. Dadurch, dass am Schieberegister der Eingang &#039;&#039;&#039;G&#039;&#039;&#039; konstant auf 0-Pegel gehalten wird, erscheint dann auch die Ausgabe sofort an den entsprechenden Pins und kann zb. mit LEDs (low-current LEDs + Vorwiderstand verwenden) sichtbar gemacht werden.&lt;br /&gt;
&lt;br /&gt;
Der Schieberegistereingang &#039;&#039;&#039;SCL&#039;&#039;&#039; wird auf einer 1 gehalten. Würde er&lt;br /&gt;
auf 0 gehen, so würde die Schieberegisterkette gelöscht. Möchte man einen weiteren Prozessorpin einsparen, so kann man diesen Pin auch generell auf Vcc legen. Das Schieberegister könnte man in so einem Fall durch Einschreiben von 0x00 immer noch löschen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
.include &amp;quot;m8def.inc&amp;quot;&lt;br /&gt;
&lt;br /&gt;
.def temp1 = r16&lt;br /&gt;
.def temp2 = r17&lt;br /&gt;
&lt;br /&gt;
.equ SCHIEBE_DDR  = DDRB&lt;br /&gt;
.equ SCHIEBE_PORT = PORTB&lt;br /&gt;
.equ RCK          = 3&lt;br /&gt;
.equ SCK          = 1&lt;br /&gt;
.equ SCL          = 2&lt;br /&gt;
.equ SIN          = 0&lt;br /&gt;
&lt;br /&gt;
    ldi   temp1, LOW(RAMEND)     ; Stackpointer initialisieren&lt;br /&gt;
    out   SPL, temp1&lt;br /&gt;
    ldi   temp1, HIGH(RAMEND)&lt;br /&gt;
    out   SPH, temp1&lt;br /&gt;
&lt;br /&gt;
;&lt;br /&gt;
; Die Port Pins auf Ausgang konfigurieren&lt;br /&gt;
;&lt;br /&gt;
    ldi   temp1, (1&amp;lt;&amp;lt;RCK) | (1&amp;lt;&amp;lt;SCK) | (1&amp;lt;&amp;lt;SCL) | (1&amp;lt;&amp;lt;SIN) ; Anm.1&lt;br /&gt;
    out   SCHIEBE_DDR, temp1&lt;br /&gt;
&lt;br /&gt;
;&lt;br /&gt;
; die Clear Leitung am Schieberegister auf 1 stellen&lt;br /&gt;
;&lt;br /&gt;
    sbi   SCHIEBE_PORT, SCL&lt;br /&gt;
&lt;br /&gt;
;&lt;br /&gt;
; Ein Datenbyte ausgeben&lt;br /&gt;
;&lt;br /&gt;
    ldi   temp1, 0b10101010&lt;br /&gt;
    rcall Schiebe&lt;br /&gt;
    rcall SchiebeOut&lt;br /&gt;
&lt;br /&gt;
loop:&lt;br /&gt;
    rjmp  loop&lt;br /&gt;
&lt;br /&gt;
;-----------------------------------------------------------------------------&lt;br /&gt;
;&lt;br /&gt;
; Die Ausgabe im Schieberegister in das Ausgaberegister übernehmen&lt;br /&gt;
;&lt;br /&gt;
; Dazu am RCK Eingang am Schieberegister einen 0-1-0 Puls erzeugen&lt;br /&gt;
;&lt;br /&gt;
SchiebeOut:&lt;br /&gt;
    sbi   SCHIEBE_PORT, RCK&lt;br /&gt;
    cbi   SCHIEBE_PORT, RCK&lt;br /&gt;
    ret&lt;br /&gt;
&lt;br /&gt;
;-----------------------------------------------------------------------------&lt;br /&gt;
;&lt;br /&gt;
; 8 Bits aus temp1 an das Schieberegister ausgeben&lt;br /&gt;
Schiebe:&lt;br /&gt;
    push  temp2&lt;br /&gt;
    ldi   temp2, 8             ; 8 Bits müssen ausgegeben werden&lt;br /&gt;
&lt;br /&gt;
Schiebe_1:&lt;br /&gt;
     ;&lt;br /&gt;
     ; jeweils das höchstwertige Bit aus temp1 ins Carry-Flag schieben&lt;br /&gt;
     ; Je nach Zustand des Carry-Flags wird die Datenleitung entsprechend&lt;br /&gt;
     ; gesetzt oder gelöscht&lt;br /&gt;
     ;&lt;br /&gt;
    rol  temp1                 ; MSB -&amp;gt; Carry&lt;br /&gt;
    brcs Schiebe_One           ; Carry gesetzt? -&amp;gt; weiter bei Schiebe_One&lt;br /&gt;
    cbi  SCHIEBE_PORT, SIN     ; Eine 0 ausgeben&lt;br /&gt;
    rjmp Schiebe_Clock         ; und Sprung zur Clock Puls Generierung&lt;br /&gt;
Schiebe_One:&lt;br /&gt;
    sbi  SCHIEBE_PORT, SIN     ; Eine 1 ausgeben&lt;br /&gt;
&lt;br /&gt;
     ;&lt;br /&gt;
     ; einen Impuls an SCK zur Übernahme des Bits nachschieben&lt;br /&gt;
     ;&lt;br /&gt;
Schiebe_Clock:&lt;br /&gt;
    sbi   SCHIEBE_PORT, SCK    ; Clock-Ausgang auf 1 ...&lt;br /&gt;
    cbi   SCHIEBE_PORT, SCK    ; und wieder zurück auf 0&lt;br /&gt;
&lt;br /&gt;
    dec   temp2                ; Anzahl der ausgegebenen Bits runterzählen&lt;br /&gt;
    brne  Schiebe_1            ; Wenn noch keine 8 Bits ausgegeben -&amp;gt; Schleife bilden&lt;br /&gt;
&lt;br /&gt;
    pop   temp2&lt;br /&gt;
    ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anm.1: Siehe [[Bitmanipulation]]&lt;br /&gt;
&lt;br /&gt;
=== Ansteuerung per SPI-Modul===&lt;br /&gt;
[[Bild:Mega8-595-SPI.png|framed|right|Anschluss eines 595 per SPI]]&lt;br /&gt;
Noch schneller geht die Ansteuerung des Schieberegisters mittels [[Serial_Peripheral_Interface | SPI]]-Modul, welches in fast allen AVRs vorhanden ist. Hier wird der Pin &#039;&#039;&#039;SCL&#039;&#039;&#039; nicht benutzt, da das praktisch keinen Sinn hat. Er muss also fest auf VCC gelegt werden. (Oder mit den Reset-Pin des AVRs, das mit einer RC Schaltung versehen ist, verbunden werden. Damit erreicht man einen definierten Anfangszustand des Schieberegisters.) Die Pins für &#039;&#039;&#039;SCK&#039;&#039;&#039; und &#039;&#039;&#039;SIN&#039;&#039;&#039; sind durch den jeweiligen AVR fest vorgegeben. &#039;&#039;&#039;SCK&#039;&#039;&#039; vom 74xxx595 wird mit &#039;&#039;&#039;SCK&#039;&#039;&#039; vom AVR verbunden sowie &#039;&#039;&#039;SIN&#039;&#039;&#039; mit &#039;&#039;&#039;MOSI&#039;&#039;&#039; (&#039;&#039;&#039;M&#039;&#039;&#039;aster &#039;&#039;&#039;O&#039;&#039;&#039;ut, &#039;&#039;&#039;S&#039;&#039;&#039;lave &#039;&#039;&#039;I&#039;&#039;&#039;n). &#039;&#039;&#039;MISO&#039;&#039;&#039; (&#039;&#039;&#039;M&#039;&#039;&#039;aster &#039;&#039;&#039;I&#039;&#039;&#039;n, &#039;&#039;&#039;S&#039;&#039;&#039;lave &#039;&#039;&#039;O&#039;&#039;&#039;ut) ist hier ungenutzt. Es kann NICHT für &#039;&#039;&#039;RCK&#039;&#039;&#039; verwendet werden, da es im SPI-Master Modus immer ein Eingang ist! Es kann aber als allgemeiner Eingang oder für 74HC165 ([[#Porterweiterung_für_Eingänge|siehe unten]]) verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Der AVR-Pin &#039;&#039;&#039;SS&#039;&#039;&#039; wird sinnvollerweise als &#039;&#039;&#039;RCK&#039;&#039;&#039; benutzt, da er sowieso als Ausgang geschaltet werden &#039;&#039;&#039;muss&#039;&#039;&#039;, sonst gibt es böse Überaschungen (siehe Datenblatt „SS Pin Functionality“). Dieser sollte mit einem Widerstand von 10 kΩ nach Masse, während der Start- und Initialisierungsphase, auf L-Potential  gehalten werden. `(&#039;&#039;&#039;SS&#039;&#039;&#039; ist während dieser Zeit noch im Tri-State und es könnte passieren, dass die zufälligen Daten des Schieberegisters in das Ausgangslatch übernommen werden.)&lt;br /&gt;
&lt;br /&gt;
Bei den kleineren ATtinys mit &#039;&#039;&#039;USI&#039;&#039;&#039; (Universal Serial Interface) darf man sich von den Pin-Bezeichnungen MOSI und MISO nicht [http://de.wikipedia.org/wiki/Bockshorn_(Redensart) ins Bockshorn jagen] lassen: Hier ist MISO der Ausgang(!) &#039;&#039;&#039;DO&#039;&#039;&#039; und MOSI der Eingang(!) &#039;&#039;&#039;DI&#039;&#039;&#039;. Die Pinbezeichnungen MOSI und MISO sind nur zum Programmieren und irreführend, weil ohnehin nur für den Slave-Betrieb.&lt;br /&gt;
&lt;br /&gt;
Je nach Bedarf kann man die Taktrate des SPI-Moduls zwischen 1/2 ... 1/128 des CPU-Taktes wählen. Es spricht kaum etwas dagegen mit maximaler Geschwindigkeit zu arbeiten. Die AVRs können zur Zeit mit maximal 20 MHz getaktet werden, d.h. es sind maximal 10 MHz SPI-Takt möglich. Das ist für ein 74xxx595 kein Problem. Die Übertragung von 8 Bit dauert dann gerade mal 800 ns!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
.include &amp;quot;m8def.inc&amp;quot;&lt;br /&gt;
&lt;br /&gt;
.def temp1 = r16&lt;br /&gt;
&lt;br /&gt;
; Die Definitionen müssen an den jeweiligen AVR angepasst werden&lt;br /&gt;
&lt;br /&gt;
.equ SCHIEBE_DDR  = DDRB&lt;br /&gt;
.equ SCHIEBE_PORT = PORTB&lt;br /&gt;
.equ RCK          = PB2     ; SS&lt;br /&gt;
.equ SCK          = PB5     ; SCK&lt;br /&gt;
.equ SIN          = PB3     ; MOSI&lt;br /&gt;
&lt;br /&gt;
    ldi   temp1, LOW(RAMEND)     ; Stackpointer initialisieren&lt;br /&gt;
    out   SPL, temp1&lt;br /&gt;
    ldi   temp1, HIGH(RAMEND)&lt;br /&gt;
    out   SPH, temp1&lt;br /&gt;
;&lt;br /&gt;
; SCK, MOSI, SS als Ausgänge schalten&lt;br /&gt;
;&lt;br /&gt;
    in    temp1, SCHIEBE_DDR&lt;br /&gt;
    ori   temp1, (1&amp;lt;&amp;lt;SIN) | (1&amp;lt;&amp;lt;SCK) | (1&amp;lt;&amp;lt;RCK) &lt;br /&gt;
    out   SCHIEBE_DDR,temp1     &lt;br /&gt;
;&lt;br /&gt;
; SPI Modul konfigurieren&lt;br /&gt;
;&lt;br /&gt;
    ldi   temp1, (1&amp;lt;&amp;lt;SPE) | (1&amp;lt;&amp;lt;MSTR)&lt;br /&gt;
    out   SPCR, temp1           ; keine Interrupts, MSB first, Master&lt;br /&gt;
                                ; CPOL = 0, CPHA =0&lt;br /&gt;
                                ; SCK Takt = 1/2 XTAL&lt;br /&gt;
    ldi   temp1, (1&amp;lt;&amp;lt;SPI2X)&lt;br /&gt;
    out   SPSR, temp1           ; double speed aktivieren&lt;br /&gt;
    out   SPDR, temp1           ; Dummy Daten, um SPIF zu setzen&lt;br /&gt;
;&lt;br /&gt;
; Ein Datenbyte ausgeben&lt;br /&gt;
;&lt;br /&gt;
    ldi   temp1, 0b10101010&lt;br /&gt;
    rcall Schiebe               ; Daten schieben&lt;br /&gt;
    rcall SchiebeOut            ; Daten in Ausgangsregister übernehmen&lt;br /&gt;
&lt;br /&gt;
loop:&lt;br /&gt;
    rjmp  loop&lt;br /&gt;
&lt;br /&gt;
;-----------------------------------------------------------------------------&lt;br /&gt;
;&lt;br /&gt;
; Die Daten im Schieberegister in das Ausgaberegister übernehmen&lt;br /&gt;
;&lt;br /&gt;
; Dazu am RCK Eingang am Schieberegister einen 0-1-0 Puls erzeugen&lt;br /&gt;
;&lt;br /&gt;
SchiebeOut:&lt;br /&gt;
    sbis  SPSR, SPIF            ; prüfe ob eine alte Übertragung beendet ist&lt;br /&gt;
    rjmp  SchiebeOut&lt;br /&gt;
    sbi   SCHIEBE_PORT, RCK&lt;br /&gt;
    cbi   SCHIEBE_PORT, RCK&lt;br /&gt;
    ret&lt;br /&gt;
&lt;br /&gt;
;-----------------------------------------------------------------------------&lt;br /&gt;
;&lt;br /&gt;
; 8 Bits aus temp1 an das Schieberegister ausgeben&lt;br /&gt;
;&lt;br /&gt;
Schiebe:&lt;br /&gt;
    sbis    SPSR, SPIF      ; prüfe ob eine alte Übertragung beendet ist&lt;br /&gt;
    rjmp    Schiebe&lt;br /&gt;
    out     SPDR, temp1     ; Daten ins SPI Modul schreiben, Übertragung beginnt automatisch&lt;br /&gt;
    ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Kaskadieren von Schieberegistern===&lt;br /&gt;
&lt;br /&gt;
[[Bild:Mega8-595-2.gif|framed|right|Kaskadieren mehrerer 595]]&lt;br /&gt;
Um ein Schieberegister anzuschließen genügen also im einfachsten Fall 4 freie Prozessorpins (3 wenn &#039;&#039;&#039;SCL&#039;&#039;&#039; nicht benutzt wird) um weitere 8 Ausgangsleitungen zu bekommen. Genügen diese 8 Leitungen nicht, so kann ohne Probleme ein weiteres Schieberegister an das bereits vorhandene angeschlossen werden.&lt;br /&gt;
&lt;br /&gt;
Das nächste Schieberegister wird mit seinem Dateneingang &#039;&#039;&#039;SER&#039;&#039;&#039; einfach an den dafür vorgesehenen Ausgang &#039;&#039;&#039;QH*&#039;&#039;&#039; des vorhergehenden Schieberegisters angeschlossen. Die Steuerleitungen &#039;&#039;&#039;SCK&#039;&#039;&#039;, &#039;&#039;&#039;RCK&#039;&#039;&#039; und &#039;&#039;&#039;SCL&#039;&#039;&#039; werden parallel zu den bereits vorhandenen geschaltet. Konzeptionell erhält man dadurch ein Schieberegister mit einer Breite von 16 Bit. Werden weiter Bausteine in derselben Manier angeschlossen, so erhöht sich die Anzahl der zur Verfügung stehenden Ausgabeleitungen mit jedem Baustein um 8 ohne dass sich die Anzahl der am Prozessor notwendigen Ausgabepins erhöhen würde. Um diese weiteren Register zu nutzen, muss man in der reinen Softwarelösung nur mehrfach die Funktion &#039;&#039;&#039;Schiebe&#039;&#039;&#039; aufrufen, um alle Daten auszugeben. Am Ende werden dann mit &#039;&#039;&#039;SchiebeOut&#039;&#039;&#039; die Daten in die Ausgangsregister übernommen.&lt;br /&gt;
&lt;br /&gt;
Bei der SPI Lösung werden ebenfalls ganz einfach mehrere Bytes über SPI ausgegeben, ehe dann mittels &#039;&#039;&#039;RCK&#039;&#039;&#039; die in die Schieberegisterkette eingetakteten Bits in das Ausgangsregister übernommen werden.&lt;br /&gt;
Um das Ganze ein wenig zu vereinfachen, soll hier eine Funktion zur Ansteuerung mehrerer kaskadierter Schieberegister über das SPI-Modul gezeigt werden. Dabei wird die Ausgabe mehrerer Bytes über eine Schleife realisiert, mehrfache Aufrufe der Funktion sind damit nicht nötig. Statt dessen übergibt man einen Zeiger auf einen Datenblock im RAM sowie die Anzahl der zu übertragenden Bytes. Außerdem wird die Datenübernahme durch &#039;&#039;&#039;RCK&#039;&#039;&#039; standardkonform integriert. Denn bei nahezu allen ICs mit SPI wird ein sog. CS-Pin verwendet (&#039;&#039;&#039;C&#039;&#039;&#039;hip &#039;&#039;&#039;S&#039;&#039;&#039;elect) Dieser Pin ist meist LOW aktiv, d.h. wenn er HIGH ist, ignoriert der IC alle Signale an &#039;&#039;&#039;SCK&#039;&#039;&#039; und &#039;&#039;&#039;MOSI&#039;&#039;&#039; und gibt keine Daten an MISO aus. Ist er LOW, dann ist der IC aktiv und funktioniert normal. Bei der steigenden Flanke an &#039;&#039;&#039;CS&#039;&#039;&#039; werden die Daten ins Ausgangsregister übernommen. Die Funktion ist sehr schnell, da die Zeit während der die Übertragung eines Bytes läuft, dazu genutzt wird, den Schleifenzähler zu verringern und zu prüfen sowie neue Sendedaten zu laden. Zwischen den einzelnen Bytes gibt es somit nur eine Pause von max. 6 Systemtakten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
.include &amp;quot;m8def.inc&amp;quot;&lt;br /&gt;
.def temp1 = r16&lt;br /&gt;
&lt;br /&gt;
; Die Definitionen müssen an den jeweiligen AVR angepasst werden&lt;br /&gt;
&lt;br /&gt;
.equ SCHIEBE_DDR  = DDRB&lt;br /&gt;
.equ SCHIEBE_PORT = PORTB&lt;br /&gt;
.equ RCK          = PB2     ; SS&lt;br /&gt;
.equ SCK          = PB5     ; SCK&lt;br /&gt;
.equ SIN          = PB3     ; MOSI&lt;br /&gt;
&lt;br /&gt;
;-----------------------------------------------------------------------------&lt;br /&gt;
;&lt;br /&gt;
; Datensegment im RAM&lt;br /&gt;
;&lt;br /&gt;
;-----------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
.dseg&lt;br /&gt;
.org $60&lt;br /&gt;
Schiebedaten:       .byte 2&lt;br /&gt;
&lt;br /&gt;
;-----------------------------------------------------------------------------&lt;br /&gt;
;&lt;br /&gt;
; Programmsegment im FLASH&lt;br /&gt;
;&lt;br /&gt;
;-----------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
.cseg&lt;br /&gt;
    ldi     temp1, LOW(RAMEND)     ; Stackpointer initialisieren&lt;br /&gt;
    out     SPL, temp1&lt;br /&gt;
    ldi     temp1, HIGH(RAMEND)&lt;br /&gt;
    out     SPH, temp1&lt;br /&gt;
;&lt;br /&gt;
; SCK, MOSI, SS als Ausgänge schalten&lt;br /&gt;
;&lt;br /&gt;
    in      temp1,SCHIEBE_DDR&lt;br /&gt;
    ori     temp1,(1&amp;lt;&amp;lt;SIN) | (1&amp;lt;&amp;lt;SCK) | (1&amp;lt;&amp;lt;RCK) &lt;br /&gt;
    out     SCHIEBE_DDR,temp1&lt;br /&gt;
&lt;br /&gt;
    sbi     SCHIEBE_PORT, RCK   ; Slave select inaktiv&lt;br /&gt;
;&lt;br /&gt;
; SPI Modul konfigurieren&lt;br /&gt;
;&lt;br /&gt;
    ldi     temp1, 0b01010000&lt;br /&gt;
    out     SPCR, temp1         ; keine Interrupts, MSB first, Master&lt;br /&gt;
                                ; CPOL = 0, CPHA =0&lt;br /&gt;
                                ; SCK Takt = 1/2 XTAL&lt;br /&gt;
    ldi     r16,1&lt;br /&gt;
    out     SPSR,r16            ; Double Speed&lt;br /&gt;
    out     SPDR,temp1          ; Dummy Daten, um SPIF zu setzen&lt;br /&gt;
&lt;br /&gt;
; den Datenblock mit Daten füllen&lt;br /&gt;
&lt;br /&gt;
    ldi     temp1,$F0&lt;br /&gt;
    sts     Schiebedaten,temp1&lt;br /&gt;
    ldi     temp1,$55&lt;br /&gt;
    sts     Schiebedaten+1,temp1&lt;br /&gt;
&lt;br /&gt;
loop:&lt;br /&gt;
; den Datenblock ausgeben&lt;br /&gt;
&lt;br /&gt;
    ldi     r16,2&lt;br /&gt;
    ldi     zl,low(Schiebedaten)&lt;br /&gt;
    ldi     zh, high(Schiebedaten)&lt;br /&gt;
    rcall   Schiebe_alle                    ; Daten ausgeben&lt;br /&gt;
&lt;br /&gt;
    rjmp  loop                              ; nur zur Simulation&lt;br /&gt;
&lt;br /&gt;
;-----------------------------------------------------------------------------&lt;br /&gt;
;&lt;br /&gt;
; N Bytes an das Schieberegister ausgeben und in das Ausgaberegister übernehmen&lt;br /&gt;
;&lt;br /&gt;
; r16: Anzahl der Datenbytes&lt;br /&gt;
; Z: Zeiger auf Datenblock im RAM&lt;br /&gt;
;&lt;br /&gt;
;-----------------------------------------------------------------------------&lt;br /&gt;
Schiebe_alle:&lt;br /&gt;
    cbi     SCHIEBE_PORT, RCK   ; RCK LOW, SPI Standardverfahren&lt;br /&gt;
    push    r17&lt;br /&gt;
&lt;br /&gt;
Schiebe_alle_2:&lt;br /&gt;
    ld      r17,Z+&lt;br /&gt;
Schiebe_alle_3:&lt;br /&gt;
    sbis    SPSR,SPIF           ; prüfe ob eine alte Übertragung beendet ist&lt;br /&gt;
    rjmp    Schiebe_alle_3&lt;br /&gt;
    out     SPDR,r17            ; Daten ins SPI Modul schreiben, Übertragung beginnt automatisch&lt;br /&gt;
    dec     r16&lt;br /&gt;
    brne    Schiebe_alle_2&lt;br /&gt;
&lt;br /&gt;
Schiebe_alle_4:&lt;br /&gt;
    sbis    SPSR,SPIF           ; prüfe ob die letzte Übertragung beendet ist&lt;br /&gt;
    rjmp    Schiebe_alle_4&lt;br /&gt;
&lt;br /&gt;
    pop     r17&lt;br /&gt;
    sbi     SCHIEBE_PORT, RCK   ; RCK inaktiv, Datenübernahme&lt;br /&gt;
    ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der Nachteil von Schieberegistern ist allerdings, dass sich die Zeit zum Setzen aller Ausgabeleitungen mit jedem weiteren Baustein immer weiter erhöht. Dies deshalb, da ja die einzelnen Bits im Gänsemarsch durch alle Bausteine geschleust werden müssen und für jeden einzelnen Schiebevorgang etwas Zeit notwendig ist. Ein Ausweg ist die Verwendung des SPI-Moduls, welches schneller arbeitet als die reine Softwarelösung. Ist noch mehr Geschwindigkeit gefragt, so sind mehr Port-Pins nötig. Kann ein kompletter Port mit 8 Pins für die Daten genutzt werden, sowie ein paar weitere Steuerleitungen, so können ein oder mehrere 74xxx573 eine Alternative sein, um jeweils ein vollständiges Byte auszugeben. Natürlich kann der 74xxx573 (oder ein ähnliches Schieberegister) auch mit dem 74xxx595 zusammen eingesetzt werden, beispielsweise in dem über das Schieberegister verschiedene 74xxx595 nacheinander aktiviert werden. Weitere Tips und Tricks dazu gibt es vielleicht in einem weiteren Tutorial...&lt;br /&gt;
&lt;br /&gt;
=== Acht LEDs mit je 20mA pro Schieberegister ===&lt;br /&gt;
&lt;br /&gt;
Will man nun acht [[LED]]s mit dem Schieberegister ansteuern, kann man diese direkt über Vorwiderstände anschließen. Doch ein genauer Blick ins Datenblatt verrät, dass der 74xx595 nur maximal 70mA über VCC bzw. GND ableiten kann. Und wenn man den IC nicht gnadenlos quälen, und damit die Lebensdauer und Zuverlässigkeit drastisch reduzieren will, gibt es nur zwei Auswege.&lt;br /&gt;
&lt;br /&gt;
* Den Strom pro LED auf 70/8 = 8,75mA begrenzen; Das reicht meistens aus um die LEDs schön leuchten zu lassen, vor allem bei low-current und ultrahellen LEDs&lt;br /&gt;
* Wenn doch 20 mA pro LED gebraucht werden, kann man die folgende Trickschaltung anwenden.&lt;br /&gt;
&lt;br /&gt;
[[bild:8x20mA_LED_mit_74xx595.png|framed|center|Mehrere LED anschließen]]&lt;br /&gt;
&lt;br /&gt;
Der Trick besteht darin, dass 4 LEDs ihren Strom über das Schieberegister von VCC beziehen (HIGH aktiv) während die anderen vier ihren Strom über GND leiten (LOW aktiv). Damit bleiben ganz offiziell für jede LED 70/4 = 17,5mA. Um die Handhabung in der Software zu vereinfachen muss nur vor der Ausgabe der Daten das jeweilige Byte mit 0x0F XOR verknüpft werden, bevor es in das Schieberegister getaktet wird. Dadurch werden die LOW-aktiven LEDs richtig angesteuert und die Datenhandhabung in der Software muss nur mit HIGH-aktiven rechnen. Außerdem wird der G Eingang verwendet, um die Helligkeit aller LEDs per [[PWM]] zu steuern. Beachtet werden muss, dass die PWM im invertierten Modus generiert werden muss, da der Eingang G LOW aktiv ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;B&amp;gt;Achtung!&amp;lt;/B&amp;gt; Die Widerstände sind auf blaue LEDs mit 3,3V Flussspannung ausgelegt. Bei roten, gelben und grünen [[LED]]s ist die Flussspannung geringer und dementsprechend muss der Vorwiderstand größer sein.&lt;br /&gt;
&lt;br /&gt;
Wenn 20mA immer noch nicht reichen sollten oder z.B. RGB-LEDs mit gemeinsamer Anode angesteuert werden müssen, dann hilft nur ein stärkerer IC. Der Klassiker ist der TPIC6A595 von TI, er kombiniert ein Schieberegister mit MOSFETs, sodass hier 250mA pro Kanal zur Verfügung stehen.&lt;br /&gt;
&lt;br /&gt;
=== Achtung beim Startup! ===&lt;br /&gt;
&lt;br /&gt;
Die Ausgänge des &#039;595 führen beim Einschalten undefinierte, also zufällige Pegel! Und der Eingang ¬SCL löscht nur die Schieberegister (= unnütz, um mit ¬RESET zu verbinden). Sind deshalb &#039;&#039;definierte&#039;&#039; Pegel beim Einschalten unerlässlich, muss man ¬OE beschalten:&lt;br /&gt;
* Entweder mit einem weiteren Mikrocontroller-Ausgang (der mit einem externen Pull-Up-Widerstand zu beschalten ist und nach dem ersten Durchschieben dauerhaft auf LOW gelegt wird)&lt;br /&gt;
* Oder mit einer RC(D)-Kombination, die die Ausgänge für eine gewisse Zeit auf Tristate hält. Spart ein Mikrocontroller-Pin.&lt;br /&gt;
Obendrein sind, wie sonst am Mikrocontroller, die betreffenden Ausgänge mit externen Pull-Up- oder Pull-Down-Widerständen zu beschalten.&lt;br /&gt;
&lt;br /&gt;
== Porterweiterung für Eingänge ==&lt;br /&gt;
&lt;br /&gt;
Ein naher Verwandter des 74xx595 ist der [[74xx | 74xx165]], er ist quasi das Gegenstück. Hierbei handet es sich um ein &#039;&#039;8-bit parallel-in/serial-out shift register&#039;&#039;. Auf Deutsch: Ein 8 Bit Schieberegister mit parallelem Eingang und seriellem Ausgang. Damit kann man eine große Anzahl Eingänge sehr einfach und preiswert zu seinem Mikrocontroller hinzufügen.&lt;br /&gt;
&lt;br /&gt;
=== Aufbau ===&lt;br /&gt;
&lt;br /&gt;
[[bild:74xx165-1.png|framed|center|Pinbelegung eines 165]]&lt;br /&gt;
&lt;br /&gt;
Der Aufbau ist sehr ähnlich zum 74xx595. Allerdings gibt es kein Register zum Zwischenspeichern. Das ist auch gar nicht nötig, da der IC ja einen parallelen Eingang hat. Der muss nicht zwischengespeichert werden. Es gibt hier also wirklich nur das Schieberegister. Dieses wird über den Eingang PL mit den parallelen Daten geladen. Dann können die Daten seriell mit Takten an CLK aus dem Ausgang Q7 geschoben werden.&lt;br /&gt;
&lt;br /&gt;
=== Funktionsweise ===&lt;br /&gt;
&lt;br /&gt;
DS ist der serielle Dateneingang, welcher im Falle von kaskadierten Schieberegistern mit dem Ausgang des vorhergehenden ICs verbunden wird.&lt;br /&gt;
&lt;br /&gt;
D0..D7 sind die parallelen Dateneingänge.&lt;br /&gt;
&lt;br /&gt;
Mittels des Eingangs PL (&#039;&#039;&#039;P&#039;&#039;&#039;arallel &#039;&#039;&#039;L&#039;&#039;&#039;oad) werden die Daten vom parallelen Eingang in das Schieberegister übernommen, wenn dieses Signal LOW ist. Hier muss man aber ein klein wenig aufpassen. Auf Grund der Schaltungsstruktur ist der Eingang PL mit dem Takt CLK verknüpft (obwohl es dafür keinen logischen Grund gibt :-0). Damit es nicht zu unerwünschten Fehlschaltungen kommt, muss der Takt CLK während des Ladens auf HIGH liegen. Wird PL wieder auf HIGH gesetzt, sind die Daten geladen. Das erste Bit liegt direkt am Ausgang Q7 an. Die restlichen Bits können nach und nach durch das Register geschoben werden.&lt;br /&gt;
&lt;br /&gt;
Der Eingang CE (&#039;&#039;&#039;C&#039;&#039;&#039;lock &#039;&#039;&#039;E&#039;&#039;&#039;nable) steuert, ob das Schieberegister auf den Takt CLK reagieren soll oder nicht. Ist CE gleich HIGH werden alle Takte an CLK ignoriert. Bei LOW werden mit jeder positiven Flanke die Daten um eine Stufe weiter geschoben.&lt;br /&gt;
&lt;br /&gt;
Wird am Eingang CLK eine LOW-HIGH Flanke angelegt und ist dabei CE auf LOW, dann werden die Daten im Schieberegister um eine Position weiter geschoben: DS-&amp;gt;Q0, Q0-&amp;gt;Q1, Q1-&amp;gt;Q2, Q2-&amp;gt;Q3, Q3-&amp;gt;Q4, Q4-&amp;gt;Q5, Q5-&amp;gt;Q6, Q6-&amp;gt;Q7. Q0..Q6 sind interne Signale, siehe [http://www.nxp.com/acrobat/datasheets/74HC_HCT165_CNV_2.pdf Datenblatt].&lt;br /&gt;
&lt;br /&gt;
Q7 ist der serielle Ausgang des Schieberegisters. Dort Werden Takt für Takt die Daten ausgegeben. Hier wird normalerweise der Eingang des Mikrocontrollers oder der Eingang des nächsten Schieberegisters angeschlossen.&lt;br /&gt;
&lt;br /&gt;
Q7\ ist der invertierte Ausgang des Schieberegisters. Er wird meist nicht verwendet.&lt;br /&gt;
&lt;br /&gt;
=== Schaltung ===&lt;br /&gt;
&lt;br /&gt;
Um nun beispielsweise zwei Schieberegister zu kaskadieren um 16 Eingangspins zu erhalten sollte man folgende Verschaltung vornehmen. Beachten sollte man dabei, dass&lt;br /&gt;
&lt;br /&gt;
* der serielle Eingang DS des ersten Schieberegisters (hier IC1) auf einen festen Pegel gelegt wird (LOW oder HIGH).&lt;br /&gt;
* der serielle Datenausgang bei der Benutzung des SPI-Moduls an MISO und nicht an MOSI angeschlossen wird.&lt;br /&gt;
&lt;br /&gt;
[[bild:74xx165-2.png|framed|center|Anschluss eines 165]]&lt;br /&gt;
&lt;br /&gt;
Nachfolgend werden zwei Beispiele gezeigt, welche die Ansteuerung nach bekanntem Muster übernehmen. Nur dass hier eben Daten gelesen anstatt geschrieben werden. Zu beachten ist, dass hier ein anderer Modus der SPI-Ansteuerung verwendet werden muss, weil der Baustein das nötig macht. Das muss beachtet werden, wenn auch Schieberegister für Ausgänge verwendet werden. Dabei muss jeweils vor dem Zugriff auf die Ein- oder Ausgangsregister der Modus des Taktes (CPOL) umgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
=== Ansteuerung per Software ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
; Porterweiterung für Eingänge mit Schieberegister 74xx165&lt;br /&gt;
; Ansteuerung per Software&lt;br /&gt;
&lt;br /&gt;
.include &amp;quot;m8def.inc&amp;quot;&lt;br /&gt;
&lt;br /&gt;
.def temp1 = r16&lt;br /&gt;
.def temp2 = r17&lt;br /&gt;
.def temp3 = r18&lt;br /&gt;
&lt;br /&gt;
; Pins anpassen, frei wählbar&lt;br /&gt;
&lt;br /&gt;
.equ SCHIEBE_DDR  = DDRB&lt;br /&gt;
.equ SCHIEBE_PORT = PORTB&lt;br /&gt;
.equ SCHIEBE_PIN  = PINB&lt;br /&gt;
.equ CLK          = PB3&lt;br /&gt;
.equ PL           = PB1&lt;br /&gt;
.equ DIN          = PB2&lt;br /&gt;
&lt;br /&gt;
;-----------------------------------------------------------------------------&lt;br /&gt;
;&lt;br /&gt;
; Datensegment im RAM&lt;br /&gt;
;&lt;br /&gt;
;-----------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
.dseg&lt;br /&gt;
.org 0x60&lt;br /&gt;
Daten:      .byte 2             ; Speicherplatz für Eingangsdaten&lt;br /&gt;
&lt;br /&gt;
;-----------------------------------------------------------------------------&lt;br /&gt;
;&lt;br /&gt;
; Programmsegment im FLASH&lt;br /&gt;
;&lt;br /&gt;
;-----------------------------------------------------------------------------&lt;br /&gt;
.cseg&lt;br /&gt;
    ldi     temp1, LOW(RAMEND)  ; Stackpointer initialisieren&lt;br /&gt;
    out     SPL, temp1&lt;br /&gt;
    ldi     temp1, HIGH(RAMEND)&lt;br /&gt;
    out     SPH, temp1&lt;br /&gt;
&lt;br /&gt;
; CLK und PL als Ausgänge schalten&lt;br /&gt;
&lt;br /&gt;
    ldi     temp1, (1&amp;lt;&amp;lt;clk) | (1&amp;lt;&amp;lt;pl)&lt;br /&gt;
    out     SCHIEBE_DDR, temp1&lt;br /&gt;
&lt;br /&gt;
    sbi     schiebe_port, clk   ; Takt im Ruhezustand immer auf 1&lt;br /&gt;
                                ; komische Schaltung im 74xx165&lt;br /&gt;
&lt;br /&gt;
; Zwei Bytes einlesen&lt;br /&gt;
&lt;br /&gt;
    ldi     ZL,low(Daten)&lt;br /&gt;
    ldi     ZH,high(Daten)&lt;br /&gt;
    ldi     temp1,2&lt;br /&gt;
    rcall   schiebe_eingang&lt;br /&gt;
&lt;br /&gt;
loop:&lt;br /&gt;
    rjmp    loop&lt;br /&gt;
&lt;br /&gt;
;-----------------------------------------------------------------------------&lt;br /&gt;
;&lt;br /&gt;
; N Bytes seriell einlesen&lt;br /&gt;
;&lt;br /&gt;
; temp1 : N, Anzahl der Bytes&lt;br /&gt;
; Z     : Zeiger auf einen Datenbereich im SRAM&lt;br /&gt;
;-----------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
schiebe_eingang:&lt;br /&gt;
    push    temp2               ; Register sichern&lt;br /&gt;
    push    temp3&lt;br /&gt;
&lt;br /&gt;
    cbi     schiebe_port, pl    ; Daten parallel laden&lt;br /&gt;
    sbi     schiebe_port, pl&lt;br /&gt;
&lt;br /&gt;
schiebe_eingang_byte_schleife:&lt;br /&gt;
&lt;br /&gt;
    ldi     temp3, 8            ; Bitzähler&lt;br /&gt;
schiebe_eingang_bit_schleife:&lt;br /&gt;
    lsl     temp2               ; Daten weiterschieben&lt;br /&gt;
&lt;br /&gt;
; das IO Bit Din in das niederwerigste Bit von temp2 kopieren&lt;br /&gt;
&lt;br /&gt;
    sbic    schiebe_pin, din    ; wenn Null, nächsten Befehl überspringen&lt;br /&gt;
    ori     temp2,1             ; nein, Bit setzen&lt;br /&gt;
&lt;br /&gt;
    cbi     SCHIEBE_PORT, CLK   ; Taktausgang auf 0&lt;br /&gt;
    sbi     SCHIEBE_PORT, CLK   ; und wieder zurück auf 1, dabei Daten schieben &lt;br /&gt;
&lt;br /&gt;
    dec     temp3               ; Bitzähler um eins verringern&lt;br /&gt;
    brne    schiebe_eingang_bit_schleife ;wenn noch keine 8 Bits ausgegeben, nochmal&lt;br /&gt;
&lt;br /&gt;
    st      z+,temp2            ; Datenbyte speichern&lt;br /&gt;
    dec     temp1               ; Anzahl Bytes um eins verringern&lt;br /&gt;
    brne    schiebe_eingang_byte_schleife   ; wenn noch mehr Bytes zu lesen sind&lt;br /&gt;
&lt;br /&gt;
    pop     temp3&lt;br /&gt;
    pop     temp2&lt;br /&gt;
    ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ansteuerung per SPI-Modul ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
; Porterweiterung für Eingänge mit Schieberegister 74xx165&lt;br /&gt;
; Ansteuerung per SPI-Modul&lt;br /&gt;
&lt;br /&gt;
.include &amp;quot;m8def.inc&amp;quot;&lt;br /&gt;
&lt;br /&gt;
.def temp1 = r16&lt;br /&gt;
.def temp2 = r17&lt;br /&gt;
.def temp3 = r18&lt;br /&gt;
&lt;br /&gt;
; Pins anpassen&lt;br /&gt;
; diese müssen mit den SPI-Pins des AVR Typs übereinstimmen!&lt;br /&gt;
&lt;br /&gt;
.equ SCHIEBE_DDR  = DDRB&lt;br /&gt;
.equ SCHIEBE_PORT = PORTB&lt;br /&gt;
.equ PL           = PB2         ; SS&lt;br /&gt;
.equ CLK          = PB5         ; SCK&lt;br /&gt;
.equ DIN          = PB4         ; MISO&lt;br /&gt;
&lt;br /&gt;
;-----------------------------------------------------------------------------&lt;br /&gt;
;&lt;br /&gt;
; Datensegment im RAM&lt;br /&gt;
;&lt;br /&gt;
;-----------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
.dseg&lt;br /&gt;
.org 0x60&lt;br /&gt;
Daten:      .byte 2             ; Speicherplatz für Eingangsdaten&lt;br /&gt;
&lt;br /&gt;
;-----------------------------------------------------------------------------&lt;br /&gt;
;&lt;br /&gt;
; Programmsegment im FLASH&lt;br /&gt;
;&lt;br /&gt;
;-----------------------------------------------------------------------------&lt;br /&gt;
.cseg&lt;br /&gt;
    ldi     temp1, LOW(RAMEND)  ; Stackpointer initialisieren&lt;br /&gt;
    out     SPL, temp1&lt;br /&gt;
    ldi     temp1, HIGH(RAMEND)&lt;br /&gt;
    out     SPH, temp1&lt;br /&gt;
&lt;br /&gt;
; CLK und PL als Ausgänge schalten&lt;br /&gt;
&lt;br /&gt;
    ldi     temp1,(1&amp;lt;&amp;lt;CLK) | (1&amp;lt;&amp;lt;PL)&lt;br /&gt;
    out     SCHIEBE_DDR,temp1     &lt;br /&gt;
;&lt;br /&gt;
; SPI Modul konfigurieren&lt;br /&gt;
;&lt;br /&gt;
    ldi     temp1, (1&amp;lt;&amp;lt;SPE) | (1&amp;lt;&amp;lt;MSTR) | (1&amp;lt;&amp;lt;CPOL)&lt;br /&gt;
    out     SPCR, temp1         ; keine Interrupts, MSB first, Master&lt;br /&gt;
                                ; CPOL = 1, CPHA =0&lt;br /&gt;
                                ; SCK Takt = 1/2 XTAL&lt;br /&gt;
    ldi     temp1, (1&amp;lt;&amp;lt;SPI2X)&lt;br /&gt;
    out     SPSR,temp1          ; double speed aktivieren&lt;br /&gt;
    out     SPDR,temp1          ; Dummy Daten, um SPIF zu setzen&lt;br /&gt;
&lt;br /&gt;
; Zwei Bytes einlesen&lt;br /&gt;
&lt;br /&gt;
    ldi     ZL,low(Daten)&lt;br /&gt;
    ldi     ZH,high(Daten)&lt;br /&gt;
    ldi     temp1,2&lt;br /&gt;
    rcall   schiebe_eingang&lt;br /&gt;
&lt;br /&gt;
loop:&lt;br /&gt;
    rjmp    loop&lt;br /&gt;
&lt;br /&gt;
;-----------------------------------------------------------------------------&lt;br /&gt;
;&lt;br /&gt;
; N Bytes seriell einlesen&lt;br /&gt;
;&lt;br /&gt;
; temp1 : N, Anzahl der Bytes&lt;br /&gt;
; Z     : Zeiger auf einen Datenbereich im SRAM&lt;br /&gt;
;-----------------------------------------------------------------------------&lt;br /&gt;
schiebe_eingang:&lt;br /&gt;
    push    temp2               ; Register sichern&lt;br /&gt;
&lt;br /&gt;
    ; CLK ist im Ruhezustand schon auf HIGH, CPOL=1&lt;br /&gt;
&lt;br /&gt;
dummyende:&lt;br /&gt;
    sbis    SPSR,7              ; prüfe ob Dummy Übertragung beendet ist, sonst&lt;br /&gt;
    rjmp    dummyende           ; kann es bei langsameren Übertragungsraten zu&lt;br /&gt;
	                        ; Überschneidungen kommen.&lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
    cbi     schiebe_port, pl    ; Daten parallel laden&lt;br /&gt;
    sbi     schiebe_port, pl&lt;br /&gt;
&lt;br /&gt;
schiebe_eingang_1:&lt;br /&gt;
    sbis    SPSR,7              ; prüfe ob eine alte Übertragung beendet ist&lt;br /&gt;
    rjmp    schiebe_eingang_1&lt;br /&gt;
&lt;br /&gt;
schiebe_eingang_byte_schleife:&lt;br /&gt;
    out     SPDR,temp1          ; beliebige Daten ins SPI Modul schreiben&lt;br /&gt;
                                ; um die Übertragung zu starten&lt;br /&gt;
schiebe_eingang_2:&lt;br /&gt;
    sbis    SPSR,7              ; auf das Ende der Übertragung warten&lt;br /&gt;
    rjmp    schiebe_eingang_2&lt;br /&gt;
&lt;br /&gt;
    in      temp2, spdr         ; Daten lesen&lt;br /&gt;
    st      z+,temp2            ; Datenbyte speichern&lt;br /&gt;
    dec     temp1               ; Anzahl Bytes um eins verringern&lt;br /&gt;
    brne    schiebe_eingang_byte_schleife   ; wenn noch mehr Bytes zu lesen sind&lt;br /&gt;
&lt;br /&gt;
    pop     temp2&lt;br /&gt;
    ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Beides in &#039;&#039;einer&#039;&#039; Kette ==&lt;br /&gt;
&lt;br /&gt;
Kann man die &#039;595 und die &#039;165 an &#039;&#039;einem&#039;&#039; SPI-Anschluss betreiben?&lt;br /&gt;
&lt;br /&gt;
Ja, einfach verketten. Das geht auch „durcheinander“. Dafür gibt es zwei Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
* Man verwendet &#039;&#039;getrennte&#039;&#039; Anschlüsse am Mikrocontroller für die Parallelübernahme der &#039;595 (Ausgänge) und &#039;165 (Eingänge). Dann sollten die Ausgänge am Ketten-Anfang (MOSI) und die Eingänge am Ketten-Ende (MISO) liegen. Beispielsweise werden für 3 Stück &#039;595 und 2 Stück &#039;165 24 Schiebetakte zum Ausgeben (mit anschließendem ↑RCLK) und 16 Schiebetakte (mit vorausgehendem ¬PL) zum Einlesen benötigt.&lt;br /&gt;
&lt;br /&gt;
* Man verwendet einen &#039;&#039;gemeinsamen&#039;&#039; Anschluss &#039;&#039;&#039;¬L&#039;&#039;&#039; für ↑RCLK und ¬PL, ein Pin sparend. Die o.g. Reihenfolge der &#039;595 und &#039;165 ist weiterhin vorteilhaft. Nach dem o.g. Beispiel gilt folgendes Regime zum Ausgeben und Einlesen in einem Rutsch:&lt;br /&gt;
** Low-Nadel an ¬L (zum Laden der &#039;165-Flipflops; die &#039;595-Ausgänge verändern sich nicht)&lt;br /&gt;
** 8 x 3 = 24 Schiebetakte (auch zum Nur-Einlesen müssen die Ausgabedaten wiederholt ausgegeben werden)&lt;br /&gt;
** Low-Nadel an ¬L (zum Aktualisieren der &#039;595-Ausgänge; das erneute Einlesen in den &#039;165 ist ohne Belang)&lt;br /&gt;
&lt;br /&gt;
Kann man per Software messen, wie lang die Kette ist?&lt;br /&gt;
&lt;br /&gt;
Für bestimmte PnP-artige Lösungen ist es zweckmäßig, die Länge der Kette zu kennen:&lt;br /&gt;
Man schiebt einfach eine einzelne 1 (oder eine einzelne 0) durch die Kette, ohne Parallelübernahmen. Vorher muss man die Kette in ihrer zu erwartenden Maximallänge initialisieren. Benutzt man byteweise arbeitende Hardware-SPI, wird man auf ganze Byte-Längen vertrauen und kann für mehr Sicherheit ein bestimmtes Kennbyte durchschicken.&lt;br /&gt;
&lt;br /&gt;
Kann man per Software messen, &#039;&#039;wo&#039;&#039; die &#039;595 und die &#039;165 liegen?&lt;br /&gt;
&lt;br /&gt;
Nur wenn man davon ausgeht, dass sich die Eingänge nicht allzu schnell ändern. Das ist bei Tastern klar der Fall. Eine 100-prozentige Sicherheit gibt es nicht. Man schiebt ein bestimmtes Bitmuster (Byte) durch und nimmt &#039;595 dort an, wo das Bitmuster auch zurückkommt. Man verwende mindestens 2 verschiedene Bitmuster, um eine derartige Eingangskombination auszuschließen. Wer ziemlich sicher gehen will, schiebt in einer Schleife alle 256 verschiedenen Kombinationen durch. Wenn (bei gemeinsamen ¬L) die Ausgänge unzulässig zappeln, muss man ¬OE beschalten, oder genau jene Bitkombinationen vermeiden.&lt;br /&gt;
&lt;br /&gt;
Kann man andere SPI-Hardware in die Kette einfügen?&lt;br /&gt;
&lt;br /&gt;
Genau dafür ist SPI gemacht! Aber nicht jeder (bspw.) A/D-Wandler ist dafür geeignet: Es muss möglich sein, Daten &#039;&#039;unverändert&#039;&#039; durchzuschieben. Oder wenigstens herumzuleiten. Wenn nicht, ist die einzig mögliche Anordnung &#039;&#039;zwischen&#039;&#039; den &#039;595 (am Kettenanfang) und den &#039;165 (am Kettenende). In der Regel wird eine gesonderte Chipselect-Leitung vom Mikrocontroller benötigt; nur in Ausnahmefällen ist o.g. &#039;&#039;&#039;¬L&#039;&#039;&#039; dafür geeignet (Datenblatt studieren!). Das Chipselect aus einem &#039;595 zu generieren geht auch.&lt;br /&gt;
&lt;br /&gt;
Was für Vorteile bringen &#039;595 und &#039;165 gegenüber einem größeren Mikrocontroller?&lt;br /&gt;
&lt;br /&gt;
* Preis! Controller mit mehr Beinchen kosten oftmals deutlich mehr&lt;br /&gt;
* Günstigeres Routing zu weiter entfernten Schaltungsteilen&lt;br /&gt;
* Kleinere Steckverbinder zu weiteren Platinen, etwa Anzeige- und Bedien-Frontplatten&lt;br /&gt;
* Beliebige Verlängerbarkeit&lt;br /&gt;
* ESD-Schutz und Überlastschutz des Controllers&lt;br /&gt;
* Verbleib beim „gewohnten“ Mikrocontroller möglich&lt;br /&gt;
&lt;br /&gt;
Und welche Nachteile handelt man sich ein?&lt;br /&gt;
&lt;br /&gt;
* Fehlende Sonderfunktionen (etwa Hardware-PWM, Interrupts)&lt;br /&gt;
* Fehlende Bidirektionalität&lt;br /&gt;
* Geringere Geschwindigkeit sowie zusätzliche Verzögerung beim Startup&lt;br /&gt;
* Fehlende Weak-Pullups (bei den Eingängen, es sei denn, man verwendet veraltete 74LS165)&lt;br /&gt;
* Höherer Bestückungsaufwand durch das Mehr an Bauteilen&lt;br /&gt;
&lt;br /&gt;
== Bekannte Probleme ==&lt;br /&gt;
&lt;br /&gt;
AVR Studio 4.12 (Build 498) hat Probleme bei der korrekten Simulation des SPI-Moduls.&lt;br /&gt;
&lt;br /&gt;
* Der Double-Speed Modus funktioniert nicht.&lt;br /&gt;
&lt;br /&gt;
* Das Bit SPIF im Register SPSR, welches laut Dokumentation nur lesbar ist, ist im Simulator auch schreibbar! Das kann zu Verwirrung und Fehlern in der Simulation führen.&lt;br /&gt;
&lt;br /&gt;
Hardwareprobleme&lt;br /&gt;
&lt;br /&gt;
* Wenn das SPI-Modul aktiviert wird, wird &#039;&#039;&#039;NICHT&#039;&#039;&#039; automatisch SPIF gesetzt, es bleibt auf Null. Damit würde die erste Abfrage in &#039;&#039;Schiebe_alles&#039;&#039; in einer Endlosschleife hängen bleiben. Deshalb muss nach der Initialisierung des SPI-Moduls ein Dummy-Byte gesendet werden, damit am Ende der Übertragung SPIF gesetzt wird&lt;br /&gt;
&lt;br /&gt;
* Da das SPI-Modul in Senderichtung nur einfach gepuffert ist, ist es nicht möglich absolut lückenlos Daten zu senden, auch wenn man mit &#039;&#039;&#039;nop&#039;&#039;&#039; eine feste minimale Zeit zwischen zwei Bytes warten würde. Zwischen zwei Bytes muss immer eine Pause von mind. 2 Systemtakten eingehalten werden.&lt;br /&gt;
&lt;br /&gt;
== Weblinks ==&lt;br /&gt;
&lt;br /&gt;
* [http://www.atmel.com/dyn/resources/prod_documents/doc2585.pdf AVR151: Setup And Use of The SPI] Atmel Application Note (PDF)&lt;br /&gt;
* [http://www.datasheetcatalog.com/datasheets_pdf/7/4/H/C/74HC595.shtml datasheetcatalog.com: 74HC595]&lt;br /&gt;
* [http://www.rn-wissen.de/index.php/Portexpander_am_AVR Roboternetz: Portexpander am AVR]&lt;br /&gt;
* [http://conductiveresistance.com/interactive-595-shift-register-simulator/ Interactive 595 Shift Register Simulator]&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/215399#2145277 48 I/O Porterweiterung mit Schieberegister 74HC595 und 74HC165]&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
{{Navigation_zurückhochvor|&lt;br /&gt;
zurücktext=PWM|&lt;br /&gt;
zurücklink=AVR-Tutorial: PWM|&lt;br /&gt;
hochtext=Inhaltsverzeichnis|&lt;br /&gt;
hochlink=AVR-Tutorial|&lt;br /&gt;
vortext=SRAM|&lt;br /&gt;
vorlink=AVR-Tutorial: SRAM}}&lt;br /&gt;
&lt;br /&gt;
[[Category:AVR-Tutorial|Schieberegister]]&lt;br /&gt;
[[Category:SPI]]&lt;br /&gt;
[[Category:Portexpander]]&lt;/div&gt;</summary>
		<author><name>130.75.30.51</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Makro&amp;diff=46526</id>
		<title>Makro</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Makro&amp;diff=46526"/>
		<updated>2010-04-22T15:03:26Z</updated>

		<summary type="html">&lt;p&gt;130.75.30.51: /* Also jetzt Macros oder Inline-Funktionen? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Makros sind eine mehr oder weniger große Anzahl von Anweisungen, die unter einer Kurzbezeichnung zu einer Gruppe zusammengefasst sind und als Einheit verwendbar sind. Makros werden i.d.R von [[Assembler]]sprachen angeboten, sind aber auch in einigen [[HLL|höheren Programmiersprachen]] verfügbar etwa in [[C]]/[[C-Plusplus|C++]] durch den [[C-Präprozessor]]. Schließlich gibt es auch reine Makrosprachen (etwa den Makroprozessor m4 von Unix/Linux), die als Werkzeug zur systematischen Transformation von Textdateien eingesetzt werden können.&lt;br /&gt;
&lt;br /&gt;
Hinsichtlich eines Makros ist zu unterscheiden zwischen dessen &#039;&#039;Definition&#039;&#039;, i.d.R. einmalig und VOR der ersten Verwendung (evtl. auch in [[Include-Files]]) und dessen &#039;&#039;Verwendungen&#039;&#039; (0-mal bis beliebig oft).&lt;br /&gt;
&lt;br /&gt;
== Allgemeines zu Macros ==&lt;br /&gt;
&lt;br /&gt;
Besonders flexibel sind &#039;&#039;&#039;parametrisierbare Makros&#039;&#039;&#039;. Die Makro-Definition ist dann als eine Schablone zu sehen, bei der einige Stellen noch offen gehalten wurden, um sie erst später, bei der Makro-Verwendung zu füllen. Bei der Programmierung haben parametrisierbare Makros eine gewisse Ähnlichkeit zu Unterprogrammen (mit Parametern), werden aber anders als diese zum Zeitpunkt der Übersetzung ausgeführt und hinsichtlich der Parameterwerte festgelegt. &lt;br /&gt;
&lt;br /&gt;
Bei der Programmierung von Mikrocontrollern ist es mitunter erforderlich, zwischen der Verwendung von Unterprogrammen und Makros abzuwägen. Universell wiederverwendbare, und deshalb in einer gewissen Umfang noch konfigurierbare Programmteile können in Form von Makros effizienter als Unterprogramme sein. Allerdings müssen die folgenden Voraussetzungen bestehen:&lt;br /&gt;
# Der &amp;quot;variable&amp;quot; Teil (= aktuelle Werte der Parameter) muss bei der Kompilierung festgelegt werden können. Sofern dieser Punkt nicht sichergestellt ist, scheiden (parametrisierte) Makros komplett aus. &lt;br /&gt;
# Der Makro wird nur ein einziges Mal in genau dieser Form verwendet. Ob die Mehrfachverwendung eines Makros mit identischen Parametern ein Vor- oder Nachteil gegenüber einem Unterprogramm ist, hängt davon ab, was optimiert werden soll. Im Hinblick auf die Ausführungsgeschwindigkeit ist der Makro vorteilhaft, geht es um geringe Code-Größe ist fast immer das Unterprogramm besser. Die Ausnahme von dieser Regel bilden triviale Makros, die weniger Machinen-Code erzeugen als der Befehl für einen Unterprogrammsprung und die notwendige Parameterübergabe.&lt;br /&gt;
&lt;br /&gt;
== Macros vs. Inline Funktionen ==&lt;br /&gt;
&lt;br /&gt;
Anstatt ein Macro zu verwenden, kann eine Funktion auch mit dem Schlüsselwort &amp;quot;inline&amp;quot; versehen werden. Dann erzeugt der Compiler kein Funktionsaufruf, sondern fügt den Code der Inline-Funktion direkt an dieser Stelle ein, an der die Funktion aufgerufen wird.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Vorteile von Inline Funktionen ===&lt;br /&gt;
* &amp;lt;b&amp;gt;Typensicherheit&amp;lt;/b&amp;gt;&amp;lt;br&amp;gt;Der Compiler kann die Typen der Parameter prüfen und Fehler erkennen. Einem Macro kann eigentlich alles übergeben werden, was dann zu seltsamen Fehlermeldungen beim compilieren oder schlimmer einem seltsamen Programmverhalten führen. Beispiels sind im Artikel [[C-Präprozessor]] zu finden.&lt;br /&gt;
* &amp;lt;b&amp;gt;Parameterauswertung&amp;lt;/b&amp;gt;&amp;lt;br&amp;gt;Die Parameter werden ausgewertet, bevor die Inline-Funktion aufgerufen wird. Auch hier sei wieder für Beispiele auf den Artikel [[C-Präprozessor]] verwiesen.&lt;br /&gt;
* &amp;lt;b&amp;gt;Optimieren&amp;lt;/b&amp;gt;&amp;lt;br&amp;gt;Da der Compiler die Typen der Parameter kennt, versteht er möglicherweise, was in der Funktion passiert und kann den gesamten Code besser optimieren. &lt;br /&gt;
* &amp;lt;b&amp;gt;Macros sind nur Hacks&amp;lt;/b&amp;gt;&amp;lt;br&amp;gt;Macros sollten vermieden werden, da sie das Debuggen erschweren und sie der strukturierten Programmierung widersprechen. Insbesondere komplexe, vermeintlich geniale Macros, können für andere oder für einen selber nach einem halben Jahr schon komplett unverständlich sein.&lt;br /&gt;
&lt;br /&gt;
=== Vorteile von Macros ===&lt;br /&gt;
* &amp;lt;b&amp;gt;Textersetzung&amp;lt;/b&amp;gt;&amp;lt;br&amp;gt;Macros sind etwas flexibler, da in ihnen bestimme Code-Schnipsel, die oft vorkommen, zusammengefasst werden können. Erst nach dem Einbauen des Macros durch den Preprozessor muss sich gültiger C-Code ergeben. Dadurch können Macros an manchen Stellen sehr flexibel eingesetzt werden.&lt;br /&gt;
* &amp;lt;b&amp;gt;Macros sind genial&amp;lt;/b&amp;gt;&amp;lt;br&amp;gt;Mit Macros kann man einige Sachen kompakt darstellen und inbesondere lästige Code-Wiederholungen vermeiden bzw. an eine Stelle zentral warten.&lt;br /&gt;
&lt;br /&gt;
== Also jetzt Macros oder Inline-Funktionen? ==&lt;br /&gt;
Es ist wohl zum Teil eine Glaubenfrage über die sich lange vortrefflich streiten lässt. Die einen sagen, dass eben schon immer Macros verwendet wurden und sie zu C einfach dazu gehören (und zu Assembler sowieso). Die anderen sehen sie eher als Altlast aus Zeiten an, in der Code in Assember geschrieben wurde, die Compiler schlecht waren und ein Goto nichts böses war....&amp;lt;br&amp;gt;&lt;br /&gt;
Die Erfahrung bei grösseren Projekten (vor allem im Nicht-uC oder 32-bit uC-Bereich) zeigt aber, dass der Einsatz von Macro mit Bedacht erfolgen sollte. Je abstrakter das Modul wird, desto weniger Macros sollten verwendet werden. Trotzdem sind Macros gerade dann sinnvoll, wenn man direkt an der Hardware programmiert und weit weg von strukturiert objektorientierter Programmierung ist. Um den einen oder anderen von Hand optimierten Hack kommt man dann einfach nicht herum, weil die der Compiler das sonst einfach doch nicht schafft.&amp;lt;br&amp;gt;&lt;br /&gt;
Trotzdem sei an dieser Stelle gewarnt, sich in vermeintlich tollen Macro zu verrennen, ohne über das ganze mal eine Nacht zu überschlafen. Jede vermeintliche Optimierung über Macro-Hacks sollte am Ende auch wirklich eine Optimierung sein. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;An dieser Stelle erwartet der Autor hitzige Debatten und praktische Beispiele darüber, was Compiler einfach nicht hinbekommen... :)&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
* [[AVR Assembler Makros]]&lt;br /&gt;
* [[C Makros]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Programmiersprachen]]&lt;/div&gt;</summary>
		<author><name>130.75.30.51</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Makro&amp;diff=46525</id>
		<title>Makro</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Makro&amp;diff=46525"/>
		<updated>2010-04-22T15:01:54Z</updated>

		<summary type="html">&lt;p&gt;130.75.30.51: /* Vorteile von Inline Funktionen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Makros sind eine mehr oder weniger große Anzahl von Anweisungen, die unter einer Kurzbezeichnung zu einer Gruppe zusammengefasst sind und als Einheit verwendbar sind. Makros werden i.d.R von [[Assembler]]sprachen angeboten, sind aber auch in einigen [[HLL|höheren Programmiersprachen]] verfügbar etwa in [[C]]/[[C-Plusplus|C++]] durch den [[C-Präprozessor]]. Schließlich gibt es auch reine Makrosprachen (etwa den Makroprozessor m4 von Unix/Linux), die als Werkzeug zur systematischen Transformation von Textdateien eingesetzt werden können.&lt;br /&gt;
&lt;br /&gt;
Hinsichtlich eines Makros ist zu unterscheiden zwischen dessen &#039;&#039;Definition&#039;&#039;, i.d.R. einmalig und VOR der ersten Verwendung (evtl. auch in [[Include-Files]]) und dessen &#039;&#039;Verwendungen&#039;&#039; (0-mal bis beliebig oft).&lt;br /&gt;
&lt;br /&gt;
== Allgemeines zu Macros ==&lt;br /&gt;
&lt;br /&gt;
Besonders flexibel sind &#039;&#039;&#039;parametrisierbare Makros&#039;&#039;&#039;. Die Makro-Definition ist dann als eine Schablone zu sehen, bei der einige Stellen noch offen gehalten wurden, um sie erst später, bei der Makro-Verwendung zu füllen. Bei der Programmierung haben parametrisierbare Makros eine gewisse Ähnlichkeit zu Unterprogrammen (mit Parametern), werden aber anders als diese zum Zeitpunkt der Übersetzung ausgeführt und hinsichtlich der Parameterwerte festgelegt. &lt;br /&gt;
&lt;br /&gt;
Bei der Programmierung von Mikrocontrollern ist es mitunter erforderlich, zwischen der Verwendung von Unterprogrammen und Makros abzuwägen. Universell wiederverwendbare, und deshalb in einer gewissen Umfang noch konfigurierbare Programmteile können in Form von Makros effizienter als Unterprogramme sein. Allerdings müssen die folgenden Voraussetzungen bestehen:&lt;br /&gt;
# Der &amp;quot;variable&amp;quot; Teil (= aktuelle Werte der Parameter) muss bei der Kompilierung festgelegt werden können. Sofern dieser Punkt nicht sichergestellt ist, scheiden (parametrisierte) Makros komplett aus. &lt;br /&gt;
# Der Makro wird nur ein einziges Mal in genau dieser Form verwendet. Ob die Mehrfachverwendung eines Makros mit identischen Parametern ein Vor- oder Nachteil gegenüber einem Unterprogramm ist, hängt davon ab, was optimiert werden soll. Im Hinblick auf die Ausführungsgeschwindigkeit ist der Makro vorteilhaft, geht es um geringe Code-Größe ist fast immer das Unterprogramm besser. Die Ausnahme von dieser Regel bilden triviale Makros, die weniger Machinen-Code erzeugen als der Befehl für einen Unterprogrammsprung und die notwendige Parameterübergabe.&lt;br /&gt;
&lt;br /&gt;
== Macros vs. Inline Funktionen ==&lt;br /&gt;
&lt;br /&gt;
Anstatt ein Macro zu verwenden, kann eine Funktion auch mit dem Schlüsselwort &amp;quot;inline&amp;quot; versehen werden. Dann erzeugt der Compiler kein Funktionsaufruf, sondern fügt den Code der Inline-Funktion direkt an dieser Stelle ein, an der die Funktion aufgerufen wird.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Vorteile von Inline Funktionen ===&lt;br /&gt;
* &amp;lt;b&amp;gt;Typensicherheit&amp;lt;/b&amp;gt;&amp;lt;br&amp;gt;Der Compiler kann die Typen der Parameter prüfen und Fehler erkennen. Einem Macro kann eigentlich alles übergeben werden, was dann zu seltsamen Fehlermeldungen beim compilieren oder schlimmer einem seltsamen Programmverhalten führen. Beispiels sind im Artikel [[C-Präprozessor]] zu finden.&lt;br /&gt;
* &amp;lt;b&amp;gt;Parameterauswertung&amp;lt;/b&amp;gt;&amp;lt;br&amp;gt;Die Parameter werden ausgewertet, bevor die Inline-Funktion aufgerufen wird. Auch hier sei wieder für Beispiele auf den Artikel [[C-Präprozessor]] verwiesen.&lt;br /&gt;
* &amp;lt;b&amp;gt;Optimieren&amp;lt;/b&amp;gt;&amp;lt;br&amp;gt;Da der Compiler die Typen der Parameter kennt, versteht er möglicherweise, was in der Funktion passiert und kann den gesamten Code besser optimieren. &lt;br /&gt;
* &amp;lt;b&amp;gt;Macros sind nur Hacks&amp;lt;/b&amp;gt;&amp;lt;br&amp;gt;Macros sollten vermieden werden, da sie das Debuggen erschweren und sie der strukturierten Programmierung widersprechen. Insbesondere komplexe, vermeintlich geniale Macros, können für andere oder für einen selber nach einem halben Jahr schon komplett unverständlich sein.&lt;br /&gt;
&lt;br /&gt;
=== Vorteile von Macros ===&lt;br /&gt;
* &amp;lt;b&amp;gt;Textersetzung&amp;lt;/b&amp;gt;&amp;lt;br&amp;gt;Macros sind etwas flexibler, da in ihnen bestimme Code-Schnipsel, die oft vorkommen, zusammengefasst werden können. Erst nach dem Einbauen des Macros durch den Preprozessor muss sich gültiger C-Code ergeben. Dadurch können Macros an manchen Stellen sehr flexibel eingesetzt werden.&lt;br /&gt;
* &amp;lt;b&amp;gt;Macros sind genial&amp;lt;/b&amp;gt;&amp;lt;br&amp;gt;Mit Macros kann man einige Sachen kompakt darstellen und inbesondere lästige Code-Wiederholungen vermeiden bzw. an eine Stelle zentral warten.&lt;br /&gt;
&lt;br /&gt;
== Also jetzt Macros oder Inline-Funktionen? ==&lt;br /&gt;
Es ist wohl zum Teil eine Glaubenfrage über die sich lange vortrefflich streiten lässt. Die einen sagen, dass eben schon immer Macros verwendet wurden und sie zu C einfach dazu gehören (und zu Assembler sowieso). Die anderen sehen sie eher als Altlast aus Zeiten an, in der Code in Assember geschrieben wurde, die Compiler schlecht waren und ein Goto nichts böses war....&amp;lt;br&amp;gt;&lt;br /&gt;
Die Erfahrung bei grösseren Projekten (vor allem im Nicht-uC oder 32-bit uC-Bereich) zeigt aber, dass der Einsatz von Macro mit Bedacht erfolgen sollte. Je abstrakter das Modul wird, desto weniger Macros sollten verwendet werden. Trotzdem sind Macros gerade dann sinnvoll, wenn man direkt an der Hardware programmiert und weit weg von strukturiert objektorientierter Programmierung ist. Um den einen oder anderen von Hand optimierten Hack kommt man dann einfach nicht herum, weil die der Compiler das sonst einfach doch nicht schafft.&amp;lt;br&amp;gt;&lt;br /&gt;
Trotzdem sei an dier Stelle gewarnt, sich in vermeindlich tollen Macro zu verrennen, ohne über das ganze mal eine Nacht zu überschlafen. Jede vermeindliche Optimierung über Macro-Hacks sollte am Ende auch wirklich eine Optimierung sein. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;An dieser Stelle erwartet der Autor hitzige Debatten und praktische Beispiele darüber, was Compiler einfach nicht hinbekommen... :)&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
* [[AVR Assembler Makros]]&lt;br /&gt;
* [[C Makros]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Programmiersprachen]]&lt;/div&gt;</summary>
		<author><name>130.75.30.51</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Makro&amp;diff=46524</id>
		<title>Makro</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Makro&amp;diff=46524"/>
		<updated>2010-04-22T15:01:38Z</updated>

		<summary type="html">&lt;p&gt;130.75.30.51: /* Vorteile von Inline Funktionen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Makros sind eine mehr oder weniger große Anzahl von Anweisungen, die unter einer Kurzbezeichnung zu einer Gruppe zusammengefasst sind und als Einheit verwendbar sind. Makros werden i.d.R von [[Assembler]]sprachen angeboten, sind aber auch in einigen [[HLL|höheren Programmiersprachen]] verfügbar etwa in [[C]]/[[C-Plusplus|C++]] durch den [[C-Präprozessor]]. Schließlich gibt es auch reine Makrosprachen (etwa den Makroprozessor m4 von Unix/Linux), die als Werkzeug zur systematischen Transformation von Textdateien eingesetzt werden können.&lt;br /&gt;
&lt;br /&gt;
Hinsichtlich eines Makros ist zu unterscheiden zwischen dessen &#039;&#039;Definition&#039;&#039;, i.d.R. einmalig und VOR der ersten Verwendung (evtl. auch in [[Include-Files]]) und dessen &#039;&#039;Verwendungen&#039;&#039; (0-mal bis beliebig oft).&lt;br /&gt;
&lt;br /&gt;
== Allgemeines zu Macros ==&lt;br /&gt;
&lt;br /&gt;
Besonders flexibel sind &#039;&#039;&#039;parametrisierbare Makros&#039;&#039;&#039;. Die Makro-Definition ist dann als eine Schablone zu sehen, bei der einige Stellen noch offen gehalten wurden, um sie erst später, bei der Makro-Verwendung zu füllen. Bei der Programmierung haben parametrisierbare Makros eine gewisse Ähnlichkeit zu Unterprogrammen (mit Parametern), werden aber anders als diese zum Zeitpunkt der Übersetzung ausgeführt und hinsichtlich der Parameterwerte festgelegt. &lt;br /&gt;
&lt;br /&gt;
Bei der Programmierung von Mikrocontrollern ist es mitunter erforderlich, zwischen der Verwendung von Unterprogrammen und Makros abzuwägen. Universell wiederverwendbare, und deshalb in einer gewissen Umfang noch konfigurierbare Programmteile können in Form von Makros effizienter als Unterprogramme sein. Allerdings müssen die folgenden Voraussetzungen bestehen:&lt;br /&gt;
# Der &amp;quot;variable&amp;quot; Teil (= aktuelle Werte der Parameter) muss bei der Kompilierung festgelegt werden können. Sofern dieser Punkt nicht sichergestellt ist, scheiden (parametrisierte) Makros komplett aus. &lt;br /&gt;
# Der Makro wird nur ein einziges Mal in genau dieser Form verwendet. Ob die Mehrfachverwendung eines Makros mit identischen Parametern ein Vor- oder Nachteil gegenüber einem Unterprogramm ist, hängt davon ab, was optimiert werden soll. Im Hinblick auf die Ausführungsgeschwindigkeit ist der Makro vorteilhaft, geht es um geringe Code-Größe ist fast immer das Unterprogramm besser. Die Ausnahme von dieser Regel bilden triviale Makros, die weniger Machinen-Code erzeugen als der Befehl für einen Unterprogrammsprung und die notwendige Parameterübergabe.&lt;br /&gt;
&lt;br /&gt;
== Macros vs. Inline Funktionen ==&lt;br /&gt;
&lt;br /&gt;
Anstatt ein Macro zu verwenden, kann eine Funktion auch mit dem Schlüsselwort &amp;quot;inline&amp;quot; versehen werden. Dann erzeugt der Compiler kein Funktionsaufruf, sondern fügt den Code der Inline-Funktion direkt an dieser Stelle ein, an der die Funktion aufgerufen wird.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Vorteile von Inline Funktionen ===&lt;br /&gt;
* &amp;lt;b&amp;gt;Typensicherheit&amp;lt;/b&amp;gt;&amp;lt;br&amp;gt;Der Compiler kann die Typen der Parameter prüfen und Fehler erkennen. Einem Macro kann eigentlich alles übergeben werden, was dann zu seltsamen Fehlermeldungen beim compilieren oder schlimmer einem seltsamen Programmverhalten führen. Beispiels sind im Artikel [[C-Präprozessor]] zu finden.&lt;br /&gt;
* &amp;lt;b&amp;gt;Parameterauswertung&amp;lt;/b&amp;gt;&amp;lt;br&amp;gt;Die Parameter werden ausgewertet, bevor die Inline-Funktion aufgerufen wird. Auch hier sei wieder für Beispiele auf den Artikel [[C-Präprozessor]] verwiesen.&lt;br /&gt;
* &amp;lt;b&amp;gt;Optimieren&amp;lt;/b&amp;gt;&amp;lt;br&amp;gt;Da der Compiler die Typen der Parameter kennt, versteht er möglicherweise, was in der Funktion passiert und kann den gesamten Code besser optimieren. &lt;br /&gt;
* &amp;lt;b&amp;gt;Macros sind nur Hacks&amp;lt;/b&amp;gt;&amp;lt;br&amp;gt;Macros sollten vermieden werden, da sie das Debuggen erschweren und sie der strukturierten Programmierung widersprechen. Indbesondere komplexe, vermeintlich geniale Macros, können für andere oder für einen selber nach einem halben Jahr schon komplett unverständlich sein.&lt;br /&gt;
&lt;br /&gt;
=== Vorteile von Macros ===&lt;br /&gt;
* &amp;lt;b&amp;gt;Textersetzung&amp;lt;/b&amp;gt;&amp;lt;br&amp;gt;Macros sind etwas flexibler, da in ihnen bestimme Code-Schnipsel, die oft vorkommen, zusammengefasst werden können. Erst nach dem Einbauen des Macros durch den Preprozessor muss sich gültiger C-Code ergeben. Dadurch können Macros an manchen Stellen sehr flexibel eingesetzt werden.&lt;br /&gt;
* &amp;lt;b&amp;gt;Macros sind genial&amp;lt;/b&amp;gt;&amp;lt;br&amp;gt;Mit Macros kann man einige Sachen kompakt darstellen und inbesondere lästige Code-Wiederholungen vermeiden bzw. an eine Stelle zentral warten.&lt;br /&gt;
&lt;br /&gt;
== Also jetzt Macros oder Inline-Funktionen? ==&lt;br /&gt;
Es ist wohl zum Teil eine Glaubenfrage über die sich lange vortrefflich streiten lässt. Die einen sagen, dass eben schon immer Macros verwendet wurden und sie zu C einfach dazu gehören (und zu Assembler sowieso). Die anderen sehen sie eher als Altlast aus Zeiten an, in der Code in Assember geschrieben wurde, die Compiler schlecht waren und ein Goto nichts böses war....&amp;lt;br&amp;gt;&lt;br /&gt;
Die Erfahrung bei grösseren Projekten (vor allem im Nicht-uC oder 32-bit uC-Bereich) zeigt aber, dass der Einsatz von Macro mit Bedacht erfolgen sollte. Je abstrakter das Modul wird, desto weniger Macros sollten verwendet werden. Trotzdem sind Macros gerade dann sinnvoll, wenn man direkt an der Hardware programmiert und weit weg von strukturiert objektorientierter Programmierung ist. Um den einen oder anderen von Hand optimierten Hack kommt man dann einfach nicht herum, weil die der Compiler das sonst einfach doch nicht schafft.&amp;lt;br&amp;gt;&lt;br /&gt;
Trotzdem sei an dier Stelle gewarnt, sich in vermeindlich tollen Macro zu verrennen, ohne über das ganze mal eine Nacht zu überschlafen. Jede vermeindliche Optimierung über Macro-Hacks sollte am Ende auch wirklich eine Optimierung sein. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;An dieser Stelle erwartet der Autor hitzige Debatten und praktische Beispiele darüber, was Compiler einfach nicht hinbekommen... :)&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
* [[AVR Assembler Makros]]&lt;br /&gt;
* [[C Makros]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Programmiersprachen]]&lt;/div&gt;</summary>
		<author><name>130.75.30.51</name></author>
	</entry>
</feed>