Hallo an alle Ich möchte nun Daten vom PC zum AVR (Mega8) senden, um sie dort zu verarbeiten. Ich will eine Zahl einlesen und damit rechenen. Als UArt Lib wwill ich die Procyon Lib verwenden. Das senden verstehe ich und funktioniert auch Ich möchte am Terminal eine Zahl eingeben und nach einem ENTER, wird die Zahl zum AVR geschickt. Nur mit dem Senden komme ich nicht zurecht Mit uartReceiveByte() lese ich die Daten aus dem Receive Buffer aus, oder? Könnte mir da jemand das genauer erklären? zahl1 = uartreceiveByte(); Nun stehet in der Variable zahl1 der String, der gesendet wurde, oder?? Danach muss ich die Zahl mit atoi() umwandeln, oder? Das mit den Interupts verstehe ich auch nicht. Gibt es dazu kein Tutorial? Nun kann ich sie zum Rechnen weiterverwenden. Sehe ich das Richtig? Könnte mir da jemand helfen?? Danke im Voraus Gruß Robert
Nö. Obwohl deine Frage ziemlich komfus ist, versuche ich mal eine Antwort. Also mit dem Senden und Empfangen schickst du bloss Bytes hin und her. Was die Bytes darstellen, also Texte (Strings) oder Zahlen in irgendwelchen Formaten (Ganzzaghlen, Gleitkommzahlen) musst du entscheiden und im Empfänger auseinanderklamüstern. Mit atol() bist du schon auf dem richtigen Weg. diese Funktion wandelt einen Puffer aus Bytes in eine long Zahl. Du musst ggf. noch beachten, ob der puffer eine abschliessende Null haben muss oder nicht. Du musst dann die einzeln über uartreceiveByte() reinkommenden Bytes in einen Puffer schreiben und den Puffer mit atol in einen Zahl umwandeln. Üblicherweise legst du zuerst einen ausreichend grossen Pufferbereich an. Für eine long Zahl mit 4 Bytes etwa so unsigned char puffer[4]; Dann brauchst du eine Schleife, um die vier Bytes einzulesen. { int i; for (i=0; i < 4; i++) puffer[i] = uartreceiveByte(); } Dann holst du dir die Zahl aus dem Puffer. zahl = (<typ>) atol(puffer); Das klappt natürlich nur, wenn der Sender die Bytes genauso auf die Reise geschickt hat, dass atol was sinnvolles draus machen kann. Stichwort an dieser Stelle ist die Endianess. Dazu Findest du was in den Artikeln hier. Und wie <typ> ausdrücken soll, musst du dire klar sein, ob du nur mit positiven oder mit positiven+negativen Zahlen rechnen willst. Wenn du weisst, dass z.B. positive long Ganzzahlen gesendet werden und wenn die Endianess passt, kannst du die Zahl auch direkt zusammensetzen. Im Beispiel wird angenommen, dass das höchstwertige Byte zuerst gesendet wird { int i; unsigned long zahl = 0; for (i=0; i < 4; i++) { zahl *= 256; zahl += uartreceiveByte(); } ... hier kannst du mit zahl rechnen... }
Hallo Stefan Danke, erstmal. Ich hab nun einen Repeater geschrieben, der die Empfangen Zeichen am LCD Display ausgeben soll: #include <avr/io.h> #include <stdlib.h> #include "uart.h" #include "lcd.h" int main(void) { uartInit(); uartSetBaudRate(19200); lcd_init(LCD_DISP_ON); while(1) { lcd_putc(uartGetByte()); } } Jedoch bekomm ich immer eine Fehlermeldung beim Linken: > "make.exe" all -------- begin -------- avr-gcc (GCC) 3.4.3 Copyright (C) 2004 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Linking: main.elf avr-gcc -mmcu=atmega8 -I. -gstabs -DF_CPU=8000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=main.o -If:/Programme/AVRlib -std=gnu99 -MD -MP -MF .dep/main.elf.d main.o lcd.o uart.o --output main.elf -Wl,-Map=main.map,--cref -lm uart.o(.text+0x48): In function `uartInitBuffers': uart.c:71: undefined reference to `bufferInit' uart.o(.text+0x56):uart.c:73: undefined reference to `bufferInit' uart.o(.text+0xd2): In function `uartReceiveByte': uart.c:145: undefined reference to `bufferGetFromFront' uart.o(.text+0x144): In function `uartAddToTxBuffer': uart.c:187: undefined reference to `bufferAddToEnd' uart.o(.text+0x154): In function `uartSendTxBuffer': uart.c:196: undefined reference to `bufferGetFromFront' uart.o(.text+0x194): In function `__vector_13': uart.c:240: undefined reference to `bufferGetFromFront' uart.o(.text+0x208): In function `__vector_11': uart.c:277: undefined reference to `bufferAddToEnd' make.exe: *** [main.elf] Error 1 > Process Exit Code: 2 Was ist da los?? Ich versteh es nicht. Kann mein Repeater so funktionieren? Danke im Voraus Gruß Robert
Was ist da los? Dir scheint im Projekt (makefile) eine Quelldatei oder Library zu fehlen und der Linker kotzt. In der fehlenden Datei werden die Symbole `bufferInit' etc. angelegt. Wo hast du das makefile her? Selbstangelegt? Ich würde eine Textsuche nach diesen Begriffen über die Quelldateien machen und so herausfinden, wo diese Symbole definiert werden. Das Lesen der Doku der verwendeten UART Bibliothek wäre ein anderer Weg. Möglicherweise gibt es keine extra Datei dafür, sondern du musst diese Symbole im eigenen Quelltext anlegen. So funktioniert der "Repeater" wahrscheinlich nicht lang. LCD-Ausgabefunktionen sind typisch ziemlich spartanisch und das lcd_putc() wird nach 8, 16, 20, 40 ? Zeichen rechts am Anschlag stehen. Das direkte, ungefilterte Weitergeben der empfangenen Zeichen ist auch nicht doll. Wenn sauber Ascii-Zeichen ankommen, klappt das. Wenn Zeichen kommen, die Control-Zeichen fürs LCD sind, kann es knallen. Besser wäre es, wenn du die empfangenen Zeichen z.B. in eine Hex-Darstellung umformst. Also beim Empfang vom Byte 0xFF das umformen in zwei Ascii-Zeichen 'F''F'. So ein paar pro LCD Zeile ausgeben, dann die nächste Zeile, dann (bei zweizeiligem LCD) scrollen (Löschen, neu mit veränderter Zeile ausgeben).
Hallo Stefan Hier einmal meine Makefile: # Hey Emacs, this is a -*- makefile -*- #----------------------------------------------------------------------- ----- # WinAVR Makefile Template written by Eric B. Weddington, Jörg Wunsch, et al. # # Released to the Public Domain # # Additional material for this makefile was written by: # Peter Fleury # Tim Henigan # Colin O'Flynn # Reiner Patommel # Markus Pfaff # Sander Pool # Frederik Rouleau # #----------------------------------------------------------------------- ----- # On command line: # # make all = Make software. # # make clean = Clean out built project files. # # make coff = Convert ELF to AVR COFF. # # make extcoff = Convert ELF to AVR Extended COFF. # # make program = Download the hex file to the device, using avrdude. # Please customize the avrdude settings below first! # # make debug = Start either simulavr or avarice as specified for debugging, # with avr-gdb or avr-insight as the front end for debugging. # # make filename.s = Just compile filename.c into the assembler code only. # # make filename.i = Create a preprocessed source file for use in submitting # bug reports to the GCC project. # # To rebuild project do "make clean" then "make all". #----------------------------------------------------------------------- ----- # MCU name MCU = atmega8 # Processor frequency. # This will define a symbol, F_CPU, in all source code files equal to the # processor frequency. You can then use this symbol in your source code to # calculate timings. Do NOT tack on a 'UL' at the end, this will be done # automatically to create a 32-bit value in your source code. F_CPU = 8000000 # Output format. (can be srec, ihex, binary) FORMAT = ihex # Target file name (without extension). TARGET = main # List C source files here. (C dependencies are automatically generated.) SRC = $(TARGET).c SRC += lcd.c SRC += uart.c # List Assembler source files here. # Make them always end in a capital .S. Files ending in a lowercase .s # will not be considered source files but generated files (assembler # output from the compiler), and will be deleted upon "make clean"! # Even though the DOS/Win* filesystem matches both .s and .S the same, # it will preserve the spelling of the filenames, and gcc itself does # care about how the name is spelled on its command-line. ASRC = # Optimization level, can be [0, 1, 2, 3, s]. # 0 = turn off optimization. s = optimize for size. # (Note: 3 is not always the best optimization level. See avr-libc FAQ.) OPT = s # Debugging format. # Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs. # AVR Studio 4.10 requires dwarf-2. # AVR [Extended] COFF format requires stabs, plus an avr-objcopy run. DEBUG = stabs # List any extra directories to look for include files here. # Each directory must be seperated by a space. # Use forward slashes for directory separators. # For a directory that has spaces, enclose it in quotes. EXTRAINCDIRS = f:/Programme/AVRlib # Compiler flag to set the C Standard level. # c89 = "ANSI" C # gnu89 = c89 plus GCC extensions # c99 = ISO C99 standard (not yet fully implemented) # gnu99 = c99 plus GCC extensions CSTANDARD = -std=gnu99 # Place -D or -U options here CDEFS = -DF_CPU=$(F_CPU)UL # Place -I options here CINCS = #---------------- Compiler Options ---------------- # -g*: generate debugging information # -O*: optimization level # -f...: tuning, see GCC manual and avr-libc documentation # -Wall...: warning level # -Wa,...: tell GCC to pass this to the assembler. # -adhlns...: create assembler listing CFLAGS = -g$(DEBUG) CFLAGS += $(CDEFS) $(CINCS) CFLAGS += -O$(OPT) CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums CFLAGS += -Wall -Wstrict-prototypes CFLAGS += -Wa,-adhlns=$(<:.c=.lst) CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) CFLAGS += $(CSTANDARD) #---------------- Assembler Options ---------------- # -Wa,...: tell GCC to pass this to the assembler. # -ahlms: create listing # -gstabs: have the assembler create line number information; note that # for use in COFF files, additional information about filenames # and function names needs to be present in the assembler source # files -- see avr-libc docs [FIXME: not yet described there] # -listing-cont-lines: Sets the maximum number of continuation lines of hex # dump that will be displayed for a given single line of source input. ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs,--listing-cont-lines=100 #---------------- Library Options ---------------- # Minimalistic printf version PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min # Floating point printf version (requires MATH_LIB = -lm below) PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt # If this is left blank, then it will use the Standard printf version. PRINTF_LIB = #PRINTF_LIB = $(PRINTF_LIB_MIN) #PRINTF_LIB = $(PRINTF_LIB_FLOAT) # Minimalistic scanf version SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min # Floating point + %[ scanf version (requires MATH_LIB = -lm below) SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt # If this is left blank, then it will use the Standard scanf version. SCANF_LIB = #SCANF_LIB = $(SCANF_LIB_MIN) #SCANF_LIB = $(SCANF_LIB_FLOAT) MATH_LIB = -lm #---------------- External Memory Options ---------------- # 64 KB of external RAM, starting after internal RAM (ATmega128!), # used for variables (.data/.bss) and heap (malloc()). #EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff # 64 KB of external RAM, starting after internal RAM (ATmega128!), # only used for heap (malloc()). #EXTMEMOPTS = -Wl,--defsym=__heap_start=0x801100,--defsym=__heap_end=0x80ffff EXTMEMOPTS = #---------------- Linker Options ---------------- # -Wl,...: tell GCC to pass this to linker. # -Map: create map file # --cref: add cross reference to map file LDFLAGS = -Wl,-Map=$(TARGET).map,--cref LDFLAGS += $(EXTMEMOPTS) LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB) #---------------- Programming Options (avrdude) ---------------- # Programming hardware: alf avr910 avrisp bascom bsd # dt006 pavr picoweb pony-stk200 sp12 stk200 stk500 # # Type: avrdude -c ? # to get a full listing. # AVRDUDE_PROGRAMMER = stk200 # com1 = lpt1. Use lpt1 to connect to parallel port. AVRDUDE_PORT = lpt1 # programmer connected to serial device AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex #AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep # Uncomment the following if you want avrdude's erase cycle counter. # Note that this counter needs to be initialized first using -Yn, # see avrdude manual. #AVRDUDE_ERASE_COUNTER = -y # Uncomment the following if you do not wish a verification to be # performed after programming the device. #AVRDUDE_NO_VERIFY = -V # Increase verbosity level. Please use this when submitting bug # reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude> # to submit bug reports. #AVRDUDE_VERBOSE = -v -v AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY) AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE) AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER) #---------------- Debugging Options ---------------- # For simulavr only - target MCU frequency. DEBUG_MFREQ = $(F_CPU) # Set the DEBUG_UI to either gdb or insight. # DEBUG_UI = gdb DEBUG_UI = insight # Set the debugging back-end to either avarice, simulavr. DEBUG_BACKEND = avarice #DEBUG_BACKEND = simulavr # GDB Init Filename. GDBINIT_FILE = __avr_gdbinit # When using avarice settings for the JTAG JTAG_DEV = /dev/com1 # Debugging port used to communicate between GDB avarice simulavr. DEBUG_PORT = 4242 # Debugging host used to communicate between GDB avarice simulavr, normally # just set to localhost unless doing some sort of crazy debugging when # avarice is running on a different computer. DEBUG_HOST = localhost #======================================================================= ===== # Define programs and commands. SHELL = sh CC = avr-gcc OBJCOPY = avr-objcopy OBJDUMP = avr-objdump SIZE = avr-size NM = avr-nm AVRDUDE = avrdude REMOVE = rm -f COPY = cp WINSHELL = cmd # Define Messages # English MSG_ERRORS_NONE = Errors: none MSG_BEGIN = -------- begin -------- MSG_END = -------- end -------- MSG_SIZE_BEFORE = Size before: MSG_SIZE_AFTER = Size after: MSG_COFF = Converting to AVR COFF: MSG_EXTENDED_COFF = Converting to AVR Extended COFF: MSG_FLASH = Creating load file for Flash: MSG_EEPROM = Creating load file for EEPROM: MSG_EXTENDED_LISTING = Creating Extended Listing: MSG_SYMBOL_TABLE = Creating Symbol Table: MSG_LINKING = Linking: MSG_COMPILING = Compiling: MSG_ASSEMBLING = Assembling: MSG_CLEANING = Cleaning project: # Define all object files. OBJ = $(SRC:.c=.o) $(ASRC:.S=.o) # Define all listing files. LST = $(SRC:.c=.lst) $(ASRC:.S=.lst) # Compiler flags to generate dependency files. GENDEPFLAGS = -MD -MP -MF .dep/$(@F).d # Combine all necessary flags and optional flags. # Add target processor to flags. ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS) ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) # Default target. all: begin gccversion sizebefore build sizeafter end build: elf hex eep lss sym extcoff elf: $(TARGET).elf hex: $(TARGET).hex eep: $(TARGET).eep lss: $(TARGET).lss sym: $(TARGET).sym # Eye candy. # AVR Studio 3.x does not check make's exit code but relies on # the following magic strings to be generated by the compile job. begin: @echo @echo $(MSG_BEGIN) end: @echo $(MSG_END) @echo # Display size of file. HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex ELFSIZE = $(SIZE) $(TARGET).elf sizebefore: @if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); \ 2>/dev/null; echo; fi sizeafter: @if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); \ 2>/dev/null; echo; fi # Display compiler version information. gccversion : @$(CC) --version # Program the device. program: $(TARGET).hex $(TARGET).eep $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM) # Generate avr-gdb config/init file which does the following: # define the reset signal, load the target file, connect to target, and set # a breakpoint at main(). gdb-config: @$(REMOVE) $(GDBINIT_FILE) @echo define reset >> $(GDBINIT_FILE) @echo SIGNAL SIGHUP >> $(GDBINIT_FILE) @echo end >> $(GDBINIT_FILE) @echo file $(TARGET).elf >> $(GDBINIT_FILE) @echo target remote $(DEBUG_HOST):$(DEBUG_PORT) >> $(GDBINIT_FILE) ifeq ($(DEBUG_BACKEND),simulavr) @echo load >> $(GDBINIT_FILE) endif @echo break main >> $(GDBINIT_FILE) debug: gdb-config $(TARGET).elf ifeq ($(DEBUG_BACKEND), avarice) @echo Starting AVaRICE - Press enter when "waiting to connect" message displays. @$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \ $(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT) @$(WINSHELL) /c pause else @$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \ $(DEBUG_MFREQ) --port $(DEBUG_PORT) endif @$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE) # Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. COFFCONVERT=$(OBJCOPY) --debugging \ --change-section-address .data-0x800000 \ --change-section-address .bss-0x800000 \ --change-section-address .noinit-0x800000 \ --change-section-address .eeprom-0x810000 coff: $(TARGET).elf @echo @echo $(MSG_COFF) $(TARGET).cof $(COFFCONVERT) -O coff-avr $< $(TARGET).cof extcoff: $(TARGET).elf @echo @echo $(MSG_EXTENDED_COFF) $(TARGET).cof $(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof # Create final output files (.hex, .eep) from ELF output file. %.hex: %.elf @echo @echo $(MSG_FLASH) $@ $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ %.eep: %.elf @echo @echo $(MSG_EEPROM) $@ -$(OBJCOPY) -j .eeprom --set-section-flags .eeprom=alloc,load \ --change-section-lma .eeprom=0 -O $(FORMAT) $< $@ # Create extended listing file from ELF output file. %.lss: %.elf @echo @echo $(MSG_EXTENDED_LISTING) $@ $(OBJDUMP) -h -S $< > $@ # Create a symbol table from ELF output file. %.sym: %.elf @echo @echo $(MSG_SYMBOL_TABLE) $@ $(NM) -n $< > $@ # Link: create ELF output file from object files. .SECONDARY : $(TARGET).elf .PRECIOUS : $(OBJ) %.elf: $(OBJ) @echo @echo $(MSG_LINKING) $@ $(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS) # Compile: create object files from C source files. %.o : %.c @echo @echo $(MSG_COMPILING) $< $(CC) -c $(ALL_CFLAGS) $< -o $@ # Compile: create assembler files from C source files. %.s : %.c $(CC) -S $(ALL_CFLAGS) $< -o $@ # Assemble: create object files from assembler source files. %.o : %.S @echo @echo $(MSG_ASSEMBLING) $< $(CC) -c $(ALL_ASFLAGS) $< -o $@ # Create preprocessed source for use in sending a bug report. %.i : %.c $(CC) -E -mmcu=$(MCU) -I. $(CFLAGS) $< -o $@ # Target: clean project. clean: begin clean_list end clean_list : @echo @echo $(MSG_CLEANING) $(REMOVE) $(TARGET).hex $(REMOVE) $(TARGET).eep $(REMOVE) $(TARGET).cof $(REMOVE) $(TARGET).elf $(REMOVE) $(TARGET).map $(REMOVE) $(TARGET).sym $(REMOVE) $(TARGET).lss $(REMOVE) $(OBJ) $(REMOVE) $(LST) $(REMOVE) $(SRC:.c=.s) $(REMOVE) $(SRC:.c=.d) $(REMOVE) .dep/* # Include the dependency files. -include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*) # Listing of phony targets. .PHONY : all begin finish end sizebefore sizeafter gccversion \ build elf hex eep lss sym coff extcoff \ clean clean_list program debug gdb-config Also soll ich das empfangene Zeichen mit atoh in einen Hex Wert umwandeln. Wie kann ich den Wert dann in 2 Werte aufteilen?? Ich benutze ein 4 Zeiliges Display mit je 27 Zeichen (Pollin). Den Zeilenumbruch kann ich so mahcen: int main (void) { uint8_t zeile = 0; uint8_t zeichen = 0; while(1) { lcd_puts(empfangenesZeichen); zeichen++; if(zeichen == 26) { lcd_puts("\n"); zeichen = 0; zeile++; } if(zeile == 3) { lcd_clr(); lcd_home(); zeile = 0; } } Funktioniert das so? Danke im Voraus Gruß Robert
Das Listing vom Riesenmakefile ist hier nicht wichtig und schreckt mich vom Antworten ab. Wer findet da in dem Text noch die Frage? Dafür sind Dateianhänge gedacht. Schreib lieber woher du das makefile hast, ob du was daran geändert hast und warum bzw. warum nicht. Zurück zu den Grundlagen: In welcher Quelldatei werden die fehlenden Symbole angelegt? Das muss irgendwo in der verwendeten Bibliothek passieren (Suche im Quelltext) oder die verwendete Bibliothek verwendet eine weitere Bibliothek (Suche in der Doku). Ob die Zeilenumbrüche so funktionieren, hast du schneller ausprobiert, also ich mich in deinen Code reinversetzen kann. Setz vielleicht probeweise eine Schleife auf, die ein paar Zeichen ans LCD rausgibt und schau ob dein Zeilenumbruchcode damit zurechtkommt. Was meint die Doku der verwendeten LCD Bibliothek dazu? Hat die ein Autoscrollen, dann könnte der Code von dir klappen. Wenn kein Autoscrollen da ist, musst du mit irgendwelchen Positionsangaben arbeiten. Siehst du, wir diskutieren jetzt nicht mehr über das UART Empfangen oder die Umwandlung eines Textes in eine Zahl oder über fehlende Symbole sondern darüber wie man eine LCD Anzeige scrollt. Wo setzt du die Prioritäten?
Hallo Stefan Ich hab noch einmal die Makefile als Anhang anghängt. Ich kann den Beitrag nicht ändern, oder? Die Makefilevorlage hab ich aus dem I-net. Ich hab das ganze auf meinen Prgrammer (STK200) angepasst. Weiters hab ich den Namen der main angepasst, Taktfrequenz eingestellt und noch die 2 c Dateien (uart.c und lcd.c) für das Linken angehängt. Das LCD ist einmal Nebensache. Ich möchte einmal nur das die Daten beim AVR ankommen. Wann wird eine Zahl vom PC zum AVR gesendet?? Oder werden die Daten sofort nach einer Eingabe gesendet und ich muss die einzelnen Daten wieder zu einer Zahl zusammen setzten?? Dazu das Stichwort Endianess. Ich hab bei den Artiklen nichts gefunden :(. Ich hab dann aber gegoogelt. Avr implementiert die Daten als littel Endain, oder? Das heißt das niedrigste Byte wird auf der niedrigsten Adresse abgelegt. uint8_t i; unsigned long zahl = 0; for (i=0; i < 4; i++) { zahl *= 256; zahl += uartreceiveByte(); } Bei deiner Routine wird die Zahl zusammen gesetzt. Die Zahl wird zuerst mit 256 (1 Byte) multipliziert) damit dei Stellen passen, oder?? Wie funktioniert das gnaze aber dann mit Zahlen unter Null? Danke im Voraus? Gruß Robert
So wie ich das verstanden habe willst du eine Zahl als String an den AVR schicken. Dann geht aber das nicht mit for (i=0; i < 4; i++) { zahl *= 256; zahl += uartreceiveByte(); } sondern du musst die empfangenen Bytes in einen Puffer legen und den dann per atol(puffer) in zahl schreiben. Walter
Hallo Walter Achso. Als welchen Datentyp werden die Daten überhaupt über den UART empfangen?? char? uint8_t i; unsigned char puffer[4]; uint32_t zahl; for (i=0; i < 4; i++) { puffer[i] = uartGetByte(); ) zahl = atol(puffer); Kann das so funktionieren? Wann wird den das ganze übertragen? Gleich nach der Eingabe? Gruß Robert
ja, so geht's im Prinzip, allerdings sollte puffer noch eins größer sein und in den letzten char solltest du eine 0 schreiben damit atol auch zu einem richtigen Ende findet. Wie das ganze übertragen wird hängt von deinem Terminal bzw. Sendeprogramm ab, normalerweise wird der String erst mit der Return-Taste abgeschickt. Geschickter Weise sollte das ganze aber auch mit unterschiedlichen Stringlängen funktionieren, jetzt musst du ja immer 4-stellige Zahlen eintippen Grüße Walter
Robert sollte vielleicht festlegen/beschreiben, was er zu senden gedenkt. Wenn er auf dem PC ASCII-Zahlen eintippt und die direkt oder gepuffert mit ENTER als Text verschickt, kommen am µC als ASCII Zeichen an. Die kann er nach Zwischenpufferung auf dem µC mit atol() in eine Zahl umwandeln. Wenn er aus dem Sendeprogramm direkt eine Zahl/Variable als binäre Bytes verschickt, kann er - unter Berücksichtigung der Endianess und des Wertebereichs - die direkt zu einer Zahl zusammensetzen. Mein Beispiel funktioniert sehr wohl, man muss halt vorher mehr überlegen, was man überträgt. Das Einfügen der beiden Dateien uart.c und lcd.c ins makefile war anscheinend noch nicht ausreichend. Robert sollte die Doku der UART Bibliothek genau lesen. Ich kann es nur zu dritten Mal schreiben. Es kann eine zusätzliche Datei mit den Definitionen der fehlenden Funktionen im makefile fehlen. Es kann ein Selbstschreiben von Codeteilen im eigentlichen Programm notwendig sein... auch ein fehlendes DEFINE ist möglich... In der Doku wird auch stehen, was der Unterschied zwischen uartreceiveByte() und uartGetByte() ist. Zu 100% steht dort auch, wann ein Zeichen ankommt. Ganz besonders interessant ist, ob auf ein Zeichen gewartet wird oder nicht. Ob ein ENTER notwendig ist oder nicht, ist im wesentlichen Sache des Sendeprogramms auf dem PC. Man kann ein Terminalprogramm benutzen, welches nicht erst nach ENTER sendet (Bsp. Hyperterminal) oder eins, bei dem man erst einen Sendepuffer beschreibt und dann mit ENTER oder Send-Button losschickt (z.B. Br@y Terminal oder Hercules Terminal). Robert, hast du einen Link auf die verwendete UART Bibliothek parat? Zur Endianess kannst du dich bei http://www.mikrocontroller.net/articles/Digitaltechnik informieren.
Hallo an alle!! Ich möchte Erstmal nur ASCII Zeichen verschicken. Wie kann ich auf das letzte Zeichen im char Array eine 0 schreiben?? Eventuell mit einer Bitverschiebung nach links?? Als Terminal nehm ich den Hyperterminal von Windows. Wo ist der genaue Unterschied zwischen beiden Funktionen zum Empfang von Daten? Hier mal ein Auszug aus deer Bibliothek: 00193 //! Gets a single byte from the uart receive buffer. 00194 /// Returns the byte, or -1 if no byte is available (getchar-style). 00195 int uartGetByte(void); 00196 00197 //! Gets a single byte from the uart receive buffer. 00198 /// Function returns TRUE if data was available, FALSE if not. 00199 /// Actual data is returned in variable pointed to by "data". 00200 /// Example usage: 00201 /// \code 00202 /// char myReceivedByte; 00203 /// uartReceiveByte( &myReceivedByte ); 00204 /// \endcode 00205 u08 uartReceiveByte(u08* data); Ich benütze wie oben geschrieben die Procyon Lib: Hallo an alle!! Ich möchte Erstmal nur ASCII Zeichen verschicken. Wie kann ich auf das letzte Zeichen im char Array eine 0 schreiben?? Als Terminal nehm ich den Hyperterminal von Windows. Ich benütze die Procyon Lib: http://hubbard.engr.scu.edu/embedded/avr/avrlib/docs/html/ Danke im Voraus Gruß Robert Danke im Voraus Gruß Robert
> letztes Zeichen 0 puffer[irgendeineposition] = 0; Du kannst auch jedes Mal wenn du ein Zeichen in den Puffer schreibst, das nächste Zeichen auf 0 setzen. Dann ist der Puffer stets schön abgeschlossen. puffer[i++] = nutzzeichen; puffer[i] = 0; > uartGetByte() und uartReceiveByte() Beide Funktionen warten nicht auf ein Zeichen. Damit funktionieren alle Beispiele oben nicht. Du musst immer abfragen, ob ein Zeichen empfangen wurde, bevor du eine Auswertung bzw. Kopieroperation machst. uartGetByte() liefert als Rückgabewert -1, wenn kein Zeichen empfangen wurde bzw. 0 bis 255 für das empfangene Zeichen. uartReceiveByte() liefert als Rückgabewert TRUE, wenn ein Zeichen empfangen wurde und FALSE, wenn nicht. Wenn ein Zeichen empfangen wurde, wird es an die Adresse kopiert, die im Funktionsargument angegeben ist. > Fehlende Dateien im Makefile Mindestens buffer.c fehlt.
Hallo Stefan Danke, das mit der Erklärun des Arrys.. Super!! Wenn ich uartReceiveByte() arbeite, muss ich warten bis ein Byte empfangen ist oder?? Kann das so funktionieren: if(uartReceiveByte(&testarray) == TRUE) lcd_puts(testarray); Danke im Voraus Gruß Robert
> if(uartReceiveByte(&testarray) == TRUE)
Ick. Das sind Wahrheitswerte, die sollte man in einer
if-Anweisung dann auch direkt testen:
if (uartReceiveByte(&testarray))
...
Wenn es echt ein test*array* ist ala char testarray[ARRAYGROESSE]; geht das Beispiel schief. Du solltest in dem Fall die Adresse des einzelnen Elements übergeben (i bspw. als Zähler für Arrayüberlauf etc.) ala if (uartReceiveByte(&testarray[i])) lcd_puts (testarray[i]);
Hallo an alle So ich hab das ganze Jetzt einmal getstet. Es kommen auf jedenfall Daten am µC an und werden auch über das LCD ausgegeben. Das Scrollen nach meiner Methode funktioniert auch super. Leider werden aber nicht die richtigen Zeichen dargestellt. Wenn ich zB die Taste "1" drücke wird ein "b" oder ein "r" dargestellt. Das ist bei den meisten Tasten so, dass zwei Zeichen dargestellt werden können Was ist da los? Am normalen Maschinschreibblock der Tastatur sind meisten nur irgenwelche zeichen. Was ist da los?? Die Daten werden bei mir aber jetzt sofort nach dem Tastendruck gesendet. Nicht nach einem Return. Wie kann ich das im Hyperterminal änderen?? Oder ist es sinnvoller auf einen nicht Windows Terminal auszuweichen?? Im Anhang hab ich derzeit meine Source File angehängt Ich hoffe ihr könnt mir helfen Danke im Voraus Gruß Robert
i ist beim Eintritt in die while(1) Schleife undefiniert. Wohin das erste Zeichen gespeichert wird, ist wie Lotto. Irgendwo in einen 256 Zeichen grossen Bereich... Hoffentlich liegt da nichts wichtiges. Also, wie bei zeichen und zeile gemacht, sauber initialisieren. uint8_t i = 0; Oder überlegen, was du programmieren willst. Denn das Array benutzt du gar nicht. Du könntest stattdessen auch mit einer einfachen Variablen arbeiten. Dann fällt auch i weg. char meinchar; ... if (uartReceiveByte(&meinchar)) { lcd_putc(meinchar); ... Wo stammt die LCD Library her? Kontrolliere, ob die Funktionsparameter stimmen. Doku lesen. Und die Procyon AVRlib hat auch LCD Funktionen mit dem entsprechenden lcd.h - nicht dass du die falsche Includedatei einbindest und für die verwendeten lcd-Funktionen die keine Prototypen hast. Die Baudrate soll also 19200 sein. Das klappt nur, wenn F_CPU korrekt definiert ist, weil die Library daraus die Einstellungen der UART berechnet. Mit welcher Taktrate läuft dein µC und ist F_CPU mit den 8 MHz im makefile richtig definiert? Und wie sind die anderen Daten? Wieviele Datenbits, welche Parity, wieviele Stopbits? Ich finde in der Doku nichts dazu und nehme an es wird das gängige 8n1 benutzt. Genau steht das in der Doku vom verwendeten µC. Ist das auf der PC Gegenseite auch so eingestellt? Dran denken, wenn man auf PC Seite die Übertragungsparameter ändert, die Schnittstelle zu machen (Disconnect) und dann neu zu öffnen (Connect), damit die Änderung auch von der Hardware übernommen wird. Für das Senden mehrerer Bytes auf Tastendruck (ENTER) brauchst du ein anderes Terminalprogramm als Hyperterminal.
Hallo an alle Es funktioniert nun so einigermaßen :-) ICh hab ein anderes Terminalprogramm genommen(Bray) und auf einmal ging alles. Ka warum??? Baudrate hab ich richtig eingestellt, denn das senden hat funktioniert. Dieser Terminal sendet jedoch auch gleich nach der Eingabe. Kennt jemand einen Terminal, der nach einem Return sendet?? Nicht ASCII konforme Zeichen auf der Tastatur, werden natürlich nicht richtig dargestellt aber das ist ja normal, oder?? Das sind aber jetzt immer ASCII Zeichen die gesendet werden. Wie geht das nun genaau wenn ich das ganze als Zahl in eine Variable abspeichern will. char puffer[6] = '000000'; uint16_t zahl; uint8_t i; for(i=0; 1<6; i++) { puffer[i] = 0; if(uartReceiveByte(&puffer[i++] } zahl = atol(puffer); Kann das so funktionieren?? Ich weiß ich bin ein Noob... Danke im Voraus Gruß Robert
Dein Puffer muss ein Element mehr Platz haben, als die Anzahl Ziffern, die du reinspeichern willst. Den zusätzlichen Platz braucht das abschliessende Nullbyte. Du kannst den Puffer so als Array von chars anlegen: char puffer[7] = { '0', '0', '0', '0', '0', '0', 0 }; oder so mit automatischen Anhängen der Null an einen String. char puffer[7] = "000000"; Ich würde beides nicht machen. uint16_t zahl; uint16_t geht bis max. 65000 und ein paar Zerquetschte. D.h. nicht alle sechsstelligen Zahlen passen hier rein. Genaugenommen passen sehr viel mehr nicht rein als reinpassen. uint8_t i; for(i=0; 1<6; i++) { puffer[i] = 0; if(uartReceiveByte(&puffer[i++] } zahl = atol(puffer); ist Quatsch (1<6) und die Hälfte fehlt (Abschluss der if-Bedingung und der ganze if-Anweisungsblock). Die for-Schleife kannst du so nicht nehmen, weil die nach sechs Runden ohne Empfang immer zu Ende ist. Daran denken uartReceiveByte() wartet nicht auf Zeichen. Du musst solange Runden drehen, bis der Puffer voll ist oder eine andere Eingabe als eine Ziffer kommt. uint32_t zahl; uint8_t i; /* Es werden max. sechsstellige positive Zahlen übertragen */ i = 0; puffer[i] = 0; /* Initialisierung vom Puffer */ do { /* Zeichen da? */ if (uartReceiveByte(&puffer[i])) { /* ja Zeichen ist da */ /* Ist eine Ziffer reingekommen? */ if (puffer[i] >= '0' && puffer[i] <= '9') { /* Ja war Ziffer */ puffer[++i] = 0; /* Puffer hinter Eingabe abschliessen */ } else { /* Nein war keine Ziffer, d.h. Ende der Zahleneingabe */ /* Empfangenes Zeichen ausnullen + so Puffer abschliessen */ puffer[i] = 0; break; /* do-while Schleife abbrechen */ } } } while (i < 6); zahl = (uint32_t) atol(puffer);
Hey Stefan Dein Code ist echt super. DANKE :-) So ist es echt verständlich erklärt. Bei mir ist es so, dass ich am meisten verstehe, wenn ich einen Code vor mir habe. Ich werde das am NAchmittag mal in der Art testen freu Danke Stefan Gruß Robert
HAllo Hab schon wieder eine Frage. Zahlen einlesen funktioniert. Mein "Repeater" funktioniert auch. Ich bin gerade am proggen eines kleinen Rechners. Jedoch komme ich bei der Eingabe der Operation überhaupt nicht zusammen. Ic knoble schon seit gestern am Nachmittag daran und finde noch immer keine Lösung :( .. . int getchar (void) { char buffer; if(uartReceiveByte(&buffer)); return(buffer); } . . . char mainpuffer; . . do { mainpuffer = getchar(); } while((mainpuffer != '+') || (mainpuffer != '*')); Hier mal das Programm. uartReceiveByte() wartet ja nicht auf eine Eingabe. Darum muss ich eine Warteschleife einbauen, oder? Jedoch funktioniert das ganz so wich progge nicht. Was ist da los?? Das Zeichen in mainpuffer verwende ich danach in einer switch - case Abfrage weiter ICh hoffe, jemand kann mir helfen. Danke im Voraus Gruß Robert
Warteschleife ist richtig, aber da sind mehrere Böcke drin. Für den Fall dass nichts empfangen wurde, ist der Inhalt von buffer nicht festgelegt zumal buffer ja auch nicht initialisiert wird. Es kann im ungünstigsten Fall was sein, mit dem du an der Stelle gar nicht gerechnet hast. So wie du es jetzt programmiert hast, wird der Fall nicht abgefangen. getchar() liefert einen Wert zwischen -127 und 127. Yes, negative Zahlen, weil du buffer als char deklariert hast. Und schau dir die Zeile mit dem if ganz genau an. Wo steht das ; und was bedeutet das? Du würdest dich beim Rückgabewert vom getchar() besser an uartReceiveByte() orientieren. Also -1 zurüeckgeben, wenn nix da war und 0 bis 255, wenn ein Zeichen da war. Aber wenn ein fortgeschrittener Programmierer getchar() liest, erwartet er die gleiche Funktion der gleichnamigen Funktion aus der C Standardbibliothek. Du kannst ein eigenes getchar() schreiben, solltest dich aber an der Standardfunktion bzw. was geht dort rein, was geht raus orientieren. Wartet das normale getchar(), wenn ja, dann die eigene Funktion auch wartend programmieren... Abgesehen davon, dass es bei Namensgleichheit Fehlermeldungen hagelt, wenn du Includefiles der Standardlibrary einbindest. Kurz - ich würde meine Funktion eher my_getchar(), uart_getchar() oder sonstwie nennen. int uart_getchar(void) { unsigned char buffer = '#'; // erleichtert das Debuggen ;-) if (uartReceiveByte(&buffer)) return buffer; // Zeichen 0x00..0xFF empfangen else return -1; // kein Zeichen empfangen } Check nochmal die Bedingung in der do-while Schleife bzw. achte auf die Warnings vom Compiler. Ist die Bedingung nicht immer wahr, auch wenn ein + oder ein * reinkommt? Noch ein Tipp: Sei verschwenderisch mit Kommentaren. Viele Probleme sieht man erst, wenn man sich und anderen umgangssprachlich formuliert, was die Maschine machen soll. Du ahnst nicht, wieviel ich bei dem Kommentieren wieder ändere. Und das Reindenken von Dritten ist bei kommentiertem Code sowieso einfacher.
Hallo Stefan Danke wiedereinmal ;-) Compilerwarnungen bekomm gar keine. Leider springt er aber nie aus der Schleife heraus. do { mainpuffer = uart_getchar(); } while((mainpuffer != '+') || (mainpuffer != '*')); Warum ist das so?? Ich frage doch ab, ob in der Variable mainpuffer ein + ODER ein * steht. Normal muss er ja wenn uart_getchar ein + oder * liefert aus der Schleife aussteigen. Danke om Voraus Gruß Robert
while((mainpuffer != '+') || (mainpuffer != '*')); ist ja auch IMMER erfüllt! Wenn mainbuffer == '+' ist, dann ist es != '*', also die abbruchbedingung NICHT erfüllt. Und umgekehrt.
> Ich frage doch ab, ob in der Variable mainpuffer ein + ODER ein * > steht. Nein das tust du eben nicht. while((mainpuffer != '+') || (mainpuffer != '*')); wird solange wiederholt, wie mainpuffer nicht gleich '+' enthaelt oder mainpuffer nicht gleich '*' enthaelt. Nun, wenn mainpuffer gleich einem '+' ist, dann ist es immer noch ungleich einem '*'. Damit ist die Bedingung aber wahr (da ODER), und auf gehts in die naechste Runde. De-Morgan NICHT ( A ODER B ) <==> ( NICHT A ) UND ( NICHT B ) NICHT ( A UND B ) <==> ( NICHT A ) ODER ( NICHT B ) d.h. du hats 2 Moeglichkeiten while( !( mainpuffer == '+' || mainpuffer == '*' ) ); das entspricht so ziemlich genau dem, was du umgangssprachlich von dir gibst: Wiederhole solange, solange gilt, dass mainpuffer nicht entweder '+' oder '*' enthaelt. Oder du wendest De-Morgan an: while( mainpuffer != '+' && mainpuffer != '*' );
Hallo ihr beiden Danke, wenn man es so sieht ist es ja logisch... Da meine lcd_put_d() (Funktion zur Darstellung von ganzen Zahlen am LCD) itoa() nutzt, kann ich damit nur maximal die Zahl 32767 darstellen. Daher hab ich eine eigene Routine für uint32 Zahlen geschrieben: int lcd_put_uint32(uint32_t data) { char string[11]; ultoa(data, string, 10); lcd_puts(string); return(0); } Mit der jetzigen Routine zum Einlesen der Zahlen kann ich ja maximal 6-stellige positive Zahlen einlesen (also 666666). Leider kann damit maximal die Zahl 32767 (int16) einlesen. Warum ist denn das so??? Zuerst hab ich gedacht, dass es meine Routine zum Anzeigen von 32 Bit Variablen einen Fehler hat, aber das Ergebnis wird richtig angezeigt (auch wenn es größer als 32767 ist). Im Anhang hab ich meine main Danke im Voraus Gruß Robert
Das passt nicht: int getzahl (void) // Rückgabe int -32768 bis 32767 { uint8_t i = 0; char puffer[7]; uint32_t zahl; // unsigned long 0 bis 4294967295 ... zahl = (uint32_t) atol (puffer); return(zahl); // Schnipp! Schnapp! } Spuckt der Compiler da kein Warning aus?
Hallo Stefan Compilerwarnungen hat es keine gegeben. Ich habs nun geändert in uint32_t getzahl(); :-) Danke Stefan Gruß Robert
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.