Maskinistens Twitter-flöde  Stöd Maskinisten via Patreon  Maskinistens nätverk - information på svenska  Maskinistens nätverk - information på finska  Maskinistens nätverk - information på norska  Maskinistens nätverk - information på danska  Maskinistens nätverk - information på isländska
Forumindex

ForumindexForumindexMaskin-databasFotoalbumKalender-informationKöp & SäljDownloadsLexikonKontaktregisterCrimedatbase

Åkerman-register
Visa forum för mobila enheter

ForumindexJord- och skogsbruk, fastigheterEnergi och uppvärmning

Inverter för solel off-grid (Ö-drift)

200 inlägg • Sida 13 av 14
Diskutera värmekällor, bygge av pannrum/panncentraler, framställning av bränsle, tillvaratagande av energi osv här

sm6ywk

#181 » 08:42:31, 29-11-2022
  • Överför markerat ord till lexikonet

Har suttit och försökt få till en riktig timer med intrrrupt, men gått bet.
Jag fick igång något, men arduinon startar om sig efter bara en 20 ms period.
Har provat med en "riktig" arduino så inte fel på simulatorn.
Hoppas få en stund ikväll, lycka till med testandet!

1 person gillar det här inlägget.
sm6ywk
Fler än 100 inlägg
 
Blev medlem: 12:40:41, 10-03-2013
Ort: Ale kommun, Västra Götaland
Maskintyp: Traktor
Maskin: BM 650



sm6ywk

#182 » 17:47:11, 29-11-2022
  • Överför markerat ord till lexikonet

Jag hittade mina fel, och fick koden att fungera som jag vill.
Mitt första fel var att jag glömde sätta ICR1, vilket gjorde att den defaultades till 0. Osäker på om inga interrupt skedde eller om de skedde hela tiden.
Mitt andra värsta fel var att jag stavade fel till TIMER1_OVF_vect vilket fick arduinon att startas om hela tiden. Jaja.
Jag har som vanligt inte kommenterat på ett anständigt sätt, skall försöka förklara vid tillfälle.
Men kort:
Timer1 räknar med samma hastighet som CPU (16 MHz), börjar från 0 och räknar till ICR1 (4000 i min kod).
När timern når värdet av OCR1A (2000) i min kod avbryter programmet vad som sker och hoppar genast till ISR(TIMER1_COMPA_vect) och utför vad som står där, för att sen hoppa tillbaks till där den avbröts.
När timern når ICR1 så nollställs timern och programmet hoppar till ISR(TIMER1_OVF_vect).
Som koden är skriven så blir frekvensen F_CPU/4000 = 4 kHz, duty cycle blir OCR1A/ICR1 = 4000/2000 = 50 %.

Prova gärna koden och fundera på om det kan vara något som passar dig?
Jag svarar gärna på frågor och ska kommentera mer, men lite upptagen just nu.
/K

Kod: Markera allt
// här sätts namnen på utgångar och ingång.
uint8_t fas1p = 8;               // fas 1 plus till ben 8
uint8_t fas1m = 7;               // fas 1 minus till ben 7
uint8_t fas2p = 6;               // fas 2 plus till ben 6
uint8_t fas2m = 5;               // fas 2 minus till ben 5
uint8_t fas3p = 4;               // fas 3 plus till ben 4
uint8_t fas3m = 3;               // fas 3 minus till ben 3
uint8_t debugPin = 9;
uint8_t debugVar = 0;

uint8_t fas1mAktiv = 0; //Flagga som talar om ifall fas1 minus trasistor ska pulsa.
uint8_t fas2mAktiv = 0; //Flagga som talar om ifall fas2 minus trasistor ska pulsa.
uint8_t fas3mAktiv = 0; //Flagga som talar om ifall fas2 minus trasistor ska pulsa.


//Interrupt som sker när timer1 når OCRA1, kanske mer logiskt att ha if-satser
//men det är aldrig farligt att släcka en utgång för mycket, så det tar bara onödig CPU-tid.
ISR(TIMER1_COMPA_vect) {
  digitalWrite(fas1m, LOW);
  digitalWrite(fas2m, LOW);
  digitalWrite(fas3m, LOW);

}
ISR(TIMER1_OVF_vect) {
  if (fas1mAktiv == 1)
    digitalWrite(fas1m, HIGH);
  if (fas2mAktiv == 1)
    digitalWrite(fas2m, HIGH);
  if (fas3mAktiv == 1)
    digitalWrite(fas3m, HIGH);
}


void setup() {
  pinMode(debugPin, OUTPUT);
  digitalWrite(debugPin, HIGH);
  // put your setup code here, to run once:
  pinMode(fas1p, OUTPUT);         // här fastställs benen att bli utgångar
  digitalWrite(fas1p, LOW);       // här ställs utgången aktivt låg.
  pinMode(fas2p, OUTPUT);         // osv
  digitalWrite(fas2p, LOW);
  pinMode(fas3p, OUTPUT);
  digitalWrite(fas3p, LOW);
  pinMode(fas1m, OUTPUT);
  digitalWrite(fas1m, LOW);
  pinMode(fas2m, OUTPUT);
  digitalWrite(fas2m, LOW);
  pinMode(fas3m, OUTPUT);
  digitalWrite(fas3m, LOW);       // nu är alla utgångar satta till aktivt låg (offläge)


  //Ställ in timer 1 för att genera interrupt för PWM
  //Timer 1 ställs in för att generera 4 kHz PWM. Timern konfigureras för Fast PWM (mod14)
  //Timern räknar från 0 till ICR1, interrupt genereras när den passerar OCR1A och när den når ICR1.
  //Vid OCR1A ställs utgång hög, vid ICR1 låg. Duty-cycle ändras med OCR1A, frekvens med ICR1.
  //Ursprungsvärden ICR1 = 4000 (16MHz/4000 = 4 kHz), OCR1A = 2000
  TCCR1A = 0x00;
  TCCR1A &= ~(1 << WGM10);
  TCCR1A |= (1 << WGM11);
  //TCCR1B
  TCCR1B = (1 << WGM12);
  TCCR1B |= (1 << WGM13);
  TCCR1B |= (1 << CS10); //prescaler = 1

  //OCR1A
  //Vilket timervärde som interrupt där utgång sätts låg. (0-ICR1)
  OCR1A = 2000;
  ICR1 = 4000;
  //TIMSK1
  //Interruptkontroll för timer 1,
  TIMSK1 |= (1 << OCIE1A);
  TIMSK1 |= (1 << TOIE1);
  digitalWrite(debugPin, LOW);

}


void loop() {

  unsigned long start;
  uint16_t actTime;

  //Räknar ut alla tider för att slippa lägga CPU-tid på det i loopen
  int ontime = 9900;
  int trettigrad = 1667; //30 grader vid 50 Hz, hjälper till att räkna tider.
  int fas1pPeakTime = trettigrad * 3; //Mitten av tiden som fas 1 ska vara positiv (5000us)
  int fas1mPeakTime = trettigrad * 9; //Mitten av tiden från start som fas 1 ska vara negativ (15000us)
  int fas2pPeakTime = trettigrad * 7;
  int fas2mPeakTime = trettigrad * 1;
  int fas3pPeakTime = trettigrad * 11;
  int fas3mPeakTime = trettigrad * 5;

  int fas1pStart = fas1pPeakTime - ontime / 2;
  int fas1pStop = fas1pPeakTime + ontime / 2;
  int fas1mStart = fas1mPeakTime - ontime / 2;
  int fas1mStop = fas1mPeakTime + ontime / 2;

  int fas2pStart = fas2pPeakTime - ontime / 2;
  int fas2pStop = fas2pPeakTime + ontime / 2;
  //int fas2mStart = fas2mPeakTime-ontime/2;
  int fas2mStart = 20000 + fas2mPeakTime - (ontime / 2);

  int fas2mStop = fas2mPeakTime + ontime / 2;

  int fas3pStart = fas3pPeakTime - ontime / 2;
  //int fas3pStop = fas3pPeakTime+ontime/2;
  int fas3pStop = fas3pPeakTime + (ontime / 2) - 20000;

  int fas3mStart = fas3mPeakTime - ontime / 2;
  int fas3mStop = fas3mPeakTime + ontime / 2;

  int i;
  //for (i = 0; i < 5; i++) {
    while(true){
    actTime = 0;
    start = micros();

    while (actTime <= 20000) { //Kollar att tiden sedan start inte passerat en period (20ms)
      actTime = micros() - start;

      if (actTime >= fas1pStart && actTime <= fas1pStop)
        digitalWrite(fas1p, HIGH);
      else
        digitalWrite(fas1p, LOW);

      if (actTime >= fas1mStart && actTime <= fas1mStop)
        fas1mAktiv = 1;
      else {
        fas1mAktiv = 0;
        digitalWrite(fas1m, LOW);
      }

      if (actTime <= fas3pStart && actTime >= fas3pStop)
        digitalWrite(fas3p, LOW);
      else
        digitalWrite(fas3p, HIGH);

      if (actTime >= fas3mStart && actTime <= fas3mStop)
        fas3mAktiv = 1;
      else {
        fas3mAktiv = 0;
        digitalWrite(fas3m, LOW);
      }

      //Omvänd logik P.G.A. ontiden passerar utanför perioden.
      if (actTime <= fas2mStart && actTime >= fas2mStop) {
        fas2mAktiv = 0;
        digitalWrite(fas2m, LOW);
      }
      else
        fas2mAktiv = 1;

      if (actTime >= fas2pStart && actTime <= fas2pStop)
        digitalWrite(fas2p, HIGH);
      else
        digitalWrite(fas2p, LOW);

    }
  }
}

1 person gillar det här inlägget.
sm6ywk
Fler än 100 inlägg
 
Blev medlem: 12:40:41, 10-03-2013
Ort: Ale kommun, Västra Götaland
Maskintyp: Traktor
Maskin: BM 650

Janson1 (trådstartaren)

#183 » 21:41:31, 29-11-2022
  • Överför markerat ord till lexikonet

Tackar K. Jodå koden funkar hos mig med. Men nu börjar jag tappa greppet om vad som händer, jag har aldrig varit i timerna och rotat utan bara kört millis/micros enligt arduinovis...
Jag känner att här behöver jag nog fördjupa mig en bra del för att förstå! Jag behöver nog få någon slags utbildning inom detta, finns det sånt någonstans? Jag förstår så långt att det blir 50% on/offtid och ändrar jag OCR1A= 2000 till tex 1000 så bör det bli 25% on? och 3000 75% on? Och 4000 är 16 Mhz/4000 vilket gör att den räknar till 4000 varje gång och då blir en utgång hög och sen tex 2000 steg senare så går den låg igen och osv . För att ändra pulsbredden så behöver jag bara ändra på 2000 talet plus och minus? Jag tror jag förstår logiken också men behöver nog tugga på detta ett tag till...
Edit: Får nog redigera lite... Timern går först 2000 steg, sedan går en utgång hög, sedan 2000 steg senare vid 4000 så resatas timern och börjar om från början samtidigt som utgången går låg igen, osv
Senast redigerad av Janson1 22:46:43, 30-11-2022, redigerad totalt 1 gång.
Janson1
Fler än 500 inlägg
 
Blev medlem: 12:50:52, 21-03-2010
Ort: Mark Västra Götaland
Sverige
Maskintyp: Grävmaskin (larvburen)
Maskin: Bobcat X125 (2.5 ton)
Case CK-15 (Kubota kx41)
+ div. flygplan, helikoptrar
Senaste renoveringsobjekten:
Piper PA-24 Comanche från -64 (flyger nu)
Ferguson Grålle/VW diesel 1952/2002 (rullar nu)
10 Kw solcellsanläggning som surrar och går.
Försöka få till ett Ö-drift elsystem utifall att...

sm6ywk

#184 » 23:39:06, 29-11-2022
  • Överför markerat ord till lexikonet

Jag vet inget annat sätt än att plöja datablad. Jag tycker atmels datablad är ganska tunga att läsa.
I just detta fallet så tror jag att du kan nöja dig med timern som den är och "bara" ändra på OCR1A och ICR1, även om jag vet att det är frustrerande att inte ha koll på vad som händer under skalet.
ATmega328 har tre timrar 0, 1 och 2. 0 och 2 är 8-bitars timrar, 1 är 16 bitar.
Fördelen med timrar är att man avlastar CPU. Arduino-sättet brukar ta ganska mycket CPU i anspråk.
Arduino använder själv timer0 till millis() och micros().
Jag valde timer1 för att det finns ganska mycket frihet med just den.
Timern är inställd på "Fast PWM", med top = ICR1. Det ställs in med registren TCCR1A och TCCR1B.
Kod: Markera allt

  TCCR1A &= ~(1 << WGM10);
  TCCR1A |= (1 << WGM11);
  //TCCR1B
  TCCR1B |= (1 << WGM12);
  TCCR1B |= (1 << WGM13);
  TCCR1B |= (1 << CS10); //prescaler = 1

Här sker lite programmeringsmagi, båda register är 8-bitar och varje bit har en mening.
TCCR1A |= (1<<WGM11) är ett kortare sätt att skriva TCCR1A = TCCR1A | 0b00000010.
WGM11 är en lagrad konstant som är 1.
(1<<1) betyder att man tar skiftar en 1 ett steg åt vänster, binärt skulle man skriva 0b00000010
(1<<0) = 0b00000001
(1<<2) = 0b00000100
osv.
| är samma sak som en OR-grind om det är mer bekant.
Tanken är att man tar registret TCCR1A och låter alla bitar vara oförändrade förutom bit 1 som skall vara 1.
För att skriva en nolla så använder man "and" istället TCCR1A &= ~(1 << WGM10), ~ betyder invertera bitvis. WGM10 = 0.
Så (1<<WGM10) = 0b00000001, ~(1<<WGM10) = 0b11111110.
Vet inte om du blir klokare av detta, jag tycker att det är ett snyggt sätt att skriva för koden blir ganska lättläst.
Jag minns dock att jag tyckte att det var lite svårt att greppa i början, så jag lägger lite extra tid på att förklara.
WGM (Waveform generation mode) bitarna ställer in typ av vågform. Jag lyckas inte ladda upp bilder, stjäl en från internet.
Bild
I koden ser du att WGM10 "och-as" ner och WGM11, WGM12 och WGM13 "or-as" upp, det blir nr 14 i tabellen.

Fast PWM med TOP ICR1 betyder att timern räknar från 0 till ICR1 (ställbart 0-65535) och börjar sedan om.
Om den passerar OCR1A (eller OCR1B) kan ett interrupt ske. Interrupt måste konfigureras att släppas fram. Det sker med TIMSK1.
I koden:
Kod: Markera allt
//TIMSK1
  //Interruptkontroll för timer 1,
  TIMSK1 |= (1 << OCIE1A);
  TIMSK1 |= (1 << TOIE1);

TOIE1 = Timer1 overflow interrupt enable, det interruptet som sker vid ICR1.
OCIE1A = Output Compare A Match Interrupt Enable (timer1).

Nu kommer interrupt ske vid dessa båda tillfällen.
När ett interrupt sker så kommer CPUn att i princip stanna mitt i vad den håller på med.
Den sparar ner lite värden på stacken så att den vet precis vad den höll på med när den avbröt och hoppar sedan till minnesadressen som interruptet pekar på.
I C-koden är det
Kod: Markera allt
ISR(TIMER1_OVF_vect)
alternativt
Kod: Markera allt
ISR(TIMER1_COMPA_vect) {

Då CPUn som sagt avbryter vad den gör så ska man alltid försöka hålla interrupt-rutinerna så korta som man någonsin kan.

En stor fördel (även om den inte är jätteviktig i detta fallet) med timrar är att timingen alltid blir rätt.
Gör man ett program med delayer så är det svårt att veta hur lång tid saker tar, t.ex. analogRead vi pratade om tidigare.
Att använda sig av millis() eller micros() är faktiskt ett sätt att använda timrarna fast indirekt (och med lite sämre tidnoggrannhet).

Det enda jag använt timern och interruptet är att styra den högfrekventa signalen på minus-sidan, plus-sidan styr jag likadant som tidigare.
Varje fas är plus i 9,9 ms, sedan dödtid på 0,1 ms, negativ i 9,9 ms, dödtid 0,1 ms.
Jag tycker 100 us är ganska generöst med dödtid, men det är bara att ändra på
Kod: Markera allt
int ontime = 9900;
om du vill ha mer eller mindre.
En sak att notera är att i ifsatserna för minus-utgångarna så släcker man utgången när pulsen tar slut, men man rör inte utgången när pulsen börjar. Det är för att säkerställa så inte den negativa pulsen kan fortsätta.
Det går inte att ladda upp bilder verkar det som, jag får försöka förklara.
När den negativa pulsen ska ta slut så sätter man variablen fasxmaAktiv till 0. Då kommer interruptet
Kod: Markera allt
ISR(TIMER1_OVF_vect) {
  if (fas1mAktiv == 1)
    digitalWrite(fas1m, HIGH);
  if (fas2mAktiv == 1)
    digitalWrite(fas2m, HIGH);
  if (fas3mAktiv == 1)
    digitalWrite(fas3m, HIGH);
}

Låta bli att sätta utången hög.
MEN
Om utgången blev satt hög precis innan actTime blev tillräckligt hög så kommer hela PWM-perioden att gå färdigt.
Med 4 kHz så är periodtiden 0,25 ms med en duty cycle på över 40% så kommer både fasXp och fasXm leda samtidigt.
Därför ser jag till att släcka utgången manuellt.
Jag har lagt fasXmAktiv = 0 innan digitalWrite(fasXm, LOW) för att det annars kan hända att interruptet sker mellan dessa två rader.

Mycket text blev det, hoppas något blir klarare.
Har du bra gate-drivare? Det är ganska enkelt att öka på frekvensen ännu mer om man vill.
Jag har funderat på om man skulle använda även timer2 och tror att jag skulle lyckas ändra duty-cycle under varje period om du vill ha mer sinus-form på strömmen.
Kan dessutom vara en bra idé att hålla nere komplexiteten på koden.

/Kristoffer
Vet dock inte om det ger något?

3 personer gillar det här inlägget.
sm6ywk
Fler än 100 inlägg
 
Blev medlem: 12:40:41, 10-03-2013
Ort: Ale kommun, Västra Götaland
Maskintyp: Traktor
Maskin: BM 650

Janson1 (trådstartaren)

#185 » 09:26:31, 30-11-2022
  • Överför markerat ord till lexikonet

Joda K, det ger mycket att tugga på. Vissa grejer förstod jag direkt och andra inte alls... Men det kommer nog. Jag tror jag förstår tänket rakt av i alla fall!

1 person gillar det här inlägget.
Janson1
Fler än 500 inlägg
 
Blev medlem: 12:50:52, 21-03-2010
Ort: Mark Västra Götaland
Sverige
Maskintyp: Grävmaskin (larvburen)
Maskin: Bobcat X125 (2.5 ton)
Case CK-15 (Kubota kx41)
+ div. flygplan, helikoptrar
Senaste renoveringsobjekten:
Piper PA-24 Comanche från -64 (flyger nu)
Ferguson Grålle/VW diesel 1952/2002 (rullar nu)
10 Kw solcellsanläggning som surrar och går.
Försöka få till ett Ö-drift elsystem utifall att...

Janson1 (trådstartaren)

#186 » 13:23:20, 04-12-2022
  • Överför markerat ord till lexikonet

Ett tag sen... Jodå, jag har bra gatedrivers (vad jag tror i alla fall, IR-2101 heter kretsen) och jag kör dom på 18 volt som ligger ganska nära max spänning. Jag mätte på en "färdig" krets och där är 7-8 Khz som högfrekvens. Jag gissar på att för låg frekvens ger hackig utsignal och för hög frekvens ger mer switchförluster. Får tänka på det...
Janson1
Fler än 500 inlägg
 
Blev medlem: 12:50:52, 21-03-2010
Ort: Mark Västra Götaland
Sverige
Maskintyp: Grävmaskin (larvburen)
Maskin: Bobcat X125 (2.5 ton)
Case CK-15 (Kubota kx41)
+ div. flygplan, helikoptrar
Senaste renoveringsobjekten:
Piper PA-24 Comanche från -64 (flyger nu)
Ferguson Grålle/VW diesel 1952/2002 (rullar nu)
10 Kw solcellsanläggning som surrar och går.
Försöka få till ett Ö-drift elsystem utifall att...

Janson1 (trådstartaren)

#187 » 22:12:14, 05-12-2022
  • Överför markerat ord till lexikonet

Det är en del saker jag inte riktigt greppat... Först i koden på inlägg #182 raderna efter void loop() ""Räknar ut alla tider för att slippa lägga CPU-tid på det i loopen"" Är det forloopen under som gör att tiderna bara räknas ut en gång? Skulle man inte kunna lagt den i set upen? Eller finns det en annan finess där? Som jag ser det så är det väldigt enkelt att ändra både bulsbrädd och total switchfrekvens via ICR1 = 4000; som är switchfrekvensen och OCR1A = 2000; som är pulsbrädden. Nu önskar jag kunna ändra pulsbrädden under drift via en analogingång för VFB (Volt FeedBack) Jag provade i din kod K. men den verkar inte vilja läsa av analogread utav någon anledning... Sen är det ju det här med analogläsning som tar ca 100 uS. Hur och när bör man lägga den för att inte störa alt att den stör lika mycket överallt och sen ändrar man totaltiden som en slags kompensation?
Janson1
Fler än 500 inlägg
 
Blev medlem: 12:50:52, 21-03-2010
Ort: Mark Västra Götaland
Sverige
Maskintyp: Grävmaskin (larvburen)
Maskin: Bobcat X125 (2.5 ton)
Case CK-15 (Kubota kx41)
+ div. flygplan, helikoptrar
Senaste renoveringsobjekten:
Piper PA-24 Comanche från -64 (flyger nu)
Ferguson Grålle/VW diesel 1952/2002 (rullar nu)
10 Kw solcellsanläggning som surrar och går.
Försöka få till ett Ö-drift elsystem utifall att...

Janson1 (trådstartaren)

#188 » 22:19:40, 05-12-2022
  • Överför markerat ord till lexikonet

Passade även på att uppdatera min egen kod så nu kör jag Arduinos egna 490 Hz PWM på dom tre nedre transistorerna och sen ställer man med poten VFB (VoltFeedBack) som ställer total ontid på dom övre och PWM:en på dom nedre transistorerna. Det låter en del i trafon men den drar mindre ström vid låg kräm och mer vid större PWM och mer ontid så detta kan nog funka fast det blir väldigt grovhugget att dela upp varje halvperiod i bara några få steg (5-6 st) ?
Janson1
Fler än 500 inlägg
 
Blev medlem: 12:50:52, 21-03-2010
Ort: Mark Västra Götaland
Sverige
Maskintyp: Grävmaskin (larvburen)
Maskin: Bobcat X125 (2.5 ton)
Case CK-15 (Kubota kx41)
+ div. flygplan, helikoptrar
Senaste renoveringsobjekten:
Piper PA-24 Comanche från -64 (flyger nu)
Ferguson Grålle/VW diesel 1952/2002 (rullar nu)
10 Kw solcellsanläggning som surrar och går.
Försöka få till ett Ö-drift elsystem utifall att...

sm6ywk

#189 » 16:37:58, 06-12-2022
  • Överför markerat ord till lexikonet

Angående uträkningarna så ska de nog ligga i setup() på arduino-maner. Lite ovan att skriva så, förstår inte riktigt poängen.
Jag är van att man skriver en egen while(true) som är samma sak som arduinos void loop().
Allt som ligger innan min while(true) kan man flytta till setup().

Jag lade till en analogRead i min kod.
Jag hade gjort en kod med A/D som inte tar alls mycket CPU tid (största delen tid i en analogRead är att vänta på att avläsningen ska bli klar), men den är väck.
Kan göra en ny.

Hur ser din kod ut när du provar analogRead()?

Jag lade till en analogRead där man borde ha nära 3000 us på sig att utföra den.
Det ser bra ut i wowki, förutom ett skolexempel på vad som händer om man ändrar OCR1A till ett lägre värde än vad timern är för stunden.
Timern kommer då fortsätta räkna till ICR1 utan att stöta på OCR1A, det kommer bli 100% pulsbredd i en puls.
Bild
Skulle man vilja undvika detta så kan man kolla timer-värdet och ändra timervärdet.
Typ (otestad kod).
Kod: Markera allt
If(4*value < TCNT1){
  TCNT1 = 0;
}


Prova gärna koden om du vill.
Kod: Markera allt
// här sätts namnen på utgångar och ingång.
uint8_t fas1p = 8;               // fas 1 plus till ben 8
uint8_t fas1m = 7;               // fas 1 minus till ben 7
uint8_t fas2p = 6;               // fas 2 plus till ben 6
uint8_t fas2m = 5;               // fas 2 minus till ben 5
uint8_t fas3p = 4;               // fas 3 plus till ben 4
uint8_t fas3m = 3;               // fas 3 minus till ben 3

uint8_t fas1mAktiv = 0; //Flagga som talar om ifall fas1 minus trasistor ska pulsa.
uint8_t fas2mAktiv = 0; //Flagga som talar om ifall fas2 minus trasistor ska pulsa.
uint8_t fas3mAktiv = 0; //Flagga som talar om ifall fas2 minus trasistor ska pulsa.


//Interrupt som sker när timer1 når OCRA1, kanske mer logiskt att ha if-satser
//men det är aldrig farligt att släcka en utgång för mycket, så det tar bara onödig CPU-tid.
ISR(TIMER1_COMPA_vect) {
  digitalWrite(fas1m, LOW);
  digitalWrite(fas2m, LOW);
  digitalWrite(fas3m, LOW);

}
ISR(TIMER1_OVF_vect) {
  if (fas1mAktiv == 1)
    digitalWrite(fas1m, HIGH);
  if (fas2mAktiv == 1)
    digitalWrite(fas2m, HIGH);
  if (fas3mAktiv == 1)
    digitalWrite(fas3m, HIGH);
}


void setup() {
  pinMode(debugPin, OUTPUT);
  digitalWrite(debugPin, HIGH);
  // put your setup code here, to run once:
  pinMode(fas1p, OUTPUT);         // här fastställs benen att bli utgångar
  digitalWrite(fas1p, LOW);       // här ställs utgången aktivt låg.
  pinMode(fas2p, OUTPUT);         // osv
  digitalWrite(fas2p, LOW);
  pinMode(fas3p, OUTPUT);
  digitalWrite(fas3p, LOW);
  pinMode(fas1m, OUTPUT);
  digitalWrite(fas1m, LOW);
  pinMode(fas2m, OUTPUT);
  digitalWrite(fas2m, LOW);
  pinMode(fas3m, OUTPUT);
  digitalWrite(fas3m, LOW);       // nu är alla utgångar satta till aktivt låg (offläge)


  //Ställ in timer 1 för att genera interrupt för PWM
  //Timer 1 ställs in för att generera 4 kHz PWM. Timern konfigureras för Fast PWM (mod14)
  //Timern räknar från 0 till ICR1, interrupt genereras när den passerar OCR1A och när den når ICR1.
  //Vid OCR1A ställs utgång hög, vid ICR1 låg. Duty-cycle ändras med OCR1A, frekvens med ICR1.
  //Ursprungsvärden ICR1 = 4000 (16MHz/4000 = 4 kHz), OCR1A = 2000
  TCCR1A = 0x00;
  TCCR1A &= ~(1 << WGM10);
  TCCR1A |= (1 << WGM11);
  //TCCR1B
  TCCR1B = (1 << WGM12);
  TCCR1B |= (1 << WGM13);
  TCCR1B |= (1 << CS10); //prescaler = 1

  //OCR1A
  //Vilket timervärde som interrupt där utgång sätts låg. (0-ICR1)
  OCR1A = 2000;
  ICR1 = 4000;
  //TIMSK1
  //Interruptkontroll för timer 1,
  TIMSK1 |= (1 << OCIE1A);
  TIMSK1 |= (1 << TOIE1);

}


void loop() {

  unsigned long start;
  uint16_t actTime;

  //Räknar ut alla tider för att slippa lägga CPU-tid på det i loopen
  int ontime = 9900;
  int trettigrad = 1667; //30 grader vid 50 Hz, hjälper till att räkna tider.
  int fas1pPeakTime = trettigrad * 3; //Mitten av tiden som fas 1 ska vara positiv (5000us)
  int fas1mPeakTime = trettigrad * 9; //Mitten av tiden från start som fas 1 ska vara negativ (15000us)
  int fas2pPeakTime = trettigrad * 7;
  int fas2mPeakTime = trettigrad * 1;
  int fas3pPeakTime = trettigrad * 11;
  int fas3mPeakTime = trettigrad * 5;

  int fas1pStart = fas1pPeakTime - ontime / 2;
  int fas1pStop = fas1pPeakTime + ontime / 2;
  int fas1mStart = fas1mPeakTime - ontime / 2;
  int fas1mStop = fas1mPeakTime + ontime / 2;

  int fas2pStart = fas2pPeakTime - ontime / 2;
  int fas2pStop = fas2pPeakTime + ontime / 2;
  //int fas2mStart = fas2mPeakTime-ontime/2;
  int fas2mStart = 20000 + fas2mPeakTime - (ontime / 2);

  int fas2mStop = fas2mPeakTime + ontime / 2;

  int fas3pStart = fas3pPeakTime - ontime / 2;
  //int fas3pStop = fas3pPeakTime+ontime/2;
  int fas3pStop = fas3pPeakTime + (ontime / 2) - 20000;

  int fas3mStart = fas3mPeakTime - ontime / 2;
  int fas3mStop = fas3mPeakTime + ontime / 2;

  int i,value;
  uint8_t doAnalogRead;

  //for (i = 0; i < 5; i++) {
    while(true){
    actTime = 0;
    start = micros();
    doAnalogRead=1;

    while (actTime <= 20000) { //Kollar att tiden sedan start inte passerat en period (20ms)
      actTime = micros() - start;

      if (actTime >= fas1pStart && actTime <= fas1pStop)
        digitalWrite(fas1p, HIGH);
      else
        digitalWrite(fas1p, LOW);

      if (actTime >= fas1mStart && actTime <= fas1mStop)
        fas1mAktiv = 1;
      else {
        fas1mAktiv = 0;
        digitalWrite(fas1m, LOW);
      }

      if (actTime <= fas3pStart && actTime >= fas3pStop)
        digitalWrite(fas3p, LOW);
      else
        digitalWrite(fas3p, HIGH);

      if (actTime >= fas3mStart && actTime <= fas3mStop)
        fas3mAktiv = 1;
      else {
        fas3mAktiv = 0;
        digitalWrite(fas3m, LOW);
      }

      //Omvänd logik P.G.A. ontiden passerar utanför perioden.
      if (actTime <= fas2mStart && actTime >= fas2mStop) {
        fas2mAktiv = 0;
        digitalWrite(fas2m, LOW);
      }
      else
        fas2mAktiv = 1;

      if (actTime >= fas2pStart && actTime <= fas2pStop)
        digitalWrite(fas2p, HIGH);
      else
        digitalWrite(fas2p, LOW);

      if(doAnalogRead == 1 && actTime > fas1mStop){
        doAnalogRead=0;
        value=analogRead(A0);
        if(value < 1000)
          OCR1A = 4* value;
        else
          OCR1A = 4000;
      }
    }

  }
  //noInterrupts();
  //while(true){}
}


Har du tänkt lägga in en PID för att styra utspänning? Eller är du nöjd med en pot?

/K
sm6ywk
Fler än 100 inlägg
 
Blev medlem: 12:40:41, 10-03-2013
Ort: Ale kommun, Västra Götaland
Maskintyp: Traktor
Maskin: BM 650

Janson1 (trådstartaren)

#190 » 20:51:19, 06-12-2022
  • Överför markerat ord till lexikonet

I dag har jag en återkoppling från trafons sekundärsida rakt in i kortet. Spänningen hamnar från början någonstans lite över 300 volt dc som jag sen spänningsdelar via 5-6 seriemotstånd och en pot vars mitt går in på analogingång A6. Som en extra säkerhet har jag även en zenerdiod på 5.6 volt utifall att... Jag tycker nu i efterhand inte om denna koppling med högspänning rakt in i kortet, så jag kommer dels bygga om det till trafo som sänker till kanske 5-6 Vac, en eller två VA räcker i storlek och sen blir det nog tre små spänningskännande transformatorer istället. Sen själva styreriet har jag inte riktigt gjort färdigt men Arduino har en funktion MAP som gott duger till detta utan att ta för mycket tid i anspråk. Att timern helt plötsligt blir upptagen med nåt annat förstår jag men borde det inte gå att låta timern köra analogread under väntetider då PWM är låg (eller hög)?
Denna kod förstår jag inte alls: If(4*value < TCNT1 ){ TCNT1 = 0; }
Annars ett kanske större problem med 4 Khz är att nu när jag med hjälp av en säck-kärra släpat in trefastrafon så är det bara att konstatera, den låter för j*vligt, det gnisslar precis som gamla trefas motorstyrningar gjorde förr...
Det går ju att välja mindre nummer än 4000 och få lite högre frekvens, samtidigt minskar ju antal olika steg i PWMen men det är så otroligt många ändå kvar. Jag testar din kod sen. Tack K!
Janson1
Fler än 500 inlägg
 
Blev medlem: 12:50:52, 21-03-2010
Ort: Mark Västra Götaland
Sverige
Maskintyp: Grävmaskin (larvburen)
Maskin: Bobcat X125 (2.5 ton)
Case CK-15 (Kubota kx41)
+ div. flygplan, helikoptrar
Senaste renoveringsobjekten:
Piper PA-24 Comanche från -64 (flyger nu)
Ferguson Grålle/VW diesel 1952/2002 (rullar nu)
10 Kw solcellsanläggning som surrar och går.
Försöka få till ett Ö-drift elsystem utifall att...

sm6ywk

#191 » 01:26:04, 07-12-2022
  • Överför markerat ord till lexikonet

Det är skönt att slippa högspänning!
Blir mycket säkrare att labba! Låter som en bra idé med trafos.
Förstår inte riktigt vad du menar med timern upptagen?
När jag tänker på det så kan man ganska enkelt flytta uppdateringen av duty-cycle till ISR(TIMER1_OVF_vect).
Då kan man ha en sats i stora loopen som bestämmer ett värde för OCR1A som man mellanlagrar i en global variabel.
Så uppdaterar man det i interruptet.
Det farliga med att ha för hög frekvens på PWM är att en allt större del av processorns tid går åt till att stacka undan allt och exekvera interruptet.
Men lite högre borde gå bra att gå utan problem, men kanske inte 40 kHz.

Måste backa igen på vart beräkningarna ska ligga.
Gör man beräkningarna i setup så måste man ha globala variabler för att nå dem i loop. Då det sitter i ryggmärgen att undvika det så ligger uträkningarna i loop.

Jag kunde inte hjälpa att klura lite, måste erkänna att detta är en bit över min kompetens, men om man ändrar switchfrekvensen kontinuerligt och slumpmässigt så borde transformatorn låta mindre.
Jag har dock aldrig provat.
Jag testade att få ner mina funderingar i kod.
Uppdaterar bara varje 50 Hz period, borde kunna göra det 6 gånger så ofta.
Har lagt in en analogRead(A0), ändra om poten sitter på någon annan ingång.
Kod: Markera allt
// här sätts namnen på utgångar och ingång.
uint8_t fas1p = 8;               // fas 1 plus till ben 8
uint8_t fas1m = 7;               // fas 1 minus till ben 7
uint8_t fas2p = 6;               // fas 2 plus till ben 6
uint8_t fas2m = 5;               // fas 2 minus till ben 5
uint8_t fas3p = 4;               // fas 3 plus till ben 4
uint8_t fas3m = 3;               // fas 3 minus till ben 3

uint8_t fas1mAktiv = 0; //Flagga som talar om ifall fas1 minus trasistor ska pulsa.
uint8_t fas2mAktiv = 0; //Flagga som talar om ifall fas2 minus trasistor ska pulsa.
uint8_t fas3mAktiv = 0; //Flagga som talar om ifall fas2 minus trasistor ska pulsa.

uint16_t PWMComp = 2000;
uint16_t PWMTop = 4000;
//Interrupt som sker när timer1 når OCRA1, kanske mer logiskt att ha if-satser
//men det är aldrig farligt att släcka en utgång för mycket, så det tar bara onödig CPU-tid.
ISR(TIMER1_COMPA_vect) {
  digitalWrite(fas1m, LOW);
  digitalWrite(fas2m, LOW);
  digitalWrite(fas3m, LOW);

}
ISR(TIMER1_OVF_vect) {
  if (fas1mAktiv == 1)
    digitalWrite(fas1m, HIGH);
  if (fas2mAktiv == 1)
    digitalWrite(fas2m, HIGH);
  if (fas3mAktiv == 1)
    digitalWrite(fas3m, HIGH);
  //Upptaterar värden för PWM
  ICR1 = PWMTop;
  OCR1A = PWMComp;
}


void setup() {
  // put your setup code here, to run once:
  pinMode(fas1p, OUTPUT);         // här fastställs benen att bli utgångar
  digitalWrite(fas1p, LOW);       // här ställs utgången aktivt låg.
  pinMode(fas2p, OUTPUT);         // osv
  digitalWrite(fas2p, LOW);
  pinMode(fas3p, OUTPUT);
  digitalWrite(fas3p, LOW);
  pinMode(fas1m, OUTPUT);
  digitalWrite(fas1m, LOW);
  pinMode(fas2m, OUTPUT);
  digitalWrite(fas2m, LOW);
  pinMode(fas3m, OUTPUT);
  digitalWrite(fas3m, LOW);       // nu är alla utgångar satta till aktivt låg (offläge)


  //Ställ in timer 1 för att genera interrupt för PWM
  //Timer 1 ställs in för att generera 4 kHz PWM. Timern konfigureras för Fast PWM (mod14)
  //Timern räknar från 0 till ICR1, interrupt genereras när den passerar OCR1A och när den når ICR1.
  //Vid OCR1A ställs utgång hög, vid ICR1 låg. Duty-cycle ändras med OCR1A, frekvens med ICR1.
  //Ursprungsvärden ICR1 = 4000 (16MHz/4000 = 4 kHz), OCR1A = 2000
  TCCR1A = 0x00;
  TCCR1A &= ~(1 << WGM10);
  TCCR1A |= (1 << WGM11);
  //TCCR1B
  TCCR1B = (1 << WGM12);
  TCCR1B |= (1 << WGM13);
  TCCR1B |= (1 << CS10); //prescaler = 1

  //OCR1A
  //Vilket timervärde som interrupt där utgång sätts låg. (0-ICR1)
  OCR1A = 2000;
  ICR1 = 4000;
  //TIMSK1
  //Interruptkontroll för timer 1,
  TIMSK1 |= (1 << OCIE1A);
  TIMSK1 |= (1 << TOIE1);


}


void loop() {
  unsigned long start;
  uint16_t actTime;

  //Räknar ut alla tider för att slippa lägga CPU-tid på det i loopen
  int ontime = 9700;
  int trettigrad = 1667; //30 grader vid 50 Hz, hjälper till att räkna tider.
  int fas1pPeakTime = trettigrad * 3; //Mitten av tiden som fas 1 ska vara positiv (5000us)
  int fas1mPeakTime = trettigrad * 9; //Mitten av tiden från start som fas 1 ska vara negativ (15000us)
  int fas2pPeakTime = trettigrad * 7;
  int fas2mPeakTime = trettigrad * 1;
  int fas3pPeakTime = trettigrad * 11;
  int fas3mPeakTime = trettigrad * 5;

  int fas1pStart = fas1pPeakTime - ontime / 2;
  int fas1pStop = fas1pPeakTime + ontime / 2;
  int fas1mStart = fas1mPeakTime - ontime / 2;
  int fas1mStop = fas1mPeakTime + ontime / 2;

  int fas2pStart = fas2pPeakTime - ontime / 2;
  int fas2pStop = fas2pPeakTime + ontime / 2;
  //int fas2mStart = fas2mPeakTime-ontime/2;
  int fas2mStart = 20000 + fas2mPeakTime - (ontime / 2);

  int fas2mStop = fas2mPeakTime + ontime / 2;

  int fas3pStart = fas3pPeakTime - ontime / 2;
  //int fas3pStop = fas3pPeakTime+ontime/2;
  int fas3pStop = fas3pPeakTime + (ontime / 2) - 20000;

  int fas3mStart = fas3mPeakTime - ontime / 2;
  int fas3mStop = fas3mPeakTime + ontime / 2;

  int i, value;
  uint8_t doAnalogRead;
  uint16_t PWMTempComp;
  uint16_t PWMTempTop;
  uint8_t PWMDuty = 50;
  //for (i = 0; i < 5; i++) {
  while (true) {
    actTime = 0;
    start = micros();
    doAnalogRead = 1;

    while (actTime <= 20000) { //Kollar att tiden sedan start inte passerat en period (20ms)
      actTime = micros() - start;

      if (actTime >= fas1pStart && actTime <= fas1pStop)
        digitalWrite(fas1p, HIGH);
      else
        digitalWrite(fas1p, LOW);

      if (actTime >= fas1mStart && actTime <= fas1mStop)
        fas1mAktiv = 1;
      else {
        fas1mAktiv = 0;
        digitalWrite(fas1m, LOW);
      }

      if (actTime <= fas3pStart && actTime >= fas3pStop)
        digitalWrite(fas3p, LOW);
      else
        digitalWrite(fas3p, HIGH);

      if (actTime >= fas3mStart && actTime <= fas3mStop)
        fas3mAktiv = 1;
      else {
        fas3mAktiv = 0;
        digitalWrite(fas3m, LOW);
      }

      //Omvänd logik P.G.A. ontiden passerar utanför perioden.
      if (actTime <= fas2mStart && actTime >= fas2mStop) {
        fas2mAktiv = 0;
        digitalWrite(fas2m, LOW);
      }
      else
        fas2mAktiv = 1;

      if (actTime >= fas2pStart && actTime <= fas2pStop)
        digitalWrite(fas2p, HIGH);
      else
        digitalWrite(fas2p, LOW);

      if (doAnalogRead == 2) {
        PWMTempTop = random(3000, 5000);
        PWMTempComp = map(PWMDuty, 0, 100, 0, PWMTempTop);
        noInterrupts(); //Stäng av interrupts så inte timervärdena kan uppdateras medan de ändras
        PWMTop = PWMTempTop;
        PWMComp = PWMTempComp;
        interrupts();//Slå på interrupts
        doAnalogRead = 0;

      }
      //Läs av A0 och använd det till att ändra Duty-cycle
      if (doAnalogRead == 1 && actTime > fas1mStop) {
        doAnalogRead = 2;
        value = analogRead(A0);
        PWMDuty = map(value, 0, 1024, 0, 100);
      }
    }
  }

}
//noInterrupts();
//while(true){}
sm6ywk
Fler än 100 inlägg
 
Blev medlem: 12:40:41, 10-03-2013
Ort: Ale kommun, Västra Götaland
Maskintyp: Traktor
Maskin: BM 650

Janson1 (trådstartaren)

#192 » 08:16:29, 07-12-2022
  • Överför markerat ord till lexikonet

Timern upptagen, jag tänker på den pulsen som blir 100% on vid analoginläsning, men det kanske är helt fel?
Jag kan se random 3000-5000 på ett ställe, så vid varje uppdatering där så tar den ett godtyckligt tal som motsvarar högsta frekvens 5,33 Khz och lägsta 3,2 Khz. Det bör väl gå att kolla vilken switchfrekvens "riktiga" invertrar jobbar med... Jag tror utan att veta men med dagens fina MOS-transistorer eller IGBT så kan man nog lägga sig över hörbar frekvens utan att få för mycket switchförluster. Men då har vi nog bottnat ATmega-kretsen för länge sedan... Jag har ju NANO med RP-2040, den har rent allmänt lite bättre snurr på allt.
Men först testa random frekvens med din kod K. !
Janson1
Fler än 500 inlägg
 
Blev medlem: 12:50:52, 21-03-2010
Ort: Mark Västra Götaland
Sverige
Maskintyp: Grävmaskin (larvburen)
Maskin: Bobcat X125 (2.5 ton)
Case CK-15 (Kubota kx41)
+ div. flygplan, helikoptrar
Senaste renoveringsobjekten:
Piper PA-24 Comanche från -64 (flyger nu)
Ferguson Grålle/VW diesel 1952/2002 (rullar nu)
10 Kw solcellsanläggning som surrar och går.
Försöka få till ett Ö-drift elsystem utifall att...

Janson1 (trådstartaren)

#193 » 20:14:26, 08-12-2022
  • Överför markerat ord till lexikonet

Random frekvens testad: Nu låter trafon som ett fågelbo men det är inte lika enerverande längre. Jag tror det är värt att leta upp en frekvens som stör så lite som möjligt? Analogstyrningen funkar som den ska fast "åt fel håll", en bagatell i sammanhanget! Jag går fortfarande i väntans tider vad gäller litteraturen på AVR-kretsarna, men den kommer nog. Jag funderar på att börja labba lite mer aktivt med timrarna och göra egna små programsnuttar för att just förstå dess hemligheter...
Fortsättning följer!
Janson1
Fler än 500 inlägg
 
Blev medlem: 12:50:52, 21-03-2010
Ort: Mark Västra Götaland
Sverige
Maskintyp: Grävmaskin (larvburen)
Maskin: Bobcat X125 (2.5 ton)
Case CK-15 (Kubota kx41)
+ div. flygplan, helikoptrar
Senaste renoveringsobjekten:
Piper PA-24 Comanche från -64 (flyger nu)
Ferguson Grålle/VW diesel 1952/2002 (rullar nu)
10 Kw solcellsanläggning som surrar och går.
Försöka få till ett Ö-drift elsystem utifall att...

Janson1 (trådstartaren)

#194 » 20:36:21, 08-12-2022
  • Överför markerat ord till lexikonet

Ett snabbtest med timern ställd på 1000, det ger 16 Khz som switchfrekvens och då låter trafon (i mina öron) ingenting vad gäller högfrekvens, bara ca 150 hz nätbrum. Om inte det blir för mycket switchförluster nu så tänker jag köra med detta och lite högre effekter. Just nu har jag bara ett simpelt nätaggregat på kanske 60 Watt så det blir inga större belastningstest än...

1 person gillar det här inlägget.
Janson1
Fler än 500 inlägg
 
Blev medlem: 12:50:52, 21-03-2010
Ort: Mark Västra Götaland
Sverige
Maskintyp: Grävmaskin (larvburen)
Maskin: Bobcat X125 (2.5 ton)
Case CK-15 (Kubota kx41)
+ div. flygplan, helikoptrar
Senaste renoveringsobjekten:
Piper PA-24 Comanche från -64 (flyger nu)
Ferguson Grålle/VW diesel 1952/2002 (rullar nu)
10 Kw solcellsanläggning som surrar och går.
Försöka få till ett Ö-drift elsystem utifall att...

Janson1 (trådstartaren)

#195 » 07:14:17, 09-12-2022
  • Överför markerat ord till lexikonet

En annan viktig grej nu vad gäller PWM och dess reglering. Dels skall PWM:en regleras för att hålla en så lika utspänning som möjligt vid tex olika laddningsnivåer i batterierna. Dels skall PWM:en ha olika pulsbredd på olika ställen i förloppet per period för att komma så nära sinus som möjligt. En regleringsmetod för detta skulle kunna se ut enligt följande: Först ett fast förhållande där PWM:en börjar med ytterst små pulser som sedan ökar till maxtid vid mitten av vågen för att sedan minska igen och bli ytterst små på slutet igen. Detta PWM pulståg har alltid samma grundförhållande. Sedan läggar man på tid per puls enligt ett annat fast mönster som motsvarar utgående spänningshållning vid högre strömuttag/lägre batterispänning. Här tror jag man är tvungen att välja en switchfrekvens som är någotsånär rätt till att gå jämnt ut med 50 hz? (Annars tror jag sinusen blir osymetrisk i ena eller andra änden) 16000/50 = 320, faktiskt ett jämnt värde 320/2 = 160. Så varje halvperiod kommer att ha 160 olika on/offtider om man utnyttjar fullt ut... Behövs detta tro?
Sen nästa grej är ju transformatorn och dess inkoppling. Jag har ju en trefastrafo som jag kan koppla på lite olika sätt. Primären där som den sönderhackade trefas 24 volten går in kommer jag triangelkoppla, det blir alldeles fel utspänning annars. Med bara 24 volt som källa så blir utgångsspänningen i minsta laget också så jag tänkte triangelkoppla även där och får då ingen nolla men däremot 230 volt mellan faserna istället. Då jag inte behöver trefas egentligen till någonting så kan man ju lika gärna köra vidare så. Fördelen med detta är att man sprider ut belastningen på flera lindningar hur man än lastar trafon vilket jag ser som en fördel. (Sen har jag en trefas trafo till, en betydligt större som är 1:2 dvs den skulle passa fint om man vill ha 3 fas 400 volt med nolla, men kanske overkill?)
Janson1
Fler än 500 inlägg
 
Blev medlem: 12:50:52, 21-03-2010
Ort: Mark Västra Götaland
Sverige
Maskintyp: Grävmaskin (larvburen)
Maskin: Bobcat X125 (2.5 ton)
Case CK-15 (Kubota kx41)
+ div. flygplan, helikoptrar
Senaste renoveringsobjekten:
Piper PA-24 Comanche från -64 (flyger nu)
Ferguson Grålle/VW diesel 1952/2002 (rullar nu)
10 Kw solcellsanläggning som surrar och går.
Försöka få till ett Ö-drift elsystem utifall att...


Återgå till Energi och uppvärmning

Vilka är online

Användare som besöker denna kategori: bonnen513 och 4 gäster



Älmeboda Maskinservice

OilQuick

TK Traktordelar

Klaravik

Crazyride

Bra Verktyg

Motrab

Engcon

Scandcut

Astrak

Olsson Parts

Nya och begagnade
truckar på vstruck.se