VU Meter con memoria di picco: convertire da assembly a C

Ciao a tutti
Su Youtube (sì, d'accordo, ma questo sembra fatto con molta cura!):

ho trovato questo codice di un vu-meter con memoria di picco in assembly per Atmega8 e mi piacerebbe studiarlo in C:

; Stereo indikator vybuzeni s ATmega8A / 8 / 8L
; int. RC 8MHz, BOD 2,7V
; IX. 2013
; vytvoril: DANYK
; http://danyk.cz/avr_iv2.html

.NOLIST
.INCLUDE "m8def.inc"
.LIST


.DEF REG=R16		; docasny registr
.DEF REG2=R17		; docasny registr 2

.DEF VYS_L=R18		; vysledek AD prevodu dolni
.DEF VYS_H=R19		; vysledek AD prevodu horni

.DEF DELREG=R20		; registr deleni frekvence
.DEF DELREG2=R21	; registr deleni frekvence 2
.DEF KANAL=R22		; prepinani kanalu
.DEF MULTREG=R23	; registr si pamatuje stav multiplexu 

.DEF LK=R24			; levy kanal
.DEF PK=R25			; pravy kanal

.DEF LKD=R26		; levy kanal indikace maxima
.DEF PKD=R27		; pravy kanal indikace maxima

.DEF LKZ=R28		; levy kanal zpozdeni maxima
.DEF PKZ=R29		; pravy kanal zpozdeni maxima


.EQU SMER=DDRD
.EQU PORT=PORTD
.EQU SMER2=DDRC
.EQU PORT2=PORTC
.EQU VSTUPY=PINC
.EQU SMER3=DDRB
.EQU PORT3=PORTB


.CSEG
.ORG 0
RJMP START

; vektory preruseni
.ORG OC2addr	;preruseni citacem2 ridici multiplex, obnovovaci frekvenci
RJMP CASOVANI


START:
;nastavi port D
LDI REG,0b11111111
OUT SMER,REG
LDI REG,0b00000000
OUT PORT,REG

;nastavi port C
LDI REG,0b000000
OUT SMER2,REG
LDI REG,0b111100
OUT PORT2,REG

;nastavi port B
LDI REG,0b00111111
OUT SMER3,REG
LDI REG,0b11111100
OUT PORT3,REG


LDI REG,LOW(RAMEND)
OUT SPL,REG
LDI REG,HIGH(RAMEND)
OUT SPH,REG	

LDI DELREG,1
LDI DELREG2,1
LDI MULTREG,1 
CLR LK
CLR PK
CLR LKD
CLR PKD
CLR LKZ
CLR PKZ

; NASTAVENI CASOVACE A JEHO PRERUSENI
LDI	REG,0b00001001 	; nulovani pri dosazeni porovnavane hodnoty...
OUT TCCR2,REG    	; ...(tzv. CTC), OC0 nevyuzit. preddeli 1

LDI	REG,249	      	; nastavi porovnavanou hodnotu (deli se n+1)
OUT	OCR2,REG     	; 

LDI	REG,0b10000000	; povoli preruseni CTC OCIE2
OUT	TIMSK,REG    	; 


;NASTAVENI ADC a MCU
; povoli uspani (sleep) a nastavi mod ADC nr
LDI	REG,0b10010000	
OUT	MCUCR,REG

; vypne analog. komparator - neni nikdy vyuzit (setri energii)
LDI	REG,0b10000000	
OUT	ACSR,REG  

; nastavi ADC - f/8, povoli ho
LDI REG,0b10000011
OUT ADCSRA,REG


SEI ;povoli globalni preruseni


;hlavni smycka
SMYCKA:
SLEEP
RJMP SMYCKA


MULT:
LDI REG,0b00000000
OUT PORT,REG
LDI REG,0b11111100
OUT PORT3,REG
LDI REG,0b111100
OUT PORT2,REG

; rychle
CP LK,MULTREG
BRLO L_NE
CBI PORT3,2
L_NE:

MOV REG,MULTREG
SUBI REG,246
CP LK,REG
BRLO L2_NE
CBI PORT3,3
L2_NE:

CP PK,MULTREG
BRLO P_NE
CBI PORT3,4
P_NE:

MOV REG,MULTREG
SUBI REG,246
CP PK,REG
BRLO P2_NE
CBI PORT3,5
P2_NE:

; pomale
IN REG,VSTUPY
SBRC REG,2
RJMP MAX_VYP

CP LKD,MULTREG
BRNE LD_NE
CBI PORT3,2
LD_NE:

MOV REG,MULTREG
SUBI REG,246
CP LKD,REG
BRNE L2D_NE
CBI PORT3,3
L2D_NE:

CP PKD,MULTREG
BRNE PD_NE
CBI PORT3,4
PD_NE:

MOV REG,MULTREG
SUBI REG,246
CP PKD,REG
BRNE P2D_NE
CBI PORT3,5
P2D_NE:

MAX_VYP:

;vetveni multiplexu
MOV REG,MULTREG
DEC REG
LDI ZL,LOW(SKOK)
LDI ZH,HIGH(SKOK)
ADD ZL,REG
CLR REG
ADC ZH,REG
IJMP

SKOK:
RJMP MULT1
RJMP MULT2
RJMP MULT3
RJMP MULT4
RJMP MULT5
RJMP MULT6
RJMP MULT7
RJMP MULT8
RJMP MULT9
RJMP MULT10

MULT1:
SBI PORT,0
RET
MULT2:
SBI PORT,1
RET
MULT3:
SBI PORT,2
RET
MULT4:
SBI PORT,3
RET
MULT5:
SBI PORT,4
RET
MULT6:
SBI PORT,5
RET
MULT7:
SBI PORT,6
RET
MULT8:
SBI PORT,7
RET
MULT9:
SBI PORT3,0
RET
MULT10:
SBI PORT3,1
RET



PADEJ:
CPI LK,0
BREQ LEVY_0
DEC LK
LEVY_0:
CPI PK,0
BREQ PRAVY_0
DEC PK
PRAVY_0:

CPI LKZ,0
BREQ LEVYZ_0
DEC LKZ
RJMP LEVYZ_NE0
LEVYZ_0:
MOV LKD,LK
LEVYZ_NE0:

CPI PKZ,0
BREQ PRAVYZ_0
DEC PKZ
RJMP PRAVYZ_NE0
PRAVYZ_0:
MOV PKD,PK
PRAVYZ_NE0:

RET


; preruseni ridici multiplex a zdroj casovani
CASOVANI:
IN VYS_L,ADCL
IN VYS_H,ADCH

MOV REG,KANAL
ANDI REG,0b00000001
ORI REG,0b11000000	;interni reference 2,56V, zarovna vpravo, vstup 0 / 1
OUT ADMUX,REG
SBI ADCSRA,6

CLR REG

LDI REG2,HIGH(11)
CPI VYS_L,LOW(11)
CPC VYS_H,REG2
BRLO MENSI2
INC REG

LDI REG2,HIGH(14)
CPI VYS_L,LOW(14)
CPC VYS_H,REG2
BRLO MENSI2
INC REG

LDI REG2,HIGH(18)
CPI VYS_L,LOW(18)
CPC VYS_H,REG2
BRLO MENSI2
INC REG

LDI REG2,HIGH(22)
CPI VYS_L,LOW(22)
CPC VYS_H,REG2
BRLO MENSI2
INC REG

LDI REG2,HIGH(28)
CPI VYS_L,LOW(28)
CPC VYS_H,REG2
BRLO MENSI2
INC REG

LDI REG2,HIGH(36)
CPI VYS_L,LOW(36)
CPC VYS_H,REG2
BRLO MENSI2
INC REG

LDI REG2,HIGH(45)
CPI VYS_L,LOW(45)
CPC VYS_H,REG2
BRLO MENSI2
INC REG

LDI REG2,HIGH(56)
CPI VYS_L,LOW(56)
CPC VYS_H,REG2
BRLO MENSI2
INC REG

LDI REG2,HIGH(71)
CPI VYS_L,LOW(71)
CPC VYS_H,REG2
BRLO MENSI2
INC REG

LDI REG2,HIGH(90)
CPI VYS_L,LOW(90)
CPC VYS_H,REG2
BRLO MENSI2
INC REG

RJMP POPOSKOC
MENSI2:
RJMP MENSI
POPOSKOC:

LDI REG2,HIGH(113)
CPI VYS_L,LOW(113)
CPC VYS_H,REG2
BRLO MENSI
INC REG

LDI REG2,HIGH(142)
CPI VYS_L,LOW(142)
CPC VYS_H,REG2
BRLO MENSI
INC REG

LDI REG2,HIGH(179)
CPI VYS_L,LOW(179)
CPC VYS_H,REG2
BRLO MENSI
INC REG

LDI REG2,HIGH(225)
CPI VYS_L,LOW(225)
CPC VYS_H,REG2
BRLO MENSI
INC REG

LDI REG2,HIGH(283)
CPI VYS_L,LOW(283)
CPC VYS_H,REG2
BRLO MENSI
INC REG

LDI REG2,HIGH(356)
CPI VYS_L,LOW(356)
CPC VYS_H,REG2
BRLO MENSI
INC REG

LDI REG2,HIGH(449)
CPI VYS_L,LOW(449)
CPC VYS_H,REG2
BRLO MENSI
INC REG

LDI REG2,HIGH(565)
CPI VYS_L,LOW(565)
CPC VYS_H,REG2
BRLO MENSI
INC REG

LDI REG2,HIGH(711)
CPI VYS_L,LOW(711)
CPC VYS_H,REG2
BRLO MENSI
INC REG

LDI REG2,HIGH(895)
CPI VYS_L,LOW(895)
CPC VYS_H,REG2
BRLO MENSI
INC REG


MENSI:


INC KANAL

SBRC KANAL,0
RJMP LEVY_NE

CP LK,REG
BRSH L_NENI_VYSSI
MOV LK,REG
L_NENI_VYSSI:
CP REG,LKD
BRLO LD_JE_NIZSI
LDI LKZ,67			;zpozdeni
MOV LKD,REG
LD_JE_NIZSI:

RJMP PRAVY_NE
LEVY_NE:

CP PK,REG
BRSH P_NENI_VYSSI
MOV PK,REG
P_NENI_VYSSI:
CP REG,PKD
BRLO PD_JE_NIZSI
LDI PKZ,67 			;zpozdeni
MOV PKD,REG
PD_JE_NIZSI:

PRAVY_NE:


DEC DELREG
BRNE HOP
LDI DELREG,32

RCALL MULT
DEC MULTREG
BRNE HOP
LDI MULTREG,10

DEC DELREG2
BRNE HOP
LDI DELREG2,3		; !!! DOBA SESTUPU / FALL TIME (2 = 400ms, 3 = 600ms, 4 = 800ms, 5 = 1s, ...) !!!
RCALL PADEJ

HOP:

RETI

Questo sito:

per più di 1500 caratteri vuole l'abbonamento, ma per i primi 1500 esce una cosa del genere, con i primi commenti veramente accurati; poi mette dei #define che complicano inutilmente la lettura:

#include <avr/io.h>
#include <avr/interrupt.h>

// Temporary registers
uint8_t REG, REG2;
// ADC conversion result
uint8_t VYS_L, VYS_H;
// Frequency division registers
uint8_t DELREG, DELREG2;
// Channel switching
uint8_t KANAL;
// Register remembers the state of multiplex
uint8_t MULTREG;
// Left and right channels
uint8_t LK, PK;
// Left and right channel max indication
uint8_t LKD, PKD;
// Left and right channel delay max
uint8_t LKZ, PKZ;

// Direction registers
#define SMER DDRD
#define SMER2 DDRC
#define SMER3 DDRB
// Port registers
#define PORT PORTD
#define PORT2 PORTC
#define PORT3 PORTB
// Input register
#define VSTUPY PINC

void setup_ports() {
    // Set port D
    REG = 0b11111111;
    SMER = REG;
    REG = 0b00000000;
    PORT = REG;
    // Set port C
    REG = 0b000000;
    SMER2 = REG;
    REG = 0b111100;
    PORT2 = REG;
    // Set port B
    REG = 0b00111111;
    SMER3 = REG;
    REG = 0b11111100;
    PORT3 = REG;
}

void setup_stack() {
    REG = LOW(RAMEND);
    SPL = REG;
    REG = HIGH(RAMEND);
    SPH = REG;
}

void setup_timer_and_interrupt() {
    // TIMER AND INTERRUPT SETUP
    REG = 0b00001001; // Clear on compare match
    // Additional timer and interrupt setup code needed here
    // This will depend on the specific use case and is not provided in the assembly
}

void initialize_variables() {
    DELREG = 1;
    DELREG2 = 1;
    MULTREG = 1;
    LK = 0;
    PK = 0;
    LKD = 0;
    PKD = 0;
    LKZ = 0;
    PKZ = 0;
}

int main(void) {
    setup_ports();
    setup_stack();
    setup_timer_and_interrupt();
    initialize_variables();

    // Main loop
    while (1) {
        // Application code here
    }

    return 0;
}

// Interrupt service routine for Timer2 Compare Match
ISR(TIMER2_COMP_vect) {
    // Timing and multiplexing code here
}

Poi ho provato con Bard (AI) ed è uscito questo, ma purtroppo è troncato e, comunque, è meno amichevole del precedente!...:

#include <avr/io.h>

// Definizioni dei registri
#define SMER DDRD
#define PORT PORTD
#define SMER2 DDRC
#define PORT2 PORTC
#define VSTUPY PINC
#define SMER3 DDRB
#define PORT3 PORTB

// Definizioni delle variabili
uint8_t reg;
uint8_t reg2;
uint16_t vys_l;
uint16_t vys_h;
uint8_t delreg;
uint8_t delreg2;
uint8_t kanal;
uint8_t multreg;
uint8_t lk;
uint8_t pk;
uint8_t lkd;
uint8_t pkd;
uint8_t lkz;
uint8_t pkz;

// Inizializzazione
void init() {
  // Imposta i registri dei pin
  SMER = 0xff;
  PORT = 0x00;
  SMER2 = 0x00;
  PORT2 = 0x00;
  SMER3 = 0xff;
  PORT3 = 0x00;

  // Imposta il clock interno a 8 MHz
  CLKPR = (1 << CLKPCE);
  CLKPR = 0x00;

  // Imposta il modo di funzionamento del ADC
  ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);

  // Abilita i pre-interrupt
  sei();
}

// Loop principale
void loop() {
  // Attiva il sleep mode
  sleep_mode();
}

// Interrupt handler per il timer 2
ISR(TIMER2_COMPA_vect) {
  // Legge i valori degli ingressi
  vys_l = ADCL;
  vys_h = ADCH;

  // Imposta il registro di selezione del canale
  reg = kanal & 0x01;
  ADMUX = (reg << 6) | (0x11 << 2);
  ADCSRA |= (1 << ADSC);

  // Imposta il valore del canale
  reg = 0;
  switch (kanal) {
    case 0:
      reg = 11;
      break;
    case 1:
      reg = 14;
      break;
    case 2:
      reg = 18;
      break;
    case 3:
      reg = 22;
      break;
    case 4:
      reg = 28;
      break;
    case 5:
      reg = 36;
      break;
    case 6:
      reg = 45;
      break;
    case 7:
      reg = 56;
      break;
    case 8:
      reg = 71;
      break;
    case 9:
      reg = 90;
      break;
    case 10:
      reg = 113;
      break;
    case 11:
      reg = 142;
      break;
    case 12:
      reg = 179;
      break;
    case 13:
      reg = 225;
      break;
    case 14:
      reg = 283;
      break;
    case 15:
      reg = 356;
      break;
    case 16:
      reg = 449;
      break;
    case 17:
      reg = 565;
      break;
    case 18:
      reg = 711;
      break;
    case 19:
      reg = 895;
      break;
  }

  // Incrementa il canale
  kanal++;
  if (kanal == 20) {
    kanal = 0;
  }

  // Controlla se il canale attuale è quello di massimo livello
  if (reg 

WOWWW!!! chat.openai.com risponde così:

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>

volatile uint8_t LK = 0, PK = 0, LKD = 0, PKD = 0, LKZ = 0, PKZ = 0;
volatile uint8_t DELREG = 1, DELREG2 = 1, MULTREG = 1, KANAL = 0;

void setup() {
    DDRD = 0xFF;    // Set PORTD as output
    PORTD = 0x00;   // Initialize PORTD to 0
    DDRC = 0x00;    // Set PORTC as input
    PORTC = 0xFF;   // Enable pull-up resistors on PORTC
    DDRB = 0xFF;    // Set PORTB as output
    PORTB = 0x03;   // Initialize PORTB to 0x03

    ADMUX = (1 << REFS1) | (1 << REFS0); // Internal 2.56V reference, right adjusted, channel 0
    ADCSRA = (1 << ADEN) | (1 << ADPS1) | (1 << ADPS0); // ADC enable, prescaler 8
    ACSR = (1 << ACD);  // Disable analog comparator

    TCCR2 = (1 << WGM21) | (1 << CS20) | (1 << CS21); // CTC mode, prescaler 64
    OCR2 = 249;     // Set compare value
    TIMSK = (1 << OCIE2);   // Enable Timer/Counter2 compare match interrupt

    sei();  // Enable global interrupts
}

void loop() {
    set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Set sleep mode
    sleep_mode();   // Enter sleep mode
}

ISR(TIMER2_COMP_vect) {
    // Analog to Digital Conversion
    ADCSRA |= (1 << ADSC); // Start conversion
    while (ADCSRA & (1 << ADSC)); // Wait for conversion to complete

    uint16_t result = ADC;

    if (KANAL & 0x01) {
        if (LK < result) {
            LK = result;
            if (LK - LKD > 1) {
                LKZ = 67;
                LKD = LK;
            }
        }
    } else {
        if (PK < result) {
            PK = result;
            if (PK - PKD > 1) {
                PKZ = 67;
                PKD = PK;
            }
        }
    }

    KANAL++;

    if (KANAL & 0x01) {
        PORTD &= ~(1 << PD2); // Reset PORTD bit 2
        if (LK == MULTREG) PORTB &= ~(1 << PB0); // Reset PORTB bit 0
        if (LK - MULTREG == 246) PORTB &= ~(1 << PB1); // Reset PORTB bit 1
    } else {
        if (PK == MULTREG) PORTB &= ~(1 << PB0); // Reset PORTB bit 0
        if (PK - MULTREG == 246) PORTB &= ~(1 << PB1); // Reset PORTB bit 1
    }

    if (DELREG == 0) {
        PORTD |= (1 << PD2); // Set PORTD bit 2
        if (DELREG2 == 0) {
            DELREG2 = 3;
            delay(600); // Delay 600ms
            decrement();
        }
    }
}

void decrement() {
    if (LK > 0) LK--;
    if (PK > 0) PK--;
    if (LKZ > 0) LKZ--;
    if (PKZ > 0) PKZ--;
}

"Questa traduzione è un adattamento diretto in C del programma in assembly per il microcontrollore ATmega8. Potrebbero esserci differenze sottili nei dettagli di implementazione, specialmente nei calcoli del timer e dell'ADC, che potrebbero richiedere alcune modifiche e ottimizzazioni. Assicurati di includere le librerie corrette e di configurare il tuo ambiente di sviluppo per il microcontrollore ATmega8."

L'IDE lo compila pure!
"Lo sketch usa 914 byte (12%) dello spazio disponibile per i programmi. Il massimo è 7168 byte.
Le variabili globali usano 20 byte (1%) di memoria dinamica, lasciando altri 1004 byte liberi per le variabili locali. Il massimo è 1024 byte."

Mi sembra, però, che manchi la visualizzazione, che dovrebbe anche essere logaritimica!

1 Like

Certo, CodeConvert AI arriva a scrivere cose del genere:

// Channel switching
uint8_t KANAL;

// Register remembers the state of multiplex
uint8_t MULTREG;

// Left and right channels
uint8_t LK, PK;

// Left and right channel max indication
uint8_t LKD, PKD;

// Left and right channel delay max
uint8_t LKZ, PKZ;

frutto di una vera comprensione del programma! (anche se, dai nomi delle variabili, non sono proprio sicuro che abbia azzeccato tutti gli abbinamenti...).

Comunque, se lo dai in pasto a google traslate vedi cosa dicono i commenti e ti puoi fare un'idea.

Ciao, Ale.

Google translate???!!! :open_mouth:
Ah! I commenti! Gli stavo dando in pasto l'assembly sperando di ottenere la traduzione in C!!! :rofl:

Dovrà aspettare. Ci stiamo lavorando

Cordiali Saluti
Chat gpt

Uh?... Parlavo di Google. Chat gpt lo fa.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.