- LiFePO4 Speicher Test         
Seite 3 von 3 ErsteErste 123
Ergebnis 21 bis 23 von 23

Thema: USI interface an tiny 2313

  1. #21
    Anzeige

    Praxistest und DIY Projekte
    Hallo,
    auch ich habe noch eine Frage:

    Zitat Zitat von linux_80 Beitrag anzeigen
    Den Ausgangspuffer nur so gross, wie die Anzahl Bytes die auf einmal zum Master übertragen werden sollen. Damit es keine "alten" Daten gibt. Dann Regelmässig diese mit den entsprehenden Daten füllen, aber nur überschreiben, wenn der Master nicht grad am lesen des Puffers ist.
    Aber es wird doch nur das erste Byte aus dem Array gesendet, oder habe ich im Assemblercode (der mir zugegebenermaßen nicht wirklich vertraut ist) irgendwas übersehen?

    Code:
    '// ----- Master write data mode ------
    '// Check reply and goto USI_SLAVE_SEND_DATA if OK, else reset USI.
    'case USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA:
    Isr_ovf_check_rep_from_send_data:     'r24 = Usi_twi_overflow_state
    cpi r24, Usi_check_reply_from_send_data        'case Usi_check_reply_from_send_data ?
    brNe Isr_ovf_slave_send_data          'no -> jmp to next case
    
         'if ( USIDR ) // If NACK, the master does not want more data.
          in r24, USIDR
          !and r24, r24
          breq Isr_ovf_req_rep_from_send_data_1    'jmp slave_send_data if Master send a ACK (send next byte)
    
          'SET_USI_TO_TWI_START_CONDITION_MODE()
       Isr_ovf_set_usi_start_cond_mode:
          ldi r24, Usicr_start_mode
          !out USICR, r24    'USICR = Usicr_start_mode
          ldi r24, Usisr_send_or_read_data
          !out USISR, r24    'USISR = Usisr_send_or_read_data
    
          LDI r24, Usi_start_condition_mode
          sts {Usi_twi_overflow_state}, r24        'USI_TWI_Overflow_State = Usi_start_condition_mode
    
          rjmp ISR_OVF_end   'break
    
    'case USI_SLAVE_SEND_DATA
    Isr_ovf_slave_send_data:              'r24 = Usi_twi_overflow_state
    cpi r24, Usi_send_data   'case Usi_send_data ?
    brNe Isr_ovf_req_rep_from_send_data   'no -> jmp to next case
    
    Isr_ovf_req_rep_from_send_data_1:
          '// Get data from Buffer
          lds r24, {Twi_txhead}           '// Pointer  Twi_txhead
          Loadadr Twi_txbuf(1) , Z        'R31:R30
          ldi r31, &H00      'paranoia
          add r30, r24       'add index
          adc r31, r1        'add carry
          ld r24, Z
          !out USIDR, r24    'USIDR = TWI_TxBuf[Twi_txhead]
    
          '//incr and mask pointer
          lds r24, {Twi_txhead}
          subi r24, &HFF     ' incr Twi_txhead
          andi r24, Twi_tx_buffer_mask    ' mask pointer
          sts {Twi_txhead}, r24           'Twi_txhead = ( Twi_txhead + 1 ) & TWI_TX_BUFFER_MASK
    
          ldi r24, Usi_request_reply_from_send_data
          sts {Usi_twi_overflow_state}, r24        'USI_TWI_Overflow_State = USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA
    
          'SET_USI_TO_SEND_DATA()'
          SBI DDR_USI, PIN_SDA            'DDR_USI  |=  (1<<PORT_USI_SDA) // Set SDA as output
          ldi r24, Usisr_send_or_read_data
          !out USISR, r24    'USISR=Usisr_send_or_read_data
          rjmp ISR_OVF_end   'break
    
    '// Set Usi To Sample Reply From Master. Next Usi_slave_check_reply_from_send_data
    'case USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA:
    Isr_ovf_req_rep_from_send_data:       'r24 = Usi_twi_overflow_state
    cpi r24, Usi_request_reply_from_send_data      'case Usi_request_reply_from_send_data ?
    brNe Isr_ovf_slave_request_data       'no -> jmp to next case
    
          ldi r24, Usi_check_reply_from_send_data
          sts {Usi_twi_overflow_state}, r24        'Usi_twi_overflow_state = Usi_slave_check_reply_from_send_data
    
          'SET_USI_TO_READ_ACK()'
          CBI DDR_USI, PIN_SDA            'DDR_USI  &= ~(1<<PORT_USI_SDA) // Set SDA as input
          !out USIDR, r1     'USIDR = 0
          ldi r24, Usisr_send_or_read_ack
          !out USISR, r24    'USISR = Usisr_send_or_read_ack
          rjmp ISR_OVF_end   'break
    Code:
    Loadadr Twi_txbuf(1) , Z
    bedeutet doch, dass immer nur das erste Byte gelesen und gesendet wird (wegen TWI_txbuf(1)).
    Könnte man da nicht eine Variable einsetzen, die im Array hochzählt, z.B. TWI_txhead ?
    TWI_txhead wird doch immer wieder um 1 erhöht. Ich verstehe aber nicht was danach geschieht.
    Danach wird doch gesendet, und das ACK oder NACK abgewartet?
    Der Slave reagiert aber nicht darauf sondern beendet die ISR, indem er nach ISR_OVF_end springt.

    Hab ich das so richtig verstanden und wie sähe es aus, wenn man nach erfolgreichem Abfragen des ACK
    wieder in die Senderoutine springt, nur mit erhöhtem Pointer/TWI_txhead?

    Leider kenne ich mich nicht so gut mit Assembler aus, es wäre nett wenn mir jemand ein paar Tipps geben könnte.
    Paul

  2. #22
    Keiner eine Idee?

  3. #23

    Anpassung mit Interruptroutine

    Hallo!
    ich hab es jetzt geschafft, den Code zu verstehen (yeaah!).
    Auch wenn es ein bisschen gedauert hat, der Attiny44 sendet und empfängt jetzt.

    Der Assembler-Code ist weitgehend gleich geblieben, belegt also immer noch weniger als 500 Byte (inkl. Testprogramm in Basic 522 Bytes).
    Der einzige Unterschied ist, dass es nur noch eine TX/RX-Variable gibt anstatt einem Array und nach jedem erfolgreichen Empfang eine Routine aufgerufen wird, in der die Variable sofort verarbeitet werden muss!

    Im wesentlichen ist der Vorteil (für mich), dass man nicht ständig auf empfangene Werte prüfen muss oder ob man das Sendearray gerade füllen darf, sondern empfangene/zu sendende Werte selbst aus/in Arrays usw. holen/füllen kann und dass der Controller sofort benachrichtigt wird, wenn er Werte erhält, was für meine Anwendung als Slave besser ist.

    Den Assembler Code habe ich wegen der Übersichtlichkeit aufgeteilt und füge ihn mit "$include" ein.

    Haupteil:
    Code:
    '######################################################
    'Author = Paul B., I just changed the Code from roboternetz.de
    'https://www.roboternetz.de/community/threads/22452-USI-interface-an-tiny-2313
    '
    'Description: I2C-slave with USI-Interface
    'Notes:       You must set the Usi-port and the pin-number of Sda and Scl
    '             The code was tested with a frequency of 100kHz and 400kHz
    '             it works in interrupt mode, so the labels below are called when
    '             the master wants to transmit or receive Data
    '######################################################
    $regfile = "attiny44.dat"
    $crystal = 8000000
    $hwstack = 40
    $swstack = 32
    $framesize = 60
    
    
    'parameters set by user (usi port, address and buffer size)
    '##########################################################
    Const Twi_ownaddress = &H56             'this is the real write-adress, not 2*twi_ownadress as in the previous code
    'It must be a number which is divisible by 2 without a leftover
    
    Const Ddr_usi = Ddra
    Const Port_usi = Porta
    Const Pin_usi = Pina
    Const Pin_sda = 6
    Const Pin_scl = 4
    
    'I saved the code as an extra file, so i can include it
    $include "USI_Slave_neededcodebeforemainloop.bas"
    
    
    'My Sample Code
    
    Config Porta.0 = Output
    Led1 Alias Porta.0
    Led1 = 0
    Config Porta.1 = Output
    Led2 Alias Porta.1
    Led2 = 0
    
    Dim I As Byte
    I = 0
    
    '############# Main Loop #############
    Gosub Usi_twi_slave_initialise
    'Interrupts must be enabled as the code works in interrupt mode
    Enable Interrupts
    
    Do
    Waitms 500
    'Usi_start_flag is set when I2Cstart was received
    Loop
    End
    
    'Routines for USI, must be included after the main loop
    $include "USI_Slave_routines.bas"
    
    
    'If the master wants to receive a byte, you must store it in Twi_tx
    I2c_master_needs_byte:
    Twi_tx = I
    I = I + 1
    Toggle Led2
    Goto After_master_needs_byte
    
    'If the master transmitted a byte, it will be stored in Twi_rx
    I2c_master_has_byte:
    If Twi_rx = 16 Then Toggle Led1
    Goto After_master_has_byte
    Initialisierung und setzten der Konstanten (USI_Slave_neededcodebeforemainloop.bas):
    Code:
    $nocompile
    '********* Initialise USI ****************************
    
    'USICR => USISIE|USIOIE|USIWM1|USIWM0   USICS1|USICS0|USICLK|USITC     (USICR = &H0d)
    Const Usicr_start_mode = &B1010_1000    'Set USI in Two-wire mode. No USI Counter overflow prior
                  'to first Start Condition (potentail failure), Shift Register Clock Source = External, positive edge
    Const Usicr_isr_start = &B1111_1000     'like above with Counter Overflow ISR
    
    'USISR => USISIF|USIOIF|USIPF|USIDC     USICNT4|USICNT2|USICNT1|USICNT0    (USISR = &H0e)
    Const Usisr_isr_start = &B1111_0000     'set USI to shift 8 bits and clear "Start Condition Interrupt Flag"
    Const Usisr_send_or_read_data = &B0111_0000       'set USI to shift 8 bits
    Const Usisr_send_or_read_ack = &B0111_1110       'set USI to shift 1 bits
    
    Dim Twi_slaveaddress As Byte
    
    Dim Twi_rx As Byte
    Dim Twi_tx As Byte
    
    Dim Usi_twi_overflow_state As Byte      'state machine
    Const Usi_start_condition_mode = &H00
    Const Usi_check_address = &H01
    Const Usi_send_data = &H02
    Const Usi_request_reply_from_send_data = &H03
    Const Usi_check_reply_from_send_data = &H04
    Const Usi_request_data = &H05
    Const Usi_get_data_and_send_ack = &H06
    
    '********* Initialise ISR ****************************
    On Usi_start _isr_usi_start Nosave      'Interrupt NOSAVE_ISR!
    Enable Usi_start
    
    On Usi_ovf _isr_usi_ovf Nosave          'Interrupt NOSAVE_ISR!
    Enable Usi_ovf
    
    '********* Main Loop Variables  ****************************
    Dim Usi_start_flag As Byte
    Routinen (USI_Slave_routines.bas):
    Code:
    $nocompile
    '********* Initialise USI for TWI Slave mode ****************************
    '---------------------------------------------------------------
    'Subroutine: Usi_twi_slave_initialise
    'Purpose:    Initialise USI for TWI Slave mode
    '            set I2C Address to TWI_ownAddress
    'Result:
    '---------------------------------------------------------------
    Usi_twi_slave_initialise:
      Twi_slaveaddress = Twi_ownaddress / 2
    
      SBI PORT_USI, PIN_SCL                 'PORT_USI |=  (1<<PORT_USI_SCL) // Set SCL high
      SBI PORT_USI, PIN_SDA                 'PORT_USI |=  (1<<PORT_USI_SDA) // Set SDA high
      SBI DDR_USI, PIN_SCL                  'DDR_USI  |=  (1<<PORT_USI_SCL) // Set SCL as output
      CBI DDR_USI, PIN_SDA                  'DDR_USI  &= ~(1<<PORT_USI_SDA) // Set SDA as input
    
      Usicr = Usicr_start_mode              'USICR = Usicr_start_mode // Enable Start Condition Interrupt. Disable Overflow Interrupt
      Usisr = Usisr_isr_start               'USISR = Usisr_isr_start // Clear all flags and reset overflow counter
    
      Usi_twi_overflow_state = Usi_start_condition_mode       'USI_TWI_Overflow_State = Usi_start_condition_mode
    Return
    
    
    '********* ISR USI_START (Interrupt Service Routine )****************************
    '---------------------------------------------------------------
    'Subroutine: _isr_USI_START
    'Purpose:    Usi start condition ISR
    '            Detects the USI_TWI Start Condition and intialises the USI
    '            for reception of the "TWI Address" packet.
    'Note:       Start Condition Interrupt Flag will _only_ be cleared by writing
    '            a logical one to the USISIF bit.
    '            A start condition interrupt will wakeup the processor from all sleep modes.
    '            Corrected the STOP CONDITION BUG in AVR312 => while ((PIN_USI & (1<<PORT_USI_SCL)) & !(tmpUSISR & (1<<USIPF)))
    'Stack use:  2 byte registers + 2 byte address
    '---------------------------------------------------------------
    _isr_usi_start:
       push r24
       in r24, SREG
       push r24
    
    'Usi_start_flag ist 1 wenn eine start condition empfangen wurde
       LDI r24, 1
       sts {Usi_start_flag}, r24            'detect _isr_USI_START in main loop
    
    'Die State Maschine wird auf CheckAdress gesetzt damit in der_isr_usi_ovf die Adresse geprüft wird
       LDI r24, Usi_check_address           '//Set default starting conditions for new TWI package
       sts {Usi_twi_overflow_state}, r24    'USI_TWI_Overflow_State = Usi_check_address
       CBI Ddr_usi,Pin_sda                  'DDR_USI  &= ~(1<<PORT_USI_SDA) // Set SDA as input
    
    _isr_usi_loop:                          'while (PIN_USI & (1<<PORT_USI_SCL))
       IN R24, Pin_usi                      '//wait until SCL is LOW, avoid counting the first level change
       sbrs r24, Pin_sda                    ' if (PIN_USI & (1<<PORT_USI_SDA))...
       rjmp _isr_usi_no_stop
    'wenn ein Stop empfangen wird, USI zurücksetzen und ISR verlassen
            ldi r24, Usicr_start_mode       '//... a Stop condition arises and ...
            !out USICR, r24                 'Usicr =Usicr_start_mode
            rjmp _isr_usi_end               '//... then leave the interrupt to prevent waiting forever.
    'ansonsten wird USI auf start gesetzt -> Das empfangene Adress Byte wird in das USIDR geschoben
    _isr_usi_no_stop:
       sbrc r24, Pin_scl
       rjmp _isr_usi_loop
    
       ldi r24, Usicr_isr_start             'USICR = Usicr_isr_start
       !Out USICR , R24
    _isr_usi_end:
       ldi r24, Usisr_isr_start             'USISR = Usisr_isr_start
       !Out USISR , R24
    
       pop r24
       !Out SREG , R24
       pop r24
    Return                                  'RETI
    
    
    '********* ISR USI_OVF (Interrupt Service Routine )****************************
    '---------------------------------------------------------------
    'Subroutine: _isr_USI_OVF
    'Purpose:    USI counter overflow ISR
    '            Handels all the comunication.
    '            Is disabled only when waiting for new Start Condition.
    'Stack use:  5 byte registers + 2 byte address
    '---------------------------------------------------------------
    _isr_usi_ovf:
       push r1
       in r1, SREG
       push r1
       eor r1, r1                           'R1 = 0 !
       push r24
       push r30
       push r31
    
    'switch (USI_TWI_Overflow_State)
    lds r24, {Usi_twi_overflow_state}
    
    '// ---------- Address mode ----------
    '// Check address and send ACK (and next USI_SLAVE_SEND_DATA) if OK, else reset USI.
    'case USI_SLAVE_CHECK_ADDRESS:
    'prüfen, ob state machine auf CheckAdress steht
    Isr_ovf_slave_check_address:            'r24 = Usi_twi_overflow_state
    cpi r24, Usi_check_address              'case Usi_check_address ?
    brNe Isr_ovf_check_rep_from_send_data   'ansonsten nächsten status prüfen
    
          'if ((USIDR == 0) || (( USIDR>>1 ) == Twi_slaveaddress))    'check also (TWI-ADDRESS==0)
          in r24, USIDR
          !and r24, r24
          breq Isr_ovf_get_valid_address    'we get a read/write address
             in r24, USIDR                  'Die Soll- und ist-Adresse werden in r30 bzw r24 geladen...
             lsr r24
             lds r30, {Twi_slaveaddress}
             cp r24, r30                    '...dort verglichen, wenn sie ungleich sind -> reset usi, exit isr ; ansonsten gehts weiter
             brne Isr_ovf_set_usi_start_cond_mode       'get a invalid address -> SET_USI_TO_TWI_START_CONDITION_MODE() + BREAK
    
       Isr_ovf_get_valid_address:
          'if ( USIDR & &H01 )
          sbis USIDR, 0
          rjmp Isr_ovf_get_write_address
    
          '//we get a read address
          ldi r24, Usi_send_data
          sts {Usi_twi_overflow_state}, r24 'USI_TWI_Overflow_State = USI_SLAVE_SEND_DATA
          rjmp Isr_ovf_set_usi_to_send_ack  'SET_USI_TO_SEND_ACK() + BREAK
    
          '//we get a write address
       Isr_ovf_get_write_address:
          ldi r24, Usi_request_data
          sts {Usi_twi_overflow_state}, r24 'USI_TWI_Overflow_State = USI_SLAVE_REQUEST_DATA
          RJMP Isr_ovf_set_usi_to_send_ack  'SET_USI_TO_SEND_ACK() + BREAK
    
    
    
    
    
    '// ----- Master write data mode ------
    '// Check reply and goto USI_SLAVE_SEND_DATA if OK, else reset USI.
    'case USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA:
    Isr_ovf_check_rep_from_send_data:       'r24 = Usi_twi_overflow_state
    cpi r24, Usi_check_reply_from_send_data 'case Usi_check_reply_from_send_data ?
    brNe Isr_ovf_slave_send_data            'ansonsten nächsten status prüfen
    
         'if ( USIDR ) // If NACK, the master does not want more data.
          in r24, USIDR
          !and r24, r24
          breq Isr_ovf_req_rep_from_send_data_1       'jmp slave_send_data if Master send a ACK (send next byte)
    
          'SET_USI_TO_TWI_START_CONDITION_MODE()
       Isr_ovf_set_usi_start_cond_mode:
          ldi r24, Usicr_start_mode
          !out USICR, r24                   'USICR = Usicr_start_mode
          ldi r24, Usisr_send_or_read_data
          !out USISR, r24                   'USISR = Usisr_send_or_read_data
    
          LDI r24, Usi_start_condition_mode
          sts {Usi_twi_overflow_state}, r24 'USI_TWI_Overflow_State = Usi_start_condition_mode
    
          rjmp ISR_OVF_end                  'break
    
    
    
    
    'case USI_SLAVE_SEND_DATA
    Isr_ovf_slave_send_data:                'r24 = Usi_twi_overflow_state
    cpi r24, Usi_send_data                  'case Usi_send_data ?
    brNe Isr_ovf_req_rep_from_send_data     'no -> jmp to next case
    
    Isr_ovf_req_rep_from_send_data_1:
    
    'zu sendendes Datenbyte muss in twi_tx abgelegt werden
       push r1
       push r24
       in r24, SREG
       push r24
       push r30
       push r31
          Goto I2c_master_needs_byte
          After_master_needs_byte:
       pop r31
       pop r30
       pop r24
       !out SREG, r24
       pop r24
       pop r1
    
          '// Get data from Buffer
          'clr r24
          Loadadr Twi_tx , Z                'R31:R30
          ldi r31, &H00                     'paranoia
          adc r31, r1                       'add carry
          ld r24, Z
          !out USIDR, r24                   'USIDR = TWI_Tx
    
          ldi r24, Usi_request_reply_from_send_data
          sts {Usi_twi_overflow_state}, r24 'USI_TWI_Overflow_State = USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA
    
          'SET_USI_TO_SEND_DATA()'
          SBI DDR_USI, PIN_SDA              'DDR_USI  |=  (1<<PORT_USI_SDA) // Set SDA as output
          ldi r24, Usisr_send_or_read_data
          !out USISR, r24                   'USISR=Usisr_send_or_read_data
          rjmp ISR_OVF_end                  'break
    
    
    
    
    
    '// Set Usi To Sample Reply From Master. Next Usi_slave_check_reply_from_send_data
    'case USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA:
    Isr_ovf_req_rep_from_send_data:         'r24 = Usi_twi_overflow_state
    cpi r24, Usi_request_reply_from_send_data       'case Usi_request_reply_from_send_data ?
    brNe Isr_ovf_slave_request_data         'no -> jmp to next case
    
          ldi r24, Usi_check_reply_from_send_data
          sts {Usi_twi_overflow_state}, r24 'Usi_twi_overflow_state = Usi_slave_check_reply_from_send_data
    
          'SET_USI_TO_READ_ACK()'
          CBI DDR_USI, PIN_SDA              'DDR_USI  &= ~(1<<PORT_USI_SDA) // Set SDA as input
          !out USIDR, r1                    'USIDR = 0
          ldi r24, Usisr_send_or_read_ack
          !out USISR, r24                   'USISR = Usisr_send_or_read_ack
          rjmp ISR_OVF_end                  'break
    
    
    
    
    
    '// ----- Master read data mode ------
    '// Set USI to sample data from master. Next USI_SLAVE_GET_DATA_AND_SEND_ACK.
    'case USI_SLAVE_REQUEST_DATA:
    Isr_ovf_slave_request_data:             'r24 = Usi_twi_overflow_state
    cpi r24, Usi_request_data               'case Usi_request_data ?
    brNe Isr_ovf_get_data_send_ack          'no -> jmp to next case
    
          ldi r24, Usi_get_data_and_send_ack
          sts {Usi_twi_overflow_state}, r24 'USI_TWI_Overflow_State = USI_SLAVE_GET_DATA_AND_SEND_ACK'
    
          'SET_USI_TO_READ_DATA()'
          CBI DDR_USI, PIN_SDA              'DDR_USI  &= ~(1<<PORT_USI_SDA) // Set SDA as input
          ldi r24, Usisr_send_or_read_data
          !out USISR, r24                   'USISR=Usisr_send_or_read_data
          rjmp ISR_OVF_end                  'break
    
    
    
    
    '// Copy data from USIDR and send ACK. Next USI_SLAVE_REQUEST_DATA
    'case USI_SLAVE_GET_DATA_AND_SEND_ACK:
    Isr_ovf_get_data_send_ack:              'r24 = Usi_twi_overflow_state
    cpi r24, Usi_get_data_and_send_ack      'case Usi_get_data_and_send_ack ?
    BRNE Isr_ovf_end                        'no -> jmp END
    
         '// Put data into Buffer
          Loadadr Twi_rx , Z                'R31:R30
          ldi r31, &H00                     'paranoia
          adc r31, r1                       'add carry flag
          IN r24, USIDR
          st Z, r24                         'TWI_Rx = USIDR
          'clr r24
    
          ldi r24, Usi_request_data
          sts {Usi_twi_overflow_state}, r24 'USI_TWI_Overflow_State = USI_SLAVE_REQUEST_DATA'
    
    'empfangenes Datenbyte liegt in Twi_rx
       push r1
       push r24
       in r24, SREG
       push r24
       push r30
       push r31
         Goto I2c_master_has_byte
         After_master_has_byte:
       pop r31
       pop r30
       pop r24
       !out SREG, r24
       pop r24
       pop r1
    
         'SET_USI_TO_SEND_ACK()
      Isr_ovf_set_usi_to_send_ack:          'jmp from case USI_SLAVE_CHECK_ADDRESS
          !out USIDR, r1                    'USIDR = 0 //Prepare ACK
          SBI DDR_USI, PIN_SDA              'DDR_USI  |=  (1<<PORT_USI_SDA) // Set SDA as output
          ldi r24, Usisr_send_or_read_ack
          !out USISR, r24                   'USISR = Usisr_send_or_read_ack
    
    Isr_ovf_end:
       pop r31
       pop r30
       pop r24
       pop r1
       !out SREG, r1
       pop r1
       reti
    Return

Seite 3 von 3 ErsteErste 123

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

12V Akku bauen