Annunciator

Projecten die niet passen in bovenstaande onderwerpen
Berichten: 163
Geregistreerd: 15 Dec 2012, 21:02
Woonplaats: Delfzijl

Annunciator

Berichtdoor FPCUser » 16 Apr 2016, 14:58

Hier een klein projectje gemaakt in eclipse met de arduino plugin.
Dit omdat ik toch wel nieuwsgierig ben geworden na de berichten van Nico
over het uitkomen van versie 3. (op 1 april j.l.!)

Ik heb meestal geen vast doel voor ogen om iets specifieks te maken maar ben
meer geïnteresseerd in het 'hoe zou het ook kunnen'.
Daarbij is de keus gevallen op een annunciator panel of te wel een
storingstableau.
Het is dus geen afgewerkt procect maar een 'proof of concept'.

Een storingstableau bestaat uit een aantal ingangen en een gelijke aantal
leds of lampjes. Wordt een ingang hoog gemaakt ten teken dat er een storing is,
dan gaat een desbetreffend ledje branden. Was dit de eerste melding, dan
knippert het ledje, was het een volgende melding dan brand het continue.
Op deze manier kan men een zekere vorm van 'oorzaak en gevolg' krijgen.
Is er een storing gemeld dan wordt ook een uitgang hoog gezet waarmee men een
buzzer kan activeren, of een doormelding naar een centrale post, of een bericht
op een telefoon kan laten zetten, of.....
Op het storingstableau is een drukknop aangesloten waarmee men de storing(en)
kan accepteren. De extern alarm uitgang wordt weer laag gemaakt (de buzzer gaat
uit, of....).
Wordt deze drukknop langer dan 5 seconden ingedrukt dan gaan alle ledjes
branden ter controle.

U begrijpt het al, ledjes die knipperen en een inschakelvertraging van 5 sec.
En gelijktijdig moet het programma de ingangen blijven scannen op
storingsmeldingen. We kunnen de opdracht delay() dus niet gebruiken!


Uit bovenstaande rolt dan als vanzelf het programma in pseudo code:

ingangen scannen,
vaststellen of er een storing is
zo ja, extern contact zetten en knipper (puls-pauze) relais starten
vaststellen of de knop storing accepteren gedrukt is
zo ja, extern contact uitzetten

met als extra een lamp- of led test

Voor elke actie is een functie gemaakt, die in de loop() worden aangeroepen.
De functies zelf zijn (hopelijk) zodanig geschreven dat de code zelfverklarend
is.

cpp code
/*
Annunciator panel
5 ingangen als test
Board: Arduino/Genuino Uno

Werking:
Rusttoestand, alle storingsingangen zijn laag, extern alarm is laag.
Eerste storing: storingsingang wordt hoog, desbetreffende uitgangsled gaat
knipperen. Extern alarm wordt hoog.
Volgende storingen: storingingangen worden hoog, desbetreffende uitgangsleds
gaan continue branden.
Storing accepteren: led eerste storing gaat van knipperen naar continue als
storing nog aanstaat, anders gaat led uit.
Van de volgende storingen blijft de led branden als de storing nog aanstaat,
anders gaan de leds uit.
Extern alarm wordt laag.
Led test: accepteren langer dan 5 seconden hoog maken.
*/

#include "Arduino.h"

#define resetPin 2 // reset en led-test pin
#define externPin 13 // externe meldings pin
#define MAX 5 // aantal storingsmelders

byte inPin[] = {3, 4, 5, 6, 7}; // array met pinnrs. ingangen
byte uitPin[] = {8, 9, 10, 11, 12}; // array met pinnrs. uitgangen
bool MsrffVast[MAX]; // merkerarray SR flipflop 'vast'
bool MrsffKnip[MAX]; // merkerarray RS flipfop 'knipper'
bool MeldingUit; // merkerbit storingsdoormelding

bool storingStatus = false; // storing(en) aanwezig = true
bool resetStatus = false; // storing(en) accepteren = true
bool knipperPuls; // led hoog = true

unsigned long MpauzeTijd; // merkerwoord pauzetijd puls/pauze relais
unsigned long MpulsTijd; // merkerwoord pulstijd puls/pauze relais
unsigned long Mvertraging = 0; // merkerwoord inschakelvertraging ledtest


// function prototypes

void scanIngangen();
void leesIngang(byte pin, byte ledPin, bool& srff_vast, bool& rsff_knip,
bool status, bool reset, bool puls);
void controleer();
void startKnipperPuls();
void accepteren(byte pin);
void externMeldingUit(bool& Merker);
void ledTest();
bool TC(unsigned long & pauzeStatus, unsigned long pauzeTijd,
unsigned long & pulsStatus, unsigned long pulstijd);
bool TON(bool ingang, unsigned long & timerStatus, unsigned long timertijd);


// implementation

void setup() {
for (byte i = 0; i < MAX; i++)
pinMode(uitPin[i], OUTPUT);
pinMode(externPin, OUTPUT);
}

void loop() {
scanIngangen();
controleer();
startKnipperPuls();
accepteren(resetPin);
externMeldingUit(MeldingUit);
ledTest();
}


// programmafuncties

/**
@brief De storingsingangen één voor één afvragen
@details De functie leesIngang() wordt in een for-next lus zo vaak aangeroepen
als er ingangen zijn.
*/
void scanIngangen() {
for (byte i = 0; i < MAX; i++) {
leesIngang(inPin[i], uitPin[i], MsrffVast[i], MrsffKnip[i], storingStatus,
resetStatus, knipperPuls);
}
}

/**
@brief Storingseenheid leesIngang
@details Als de ingangspin 'storing' hoog is, wordt de uitgangs ledpin
afwisselend hoog en laag als dit de eerste storingsmelding is.
Is er reeds een andere melding binnengekomen, dan is de uitgang
continue hoog.
Bij accepteren wordt ook de eerste melding continue hoog.
@param [pin] Ingang storingspin
@param [ledPin] Uitgang ledpin
@param [srff_vast] Merker SR flipflop vast
@param [rsff_knip] Merker RS flipflop knipper
@param [status] Op een of meerdere ingangen wordt een storing waargenomen
@param [reset] Accepteren
@param [puls] Knipperpuls
*/
void leesIngang(byte pin, byte ledPin, bool& srff_vast, bool& rsff_knip,
bool status, bool reset, bool puls) {
bool storing = digitalRead(pin);
rsff_knip = ((storing && !status) || rsff_knip) && !reset;
srff_vast = (storing && status && !rsff_knip) || (srff_vast && !reset);

if ((rsff_knip && puls) || srff_vast)
digitalWrite(ledPin, HIGH);
else
digitalWrite(ledPin, LOW);
}

/**
@brief Storingsstatus vaststellen
@details Storingstatus veranderd van 'false' naar 'true' als er minimaal
één storing is binnengekomen.
"Guess and Check" methode.
*/
void controleer() {
storingStatus = false;
for (byte i = 0; i < MAX; i++) {
if (MsrffVast[i] || MrsffKnip[i])
storingStatus = true;
}
}

/**
@brief Start van het puls-pauze relais
@details Wanneer de storingstatus 'true' is wordt het puls-pauze relais
gestart en blijft actief zolang dat het geval is.
Starten met een puls: MpauzeTijd = 0, MpulsTijd = 1,
starten met een pauze: MpauzeTijd = 1, MpulsTijd = 0.
*/
void startKnipperPuls() {
if (storingStatus)
knipperPuls = TC(MpauzeTijd, 1000, MpulsTijd, 1000);
else {
MpauzeTijd = 0;
MpulsTijd = 1;
}
}

/**
@brief Drukknop storing(en) accepteren.
@param [pin] pinnummer
*/
void accepteren(byte pin) {
if (digitalRead(pin))
resetStatus = true;
else
resetStatus = false;
}

/**
@brief externMeldingUit
@details Bij binnenkomende storingen wordt de externe doormelding hoog.
Bij het accepteren wordt de externe doormelding weer laag gezet,
ook als er nog meldingen staan.
@param [Merker]
*/
void externMeldingUit(bool& Merker) {
/*
Opmerking: SR flipflop => Q1=S1+(Q1.!R), dus geinverteerde reset.
Nu is de restingang nogmaals geinventeerd, zie schema, !!R = R.
En toestand wordt vastgehouden in merker.
*/
Merker = resetStatus || (Merker && storingStatus);
if (storingStatus & !Merker)
digitalWrite(externPin, HIGH);
else
digitalWrite (externPin, LOW);
}

/**
@brief Led test
@details Na 5 seconden de knop accepteren ingedrukt te hebben worden alle
uitgangsleds hoog.
@param [resetStatus]
@param [Mvertraging]
@param [wachttijd]
*/
void ledTest() {
if (TON(resetStatus, Mvertraging, 5000)) {
for (byte i = 0; i < MAX; i++)
digitalWrite(uitPin[i], HIGH);
}
}


//hulpfuncties

/**
@brief Puls-pauze relais of asynchrone impulsgever
@details De returnwaarde is gedurende de ingesteld pulstijd (ms) 'true',
daarna gedurende de pauzetijd 'false' enz.
@param [pauzeStatus] status pauzetijd
@param [pauzeTijd] pauzetijd(ms)
@param [pauzeStatus] status pulstijd
@param [pauzeTijd] pulstijd(ms)
@return true/false knipperPuls
*/
bool TC(unsigned long & pauzeStatus, unsigned long pauzeTijd,
unsigned long & pulsStatus, unsigned long pulstijd) {
if (pulsStatus == 0) {
if (pauzeStatus == 1)
pauzeStatus = millis();
else
if (millis() > (pauzeStatus + pauzeTijd)) {
pauzeStatus = 0;
pulsStatus = 1;
}
return (false);
}

if (pauzeStatus == 0) {
if (pulsStatus == 1)
pulsStatus = millis();
else
if (millis() > (pulsStatus + pulstijd)) {
pulsStatus = 0;
pauzeStatus = 1;
}
return (true);
}
}

/**
@brief Inschakelvertraging (Time On Delay)
@details Bij het hoog gaan van de ingang begint de ingestelde tijd (ms)
te lopen. Na het verstrekken van deze tijd wordt de uitgang 'true'.
Wordt de ingang laag dan wordt de uitgang 'false'.
@param [ingang] enable/disable
@param [timerStatus] status
@param [timerPeriot] tijdvertraging(ms)
@return true/false
*/
bool TON(bool ingang, unsigned long & timerStatus, unsigned long timertijd) {
if (!ingang)
timerStatus = 0; // wis timer
else {
if (timerStatus == 0) { // Timer is nog niet gestart
timerStatus = millis(); // timerStatus krijgt huidige tijd (ms)
return (false); // tijd is nog niet verstreken
}
else {
// Timer is gestart, kijk of tijd is verstreken
if (millis() > (timerStatus + timertijd))
return (true); // tijd is verstreken
else
return (false); // tijd is nog niet verstreken
}
}
}


Ik wil wel wat uitgebreider ingaan op de functie leesIngang(), omdat dat eigenlijk
de belangrijkste functie is waar het allemaal om draait.

< tekening als bijlage>

Het functieblok-diagram mag de werking duidelijk maken.
Een functieblok diagram bestaat uit blokjes die een bepaalde functie hebben en
aan elkaar geknoopt worden.
Links staan de ingangs parameters van de functie en rechts is de uitgang.

Als u nog niet zo bekend bent met de digitale techniek volgt hier een zeer
beknopte uitleg.

De digitale ingangen en uitgangen van de arduino kunnen twee
toestanden aannemen, nl. of hoog (5 volt voor de Uno) of laag (0 volt).
We spreken ook wel van 1 en 0, of true en false. Dit is ook van toepassing op
de functieblokjes.
De blokjes met het '&'teken, de nrs 1, 2 en 5 zijn 'en' poorten. Dat wil zeggen
dat de uitgang 1 is als alle ingangen 1 zijn. Is één ingang 0 dan is de uitgang
ook 0.
Blok nr. 6 is een 'of' poort, uitgang is 1 als er minimaal één ingang 1 is.
Blok nr. 3 is een R/S flipflop en blok nr.4 is een S/R flipflop. De uitgang van
beide wordt 1 door de "set" ingang kortstondig 1 te maken en wordt weer 0 als
de "reset" ingang kortstondig 1 gemaakt is. Het verschil tussen beide flipflops
is het gedrag als gelijktijdig de "set"als de "reset" ingangen 1 gemaakt worden.
Bij een R/S flipflop is de reset ingang dominant, de uitgang wordt dus 0, en bij
een S/R flipflop is de set ingang dominant, de uitgang wordt 1.
Dit volgens IEC 61131-3, Siemens volgt met haar Step 5 software een iets andere
benadering :-), maar dit terzijde.

In rust zijn alle ingangen 0, dus zowel knipperpuls, alarm, status en reset.

Men kan nu het verloop van de in- en uitgangen hier in aantekenen.
Samenvattend: bij een eerste melding wordt de R/S flipflop, blok 3 geset, en bij de
volgende meldingen de melding(en) de S/R flipflop, blok 4, natuurlijk van (een) andere
ingang(en).


Het programma is gemaakt voor 5 ingangen. Wil je meer dan gebruik je de analoge
ingangen ook. De schakeling voor de ingangen is: een trekweerstand van ingang naar
aarde van 10K en een maker tussen +5V en ingang. Pas dit aan als je brekers als
storinggevers wilt hebben.
Kortom: voldoende ruimte voor eigen initiatief...
Bijlagen
leesIngang.gif
leesIngang.gif (19.83 KiB) 2984 keer bekeken

Advertisement

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

Re: Annunciator

Berichtdoor shooter » 16 Apr 2016, 20:15

Ik heb een deel van de beschrijving gelezen, morgen de rest of zo.
wel een leuke denkoefening!

tjonge zeg het zijn nogal wat regels, maar ach vroeger was het allemaal elektronisch of zelfs met relais. (ik heb nog een stel tekeningen liggen hoor.
Uiteraard zoals je gewend bent, heb ik wel een paar opmerkingen:
als een alarm optreedt altijd knipperen , en alarm en sound aan.
dan drukknop silence bedienen dan stopt de herrie, maar verder niets, als er dan weer een alarm optreedt weer de toeter aan, dit met een SR doen, ik heb wel vaker gezien dat die drukknop met een gewicht vastgezet wordt, dus daar moet dan eigenlijk een trigger voorstaan om dat te voorkomen.
de lamp blijft knipperen (2 seconden aan, 1 seconde uit als alarm nog bestaat anders 1 aan 2 uit.
dan is er dus tijd om naar het alarm te gaan kijken, als er iets aan gedaan is dan accepteren. en dan inderdaad lampje uit als alarm uit is en anders aan.
als er in die tijd een ander alarm optreedt weer sound en lamp en alarm weer aanzetten.en deze anders dan ik begrijp van je ook laten de lamp knipperen en niet aan, want dat zou betekenen dat je die al accept en dat is niet waar.(en inderdaad je kunt dan geen volgorde meer zien bij meerdere alarmen.
lamp test NOOIT op accept, maar apart uitvoeren (vroeger zaten daar allemaal diodes tussen)

Ik maak dit vaak in IEC61131 (PLC).
is een module met als eerste een type NC en NO te kiezen, en een array(byte) bit 0 is not used (inhibit), bit 1 is alarm, bit 2 is accept, bit 3 timer, bit 4 is hysteresis (voor analoge signalen) (ik gebruik tegenwoordig structure maar dat maakt de code erg groot, maar wel duidelijker we zijn het tijdperk van geheugen krapte wel voorbij.
kijk eens bij oscat.de (is wel op PLC gericht maar jij kunt dat wel lezen denk ik, zoek de oscat333.txt versie
paul deelen
shooter@home.nl

Berichten: 163
Geregistreerd: 15 Dec 2012, 21:02
Woonplaats: Delfzijl

Re: Annunciator

Berichtdoor FPCUser » 17 Apr 2016, 09:35

@Shooter.

Bedankt voor je opmerkingen en adviezen.
Deze zijn altijd welkom, het is goed dat een ander eens naar m’n knudsels kijkt.
Anders wordt ik ‘bedrijfsblind’ :)

Accepteren en led-test worden verschillende pinnen.
Accepteren ga ik veranderen zodat je deze niet vast kan zetten. Een RS flipflop die
na een zekere tijd zich reset, of d.m.v. flankdetectie, ik zie nog wel.
Ik wou wel een ‘eerste melding’ indicatie hebben, dus alle storingen knipperend
binnen laten komen weet ik nog niet.
Het is nu wel zo, dat als na het accepteren er nog meerdere storingen voorstaan, deze vast
branden. Valt er een weg en komt direct weer, of er komt een nieuwe bij, dan branden
deze ook vast. Dat wil ik gaan veranderen in knipperen zodat je kunt zien: nieuwe storing.
Maar hoe, dat weet ik nog niet.

Een hoop regels, dat wel maar als je het commentaar weglaat dan valt het nog wel mee.
Dat commentaar heb ik echter wel nodig anders weet ik de volgende week niet meer wat de bedoeling van het stukje code is.
Het korte termijn geheugen van mij is pet!

Van je tip orcat.de heb ik inmiddels de tekstversie van de 333.lib opgehaald en de documentatie pdf.
Nog meer huiswerk. Ik ben naar het laat aanzien de komende weken nog wel even bezig. ;)

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

Re: Annunciator

Berichtdoor nicoverduin » 17 Apr 2016, 09:38

Er is niks mis met je code hoor :) Beter dan wat ik al een tijdje zie!!. Zorg er wel voor dat de parameters die je in de functies hebt ook corresponderen met de Doxygen documentatie. Nu klopt ie niet.
Docent HBO Technische Informatica, Embedded ontwikkelaar & elektronicus
http://www.verelec.nl

Berichten: 163
Geregistreerd: 15 Dec 2012, 21:02
Woonplaats: Delfzijl

Re: Annunciator

Berichtdoor FPCUser » 17 Apr 2016, 10:55

@Nico,

Bedankt voor je oplettende blik!
Tja, dat is een van m'n mankementen, niet voldoende doordenken: :oops:
Als je op de ene plaats iets veranderd, heeft dat meestal ook gevolgen op een andere plaats.

Ik heb de boel eens goed? nagekeken en veranderd in mijn origineel.

Terug naar Overige projecten

Wie is er online?

Gebruikers in dit forum: Geen geregistreerde gebruikers en 44 gasten