Anzeige:

Schwierigkeiten: erstes Programm/ADC,Interrupts, Arrays

Hier finden sie die archivierten Beiträge des alten PHPBB Forums von www.loetstelle.net

Schwierigkeiten: erstes Programm/ADC,Interrupts, Arrays

Von Caligula am 21.11.2012 10:01

Hallo,

ich programmiere im Moment die Firmware für eine im Rahmen meines "Jugend forscht"-Projekts entworfene Platine. Gerne lade ich Euch ein die Projekt-Website (siehe Signatur) zu besuchen. Ich kann von mir behaupten, dass ich mich in Pascal mit Windows-Aplikationen einigermaßen auskenne. BASIC und Mikrocontroller sind für mich Neuland.

Mit den Compilermeldungen (Anhang) komme ich noch nicht ganz zu recht. Was habe ich hier falsch gemacht? Vielen Dank für Eure Hilfe! Das Projekt steht und fällt mit dieser Firmware ...

1]
$regfile = "M32def.dat" 'es handelt sich um einen ATmega8
$crystal = 4915200 'der Quarz-Oszillator läuft mit 4,9152 Mhz
$hwstack = 100 'im Speicher werden für den Hardware-Stack 100 Byte reserviert
$swstack = 100 'im Speicher werden für den Software-Stack 100 Byte reserviert
$framesize = 1900 'im Speicher werden für den Frame 1900 Byte reserviert

Ddrc = &B00000001 'PC0 als Output
Ddrd = &B00000000 'PD2(Durchflusszähler) und PD3(Taster) müssen Input bleiben

Dim Impulse As Word 'Anzahl der Impulse seit Messungsbeginn, bis 2^16; Durchflussmesser: 10^4 Impulse pro Liter; 16Bit
Dim Status As Bit 'Messung an/aus; 1 Bit
Dim Spannung(300) As Single 'Arrays; 9600 Bit
Dim Verbrauch(300)as Word '4800 Bit
Dim Zeit As Byte 'wird jede Sekunde um 1 hochgezählt; 8 Bit
Dim I As Word '16 Bit für Forschleife

'Variablen- Speicherplatz insgesamt: 14441 Bit --> 1805 Byte (zu viel)

Status = 0 'Initialisierungen

Do 'mainloop

On Int0 On_int0 'Interrupt um Messung zu beginnen
Config Int0 = Falling
Enable Int0

Config Timer1 = Timer , Prescale = 256 'Timer einstellen: 19200 Signale für 1s

On Int1 On_int1 'Interrupt um Messung zu beginnen
Config Int1 = Falling
If Status = 1 Then 'Nur enabeln wenn die Messung begonnen werden soll
Enable Int1
End If

Enable Interrupts 'Interrupts global einschalten. Das ist der Hauptschalter für alle Interrupts

Config Adc = Single , Prescaler = Auto , Reference = Avcc 'für den ADC: AVCC Referenzspannung verwenden
Start Adc 'ADC starten

If Timer1 = 19200 Then
Disable Interrupts 'Interrupts ausschalten, dass der ADC nicht gestört wird/Einstellungen im Multiplexer könnten fatal manipuliert werden
Spannung(zeit) =(5 / 1024) * Getadc(0) 'Spannung die an PC0 anliegt; direkt umgewandelt in V
Verbrauch(zeit) = Impulse
Incr Zeit
Impulse = 0
Timer1 = 0
End If
Enable Interrupts

On_int0: 'Messung ein/ausschalten
Toggle Status
Toggle Portc.0
Zeit = 0
Impulse = 0 'Kontroll-LED
Return

On_int1: 'ein Impuls registriert
Incr Impulse
Return

If Zeit = 300 Then
For I = 0 To 300 Step 1
Print Spannung(i)
Print Verbrauch(i)
Toggle Status
Next I
Wait 10 'periodisch senden
End If

Loop 'mainloop

End 'Ende des Programms
1]

Von BellaD am 21.11.2012 15:27

moin moin

Die reservierten Wörter findest du unter Hilfe oder bei MCS auf der Website.

Kommentare stimmen nicht mit source überein = Atmega8 != ATmega 32

Du hast bestimmt schon gemerkt das das Ram des ATmega8 nicht ausreichen wird für deine Arrays , da könnte man aber wenn nur jede sec. gemessen wird die Werte direkt über rs232 an den PC senden oder ein externes memory (flash oder eeprom) benutzen.

Deine Init routinen gehören vor das "do" oder willst du bei jedem Schleifendurchlauf alles neu initialisieren ?
Damit meine ich alles was zum Anfang einmalig initialisiert wird , Interupts,ADC,Variablen usw.

Port C ist standartmäßig der jtag port und nur nach Abschaltung desselben zu benutzen (Fuse settings)

siehe
kleiner Bascom kurs = www.halvar.at
und die Seite vom Hersteller MCS ist auch sehr hilfreich !

und warum die geschwärzten Zeilen in dem error log ?
wiedermal irgendwas geheimes?

mfg

Von BellaD am 21.11.2012 20:34

moin

Ich hab mal versucht das ein bischen zurechtzurücken wie ich mir das so ungefähr von der strukturierung her vorstelle , aber ich glaub du hast noch eine steile Lernkurve vor dir,
und immer daran denken ein single benötigt 4 Byte speicherplatz,besser wäre ein anderes speichersparendes Format - zBsp. den Integerwert 10bit des ADC in einem Word speichern oder intelligent auf 8 bit runden und in einem byte speichern ......

mfg

Von Caligula am 21.11.2012 20:35

Ich danke Dir BellaD!
So habe jetzt kein Compiler-Gemecker mehr! Ich arbeite mit dem AtMega32.
Funktioniert meine Messung jetzt so?

Code:

$regfile = "M32def.dat"                                     'es handelt sich um einen ATmega32
$crystal = 4915200                                          'der Quarz-Oszillator läuft mit 4,9152 Mhz
$hwstack = 100                                              'im Speicher werden für den Hardware-Stack 100 Byte reserviert
$swstack = 100                                              'im Speicher werden für den Software-Stack 100 Byte reserviert
$framesize = 100                                            'im Speicher werden für den Frame 1900 Byte reserviert

Ddra = &B00000001                                           'PC0 als Output
Ddrd = &B00000000                                           'PD2(Durchflusszähler) und PD3(Taster) müssen Input bleiben

Dim Impulse As Word                                         'Anzahl der Impulse seit Messungsbeginn, bis 2^16; Durchflussmesser: 10^4 Impulse pro Liter; 16Bit
Dim Status As Bit                                           'Messung an/aus; 1 Bit
Dim Spannung(255) As Byte                                   'Arrays; 4800 Bit
Dim Verbrauch(255)as Byte                                   '4800 Bit
Dim Zeit As Byte                                            'wird jede Sekunde um 1 hochgezählt; 16 Bit
Dim I As Byte                                               '16 Bit für Forschleife

Status = 0                                                  'Initialisierungen

On Int0 On_int0                                             'Interrupt um Messung zu beginnen
Config Int0 = Falling
Enable Int0

Config Timer1 = Timer , Prescale = 256                      'Timer einstellen: 19200 Signale für 1s

On Int1 On_int1                                             'Interrupt um Messung zu beginnen
Config Int1 = Falling
If Status = 1 Then                                          'Nur enabeln wenn die Messung begonnen werden soll
Enable Int1
End If

Enable Interrupts                                           'Interrupts global einschalten. Das ist der Hauptschalter für alle Interrupts

Config Adc = Single , Prescaler = Auto , Reference = Avcc   'für den ADC: AVCC Referenzspannung verwenden
Start Adc                                                   'ADC starten

On_int0:                                                    'Messung ein/ausschalten
Toggle Status
Toggle Porta.0
Zeit = 0
Impulse = 0                                                 'Kontroll-LED
Return

On_int1:                                                    'ein Impuls registriert
Incr Impulse
Return

Do                                                          'mainloop

If Timer1 = 19200 Then
Disable Interrupts                                          'Interrupts ausschalten, dass der ADC nicht gestört wird/Einstellungen im Multiplexer könnten fatal manipuliert werden
Spannung(zeit) = Getadc(0)                                  'Spannung die an PC0 anliegt (Zahl zwischen 0 und 1024(=5V))
Verbrauch(zeit) = Impulse
Incr Zeit
Impulse = 0
Timer1 = 0
End If
Enable Interrupts

If Zeit = 255 Then
For I = 0 To 255 Step 1
Print Spannung(i)
Print Verbrauch(i)
Toggle Status
Next I
Wait 10                                                     'periodisch senden
End If

Loop                                                        'mainloop

End                                                         'Ende des Programms

Von Caligula am 21.11.2012 20:38

Haben wohl zeitgleich gepostet. Sorry. Ich geh nochmal drüber!

Von Caligula am 21.11.2012 20:50

So jetzt aber. Echt klasse BellaD! Ich brauche allerdings Einträge ins Array jede Sekunde und auch mehr als 200 Sekunden lang. Geht das dann vom Speicher her mit dem Atmega32 trotzdem?

So siehts jetzt aus ohne Speicherumrechnung. Eben aus dem Grund um Speicherplatz zu sparen. Oder kann ich die Funktion der Umrechnung in Volt getrost miteinbauen (beid er größe der Arrays von 300 Zellen)?


Code:

$regfile = "M32def.dat"                                     'es handelt sich um einen ATmega32
$crystal = 4915200                                          'der Quarz-Oszillator läuft mit 4,9152 Mhz
$hwstack = 100                                              'im Speicher werden für den Hardware-Stack 100 Byte reserviert
$swstack = 100                                              'im Speicher werden für den Software-Stack 100 Byte reserviert
$framesize = 100                                            'im Speicher werden für den Frame 1900 Byte reserviert

Ddra = &B00000001                                           'PC0 als Output
Ddrd = &B00000000                                           'PD2(Durchflusszähler) und PD3(Taster) müssen Input bleiben

Dim Impulse As Word                                         'Anzahl der Impulse seit Messungsbeginn, bis 2^16; Durchflussmesser: 10^4 Impulse pro Liter; 16Bit
Dim Status As Bit                                           'Messung an/aus; 1 Bit
Dim Spannung(255) As Byte                                   'Arrays; 4800 Bit
Dim Verbrauch(255)as Byte                                   '4800 Bit
Dim Zeit As Byte                                            'wird jede Sekunde um 1 hochgezählt; 16 Bit
Dim I As Byte                                               '16 Bit für Forschleife

Status = 0                                                  'Initialisierungen

On Int0 On_int0                                             'Interrupt um Messung zu beginnen
Config Int0 = Falling
Enable Int0

Config Timer1 = Timer , Prescale = 256                      'Timer einstellen: 19200 Signale für 1s

On Int1 On_int1                                             'Interrupt um Messung zu beginnen
Config Int1 = Falling

Config Adc = Single , Prescaler = Auto , Reference = Avcc   'für den ADC: AVCC Referenzspannung verwenden
Start Adc                                                   'ADC starten

Enable Interrupts                                           'Interrupts global einschalten. Das ist der Hauptschalter für alle Interrupts

Do

If Status = 1 Then                                          'Nur enabeln wenn die Messung begonnen werden soll
Enable Int1
End If                                                          'mainloop

If Timer1 = 19200 Then
Disable Interrupts                                          'Interrupts ausschalten, dass der ADC nicht gestört wird/Einstellungen im Multiplexer könnten fatal manipuliert werden
Spannung(zeit) = Getadc(0)                                  'Spannung die an PC0 anliegt (Zahl zwischen 0 und 1024(=5V))
Verbrauch(zeit) = Impulse
Incr Zeit
Impulse = 0
Timer1 = 0
End If
Enable Interrupts

If Zeit = 255 Then
For I = 0 To 255 Step 1
Print Spannung(i)
Print Verbrauch(i)
Toggle Status
Next I
Wait 10                                                     'periodisch senden
End If

Loop                                                        'mainloop

On_int0:                                                    'Messung ein/ausschalten
Toggle Status
Toggle Porta.0
Zeit = 0
Impulse = 0                                                 'Kontroll-LED
Return

On_int1:                                                    'ein Impuls registriert
Incr Impulse
Return

End                                                         'Ende des Programms

Von BellaD am 21.11.2012 22:07

schön schön ,-)
sieht doch schonmal gut aus

Die Interupt handler können vor der Hauptschleife oder danach stehen , wenn sie in der mainloop stehen werden sie logischerweise ausgeführt bis zum return und dann erfolgt ein rücksprung auf den letzten eintrag auf dem stack und schon befinden wir uns im nirvana ...
siehe stack ,stackpointer,stackmanipulation (wicki oder so)

vorne ist besser da sich beim zufügen von code zum prg. nicht immer alles nach unten verschiebt ich hatte das vorhin nur mal auf die schnelle rausgenommen da sich das prg. (siehe oben ) nach dem start ins nirvana begeben hat.

Spannung(zeit) = Getadc(0) das geht nicht ,einem byte array einen 16 bit wert zuweisen. siehe das in dem von mir geposteten bspl. den umweg ueber 2 variablen - da dann der compiler intern die werte entsprechend konvertiert..
Verbrauch(zeit) = Impulse hier auch , da jetzt verbrauch als byte definiert ist (wenn du bis 65534 zählen willst dann muss das 16 bit lang werden ) evtl einen faktor zum skalieren benutzen, komm auf die Genauigkeit an die du haben willst und dann zur ausgabe wieder dazu rechnen ... zbsp. max messbare impulsanzahl <= 512 dann könnte man das durch 2 teilen - sind dann 8 bit - und bei der ausgabe wieder verdoppeln..

ich würde die adc werte speichern und bei der ausgabe erst in volt umrechnen und das dann ausgeben- da darfs dann auch wieder single sein ..

ob das prg so geht kann ich nicht sagen da ich die hardware nicht habe und du sollst ja auch was lernen Razz aber der BascomSimulator hilft dir vielleich schonmal etwas weiter

evtl. kann man den adc in den sognannten left adjust modus setzen und spart sich dadurch das konvertieren von 10 auf 8 bit - musst du mal ins datenbltt des mega32 schauen ob du da was in den erklärungen für den 32er was findest, ist sozusagen aufrunden durch schieben nach links und man liest nur noch das high byte aus und wirft die unteren bits weg...


so genug für heute
mfg

Von Caligula am 24.11.2012 18:16

Hallo BellaD,

hab nochmal bisschen dran rumgefummelt. Dass für das Array "Verbrauch" Byte reicht, konntest Du nicht wissen. Ich lasse jetzt den Digitalwert beim Übertragen umwandeln. Später soll natürlich mal länger als 10 Sekunden gemessen werden!

Außerdem habe ich jetzt mal noch den Schaltplan hier dazu gepackt: http://co2collector.cwsurf.de/galerie/schaltplanv1.1.png
Ich wäre Dir wirklich sehr dankbar, wenn Du mir ein paar genauere Angaben machen kannst, ob das so läuft.

Jetzt muss ich für PD3 bzw. INT1 den internen Pullup aktivieren (siehe Datenrichtungsregister am Anfang) oder?

Gruß

Caligula

Code:

 $regfile = "M32def.dat"                                     'es handelt sich um einen ATmega32
$crystal = 4915200                                          'der Quarz-Oszillator läuft mit 4,9152 Mhz
$hwstack = 100                                              'im Speicher werden für den Hardware-Stack 100 Byte reserviert
$swstack = 100                                              'im Speicher werden für den Software-Stack 100 Byte reserviert
$framesize = 100                                            'im Speicher werden für den Frame 1900 Byte reserviert

Ddra = &B00000001                                           'PC0 als Output
Ddrd = &B00000000                                           'PD2(Durchflusszähler); und PD3 -->Pullup einschalten

Portd.4 = 0

Dim Impulse As Word                                         'Anzahl der Impulse seit Messungsbeginn, bis 2^16; Durchflussmesser: 10^4 Impulse pro Liter
Dim Status As Bit                                           'Messung an/aus
Dim Spannung(10) As Word                                    'Arrays
Dim Verbrauch(10) As Byte                                   'reicht aus, da kein 50ccm-Motor der Welt einen höheren Verbrauch innerhalb einer Sekunde haben wird ;D
Dim Zeit As Byte                                            'wird jede Sekunde um 1 hochgezählt
Dim I As Byte                                               'für Forschleife

Dim Tsp As Single                                           ' von variablen unterschiedlicher wertigkeit
Const Adc_multi = 0.0048828125                              ' = 5.0 / 1024.0            'constante für umrechnung adc = volt

Status = 0                                                  'Initialisierungen
Porta.0 = 0

On Int0 On_int0                                             'Interrupt um Messung zu beginnen
Config Int0 = Falling
Enable Int0

Config Timer1 = Timer , Prescale = 256                      'Timer einstellen: 19200 Signale für 1s

On Int1 On_int1                                             'Interrupt um Messung zu beginnen
Config Int1 = Falling

Config Adc = Single , Prescaler = Auto , Reference = Avcc   'für den ADC: AVCC Referenzspannung verwenden
Start Adc                                                   'ADC starten

Enable Interrupts                                           'Interrupts global einschalten. Das ist der Hauptschalter für alle Interrupts

Do

If Status = 1 Then                                          'Nur enabeln wenn die Messung begonnen werden soll
Enable Int1
End If                                                      'mainloop

If Timer1 = 19200 Then
Disable Interrupts                                          'Interrupts ausschalten, dass der ADC nicht gestört wird/Einstellungen im Multiplexer könnten fatal manipuliert werden
Spannung(zeit) = Getadc(0)                                  'Spannung die an PC0 anliegt (Zahl zwischen 0 und 1024(=5V))
Verbrauch(zeit) = Impulse
Incr Zeit
Impulse = 0
Timer1 = 0
End If
Enable Interrupts

If Zeit = 10 Then
For I = 0 To 10 Step 1
Tsp = Spannung(i) * Adc_multi
Print Tsp
Print Verbrauch(i)
Toggle Status
Next I
Wait 10                                                     'periodisch senden
End If

Loop                                                        'mainloop

On_int0:                                                    'Messung ein/ausschalten
Toggle Status
Toggle Porta.0
Zeit = 0
Impulse = 0                                                 'Kontroll-LED
Return

On_int1:                                                    'ein Impuls registriert
Incr Impulse
Return


End                                                         'Ende des Programms                                         

Von BellaD am 24.11.2012 18:55

moin

beim atmega32 mit 2kbyte Ram sollten mehr Messungen speicherbar sein -

wir haben :
$hwstack = 100
$swstack = 100
$framesize = 100

also bleiben ca. 1700byte über

ein word = 2 byte
ein byte = 1 byte

300 Werte = 300 * 3 = 900byte

sollten also locker zu speichern sein.

zu den Interupt routinen , es ist besser du schreibst die am ende hinter 'End' .

schau dir bitte nochmal den Schaltplan an und vergleiche die Portbelegung deines Programms mit der Anschlussbelegung des mega32.

Der ADC(0) liegt auf Port anschluss PA0 ! - da ist jetzt eine LED eingezeichnet ????
kann es sein das du vom mega 8 auf mega 32 umgestiegen bist , dann musst du alles überpruefen !!


mfg

Von Caligula am 25.11.2012 11:55

Hallo,

ja die Größe der Arrays ist jetzt erstmal nur zum Testen. Wie manipuliert man beim Simulator die Anzahl der Zyklen? Das geht mir zu lange bei einer Frequenz von 4915200 Hz.

Gruß

Caligula

Anzeige: