Guten Tag, ich plane einen MCP3201 ADC mit einem ATmega 8 auszulesen. Als Programmiersprache benutze ich BASCOM. Wie würde ich den ADC per SPI auslesen? Der ADC schiebt die Daten in zwei "Schüben" raus. Für den µC ist das aber immer noch der selbe Taktzyklus. Bei BASCOM gibt es ja den Befehl SPIIN, der geht aber nur bis 255 (ist halt 8 bit). Ich habe den ADC noch nicht, möchte aber wissen wie das geht. Wären die Anschlüsse so richtig? CLK(ADC)--->SCK(AVR) pin 17 Dout--->MISO pin 16 CS--->SS pin 14 MfG Steven
Steven, schau ins Datenblatt des MCP3201 - http://ww1.microchip.com/downloads/en/DeviceDoc/21290D.pdf Wie das Timing auszusehen hat FIGURE 1-1: Serial Timing und dann vergleiche es mit der SPI Funktionalität deines Zielprozessors. Also ich sehe das viele CLK Signale und irgendwann fängt die Datenübertragung mit einem Start-Bit an !
Das hatte ich noch vergessen: 3.3 Chip Select/Shutdown (#CS/SHDN) p.12 The #CS/SHDN pin is used to initiate communication with the device when pulled low and will end a conversion and put the device in low power standby when pulled high. The CS/SHDN pin must be pulled high between conversions. Somit musst Du auch noch #CS/SHDN bedienen. Eine SPI "Hardwarelösung", wie Du sie anstrebst, kann es in meinen Augen nicht geben.
Hallo, das mit der #CS/SHDN hatte ich schon gesehen. Passt das wenn die #CS/SHDN an pin 14 am µC geht? Ich hatte auch Datenblatt vom ATmega 8 gesehen das es dort nur ein 8-bit Schieberegister für die SPI kommunikation gibt. Heißt das auch das nur Soft-SPI geht? Andere Leute haben auch schon sowas gemacht: http://www.roboternetz.de/community/threads/66428-12-Bit-aus-SPI-in-Word-speichern Dort leuchtet es mir aber nicht ein wie die Kommunikation von statten geht, weil dort auch der SPIIN Befehl genutzt wird der aber nur 8-bit ist. MfG Steven
Hi Steven, mache es doch, so wie es im Datenblatt beschrieben ist und nutze eine reine Softwarelösung für das Timing und die Abbildung des Datenstroms. Wo ist das Problem - selber Programmieren ?
Das Problem ist das ich keine Ahnung habe wie man das in Bascom realisiert. Kenn mich nur mit Grundlegenden Dingen in BASCOM aus. MfG Steven
Hallo Steven, ich schreibe in Assembler, LunaAVR und C meine Programme. Bascom kenne ich nicht. Wie willst Du Programmieren ? - wenn Du nicht mal so einfache Dinge wie Pins Setzen und Abfragen nicht kennst ? Dann solltest Du dich mit der Sprache beschäftigen, lernen - lernen und im Bascom Forum versuchen einen Programmierer für Dich zu finden.
Sowas wie Register, Variablen, Schleifen sind mit durchaus geläufig. Ich habe aber SPI vorher noch nicht benutzt, daher bin ich ratlos wie ich das Problem lösen kann, dass es schnell genug (CLK soll für 100kSpS bei 1,6Mhz leigen)) und möglichst wenig Rechenleistung verbraucht. MfG Steven
Steven, fange doch mal direkt an, ohne HARDWARE SPI, sowie ich es seit Anfang an propagiere. Ziel: Das Programm/ die Funktion MCP3201_Read() muss erstmal funktionieren ! Die Ablaufsteuerung der Funktion MCP3201_Read() ergibt sich direkt aus den Anforderungen und der Impulsabfolge im Datenblatt des MCP3201. Scheller Lesen der ADC-Werte kann immer durch Optimierungen am Code und durch Anpassen der CLK-Frequenz erreichen. Du must verstehen, wie das ganze funktioniert. Es reicht nicht, wenn ein anderer es versteht. Aber mal ehrlich, mit deinem jetzigen Wissen, ist das ein realistisches Ziel. Im Datenblatt steht: 100ksps max. sampling rate at VDD = 5V !!
Steven, Ach noch etwas, was willst Du mit den ADC-Daten machen, wenn die alle 10µs "eintreffen" ? Da wird u.a. Bascom deine Bremse sein, das ist nicht sehr effizient in der Codeerzeugung. Ich bin mal gespannt, was Du antwortest, es ist ja nicht so, dass andere nicht Mitlesen. Sie sehen alle, dass wir Dir nicht nach "Hilfe zur Selbsthilfe" weiterhelfen können.
Danke für die Antworten, Im Datenblatt steht bei Description: The device is capable of sample rates of up to 100 ksps at a clock rate of 1.6 MHz. Was geschehen soll nachdem ein Sample reinkommt: Sample in Variable(y) eine andere Variable wird um 1 hochgezählt (z=z+1) (Anzahl der Samples) Der Wert des Samples (als Zahl) wird mit sich selber Multipliziert und in Variable gesteckt (x=x+(y*y)) Nach einer bestimmten Anzahl von Samples wird x durch z geteilt und daraus die Wurzel gezogen. (Aus den Samples wird der quadratische Mittelwert gezogen) Langsam denke ich auch nach ob es nicht in C besser gehen würde.(effizienterer Code) Auslese Code kommt noch. MfG Steven
Steven J. schrieb: > Nach einer bestimmten Anzahl von Samples wird x durch z geteilt und > daraus die Wurzel gezogen. (Aus den Samples wird der quadratische > Mittelwert gezogen) 4 Mal addieren und dann 2 Mal rechts schieben ist viel schneller und in deinem Fall auch viel besser (arithmetischer Mittelwert). Bei quadratischem Mittelwert werden grössere Werte bevorzugt - warum solltest du das machen ?
Das muss der quadratische Mittelwert sein, ist für eine RMS-Spannungsmessung. Vorschläge wie mann das schneller hin bekommt sind aber willkommen. MfG Steven
Ob C oder Bascom ist ziemlich Wurst ... zur not kann man mit Schokopudding an der Fensterscheibe proggen ... so wie ich das Datenblatt lese hat das Ding also nen CS und solange der low ist und an Clk n Takt kommt schiebt der über Dout die Daten rüber, wobei scheinbar die ersten 4 Bits eh 0 sind, was die Sache einfach machen würde. Du hast also 12 Bits, die ergo nicht in ein Byte passen, ergo nehme man 2 Bytes. Daraus folgt, CS low setzen und dann nacheinander 2 Bytes per SPI abholen, dann wieder CS high Die 2 Bytes muss man dann eben zusammen setzen, das kann man mit Wordvariable Highbyte Lowbyte zu Fuß machen, geht aber unnötig auf die Rechenleistung. Bascom bietet da an Overlay Variablen. dim demo_Wordvariable as word dim demo_Bytearray (2) as byte at demo_Wordvariable overlay nun liest Du einfach den SPI in demo_Bytearray(1) und demo_Bytearray(2) ein und fertig ist der Lack, Dein Wert steht im 16 Bit Word.
Hallo, hier ist eine beispielhafte Implementierung in LunaAVR für den MCP3201. Das MCP3201 Timing ist in weitern Bereichen einstellbar. der MCP3201 CLK läuft nun mit einer Frequenz von 1MHz.
1 | '--------------------------------------- |
2 | ' MCP3201.luna |
3 | '--------------------------------------- |
4 | ' 2016-11-19 de0508 |
5 | '--------------------------------------- |
6 | ' changelog |
7 | '--------------------------------------- |
8 | |
9 | '--------------------------------------- |
10 | ' System Settings |
11 | '--------------------------------------- |
12 | avr.device = atmega328p |
13 | avr.clock = 16000000 |
14 | avr.stack = 42 |
15 | |
16 | '--------------------------------------- |
17 | ' Macros |
18 | '--------------------------------------- |
19 | #define BV(n) as ( 1<<(n) )
|
20 | #define NBV(n) as not( BV(n) )
|
21 | |
22 | ' Init MCP3201 |
23 | MCP3201.Init() |
24 | |
25 | ' Read one 12Bit ADC-Value |
26 | dim result as word |
27 | result = MCP3201.getWord() |
28 | |
29 | '--------------------------------------- |
30 | ' main loop |
31 | do
|
32 | loop
|
33 | |
34 | '--------------------------------------- |
35 | ' end |
36 | end
|
37 | |
38 | class MCP3201 |
39 | '--------------------------------------- |
40 | ' Defines |
41 | // example port and pin definiton
|
42 | #define MCP3201_DIN as portd.0
|
43 | ' #define MCP3201_DOUT as portd.1 ' not used ! |
44 | #define MCP3201_CLK as portd.2
|
45 | #define MCP3201_CS as portd.3
|
46 | |
47 | '--------------------------------------- |
48 | ' Macro |
49 | #macro waitns(time_ns)
|
50 | ' use global macro _DELAY_Cycle(clk) |
51 | asm
|
52 | .set T_DELAY_NS = long((@time_ns) *AVR_CLOCK /10000000) |
53 | .set T_DELAY_NS = word( (T_DELAY_NS +99) /100 ) ; +1 aufrunden |
54 | _DELAY_Cycle( T_DELAY_NS ) |
55 | endasm
|
56 | #endmacro
|
57 | |
58 | '--------------------------------------- |
59 | ' Const |
60 | // MCP3201 timing
|
61 | #define MCP3201_tHI as 500 '[ns]; >= 312ns, Clock High Time
|
62 | #define MCP3201_tLO as 500 '[ns]; >= 312ns, Clock Low Time
|
63 | |
64 | #define MCP3201_tSUCS as 100 '[ns]; >= 100ns, CS Fall To First Rising CLK Edge
|
65 | #define MCP3201_tDO as 200 '[ns]; <= 200ns, CLK Fall To Output Data Valid
|
66 | #define MCP3201_tEN as 200 '[ns]; <= 200ns, CLK Fall To Output Enable
|
67 | #define MCP3201_tDIS as 0 '[ns]; <= 100ns, CS Rise To Output Disable
|
68 | |
69 | #define MCP3201_tCSH as 625 '[ns]; >= 625ns, CS Disable Time
|
70 | |
71 | '--------------------------------------- |
72 | ' Typedef |
73 | '--------------------------------------- |
74 | ' Variable |
75 | |
76 | '--------------------------------------- |
77 | ' Public |
78 | procedure Init() |
79 | MCP3201_DIN.mode = input, pullup |
80 | 'MCP3201_DOUT.mode = output, low ' not used ! |
81 | MCP3201_CLK.mode = output, low |
82 | MCP3201_CS.mode = output, high |
83 | endproc
|
84 | |
85 | function getWord() as word |
86 | dim result as word |
87 | dim mask as word |
88 | |
89 | ' waitns( MCP3201_tCSH ) |
90 | |
91 | MCP3201_CLK = 0 |
92 | MCP3201_CS = 0 |
93 | waitns( MCP3201_tSUCS ) |
94 | |
95 | result = 0 |
96 | mask = BV(15) ' read 15 = 2 start-bits, 1 null-bit and 12 adc-bits |
97 | |
98 | while (mask) |
99 | MCP3201_CLK = 1 |
100 | waitns( MCP3201_tHI ) |
101 | |
102 | MCP3201_CLK = 0 |
103 | waitns( MCP3201_tLO ) |
104 | |
105 | waitns( MCP3201_tDO ) ' same as MCP3201_tEN |
106 | if (MCP3201_DIN) then |
107 | result or= mask |
108 | endif
|
109 | |
110 | mask >>= 1 |
111 | wend
|
112 | |
113 | MCP3201_CS = 1 |
114 | waitns( MCP3201_tDIS ) |
115 | |
116 | return (result and 0x0fff) |
117 | endfunc
|
118 | |
119 | '--------------------------------------- |
120 | ' Private |
121 | |
122 | endclass
|
Großes Dankeschön an Weinbauer! Könnte man nicht auch alles in einem Rutsch in eine Word Variable einlesen? So wie auf dem Datenblatt bei 5.0? mit SPIIN Varible , 2 ? (2 für zwei Bytes) Dann hätte mann 16 bit, davon die ersten 2 und das letzte zu ignoriren.(MSB first Kommunikation) Und den CS vom ADC mit SS am µC bedienen? MfG Steven
Karl M. schrieb: > hier ist eine beispielhafte Implementierung in LunaAVR für den MCP3201. Da sieht mir die Implementierung des Beispiels aus dem Roboternetz mit BASCOM doch "etwas" einfacher aus. Steven J. schrieb: > Andere Leute haben auch schon sowas gemacht: > http://www.roboternetz.de/community/threads/66428-12-Bit-aus-SPI-in-Word-speichern > Dort leuchtet es mir aber nicht ein wie die Kommunikation von statten > geht, weil dort auch der SPIIN Befehl genutzt wird der aber nur 8-bit > ist. @Steven: Dort ist ein arry mit Namen Byte deklariert. Beim SPIIN Befehl wird das erste Element des Arrays angegeben, in der das erste gelesene Byte abgelegt werden soll plus und die Anzahl der Bytes, die gelesen werden sollen. Das zweite gelesene wird dann in das zweite Element des Arrays abgelegt. Ist aber alles der BASCOM Hilfe zu entnehmen.
kernlos, BASCOM SPIIN <var>, <byte> kann man nicht verwenden, da man #CS auch für jede 12bit ADC-Wandlung bedienen muss. Steht alles im Datenblatt...
Karl M. schrieb: > kernlos, > > BASCOM SPIIN <var>, <byte> kann man nicht verwenden, da man #CS auch für > jede 12bit ADC-Wandlung bedienen muss. > > Steht alles im Datenblatt... Na denn könnte man es mit TOGGLe CS vor und nach dem SPIIN versuchen wenn das Kommando es nicht selbst macht. CS steht hier für einen Portpin, der mit dem CS des ADC verbunden ist.
Yepp, CS ist mit irgend einem freier I/O Pin des Atmel verbunden. Dann passt muss man ihn noch im umliegenden Code von SPIIN "bedienen". wenn man es nicht vergisst, kernlos schrieb: > Na denn könnte man es mit TOGGLe CS vor und nach dem SPIIN versuchen > wenn das Kommando es nicht selbst macht. CS steht hier für einen > Portpin, der mit dem CS des ADC verbunden ist.
Karl M. schrieb: > wenn man es nicht vergisst, Genau, wenn man es nicht vergißt. Wenn man es doch vergißt, sollte man nicht vergessen haben hier nochmal nachzuschauen.
Hallo, ich denke mal es wäre am besten die 12bit´s vom ADC in einem Array zu speichern, das macht es einfacher die binär Zahl in einem dezimal zahl umzuwandeln. CS zu bedienen dürfe kein Problem sein. Würde es gehen wenn ich bei SPIIN Array(1) angebe, dass die darauffolgende bits in das Array gepackt werden(halt erstes bit in Array(1),zweites bit in Array(2),...)? oder müsste mann im Array verschieben o.ä. MfG Steven
Hallo Wolfgang, danke, wir wissen auch noch nicht, warum der TE 100kSPS haben will. Bei 50Hz Leistungsmessung ist das Abtasten mit 100kSPS etwas oversized!
Wolfgang S. schrieb: > I2C-Bus ist einfacher und wird von BASCOM ... Blödsinn. Solange du keine komplette Lösung mit I2C in BASCOM hier präsentierst, an der man erkennen kann, wie einfach das ist, ist das nur eine Behauptung, die an deinem Sachverstand zweifeln läßt. @Steven: hör auf rumzufragen sondern sieh zu, daß du den ADC bekommst und probier endlich was aus. Komm wieder mit Schaltplan, Programm und Fehlerbeschreibung, wenn etwas nicht funktioniert.
@Karl M. Ich hatte auch nichts von 50Hz Messung gesagt. Ist natürlich auch möglich mit 100kSpS. Ich möchte auch z.b. an Schaltnetzteilen messen, da ist es suboptimal mit einer Abtastrate für 50Hz zu messen. @Kernlos werd ich machen. Wollte nur im Vorraus abklären was machbar ist. Danke für die Hilfe, ich Melde mich wenns bei mir aufn Tisch liegt und nicht Funktioniert :)
Steven J. kein Problem, mich interessiert wirklich für was die Anwendung gedacht ist. Das 50Hz Stromnetz hatte ich als Diskussioneinstieg genannt. Steven J. schrieb: > Ich hatte auch nichts von 50Hz Messung gesagt. Ist natürlich auch > möglich mit 100kSpS. Ich möchte auch z.b. an Schaltnetzteilen messen, da > ist es suboptimal mit einer Abtastrate für 50Hz zu messen. Ich würde dann auch nicht weiterrechnen mit 32bit Gleitkommazahlen, sondern, je nach Wertebereich, 16Bit oder 32Bit Fixpoint Zahlen verwenden. Wir sind gespannt. ;) # Beitrag "Wurzelfunktion für 16bit Fixed Point Werte"
Hallo, warum so kompliziert? Man braucht für den MCP3201 nicht unbedingt die SPI-Schnittstelle zu benutzen. Einfach nur den Takt, CS ausgeben und dann Daten einlesen. Also 3+12 Takte lt. Datenblatt. Hier mein Beispiel: '********************************************************************** 'Auslesen AD-Converter MCP3201 'Hardware : Data - an PD.5 ' Clock - an PD.6 ' CS - an PD.7 'Chip : ATMega48V '********************************************************************** $regfile = "m48def.dat" 'ATMega48V $crystal = 3686400 'Quarz 3.6864MHz DDRD.6 = 1 'Pin PD6 ist Ausgang DDRD.7 = 1 'Pin PD7 ist Ausgang Config Lcdpin = Pin , DB4 = Portb.0 , DB5 = Portb.1 , DB6 = Portb.2 Config Lcdpin = Pin , DB7 = Portb.3 , E = Portb.5 , RS = Portb.4 Config Lcd = 16x2 'configure lcd screen Dout Alias Pind.5 Clk Alias Portd.6 Cs Alias Portd.7 Dim I As Byte Dim Wert As Word Wait 3 'warte mal kurz Cls 'lösche LCD Set Cs 'Cs auf High setzen Cursor off Do 'Beginn Hauptprogramm Wert = 0 Clk = 0 'Clk auf Low setzen Cs = 0 'Cs auf Low setzen Waitus 2 '100ns Mindestwartezeit Tsucs For I = 1 To 3 '3 Leertakte lt. Datenblatt Clk = 1 'Clk auf High setzen waitus 2 Clk = 0 'Clk auf Low setzen Next For I = 1 To 12 'bis 12 Bits einlesen Clk = 1 'Clk auf High setzen Shift Wert , Left 'Wert nach links schieben Wert = Wert + Dout 'Bit an Wert addieren Clk = 0 'Clk auf Low setzen Next Cs = 1 'Cs auf High setzen Clk = 1 'Clk auf High setzen Locate 1,1 Lcd "Sp.-Wert: " ; Wert ; " " Waitms 50 'warten für Wandlung Loop End
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.