Dynamische pulsen met Timer1

Arduino specifieke Software
Berichten: 11
Geregistreerd: 11 Jan 2014, 12:38

Dynamische pulsen met Timer1

Berichtdoor liemstra » 01 Aug 2017, 16:22

hallo,
Ben bezig met de A-Mega2560 om een pulstrein te maken die verschillende pulsbreedtes hebben (géén PWM).

Bijvoorbeeld> puls1: level=1,breedte=400µs -- puls2: level=0, breedte=900µs -- puls3: level=1, breedte=500µs -- puls4: level=0,breedte=350µs enz.
Geprobeerd met de Timer1-CTC mode: een 'gewone' pulstrein maken (van bv 400µs) is geen enkel probleem.
Echter, op het moment dat de Timer gestopt wordt om een nieuwe OCR1A waarde in te voeren gaat het fout: de single-puls wordt dan 1.049s ipv de ingestelde 400µs ... .
Gebruikte code is de sketch van: http://www.engblaze.com/microcontroller ... nterrupts/

Wat is er fout gegaan?
Alvast dank!
grtn, liemstra.

Advertisement

Gebruikers-avatar
Berichten: 2655
Geregistreerd: 06 Aug 2016, 01:03

Re: Dynamische pulsen met Timer1

Berichtdoor Koepel » 02 Aug 2017, 04:33

Waar is het voor ? Misschien bestaat er al een library voor.

Ik begrijp niet helemaal wat je bedoelt met: level=1, level=0, level=1

Wanneer je iets wijzigt aan de frequentie of de pwm, dan wordt over het algemeen de timer opnieuw ingesteld.

Kun je jouw sketch laten zien ?

Gebruikers-avatar
Berichten: 5043
Geregistreerd: 13 Mei 2013, 20:57
Woonplaats: Heemskerk

Re: Dynamische pulsen met Timer1

Berichtdoor nicoverduin » 02 Aug 2017, 11:11

Ik denk dat ie met levels bedoeld logic levels.
Docent HBO Technische Informatica, Embedded ontwikkelaar & elektronicus
http://www.verelec.nl

Berichten: 11
Geregistreerd: 11 Jan 2014, 12:38

Re: Dynamische pulsen met Timer1

Berichtdoor liemstra » 02 Aug 2017, 21:01

@koepel: hieronder de gebruikte sketch, rechtoe rechtaan vanaf de engblaze.com site met wat lokale aanpassingen>
// Arduino timer CTC interrupt example
// http://www.engblaze.com
// avr-libc library includes
#include <avr/io.h>
#include <avr/interrupt.h>
#define LEDPIN 3
void setup()
{
pinMode(LEDPIN, OUTPUT);
Serial.begin(9600);
// initialize Timer1
cli(); // disable global interrupts
TCCR1A = 0; // set entire TCCR1A register to 0
TCCR1B = 0; // same for TCCR1B
// set compare match register to desired timer count:
OCR1A = 1;
// turn on CTC mode:
TCCR1B |= (1 << WGM12);
// Set CS10 and CS12 bits for 256 prescaler:
TCCR1B |= (1 << CS12);
// enable timer compare interrupt:
TIMSK1 |= (1 << OCIE1A);
// enable global interrupts:
sei();
}
void loop()
{
// do some crazy stuff while my LED keeps blinking
}
ISR(TIMER1_COMPA_vect)
{
digitalWrite(LEDPIN, !digitalRead(LEDPIN));
}
-------------------------------------------------------------

@nicoverduin: correct, met 'level' bedoelde ik idd de logic levels H en L.
--------------------------------------------------------------
Sorry voor de vaagheden. Hier wat informatie over het project:

1. Waar het voor is: het doel is om data die afkomstig is van een OpenTherm-CV ketel na te spelen op de A-Mega (tbv een andere project). Deze CV data is een zgn Manchester-codestream, waarbij de éénen en de nullen vlgs een bepaalde protocol ontstaan.
Het is dus deze datastream die ik tracht te reproduceren via een Timer procedure. Gedachte is dus: een H-puls genereren van x-µs, de daaropvolgende een L-puls van y-µs enz. enz. Het is dus géén PWM.
Idee is dan om Timer1 in de CTC modus te starten met een bepaalde countwaarde, bv "1" voor een pulsbreedte van 32µs bij een clkfreq van 16MHz en Prescaler=256.
Als je de Timer as-is laat lopen, gaat dit "treintje" perfect. Echter, doel is dan om ná de eerste puls van 32µs de Timer te stoppen en de countwaarde (OCR1A) te wijzigen in, bv"28", om een pulsbreedte te krijgen van "461µs".

Hier gaat het dus fout ... .
Gedrag is: zodra ik Timer1 stop verschijnt op de LogicAnalyzer idd slechts één puls, maar die is niet meer die van "32"µs ... maar een heel 'rare' 1.048s .... (?).

Probleem zou je dus kunnen terugbrengen tot: hoe creëer ik een gedefinieerde single-pulse? Een soort One-Shot ...

2. Er is gekeken/gewerkt met diverse Timer libraries, maar die bieden niet de 'vrijheden' die ik nodig heb voor dit Manchester-code-playback ... .

Dank voor het reageren!
grtn.

Berichten: 4064
Geregistreerd: 16 Okt 2013, 14:31
Woonplaats: s hertogenbosch

Re: Dynamische pulsen met Timer1

Berichtdoor shooter » 02 Aug 2017, 22:03

een andere benadering isbijvoorbeeld een timer te zetten op bijv 100 us en dan 4 pulsen afwachten dan heb je 400 us, of iets dergelijks, dan hoef je niet moeilijk te doen met de timers.
net zoals 60 seconden is 1 minuut.
paul deelen
shooter@home.nl

Gebruikers-avatar
Berichten: 2655
Geregistreerd: 06 Aug 2016, 01:03

Re: Dynamische pulsen met Timer1

Berichtdoor Koepel » 03 Aug 2017, 00:21

Waar kan ik vinden hoe het OpenTherm signaal er uit ziet ?
Als het inderdaad een meervoud is van 100 µs, dan kun je doet wat shooter zegt.
Maar 100 µs is weinig, misschien heb je een snellere Arduino nodig.

Er zijn verschillende libraries die een soort van puls-trein gebruiken:
* IR libraries
* NeoPixel
* OneWire
* DHT11, DHT22
* VirtualWire/RadioHead in TX mode

Bij de NeoPixel komt het er echt op aan. In de broncode (https://github.com/adafruit/Adafruit_NeoPixel/blob/master/Adafruit_NeoPixel.cpp) zie je dat de interrupts uit worden gezet, en assembly code wordt gebruikt om de juiste timing te maken.
De OneWire (https://github.com/PaulStoffregen/OneWire/blob/master/OneWire.cpp) zet ook de interrupts uit en gebruikt direkt naar de registers schrijven om snel een uitgang te wijzigen, en de Arduino delayMicroseconds() functie.

Berichten: 11
Geregistreerd: 11 Jan 2014, 12:38

Re: Dynamische pulsen met Timer1

Berichtdoor liemstra » 03 Aug 2017, 00:40

@paul-shooter: dank voor je reaktie.
Idee is goed, alleen zit dan nog steeds met het basis-issue: om de volgende puls te maken moét ik de Timer stoppen alvorens de countwaarde te wijzigen. En hier gaat het dus fout ... .
Ik mis dus iets/doe iets basiek fout met een of ander register danwel procedure. Alhoewel de voorbeeldsketches allemaal iets 'simpels' zeggen:
<quote>To stop the timer you have to clear the three bits CS10, CS11 and CS12.<endquote>
of ook: <quote>TCCR1A = 0; //set entire TCCR1A (Timer/Counter Control Register) register to 0<endquote>

De Timer stopt inderdaad ... maar de gemaakte puls heeft dan een constante waarde van 1.049s - vandaar m'n vermoeden dat ik iets onrechtmatigs doe.
grtn.

Berichten: 11
Geregistreerd: 11 Jan 2014, 12:38

Re: Dynamische pulsen met Timer1

Berichtdoor liemstra » 03 Aug 2017, 00:49

@koepel:
Hierbij een link waar de Manchester code uitgelegd wordt:
https://en.wikipedia.org/wiki/Manchester_code

De data is dus niet een veelvoud van 100µs, maar kan variëren van 400µs tot 500ms ... . De 'lange' tijden zijn dan wachttijden in de 'conversatie' tussen zender (CV ketel) en ontvanger (CV regelaar).

Dank voor de tips + url's! Zal er naar gaan kijken.
Voor nu ... paar uurtjes op één oor liggen ;-)
grtn.

Gebruikers-avatar
Berichten: 2655
Geregistreerd: 06 Aug 2016, 01:03

Re: Dynamische pulsen met Timer1

Berichtdoor Koepel » 03 Aug 2017, 06:50

Uhm... de bedoeling van dit forum is dat jij laat zien wat niet werkt, en hopelijk kunnen we er dan iets van zeggen of alternatieven aanbrengen.
Kun je misschien de sketch laten zien die het niet doet ? Dan kunnen we dat eventueel zelf proberen. Die sketch die je liet zien laat een ledje knipperen.
Staat ergens beschreven hoe het OpenTherm signaal er precies uit ziet ? Ik weet wat manchester code is.

In plaats van wekenlang (maandenlang) te tobben, zou je kunnen beginnen met iets dat schijnt te werken: https://github.com/amvv/ArduinoOpenTherm.
De OT_encoder werkt met een vaste timer interrupt zoals shooter schreef. Het is een paar jaar oud, dus ik vermoed dat de code bedoeld is voor de Arduino Uno.
In het voorbeeld zie je hoe verschillende waarden kunnen worden gebruikt (MM1, MM2, MM3, MM4).

Ik wilde PulseView + sigrok eens proberen. Dat valt een beetje tegen :( Misschien heb ik nog een oudere versie :?
Test met Arduino Uno en OT_encoder sketch.

Een pin toggle in de interrupt deed ik door pin 13 als output te zetten en in de interrupt een "PINB = bit(5);". Er is een interrupt iedere 512 µs.
Het donkere plaatje is salaea, die kan zelfs Manchester code decoderen.
Bijlagen
toggle.png
Output signaal met pin toggle in interrupt.
toggle.png (6.36 KiB) 10346 keer bekeken
saleae.png
Saleae capture met manchester decodering.
saleae.png (9.62 KiB) 10347 keer bekeken
sigrok.png
PulseView + Sigrok
sigrok.png (16.96 KiB) 10347 keer bekeken

Berichten: 11
Geregistreerd: 11 Jan 2014, 12:38

Re: Dynamische pulsen met Timer1

Berichtdoor liemstra » 03 Aug 2017, 20:42

@koepel:
Mijn excuses ... de manier waarop ik het probleem tracht te schetsen is ietwat 'warrig' ... . Ik geef hieronder nogwel een link naar de omschrijving van het OT protocol: <https://nl.wikipedia.org/wiki/OpenTherm>.
Tegelijkertijd wil ik het daarbij laten - inclusief het Manchester topic. Is op dit moment irrelevant voor mij.

Terug naar je commentaar: hieronder tref je de volledige sketch die ik momenteel gebruik om het probleem duidelijk te maken (is een paar berichten eerder ook al gepubliceerd). Nu met detail toelichting:
- sketch overgenomen van: //http://www.engblaze.com/microcontroller-tutorial-avr-and-arduino-timer-interrupts/
--------------------------------------------------------------------------------------
// Arduino timer CTC interrupt example
// http://www.engblaze.com

// avr-libc library includes
#include <avr/io.h>
#include <avr/interrupt.h>

#define LEDPIN 3

void setup()
{
pinMode(LEDPIN, OUTPUT);
Serial.begin(9600);
// initialize Timer1
cli(); // disable global interrupts
TCCR1A = 0; // set entire TCCR1A register to 0
TCCR1B = 0; // same for TCCR1B

// set compare match register to desired timer count:
OCR1A = 1;
// turn on CTC mode:
TCCR1B |= (1 << WGM12);
// Set CS10 and CS12 bits for 256 prescaler:
//TCCR1B |= (1 << CS10);
TCCR1B |= (1 << CS12);
// enable timer compare interrupt:
TIMSK1 |= (1 << OCIE1A);
// enable global interrupts:
sei();
}

void loop()
{
// do some crazy stuff while my LED keeps blinking
}

ISR(TIMER1_COMPA_vect)
{
digitalWrite(LEDPIN, !digitalRead(LEDPIN));
cli(); // disable global interrupts
//TCCR1B &= ~(1 << CS10 | 1 << CS11 | 1 << CS12); //stop the Timer (clear bits C10,11,12)
//TCCR1A = 0; // set entire TCCR1A register to 0
//TCCR1B = 0; // same for TCCR1B
}
--------------------------------------------------------------------------------------

- negeer commentaar in de (lege-) void loop.
- Saleae capture op Arduino pin 3 én code 'as-is' geeft een correcte pulstrein van 32µs. Zie plaatje hieronder:
ftalk1.jpg
ftalk1.jpg (11.52 KiB) 10323 keer bekeken


Hier is duidelijk te zien dat de gecalculeerde 32µs puls (OCR1A=1, f=16MHz, Prescale=256) ook tevoorschijn komt.

Het probleem doet zich voor wanneer de Timer gestopt wordt in de CompareMatch sectie: code <TCCR1B &= ~(1 << CS10 | 1 << CS11 | 1 << CS12); //stop the Timer (clear bits C10,11,12)> speelt dan mee. De puls ziet er nu opeens alsvolgt uit:
ftalk2.jpg
ftalk2.jpg (11.9 KiB) 10323 keer bekeken


De '32µs' puls is nu '1.049s' geworden .... (!).

Dít is dus (op dit moment) mijn probleem. (skip alle OpenTherm en Manchester texten, nu niet relevant).
Ik doe iets principieels fout ... .
grtn, L.

Volgende

Terug naar Arduino software

Wie is er online?

Gebruikers in dit forum: Bing [Bot] en 13 gasten