Waar moet ik beginnen??

Alles wat niet past in bovenstaande onderwerpen
Berichten: 287
Geregistreerd: 15 Apr 2021, 20:05

Re: Waar moet ik beginnen??

Berichtdoor ctunes » 09 Mei 2021, 01:16

@Frits1956

Wat stoorde U eigenlijk in mijn manier van reageren?
Pas als ik dat weet kan ik wellicht mijn methode wijzigen, zodat die tenminste op Frits1956-normen van toepassing is.

Advertisement

Berichten: 287
Geregistreerd: 15 Apr 2021, 20:05

Re: Waar moet ik beginnen??

Berichtdoor ctunes » 09 Mei 2021, 02:49

Weet je wat het leuke is van al deze "projectjes"?
Ze zetten je eerst aan het zelf te proberen, en als je er dan niet uit komt verwachten ze een "patreon" (of iets soortgelijks) subsidie.
Vervolgens verschijnen er op youtube filmpjes waarin alles "perfect werkt".

Maar als je het daadwerkelijk kopen wilt, komt het nooit beschikbaar ...
En als je het nabouwen wilt, mis je altijd cruciale informatie.

Het lijkt wel te mooi om waar te zijn.
En wat heeft handelen op marktplaats ons geleerd? Als het te mooi is om waar te zijn? .... Niets, blijkbaar.


Hieronder staat een stukje code dat ik zelf gemaakt heb.
Voel je vrij commentaar te geven op de plekken die verbeterd kunnen worden.

Het emuleert 1:1 een "Ferrari F1 Wheel" op een "Thrustmaster racing wheel base" (Ook in "advanced mode")

Getest op zowel een 168P als 328P met gebruik van de 8MHz interne oscillator.

De rotary encoders werken niet in deze publieke uitgave, wel in de commerciële.

cpp code
#include <Arduino.h>
//#include "RotaryEncoder.h"
#define NOP __asm__ __volatile__ ("nop\n\t")

#define PIN_IN1 A4 // Encoder pin A
#define PIN_IN2 A5 // Encoder pin B

#define W_INDEX 10 // When an F1 wheel is attached, base will read 10 bytes.
#define FREQ 63000 // This value makes the timer tick at around 1500Hz (with an 8MHz clocked chip); increase to go faster.


//RotaryEncoder encoder1(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::TWO03);
//RotaryEncoder encoder2(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::TWO03);

volatile byte wIndex = 0, // Index to wState
CTS = 0; // "Clear To Send", used to update wState outside of base polling.

byte wState[W_INDEX] = { // 1 and 0 are fixed bits that identify F1 wheel, n is reset by pressing -and set by releasing- the corresponding switch.
0b11001111, // n100 nnnn -> buttons 5, F1 wheel code, 1, 2, 3, 4
0b11111111, // nnnn nnnn -> buttons 13, 6, 7, 8, 9, 10, 11, 12
0b11111111, // nnnn nnnn -> buttons 21, D_d, D_r, D_l, D_u, 20,19,18
0b11111111, // 1nnn n111 -> "buttons" 16, 14, 15, 17, which is in realty: Re_CCW, Le_CCW, Le_CW, Re_CW
0b00000000, // nnnn nnnn -> left encoder; 0000 0000 when not turning, 0100 0000 for button 15 (CW rotation) 1111 1111 for button 14 (CCW rotation)
0b00000000, // nnnn nnnn -> right endocer; 0000 0000 when not turning, 0100 0000 for button 17 (CW rotation) 1111 1111 for button 16 (CCW rotation)
0b01100000, // 0110 0000 -> makes the base recognise an F1 Wheel
0b01000000, // 0100 0000 -> makes the base recognise an F1 Wheel
0b01111111, // 0111 1111 -> F1 wheel specific. When the base recognises an F1 wheel it pulls 10 bytes.
0b01111111 // 0111 1111 -> idem.
};

ISR(PCINT0_vect) { // Base wants next cycle of wState[]

if (!(PINB & 0b00000100)) { // SS is active, must do work
CTS = 0; // Halt updates of wState
wIndex = 0; // Reset index pointer
SPDR = wState[wIndex]; // Load first byte in SPI-shiftregister.
} else CTS = 1; // Updates to wState are allowed, i.e. SS is high at this point

};

ISR(SPI_STC_vect) { // First transaction (PCINT0_vect) has completed, prepare next byte.
SPDR = wState[++wIndex];
if (wIndex > 7) { // previous encoder state has been sent, now it's ok to clear them
wState[3] |= 0b00110000; // reset encoder "buttons" 15 and 14
wState[4] = 0b00000000; // clear direction
wState[3] |= 0b01001000; // reset encoder "buttons" 17 and 16
wState[5] = 0b00000000; // clear direction
}
};

ISR(TIMER1_OVF_vect) {

// if (PINC & 0b00001000) encoder1.tick(); // Which encoder is currently selected? i.e. is pin A3 HIGH?
// else encoder2.tick(); // update the currently selected encoder

asm ("sbi %0, %1 \n": : "I" (_SFR_IO_ADDR(PINC)), "I" (PINC3)); // Toggle state of pin A3, implemented in assembly.

TCNT1 = FREQ;

}; // End of TIMER1_OVF_vect


void doButtons() {

if (CTS) {
for (byte x = 0 ; x < 3 ; x++) {

DDRC |= 1 << x ; // Change port Ax from 3-state to OUTPUT
NOP; //(See paragraph 13.2.4 on page 60/61 of atmega168 datasheet)

wState[x] = (PINB << 6) | (PIND >> 2); // shift PB1 and PB0 and PD7..2 in

DDRC &= ~(1 << x); // Change port Ax from OUTPUT to 3-state
NOP; //(See paragraph 13.2.4 on page 60/61 of atmega168 datasheet)
}
}
} // doButtons()

void doEncoders() {

static int pos1, pos2;

if (CTS) {
int newPos1 = encoder1.getPosition();

if (pos1 != newPos1) {
if ( (int)(encoder1.getDirection()) == 1 ) {
wState[3] &= 0b11101111; // "button" 15
wState[4] = 0b01000000; // CW
}
else {
wState[3] &= 0b11011111; // "button" 14
wState[4] = 0b11111111; // CCW
}
pos1 = newPos1;
}

int newPos2 = encoder2.getPosition();

if (pos2 != newPos2) {
if ( (int)(encoder2.getDirection()) == 1 ) {
wState[3] &= 0b11110111; // "button" 17
wState[5] = 0b11111111; // CW
}
else {
wState[3] &= 0b10111111; // "button" 16
wState[5] = 0b01000000; // CCW
}
pos2 = newPos2;
}
}
} // doEncoders()

void setup() {

PORTB |= 0b00000011; // PB1, PB0 PULLUP ** NOTE ** internal pullups are to weak, need external 10k pullups.
DDRB &= ~0b00000011; // PB1, PB0 input

PORTD |= 0b11111100; // PD7..2 PULLUP ** NOTE ** internal pullups are to weak, need external 10k pullups.
DDRD &= ~0b11111100; // PD7..2 input

PORTC &= ~0b00001000; // set encoder select pin A3 LOW
DDRC |= 0b00001000; // set encoder select pin A3 output


PORTC &= ~0b111; // no pullups for A2..A0, i.e. 3-state. (high-Z)
DDRC &= ~0b111; // A2..A0 input

cli();
// Setup Timer ...
TCCR1A = 0;
TCCR1B = 0b00000001; // last three bits set the prescalar, to the left is slower. We want fastest.
TIMSK1 |= (1 << TOIE1); // enable timer overflow interrupt
TCNT1 = FREQ;

// Initialise SPI interface ...
DDRB |= 0b00010000; // D12 = MISO = OUTPUT
PCMSK0 |= 0b00000100; // Enable PCINT2 (external INT for port D10/SS) See page 74 of atmega168 datasheet
SPCR |= 0b11000000; // Enable SPI-interface (slave mode)
PCICR |= 0b00000001; // Enable PCIE0 (interrupt control register for PCINT7..0) See page 73 of atmega168 datasheet
sei();

}; // setup()

void loop() {

doButtons();
// doEncoders();
idle();

// That's all folks.

}; // loop()




Maar aan deze code heb je uiteindelijk niets zonder de bijbehorende hardware.

Je kunt er wel iets van leren.

Afbeelding

@fritz1956 "F1 racing" is correct gegokt, als je wilt racen moet je eerst leren vliegen?

En vraag me nu nog eens: "Hoe moet ik een buttonbox aansluiten?"



::

Waarom werkt dit
Code: Alles selecteren
int newPos1 = encoder1.getPosition();

wel, en dit:
Code: Alles selecteren
unsigned long currentMillis = millis();

niet?

Laat ik als puzzelstukje achter.

(Het is niet moeilijk, als je het verschil tussen functie en methode kent, ofwel weet waar C en C++ verschillen volgens de compiler.


Hier is het schema overigens:
Afbeelding


Zodat het tenminste duidelijk is dat ik niet weet waar ik het over heb.

Berichten: 180
Geregistreerd: 26 Aug 2015, 11:57

Re: Waar moet ik beginnen??

Berichtdoor Frits1956 » 09 Mei 2021, 09:40

RichardZ schreef:beste Frits ,

Heb de code geprobeerd maar er gebeurd niks het ledje gaat niet branden.

Maar als ik de code goed begrijp zou de interval bij iedere loop met 200millis verlangd moeten worden?


Jouw redenatie klopt maar zoals ik al schreef, heb ik een klein foutje gemaakt. Dit foutje leg ik nu uit.
De arduino wordt aangezet, de interne teller staat op 0, de variabelen previousMillis staat op 0 en interval staat op 1000
we gaan de setup in en vertellen de controler dat pin nr LED_BUILTIN gebruikt moet worden voor output
we gaan de loop in, we kijken welke waarde de interne teller heeft en geven variabele currentMillis deze waarde
currentMills zal op 1 komen te staan, de interval is nog steeds 1000, previousMillis is ook nog steeds 0
we vergelijk of 1-0 >= 1000, zo ja, dan voeren we de if uit.
Nu komt de fout!!!! Vervolgens is de eerste opdracht VERHOOG INTERVAL MET 200
We gaan opnieuw de loop in we kijken welke waarde de interne teller heeft en geven variabele currentMillis deze waarde
currentMillis heeft nu de waarde 2, previousMillis de waarde 0 en interval de waarde 1200
we vergelijk of 2-0 >= 1200, zo ja, dan voeren we de if uit. Je ziet al, currentMillis zal op deze manier nooit >= interval worden.
Er is een uitzondering:
interval is van het type long en dat kan maar maximaal 2147483647 bevatten. tel je er nog een bij op, dan wordt het getal negatief en krijgt het de waarde -2,147,483,648. Als de loop vaak genoeg wordt uitgevoerd zal currentMillis dan dus groter zijn.
In het herstelde voorbeeld is het ophogen van interval alleen als de if wordt uitgevoerd.

Ik hoop je weer een beetje op weg te hebben geholpen.

Berichten: 20
Geregistreerd: 28 Apr 2020, 21:24

Re: Waar moet ik beginnen??

Berichtdoor RichardZ » 09 Mei 2021, 10:06

beste Frits,

jouw uitleg begin ik een beetje te snappen, dus ik zal vanavond wel weer ff gaan proberen.

Want wat ctunes verteld gaat me allemaal een beetje te snel.

Berichten: 180
Geregistreerd: 26 Aug 2015, 11:57

Re: Waar moet ik beginnen??

Berichtdoor Frits1956 » 10 Mei 2021, 01:25

Hoi Richard, ik heb nog wat toegevoegd.
Op de donker groene balk van de IDE helemaal rechts zie je een vergrootglas. Als je met de cursor bovenop gaat staan, komt daar de tekst serial monitor te staan.
Serial monitor is een extra schermpje waarin uitvoer te zien is als je het statement Serial.print() hebt gebruikt.
Tussen de haakjes zet je de variabele waarde die je wil zien.
Om Serial monitor te kunnen gebruiken is het nodig dat je in de setup Serial.begin () aanroept (Zie regel 9) met een snelheidwaarde. Op regel 26 voor ik de statements uit om gewenste waarden in het extra schermpje te laten zien. In dit geval currentMillis en interval.
Zodra je de software hebt ge-upload ga dan naar dat vergrootglas en klik erop.

Verder heb ik het programma aangepast.
Regel 23 begin nu met // en op regel 25 staat hetzelfde statement maar dan zonder // ervoor. Door de comment strepen bij regel 23 weg te halen en op regel 25 toe te voegen en na iedere upload op het vergrootglas te klikken kan je de verschillen zien wat het "verplaatsen" van de regel voor gevolg heeft.

Nogmaals. suc7



Code: Alles selecteren
const int ledPin =  LED_BUILTIN;       // the number of the LED pin
int ledState = LOW;                         // ledState used to set the LED
unsigned long previousMillis = 0;      // will store last time LED was updated
int interval = 100;                           // interval at which to blink (milliseconds)

void setup()
{
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);                        // toegevoegd voor controle middels serial monitor.
}

void loop()
{
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }
    digitalWrite(ledPin, ledState);
    // interval += 200;                   // dit is de juiste plek voor de regel
  }
  interval += 200;                     // dit is de plek waar ik de de eerste keer de regel toevoegde.
  Serial.print(currentMillis); Serial.print(" "); Serial.println(interval); // deze regels zijn toegevoegd om op het scherm de uitvoer te zien.
}

Berichten: 20
Geregistreerd: 28 Apr 2020, 21:24

Re: Waar moet ik beginnen??

Berichtdoor RichardZ » 10 Mei 2021, 20:18

Beste frits,

ik heb jou code uitgeprobeerd en ik zie het volgende gebeuren.

De interval wordt steeds met 200millis vergroot zo blijf het lampje steeds langer aan en uit.

Op de serial Monitor zie ik links de millis steeds verder oplopen en rechts zie ik ook steeds een getal
oplopen eerst positief en daarna negatief.

Dat heeft volgens mij te maken met dat het een INT data type is en die kan tot 32768 en -32768.
maar houd die waarde precies in ? is dat ook gewoon weer millis dus een tijds waarde?

Berichten: 180
Geregistreerd: 26 Aug 2015, 11:57

Re: Waar moet ik beginnen??

Berichtdoor Frits1956 » 10 Mei 2021, 20:57

RichardZ schreef:Beste frits,

Dat heeft volgens mij te maken met dat het een INT data type is en die kan tot 32768 en -32768.
maar houd die waarde precies in ? is dat ook gewoon weer millis dus een tijds waarde?

Het is niet meer of minder dan een getal waarmee gerekend kan worden. 100 koeien, 10 liter, 5 auto's, 3 uren enz.
Je kan er gewoon mee rekenen: 100 koeien *2 is 200 koeien enz.
Het type integer houdt in dat het alleen hele getallen kan bevatten, dus geen decimalen. Dat heeft te maken met hoe een computer getallen opslaat als een verzameling van enen en nullen. zoek hiervoor naar binaire getallen

Gebruikers-avatar
Berichten: 631
Geregistreerd: 15 Nov 2015, 11:54

Re: Waar moet ik beginnen??

Berichtdoor Gij Kieken » 11 Mei 2021, 21:38

Hey Richard,
Heb mij terug wat zitten amuseren,
Code: Alles selecteren
/*
   Under construction
   Date:    11/05/2021
   Author:  Gij kieken
   Purpose: Switch a couple of Led's On and Off at different times
*/

const byte LED1PIN = 4; //LED 1 on pin D4
const byte LED2PIN = 5; //Led 2 on pin D5
//const byte LED3PIN =6; //Led 3 on pin D6
#define On true
#define Off false

unsigned long previousMillis1 = 0; //will store last time LED 1 was updated
unsigned long previousMillis2 = 0; //will store last time LED 2 was updated
//unsigned long previousMillisn = 0; //will store last time LED n was updated
const byte num1Events = 5;  //max number of time events for Led 1
const byte num2Events = 3;  //max number of time events for Led 2
//const byte numnEvents = n;  //max number of time events for Led n
int time1Seq[num1Events] = {2000, 3000, 4000, 5000, 6000};  //incremental On/Off sequences Led 1
int time2Seq[num2Events] = {2345, 2590, 3261};  //incremental On/Off sequences Led 2
//int timenSeq[numnEvents] = {n1, n 2, n..n};  //incremental On/Off sequences Led n
bool led1State = Off; //initial led1State
bool led2State = Off; //initial led2State
//bool lednState = Off; //initial led n State

void setup() {
  pinMode(LED1PIN, OUTPUT); //Led 1 as output
  pinMode(LED2PIN, OUTPUT); //Led 2 as output
  //pinMode(LEDnPIN, OUTPUT); //Led n as output
}

void loop() {
  static byte T1 = 0;
  static byte T2 = 0;
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis1 >= time1Seq[T1]) {
    T1++;
    previousMillis1 = currentMillis;
    if (led1State == Off) {
      led1State = On;
    } else {
      led1State = Off;
    }
    digitalWrite(LED1PIN, led1State);
    if (T1 == num1Events) {
      T1 = 0; //start over again
    }
  }

  if (currentMillis - previousMillis2 >= time2Seq[T2]) {
    T2++;
    previousMillis2 = currentMillis;
    if (led2State == Off) {
      led2State = On;
    } else {
      led2State = Off;
    }
    digitalWrite(LED2PIN, led2State);
    if (T2 == num2Events) {
      T2 = 0; //start over again
    }
  }
}

Berichten: 20
Geregistreerd: 28 Apr 2020, 21:24

Re: Waar moet ik beginnen??

Berichtdoor RichardZ » 14 Mei 2021, 08:39

Beste Gij Kieken,

Allereerst bedankt voor je tijd.
Heb naar jouw code gekeken en uitgeprobeerd op mijn arduino.
Ik zag wat er gebeurde maar van de code snapte ik natuurlijk geen ....

Dus ik heb de serial . begin functie eraan toegevoegd om te zien wat een ledje nou precies doet en wanneer.
Ook zaten er weer nieuwe dingen in de code zoals de define true and false , bool ,static byte.

Dus dat gaat ik dan ook weer ff opzoeken wat dat allemaal inhoud.

Kan ik bij deze regel in de code de waarde aanpassen naar 540 bijvoorbeeld?

const byte num1Events = 5; //max number of time events for Led 1

en waarom moeten we eigenlijk die waarde aangeven?
de waarde worden toch ook al genoemd bij int time1Seq[num1Events]

gr Richardz

Gebruikers-avatar
Berichten: 631
Geregistreerd: 15 Nov 2015, 11:54

Re: Waar moet ik beginnen??

Berichtdoor Gij Kieken » 14 Mei 2021, 10:13

@Richard,
Een aantal zaken kunnen inderdaad wat anders, maar ik heb het gedaan om jouw kennis te laten maken met eventueel wat nieuwe dingen.
Wat betreft de keuze van de variabelen, je kan gemakkelijk bijna overal<int> gebruiken.
Een int is 16-bit en gebruikt bij deze 2-bytes geheugen.
Als je geheugen zat hebt ,zoals hier in dit voorbeeld, is dit geen probleem.
Bij grotere projectjes kan dat soms kritiek worden.
Dus als het niet nodig is en je bijvoorbeeld maar van 0 tot 255 moet tellen,gebruik dan een <byte> 8-bit.
In menig voorbeeldjes vind je dan ook uitdrukkingen als uint8_t en uint16_t wat eigenlijk de standaard benoeming is en veel meer betekenis heeft.
Een bool is ook 8-bit maar wordt gebruikt enkel om, waar of niet waar,weer te geven ,<true> <false>.
Om het wat makkelijker leesbaar te maken in de code kan je dat zelf wat nuanceren met <#define>
In plaats van code te schrijven als de Lamp is <true> is het dan mogelijk om te schrijven de Lamp is <AAN> of de Lamp is <On>.
Voor de verschillende tijdstippen heb ik een array gebruikt per Led, int time1Seq[num1Events] = {2000, 3000, 4000, 5000, 6000};
Die tijden kun je vrij wijzigen naar behoefte
num1Events ,dit zijn het aantal schakel events die je wilt gebruiken voor Led1
Ik gebruik die variabel <num1Events> verder in de code om te weten wanneer heel het zaakje opnieuw moet beginnen.
Initieel starten we b.v. met de Led1 Uit,
op tijdstip T1[0] na 2000msec Led1 Aan,
op tijdstip T1[1] 3000msec later Led1 Uit,
op tijdstip T1[2] nog eens 4000msec later Led1 Aan,
en zo verder.
Dit alles wordt ook gebruikt voor Led2 en Led n.
Op die manier kan je non-blocking een aantal Led's op pseudo verschillende tijdstippen laten schakelen.

VorigeVolgende

Terug naar Theekransje

Wie is er online?

Gebruikers in dit forum: Geen geregistreerde gebruikers en 11 gasten