DS3231 mit Systemzeit von PC aktualisieren

ds1074

Neues Mitglied
7 Jan 2020
29
0
1
Sprachen
BascomAVR, Assembler, Python
Hallo,
heute melde ich mich mit einer Erfolgsnachricht. :)
Mein Programm zur Übertragung der Uhrzeit vom PC auf den DS3231 läuft jetzt dank der vielen Tipps von Euch weitestgehend.

Es soll wie gesagt, keine Uhr im eigentlichen Sinne sein, das geht auch anders.

Ich will nur testen, wie man den RTC bedient, um herausbekommen, warum er sich beim Einschalten bzw. flashen des Atemgas öfter wieder zurücksetzt.
Das passiert leider immer noch, bisher nicht nachvollziehbar, warum.:(

Ich habe einige Kommentare eingefügt, vielleicht hilft dies auch anderen.

Man kann sicher noch einiges optimieren, mir ging es darum, das es funktioniert.(siehe TODO's in den Kommentaren)
Vielleicht habt ihr noch ein paar Hinweise, was ich besser machen kann.

Hier das Listing:
Hoffentlich farbig, wie in BASCOM, das sieht man in der Vorschau leider nicht, oder mache ich da was falsch?




CodeBox BascomAVR
'Echtzeituhr mit DS3231 am PollinBoard mit Mega 32
'Testprogramm von DS1074
'09.01.2020
'--- Atmega 32 -----------------------------------------------------------------------------------
$regfile = "m32def.dat" ' ATmega32
$crystal = 8000000 ' 8 MHz
$hwstack = 100 'hardware stack
$swstack = 100 'SW stack
$framesize = 100 'frame space
$baud = 9600 'für Prints
'*** Init Tasten '***************************************
Config Portd.2 = Input
Config Portd.3 = Input
Config Portd.4 = Input
Ta_links Alias Pind.2
Ta_mitte Alias Pind.3
Ta_rechts Alias Pind.4
'*** Init Leds und Beeper *******************************
Config Portd.5 = Output
Config Portd.6 = Output
Config Portd.7 = Output
Led_links Alias Portd.5
Led_rechts Alias Portd.6
Beep Alias Portd.7
Waitms 100
'******************* Deklarationen ************************
'****************** Initialisierung LCD und I2C **********************************
$lib "i2c_TWI.lib" 'Hardware I²C einbinden
Config Twi = 100000 'Takt 100kHz 400 geht auch noch
'-----------------------------------------------------------------------------------------------------------------------------
' TWI gleich einschalten, das macht Bascom ansonsten erst beim I2CStart !
Twcr = &B00000100 ' nur TWEN setzen
'!!! Scheint was zu bringen, warum auch immer !!!
'seit dieser Einstellung startet mein LCD ohne Probleme,
'warum steht sowas nicht in der BASCOM Hilfe? ;-(
'****************** Initialisierung LCD und I2C **********************************
$lib "YwRobot_Lcd_i2c.lib" 'YwRobot Treiber für LCD
Config Scl = Portc.0 'Clock Pullups wahrscheinlich softwaremäßig gesetzt
Config Sda = Portc.1                                                  'Data  Jumper 11 und 12 entfernen blockieren AD4 und AD5
'-------- Init DS3231 ----------------------------------------
'7 Bit Addresse = 0h68 = 0110_1000
'Bit 8 entscheidet über 0 = schreiben 1 = lesen
Const Ds3231_schreib_adresse = 208 'hex D0 write 0b 1101_0000
Const Ds3231_lese_adresse = 209                                       'hex D1 read      0b 1101_0001
'---- Init LCD -------------------------------------------------------------------------------------------------------
Const Pcf8574_lcd = 126 'Adresse des I2C-LCDs = hex 7E
Waitms 500 ' für LCD-Init!
Dim Lcd_backlight As Byte '1 = an; 0 = aus. Wird erst durch einen LCD-Befehl umgesetzt!
Led_links = 1
Lcd_backlight = 1 'danach muß ein Kdo folgen
Cls
'*** Variablen ****************************************
Dim Datum As String * 25
Dim Datum_byte(25) As Byte At Datum Overlay
Dim Tag As Byte
Dim Monat As Byte
Dim Jahr_high As Byte
Dim Jahr As Byte
Dim Stunde As Byte
Dim Minute As Byte
Dim Sekunde As Byte
Dim Wochentag As Byte 'Montag=1 bis Sonntag=7
Dim Wo_tag_str As String * 2
Dim Temp_h As Byte
Dim Temp_l As Byte
Dim X As Byte
Deflcdchar 0 , 2 , 5 , 5 , 2 , 32 , 32 , 32 , 32                      ' Grad Zeichen
'### Pragrammstart ###################################################
Locate 1 , 3
Lcd "Uhr mit DS3231"
Waitms 500
'--- Hauptschleife -------------------------------------------
Do
Toggle Led_links
If Ta_rechts = 1 Then Gosub Uhr_stellen 'linke Taste am Pollinboard
'---sonst Zeit anzeigen ------------------------------------------------------------------------------------------------
I2cstart
I2cwbyte Ds3231_schreib_adresse
I2cwbyte 0 'ab Register 0
I2cstop 'kann man gleich bei Zeile 84 weitermachen?
I2cstart
I2cwbyte Ds3231_lese_adresse
I2crbyte Sekunde , Ack 'Zeit und Datum aus RTC lesen
I2crbyte Minute , Ack
I2crbyte Stunde , Ack
I2crbyte Wochentag , Ack
I2crbyte Tag , Ack
I2crbyte Monat , Ack
I2crbyte Jahr , Nack
I2cstop
Waitms 50
'--------------------- ab hier wird die Temp ausgelesen ----------------------------------
I2cstart
I2cwbyte Ds3231_schreib_adresse
I2cwbyte 17 'ab Register 11 hex = 17 dez
I2cstop
I2cstart
I2cwbyte Ds3231_lese_adresse
I2crbyte Temp_h , Ack 'Temp h lesen
I2crbyte Temp_l , Nack 'Temp l lesen
I2cstop 'generate stop
'-- Anzeige im LCD Display -------------------------------------------------------------------------------
Locate 2 , 1
Wochentag = Makedec(wochentag)
Select Case Wochentag
Case 1 : Lcd "Mo "
Case 2 : Lcd "Die "
Case 3 : Lcd "Mi "
Case 4 : Lcd "Do "
Case 5 : Lcd "Fr "
Case 6 : Lcd "Sa "
Case 7 : Lcd "So "
End Select
'--- evtl. an Stelle von case
    'TODO  Wochentag aus Tabelle   Wo_tag_data holen
    '---- Umrechnung der Nachkommastellen der Temp --------------------------------------
Shift Temp_l , Right , 6 'damit Temp_l 0 - 3 ...
Temp_l = Temp_l * 25 '... * 0,25 = 0...0,75 (75 nach dem Komma) ergibt
'Vorzeichen noch nicht berücksichtigt
'---------------------------------------------
Lcd Bcd(tag) ; "." ; Bcd(monat) ; "." ; "20" ; Bcd(jahr)
Locate 3 , 8
Lcd Bcd(stunde) ; ":" ; Bcd(minute) ; ":" ; Bcd(sekunde)
Locate 4 , 1
Lcd "Temp : " ; Temp_h ; "," ; Temp_l ; " " ; Chr(0) ; "C " '°C
    Waitms 50
Loop Until Ta_links = 1                                               '~> Sprung zum ....
'--- ...Programmende -----------------------------------------------------------------
Led_links = 0
Lcd_backlight = 0 'LCD Licht aus
Cls
End
'### ENDE Programm ###############################################
'--- UPS ---------------------------
Uhr_stellen:
Led_links = 0
Led_rechts = 1
'(
'--- Datum und Uhrzeit hier noch von Hand eingetragen:
Wochentag = 1 'Montag=1 bis Sonntag=7
Tag = 13
Monat = 1
Jahr = 20
Stunden = 19
Minuten = 29
Sekunden = 00
')
'##### neu ########################################################
'****************************************************************************************
' Datum vom PC batch oder hier direkt von der cmd
' Wochentag
'      for /f %A in ('wmic path win32_localtime get dayofweek^|findstr /v /r "^$"') do (set daynumber=%A)
'      Serielle Ausgabe per DOS cmd
' Echo %date% %time% %daynumber%
'****************************************************************************************
Input Datum Noecho 'Datums String einlesen, Noecho ???
Sound Beep , 300 , 300 'Kontrollton für Empfang
Bitwait Ta_links , Set 'Taste nach Empfang
'Terminal starten !!!!!
    Print Datum                                                       'Kontrollanzeige
'--- Berechnungen für RTC ------------------------------------------------------
' TODO folgendes entweder in Assembler oder über Subroutinen
    If Datum_byte(1) > 13 Then X = 0 Else X = 1                       '0x0A abfangen
    'umwandeln
Tag = Datum_byte(1 + X) - 0x30
Swap Tag
Tag = Tag + Datum_byte(2 + X)
    Tag = Tag - 0x30
    Monat = Datum_byte(4 + X) - 0x30
Swap Monat
Monat = Monat + Datum_byte(5 + X)
    Monat = Monat - 0x30
    Jahr = Datum_byte(9 + X) - 0x30
Swap Jahr
Jahr = Jahr + Datum_byte(10 + X)
Jahr = Jahr - 0x30
    Jahr_high = 0x20
'--- Zeit ------------------------------------------------
    Stunde = Datum_byte(12 + X) - 0x30
Swap Stunde
Stunde = Stunde + Datum_byte(13 + X)
    Stunde = Stunde - 0x30
    Minute = Datum_byte(15 + X) - 0x30
Swap Minute
Minute = Minute + Datum_byte(16 + X)
    Minute = Minute - 0x30
    Sekunde = Datum_byte(18 + X) - 0x30
Swap Sekunde
Sekunde = Sekunde + Datum_byte(19 + X)
    Sekunde = Sekunde - 0x30
    Wochentag = Datum_byte(24 + X) - 0x30
    Wo_tag_str = Lookupstr(wochentag , Wo_tag_data)
    '--- vielleicht kann ich auch das verwenden
'Tag = Makebcd(tag) 'in BCD-Format fuer Uhr umsetzen
'Monat = Makebcd(monat)
'Jahr = Makebcd(jahr)
    '--- TODO wird noch getestet
    '--- Testausdruck -----------------------------------
Print
Print Wo_tag_str
Print
Print Hex(tag)
Print Hex(monat)
Print Hex(jahr_high) '0x20 , da constant
Print Hex(jahr)
Print
Print Hex(stunde)
Print Hex(minute)
Print Hex(sekunde)
Print
Print "Ta_mitte = Schreiben Ta_rechts = Abbruch"
Do
If Ta_mitte = 1 Then
Gosub Schreiben 'Schreiben auf RTC
Exit Do
Else
If Ta_rechts = 1 Then Exit Do 'wenn Datum falsch übertragen
End If
    Loop
    Sound Beep , 600 , 300                                            'Ende Signal
Wait 1
Led_rechts = 0
Return
End
'##################################################################
Schreiben:
Print "auf RTC Schreiben"
'----- Datum schreiben: -----
'--- brauche ich hier nicht mehr, siehe Umwandlung
'Tag = Makebcd(tag) 'in BCD-Format fuer Uhr umsetzen
'Monat = Makebcd(monat)
'Jahr = Makebcd(jahr)
I2cstart
I2cwbyte Ds3231_schreib_adresse
I2cwbyte 3 'Datum ab Register 3
I2cwbyte Wochentag
I2cwbyte Tag
I2cwbyte Monat
I2cwbyte Jahr
    I2cstop
' ----- Uhrzeit schreiben: -----
'--- siehe Umwandlung
'Sekunde = Makebcd(sekunde) 'in BCD-Format fuer Uhr umsetzen
'Minute = Makebcd(minute)
'Stunde = Makebcd(stunde)
I2cstart
I2cwbyte Ds3231_schreib_adresse
I2cwbyte 0 'Zeit ab Register 0
I2cwbyte Sekunde
I2cwbyte Minute
I2cwbyte Stunde
I2cstop
Return
End                                                                   'vor Tabellen
'----------------------------------------------------------------------------------------------------------------
Wo_tag_data:
    Data "So" , "Mo" , "Di" , "Mi" , "Do" , "Fr" , "Sa"


Also nochmals vielen Dank
schönes WE
Gruß DS1074

PS: die farbige Darstellung des Listings erschien erst, nachdem ich die Nachricht gesendet habe und am PC mit F5 aktualisiert habe, aber nicht in der Vorschau und auch nicht in den von mir eingestellten Farben.
 
Zuletzt bearbeitet:

Dirk

Administrator
Teammitglied
28 Jan 2007
4.299
146
63
Mittelhessen, Giessen
Sprachen
ANSI C, C++, C#, Java, Kotlin, Pascal, Assembler, PHP
Hoffentlich farbig, wie in BASCOM, das sieht man in der Vorschau leider nicht, oder mache ich da was falsch?
Du machst nichts falsch, in der Vorschau ist das Codehighlighting nicht aktiv.
... und auch nicht in den von mir eingestellten Farben.
Regeln für das Codehighlighting gibt das Forum vor. Persönliche Regeln zu verwenden geht leider nicht so einfach zu lösen.
 

ds1074

Neues Mitglied
7 Jan 2020
29
0
1
Sprachen
BascomAVR, Assembler, Python
alles klar,

Mein LCD hat heute trotz mehrfachen Flashen des ATmegas nicht einmal gesponnen,
seit ich folgendes in meine Codes eingefügt habe.

TWI gleich einschalten, das macht Bascom ansonsten erst beim I2CStart !
Twcr = &B00000100 ' nur TWEN setzen
Nochmals Dank für diesen und auch alle anderen Tipps
 

LotadaC

Sehr aktives Mitglied
22 Jan 2009
3.401
62
48
Marwitz
Sprachen
BascomAVR, Assembler
Wobei mir nicht klar ist, wo das greifen sollte...

Default sind die Beine alle Tristate, extern hast Du sie über einen Pullup hochgezogen (oder verwendest Du die internen?)
TWEN übersteuert die normale Funktion wie folgt:

Pullup-Override -> PORTC-Bits können die Pullups aktivieren (und zwar unabhängig von der Datenrichtung)
Datenrichtungs-Override -> Je nach auszugebendem Pegel wird zwischen Eingang und Ausgang umgeschaltet.
PortValue-Override -> immer Low (je nach Datenrichtung also Tristate oder Gnd)

Bei gesetztem TWEN hast Du im Ruhezustand des Busses also weiterhin Tristate - es ändert sich nach außen hin also nichts.
 

dino03

Aktives Mitglied
27 Okt 2008
6.729
16
38
Sprachen
BascomAVR, Assembler
Hi,

Ich will nur testen, wie man den RTC bedient, um herausbekommen, warum er sich beim Einschalten bzw. flashen des Atemgas öfter wieder zurücksetzt.
Das passiert leider immer noch, bisher nicht nachvollziehbar, warum.:(
ich hab mir mal das Datenblatt gezogen und ein wenig gestöbert.

Auf Seite 9 ist die Pin-Beschreibung. Man benötigt keine externe Reset-Beschaltung da das Ding nach meinem Verständnis als eigener Reset-Controller arbeitet. Der DS3231 kann also angeschlossene CPUs nach PowerOn etwa 250ms auf Reset halten. Steht ja auch auf Seite 1 wenn ich es gelesen hätte ;) ...
"A precision temperature-compensated voltage reference and comparator circuit monitors the status of VCC to detect power failures, to provide a reset output, and to automatically switch to the backup supply when necessary. Additionally, the RST pin is monitored as a pushbutton input for generating a reset externally."
Demnach würde ich den Reset also überhaupt nicht verbinden. Pin offen lassen.

Der Vcc-Pin sollte nach der Pin-Beschreibung mit einem 100nF bis 1µF Keramik nach GND beschaltet werden. Würde ich alleine schon vom Gefühl her machen. Der muß dann auf dein Modul mit drauf was du vom PC zum Atmel trägst. Parallel zum VBat (also der Batterie) soll nach der Pin-Beschreibung auch ein 100nF bis 1µF Keramik.

Seite 13: Im Controll-Register 0Eh sollte das Bit 7 (EOSC) immer auf 0 sein damit der Oszillator läuft. Beim ersten Einschalten setzt der DS3231 das automatisch auf 0. Das erste Einschalten ist gleichbedeutend mit "alle Spannungen waren weg (auch Batterie)". Eine 1 in diesem Bit würde den Oszillator und damit die Uhr stoppen. Bit 6 (BBSQW) würde ich auch auf 0 setzen um Strom zu sparen.

Eventuell würde ich auf dem Modul vor dem Abziehen vom PC oder dem Atmel mit einem Schalter Vcc unterbrechen. Also etwa so wie bei ner Festplatte (sicher Entfernen). Damit wäre der DS3231 im Timeceeper-Mode wenn man ihn abzieht. Ist aber nur so ne Idee. Könnte man statt mit nem Schalter auch mit men kürzeren Steckkontakt machen (Stichwort voreilende/nacheilende Kontakte).

Das sind so meine Gedanken zu dem Problem mit der kaputten Zeit im DS3231.

Gruß
Dino
 

ds1074

Neues Mitglied
7 Jan 2020
29
0
1
Sprachen
BascomAVR, Assembler, Python
Hallo Dino,
Danke für deine Nachricht. Ist schon ein interessantes Bauteil. der DS3231.
Reset habe ich nicht verbunden, könnte vielleicht auf der RTC Platine irgendwie verschaltet sein.
Das mit dem Kondensator und den Bits im Kontrollregister werde ich noch testen.

In meinem Listing hat sich übrigens ein Fehler eingeschlichen ab Zeile 80:

I2cstop 'kann man gleich bei Zeile 84 weitermachen?
statt "Zeile 84" ist Zeile 82 gemeint, meine Frage dazu:
Muss man I2cStop und gleich danach wieder I2Cstart eingeben nachdem man vorher die Schreibaddresse und das erste Leseregister übertragen hat?
Oder kann man da mit einem I2CRestart weitermachen.

Grüße DS1074
 

ds1074

Neues Mitglied
7 Jan 2020
29
0
1
Sprachen
BascomAVR, Assembler, Python
Wobei mir nicht klar ist, wo das greifen sollte...
mir auch nicht wirklich, der Tipp kam von fredred, seitdem startet aber mein Display fast immer auf Anhieb.
"fast "bedeutet, das es immer noch, aber viel seltener zu den besagten Fehlanzeigen kommt.

Die Pullups sind ja häufig schon auf den Platinen enthalten.
Ich überprüfe die Signale immer erst mal mit dem Oszi, ob da auch die ca. 5V-Impulse erzeugt werden.
 

fredred

Mitglied
1 Okt 2015
76
2
7
Hallo,
mir auch nicht wirklich, der Tipp kam von fredred, seitdem startet aber mein Display fast immer auf Anhieb.
"fast "bedeutet, das es immer noch, aber viel seltener zu den besagten Fehlanzeigen kommt.
Com mit Input abzufragen würde ich hier nicht machen. Hast ja keine Handshake Unterstützung. Warum auch? Dein Vorteil ist doch, du hast immer die gleiche Anzahl an Zeichen.
Mein Vorschlag war. Nur diese in ein eigenen Stringpuffer schreiben und erst dann für weitere Verarbeitung nutzen. Somit Zeit für anderes denn die Uart Interrupt- Routine blockiert nicht länger als nötig.

So betrachte ich es auch bei I²C. Stichwort: TWEN. Möchte hier doch erst mal wissen was so am Bus los ist also erst mal zuhören ist angesagt und dann erst fragen wer bist du und dann kann er antworten und ich kann die Antwort den Kerl zuordnen. Ist doch nicht so schlecht in Bascom gelöst. Natürlich geht es auch wenn alle erst mal losschreien und ich versuche nur einen zu zuhören da er der lauteste ist ( erst mal Tristrate ist auch die Zeit)
Kann natürlich sein das ich einen falschen Lösungsweg gewählt habe, weil ich nicht nur die tollen Eigenschaften der Controller nutze, sonder auch versuche die Eigenschaften von Bascom zu berücksichtigen. Einzelheiten wie der Bascom - Mechanismus einige Register der Controller nutzt kenne ich auch nicht so genau.

Da die Com -Schnittstellenverwaltung bezüglich Input und viele Protokolle schon umfangreich auf die AVR- Register zugreifen vermeide ich, wenn es möglich ist, einen eigenen Zugriff auf einzelne Register.

Es werden einige spezielle Lösungswege in dieser Sprache angeboten. Als User muss ich nur Wissen. Was habe ich, was will ich und natürlich wie viel Raumzeit benötige ich um den Weg festzulegen. Wenn es kein HW- Fehler ist würde ich wieder mal behaupten es ist die Laufzeit der einzelnen Teilnehmer des Projekts. Einer kann zu schnell oder zu langsam sein und schon ist Projekt ausgebremst.
Ich überprüfe die Signale immer erst mal mit dem Oszi, ob da auch die ca. 5V-Impulse erzeugt werden.
Ist lobenswert aber, wenn es Steuersignale sind, kommen diese auch zum „richtigen“ Zeitpunkt an und passt die Flange?
Bascom hat einen wichtigen Unterschied zu anderen Hochsprachen (ist ja kein Basic) Ich betrachte vieles nicht mehr aus Assemblerebene seit die Controller nicht nur noch Master sein können und dies wird in dieser Sprache schon umgesetzt.

Entschuldigung für Kommentar. Hatte aber schon mal Versucht auf direkte Frage zu antworten. Wichtig ist nimm dir Zeit. Bleib dran und viel Erfolg.

Tschüß
 

LotadaC

Sehr aktives Mitglied
22 Jan 2009
3.401
62
48
Marwitz
Sprachen
BascomAVR, Assembler
Com mit Input abzufragen würde ich hier nicht machen. Hast ja keine Handshake Unterstützung. Warum auch? Dein Vorteil ist doch, du hast immer die gleiche Anzahl an Zeichen.
Input wartet auf "Zeichen" (ASCII) am UART, und überträgt die in die in die referenzierte Stringvariable. Input terminiert, wenn ein "Input Line Terminator" (Default das Carriage Return) empfangen wurde.
Das vom PC gesendete "Echo" endet mit einem CRLF.
Es wird also kein UART-IRQ verwendet, insbesondere kommt der UART auch dem TWI nicht in die Quere.

Was macht config TWI?
Es stellt die Busgeschwindigkeit ein (also das TWI-Bit-Rate-Register und den TWI-Prescaler). Mehr nicht.

Das Setzen von TWEN schaltet nur auf die Overrides der Beine - also von Tristate (durch die Defaults der PORT-/DDR-Register) auf Tristate (durch die Overrides). Aus Sicht der anderen Busteilnehmer ändert sich aber nichts...

So betrachte ich es auch bei I²C. Stichwort: TWEN. Möchte hier doch erst mal wissen was so am Bus los ist also erst mal zuhören ist angesagt und dann erst fragen wer bist du und dann kann er antworten und ich kann die Antwort den Kerl zuordnen.
???
Wenn ein (Möchtegern-) Master einen Datentransfer veranlassen soll, wird in seinem TWCR TWSTA gesetzt. Daraufhin überprüft die Hardware ob der Bus frei ist (bzw wartet bis er frei wird), und generiert dann die Startcondition. Dadurch wird er zum Master (zumindest einem der Master, die es gleichzeitig versuchen (Multi Master Arbitrierung))
Im hier vorliegenden Fall sollte der Mega32 aber eh der einzige mögliche Master sein (der Bus ist immer frei, es sei denn er belegt ihn selbst) - sowohl die RTC als auch das Display sind strikte Slaves, versuchen nie Kontrolle über den Bus zu übernehmen.
Der Mega32 muß also jedesmal Daten zum Display schicken oder Daten von der RTC anfordern - selbst machen die das nicht...

Was mir auffällt ist, daß scheinbar zwei I²C-Bibliotheken eingebunden werden (Code aus #41: Zeile 28 und 37).
Wie ist das mit den Bibliotheken in Bascom grundsätzlich?
Stößt der Compiler auf eine Instruktion (die kein reserviertes Wort ist), durchsucht er die eingebundenen Bibliotheken bis er die Instruktion findet, und zwar genau in der Reihenfolge in der sie eingebunden sind.
Findet er sie auch in der letzten nicht, wird die Standard-Bibliothek durchsucht. Gibt's auch da nichts, kommt 'ne Fehlermeldung.

Du kannst also Instruktionen in einer neuen Bibliothek umschreiben, und diese dann (ggf vorher) einbinden.

Hier wird also immer zuerst die I²C-TWI-lib verwendet, nur Instruktionen die da nicht gefunden werden, werden aus der ywrobot-Bibliothek genommen.
Ist das Absicht?

P.S.: Bei der Kommunikation mit der RTC gehst Du zu Fuß (Start, Adresse+R/W senden, Daten senden/empfangen, Stop usw). Bascom bietet Dir natürlich auch kombinierte Instruktionen dafür an (I2CSEND, I2CRECEIVE)...
 

ds1074

Neues Mitglied
7 Jan 2020
29
0
1
Sprachen
BascomAVR, Assembler, Python
Danke für die vielen neuen Infos,
Muss ich erst mal verdauen.

- Das mit dem "zu Fuß gehen beim RTC" habe ich auch deshalb gemacht , um mir am Oszi bzw. Logiganalysator das I2C Protokoll anzuzeigen.

- Die beiden Bibliotheken habe ich zum einen für die I2C allgemein und die "ywrobot.lib" für das LCD eingebunden. (habe ich in einem anderen Threed gelesen)
An Bibliotheken, die von anderen erstellt wurden, habe ich es bisher vermieden, diese zu ändern.

- Das Programm ist sicher alles andere als optimal, sollte für mich erst mal nur ein Test für spätere Projekte sein.

- Das mit dem Input habe ich nicht ganz verstanden. Vielleicht könnt ihr mir andere Möglichkeiten an einem Beispiel zeigen.
in meinem Fall soll der Mega32 solange warten, bis der vollständige String von der cmd gesendet wurde. (mit Cr Lf als Endekennung)
 

fredred

Mitglied
1 Okt 2015
76
2
7
Hallo,
- Das mit dem Input habe ich nicht ganz verstanden. Vielleicht könnt ihr mir andere Möglichkeiten an einem Beispiel zeigen.
in meinem Fall soll der Mega32 solange warten, bis der vollständige String von der cmd gesendet wurde. (mit Cr Lf als Endekennung)
Genau hier sehe ich ein Problem. Hab mir mal die Mühe gemacht die Quelle meiner Meinungsbildung zu finden. Hier mal von Roland Walter.

Zitat Start:
Probleme bereitet aber die Vorstellung, eine Reihe von Bytes via UART nach und nach zu empfangen, während man zwischendurch ganz andere Programmschritte abarbeitet. Um einfacher vorgehen zu können, setzen viele Leute zum UART-Empfang die Bascom-Funktion Input ein. Diese Funktion arbeitet intern nach der Poll-Methode und kehrt erst zurück, wenn alle angegebenen Bytes empfangen wurden. Will man mit Input z.B. Zeichen in einen String einlesen, der mit 10 Bytes Länge dimensioniert wurde, dann kehrt Input erst zurück, wenn tatsächlich 10 Bytes empfangen wurden, vorher nicht(!). Das kann beim Test im Terminalprogramm den Eindruck erwecken, als wenn das Programm hängengeblieben ist. Analog gilt dies für Integer: Hat man eine Variable z.B. als WORD dimensioniert, dann kehrt Input erst zurück, wenn 2 Bytes empfangen wurden - ein WORD besteht nun einmal aus zwei Bytes. Das zweite Problem ist die Ineffizienz der Input-Funktion. Soll Input z.B. 10 Bytes einlesen, dann wartet man, bis endlich alle 10 Zeichen empfangen wurden. Bis dahin kann man nichts, aber auch gar nichts anderes tun. Wenn wir 9.600 Baud bei 8N1 annehmen, dann muß der AVR bei 10 Bytes mindestens 1/96 Sekunde lang warten, was bei 10 MHz AVR-Taktfrequenz 104167 Takten Totzeit entspricht. Das ist schon eine sehr bedeutende Verschwendung von Rechenkapazität, die man sich nur leisten sollte, wenn der AVR ohnehin nichts anderes zu tun hat.
Zitat End:

Dies wollte ich mit meiner Antwort ausdrücken. Alles wird noch problematischer, wenn noch mehr Interruptus ins Spiel kommen, die eventuell ein Bussystem hat. Bin mir sicher TWI ist durch Taktfrequenz so einer.

???
Wenn ein (Möchtegern-) Master einen Datentransfer veranlassen soll, wird in seinem TWCR TWSTA gesetzt. Daraufhin überprüft die Hardware ob der Bus frei ist (bzw wartet bis er frei wird), und generiert dann die Startcondition. Dadurch wird er zum Master (zumindest einem der Master, die es gleichzeitig versuchen (Multi Master Arbitrierung))
Im hier vorliegenden Fall sollte der Mega32 aber eh der einzige mögliche Master sein (der Bus ist immer frei, es sei denn er belegt ihn selbst) - sowohl die RTC als auch das Display sind strikte Slaves, versuchen nie Kontrolle über den Bus zu übernehmen.
Der Mega32 muß also jedesmal Daten zum Display schicken oder Daten von der RTC anfordern - selbst machen die das nicht...
Nun sag uns Bitte noch wie viel Zeit der Mega32 hat um sicherzustellen das alle Businformationen abgearbeitet wurden. Oder kommt ein Bussystem ohne Interrupt aus. Solange der µC wartet bis was frei wird kann er doch nixs beeinflussen dachte ich.
Der Bus wird einmal durch Slave freigegeben und natürlich vorrangig durch den Master aber nur wenn er kann. Denn Interrupt ist die Frau im Hause und bestimmt was wann abzulaufen hat.
Da die Interruptvektoren je nach AVR unterschiedlich zu betrachten sind nur mal so viel.
Sobald die Peripherie den Bedarf nach abarbeiten einer Routine signalisiert, wird ein entsprechendes Flag gesetzt. Sofern das Global Interrupt Enable Flag gesetzt ist, pushed der Prozessor Status und Code auf dem Stack und springt in die ISR. Gleichzeitig wird das Global Interrupt Flag zurück genommen. Damit sind weitere ISR- Ausführungen blockiert und werden erst einmal keine weiteren ISR angesprungen.
Somit meine Behauptung je mehr Peripherien eingebunden werden ist das Zeitverhalten des gesamten Projekts zu betrachten. Falls zufällig während der Abarbeiten des Codes ein weiterer Interrupt zur selben Vektoradresse aufgetreten ist oder auch falls der selbe Grund das Flag erneut gesetzt hat, während die ISR abgearbeitet wurde und, oder und.

Richtig ist die Blockade kann nur der Master aufheben. Ist ja alles als Multimastersystem zu betrachten wenn die Initialisierung eindeutig ist( wohl kaum bei 2 unterschiedliche in einem Code) wie hier der Fall. Nicht mit „Treiberlib’s“ für einzelne Peripherie verwechseln wie die für Display. Ach so gleich noch ein Tipp. Schreib doch mal an verschiedenen Stellen im Code LCD init um zu testen ob nach Kaltstart diese Condition nicht schon gestört wurde und mit neu init zum richtigem Zeitpunkt der Fehler eingegrenzt werden kann.

Hinweise sind alles nur Erfahrungen aus meiner Praxis und sollten niemals als akademische Anleitung betrachtet werden. Danke
Mit freundlichen Grüßen
fredred
 

LotadaC

Sehr aktives Mitglied
22 Jan 2009
3.401
62
48
Marwitz
Sprachen
BascomAVR, Assembler
Roland Walter schrieb:
Probleme bereitet aber die Vorstellung, eine Reihe von Bytes via UART nach und nach zu empfangen, während man zwischendurch ganz andere Programmschritte abarbeitet[…]
Genau das ist hier aber nicht der Fall, während des empfanges soll nichts anderes getan werden - und natürlich würde man hier mit Interrupts auch rauskommen
Roland Walter schrieb:
[...]Um einfacher vorgehen zu können, setzen viele Leute zum UART-Empfang die Bascom-Funktion Input ein. Diese Funktion arbeitet intern nach der Poll-Methode und kehrt erst zurück, wenn alle angegebenen Bytes empfangen wurden. Will man mit Input z.B. Zeichen in einen String einlesen, der mit 10 Bytes Länge dimensioniert wurde, dann kehrt Input erst zurück, wenn tatsächlich 10 Bytes empfangen wurden, vorher nicht(!)[...]
Quark!
Input terminiert, wenn ein "Input Line Terminator" (Default das Carriage Return) empfangen wurde.
Das vom PC gesendete "Echo" endet mit einem CRLF.
Wenn Du also einen x Zeichen langen String definiert hast, kannst Du beliebig lange auf der Tastatur rumhämmern; die ersten x Zeichen landen in der Variable (also im SRAM), der Reset landet im Nirvana.
Weiter geht's erst, wenn der Input Line Terminator empfangen wurde, und zwar unabhängig davon, wie viele Zeichen empfangen wurden. Wenn Du gleich den Terminator senden - dann wird das als leerer String bzw "0" behandelt.

Kannst ja einfach mal folgendes Programm durch den Simulator jagen, und das SRAM-Bild dabei im Auge behalten:


CodeBox BascomAVR
$regfile = "m32def.dat"                                     ' ATmega32
$crystal = 8000000 ' 8 MHz
$hwstack = 100 'hardware stack
$swstack = 100 'SW stack
$framesize = 100 'frame space
$baud = 9600 'für Prints
Print "los"
Dim A As Word
Dim S As String * 10

Do
Input "Word:" , A
Print A
Input "String:" , S
Print S
Loop

Interruptus ins Spiel kommen, die eventuell ein Bussystem hat. Bin mir sicher TWI ist durch Taktfrequenz so einer.
Nö.

Durch die i2c-twi-lib wird die Hardware-TWI verwendet, der Mega32 ist (einziger) Master. Er gibt die Clock vor. Alle Slaves müssen sich dran halten, und dürfen lediglich die Clock weiterstretchen...
Bascom verwendet hier keine IRQs, sondern pollt nur das TWINT (AFAIR ohne Timeout). Das TWINT wird zB auch gesetzt, wenn die eigene Startcondition erkannt wurde (Wenn der Bus belegt ist kann man also mit TWSTA 'ne Startcondition … äh … vorbereiten … und auf TWINT warten. Wenn der Bus wieder frei ist, schlägt das TWI automatisch zu und generiert die SC. Dadurch wird TWINT gesetzt, und unser Polling ist am Zuge. Da auch andere Quellen TWINT setzen (erkanntes N/ACK, erkannte Adresse usw), muß natürlich das TWISR ausgewertet werden.)

Der Bus wird einmal durch Slave freigegeben und natürlich vorrangig durch den Master aber nur wenn er kann. Denn Interrupt ist die Frau im Hause und bestimmt was wann abzulaufen hat.
???
Wir reden immer noch über das TWI, oder wie?
Der Bus ist entweder frei, oder durch irgendeinen Master belegt.
Jeder Teilnehmer, der nicht Master ist, ist Slave.
Jeder Teilnehmer kann zum Master werden, indem er erfolgreich 'ne Startcondition generiert.
Ein Master bleibt solange Master bis er entweder selbst den Bus wieder freigibt (Stopcondition), oder die Arbitrierung verliert. Dadurch wird er Zum Slave.
Nach der Startcondition ist der Master Transmitter
Ein Master kann entweder ein Telegramm an alle Busteilnehmer senden (generall call), oder einen bestimmten Teilnehmer adressieren.
Bei der Adressierung eines Teilnehmers wird außerdem die Transferrichtung für den Rest des Telegrammes festgelegt - Der Master kann also Transmitter bleiben oder Receiver werden.
Der adressierte Slave kann als Receiver die empfangenen Bytes entgegennehmen bzw darf als Transmitter antworten.
Jedes Byte wird durch den Receiver ge-N/ACKt.
Ein Master kann auch eine Startcondition generieren ohne vorher den Bus freizugeben, wodurch er Kontrolle über den Bus behält/Master bleibt. Dadurch kann er zB die Transferrichtung ändern oder auch 'n anderen Slave adressieren.

Sobald die Peripherie den Bedarf nach abarbeiten einer Routine signalisiert, wird ein entsprechendes Flag gesetzt. Sofern das Global Interrupt Enable Flag gesetzt ist, pushed der Prozessor Status und Code auf dem Stack und springt in die ISR. Gleichzeitig wird das Global Interrupt Flag zurück genommen. Damit sind weitere ISR- Ausführungen blockiert und werden erst einmal keine weiteren ISR angesprungen.
Wenn das lokale Interrupt enable Flag und das globale Interrupt enable Flag gesetzt sind, ist der Interrupt scharf.
Tritt das Interrupt-Ereignis ein, wird das Interrupt-Flag gesetzt.
Der Controller beendet dann die eventuell laufende Maschineninstruktion (bzw besser und auch einfacher zu verstehen: dem Program Counter wird die Adresse des korrespondierenden Interruptes in der Interruptvektortabelle zugewiesen) - während die laufende Instruktion abgearbeitet wird.
Wann genau das globale Interrupt Enable Flag gelöscht wird (also mit dem setzen des Interrupt Flags oder erst, wenn die laufende Instruktion beendet wurde), ist mir nicht ganz klar.
In den nächsten vier Takten wird die Rücksprungadresse auf den Stack gepusht.
Danach wird das Programm also in der IVT fortgesetzt, praktisch alle Hochsprachen platzieren dort eine Sprunganweisung in die eigentliche Interrupt Service Routine. Dieser Sprung dauert üblicherweise weitere drei Takte.
Werden in der ISR irgendwelche Rechenregister bzw das Statusregister manipuliert, und werden diese auch außerhalb verwendet, müssen siese Register irgendwo (üblicherweise im SRAM, genauer im Bereich des (Hardware-)Stacks) gesichert werden. Und am Ende der ISR wiederhergestellt werden. Darum kümmert sich normalerweise die Hochsprache - mehr oder weniger effizient. Einige sichern nur, was verwendet wird, bei Bascom kann man das in gewissen Grenzen selbst beeinflussen oder sich selbst drum kümmern.
Das sichern aller 32 Rechenregister und des SREG würde 67 Takte kosten.

P.S.: Man kann auch innerhalb einer ISR Interrupts global freigeben, was verschachtelte Interrupts erlauben würde (Obacht! Stack!). Bei den ATXmega und meiner Meinung nach auch bei den X-Core-Tinies wird AFAIR I nicht mehr automatisch gelöscht wenn ein IRQ eintritt.
 

fredred

Mitglied
1 Okt 2015
76
2
7
Genau das ist hier aber nicht der Fall, während des empfanges soll nichts anderes getan werden - und natürlich würde man hier mit Interrupts auch rauskommen
Na dann habe ich die Anfrage völlig falsch verstanden.
Nur jede Aktion einzeln zu betrachten habe ich DS1074 zugetraut.

Ich dachte der Fragende hat Probleme mit Störungen gleichzeitig Busteilnehmer wie Display und Rtc.
Somit habe ich immer versucht sein Projekt so zu betrachten. Wichtig war für mich wie es Herr Walter geschrieben hat. “während man zwischendurch ganz andere Programmschritte abarbeitet“ ich nannte es dazwischen funken.
Da lagen natürlich die Hinweise zu Interrupt na.
Kannst ja einfach mal folgendes Programm durch den Simulator jagen, und das SRAM-Bild dabei im Auge behalten:
Warum das ? Sage ich doch. Du knallst Input in die Do Loop da kann die Abfrage rattern solange es der µC durchhält. Aber was wenn Input im ISR rattert und in der Do Loop zum Beispiel die Uhrzeit aktualisiert und dann noch angezeigt werden soll und all dies noch mittels I²C (diese Hardware ist unkritisch aber die Software wie so oft gedacht, bei mehreren Teilnehmern, nicht)
Der Controller beendet dann die eventuell laufende Maschineninstruktion (bzw besser und auch einfacher zu verstehen: dem Program Counter wird die Adresse des korrespondierenden Interruptes in der Interruptvektortabelle zugewiesen) - während die laufende Instruktion abgearbeitet wird.
Wann genau das globale Interrupt Enable Flag gelöscht wird (also mit dem setzen des Interrupt Flags oder erst, wenn die laufende Instruktion beendet wurde), ist mir nicht ganz klar.
Kennst dich Suber mit dem Interrupt Flag aus aber versuche mal zu spinnen wie ich es mache der grundsätzlich in ein Projekt die Zeit als Hauptproblem betrachtet.
Sobald der Prozessor die ISR verlässt, holt er sich die Adresse für den Code außerhalb der ISR und das Statusregister vom Stack zurück und setzt seine ursprüngliche Bearbeitung weiter fort und zwar mit dem Globalen Interrupt Flag, das beim IRET wieder gesetzt wurde
Sind jetzt zwischenzeitlich andere Interrupt Quellen zu anderen Vektoradressen zu anderen ISR aufgetreten, werden die in der Reihenfolge der Priorität angesprungen. Wer setzt die Priorität.
Wann und welche auslösende IQR- Flag werden automatisch gelöscht wenn der Automatismus sich selber ausbremst Kann ja von einem I²C Slave ausgelöst werden der eine Ewigkeit benötig auf eine Frage zu antworten und solange halten diese den Anschluß auf Low. (Bus steht)
Na gut die Timerinterrupts löschen ihre Flag nicht automatisch. Betrachte ich immer als eigenständig. Somit tickt noch was und kann den Eindruck erwecken alles lauft noch prima.

Mein Schlusswort:
Wenn solche Fehler wie von DS13074 beschrieben und erst mal unerklärlich sind, sollte immer das gesamte Projekt betrachtet werden, wenn eine Trennung der einzelnen Komponenten nicht möglich ist hilft nur das Ausschlussverfahren in kleine Schritte aber bestimmt keine Diskussion über Flag's

Mit freundlichen Grüßen
 

LotadaC

Sehr aktives Mitglied
22 Jan 2009
3.401
62
48
Marwitz
Sprachen
BascomAVR, Assembler
Warum das ? Sage ich doch.
Nein! Du hast irgendjemanden mit der offensichtlich falschen Aussage zitiert, Input würde erst terminieren, wenn eine geforderte Anzahl an Bytes empfangen worden wäre. Da Du dieses Zitat bis auf den Namen nicht weiter belegst, kann das natürlich niemand nachprüfen. Ich kenne auch keinen Roland.
Ich habe darauf hingewiesen, daß Input mit dem Empfang des Input Line Terminators terminiert, und zur Veranschaulichung 'n kleines Beispiel gepostet.
Input empfängt übrigens immer Strings (ASCII-Codes). Soll die empfangene Zeichenkette einem String zugewiesen werden, legt Input die einzelnen Zeichen bereits beim Empfang in der zugewiesenen Variable ab (ist die Variable bereits gefüllt, werden weitere Zeichen ignoriert).
Soll die Zeichenkette einer numerischen Variable (im Beispiel ein Word) zugewiesen, legt Bascom irgendwo im Speicher (wahrscheinlich im Softstack oder im Framebuffer) einen Stringpuffer an (im konkreten Beispiel ab Adresse 0x0734 bis 0x073A), in dem die einzelnen ASCII-Zeichen landen. Nach dem Empfang des Terminators wird daraus 'ne Zahl generiert, und diese in der eigentlichen Variable abgelegt.

Um numerische Werte die keine Strings sind zu empfangen gibt es Inputbin, und diese Instruktion wartet auf die angegebene Anzahl Bytes.

Sobald der Prozessor die ISR verlässt, holt er sich die Adresse für den Code außerhalb der ISR und das Statusregister vom Stack zurück und setzt seine ursprüngliche Bearbeitung weiter fort und zwar mit dem Globalen Interrupt Flag, das beim IRET wieder gesetzt wurde
Ein Return from Interrupt (RETI) poppt die Rücksprungadresse vom Stack (bzw verwertet das was da stand als Rücksprungadresse) spring dahin und enabled nebenbei die IRQs global. Das wiederherstellen der Rechenregister und des SREG muß in der ISR erfolgen, vor dem RETI. (darum kümmert sich aber wie gesagt die Hochsprache)
Ein Return from Subroutine (RET) macht genau dasselbe bis auf das enablen der IRQs.
Allerdings wandelt Bascom das Return am Ende einer ISR immer in ein RETI um.

Der TE verwendet aber keine IRQs.

In der Hauptschleife:
  • prüft er ob ein Taster betätigt wurde; ist das der Fall ruft er 'ne Subroutine zum Stellen der RTC auf
  • liest er Uhrzeit und Temperatur aus der RTC aus
  • stellt er Uhrzeit und Temperatur auf dem Display dar
  • prüft er 'ne weitere Taste, die das ganze Programm (nach Abschaltung der Beleuchtung) terminiert
 

ds1074

Neues Mitglied
7 Jan 2020
29
0
1
Sprachen
BascomAVR, Assembler, Python
Hallo,
LotadaC hat mein Test Programm richtig analysiert. Es funktioniert genau so, wie er es in #54 beschrieben hat.
In einem speziellen Projekt würde ich sicher einiges anders und mit dem neu gelernten auch besser machen.

Zur Information, Roland Walter ist Autor des Buches "AVR Mikrocontroller Lehrbuch".
Das ist ein Buch, in welchem er die Programmierung in Bascom am Beispiel des Atmega8 sehr ausführlich und vor allem hardwarenah beschreibt.
Ich hoffe, das wird nicht als Werbung verstanden. Ich habe schon viele für mich nützliche Informationen darin gefunden.

Übrigens habe ich mir u.a. einen Arduino Nano R3 zugelegt. Dank eines Beitrags im anderen Bascom Forum konnte ich mit wenigen Änderungen
kleine in Bascom geschriebenen Tests ohne Probleme auf den Nano über USB herunterladen.
Nur so als kleiner Hinweis für Interessierte.

Eine Frage habe ich noch, wegen der beiden Libs in meinem Programm.
Ich muss doch beide verwenden, oder sehe ich das falsch?
In vorhanden Bibliotheken was zu ändern ist nicht so mein Ding, es sei denn ich erstelle sie mir selber.

Das mit dem Simulator werde ich am WE testen.

Damit schönen Abend DS1074
 
Zuletzt bearbeitet:

LotadaC

Sehr aktives Mitglied
22 Jan 2009
3.401
62
48
Marwitz
Sprachen
BascomAVR, Assembler
Eine Frage habe ich noch, wegen der beiden Libs in meinem Programm.
Ich muss doch beide verwenden, oder sehe ich das falsch?
Kommt drauf an. Also nicht unbedingt.
Hintergrund:
Nach diesem Beispiel muß für die Verwendung der I²C-Routinen (I2CINIT, und die dort genannten) gar keine Bibliothek eingebunden werden. Meinem Verständnis sind I2CINIT, I2START, I2CSTOP, I2CRBYTE, I2CWBYTE, I2CREPSTART sowie I2CSEND und I2CRECEIVE Routinen des Bascom-Kerns (Standard-Bibliothek), welche ihrerseits andere Routinen Aufrufen ( also I2CINT zB _I2C_INIT).
Wenn keine entsprechende Bibliothek eingebunden ist, scheint Bascom die Bibliothek I2C.lib zu verwenden (bzw diese Bibliothek wird automatisch miteingebunden).
I2C.lib implementiert die ganze Kommunikation in Software..
I2C_TWI.lib implementiert dieselben Funktionen, aber eben in Hardware. Wenn Du also diese Bibliothek miteinbindest (oder eine entsprechende andere), wird statt der Softwareimplementierung die Hardwareimplementierung verwendet - Du verwendest aber dieselben Instruktionen.
Soweit klar?

So, jetzt die andere Seite:
Eigentlich hast Du ein konventionelles Character-LCD, welches über einen parallelen (4-Bit ? ) Bus angesteuert wird. (Jaja, es hängt an einem I²C-Portexpander...).
Diese Displays unterstützt der Bascom-Kern (bzw 'ne automatisch eingebundene Bibliothek dafür), insbesondere gibt es Ausgabefunktionen wie LCD usw.

LCD erwartet also einen String bzw konvertiert irgendwas in einen String, und ruft eine Routine auf, die den String zeichenweise über den parallelen Bus ausgibt.
Diese Routine ist natürlich auch in der Bibliothek implementiert, das Byte wird in seine Nibbles zerlegt, und diese beiden mit den entsprechenden Steuerleitungen übertragen.

Dein Display ist aber wie gesagt (wie viele andere auch) an einen I2C-Portexpander angebunden, die zu sendenden Bytes (bzw Nibbles) sowie die Steuerleitungen müssen also in I²C-Bytes verpackt, und über das I²C versendet werden (also auch an die Adresse des Expanders). Genau da kommen die Bibliotheken wie LCD_I2C.lib und eben Deine YWrobot ins Spiel.
In denen sind nämlich auch die LCD-Senderoutinen implementiert, das Byte wird auch hier in Nibbles zerlegt. Die werden aber nicht auf irgendeinen parallelen Bus gelegt, stattdessen wird dreimal die Routine I2CSEND aufgerufen (die Adresse und die beiden Nibbles) - genau, die Kernroutine von oben, die entweder die Software- oder die Hardwareimplementierung verwendet.

Die LCD-I2C-Bibliotheken fangen also quasi die Standard-Kommunikation über den Parallelbus ab, und kapseln das ganze in's TWI.
Wird keine spezielle I2C-Bibliothek eingebunden (die zB das Hardware-TWI verwendet), benutzt Bascom automatisch die I2C.lib, welche Soft-TWI implementiert.

So, die Bibliothek LCD_I2C.lib ist laut Header wohl die (DIE) Bibliothek von Kent Anderson. Deine Robot-Bibliothek scheint eine recht simple Modifikation der Kent Anderson Bibliothek zu sein.
(Pro eigentlichem Display-Byte müssen ja neben der Adresse je zwei Bytes (die die beiden Nibbles enthalten) durch den Expander gejagt werden. Der ist beim Robot aber anders verdrahtet. Die Modifikation verwendet eigentlich denselben Weg wie Kent, aber je vor dem Senden der beiden Bytes werden die Bits in einem Bit Load and store Marathon übelst hin und herkopiert (0->4, 1->5, 2->6, 3->7, 4->0, 5->1, 7->2, 6->3). Die sechzehn Takte/Words könnte man unter Verwendung von MOV und SWAP übrigens auf sechs einstampfen.

Zur Information, Roland Walter ist Autor des Buches "AVR Mikrocontroller Lehrbuch".
Und da steht das mit Input wirklich so falsch drin?

u.a. einen Arduino Nano R3 zugelegt.
Das scheint ein Mega328P (AKA "neuer Mega8 mit doppelt Fleisch" … äh … vierfach Speicher usw) mit an den UART drangeflanschtem FT232 (UART-USB-Adapter) zu sein. Via DTR-Handshake scheint auch ein Reset des AVR ausgelöst werden zu können (um zB einen Bootloader zu füttern). Arduinotypisch mit einem 16MHz-Quarz getaktet - gibts'n Grund für die LED an B5? Die blinkt doch dann jedesmal, wenn der Controller via SPI geflasht wird, oder man das SPI verwendet...
 

ds1074

Neues Mitglied
7 Jan 2020
29
0
1
Sprachen
BascomAVR, Assembler, Python
Hallo LotadaC,

Ich habe meine "Hausaufgaben" gemacht. ;)
Die Sache mit dem Input aus #52 stimmt. Man kann die Inputabfrage mit Eingabe von Enter immer vorzeitig beenden.
Ich gehe davon aus das du dich auf Seite 87 von Roland Walters Buch beziehst.
Meine Ausgabe ist von 2012, vielleicht hat er's schon korrigiert.


Auch das mit den Libs habe ich getestet. Wenn ich den "I2cinit" Befehl nach der Konfiguration von SDA und SCL aufrufe, kann ich mir die folgenden Kdo's
sparen:

'**** config I2C *************************************************************
$lib "i2c_TWI.lib" 'Hardware I²C einbinden
Config Twi = 100000 'Takt 100kHz 400 geht auch noch
Twcr = &B00000100

die RTC startet munter los, aber die "$lib "YwRobot_Lcd_i2c.lib" für das LCD brauche ich, sonst tut sich da nichts.

Also, wieder was dazu gelernt.


Das mit dem Mega328P stimmt soweit, nur der USB Chip ist ein CH340-Chip. Er kann wohl nur mit 57600 Baud 'brennen', aber das hat mich bisher nicht gestört.
Kann man in Bascom die Konfiguration speichern, wenn man das Board und damit den Prozessor wechselt, oder muss man das immer manuell neu einstellen?

Das wars nun wirklich für heute
Damit schönes WE
 
Zuletzt bearbeitet:

LotadaC

Sehr aktives Mitglied
22 Jan 2009
3.401
62
48
Marwitz
Sprachen
BascomAVR, Assembler
Man kann die Inputabfrage mit Eingabe von Enter immer vorzeitig beenden.
Nicht vorzeitig, sondern überhaupt erst. Ohne "Enter" (CR) terminiert Input gar nicht.

Das Buch kenne/hab ich nicht. Fredred hatte es zitiert.

I2CINIT ruft selbst eine _I2C_INIT Routine auf. Diese ist in I2C.lib und in der I2C_TWI.lib definiert. Beide versuchen die (festgelegten) I²C-Beine SDA und SCL über PORT- und DDR-Register Tristate zu setzen. Wenn die vorher bereits/nochTristate sind/waren, ändert sich hier nichts. Wird vorher TWEN gesetzt, sind die Register eh unwirksam, die Beine wie oben beschrieben per Overrides Tristate.
I2CINIT erzeugt außerdem Kompilerkonstanten für die Beine.
_sdaDDR, _sdaPORT, _sclDDR und _sclPORT entsprechen dann den Adressen der jeweiligen I/O-Register,
_sda und _scl den jeweiligen Bits.
Diese Konstanten kannst Du in Deinem Programm verwenden. Die Adressen legst Du mit config SDA/SCL fest, aber der Compiler erzeugt erst bei i2cinit.

Legst Du in einer eigenen Bibliothek 'ne leere _i2c_init an (nur den label und ein Return), werden diese Konstanten bereits mitangelegt und config sda/scl geht.
Dadurch kann man dann eigene I²C-Routinen/Bibliotheken schreiben, die sich mit den Standard-Bascom-Instruktionen verwenden lassen, im Hintergrund aber zB das USI der ATtinies nutzen oder was auch immer.

Ich hätte 'ne ähnliche Sache gern beim 1wire gehabt (also daß ich 'ne eigene 1wire-Bibliothek erzeugen kann, die den durch Config 1wire bzw die Defaults (Menu -> Optionen -> Compiler -> I2C) festgelegten Pin verwendet.)

$lib "i2c_TWI.lib" 'Hardware I²C einbinden
Wenn Du das wegläßt, werden die Routinen aus der I2C.lib verwendet, also Software-I²C. Da könntest Du dann jeden beliebigen Pin für SDA/SCL verwenden aber der Code wäre umfangreicher und "langsamer" (durch Hardwareverwendung sollte es zB möglich sein mit einer langsameren Taktfrequenz hinzukommen).

aber die "$lib "YwRobot_Lcd_i2c.lib" für das LCD brauche ich, sonst tut sich da nichts.
Die brauchst Du nur, wenn Du die Standard-Bascom-Routinen für die LCD-Ausgabe zu verwenden. Du kannst die Bytes auch zu Fuß via I2Csend oder über I2Cwrite usw an den Portexpander schicken.

Kann man in Bascom die Konfiguration speichern, wenn man das Board und damit den Prozessor wechselt, oder muss man das immer manuell neu einstellen?
Diverse Defaults kannst Du in den Options einstellen, aber ich hab das alles lieber im Code.
Was meinst Du mit Board? Den Programmer? Zum flashen verwende ich BAscom GRUNDSÄTZLICH NICHT (sondern immer das AVR/Atmel Studio).
 

fredred

Mitglied
1 Okt 2015
76
2
7
Guten Tag,

Da es zum Thema passen könnte. Ein kleines Werkzeug um nicht nur PC Zeit mit USB an AVR zusenden.
Ist ein Beispiel für eine Uhr ohne externes RTC- Modul. Der AVR- Systemtakt ist doch genau genug für eine Uhr.
Zeit stellen wenn nötig mit PC oder kurzzeitigen Anschluss eines externen DCF77 Empfängers ist die Aufgabe.

Ist erkennbar, das mit diesem Werkzeug natürlich viele Parameter mit PC an Controller übergeben werden können, ohne diesen neu zu flashen. Die Excel-VBA und Bascom-Lösung soll nur eine Anregung sein und nicht als fertiges Projekt betrachtet werden, obwohl es funktioniert, gibt es bestimmt Verbesserungen, somit habe ich jegliche Programmierung auch für Desingns offen gelassen und Versucht im Code mit meinen Worten den Ablauf zu erklären. Mein Hauptproblem war die USB- Schnittstelle zuverlässig für alle Portvergaben zu realisieren. Da es da immer wieder neue Ereignisse je nach benutztem Steckplatz und verschiedene USB- Teilnehmer gibt, bezeichne ich dieses Projekt als funktionsfähig, obwohl einzelne Anpassungen im Userbereich nötig sein könnten(Stichwort „neue Hardware gefunden“)
Einzelheiten im Anhang. COM Endgeräte mit AVR Controller. doc

Hinweis:
Habe mich die größte Mühe gegeben Programme auf verschiedene Windowsanwendungen zu testen Natürlich nicht Kachelwindows 10 (Begründung im Projektanhang zu lesen.
Die Makros sind völlig harmlos und offen für eigene Änderungen.
Somit übernehme ich keinerlei Haftung wenn die notwendige Einstellung in Extras/Makro/Sicherheit gemacht wird.

1589205181986.png

Natürlich benötigen wir für Automatisierungen noch eine kleine Windows-System dll die muss einmalig geladen werden(kann mit Klick im Programm- Start erledigt werden) auch ein Button(USB- Deview zum Prüfen wie USB seine eigenwillige Vergabe der Anschlüsse organisiert) ist sehr hilfreich um Port zu erkennen(Tool wird nicht installiert ist aber sehr nützlich) Der Bascom- Code mit UDR ist so flexibel/einfach, dass die Parameterübergaben von PC mit vielen Terminalprogrammen mit einem Send File möglich ist. Mein bevorzugtes Free- Terminal steht mit ein Klick zu Verfügung.

Startseite habe ich so gestaltet. Beispielbild Uhr stellen und Anzeigemodus 2 für Kontrollergebnis

Bild01.jpg

Wichtigstes Merkmal ist die Einzelparametereingaben die immer mit einem Blockname beginnen sollte und natürlich die PC- Uhr mit AN/AUS und Button für Sendstring Übernahme.
Nach Klick auf COM- Starten so.

Bild02.jpg

Anweisungen stehen in Modul 1 zu Verfügung. Na da kann doch ein Programmierer sofort die Gemeinsamkeiten mit Bascom erkennen und hoffentlich noch ein paar Verbesserungen einbringen.

Declare Function OPENCOM Lib "RSCOM" (ByVal OpenString$) As Integer
Declare Sub TIMEOUTS Lib "RSCOM" (ByVal b%)
Declare Sub BUFFERSIZE Lib "RSCOM" (ByVal b%)
Declare Sub CLOSECOM Lib "RSCOM" ()
Declare Sub SENDBYTE Lib "RSCOM" (ByVal Dat%)
Declare Function READBYTE Lib "RSCOM" () As Integer
Declare Sub SENDSTRING Lib "RSCOM" (ByVal Dat$)
Declare Function READSTRING Lib "RSCOM" () As String
Declare Sub CLEARBUFFER Lib "RSCOM" ()
Declare Function INBUFFER Lib "RSCOM" () As Integer
Declare Function OUTBUFFER Lib "RSCOM" () As Integer
Declare Sub DTR Lib "RSCOM" (ByVal b%)
Declare Sub RTS Lib "RSCOM" (ByVal b%)
Declare Sub TXD Lib "RSCOM" (ByVal b%)
Declare Function CTS Lib "RSCOM" () As Integer
Declare Function DSR Lib "RSCOM" () As Integer
Declare Function RI Lib "RSCOM" () As Integer
Declare Function DCD Lib "RSCOM" () As Integer
Declare Function INPUTS Lib "RSCOM" () As Integer
Declare Sub TIMEINIT Lib "RSCOM" ()
Declare Function TIMEREAD Lib "RSCOM" () As Double
Declare Sub DELAY Lib "RSCOM" (ByVal ms As Double)
Declare Sub REALTIME Lib "RSCOM" ()
Declare Sub NORMALTIME Lib "RSCOM" ()

Mehr Infos und Code für diese Spielerei im Anhang.

Der Bascomcode funktioniert ab Mega 8 und so sieht ein Anzeigemodus aus.
Bild2.jpg
Der Bascomcode stellt auch den Sekundentakt als Sub für weitere Anwendungen zu Verfügung. Ist optimal wenn in einem Projekt der genaue Sekundentakt öfters benötigt wird.

Beispiel:
Sectic:
Dim T As Bit
Toggle T
If T = 0 Then Tex1 = "Tick"
If T = 1 Then Tex1 = "Tack"
Return

PC sendet Wert 7 der soll den Parameter 1 für Anzeigemodus erhalten.
Mit Anzeigemodus 1

Unruhe1.jpg

Mit freundlichen Grüßen
 

Anhänge

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)