Forum: Mikrocontroller und Digitale Elektronik MCP3201 mit Atmega 8 in BASCOM


von Steve M. (jodziste)


Lesenswert?

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

von Karl M. (Gast)


Lesenswert?

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 !

von Karl M. (Gast)


Lesenswert?

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.

von Steve M. (jodziste)


Lesenswert?

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

von Steve M. (jodziste)


Lesenswert?

Habe ich es schlecht beschrieben?

von Karl M. (Gast)


Lesenswert?

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 ?

von Steve M. (jodziste)


Lesenswert?

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

von Karl M. (Gast)


Lesenswert?

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.

von Steve M. (jodziste)


Lesenswert?

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

von Karl M. (Gast)


Lesenswert?

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 !!

von Karl M. (Gast)


Lesenswert?

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.

von Steve M. (jodziste)


Lesenswert?

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

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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 ?

von Steve M. (jodziste)


Lesenswert?

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

von Weinbauer (Gast)


Lesenswert?

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.

von Karl M. (Gast)


Lesenswert?

Weinbauer,

CS (PowerDown) muss bedient werden, siehe 
Beitrag "Re: MCP3201 mit Atmega 8 in BASCOM"

von Karl M. (Gast)


Lesenswert?

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

von Steve M. (jodziste)


Lesenswert?

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

von kernlos (Gast)


Lesenswert?

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.

von Karl M. (Gast)


Lesenswert?

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...

von kernlos (Gast)


Lesenswert?

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.

von Karl M. (Gast)


Lesenswert?

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.

von kernlos (Gast)


Lesenswert?

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.

von Steve M. (jodziste)


Lesenswert?

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

von Wolfgang S. (wsm)


Lesenswert?

Schau mal nach einem MAX1238.

I2C-Bus ist einfacher und wird von BASCOM gut unterstützt.

W.

von Wolfgang S. (wsm)


Lesenswert?

Ups,
ich habe den ADS1015 gemeint.

Ist sehr preiswert.

W.

von Karl M. (Gast)


Lesenswert?

Hallo Wolfgang,

danke, wir wissen auch noch nicht, warum der TE 100kSPS haben will.

Bei 50Hz Leistungsmessung ist das Abtasten mit 100kSPS etwas oversized!

von kernlos (Gast)


Lesenswert?

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.

von Steve M. (jodziste)


Lesenswert?

@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 :)

von Karl M. (Gast)


Lesenswert?

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"

von Bastler (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.