PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Digital-Poti via SPI und ATMega ansteuern - aber wie? Komplettes Neuland!



Unregistriert
13.04.2015, 22:24
Hallo Freunde.

Dank eurer Hilfe bin ich auf dem BASCOM-Programmierungssektor schon recht weit voran gekommen. Nun beschäftigt mich jedoch ein neues Gebiet, nämlich die SPI-Ansteuerung (oder wie man das auch nennt ^^).

Dazu folgender Grundgedanke:

Ich baue derzeit portable, akkubetriebene Lautsprechersysteme auf. Bislang verwendete ich immer Potentiometer zur Einstellung von Lautstärke, Höhen und Tiefen, jedoch möchte ich mich der Zeit anpassen.
Ich weiß, dass es auch bereits fertige digitale HiFi-Lautstärkeregler gibt, jedoch sind die mit knapp 28€ nahezu unerschwinglich, zumal ich nicht nur einen bräuchte, sondern mindestens 3.
Also habe ich mir digitale 2Ch-Potentiometer mit je 10K-Ohm gekauft, welche per SPI angesteuert werden müssen.

Meine Fragen hierzu wären nun die Folgenden:

Wie sieht solch ein SPI-Code aus?
Da ich ein neben mindestens 3 Tastern (<Leiser>|<Menü>|<Lauter>) auch noch ein Display und eine Display-Beleuchtung ansteuern möchte, wäre meine 2te Frage: Reicht ein ATMega8 dazu aus?

Das Designen des Tiefpass ist im Grunde kein Ding. Beim Hochpass hätte ich nur das Problem, dass zunächst ja der Hochpass am Poti auf 0% laufen soll, der Full-Range auf 100%. Beim Anheben der Höhen soll dann der Hochpass lauter werden während der Full-Range simultan leiser wird.
Was denkt ihr? Ist das so machbar oder sollte ich dann doch besser auf den Hochpass verzichten?


Ich freue mich auf eure Antworten.


LG - Maik

stardust19322
13.04.2015, 23:48
Für alle Anderen: Entschuldigung - hatte mich vergessen anzumelden. Falls PN-Vorschläge kommen sollten, bitte an diesen Nick.

Danke sehr


LG - Maik

Sauerbruch
14.04.2015, 16:52
Da ich ein neben mindestens 3 Tastern (<Leiser>|<Menü>|<Lauter>) auch noch ein Display und eine Display-Beleuchtung ansteuern möchte, wäre meine 2te Frage: Reicht ein ATMega8 dazu aus?

Da gab´s vor kurzem einen ganz ähnlichen Thread hier im Forum :-)
Trotzdem gerne nochmal:
Ja, ein einziger AT Mega reicht aus. Du könntest es z.B. so machen, dass bei jedem Tastendruck ein Flag gesetzt wird, das in der Hauptschleife abgefragt wird. Ist das Flag gesetzt, ist offensichtlich etwas passiert, und dann wird das LC-Display mit den aktuellen Werten versorgt.

Nachdem Du die Bascom-Hilfe zu den drei SPI-Befehlen ja offensichtlich noch nicht gelesen hast, erkläre ich´s hier mal kurz:

Für SPI brauchst Du mindestens 3 und höchstens 4 Leitungen zwischen Master (AT Mega) und Slave (z.B. elektronisches Poti):
- Datenleitung Master -> Slave
- Datenleitung Slave -> Master (wird nicht benötigt, wenn der Slave ein reiner "Befehlsempfänger" ist)
- Taktimpuls (Clock)
- "Chip Select": Wenn der Master diesen Anschluss des Slaves auf Low zieht weiß der Slave, dass jetzt die Übertragung von Takt & Daten beginnt.
Bei den meisten peripheren Bausteinen heißt dieser Anschluss "CS", Bascom verwendet die historisch etwas unglückliche Abkürzung "Ss" (=Slave select)

In Bascom kannst Du diese Anschlüsse frei auf beliebige I/O-Ports zuordnen, und zwar mit dem Config SPI Befehl:



Config Spi = Soft , Dout = Portb.1 , Ss = Portb.2 , Clock = Portb.3
SPIINIT


Heißt also dass über B.1 Daten rausgehen (dieser Pin muss dann mit dem Daten-Eingang des Potis verbunden werden), der Takt kommt bei B.3 raus (geht an den Clock-Anschluss des Potis), und B.2 als "Slave Select" wird mit dem Chip-Select-Anschluss des peripheren Bausteins verbunden.
Spiinit initiiert diese Konfiguration, und schon kann die Übertragung losgehen.

Mit dem Befehl Spiout kann man nun zwischen einem und 255 Bytes vom Master zum Slave schicken. Der Spiout-Befehl hat die Syntax "Spiout X, Y", wobei X der Name der Variablen ist, und Y die Anzahl an Bytes, die gesendet werden sollen. Bei einem einzigen Byte ist es einfach:



Dim A as Byte
A=&b00101010

Spiout A, 1


Sollen mehrere Bytes hintereinander gesendet werden, muss man sie in ein Array anlegen. Hierbei muss man wissen, dass man mit dem Spiout-Befehl auch festlegen kann, welches das erste Byte aus dem Array sein soll, das übertragen wird. Auch hier ein Beispiel:



Dim A(10) as Byte
A(1)=&b00101010
A(2)=&b00000001
A(3)=&b11001010
...
A(10)=&b11111100




Spiout A(3), 2


sendet die 2 Bytes A(3) und A(4)



Spiout A(2), 6


sendet die 6 Bytes A(2) bis A(8).

Jetzt müsste man nur noch wissen, welche Art von Daten-Bytes Dein digitales Potentiometer erwartet. Auch hier lesen wir gerne das Datenblatt für Dich, nur sagen wie der Chip heißt müsstest Du uns schon selbst :-)

stardust19322
15.04.2015, 00:37
Hallo Sauerbruch.

Danke sehr, dass du dir die Zeit genommen hast, mir so ausführlich und überaus hilfsbereit zu antworten. Weiß ich sehr zu schätzen.

Sicher hast du recht - ich habe die BASCOM-Hilfe bislang noch nicht genutzt. Mein Problem ist halt mein Schulenglisch in Verbindung mit einer sehr miesen, ländlichen Datenverbindung. Ich muss beinahe jedes 3te Wort nachschlagen, und nicht selten braucht eine Seite bis zu 1min zum Laden. Da geht eine ganze Menge Zeit ins Land, und bislang haben mich nur 2 Dinge davon abgehalten, alles hinzuschmeißen: Mein eiserner Wille mich zu verbessern, und eure Hilfsbereitschaft. Danke dafür.


Da ich die Bauteile erst in der Praxis testen kann (habe kein geeignetes Testboard zur Verfügung), würde ich gern im Vorfeld einen Fehler vermeiden.
Ich habe dich nun so verstanden, dass ich beim Anschluss mehrerer Slaves an den Controller nur jeweils einen Controller-Pin parallel an die anderen Slaves legen brauche, nämlich die Pins "Clock" und "Slave Select". Lediglich der Pin "Data out" wird seriell angeschlossen, also in etwa: Controller -> Slave_1 -> Slave_2 -> etc.pp. So gesehen also nur 3 Pin für beliebig viele Endgeräte. Ist das so korrekt?

Verdammt - ich habe tatsächlich vergessen, das Bauteil zu nennen. Es handelt sich hierbei um MCD 42010, wobei "010" wohl für den K-Ohm Wert stehen dürfte.

Das mit dem Array habe ich noch nicht so ganz verstanden. Für mich sieht das so aus:
Ich lege beispielsweise ein Array mit 6 Bytes an, lege die 6 Bytes fest und starte die Übertragung an 3 Slaves, dann wird also nicht das einzelne Byte übertragen, sondern die gesamte Variable mit den darin geschriebenen Bytes? Somit landen dann also die ersten beiden Bytes (Var A (1) und Var A (2) ) im in dem in der Reihenfolge am weitesten vom Controller entfernten Slave, die mittleren beiden im mittleren Slave und die letzten beiden im Controller-ersten Slave?

In meiner derzeitigen Vorstellung würde das so ausschauen, dass ich eine Zählvariable erzeuge, die per Tastendruck rauf oder runter zählt. Der neue Wert wird dann sofort in das Array geschrieben und sobald der neue Wert nicht mehr mit dem hinein bereits im Array befindlichen Wert überein stimmt, wird eine Übertragung gestartet. Kann man dies so machen?
leider habe ich diese Woche keine Programmier-Hardware dabei, wodurch ich keinen Code ausprobieren kann. Bei meinem letzten Programm war ich so in der Materie, dass ich den Code unterwegs schreiben und dann daheim nur überspielen brauchte, aber das hier ist für mich komplettes Neuland.

Danke im Voraus für eure Hilfen und Mühen.


LG - Maik

Sauerbruch
15.04.2015, 15:51
Hey Maik,

Oh je, wenn sich die Seiten soooo langsam bei Dir aufbauen, werde ich mal versuchen, mich auf 10 nicht allzu lange Sätze zu beschränken :-)


Da ich die Bauteile erst in der Praxis testen kann (habe kein geeignetes Testboard zur Verfügung), würde ich gern im Vorfeld einen Fehler vermeiden.

Das geht doch auch ohne spezielle und teure Testboards! Ich entwickle und teste eigentlich alle meine Mikrocontroller-Anwendungen auf einem ganz normalen Labor-Steckboard. Das erspart einem unangenehme Überraschungen, und für etwa 10 Euro bist Du dabei:

http://www.pollin.de/shop/dt/NDI4OTg0OTk-/Werkstatt/Werkstattbedarf/Sonstiges/Labor_Steckboard.html
http://www.pollin.de/shop/dt/Mjk5ODg0OTk-/Werkstatt/Werkstattbedarf/Sonstiges/Steckbruecken_Sortiment_65_teilig.html

Die Verdrahtung ist genau wie Du es beschrieben hast:
Der als Clock definierte Anschluss des Controllers geht bei allen 3 Potis auf Pin 2 (SCK), Ss des Controllers geht dementsprechend dreimal auf Pin 1 (CS), nur Dout wird "durchgeschleift", d.h. beim ersten Poti bei Pin 3 rein (SI für "Serial In"), bei Pin 13 wieder raus (SO für "Serial Out") und von dort in´s zweite Poti usw. Im Datenblatt (http://pdf1.alldatasheet.com/datasheet-pdf/view/91954/MICROCHIP/MCP42010.html) ist auf Seite 20 genau dieser Aufbau skizziert.

Nun muss man noch wissen, dass man dem MCP42010 immer zwei Bytes senden muss, um eine Einstellung vorzunehmen: Ein sogenanntes Kommandobyte und ein Datenbyte. Das Kommandobyte sagt dem Chip, was man von ihm will (z.B. Poti 1 einstellen, Poti 2 einstellen o.Ä.), und das Datenbyte entspricht dann dem einzustellenden Wert.

Beim Kommandobyte sind nur die Bits 5, 4, 1 und 0 von Bedeutung. Mit den Bits 5 und 4 wird festgelegt, ob entweder ein neuer Wert eingestellt werden soll (Bit 5 = 0, Bit 4 = 1), oder das Poti "abgeschaltet" werden soll (Shutdown-Modus: Bit 5 = 1, Bit 4 = 0). Mit den Bits 1 und 0 sagst Du dem Controller, welches der beiden Potis denn gemeint ist. Für Poti 1: Bit 1 = 0, Bit 0 = 1, für Poti 2: Bit 1 = 1, Bit 0 = 0, für beide Potis: Bit 1 = 1, Bit 0 = 1.

Wenn Du also z.B. einen neuen Wert für Poti 1 senden willst, muss das Kommando-Byte &b00010001 sein.
Da Du ja wahrscheinlich den Shutdown-Modus nicht brauchst, sondern den Potis i.d.R. immer nur aktuelle Werte zuweisen wirst, dürftest Du mit den drei Kommandobytes &b00010001 (neuer Wert für Poti 1), &b00010010 (neuer Wert für Poti 2) und &b00010011 (neuer Wert für Potis 1+2) auskommen.

Und nach dem Kommandobyte folgt dann gleich das Datenbyte, mit dem die eigentliche Einstellung des ausgewählten Potis erfolgt.

So, nachdem ich nun das halbe Datenblatt auf deutsch übersetzt habe, noch zwei Beispiele, dass es vollständig klar wird:

Poti 1 soll auf die Mittelstellung (128ste von 255 Stufen) gebracht werden:




Dim A(2) as Byte
A(1)=&b00010001
A(2)=128

Spiout A(1), 2



Und wenn Du beide Potis auf 90% stellen willst (229ste von 255 Stufen) ginge das so:




Dim A(2) as Byte
A(1)=&b00010011
A(2)=229

Spiout A(1), 2



Und wenn Du drei Chips hintereinanderhängst, musst Du die Prozedur verdreifachen:

A(1) = Kommandobyte für Chip Nr. 3
A(2) = Datenbyte für Chip Nr. 3
A(3) = Kommandobyte für Chip Nr. 2
A(4) = Datenbyte für Chip Nr. 2
A(5) = Kommandobyte für Chip Nr. 1
A(6) = Datenbyte für Chip Nr. 1

Spiout A(1), 6

Ich würde das ganze mal auf einem Steckboard aufbauen und mich mit ein bisschen Code & ´nem Ohm-Meter vertraut mit der Materie machen. Und das Datenblatt (http://pdf1.alldatasheet.com/datasheet-pdf/view/91954/MICROCHIP/MCP42010.html) runterladen & lesen :-)

stardust19322
15.04.2015, 21:28
Sauerbruch: Wärst du eine Frau und ich nicht verheiratet, ich hätte dir einen Antrag gemacht :-({|=
Spaß beiseite - ich bin ehrlich mehr als beiegstert. Auch wenn du dies sicher schon öfter geschrieben hast, so hilfst du mir so dermaßen weiter, das kann ich gar nicht wieder gutmachen.
So sind nun keine Fragen mehr offen.
Als ich den Beitrag das erste mal durchlas und beim ersten Beispiel ankam, fragte ich mich, warum da bei "Spiout a(1), " eine 2 hinter stand. Als du dann die Kommandokette für 3 der Controller schriebst, hatte ich das erst gescheckt, dass mit der Ziffer die Anzahl der zu übertragenden Befehlszeilen gemeint ist ^^. Ich Dummchen ;). Bei mir dauern solche Sachen immer ein wenig länger - offenbar sitzt da ein Knoten zwischen Auge und Gehirn-Synapsen :D

Ein Steckboard habe ich, sogar das ganz große. Bislang hatte ich immer Probleme, die Programmieranbindung direkt auf das Board zu bringen, weshalb ich den Controller auf dem Eva-Board programmierte und dann umsetzte.

Werde deinen Rat aber sauber befolgen und am Wochenende mal ein Testprogramm fertig machen.

Dank deiner Hilfe kann ich nun auch weitaus mehr anstellen. Statt einfach nur Bass und Lautstärke, wäre auch eine Kanal-Absenkung (Fading) problemlos machbar.


Dankedankedankedankedanke dir noch einmal recht herzlich. Die Seite speichere ich mir gleich ab ^^.


LG - Maik