Beginners mini-cursus (deel 7)

In dit deel gaan we laagspanningsmotoren met variabele snelheden laten draaien.
Hiervoor staan een paar instructies tot onze beschikking, waardoor dit vrij eenvoudig te realiseren is.

PWM Softwarematige Pulse Width Modulation
HPWM Hardwarematige Pulse Width Modulation

Ook wordt in het deel van de PWM instructie een simpele DAC getoond en in het deel van de HPWM instructie iets met geluid gedaan.
Verder een simpele overbelastingsdetectie met voorbeeldprogrammaatjes voor de hier gebruikte RB35 motoren van Conrad, waar het PIC programma dan weer op kan reageren.

Onder elke schema zit een alternatief schema dat tevoorschijn komt door er met de muis op te gaan staan.
Mensen zonder breedband moeten even wachten tot het extra schema verschijnt als ze op een schema gaan staan.

Nogmaals de tip om de cursus op volledige schermgrootte te bekijken, in verband met schema's (druk op F11).
 


PWM

Softwarematige Pulse Width Modulation

 

De syntaxis
 PWM Pin, Duty, Cycles 

PWM schakelt de opgegeven poort Pin automatisch om als uitgang, voert een opgegeven aantal Cycles pulsen uit van een opgegeven Duty lengte en schakelt de poort Pin daarna om als ingang (= hoog-ohmig).

Pin - Is een Poort . Pin constante waarop het PWM signaal komt.
Na uitvoering van de PWM instructie blijft de pin als ingang achter(!)
Duty - Is een 8-bit (0 ... 255) waarde die de verhouding van het hoog/laag niveau van de puls aangeeft.
Dit wordt de puls-pauze verhouding genoemd.
Dit hoeft geen vast getal (constante) te zijn, maar mag ook de waarde van een variabele of een berekening zijn (zie zodadelijk voorbeelden).
Cycles - Is een 16-bit (0 ... 65535) waarde die het aantal pulsen aangeeft.
Dit hoeft geen vast getal (constante) te zijn, maar mag ook de waarde van een variabele of een berekening zijn.

De cyclus tijd is afhankelijk van de oscillator frequentie.
Als een 4MHz kristal wordt gebruikt dan duurt 1 volledige cyclus 5 milliseconden, bij een 10MHz kristal 2 mSec en bij een 20MHz kristal duurt dat 1 mSec.
Aangezien de voorbeelden in de cursus met de inwendige oscillator werken en de oscillator van een PIC16F628A 4MHz is, duurt een cycle in de voorbeelden dus ook 5 mSec (zie tekening).

De PWM frequentie is bij de instructie PWM dus niet apart in te stellen.
Kristal: PWM frequentie:
4MHz
10MHz
20MHz
      5ms =
2ms =
1ms =
200Hz 
500Hz 
1000Hz 

 

Wat is PWM?
P
ulse Width Modulation (= puls breedte modulatie) is het snel achtereen hoog/laag schakelen van een poort, oftewel een heleboel pulsjes na elkaar op een uitgang, een blokgolf dus.
De verhouding van de tijd tussen de enen en nullen bij PWM wordt de duty cycle genoemd.
Als een PIC16F628A loopt op zijn inwendige oscillator, zoals bij de voorbeelden hier, dan is er om de 5 milliseconden een puls (= 200Hz).
De puls-pauze verhouding is afhankelijk van de waarde van Duty.
Wanneer je bij Duty de minimum waarde 0 ingeeft is er helemaal geen puls, de poort is met 0V constant laag (de dutycycle is dan 0%), en als je de maximale waarde 255 ingeeft is de poort met +5V constant hoog (dutycycle is dan dus 100%).

Je kunt de waarde die je voor Duty moet invullen berekenen door 2,55 te vermenigvuldigen met het gewenste percentage (= in procenten, %) van de dutycycle, oftewel Duty = 2,55 × percentage.
Die berekening kan eventueel ook door de PIC zelf uitgevoerd worden.
Als je bijvoorbeeld een dutycycle van 50% wilt hebben dan is de berekening 2,55 × 50 = 127,5.
Geef dus voor Duty een waarde van 127 op.
Nu is ook de puls hoog/laag verhouding 50/50.
Elke puls is dan 2,5mSec hoog en 2,5mSec laag, de dutycycle is dus 50%.


Motoren
Je kunt het toerental van een motor regelen door de spanning te regelen.
Bij een lagere spanning zal de motor langzamer gaan draaien (zoals een trein op een modelbaan).
Een nadeel is dat de motor dan flink aan kracht inlevert.
Als de motor zeer langzaam draait heeft hij vrijwel geen kracht meer.

Wanneer het toerental met PWM wordt geregeld blijft er meer aan kracht over.
Als PWM de motor langzamer laat draaien dan krijgt de motor wel zijn maximale spanning, alleen niet continu, de motor krijgt als het ware steeds een duwtje met maximale kracht (al is deze manier van denken wel erg kort door de bocht).

Stel je voor dat je met een schakelaar een motor aan/uit kunt zetten.
Als je nu de schakelaar heel vaak, snel aan en uit pulst, zal de motor langzamer draaien dan wanneer je de schakelaar continu op aan laat staan.
Zo kun je dat ook zien met PWM, alleen doet die dat aan/uit schakelen heel snel, waardoor de motor constant langzaam draait.

Aan motoren uit platenspelers en cassettedecks enzovoort heb je eigenlijk niet zo veel.
Ze draaien snel bij weinig kracht, zodat je er bijna niets zinnigs van kunt bouwen.
Bovendien is bij dit soort motoren de snelheid niet mooi te regelen.
Ik heb dit cursusdeel getest met zo'n 10 soorten motoren maar alleen de RB35 motor komt als beste uit de test.
Platenspeler- en cassettedeckmotoren geven een erg bedroevend resultaat.
Motoren uit CD spelers doen het weer wat beter.

In de voorbeelden heb ik een RB35 motor van Conrad gebruikt (zie foto's).
Dit zijn ongelooflijk krachtige 12V motoren, die verkrijgbaar zijn met diverse transmissies (= vertragingskasten).
Je moet flink in een tang knijpen om de as van een motor met vertraging 1:600 tegen te kunnen houden.
Deze motoren zijn met PWM en vooral HPWM supermooi in snelheid (en kracht!) te regelen.
Ik gebruik ze onder andere voor het handdoekrek, de poster verplaatsing, de automatische klapramen en het automatisch badstop.
Dit deel van de cursus is dan ook gebaseerd op deze motor.

Overzicht RB35 motoren

 


Voorbeelden
Sluit eerst een gelijkspanningsmotor aan die geschikt is voor een spanning die ligt tussen 5V en 24V.
Het volgende schema is een zeer eenvoudig schema om een motor aan te sturen.
Grote prestaties moet je van dit schema dus niet verwachten, maar dit is voor degenen die geen speciaal IC willen aanschaffen.
Beter is een schakeling met een speciaal (goedkoop) "motordrive" IC om motoren aan te sturen, dat schema volgt zodadelijk.
Gebruik als het kan dus RB35 motoren om echt resultaat te zien.

8

8 De BC337 kan maximaal 0,5A (= 500mA) leveren.
Ga met de muis op het schema staan voor een alternatief schema.

 

Op één aansluiting van de motor zet je een spanning die overeenkomt met de spanning van de gebruikte motor.
Dus stel dat de motor voor 12VDC is, dan zet je op de ene aansluiting van de motor de + van de 12V.

Door met de muis op het schema te gaan staan zie je een alternatief schema voor degenen die geen tweede, externe voeding hebben.

Het wordt echter afgeraden om een 5V motor rechtstreeks op de voedingslijn van de PIC aan te sluiten, de PIC kan hierdoor van slag raken.
Beter is het om de motor een eigen 7805 spanningsstabilisator of, nog beter, een eigen voeding te geven.

Zoals in het schema is te zien, moet je de massa (0V) van een eventuele tweede voeding verbinden met de massa (0V) van de voeding van de PIC.
De voeding van de PIC hoeft maar een klein ding te zijn (zelfs een batterij behoort tot de mogelijkheden).
Verder ga ik het niet uitleggen, dit is een programmeercursus, geen elektronica cursus.
Heb je echter toch nog vragen met betrekking tot de elektronica, stel ze dan op Circuits Online.


Eerst even een testprogrammaatje om te kijken of de motor werkt en goed is aangesloten.
Het programma schakelt continu 3 seconden de motor aan en daarna 3 seconden de motor uit.

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Poortnamen
SYMBOL Motor = PORTA.6        ;Hierop zit de motor aansturing aangesloten

;        76543210 
TRISA = %10111111             ;Maak van PORTA.6 een uitgang

CLEAR                         ;Wis alle RAM geheugen


;Hoofdprogramma
WHILE 1 = 1                   ;Oneindige lus
  Motor = Motor ^ 1           ;Motor toggle
  DELAYMS 3000                ;Om de 3 seconden de motor aan of uit schakelen 
WEND                          ;Terug naar WHILE

END 

De motor moet hier om de 3 seconden aan of uit gezet worden.
Als dit niet gebeurt eerst onderzoeken waarom niet, omdat anders de rest van de cursus geen zin heeft.


Het volgende voorbeeld laat de motor automatisch van 0 naar maximaal draaien en dan weer terug naar 0.
Dit herhaalt zich continu (door WHILE 1 = 1).

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Variabele declareren
DIM Duty AS BYTE              ;'Duty' is de variabele die de snelheid v.d. motor bepaalt 

CLEAR                         ;Wis alle RAM geheugen


;Hoofdprogramma
WHILE 1 = 1                   ;Oneindige lus
  FOR Duty = 1 TO 255         ;Motor gaat steeds sneller draaien tot maximum (= 255)
    PWM PORTA.6, Duty, 5      ;Stuur 5 pulsen met pulsbreedte 'Duty', naar PORTA.6
  NEXT

  FOR Duty = 254 TO 0 STEP -1 ;Motor gaat steeds langzamer draaien tot 0
    PWM PORTA.6, Duty, 5      ;Stuur 5 pulsen met pulsbreedte 'Duty', naar PORTA.6
  NEXT
WEND                          ;Terug naar WHILE

END 

De PWM instructie is vrij eenvoudig.
In de eerste FOR ... NEXT lus gaat de motor steeds sneller draaien omdat de Duty in de PWM instructie steeds groter wordt, aangezien 'Duty' de telvariabele van de FOR ... NEXT lus is.
De tweede FOR ... NEXT lus die dan uitgevoerd wordt telt terug (STEP -1), waardoor de motor weer langzamer gaat draaien tot aan 0.
Dat is eigenlijk alles.

De eerste FOR ... NEXT lus begint bij 1, waardoor er een heel kort, hoog pulsje op de uitgang verschijnt (met een dutycycle van 1 ÷ 2,55 = 0,39%).
Een dutycycle van 0,39% betekent dat van de totale tijd van PWM (en die is hier 5 mSec), hiervan 0,39% een hoog signaal is, de rest van de tijd is hij laag.
Omdat voor Cycles een 5 is opgegeven, wordt dit korte pulsje 5 keer uitgevoerd.
Steeds als de FOR ... NEXT lus de variabele 'Duty' met 1 verhoogt, zullen de 5 pulsjes op de uitgang steeds langer hoog blijven.
Totdat de telvariabele 'Duty' 255 is geworden, dan is de dutycycle 255 ÷ 2,55 = 100%.
Nu wordt ook de FOR ... NEXT lus verlaten omdat de Eindstand van deze lus is bereikt.

In de tweede FOR ... NEXT lus gebeurt precies hetzelfde, alleen telt deze lus terug (STEP -1), waardoor de pulsjes weer steeds korter hoog zijn en hierdoor de motor steeds langzamer gaat draaien tot stilstand.


Aanbevolen wordt om nu eerst het volgende schema te bouwen met het goedkope "motordrive" IC L293D (€ 3,30 bij Voti, de prijs van nog geen 3 pilsjes).
Met de L293D kun je 2 motoren aansturen die bovendien in beide richtingen kunnen draaien, of 3 motoren waarvan er dan 1 in twee richtingen kan draaien, of 4 motoren die allen dan maar in één richting kunnen draaien.
De volgende paar voorbeelden kúnnen wel met het eenvoudige schema met de BC337 aangestuurd worden, maar dan kun je niet écht mooi het toerental regelen en zie je niet echt wat PWM (en HPWM) doet.
Bovendien kan met de BC337 de motor niet in twee richtingen draaien.
De cursus gaat er vanaf hier vanuit dat je de L293D gebruikt.

8

8 LET OP: het schema gaat uit van de L293D in 16-pins DIL behuizing (dus niet de SMD uitvoering).
Ga met de muis op het schema staan voor een alternatief schema.

 
In dit schema is de voeding van de motor als een losse, aparte (= externe) voeding getekend, voor een alternatief schema even weer met de muis op het schema gaan staan.

De L293D heeft 4 ingangen met de daarbij behorende uitgangen.
In het schema is ingang 2 (pin 7) en uitgang 2 (pin 6) gebruikt.
Alle overige, ongebruikte ingangen moet je verbinden met massa (= GND, 0V) (zie schema Beginners (7b)).
Voor meer informatie even de (eenvoudige) datasheet van de L293D lezen.

Download datasheet L293D


Voorbeelden
Lees in de voorbeelden ook steeds aandachtig de REM regels, die achter de programmaregels staan, ook daarin staat informatie.
Het volgende voorbeeld doet eigenlijk precies hetzelfde als het allereerste programmavoorbeeld, alleen kun je hier wat dingen instellen en is het programma duidelijker doordat met SYMBOL namen aan constanten zijn gegeven.

Het kan zijn dat afhankelijk van de soort motor, deze aardig lang stil blijft staan, terwijl de telvariabele oploopt.
De motor gaat dan bijvoorbeeld pas draaien als 'Duty' al 60 is.
Dat betekent dat de motor stilstaat als de FOR ... NEXT telvariabele een waarde heeft van 0 t/m 59.
In het volgende programma kun je een waarde opgeven voor de minimumsnelheid, dat moet een waarde zijn waarop de motor net niet (meer) draait (even experimenteren wat deze waarde moet zijn).
Het maximum toerental kun je ook opgeven, deze staat hier gewoon op maximaal, een waarde van 255 dus, maar die kun je eventueel wat lager zetten.

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Algemene constanten 
SYMBOL Cycles       = 10      ;(WORD) 'Cycles' van de PWM instructie
SYMBOL MaxSnelheid  = 255     ;(BYTE) Maximale snelheid van de motor
SYMBOL MinSnelheid  = 60      ;(BYTE) Minimale snelheid van de motor

;Poortnamen
SYMBOL Motor        = PORTA.6 ;Hierop zit de motor aansturing aangesloten

;Variabele declareren
DIM Duty            AS BYTE   ;'Duty' is de variabele die de snelheid v.d. motor bepaalt 

CLEAR                         ;Wis alle RAM geheugen


;Hoofdprogramma
WHILE 1 = 1                   ;Oneindige lus
  FOR Duty = MinSnelheid TO MaxSnelheid         ;Motor gaat steeds sneller draaien
    PWM Motor, Duty, Cycles
  NEXT

  FOR Duty = MaxSnelheid TO MinSnelheid STEP -1 ;Motor gaat steeds langzamer draaien
    PWM Motor, Duty, Cycles
  NEXT
WEND                          ;Terug naar WHILE

END

De minimum snelheid van de constante 'MinSnelheid' is in het voorbeeld op 60 gezet.
Het kan zijn dat de motor dan al langzaam draait, dan moet je de waarde dus wat kleiner maken.

Misschien is het je opgevallen dat er geen TRIS in het programma staat.
Dat is hier nog niet nodig want de PWM instructie schakelt de opgegeven poort zelf om als uitgang, voert het aantal pulsjes uit en schakelt dan de poort weer om als ingang.


Hieronder wisselt het toerental steeds abrupt tussen twee snelheden.

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Algemene constanten 
SYMBOL Cycles       = 500     ;(WORD) 'Cycles' van de PWM instructie
SYMBOL Snelheid_1   = 200     ;(BYTE) Eerste snelheid van de motor
SYMBOL Snelheid_2   = 65      ;(BYTE) Tweede snelheid van de motor

;Poortnamen
SYMBOL Motor        = PORTA.6 ;Hierop zit de motor aansturing aangesloten 


;Hoofdprogramma
WHILE 1 = 1                   ;Oneindige lus
  PWM Motor, Snelheid_1, Cycles
  PWM Motor, Snelheid_2, Cycles
WEND                          ;Terug naar WHILE

END

Het aantal Cycles is op 500 gezet.
Dit betekent dat elke PWM instructie nu 500 × 5mSec = 2500mSec (tweeënhalf seconde) duurt.
Dan volgt WEND en begint het weer van voren af aan, dus wordt de eerste PWM weer uitgevoerd, enz.
Het resultaat is dat de motor continu om de 2500mSec tussen 2 snelheden wisselt.


Sluit twee pulsschakelaars aan volgens schema Beginners (7b).
Met het volgende programma is de motorsnelheid te regelen met de beide toetsen die aangesloten zijn op PORTB.0 en PORTB.1.

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Logische constanten
SYMBOL HOOG         = 1       ;Hoog signaal
SYMBOL LAAG         = 0       ;Laag signaal

;Algemene constanten 
SYMBOL StartSnelheid= 127     ;Motorsnelheid waarmee het programma start (Dutycycle 50%)

;Poortnamen
SYMBOL Motor        = PORTA.6 ;Hierop zit de motor aansturing aangesloten
SYMBOL ToetsHoger   = PORTB.0 ;Deze pulstoets laat de motor sneller draaien
SYMBOL ToetsLager   = PORTB.1 ;Deze pulstoets laat de motor langzamer draaien

;Variabelen declareren
DIM Snelheid    AS BYTE       ;Deze variabele bevat de snelheid van de motor

;        76543210 
TRISA = %10111111             ;PORTA.6 is een uitgang voor aansturing motor
TRISB = %11111111             ;PORTB allen ingangen

PORTB_PULLUPS ON              ;On-chip pull-up weerstanden actief (voor de schakelaars) 
CLEAR                         ;Wis alle RAM geheugen


;Hoofdprogramma
Snelheid = StartSnelheid      ;Geef de variabele 'Snelheid' een startwaarde

WHILE 1 = 1                   ;Oneindige lus
  PWM Motor, Snelheid, 10     ;Stuur 10 pulsjes met de grootte van 'Snelheid' naar motor

  ;Als ToetsHoger wordt ingedrukt EN Snelheid is nog niet maximaal, dan snelheid verhogen
  IF ToetsHoger = LAAG AND Snelheid < 255 THEN INC Snelheid

  ;Als ToetsLager wordt ingedrukt EN Snelheid is nog niet minimaal, dan snelheid verlagen 
  IF ToetsLager = LAAG AND Snelheid > 0   THEN DEC Snelheid
  
WEND                          ;Terug naar WHILE

END 

Zodra de PIC wordt opgestart zal de motor op middelmatige snelheid draaien die in de constante 'StartSnelheid' is opgegeven.

Om de snelheid te veranderen moet een toets ingedrukt worden gehouden.
Als de toets wordt losgelaten, blijft de motor op die snelheid draaien, die het op dat moment heeft.
Is 'ToetsHoger' ingedrukt en de snelheid heeft het maximum bereikt, dan wordt de snelheid niet verder verhoogt (dat kan ook niet, je kunt immers niet verder dan 255) en blijft de motor op hetzelfde, maximale toerental draaien.
Andersom geldt dit voor de minimum snelheid ook.

De daal- en stijgsnelheid van de motor bij het indrukken van een toets is afhankelijk van de grootte die voor het aantal Cycles in de PWM instructie is opgegeven.
Ga maar na, hoe meer pulsjes PWM moet geven van de ingestelde snelheid, des te langer duurt het voordat deze instructie hiermee klaar is, aangezien elk pulsje 5 mSec duurt.
Als je bijvoorbeeld een 2 voor Cycles zou opgeven dan duurt de PWM instructie 2 pulsjes × 5mSec = 10mSec.
Maar als je 200 voor Cycles zou invullen dan duurt deze instructie 200 × 5mSec = 1000mSec, maarliefst 1 seconde dus, en zou de snelheid maar om de seconde steeds een stapje omhoog (of omlaag) gaan.
Om dan van 0 (stilstand) naar 255 (maximale snelheid) te komen, zou je de toets 255 seconden ingedrukt moeten houden!


Nu moet de motor worden aangesloten zoals in onderstaand schema.
De motoraansluiting die eerst aan de GND zat, komt nu ook aan de L293D.
Pin 1 en pin 2 van de L293D moeten nu op PORTA.0 en PORTA.7 van de PIC worden aangesloten.
Hierdoor kunnen we de motor in beide richtingen laten lopen en wel of niet laten remmen.

8

8 De rood aangegeven verbindingen zijn gewijzigd ten opzichte van het vorige schema.

 
Met PORTA.0 kun je de uitgangen OUT1 en OUT2 van de L293D in- of uitschakelen (= enable / disable).
Zolang deze PORTA.0 hoog is kun je de motor aansturen en zal de motor remmen als PORTA.6 en PORTA.7 beide laag (of hoog) zijn.
De motor blijft op de rem staan of zal zwaar lopen als je aan de motor-as draait.
Door PORTA.0 laag te maken (= disable OUT1 en OUT2) wordt de motor ontkoppelt en zal de motor vrijlopen (geen rem).

Door PWM pulsjes op PORTA.6 aan te bieden loopt de motor zoals in de vorige voorbeelden.
Met het aansluiten van de motor volgens bovenstaand schema kan deze nu ook in tegengestelde richting draaien.
Hiervoor moeten de PWM pulsjes naar PORTA.7 worden gestuurd, waardoor de motor de andere kant op zal gaan draaien.


De "rem" van de motor
In het volgende voorbeeld zal de motor steeds op maximale snelheid lopen en beurtelings stoppen met "rem" en daarna zonder "rem" en dat doet het programma continu door, waardoor je het verschil zult merken.
Bij de ene soort motor zal het rem effect overigens beter zijn dan bij de andere.
De RB35 motor die ik gebruik laat het verschil heel sterk zien:

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Logische constanten
SYMBOL HOOG         = 1       ;Hoog signaal
SYMBOL LAAG         = 0       ;Laag signaal

;Algemene constanten
SYMBOL Tijd         = 2000    ;mSec: Tijd van draaien en stilstaan

;Poortnamen
SYMBOL MotorEnable  = PORTA.0 ;Motor aansturing ingeschakeld bij hoog niveau
SYMBOL MotorRechtsOm= PORTA.7 ;Motor draait rechtsom

;        76543210 
PORTA = %00000000             ;Alle PORTA uitgangen laag
TRISA = %00111110             ;PORTA.7, A.6 en A.0 zijn uitgangen voor L293D


;Hoofdprogramma
WHILE 1 = 1                   ;Oneindige lus
  ;Motor laten draaien
  MotorRechtsOm = HOOG        ;PORTA.7 hoog maken, motor (rechtsom) laten draaien
  MotorEnable   = HOOG        ;Maak EN1/2 van L293D hoog, OUT1 en OUT2 worden dan actief
  DELAYMS Tijd                ;Even de motor laten draaien

  ;Motor stoppen MET rem
  MotorRechtsOm = LAAG        ;De motor wordt stopgezet met PORTA.7, maar...
  MotorEnable   = HOOG        ;...de enable blijft hoog, waardoor de motor stopt MET rem
  DELAYMS Tijd                ;Tijd om de motor uit te laten draaien, al zal dat kort zijn

  ;Motor laten draaien
  MotorRechtsOm = HOOG        ;PORTA.7 weer hoog maken (motor weer laten draaien)
  MotorEnable   = HOOG        ;De enable was al hoog, dus eigenlijk staat dit er voor niets 
  DELAYMS Tijd                ;Even de motor laten draaien

  ;Motor stoppen ZONDER rem
  MotorRechtsOm = HOOG        ;Nu blijft PORTA.7 hoog en stoppen we de motor...
  MotorEnable   = LAAG        ;...door de enable uit te schakelen, motor stopt ZONDER rem
  DELAYMS Tijd                ;Tijd om de motor uit te laten draaien
WEND

Het programma werkt hier niet met PWM.
De motor wordt gewoon aan of uit gezet door het hoog of laag maken van de poorten.

Is de enable ingang (EN1/2) van de L293D laag, dan is de motor ontkoppelt van de L293D en kan dan vrij lopen als je aan de as draait.
Door hem nu hoog te maken wordt het signaal op IN1 (van de L293D) versterkt weergegeven op OUT1 en het signaal van IN2 op OUT2.
(De andere enable ingang (EN3/4) is voor IN3 met OUT3 en IN4 met OUT4, deze worden hier niet gebruikt).


Met het volgende programma is de motorsnelheid én richting te regelen met S1 en S2 die aangesloten zijn op PORTB.0 en PORTB.1.
Als de PIC opstart staat de motor stil.
Door toets S1 ingedrukt te houden zal de motor steeds sneller linksom gaan draaien en de snelheid aanhouden die het heeft als de toets wordt losgelaten.
Voor S2 geldt hetzelfde alleen zal de motor steeds sneller rechtsom draaien.

Als de motor linksom draait, kan door S1 in te drukken de snelheid dus verhoogt worden.
Met S2 kan de snelheid nu verlaagt worden totdat de motor stilstaat.
Blijf je S2 echter vasthouden dan gaat de motor weer sneller draaien, alleen nu rechtsom.
Om de snelheid weer te verlagen moet nu op S1 gedrukt worden.

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Logische constanten
SYMBOL HOOG         = 1       ;Hoog signaal
SYMBOL LAAG         = 0       ;Laag signaal
SYMBOL LinksOm      = 0       ;
SYMBOL RechtsOm     = 1       ;

;Poortnamen
SYMBOL MotorEnable  = PORTA.0 ;Motor aansturing ingeschakeld bij hoog niveau
SYMBOL MotorLinksOm = PORTA.6 ;Motor draait linksom
SYMBOL MotorRechtsOm= PORTA.7 ;Motor draait rechtsom
SYMBOL S1           = PORTB.0 ;Puls-toets 1 (motor naar links)
SYMBOL S2           = PORTB.1 ;Puls-toets 2 (motor naar rechts)

;Variabelen declareren
;BYTE
DIM Snelheid        AS BYTE   ;Deze variabele bevat de snelheid van de motor
;BIT
DIM Richting        AS BIT    ;Deze variabele bepaalt de richting van de motor

;        76543210 
PORTA = %00000000             ;Alle PORTA uitgangen laag
TRISA = %00111110             ;PORTA.7, A.6 en A.0 zijn uitgangen voor L293D
TRISB = %11111111             ;PORTB zijn allen ingangen

PORTB_PULLUPS ON              ;On-chip pull-up weerstanden actief (voor de schakelaars) 
CLEAR                         ;Wis alle RAM geheugen


;Hoofdprogramma
MotorEnable = HOOG            ;Maak EN1/2 van L293D hoog, OUT1 en OUT2 worden dan actief

WHILE 1 = 1                   ;Oneindige lus
  IF S1 = LAAG THEN                         ;Als op S1 wordt gedrukt, dan...
    IF Snelheid = 0 THEN Richting = LinksOm ;Als motor stilstaat, omschakelen naar linksom
    IF Richting = LinksOm THEN              ;Als motor linksom draait, dan...
      IF Snelheid < 255 THEN INC Snelheid   ;Als snelheid niet maximaal is, deze verhogen
    ELSE                                    ;...anders... (als motor dus rechtsom loopt)
      IF Snelheid > 0   THEN DEC Snelheid   ;Als snelheid nog niet 0 is, dan deze verlagen
    ENDIF
  ENDIF

  IF S2 = LAAG THEN                         ;Als op S2 wordt gedrukt, dan...
    IF Snelheid = 0 THEN Richting = RechtsOm;Als motor stilstaat, omschakelen naar rechtsom
    IF Richting = RechtsOm THEN             ;Als motor rechtsom draait, dan...
      IF Snelheid < 255 THEN INC Snelheid   ;Als snelheid niet maximaal is, deze verhogen
    ELSE                                    ;...anders... (als motor dus linksom loopt)
      IF Snelheid > 0   THEN DEC Snelheid   ;Als snelheid nog niet 0 is, dan deze verlagen
    ENDIF
  ENDIF

  IF Richting = LinksOm THEN        ;Als motor linksom moet lopen, dan...
    PWM MotorLinksOm,  Snelheid, 10 ;Stuur 10 pulsjes met grootte van 'Snelheid' naar motor
  ELSE                              ;...anders... (rechtsom lopen)
    PWM MotorRechtsOm, Snelheid, 10 ;Stuur 10 pulsjes met grootte van 'Snelheid' naar motor 
  ENDIF
  
WEND

Er worden hier twee variabelen gebruikt.
De variabele 'Snelheid' is een BYTE variabele die de snelheid (0 ... 255) bevat.
Variabele 'Richting' is een BIT variabele en kan dus maar twee waarden aannemen (0 of 1).
Als je de variabele 'Richting' nul maakt (Richting = 0) dan loopt de motor linksom en als je 'Richting' één maakt, dan rechtsom.
Door met SYMBOL de naam 'LinksOm' de waarde 0 te geven en 'RechtsOm' de waarde 1 kun je simpel schrijven: Richting = LinksOm of Richting = RechtsOm om de motor links- of rechtsom te laten draaien.

Dan wordt pin 1 (EN1/2) van de L293D hoog gemaakt (met MotorEnable = HOOG) zodat OUT1 en OUT2 van dat IC actief worden.

In de WHILE - WEND lus wordt steeds snel even naar S1 en S2 gekeken en dan weer 10 pulsjes in PWM uitgevoerd.

Stel dat S1 wordt ingedrukt (PORTB.0 wordt laag) dan wordt eerst gekeken of de motor stilstaat en zo ja ('Snelheid' = 0), dan de juiste richting ingesteld, voor S1 is dat linksom, dus: Richting = LinksOm.
Dan wordt gekeken in welke richting de motor loopt.
Is 'Richting' linksom, dan wordt 'Snelheid' verhoogt, anders verlaagt.
Hiermee wordt bereikt dat als de motor rechtsom loopt, 'Snelheid' eerst wordt verlaagt tot stilstand.
Als 'Snelheid' op een gegeven moment nul is dan wordt de richting omgedraaid en wordt de snelheid weer opgevoerd.

Voor S2 geldt precies hetzelfde alleen dan alles zo'n beetje andersom.

Dan wordt PWM uitgevoerd.
Als 'Richting' linksom is dan wordt de PWM uitgevoerd die pulsjes naar PORTA.6 (met de naam 'MotorLinks') stuurt en anders wordt de andere PWM instructie uitgevoerd, die de pulsjes stuurt naar PORTA.7, oftewel 'MotorRechts'.

Met WEND wordt teruggegaan naar WHILE 1 = 1 en begint alles weer opnieuw.


De instructie PWM heeft echter een probleem met het aansturen van motoren.
Je merkt dat de motor stoterig loopt.
Het PIC programma is continu bezig om pulsjes op te wekken, waardoor je in dezelfde tijd nauwelijks iets anders kunt gaan doen.
Staan er veel instructies in de lus waar ook de PWM instructie staat, dan wordt dit stoten van de motor nog erger.
Als je bijvoorbeeld elke seconde een LED wilt laten knipperen terwijl de motor loopt, dan is dat niet simpel op te lossen met een DELAYMS 1000 want dan komt de motor stil te staan.
Daarom hebben de meeste PIC types een CCP(PWM) module aan boord.
Niet het programma, maar een circuitje in de PIC wekken dan de PWM pulsjes op.
Je stelt van dat inwendige circuitje (= de CCP module) eenmalig de dutycycle in en de CCP in de PIC wekt op de achtergrond de pulsjes op, waardoor het PIC programma zelf verder kan gaan met andere dingen besturen.
Het instellen van de CCP module gebeurt met de instructie HPWM (= Hardwarematige PWM).

Met de PWM instructie is wel uitstekend een simpele DAC te maken, klik hiervoor op de knop.

 

Toch is de instructie PWM niet nutteloos omdat niet alle PIC-types een CCP module aan boord hebben, maar de instructie PWM wel op alle PIC-types te gebruiken is.
Het automatisch handdoekrek project bijvoorbeeld gebeurt met een 8-pins PIC12F629, en die heeft geen CCP module aan boord waardoor je wel moet werken met PWM.
En zolang het programma alleen maar een motor hoeft aan te sturen is de PWM instructie prima.
Een ander voordeel van PWM is dat je de PWM pulsen op elke uitgangspoort kunt zetten, iets dat bij HPWM meestal niet kan.
Zoals de PIC16F628A, die maar 1 vaste poort heeft waar de HPWM pulsjes naar buiten worden gebracht (PORTB.3).

 


HPWM

Hardwarematige Pulse Width Modulation

 

De syntaxis
 HPWM Kanaal, Dutycycle, Frequentie 

De CCP (= Capture/Compare/PWM) module kun je instellen om hardwarematig PWM pulsjes op te wekken.
Over Capture en Compare later meer, ons interesseert nu alleen het PWM gedeelte van de module.
Je stelt het Kanaal, de Dutycycle en de Frequentie in en de module in de PIC wekt op de achtergrond de pulsjes op, waardoor het PIC programma zelf verder kan gaan met andere instructies uitvoeren.
Het instellen van het PWM gedeelte van de CCP module gebeurt met de instructie HPWM (= Hardwarematige PWM).

Kanaal - Is een constante waarde die aangeeft welk hardware PWM kanaal (CCP1, CCP2, CCP3) wordt gebruikt.
Sommige PIC types hebben 1, 2 of 3 PWM kanalen.
Lees de datasheet van het gebruikte PIC type, omdat de meeste PIC types de module naar buiten hebben gebracht op een vaste poortpin.

Bij een PIC16F877 bijvoorbeeld zit CCP1 (= Kanaal 1) op PORTC.2 en CCP2 (= Kanaal 2) op PORTC.1.
Bij de in deze cursus gebruikte PIC16F628A zit maar 1 CCP module (CCP1 (= Kanaal 1)) en die zit op PORTB.3.

Dutycycle - Is een 8-bit (0 ... 255) waarde die de verhouding van het hoog/laag niveau van de puls aangeeft.
Dit wordt de puls-pauze verhouding genoemd en hoeft geen vast getal (constante) te zijn, maar mag ook een variabele of een berekening zijn (zie zodadelijk voorbeelden).
Frequentie - Is een 15-bit (0 ... 32767) waarde waarmee je de benodigde PWM frequentie opgeeft.
Dit hoeft geen vast getal (constante) te zijn, maar mag ook een variabele of een berekening zijn.
De hoogste frequentie is dus 32767Hz.
Maar niet alle lage frequenties zijn beschikbaar bij elke oscillator (kristal) frequentie, zie tabel:

kristal laagst mogelijke PWM frequentie
4MHz
8MHz
10MHz
12MHz
16MHz
20MHz
24MHz
33MHz
40MHz
245Hz
489Hz
611Hz
733Hz
977Hz
1221Hz
1465Hz
2015Hz
2442Hz

Op PIC types die 2 PWM kanalen hebben moet de frequentie van beide kanalen hetzelfde zijn (dit is een beperking van de PIC zelf, niet van PIC Basic).
De 16F628A heeft maar 1 CCP kanaal die uitkomt op PORTB.3.

 

In tegenstelling tot de PWM instructie, kan bij HPWM de frequentie worden ingesteld (bij PWM ligt dit vast, afhankelijk van de oscillator).
Voor RB35 motoren is 1000Hz tot 2000Hz een mooie waarde.
Als je de frequentie lager maakt, loopt de motor rauw en maakt meer lawaai dan bij 2000Hz (2kHz).
En bij hele hoge frequenties kan de motor het niet bijbenen en levert dan kracht in.
Alle voorbeelden (op de eerste paar na) zijn op 2000Hz ingesteld.
Maar het staat je vrij om deze een andere waarde te geven (experimenteren!), vooral ook omdat een ander type motor weer betere prestaties levert bij andere frequenties.


Voorbeelden
Sluit de L293D aan volgens onderstaand schema.
Let op dat IN2 van de L293D nu aan PORTB.3 zit, de vaste PWM uitgang van de PIC16F628A.

8

8 Sluit IN1, IN2 en EN1/2 van de L293D aan volgens schema.
De motor weer met 1 pool aan GND en een LED op PORTA.2.

 
Onderstaand voorbeeld laat een motor constant lopen op halve snelheid (= 50% dutycycle) door Dutycycle een waarde van 127 te geven, bij een frequentie van 1kHz (= 1000Hz).

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

HPWM 1, 127, 1000             ;CCP1, Dutycycle 127 (= 50%), 1000Hz 

;        76543210
TRISB = %11110111             ;PORTB.3 uitgang voor CCP module (PWM) 

DELAYMS 4000                  ;Na 4 seconden...

END                           ;...programma beeindigen

De uitgang van de CCP module is binnenin een PIC16F628A vast verbonden met PORTB.3.
De HPWM uitgang kun je hierdoor helaas niet naar een andere pin brengen, je zit bij de PIC16F628A dus altijd vast aan PORTB.3 (= pin 9) (Zie de datasheet van de PIC16F628A).

Eerst wordt de CCP module met behulp van de HPWM instructie ingesteld.
Voor Kanaal wordt een 1 ingevuld, de PIC16F628A heeft maar 1 CCP module (CCP1) dus we hebben ook geen andere keus.
Voor Dutycycle is in het voorbeeld 127 ingevuld, waardoor de motor op halve snelheid zal gaan lopen (255 = 100% dus 127 = 50%).
Voor Frequentie is hier 1000 ingevuld, waardoor er 1000 pulsjes per seconde (= 1000Hz) naar PORTB.3 worden gezonden.

Dan wordt PORTB.3 als uitgang ingesteld met TRISB.
Nu begint de motor op halve snelheid te lopen.

Het programma zelf wacht nu 4 seconden.

Na die 4 seconden stopt het programma door END en nu gebeurt er iets vreemds.
De motor stopt of draait ineens op maximale snelheid!
Dat komt omdat END de PIC in low-power mode zet waardoor onder andere de CCP module wordt uitgeschakeld.
Alle uitgangen blijven nu op het huidige niveau (hoog of laag) die ze hadden op het moment dat END werd "uitgevoerd".


Het volgende voorbeeld is hetzelfde, alleen is END nu vervangen door STOP.

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

HPWM 1, 127, 1000             ;CCP1, Dutcycle 127 (= 50%), 1000Hz 

;        76543210
TRISB = %11110111             ;PORTB.3 uitgang voor CCP module (PWM) 

DELAYMS 4000                  ;Na 4 seconden programma stoppen

STOP                          ;Geen END maar STOP!

Let dus op dat nu niet END maar STOP onderaan het programma wordt gezet!
Als je STOP opgeeft stopt de PIC met verdere uitvoering van het programma omdat hij in een oneindige lus wordt gebracht, maar de PIC blijft verder wel in actieve mode.
Als je END opgeeft zal de PIC, nadat HPWM uitgevoerd is en de 4 seconden voorbij zijn, in low-power mode (= laag stroomgebruik) worden gezet waardoor onder andere de CCP module wordt uitgeschakeld.

Nadat de 4 seconden voorbij zijn stopt het programma, maar de PIC blijft met STOP wel actief en de motor zal gewoon door lopen.

Als je helemaal geen STOP plaatst zal het voorbeeld waarschijnlijk net zo goed werken.
Maar in grotere programma's kan de PIC bij weglaten van STOP of END onvoorspelbare dingen gaan doen.
Bij dit voorbeeld zal waarschijnlijk de CCP module niet meer (bij toeval) aangesproken worden waardoor de motor gewoon blijft draaien zoals ingesteld.
END of STOP kan alleen worden weggelaten als je zeker weet dat de PIC nooit uit een oneindige lus kan springen.
Als je er niet zeker van bent kun je altijd voor alle zekerheid helemaal onderaan elk programma END schrijven.
In het volgende voorbeeld is END weggelaten omdat zeker is dat het programma altijd in de WHILE 1 = 1 lus zal blijven.


Je ziet in het vorige voorbeeld dat de HPWM instructie in tegenstelling tot de PWM instructie niet in een lus staat, waardoor je, terwijl de motor de ingestelde snelheid draait, gewoon verder kunt gaan met je programma, zoals het volgende voorbeeld, dat een LED laat knipperen, terwijl de motor zonder haperingen op de ingestelde snelheid (25%) blijft draaien:

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

SYMBOL LED = PORTA.2          ;Groene LED op deze poort aansluiten

HPWM 1, 63, 2000              ;CCP1, Dutcycle 63 (= 25%), 2000Hz

;        76543210
TRISA = %11111011             ;PORTA.2 uitgang voor LED
TRISB = %11110111             ;PORTB.3 uitgang voor motorbesturing (L293D IC)

WHILE 1 = 1                   ;Oneindige lus
  DELAYMS 500                 ;Knippersnelheid van de LED
  LED = LED ^ 1               ;Als LED aan was dan uitzetten anders aanzetten 
WEND                          ;Terug naar WHILE

Eerst wordt HPWM weer ingesteld (zie vorige voorbeelden) waardoor de motor langzaam op 25% begint te draaien.
Daarna gaat het programma verder om op de bekende manier een LED te laten knipperen, terwijl de motor langzaam blijft draaien.
Je hoeft je dus niet meer druk te maken om de motor aan te sturen, dat doet de CCP module in de PIC.


Onderstaand programma laat een motor automatisch van 0 naar maximaal draaien en dan weer terug naar 0.
Dit herhaalt zich continu (door WHILE 1 = 1):

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Algemene constanten
SYMBOL Daling       = 20      ;mSec: Daalsnelheid van de motor
SYMBOL Stijging     = 40      ;mSec: Stijgsnelheid van de motor

;Variabele declareren
DIM Duty            AS BYTE   ;'Duty' is de variabele die de snelheid v.d. motor bepaalt 

HPWM 1, 0, 2000               ;Reset de CCP/PWM module (Op 0% = constant laag)

;        76543210
TRISB = %11110111             ;PORTB.3 is uitgang voor PWM signaal naar L293D

CLEAR                         ;Wis alle RAM geheugen


;Hoofdprogramma
WHILE 1 = 1                   ;Oneindige lus
  FOR Duty = 1 TO 255         ;Motor gaat steeds sneller draaien tot maximum (= 255)
    HPWM 1, Duty, 2000        ;De snelheid is afhankelijk van de FOR...NEXT telvariabele
    DELAYMS Stijging          ;Stijgsnelheid van motorsnelheid
  NEXT

  FOR Duty = 254 TO 0 STEP -1 ;Motor gaat steeds langzamer draaien tot 0
    HPWM 1, Duty, 2000        ;Motorsnelheid is afhankelijk van 'Duty', de telvariabele
    DELAYMS Daling            ;Daalsnelheid van motorsnelheid
  NEXT
WEND                          ;Terug naar WHILE

END

In de eerste FOR ... NEXT lus gaat de motor steeds sneller draaien omdat de Duty in de HPWM instructie steeds groter wordt, aangezien 'Duty' de telvariabele van de FOR ... NEXT lus is.
De tweede FOR ... NEXT lus die dan uitgevoerd wordt telt terug (STEP -1), waardoor de motor weer langzamer gaat draaien tot aan 0.
Dat is eigenlijk alles.

De stijg- en daalsnelheid zijn in het programma apart in te stellen.
In het voorbeeld is de daalsnelheid (20) twee maal zo snel dan de stijgsnelheid (40).
Experimenteer door deze waarden te wijzigen.

Als de motor bij lagere snelheden een lichte fluittoon maakt, dan hoor je de 2000Hz pulsjes.
Eventueel kun je de 2000 verhogen (max. 32767).
Denk er wel aan dat de L293D maximaal 5000Hz (= 5kHz) mag schakelen, zie fragment datasheet hieronder.


Fragment van de L293 datasheet.
 

Download datasheet L293D


Sluit nu een potmeter van 25k met in serie een condensator van 100n aan op PORTA.1.

8

8 Sluit een potmeter van 25k aan, vergeet de 100n condensator niet.

 
Met behulp van de instructie POT is nu met de potmeter rechtstreeks de snelheid van de motor te regelen.
Hier is voor Schaal van de instructie POT een waarde van 140 gegeven, dit is een schatting, in principe moet dit even bepaalt worden (Meer info hierover).

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Variabele declareren
DIM Duty AS BYTE              ;'Duty' is de variabele die de snelheid v.d. motor bevat

HPWM 1, 0, 2000               ;Reset de CCP/PWM module (Op 0% = constant laag)

;        76543210
TRISB = %11110111             ;PORTB.3 is uitgang voor PWM signaal naar L293D

CLEAR                         ;Wis alle RAM geheugen


;Hoofdprogramma
WHILE 1 = 1                   ;Oneindige lus (constant de potmeter inlezen)
  Duty = POT PORTA.1, 140     ;Lees de potmeter (PORTA.1) in en geef de waarde aan 'Duty' 
  HPWM 1, Duty, 2000          ;Geef de potmeterwaarde via 'Duty' aan de CCP/PWM module
WEND                          ;Terug naar WHILE

END

De werking van dit programma moet verder toch duidelijk te begrijpen zijn (REM regels lezen).


In het volgende programma is de snelheid ook met de potmeter te regelen maar zal de motor de potmeter niet abrupt, maar vloeiend volgen:

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Algemene constanten
SYMBOL VolgTijd     = 10      ;mSec: Snelheid dat de motor de potmeter volgt

;Poortnamen
SYMBOL Potmeter     = PORTA.1 ;Hierop zit de potmeter aangesloten
;YMBOL HPWM         = PORTB.3  We zitten vast aan deze PORT voor HPWM bij de 16F628A

;Variabelen declareren
DIM Duty            AS BYTE   ;'Duty' is de variabele die de snelheid v.d. motor bevat
DIM Weerstand       AS BYTE   ;'Weerstand' bevat de actuele potmeter waarde

HPWM 1, 0, 2000               ;Reset de CCP/PWM module (Op 0% = constant laag)

;        76543210
TRISB = %11110111             ;PORTB.3 is uitgang voor PWM signaal naar L293D

CLEAR                         ;Wis alle RAM geheugen


;Hoofdprogramma
WHILE 1 = 1                   ;Oneindige lus (constant de potmeter inlezen)
  Weerstand = POT Potmeter, 140 ;Lees de potmeter in en geef de waarde aan 'Weerstand'

  SELECT Weerstand            ;We gaan de potmeterstand vergelijken met de motorsnelheid
    CASE > Duty : INC Duty    ;Als 'Weerstand' groter is dan 'Duty', dan 'Duty' verhogen
    CASE < Duty : DEC Duty    ;Als 'Weerstand' kleiner is dan 'Duty', dan 'Duty' verlagen 
  END SELECT

  DELAYMS VolgTijd            ;Volgsnelheid dat de motor de potmeter volgt

  HPWM 1, Duty, 2000          ;Geef de potmeterwaarde via 'Duty' aan de CCP/PWM module
WEND                          ;Terug naar WHILE

END

Om dit voor elkaar te krijgen moet er een tweede variabele bij komen.
De ene variabele bevat de potmeterstand (in 'Weerstand'), oftewel de snelheidswaarde die de motor moet krijgen.
De ander bevat de actuele motorsnelheid (in 'Duty').

Met SELECT ... CASE bekijken we nu of er verschil zit tussen die twee variabelen en zo ja, dan dat verschil net zo lang verkleinen tot het onderlinge verschil is verdwenen.

Door de waarde van de constante 'VolgTijd' (bovenin het programma) te vergroten, zal de motor nóg langzamer de potmeter volgen.


In het volgende voorbeeldprogramma is de snelheid met de twee toetsen te regelen.
De toets op PORTB.0 laat de motor sneller draaien, de toets op PORTB.1 is voor langzamer.
Met de potmeter is de maximum haalbare snelheid in te stellen:

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Logische constanten
SYMBOL LAAG         = 0       ;Laag signaal

;Algemene constanten
SYMBOL StijgTijd    = 10      ;mSec: snelheid dat motor van toerental wijzigt

;Poortnamen
SYMBOL Potmeter     = PORTA.1 ;Hierop zit de potmeter aangesloten
SYMBOL ToetsHoger   = PORTB.0 ;Deze pulstoets laat de motor sneller draaien
SYMBOL ToetsLager   = PORTB.1 ;Deze pulstoets laat de motor langzamer draaien
;YMBOL HPWM         = PORTB.3  We zitten vast aan deze PORT voor HPWM bij de 16F628A

;Variabelen declareren
DIM Duty            AS BYTE   ;'Duty' is de variabele die de snelheid v.d. motor bevat
DIM Weerstand       AS BYTE   ;'Weerstand' bevat de actuele potmeter waarde

HPWM 1, 0, 2000               ;Reset de CCP/PWM module (Op 0% = constant laag)

;        76543210
TRISB = %11110111             ;PORTB.3 is uitgang voor PWM signaal naar L293D

PORTB_PULLUPS ON              ;On-chip pull-up weerstanden actief (voor de schakelaars)
CLEAR                         ;Wis alle RAM geheugen


;Hoofdprogramma
WHILE 1 = 1                   ;Oneindige lus (constant de potmeter inlezen)
  Weerstand = POT Potmeter, 140 ;Lees de potmeter in en geef de waarde aan 'Weerstand'

  ;Als ToetsHoger wordt ingedrukt EN Snelheid is nog niet maximaal, dan toerental verhogen
  IF ToetsHoger = LAAG AND Duty < Weerstand THEN INC Duty

  ;Als ToetsLager wordt ingedrukt EN Snelheid is nog niet minimaal, dan toerental verlagen 
  IF ToetsLager = LAAG AND Duty > 0 THEN DEC Duty

  ;Als potmeter lager wordt gedraaid dan het huidige toerental, het toerental ook verlagen
  IF Weerstand < Duty THEN Duty = Weerstand

  DELAYMS StijgTijd           ;Stijgsnelheid dat de motor van toerental wijzigt

  HPWM 1, Duty, 2000          ;Stel van de CCP module de PWM in
WEND                          ;Terug naar WHILE

END

In het hoofdprogramma wordt steeds eerst de potmeter ingelezen en daarna naar de toetsen gekeken.

Als op 'ToetsHoger' wordt gedrukt, wordt 'Duty' met 1 verhoogt, maar alleen als 'Duty' nog niet de maximale waarde heeft bereikt die met de potmeter is ingesteld, te vinden in de variabele 'Weerstand'.

Als op 'ToetsLager' wordt gedrukt, wordt 'Duty' met 1 verlaagt, maar doet dat alleen als deze de waarde 0 nog niet heeft bereikt, anders zou je 0 met 1 verminderen en weer op 255 uitkomen, waardoor de motor ineens op maximale snelheid gaat draaien.

Is de motor echter met 'ToetsHoger' op maximaal toerental gezet en wordt dan de potmeter lager gesteld, dan zorgt het programma ervoor dat het toerental (de waarde van 'Duty' dus) ook naar beneden gaat, ook al wordt 'ToetsLager' niet bedient.
Het volgen van de potmeter gaat dan direct (abrupt).
Moet dit ook op de softe manier gebeuren, dan moet de derde IF regel worden gewijzigd in IF Weerstand < Duty THEN DEC Duty


In dit voorbeeld is de snelheid opnieuw met de twee toetsen te regelen.
De toets op PORTB.0 laat de motor weer sneller draaien, de toets op PORTB.1 langzamer.
Met de potmeter is dit keer de stijgsnelheid in te stellen.
Hoe kleiner de potmeterinstelling, hoe sneller de wijziging van het toerental bij het indrukken van de toetsen zal zijn:

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Logische constanten
SYMBOL LAAG         = 0       ;Laag signaal

;Poortnamen
SYMBOL Potmeter     = PORTA.1 ;Hierop zit de potmeter aangesloten
SYMBOL ToetsHoger   = PORTB.0 ;Deze pulstoets laat de motor sneller draaien
SYMBOL ToetsLager   = PORTB.1 ;Deze pulstoets laat de motor langzamer draaien
;YMBOL HPWM         = PORTB.3  We zitten vast aan deze PORT voor HPWM bij de 16F628A

;Variabelen declareren
DIM Duty            AS BYTE   ;'Duty' is de variabele die de snelheid v.d. motor bevat
DIM Weerstand       AS BYTE   ;'Weerstand' bevat de actuele potmeter waarde

HPWM 1, 0, 2000               ;Reset de CCP/PWM module (Op 0% = constant laag)

;        76543210
TRISB = %11110111             ;PORTB.3 is uitgang voor PWM signaal naar L293D

PORTB_PULLUPS ON              ;On-chip pull-up weerstanden actief (voor de schakelaars)
CLEAR                         ;Wis alle RAM geheugen


;Hoofdprogramma
Duty = 200                    ;Opstart snelheid bij opstarten PIC

WHILE 1 = 1                   ;Oneindige lus (constant de potmeter inlezen)
  Weerstand = POT Potmeter, 140 ;Lees de potmeter in en geef de waarde aan 'Weerstand'

  ;Als ToetsHoger wordt ingedrukt EN Snelheid is nog niet maximaal, dan toerental verhogen
  IF ToetsHoger = LAAG AND Duty < 255 THEN INC Duty

  ;Als ToetsLager wordt ingedrukt EN Snelheid is nog niet minimaal, dan toerental verlagen 
  IF ToetsLager = LAAG AND Duty > 0   THEN DEC Duty

  DELAYMS Weerstand           ;Stijgsnelheid dat de motor van toerental wijzigt

  HPWM 1, Duty, 2000          ;Stel van de CCP module de PWM in
WEND                          ;Terug naar WHILE

END

Voordat het programma in de WHILE ... WEND routine verzeild raakt, wordt eerst de snelheid van de motor op 200 gezet, zodat de motor bij het opstarten van de PIC meteen al een snelheid heeft.

De potmeterinstelling staat in 'Weerstand' en wordt verderop achter DELAYMS geplaatst zodat de stijgsnelheid van de potmeter afhankelijk wordt.


Motor in beide richtingen met HPWM
Zoals nu bekend is heeft een PIC16F628A maar 1 CCP module, die ook nog eens op een vaste poort zit (PORTB.3).
Maar veel PIC types hebben helemaal geen CCP module, dus mogen we toch niet klagen.
Een nadeel is wel dat je de motor zo niet in 2 richtingen kunt laten lopen zoals te zien is bij de PWM instructie.
Om de motor toch twee richtingen op te laten lopen samen met HPWM moet er bij de 16F628A een circuitje bij worden gebouwd.
Er zijn vele manieren en iedere elektronicus weet er wel één.
Het onderstaand schema is een eenvoudig voorbeeld:

8

8 Het beste is om in een origineel ontwerp Schottky diodes zoals BAT85 te nemen.
Maar als je deze nu niet hebt kun je zolang ook normale diodes 1N4148 nemen.
Vergeet niet om beide aansluitingen van de motor met de L293D te verbinden.

 
Uit PORTB.3 komen nog steeds de PWM pulsjes, want dat ligt nu eenmaal vast in de PIC zelf, deze bepaalt de snelheid van de motor.
De enable ingang van de L293D zit aangesloten op PORTA.0, deze bepaalt of de motor is geactiveerd of ontkoppeld.
En met de poorten PORTA.6 en PORTA.7 is de draairichting in te stellen.

Vier poorten om een motor aan te sturen?
Jazeker, en het kan wel met minder poorten (2 stuks), maar dan moet je om de draairichting in te stellen een ander circuitje er bij bouwen.
PORTB.3 blijft dan voor het PWM signaal, en een tweede poort bepaalt dan de draairichting.
De L293D laat je dan constant actief zijn door EN1/2 met +5V te verbinden (zie eerste schema's).


Het volgende programma laat de motor automatisch beurtelings linksom en rechtsom draaien:

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Logische constanten
SYMBOL HOOG         = 1       ;Hoog signaal
SYMBOL LAAG         = 0       ;Laag signaal

;Algemene constanten
SYMBOL WachtTijd    = 2000    ;mSec: Wachttijd tussen linksom, rechtsom en stoppen

;Poortnamen
SYMBOL MotorEnable  = PORTA.0 ;Motor aansturing ingeschakeld als poort hoog is
SYMBOL MotorLinksOm = PORTA.6 ;Motor draait linksom
SYMBOL MotorRechtsOm= PORTA.7 ;Motor draait rechtsom
;YMBOL HPWM         = PORTB.3  We zitten vast aan deze PORT voor HPWM bij de 16F628A 

HPWM 1, 127, 2000             ;CCP1, Dutcycle 127 (= 50%), 2000Hz

PORTA = 0                     ;Maak alle poorten van PORTA laag
;        76543210
TRISA = %00111110             ;PORTA.7, A.6 en A.0 uitgangen voor L293D 
TRISB = %11110111             ;PORTB.3 voor motor (L293D IC)


;Hoofdprogramma
WHILE 1 = 1                   ;Oneindige lus
  MotorLinksOm  = HOOG        ;Motor linksom inschakelen
  MotorEnable   = HOOG        ;Motor inschakelen
  DELAYMS WachtTijd           ;Effen wachten

  MotorEnable   = LAAG        ;Eerst de motor ontkoppelen en dan pas...
  MotorLinksOm  = LAAG        ;...motor linksom uitschakelen
  DELAYMS WachtTijd           ;Effen wachten

  MotorRechtsOm = HOOG        ;Motor rechtsom inschakelen
  MotorEnable   = HOOG        ;Motor inschakelen
  DELAYMS WachtTijd           ;Effen wachten

  MotorEnable   = LAAG        ;Eerst de motor ontkoppelen en dan pas...
  MotorRechtsOm = LAAG        ;...motor rechtsom uitschakelen
  DELAYMS WachtTijd           ;Effen wachten
WEND                          ;Terug naar WHILE

END                           ;Einde programma

Eerst worden alle PORTA poorten tegelijk laag gemaakt door PORTA = 0.
Decimaal 0 is immers hetzelfde als binair 00000000, dus PORTA = 0 is hetzelfde als PORTA = %00000000.
Zo is PORTA = 17 hetzelfde als PORTA = %00010001 (16 + 1), enz.

Daarna wordt de motorsnelheid vastgezet op 50% door de CCP module een waarde van 127 te geven.

Het linksom, rechtsom en uitschakelen van de motor doen we door met de 3 signalen van de L293D te spelen.
De motor zal bij het uitschakelen vrij uit lopen, dus zonder "rem".


Het volgende programma is bijna hetzelfde als het vorige.
Als je de toets op PORTB.0 ingedrukt houdt zal de motor stoppen met "rem" en anders zonder "rem":

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Logische constanten
SYMBOL HOOG         = 1       ;Hoog signaal
SYMBOL LAAG         = 0       ;Laag signaal

;Algemene constanten
SYMBOL WachtTijd    = 2000    ;mSec: Wachttijd tussen linksom, rechtsom en stoppen

;Poortnamen
SYMBOL MotorEnable  = PORTA.0 ;Motor aansturing ingeschakeld als poort hoog is
SYMBOL MotorLinksOm = PORTA.6 ;Motor draait linksom
SYMBOL MotorRechtsOm= PORTA.7 ;Motor draait rechtsom
SYMBOL RemToets     = PORTB.0 ;Bij ingedrukt houden van deze toets stopt de motor met rem 
;YMBOL HPWM         = PORTB.3  We zitten vast aan deze PORT voor HPWM bij de 16F628A

HPWM 1, 255, 2000             ;CCP1, Dutycycle 255 (= 100%), 2000Hz

;        76543210
PORTA = %00000000             ;Maak alle poorten van PORTA laag
TRISA = %00111110             ;PORTA.7, A.6 en A.0 uitgangen voor L293D 
TRISB = %11110111             ;PORTB.3 uitgang voor PWM, snelheid van de motor (L293D IC)

PORTB_PULLUPS ON              ;On-chip pull-up weerstanden actief (voor de remschakelaar)


;Hoofdprogramma
WHILE 1 = 1                   ;Oneindige lus
  MotorLinksOm  = HOOG        ;Motor linksom inschakelen
  MotorEnable   = HOOG        ;Motor inschakelen
  DELAYMS WachtTijd           ;Effen wachten

  MotorEnable   = ~RemToets   ;Motor ontkoppelt alleen als remtoets NIET is ingedrukt
  MotorLinksOm  = LAAG        ;Motor linksom uitschakelen
  DELAYMS WachtTijd           ;Effen wachten

  MotorRechtsOm = HOOG        ;Motor rechtsom inschakelen
  MotorEnable   = HOOG        ;Motor inschakelen
  DELAYMS WachtTijd           ;Effen wachten

  MotorEnable   = ~RemToets   ;Motor ontkoppelt alleen als remtoets NIET is ingedrukt
  MotorRechtsOm = LAAG        ;Motor rechtsom uitschakelen
  DELAYMS WachtTijd           ;Effen wachten
WEND                          ;Terug naar WHILE

END                           ;Einde programma

Om het verschil met of zonder rem goed te kunnen laten zien is de motor hier op maximale snelheid gezet, HPWM is 255.
We hadden hier dus net zo goed gewoon de poort hoog kunnen maken (PORTB.3 = HOOG).

De motor stopt hier als 'LinksOm' en 'RechtsOm' beide laag zijn.
Als 'LinksOm' en 'RechtsOm' van gelijk niveau zijn (allebei hoog of allebei laag) dan stopt de motor, ook al gaan de PWM pulsjes gewoon door.

De poort 'MotorEnable' bepaalt of de motor wordt ontkoppelt of niet.
Als de motor is ontkoppelt kan die vrij lopen ('MotorEnable' = LAAG) en anders zal de motor remmen.
Door de ingangspoort 'RemToets' rechtstreeks te koppelen aan 'MotorEnable' wordt steeds als het programma bij 'MotorEnable' komt, bekeken of de remtoets is ingedrukt.
Echter, als je schrijft MotorEnable = RemToets, dus 'RemToets' zonder " ~ " dan werkt het net verkeerd om.
De motor remt dan als de toets niet is ingedrukt, terwijl hij juist moet remmen als de toets wel is ingedrukt.
Daarom moet ~ ervoor worden gezet.

~

   De bitsgewijs NOT (= bitwise complement) functie, wordt aangeduid met een  ~  (= tilde)

Het tilde " ~ " teken keert het signaal om (= inverteren).
Inverteren betekent dat als het signaal hoog is, deze laag wordt gemaakt en als het signaal laag is, dan wordt deze juist hoog gemaakt.
Als een bit 0 is wordt deze dus 1 gemaakt en andersom.

Dit werkt ook met meerdere bits tegelijk:
Dus ~%00011110 is hetzelfde als %11100001.
En natuurlijk werkt dit ook in decimale en hexadecimale notatie.
Dus ~31 is hetzelfde als 224 (als BYTE) en ~$F1 is hetzelfde als $0E (als BYTE).

Het inverteren met de NOT functie is afhankelijk van hoe je de variabele gedeclareerd hebt.
Als bijvoorbeeld de waarde 50 zich in een BYTE variabele bevindt en geïnverteerd wordt, dan is de uitkomst (255 - 50) = 205.
Is die variabele met de waarde 50 echter als WORD gedeclareerd, dan is de uitkomst (65535 - 50) = 65485.
En dit geldt ook voor de andere type variabelen BIT en DWORD, het werkt alleen niet met FLOAT.
~31 is hetzelfde als 224, als het een BYTE betreft, maar
~31 is hetzelfde als 65504, als het een WORD betreft, en
~31 is hetzelfde als 2147483616, als het een DWORD betreft.
Let ook op (sowieso bij DWORD) dat als je werkt met negatieve getallen en alle bits inverteert, dat ook het signed bit (MSB) wordt geïnverteerd (een positief getal wordt negatief en een negatief getal wordt positief).

Nog een voordeel van de bitwise NOT functie:
In de voorgaande cursusdelen wordt van de bitwise XOR functie gebruik gemaakt om een LED te togglen (te laten knipperen):

LED = LED ^ 1  ;Als LED is aan dan LED uitzetten anders aanzetten

Dit kan dus ook met de NOT functie.
Ga maar na, er staat "LED moet zijn wat LED niet is".
Dus stel dat de LED uit is (= 0), dan staat er "LED moet niet (= NOT) uit zijn", dus de LED zal aan (= 1) gaan:

LED = ~LED     ;Als LED is aan dan LED uitzetten anders aanzetten

Het voordeel van de bitwise NOT functie is dat het minder geheugen van de PIC in neemt dan voorgaande bitwise XOR functie.
Echter ten tijde van schrijven van cursus deel 1 was de bitwise NOT functie nog niet beschikbaar in PIC Basic.
Vanaf nu gaan we dus togglen met de NOT functie.


Het volgende programma is het motorbestuur gedeelte uit het beweegbare poster project (vereenvoudigd weergegeven).

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Logische constanten
SYMBOL HOOG         = 1       ;Hoog signaal
SYMBOL LAAG         = 0       ;Laag signaal

;Algemene constanten
SYMBOL Daling       = 20      ;mSec: Daalsnelheid van de motor
SYMBOL ExtraTijd    = 2500    ;mSec: Extra tijd zodat poster verder naar rechts gaat 
SYMBOL Frequentie   = 2000    ;Hz  : Frequentie van PWM pulsjes voor de motor 
SYMBOL Langzaam     = 60      ;BYTE: Langzame snelheid waarmee poster tegen schakelaar loopt
SYMBOL MaxSnelheid  = 220     ;BYTE: Loopsnelheid van de motor
SYMBOL PosterTijd   = 5000    ;mSec: Tijd dat motor op maximum loopt voordat hij afremt 
SYMBOL Stijging     = 20      ;mSec: Stijgsnelheid van de motor

;Poortnamen
SYMBOL MotorEnable  = PORTA.0 ;Motor aansturing ingeschakeld bij hoog niveau
SYMBOL LED          = PORTA.2 ;LED brandt als motorsturing L293D actief (enabled) is
SYMBOL MotorLinksOm = PORTA.6 ;Motor draait linksom
SYMBOL MotorRechtsOm= PORTA.7 ;Motor draait rechtsom
SYMBOL Toets        = PORTB.0 ;Verplaats poster bij druk op deze toets
;YMBOL HPWM         = PORTB.3  We zitten vast aan deze PORT voor HPWM bij de 16F628A

;Variabele declareren
DIM Duty            AS BYTE   ;'Duty' is de variabele die de snelheid v.d. motor bepaalt

HPWM 1, 0, 2000               ;Reset de CCP/PWM module (Op 0% = constant laag)

;        76543210
PORTA = %00000000             ;Alle uitgangen PORTA laag maken
TRISA = %00111010             ;PORTA.7, A.6, A.2 en A.0 uitgangen voor L293D en LED
TRISB = %11110111             ;PORTB.3 is uitgang voor PWM signaal naar L293D

PORTB_PULLUPS ON              ;On-chip pull-up weerstanden actief (voor de schakelaar)
CLEAR                         ;Wis alle RAM geheugen


;HoofdProgramma
WHILE 1 = 1                   ;Oneindige lus
  HPWM 1, 0, Frequentie       ;PWM van CCP module op 0 zetten

  WHILE Toets = HOOG : WEND   ;Wacht op commando van gebruiker om poster te verplaatsen

  MotorLinksOm  = ~MotorLinksOm ;Als motor linksom draaide, dan nu rechtsom (en andersom)
  MotorRechtsOm = ~MotorLinksOm ;LinksOm ingeschakeld dan RechtsOm uitschakelen en andersom 
  MotorEnable   = HOOG          ;Motorsturing activeren
  LED           = MotorEnable   ;LED brandt als motorsturing L293D actief is

  ;Motor optrekken
  FOR Duty = 1 TO MaxSnelheid ;Motor gaat steeds sneller draaien tot waarde 'MaxSnelheid'
    HPWM 1, Duty, Frequentie  ;Motor draait met snelheid 'Duty' op ingestelde frequentie
    DELAYMS Stijging          ;Stijgsnelheid van motorsnelheid
  NEXT

  ;Tijd dat motor op 'MaxSnelheid' blijft lopen (voordat hij weer afremt)
  DELAYMS PosterTijd + (MotorRechtsOm * ExtraTijd)    ;Bij motor rechtsom 'ExtraTijd' langer

  ;Motor afremmen, bij LinksOm tot 'Langzaam', bij rechtsom tot stilstand
  FOR Duty = Duty TO (MotorLinksOm * Langzaam) STEP -1;Motor gaat steeds langzamer draaien
    HPWM 1, Duty, Frequentie  ;Motor draait met snelheid 'Duty' op ingestelde frequentie
    DELAYMS Daling            ;Daalsnelheid van motorsnelheid
  NEXT

  ;Tijd dat motor met snelheid 'Langzaam' tegen schakelaar kan lopen
  DELAYMS 4000 * MotorLinksOm ;Alleen hier wachten als MotorLinksOm hoog (= 1) is.

  ;Motor uitschakelen
  MotorEnable   = LAAG        ;Motorsturing deactiveren (motor kan vrijlopen)
  LED           = MotorEnable ;LED brandt als motorsturing L293D actief is (nu uitzetten dus)
WEND                          ;Terug naar WHILE

Voor onderstaand verhaal kun je het beste eerst even het poster project bekijken, om beter te weten waar het om gaat en wat het voor moet stellen.

De motor wordt hier gestart met 'Toets', in de praktijk is het een afstandsbediening signaal.

Als op de "Poster" toets 'Toets' wordt gedrukt dan begint de motor te lopen.
De eerste opdracht is MotorLinksOm = ~MotorLinksOm.
Dit is een variant op MotorLinksOm = MotorLinksOm ^ 1, waarmee in de vorige cursusdelen een signaal wordt omgekeerd (als hij laag is, moet hij hoog worden en andersom).
Wordt de poster nu verplaatst, dan is dat steeds de tegenovergestelde richting van de vorige keer.

En de opdracht MotorRechtsOm = ~MotorLinksOm zorgt ervoor dat de poort 'MotorRechtsOm' altijd het tegenovergestelde van de poort 'MotorLinksOm' is, dus altijd maar één van beide poorten hoog is.
'MotorRechtsOm' zal zo altijd de geïnverteerde waarde van 'MotorLinksOm' zijn.
Dan wordt de L293D geactiveerd en de LED aangezet.

Vóór het hoofdprogramma staat PORTA = %00000000, dit maakt alle PORTA uitgangen laag.
Dit is nodig omdat bij het opstarten van de PIC de uitgangen in een willekeurige toestand kunnen staan.
Om er zeker van te zijn dat de motor bij PIC opstart na stroomuitval eerst linksom gaat draaien, moet PORTA altijd in dezelfde toestand zijn bij opstart.

De eerste keer na PIC opstart gaat de poster dus naar links.
De motor zal langzaam optrekken, dan 5 seconden ('PosterTijd') constant op duty snelheid 220 ('MaxSnelheid') lopen en dan afremmen tot duty snelheid 60 ('Langzaam').
Deze langzame snelheid blijft de motor maximaal 4 seconden lopen (DELAYMS 4000 * MotorLinksOm)

Alleen als de motor linksom draait wordt deze 4 seconden tijd uitgevoerd.
Hoe dat kan zonder IF ... THEN ?
Eenvoudig, met een berekening.
Als de motor linksom loopt is poort 'MotorLinksOm' hoog (= 1) en anders laag (= 0).
Door achter DELAYMS de berekening 4000 × MotorLinksOm te zetten kun je de volgende situaties krijgen:

Linksom:
Rechtsom:
 DELAYMS 4000 × 1 (= 4000)
 DELAYMS 4000 × 0 (= 0),
dus 4 seconden wachten.
dus 0 seconden wachten.

In die 4 seconden zal de poster tegen de eindschakelaar lopen en de motor stoppen.
De schakelaar zit in de voedingsdraad van de motor.
Zodoende hoef ik geen draad te trekken van de schakelaar naar de PIC en het spaart me een ingangspoort uit.
Over de schakelaar is een diode geplaatst want anders zou de motor ook geen stroom krijgen als de poster weer de andere kant op moet.

Als de motor linksom draait en afremt zal hij afremmen tot snelheid 60 ('Langzaam').
Draait de motor rechtsom dan remt hij verder af tot stilstand.
Dit regelt de tweede FOR ... NEXT ... STEP -1 lus.
Hier staat namelijk ook weer een berekening in: (MotorLinksOm * Langzaam)

Linksom:
Rechtsom:
 FOR Duty = Duty TO (1 × 60)  (= 60)
 FOR Duty = Duty TO (0 × 60)  (= 0)
dus terugtellen tot langzaam.
dus terugtellen tot stilstand.

Dus bij linksom staat er eigenlijk:
En bij rechtsom staat er eigenlijk:


 FOR Duty = Duty TO 60 STEP -1.
 FOR Duty = Duty TOSTEP -1.

Om er zeker van te zijn dat, als de poster naar links loopt, de poster op langzame snelheid tegen de schakelaar loopt, loopt de poster 2,5 seconden langer op 'MaxSnelheid' naar rechts, zodat de poster iets verder naar rechts staat.
Ook hier is weer gebruik gemaakt van een berekening achter een DELAYMS.

DELAYMS PosterTijd + (MotorRechtsOm × ExtraTijd)

'PosterTijd' heeft de waarde 5000 (= 5 sec.), 'ExtraTijd' is 2500 (= 2,5 sec.) en de poort 'MotorRechtsOm' is 0 of 1 (= laag of hoog).
Nu krijg je de volgende situatie:

Linksom:
Rechtsom:
 DELAYMS 5000 + (0 × 2500) (= 5000 + 
 DELAYMS 5000 + (1 × 2500) (= 5000 +
0 = 5000),
2500 = 7500)
,
 dus 5 seconden wachten.
 dus 7,5 seconden wachten.

In dit voorbeeld is de PWM frequentie niet rechtstreeks achter HPWM gezet maar via de constante 'Frequentie'.
Als je nu de frequentie van alle HPWM instructies wilt wijzigen dan hoef je alleen maar deze constante aan te passen.
Dit neemt zoals bekend geen extra geheugen van de PIC in.
Geen enkele constante neemt extra geheugen in, omdat de PIC Basic compiler bij het compileren eerst alle namen van de constanten verandert in de bijbehorende waarden, vóórdat het in de PIC wordt geprogrammeerd.

In de volledige versie van Positron PIC Basic moet je het liefst zoveel mogelijk gebruik maken van constanten, het is makkelijker bij wijzigen en overzicht en kost dus geen extra geheugenruimte van de PIC.
Bij de PIC Basic LITE (demo) versie ontkom je er soms niet aan om waarden rechtstreeks achter bijvoorbeeld DELAYMS te zetten omdat we vastzitten aan die 50 regels limiet.


In het volgende HPWM voorbeeld is een toepassing te zien van array's.
Array's zijn behandeld in mini-cursus deel 6.

Met het volgende voorbeeld is de motor in 5 verschillende versnellingen te "schakelen".
Inclusief stilstand wordt hiervoor gebruik gemaakt van een array variabele bestaande uit 6 elementen.

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Logische constanten
SYMBOL HOOG         = 1       ;Hoog signaal
SYMBOL LAAG         = 0       ;Laag signaal

;Algemene constanten
SYMBOL AntiDender   = 5       ;mSec: Tijd tegen contactdender van de schakelaars

;Poortnamen
SYMBOL MotorEnable  = PORTA.0 ;Motor aansturing ingeschakeld bij hoog niveau
SYMBOL MotorLinksOm = PORTA.6 ;Motor draait linksom
SYMBOL MotorRechtsOm= PORTA.7 ;Motor draait rechtsom
SYMBOL ToetsHoger   = PORTB.0 ;Deze toets schakelt de motor in een hogere versnelling
SYMBOL ToetsLager   = PORTB.1 ;Deze toets schakelt de motor in een lagere versnelling
;YMBOL HPWM         = PORTB.3  We zitten vast aan deze PORT voor HPWM bij de 16F628A

;Variabelen declareren
;BYTE-ARRAY
DIM Snelheid[6]     AS BYTE   ;Deze 6 variabelen bevatten de diverse snelheden incl.stop
;BYTE
DIM Versnelling     AS BYTE   ;Hierin zit de waarde in welke versnelling de motor staat

HPWM 1, 0, 2000               ;CCP/PWM module dutycycle op 0% zetten

;        76543210
TRISA = %00111110             ;PORTA.7, A.6, en A.0 uitgangen voor signalen naar L293D
TRISB = %11110111             ;PORTB.3 uitgang voor PWM signaal naar L293D

PORTB_PULLUPS ON              ;On-chip pull-up weerstanden actief (voor de schakelaars)
CLEAR                         ;Wis alle RAM geheugen


;Hoofdprogramma
;Geef aan de 6 array variabelen de snelheidswaarden
Snelheid[0] = 0               ;Stilstand (De "0e" versnelling)
Snelheid[1] = 60              ;De 1e versnelling
Snelheid[2] = 100             ;De 2e versnelling
Snelheid[3] = 140             ;De 3e versnelling
Snelheid[4] = 180             ;De 4e versnelling
Snelheid[5] = 255             ;De 5e versnelling (maximum snelheid)

MotorLinksom  = HOOG          ;In dit voorbeeld draait de motor alleen linksom
MotorRechtsOm = LAAG          ;In dit voorbeeld draait de motor nooit rechtsom
MotorEnable   = HOOG          ;L293D activeren (enable 1/2)

WHILE 1 = 1                   ;Oneindige lus
  HPWM 1, Snelheid[Versnelling], 2000

  WHILE PORTB & 3 < 3 : WEND  ;Wacht zolang een (of meer) toetsen zijn ingedrukt
  DELAYMS AntiDender          ;Tijd voor contactontdendering van pulstoetsen
  WHILE PORTB & 3 = 3 : WEND  ;Wacht zolang er geen toets is ingedrukt
  DELAYMS AntiDender          ;Tijd voor contactontdendering van pulstoetsen

  IF ToetsHoger = LAAG AND Versnelling < 5 THEN INC Versnelling
  IF ToetsLager = LAAG AND Versnelling > 0 THEN DEC Versnelling
WEND                          ;Terug naar WHILE

END

Bovenaan de lijst met declaraties wordt eerst een BYTE array van 6 elementen gedeclareerd met DIM Snelheid[6] AS BYTE.

Dan wordt eerst met HPWM 1, 0, 2000 de dutycycle op 0% gezet, omdat bij het opstarten van de PIC de CCP module op een willekeurige instelling kan staan en dan zou de motor, als je het met 'MotorEnable' inschakelt, meteen op een willekeurige snelheid gaan draaien.
Door de CCP eerst op 0 te zetten en pas daarna de L293D te enablen (= inschakelen, activeren) blijft de motor stil staan.
In het hoofdprogramma geven we eerst de snelheidswaarden aan de 6 array's (Snelheid[0] = 0 voor stilstand).

Voordat we de oneindige WHILE ... WEND lus in gaan worden er eerst 6 verschillende versnellingswaarden in de array opgegeven.
En daarna wordt eerst nog de L293D op linksom gezet en geactiveerd.

De oneindige lus begint met HPWM 1, Snelheid[Versnelling], 2000.
Er zijn 6 versnellingswaarden opgegeven (0, 60, 100, 140, 180 en 255) die staan in de arrayvariabele Snelheid[0] t/m Snelheid[5].
Welke van deze uitgevoerd wordt is hier afhankelijk van de variabele 'Versnelling', die in dit programma een waarde kan hebben van 0 ... 5.
Aangezien we de variabele 'Versnelling' tussen de blokhaken van de array variabele 'Snelheid' hebben gezet, bepaalt de variabele 'Versnelling', welke snelheid de motor nu gaat lopen.
De variabele 'Versnelling' noemen we in zo'n geval de index variabele van de array.

Stel dat 'Versnelling' de waarde 4 heeft, dan is Snelheid[Versnelling] dus hetzelfde als Snelheid[4].
En Snelheid[4] heeft de waarde 180.
Kortom, als je 'Versnelling' de waarde 4 geeft, dan loopt de motor op snelheid 180.

Met PORTB & 3 lezen we alleen PORTB.0 en PORTB.1 in, PORTB.2 t/m PORTB.7 zijn er hierdoor uitgefilterd.
PORTB & 3
is hetzelfde als PORTB & %00000011, want %00000011 (binair) is immers hetzelfde als 3 (decimaal).
Als je bijvoorbeeld PORTB.7 en PORTB.2 wilt filteren dan schrijf je PORTB & %10000100 of PORTB & 132.
(Meer info zie cursus deel 6)

Als er op 'ToetsHoger' (= PORTB.0) wordt gedrukt, dan wordt de poort laag en als de variabele 'Versnelling' nog niet in de hoogste versnelling staat, dan wordt de variabele 'Versnelling' met 1 verhoogt.
Stel dat 'Versnelling' de waarde 2 heeft dan loopt de motor de snelheid die aan 'Snelheid[2]' is gegeven.
Wordt er nu op 'ToetsHoger' gedrukt dan verhoogt de motor de snelheid van 'Snelheid[2]' (= 100) naar 'Snelheid[3]' (= 140).


Je zult gemerkt hebben dat bij het vorige voorbeeld het op- en neer schakelen van de motor abrupt van de ene naar de andere schakelt.
Het volgende voorbeeld doet het vloeiend.
De motor zal bij het verhogen of verlagen van de versnelling langzaam naar de nieuw ingestelde versnelling met de daarbij behorende snelheid gaan.
Leuk voor een modelspoorbaan, bovendien houden de treinen door PWM bij een lagere snelheid veel meer kracht over dan bij een gewone treintrafo.
Tijdens het vertragen of versnellen van de motor brandt de groene LED, ten teken dat de motorsnelheid aan het veranderen is.

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Logische constanten
SYMBOL HOOG         = 1       ;Hoog signaal
SYMBOL LAAG         = 0       ;Laag signaal

;Algemene constanten
SYMBOL AntiDender   = 5       ;mSec: Tijd tegen contactdender van de schakelaars
SYMBOL StijgSnelheid= 40      ;mSec: Stijgsnelheid van motor naar ingestelde versnelling

;Poortnamen
SYMBOL MotorEnable  = PORTA.0 ;Motor aansturing ingeschakeld bij hoog niveau
SYMBOL LED          = PORTA.2 ;LED brandt als snelheid van motor wijzigt
SYMBOL MotorLinksOm = PORTA.6 ;Motor draait linksom
SYMBOL MotorRechtsOm= PORTA.7 ;Motor draait rechtsom
SYMBOL ToetsHoger   = PORTB.0 ;Deze toets schakelt de motor in een hogere versnelling
SYMBOL ToetsLager   = PORTB.1 ;Deze toets schakelt de motor in een lagere versnelling
;YMBOL HPWM         = PORTB.3  We zitten vast aan deze PORT voor HPWM bij de 16F628A

;Variabelen declareren
;BYTE-ARRAY
DIM Snelheid[6]     AS BYTE   ;Deze 6 variabelen bevatten de diverse snelheden
;BYTE
DIM MotorSnelheid   AS BYTE   ;Hierin zit de waarde van de actuele snelheid van de motor 
DIM Versnelling     AS BYTE   ;Hierin zit de waarde in welke versnelling de motor staat

HPWM 1, 0, 2000               ;CCP/PWM module dutycycle op 0% zetten

;        76543210
TRISA = %00111010             ;PORTA.7, A.6, A.2 en A.0 uitgangen voor L293D en LED
TRISB = %11110111             ;PORTB.3 is uitgang voor PWM signaal naar L293D

PORTB_PULLUPS ON              ;On-chip pull-up weerstanden actief (voor de schakelaars)
CLEAR                         ;Wis alle RAM geheugen


;Hoofdprogramma
;Geef aan de 6 array variabelen de snelheidswaarden
Snelheid[0] = 0               ;Stilstand (De 0e versnelling)
Snelheid[1] = 60              ;De 1e versnelling
Snelheid[2] = 100             ;De 2e versnelling
Snelheid[3] = 140             ;De 3e versnelling
Snelheid[4] = 180             ;De 4e versnelling
Snelheid[5] = 255             ;De 5e versnelling (maximum snelheid)

MotorRechtsOm = LAAG          ;In dit voorbeeld draait de motor nooit rechtsom
MotorLinksom  = ~MotorRechtsOm;In dit voorbeeld draait de motor alleen linksom
MotorEnable   = HOOG          ;L293D activeren (enable 1/2)

WHILE 1 = 1                   ;Oneindige lus
  WHILE PORTB & 3 < 3 : WEND  ;Wacht zolang een (of meer) toetsen zijn ingedrukt
  DELAYMS AntiDender
  WHILE PORTB & 3 = 3 : WEND  ;Wacht zolang er geen toets is ingedrukt
  DELAYMS AntiDender

  IF ToetsHoger = LAAG AND Versnelling < 5 THEN INC Versnelling
  IF ToetsLager = LAAG AND Versnelling > 0 THEN DEC Versnelling

  LED = HOOG                  ;Een hoog signaal laat de LED branden (snelheid wijzigt)
  REPEAT
    IF Snelheid[Versnelling] > MotorSnelheid THEN INC MotorSnelheid
    IF Snelheid[Versnelling] < MotorSnelheid THEN DEC MotorSnelheid

    HPWM 1, MotorSnelheid, 2000
    DELAYMS StijgSnelheid     ;Stijgsnelheid van motor, tevens antidender van toetsen
  UNTIL Snelheid[Versnelling] = MotorSnelheid
  LED = LAAG                  ;LED weer uitzetten (snelheid is klaar met wijziging)
WEND                          ;Terug naar WHILE

END

Dit programma is bijna hetzelfde als het voorgaande voorbeeld.
Om het voor elkaar te krijgen dat de motor vloeiend van de ene naar de andere snelheid gaat, moet er een nieuwe variabele (hier met de naam 'MotorSnelheid') worden aangemaakt.
Als nu 'Versnelling' wordt verhoogt dan is de waarde van de array 'Snelheid' groter dan de variabele 'MotorSnelheid' geworden.
Hierdoor wordt de regel IF Snelheid[Versnelling] > MotorSnelheid THEN INC MotorSnelheid uitgevoerd, waardoor de motor langzaam maar zeker steeds sneller gaat lopen, totdat 'Snelheid' weer gelijk is aan 'MotorSnelheid'.

Stel dat 'Versnelling' de waarde 2 heeft, dan loopt de motor op 100.
Zowel 'Snelheid [Versnelling]' als 'MotorSnelheid' hebben beide de waarde 100.
Wordt 'Versnelling' nu verlaagt naar 1 dan heeft 'Snelheid [Versnelling]' ineens de waarde 60 terwijl 'MotorSnelheid' nog steeds 100 is.
In de REPEAT ... UNTIL lus wordt de regel IF Snelheid[Versnelling] < MotorSnelheid THEN DEC MotorSnelheid uitgevoerd, oftewel als Snelheid van de ingestelde versnelling kleiner is dan MotorSnelheid dan verlaag MotorSnelheid met 1.
Door DEC wordt 'MotorSnelheid' verlaagt met 1, dus 100 - 1 = 99.

De variabele 'MotorSnelheid' staat in de instructie HPWM, waardoor de motor nu van 100 naar 99 gaat lopen.
Nu volgt eerst een vertraging, afhankelijk van de constante 'StijgSnelheid', anders zou er bloedsnel van 100 naar 60 worden geteld, waardoor de motor nog steeds abrupt van de ene naar de andere snelheid zou gaan, daarom deze vertraging.
Bij UNTIL wordt bekeken of 'MotorSnelheid' al gelijk is geworden aan 'Snelheid [Versnelling]', maar 99 is nog geen 60, dus wordt de REPEAT ... UNTIL lus opnieuw uitgevoerd, net zolang tot (= UNTIL) 'MotorSnelheid' weer gelijk is aan de array 'Snelheid [Versnelling]'.

Pfff... moeilijk als je het zo ziet?
Kan ik me voorstellen.
Daarom, als je iets voor je zelf maakt, bouw het langzaam op, test steeds ieder stukje en breidt het dan verder uit.
Iets in één keer programmeren is vragen om problemen.


Het volgende voorbeeld is een deel uit mijn Basic programma dat ik in de badkamer gebruik.
Van oorsprong heeft het bubbelbad maar twee instellingen: Bubbelen op maximaal of niet bubbelen (gewoon aan/uit dus).
Nú stuur ik de motor van het bubbelbad met het volgende programma, waardoor ik met 1 pulstoets de bubbelkracht kan variëren alsook de motor geheel kan uitschakelen.


Met de toets 'Hydro' kan ik de snelheid van de motor van het bubbelbad regelen.
Als de motor loopt, brandt de LED in de toets.
Tijdens wijzigen van de snelheid knippert deze LED.

 

De bediening is eenvoudig.
Door de toets kort in te drukken of ingedrukt te houden wordt de enable van de L293D hoog en begint ook de motor steeds sneller te lopen tot aan een maximum.
Is er kort gedrukt, dan gebeurt dit automatisch.
Wordt de toets echter vast gehouden dan gaat de motor ook sneller lopen maar als de toets nú wordt losgelaten zal de motor blijven draaien met de snelheid die het op dat moment heeft.
Als er nu opnieuw op de toets gedrukt wordt (kort of continu) dan geldt hetzelfde verhaal als net alleen zal de motor nu steeds langzamer gaan lopen.

Is de motor bezig met het automatisch wijzigen van de snelheid (omdat er kort op de toets is gedrukt) dan is de wijziging te stoppen door opnieuw op de toets te drukken.
De motor blijft dan lopen met de snelheid die het heeft op het moment van drukken op de toets.

Bij het verlagen van de snelheid op handbediening (door de toets vast te houden) zal de motor tot aan een minimum snelheid gaan lopen en op die snelheid blijven lopen.
Gebeurt het verlagen automatisch (door een korte druk) dan zal de motor eerst naar de minimum snelheid lopen en dan ineens stoppen en wordt tevens de enable van de L293D weer laag gemaakt (motor gaat hierdoor van de "rem").
Een minimum snelheid instelling is nodig omdat de motor van het bubbelbad niet lager dan 15% dutycycle mag draaien, omdat er anders de kans is dat de motor brommend blijft staan en mogelijk oververhit kan raken.
Door de minimum snelheid zal de motor altijd starten vanaf- en stoppen met de opgegeven minimum snelheid.

Probeer het voorbeeldprogramma maar eens uit, het werkt zeer praktisch:

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Logische constanten
SYMBOL HOOG         = 1       ;Hoog signaal (of aanduiding snelheid verhogen)
SYMBOL LAAG         = 0       ;Laag signaal (of aanduiding snelheid verlagen)

;Algemene constanten
SYMBOL Maximum      = 240     ;BYTE: Maximumsnelheid van de motor
SYMBOL Minimum      = 40      ;BYTE: Minimumsnelheid van de motor

;Poortnamen
SYMBOL MotorEnable  = PORTA.0 ;Motor aansturing ingeschakeld bij hoog niveau
SYMBOL LED          = PORTA.2 ;Geeft aan of motor loopt en knippert bij wijzigen
SYMBOL S1           = PORTB.0 ;Hiermee is de motorsnelheid te wijzigen
;YMBOL HPWM poort   = PORTB.3  Op deze poort zit de CCP module van de PIC16F628A

;Variabelen declareren
;BYTE
DIM Snelheid        AS BYTE   ;Bevat de actuele snelheid van de motor
;BIT
DIM HogerLager      AS BIT    ;Bepaalt hoger of lager gaan van de motorsnelheid

HPWM 1, 0, 2000               ;CCP/PWM module: Motor stop

;        76543210
PORTA = %10000000             ;Alle PORTA uitgangen laag op PORTA.7 na (=motor rechtsom)
TRISA = %00111010             ;PORTA.7, A.6, A.2 en A.0 uitgangen voor L293D en LED
TRISB = %11110111             ;PORTB.3 is uitgang voor PWM signaal naar L293D

PORTB_PULLUPS ON              ;On-chip pull-up weerstanden actief voor de schakelaar
CLEAR                         ;Wis alle RAM geheugen

GOTO HoofdProgramma           ;Spring over de subroutine


;Subroutine
WijzigSnelheid:               
  IF HogerLager = LAAG OR Snelheid < Maximum THEN
    Snelheid = Snelheid + (2 * HogerLager) + -1 ;Uitleg zie tekst PIC cursus deel 7
    HPWM 1, Snelheid, 2000    ;Motor op PORTB.3 aansluiten CCP1, snelheid, 2000Hz
    LED = Snelheid / 10       ;LED knippert bij wijzigen van de motorsnelheid
    DELAYMS 20                ;Stijg/daal snelheid van motorsnelheid bij wijzigen
  ENDIF
RETURN


HoofdProgramma:
WHILE 1 = 1                   ;Oneindige lus
Begin:
  LED = MotorEnable           ;LED geeft aan of motor loopt

  WHILE S1 = LAAG : WEND      ;Wacht hier zolang toets is ingedrukt
  DELAYMS 5                   ;Tijd tegen contactdender van pulstoets S1 bij loslaten
  WHILE S1 = HOOG : WEND      ;Wacht hier totdat een toets wordt ingedrukt
  DELAYMS 5                   ;Tijd tegen contactdender van pulstoets S1 bij indrukken

  MotorEnable = HOOG          ;L293D activeren
  HogerLager  = ~HogerLager   ;Richting verhogen/verlagen van snelheid omkeren
  DELAYMS 250                 ;Tijd die het verschil maakt tussen kort en lang indrukken

  IF S1 = HOOG THEN           ;Als toets S1 nu alweer is losgelaten, dan AUTOMATISCH
    WHILE HogerLager = HOOG OR Snelheid > Minimum ;Zolang snelheid stijgt of snelheid
      GOSUB WijzigSnelheid    ;Wijzig PWM waarde (= motorsnelheid) in CCP module
      IF S1 = LAAG OR Snelheid = Maximum THEN GOTO Begin ;Auto. is te onderbreken door S1
    WEND
    MotorEnable = LAAG        ;L293D deactiveren, motor compleet uit na automatisch dalen
  ELSE                        ;...anders... (toets S1 nog steeds ingedrukt) = HANDBEDIEND 
    WHILE S1 = LAAG           ;Zolang toets S1 is ingedrukt snelheid veranderen
      GOSUB WijzigSnelheid    ;Wijzig PWM waarde (= motorsnelheid) in CCP module
      IF HogerLager = LAAG AND Snelheid <= Minimum THEN BREAK ;Minimumsnelheid bereikt
    WEND
  ENDIF
WEND

In dit voorbeeld zijn achter diverse DELAYMS instructies de tijdswaarden rechtstreeks ingevuld in plaats van met SYMBOL een naam te geven en is met PORTA = %10000000 de motor op rechtsom draaiend gezet en de overige PORTA poorten laag gemaakt.
Dit is overmacht, omdat de PIC Basic LITE versie een limiet van 50 programmaregels heeft.
Bij het originele programma (volledige PIC Basic versie thuis) heeft alles keurig een naam.

Om te kunnen meten of de toets lang of kort is ingedrukt is hier het volgende gedaan.
Zolang er geen toets is ingedrukt wacht het programma bij WHILE S1 = HOOG : WEND.
Wordt er nu op toets S1 gedrukt dan loopt het programma verder.
Het maakt eerst de enable van de L293D hoog en keert de richting van de snelheidwijziging om, dus ging de motor eerst sneller lopen, dan nu langzamer (of andersom).
En dan komt er de wachttijd die het verschil bepaalt tussen lang of kort indrukken van de toets.
Als namelijk de tijd verstreken is, wordt opnieuw toets S1 gemeten.
Is het signaal alweer weg, dan is er kort op de toets gedrukt, en anders dus lang.
Als er kort op de toets is gedrukt, dan wordt het programmagedeelte van automatisch verhogen (of verlagen) van de snelheid uitgevoerd.

Nog even over de berekening in de subroutine:
De bitvariabele 'HogerLager' is 1 als de motor versneld en 0 als de motor vertraagd.
Normaal doen we dat met een IF ... THEN ... ELSE regel:
IF
HogerLager = 1 THEN INC Snelheid ELSE DEC Snelheid.
Hier is het voor de verandering met een berekening gedaan:

Snelheid = Snelheid + (2 * HogerLager) + -1

Simpel narekenen wat er hier gebeurt laat zien hoe het werkt.
'HogerLager' is dus 1 bij versnellen en 0 bij vertragen:

Versnellen: Snelheid = Snelheid + (2 × 1) + -1, oftewel: Snelheid = Snelheid + 2 + -1
Vertragen: Snelheid = Snelheid + (2 × 0) + -1, oftewel: Snelheid = Snelheid + 0 + -1
Bij versnellen staat er Snelheid = Snelheid
Bij vertragen staat er Snelheid = Snelheid
+ 1   (+1
- 1    (-1
komt van 2 + -1).
komt van 0 + -1).

Hier zie je dat om iets te bereiken vaak meerdere mogelijkheden zijn.
In het voorbeeld moet 'Snelheid' met 1 verhoogt of verlaagt worden, afhankelijk van bitvariabele 'HogerLager' en is dus opgelost met de berekening:

Snelheid = Snelheid + (2 * HogerLager) + -1

Bovenstaande oplossing met de getoonde berekening is echter verre van ideaal, want deze neemt maarliefst 23 program words (geheugen) van de PIC in, terwijl onderstaande oplossing precies hetzelfde doet, en toch maar 5 program words van de PIC inneemt.

IF HogerLager = HOOG THEN 
  INC Snelheid
ELSE
  DEC Snelheid
ENDIF

Kies uit de verschillende mogelijkheden de oplossing die het minste geheugen van de PIC inneemt.
Het neemt niet alleen minder geheugen, maar is ook sneller in afhandeling.


Links onderaan in Positron PIC Basic IDE staat hoeveel program words
een programma (na compileren) inneemt in de PIC.

 


Hoe nu het HD44780 display en PORTB.3?
De instructie PRINT, waarmee tekst op het display wordt geplaatst, stuurt de signalen voor het HD44780 display standaard naar PORTB.2 t/m PORTB.7.
Omdat de CCP module nu eenmaal vast op PORTB.3 zit, moet de RS pin van het display verhuizen naar een andere poortpin.
PORTA.4 is nog vrij, dus pakken we die maar.
Aangezien PORTA.4 een open-drain uitgang is, moet er mogelijk een pull-up weerstand (bijv. 10k) bij geplaatst worden, maar dat is niet altijd nodig, het display heeft meestal een pull-up van zichzelf.
Sluit nu een HD44780 display aan op de in rood aangegeven punten:

8

8 Sluit een HD44780 display aan op de aangegeven punten (meer info zie cursus deel 4).

 
Om de PIC Basic compiler te kennen te geven dat de RS aansluiting van het display niet op de standaard poort is aangesloten, moet opgegeven worden naar welke pin deze is verhuist.
Door ergens bovenin het programma LCD_RSPIN = PORTA.4 te schrijven weet de compiler dat de RS pin nu op PORTA.4 zit (zie volgende voorbeelden).

Meer hierover? Klik op de knop.

 


Met het volgende programma is de motorsnelheid te regelen met de beide toetsen die aangesloten zijn op PORTB.0 en PORTB.1.
Het percentage van de dutycycle is op het display af te lezen.

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Logische constanten
SYMBOL HOOG         = 1       ;Hoog signaal
SYMBOL LAAG         = 0       ;Laag signaal

;Algemene constanten 
SYMBOL StartSnelheid= 128     ;BYTE: Motorsnelheid waarmee het programma start (Dutycycle 50%)
SYMBOL StijgSnelheid= 10      ;mSec: Bepaalt hoe snel de motor optrekt / afremt

;Poortnamen
SYMBOL MotorEnable  = PORTA.0 ;Motor aansturing ingeschakeld bij hoog niveau
LCD_RSPIN           = PORTA.4 ;De RS pin van het display zit nu aan deze poort
SYMBOL MotorRechtsOm= PORTA.7 ;Motor rechtsom
SYMBOL ToetsHoger   = PORTB.0 ;Deze pulstoets laat de motor sneller draaien
SYMBOL ToetsLager   = PORTB.1 ;Deze pulstoets laat de motor langzamer draaien
;YMBOL HPWM         = PORTB.3  We zitten vast aan deze PORT voor HPWM bij de 16F628A

;Variabelen declareren
DIM Snelheid        AS BYTE   ;Deze variabele bevat de snelheid van de motor

;        76543210
PORTA = %00000000             ;Maak alle poorten van PORTA laag
TRISA = %00111110             ;PORTA.7, A.6 en A.0 uitgangen voor L293D
TRISB = %11110111             ;PORTB.3 is uitgang voor PWM signaal naar L293D

PORTB_PULLUPS ON              ;On-chip pull-up weerstanden actief (voor de schakelaars) 
CLEAR                         ;Wis alle RAM geheugen
DELAYMS 500                   ;LCD stabilisering 


;Hoofdprogramma
CLS                           ;Wis display
PRINT "Dutycycle ="           ;Zet tekst op het display

Snelheid      = StartSnelheid ;Geef de variabele 'Snelheid' een startwaarde
MotorRechtsOm = HOOG          ;Motor op rechtsom zetten
MotorEnable   = HOOG          ;L293D activeren (enable 1/2)

WHILE 1 = 1                   ;Oneindige lus
  HPWM 1, Snelheid, 2000      ;Motor op PORTB.3 aansluiten CCP1, snelheid, 2000Hz

  ;Als ToetsHoger wordt ingedrukt EN Snelheid is nog niet maximaal, dan snelheid verhogen
  IF ToetsHoger = LAAG AND Snelheid < 255 THEN INC Snelheid

  ;Als ToetsLager wordt ingedrukt EN Snelheid is nog niet minimaal, dan snelheid verlagen 
  IF ToetsLager = LAAG AND Snelheid > 0   THEN DEC Snelheid
  
  DELAYMS StijgSnelheid       ;Bepaalt hoe snel de motor optrekt / afremt
  PRINT AT 1, 13, DEC (Snelheid * 100) / 255, "% " ;Geef motorsnelheid weer in procenten
WEND                          ;Terug naar WHILE

END 

LCD_RSPIN = PORTA.4 is geplaatst bij Poortnamen.
Normaal zet ik het toewijzen van namen aan constanten en het declareren van variabelen altijd op alfabetische volgorde, alleen bij Poortnamen niet, die zet ik altijd op numerieke volgorde, eerst PORTA op nummer, dan PORTB op nummer, dat geeft een beter overzicht van de gebruikte poorten.

De poort voor linksom (PORTA.6) staat er dit keer niet bij omdat we de motor alleen rechtsom laten draaien.
Met PORTA = %00000000 wordt ervoor gezorgd dat alle 8 poorten van PORTA laag zijn, dus ook PORTA.6.
PORTA.6 moet natuurlijk wel een uitgang zijn, ook al blijft hij in dit programma altijd laag, dus wel opgeven bij TRISA.

Tot slot wordt nog de waarde van 'Snelheid' op het display gezet.
Het display geeft de waarde van 'Snelheid' als percentage aan, dus niet als 0 ... 255, maar als 0% ... 100%.
Dit wordt bereikt door 'Snelheid' eerst met 100 te vermenigvuldigen en daarna te delen door 255.


Met het volgende voorbeeld kun je de motorsnelheid met de aangesloten potmeter regelen en aflezen op het display.
Van de functie POT is Schaal hier op 140 gezet (eventueel aanpassen):

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Logische constanten
SYMBOL HOOG         = 1       ;Hoog signaal
SYMBOL LAAG         = 0       ;Laag signaal

;Poortnamen
SYMBOL MotorEnable  = PORTA.0 ;Motor aansturing ingeschakeld bij hoog niveau
SYMBOL Potmeter     = PORTA.1 ;Hierop zit de potmeter voor de snelheidsregeling
LCD_RSPIN           = PORTA.4 ;De RS pin van het display zit nu aan deze poort
SYMBOL MotorRechtsOm= PORTA.7 ;Motor rechtsom
;YMBOL HPWM poort   = PORTB.3  Op deze poort zit de CCP module van de PIC16F628A

;Variabele declareren
DIM Duty            AS BYTE   ;Deze variabele bevat de actuele snelheid van de motor

HPWM 1, 0, 2000               ;CCP1 module op 0% zetten

;        76543210
PORTA = %00000000             ;Maak alle poorten van PORTA laag
TRISA = %00111110             ;PORTA.7, A.6 en A.0 uitgangen voor L293D
TRISB = %11110111             ;PORTB.3 is uitgang voor PWM signaal naar L293D

CLEAR                         ;Wis alle RAM geheugen
DELAYMS 500                   ;LCD stabilisering 


;Hoofdprogramma
CLS                           ;Wis display en plaats cursor op regel 1, eerste positie
PRINT          "Instel ="     ;Zet tekst op het display
PRINT AT 2, 1, "Perc.  ="     ;Zet tekst vooraan op regel 2 van het display

MotorRechtsOm = HOOG          ;In dit voorbeeld draait de motor alleen rechtsom
MotorEnable   = HOOG          ;L293D activeren (enable 1/2)

WHILE 1 = 1                   ;Oneindige lus
  Duty = POT Potmeter, 140    ;Geef potmeterwaarde aan variabele 'Duty'

  HPWM 1, Duty, 2000          ;Geef de potmeterwaarde via 'Duty' aan de CCP/PWM module 

  PRINT AT 1, 10, DEC Duty, "  " ;Plaats de decimale waarde achter de tekst "Instel ="
  PRINT AT 2, 10, DEC (Duty * 100) / 255, "% " ;Het percentage op regel 2
WEND                          ;Terug naar WHILE

END

In de lus wordt steeds eerst de potmeter met de functie POT ingelezen en de stand hiervan aan de variabele 'Duty' gegeven.

Meteen daarna komt de instructie HPWM waarbij voor de Duty de variabele 'Duty' is neergezet, waardoor de snelheid van de motor dus rechtstreeks afhankelijk is van de potmeterstand.

Tot slot wordt nog de actuele waarde van de potmeter (en dus de motorsnelheid) op het display afgebeeld in zowel decimalen en procenten.
Als het display zenuwachtig tussen twee waarden staat te knipperen dan kun je ergens in de lus een DELAYMS 100 plaatsen, dan wordt er maar om de 0,1 seconde gemeten.
Wanneer het display met de potmeter op maximaal nog niet 100% aangeeft, dan moet de waarde van Schaal van de functie POT verhoogt worden.


Met het programma hieronder kun je de motorsnelheid ook met de instelling van de potmeter regelen, alleen zal de motor dit langzaam volgen.
Hóe langzaam is afhankelijk van de grootte van 'StijgSnelheid'.
Zowel de instelling van de potmeter, als de actuele snelheid van de motor worden op het display geplaatst, beide in procenten:

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Logische constanten
SYMBOL HOOG         = 1       ;Hoog signaal
SYMBOL LAAG         = 0       ;Laag signaal

;Algemene constanten 
SYMBOL StijgSnelheid= 10      ;mSec: Bepaalt hoe snel de motor optrekt / afremt

;Poortnamen
SYMBOL MotorEnable  = PORTA.0 ;Motor aansturing ingeschakeld bij hoog niveau
SYMBOL Potmeter     = PORTA.1 ;Hierop zit de potmeter voor de snelheidsregeling
LCD_RSPIN           = PORTA.4 ;De RS pin van het display zit nu aan deze poort
SYMBOL MotorLinksOm = PORTA.6 ;Motor linksom
;YMBOL HPWM poort   = PORTB.3  Op deze poort zit de CCP module van de PIC16F628A

;Variabelen declareren
DIM Instelling      AS BYTE   ;Deze variabele bevat de instelsnelheid van de motor
DIM Snelheid        AS BYTE   ;Deze variabele bevat de actuele snelheid van de motor

HPWM 1, 0, 2000               ;CCP1 module op 0% zetten

;        76543210
PORTA = %00000000             ;Maak alle poorten van PORTA laag
TRISA = %00111110             ;PORTA.7, A.6 en A.0 uitgangen voor L293D
TRISB = %11110111             ;PORTB.3 is uitgang voor PWM signaal naar L293D

CLEAR                         ;Wis alle RAM geheugen
DELAYMS 500                   ;LCD stabilisering 


;Hoofdprogramma
CLS                           ;Wis display
PRINT          " Instel ="    ;Zet tekst op het display
PRINT AT 2, 1, "Actueel ="

MotorLinksOm  = HOOG          ;In dit voorbeeld draait de motor alleen linksom
MotorEnable   = HOOG          ;L293D activeren (enable 1/2)

WHILE 1 = 1                   ;Oneindige lus
  HPWM 1, Snelheid, 2000      ;Geef de CCP/PWM module de waarde van 'Snelheid'

  Instelling = POT Potmeter, 140 ;De schaalwaarde (140) eventueel aanpassen

  IF Snelheid < Instelling THEN INC Snelheid ;Sneller als snelheid lager is dan instelling 
  IF Snelheid > Instelling THEN DEC Snelheid ;Trager  als snelheid hoger is dan instelling
  
  PRINT AT 1, 11, DEC (Instelling * 100) / 255, "%  "
  PRINT AT 2, 11, DEC (Snelheid   * 100) / 255, "%  "

  DELAYMS StijgSnelheid
WEND                          ;Terug naar WHILE

END

Hier worden twee variabelen gebruikt, één voor de instelling van de potmeter en één van de werkelijke snelheid van de motor.
Als de werkelijke snelheid (de variabele 'Snelheid') afwijkt van de potmeterinstelling, dan zal het programma dit langzaam maar zeker op gelijk niveau brengen.
Dat gaat simpel; als 'Snelheid' lager is dan 'Instelling', dan de snelheid met 1 verhogen (met INC).
Hierna wordt eerst alles in de lus weer uitgevoerd, dus het display geeft de nieuwe waarde aan en de motor zal ietsje sneller gaan draaien.
En dan is het programma opnieuw bij de vergelijking aangekomen en wordt weer gekeken of de snelheid lager is dan de instelling.

De programmaregel die daar meteen onder staat doet precies hetzelfde, alleen dan voor als de snelheid hoger is dan de potmeterinstelling, waardoor de snelheid wordt verlaagt (met DEC).

Het volgen van de motor gaat nu dus langzamer dan in het programma hiervoor, omdat de variabele die de stand van de potmeter bevat, hier niet rechtstreeks aan HPWM wordt aangeboden, maar via de variabele 'Snelheid' stapje voor stapje wordt verhoogt (of verlaagt).

Het display laat zowel het percentage van de instelling, als de actuele snelheid van de motor zien.


Met het volgende programma is de motorsnelheid én richting te regelen met S1 en S2 die aangesloten zijn op PORTB.0 en PORTB.1.
Als de PIC opstart staat de motor stil.
Door toets S1 ingedrukt te houden zal de motor steeds sneller linksom gaan draaien en de snelheid aanhouden die het heeft als de toets wordt losgelaten.
Voor S2 geldt hetzelfde alleen zal de motor steeds sneller rechtsom draaien.

Als de motor linksom draait, kan door S1 in te drukken de snelheid dus verhoogt worden.
Met S2 kan de snelheid nu verlaagt worden totdat de motor stilstaat.
Blijf je S2 echter vasthouden dan gaat de motor weer sneller draaien, alleen nu rechtsom.
Om de snelheid weer te verlagen moet op S1 gedrukt worden.

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Logische constanten
SYMBOL HOOG         = 1       ;Hoog signaal
SYMBOL LAAG         = 0       ;Laag signaal
SYMBOL LinksOm      = 0       ;
SYMBOL RechtsOm     = 1       ;

;Poortnamen
SYMBOL MotorEnable  = PORTA.0 ;Motor aansturing ingeschakeld bij hoog niveau
LCD_RSPIN           = PORTA.4 ;De RS pin van het display zit nu aan deze poort
SYMBOL MotorLinksOm = PORTA.6 ;Motor draait linksom  als deze poort HOOG is
SYMBOL MotorRechtsOm= PORTA.7 ;Motor draait rechtsom als deze poort HOOG is
SYMBOL S1           = PORTB.0 ;Puls-toets 1 (motor naar links)
SYMBOL S2           = PORTB.1 ;Puls-toets 2 (motor naar rechts)
;YMBOL HPWM poort   = PORTB.3  Op deze poort zit de CCP module van de PIC16F628A

;Variabelen declareren
;BYTE
DIM Snelheid        AS BYTE   ;Deze variabele bevat de snelheid van de motor
;BIT
DIM Richting        AS BIT    ;Deze variabele bepaalt de richting van de motor

HPWM 1, 0, 2000               ;CCP1 module op 0% zetten

;        76543210
PORTA = %00000000             ;Maak alle poorten van PORTA laag
TRISA = %00111110             ;PORTA.7, A.6 en A.0 uitgangen voor L293D
TRISB = %11110111             ;PORTB.3 is uitgang voor PWM signaal naar L293D

PORTB_PULLUPS ON              ;On-chip pull-up weerstanden actief (voor de schakelaars) 
CLEAR                         ;Wis alle RAM geheugen
DELAYMS 500                   ;LCD stabilisering 


;Hoofdprogramma
CLS                           ;Wis display
PRINT "Dutycycle ="           ;Zet tekst op het display

MotorEnable = HOOG            ;Maak EN1/2 van L293D hoog, OUT1 en OUT2 worden dan actief

WHILE 1 = 1                   ;Oneindige lus
  IF S1 = LAAG THEN                         ;Als op S1 wordt gedrukt, dan...
    IF Snelheid = 0 THEN Richting = LinksOm ;Als motor stilstaat, omschakelen naar linksom
    IF Richting = LinksOm THEN              ;Als motor linksom draait, dan...
      IF Snelheid < 255 THEN INC Snelheid   ;Als snelheid niet maximaal is, deze verhogen
    ELSE                                    ;...anders... (als motor dus rechtsom loopt)
      IF Snelheid > 0   THEN DEC Snelheid   ;Als snelheid nog niet 0 is, dan deze verlagen
    ENDIF
  ENDIF

  IF S2 = LAAG THEN                         ;Als op S2 wordt gedrukt, dan...
    IF Snelheid = 0 THEN Richting = RechtsOm;Als motor stilstaat, omschakelen naar rechtsom
    IF Richting = RechtsOm THEN             ;Als motor rechtsom draait, dan...
      IF Snelheid < 255 THEN INC Snelheid   ;Als snelheid niet maximaal is, deze verhogen
    ELSE                                    ;...anders... (als motor dus linksom loopt)
      IF Snelheid > 0   THEN DEC Snelheid   ;Als snelheid nog niet 0 is, dan deze verlagen
    ENDIF
  ENDIF

  MotorRechtsOm = Richting                  ;Als Richting = HOOG dan MotorRechtsOm = HOOG
  MotorLinksOm  = ~MotorRechtsOm            ;MotorLinksOm is geinverteerd aan MotorRechtsOm

  HPWM 1, Snelheid, 2000                    ;Stuur waarde van 'Snelheid' naar de CCP module 
  
  PRINT AT 1, 13, DEC (Snelheid * 100) / 255, "%  " ;Geef snelheid in procenten weer

  DELAYMS 10                                ;StijgSnelheid
  IF Snelheid = 0 THEN DELAYMS 700          ;Wacht wat langer als 'Snelheid' 0 is
WEND                                        ;Terug naar WHILE

Het programma kan je bekend voor komen omdat eenzelfde soort programma ook in PWM is behandeld.
Voor nadere uitleg even daar weer kijken dus.
Deze is wel iets uitgebreider, het werkt met de CCP module, heeft een displayaflezing en het wacht heel even als de motor stilstaat.
Door de laatste optie is het punt om de motor volledig stil te zetten makkelijker in te stellen.
Dit is heel simpel te maken, als de snelheid 0 is dan 0,7 seconde (= 700mSec) wachten.


Het volgende voorbeeld van HPWM kan de motor ook twee richtingen op laten draaien, alleen gaat het hier met de potmeter.
Als de potmeter in de middenstand staat, staat de motor stil.
De potmeter naar links draaien laat de motor linksom draaien en de potmeter naar rechts is rechtsom.
Overbodig om nog eens te zeggen dat Schaal van POT hier een richtwaarde is die je zelf nog even moet bepalen.

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Logische constanten
SYMBOL HOOG         = 1       ;Hoog signaal
SYMBOL LAAG         = 0       ;Laag signaal
SYMBOL LinksOm      = 0       ;
SYMBOL RechtsOm     = 1       ;

;Poortnamen
SYMBOL MotorEnable  = PORTA.0 ;Motor aansturing ingeschakeld bij hoog niveau
SYMBOL Potmeter     = PORTA.1 ;Hierop zit de potmeter voor de snelheidsregeling
LCD_RSPIN           = PORTA.4 ;De RS pin van het display zit nu aan deze poort
SYMBOL MotorLinksOm = PORTA.6 ;Motor draait linksom  als deze poort HOOG is
SYMBOL MotorRechtsOm= PORTA.7 ;Motor draait rechtsom als deze poort HOOG is
;YMBOL HPWM poort   = PORTB.3  Op deze poort zit de CCP module van de PIC16F628A

;Variabelen declareren
;BYTE
DIM Snelheid        AS BYTE   ;Deze variabele bevat de snelheid van de motor
DIM Weerstand       AS BYTE   ;Deze variabele bevat de instelling van de potmeter
;BIT
DIM Richting        AS BIT    ;Deze variabele bepaalt de richting van de motor

HPWM 1, 0, 2000               ;CCP1 module op 0% zetten

;        76543210
PORTA = %00000000             ;Maak alle poorten van PORTA laag
TRISA = %00111110             ;PORTA.7, A.6 en A.0 uitgangen voor L293D
TRISB = %11110111             ;PORTB.3 is uitgang voor PWM signaal naar L293D

CLEAR                         ;Wis alle RAM geheugen
DELAYMS 500                   ;LCD stabilisering 


;Hoofdprogramma
CLS                           ;Wis display
PRINT "Dutycycle ="           ;Zet tekst op het display

MotorEnable = HOOG            ;Maak EN1/2 van L293D hoog, OUT1 en OUT2 worden dan actief 

WHILE 1 = 1                   ;Oneindige lus
  Weerstand = POT Potmeter, 140 ;Geef potmeterwaarde aan variabele 'Weerstand'

  IF Weerstand < 128 THEN     ;Als potmeter ONDER de helft staat, dan...
    Richting = LinksOm        ;...omschakelen naar linksom en...
    Snelheid = (128 - Weerstand) * 2 ;...bereken snelheid voor linksom
  ELSE                        ;...anders... (potmeter dus over de helft)
    Richting = RechtsOm       ;...omschakelen naar rechtsom en...
    Snelheid = Weerstand * 2  ;...bereken snelheid voor rechtsom
  ENDIF

  MotorRechtsOm = Richting    ;Als Richting = HOOG dan MotorRechtsOm = HOOG
  MotorLinksOm  = ~MotorRechtsOm ;MotorLinksOm is geinverteerd aan MotorRechtsOm

  HPWM 1, Snelheid, 2000      ;Stuur waarde van 'Snelheid' naar de CCP module
  
  PRINT AT 1, 13, DEC (Snelheid * 100) / 255, "%  " ;Geef snelheid in procenten weer
  IF Richting = LinksOm THEN  ;Plaats tekst op regel 2 afhankelijk van draairichting
    PRINT AT 2, 1, "Motor linksom "
  ELSE
    PRINT AT 2, 1, "Motor rechtsom"
  ENDIF
WEND                          ;Terug naar WHILE

De functie POT levert een waarde van 0 ... 255.
Dan blijven er maar 127 over voor linksom en 127 voor rechtsom.
Daarom wordt bij de berekening van de snelheid de variabele 'Weerstand' met twee vermenigvuldigd, om zo weer bijna aan het maximum te komen (127 × 2 = 254 (= 99% dutycycle)).

Als de 0% niet in het midden van de potmeter zit, dan moet Schaal van de functie POT aangepast worden.
Denk er wel aan dat je een (lineaire) potmeter van 25k gebruikt in serie met een 100n condensator.
Meer over POT en Schaal vindt je in cursus deel 5.


Eenvoudiger schema

Om de motor met HPWM beide richtingen op te kunnen laten draaien zijn in de vorige voorbeelden maarliefst 4 poorten in gebruik.
Onderstaand schema 7i doet met 3 poorten hetzelfde als schema 7f, waarbij bovendien ook nog eens de beide dioden en beide weerstanden zijn vervallen.
Dit heeft wel gevolgen voor de regeling van de motor.

In voorgaande schema's is de (RB35) motor supermooi in snelheid én remkracht te regelen.
Dit is duidelijk te merken bij bijvoorbeeld het sluiten van een klapraam.
Als het klapraam dicht moet, dan drukt het raam zélf de motor aan, waardoor de motor als een soort rem moet fungeren om ervoor te zorgen dat het raam niet met een klap dicht valt.
Of neem als voorbeeld een (model)trein die van een berg af rijdt, waar de motor er nu voor moet zorgen dat de trein niet op hol slaat en de trein dus niet aandrijft, maar juist afremt.

Door de vereenvoudiging van het schema wordt de motor echter niet meer geregeld met "remfunctie", waardoor tijdens het sluiten van het klapraam deze met een klap dicht valt.
De motor is nu nog wel mooi op aandrijfsnelheid te regelen, maar als de motor zélf aangedreven wordt, dan remt deze de snelheid níet meer af.
Het hangt dus maar helemaal van de toepassing af of schema 7i toe te passen is.
In eerder genoemd verplaatsbare poster project is dit schema bijvoorbeeld wél goed te gebruiken, de poster zal de motor immers nooit zelf aandrijven.

8

8 Schema 7i is een eenvoudige variant van schema 7f.
Hierdoor is de motor echter iets minder mooi te regelen (zie tekst).

 

De PWM pulsjes worden hier op de enable ingang van de L293D aangeboden, terwijl met IN1 en IN2 van de L293D de draairichting is in te stellen.
Kreeg de motor in voorgaande schema's PWM pulsjes van hoog en laag niveau, nu krijgt het alleen de hoge pulsjes, en is het lage niveau een zwevend niveau geworden (hoog-ohmig, vandaar dat de remmende werking verdwenen is).
Dat komt omdat PWM nu op de (ongebruikelijke) enable ingang van de L293D wordt aangeboden.
Als PORTA.6 hoog is en PORTA.7 laag dan draait de motor linksom, met een snelheid die afhankelijk is van de instelling van HPWM.
Als PORTA.6 laag is en PORTA.7 hoog, dan draait de motor rechtsom.

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Logische constanten
SYMBOL HOOG         = 1       ;Hoog signaal
SYMBOL LAAG         = 0       ;Laag signaal
SYMBOL LinksOm      = 0       ;
SYMBOL RechtsOm     = 1       ;

;Poortnamen
SYMBOL Potmeter     = PORTA.1 ;Hierop zit de potmeter voor de snelheidsregeling
SYMBOL MotorLinksOm = PORTA.6 ;Motor draait linksom  als deze poort HOOG is
SYMBOL MotorRechtsOm= PORTA.7 ;Motor draait rechtsom als deze poort HOOG is
;YMBOL HPWM poort   = PORTB.3  Op deze poort zit de CCP module van de PIC16F628A

;Variabelen declareren
;BYTE
DIM Snelheid        AS BYTE   ;Deze variabele bevat de snelheid van de motor
DIM Weerstand       AS BYTE   ;Deze variabele bevat de instelling van de potmeter 
;BIT
DIM Richting        AS BIT    ;Deze variabele bepaalt de richting van de motor

HPWM 1, 0, 2000               ;CCP1 module op 0% zetten

;        76543210
PORTA = %00000000             ;Maak alle poorten van PORTA laag
TRISA = %00111111             ;PORTA.7 en A.6 zijn uitgangen voor de L293D
TRISB = %11110111             ;PORTB.3 is uitgang voor PWM signaal naar L293D

CLEAR                         ;Wis alle RAM geheugen
DELAYMS 500                   ;LCD stabilisering 


;Hoofdprogramma
WHILE 1 = 1                   ;Oneindige lus
  Weerstand = POT Potmeter, 140 ;Geef potmeterwaarde aan variabele 'Weerstand'

  IF Weerstand < 128 THEN     ;Als potmeter ONDER de helft staat, dan...
    Richting = LinksOm        ;...omschakelen naar linksom en...
    Snelheid = (128 - Weerstand) * 2 ;...bereken snelheid voor linksom
  ELSE                        ;...anders... (potmeter dus over de helft)
    Richting = RechtsOm       ;...omschakelen naar rechtsom en...
    Snelheid = Weerstand * 2  ;...bereken snelheid voor rechtsom
  ENDIF

  MotorRechtsOm = Richting    ;Als Richting = HOOG dan MotorRechtsOm = HOOG
  MotorLinksOm  = ~MotorRechtsOm ;MotorLinksOm is geinverteerd aan MotorRechtsOm

  HPWM 1, Snelheid, 2000      ;Stuur waarde van 'Snelheid' naar de CCP module
WEND                          ;Terug naar WHILE

Bovenstaande voorbeeld werkt precies als voorgaande voorbeeld (alleen zonder display) en werkt met schema 7i, waarbij PORTA.0 niet meer wordt gebruikt.


Eenvoudige overbelasting / beveiliging RB35 motor

Met het onderstaande schema kan worden gedetecteerd door de PIC of een RB35 motor overbelast wordt.
Omdat de stroommeting door een optocoupler wordt gedaan is de motorspanning onafhankelijk van de voedingsspanning van de PIC besturing zelf.
De optocoupler geeft een laag signaal aan de PIC door, als de motor overbelast wordt.
De weerstandswaarden in het schema zijn gebaseerd op de RB35 motoren van Conrad, voor andere soorten motoren zullen de waarden anders zijn (experimenteren!).
Hoe en wanneer de motor stopt kan op deze manier volledig afhankelijk zijn van het PIC Basic programma.
Zo kun je bijvoorbeeld een overbelasting toestaan voor een aantal seconden voordat je de motor uitschakelt.
Of je laat de motor (even) de andere kant opdraaien na een overbelasting (denk aan een wals of een geblokkeerde lade van een CD/DVD speler).
Op een display zou je een teller kunnen weergeven die telt hoe vaak er een overbelasting is geweest.
Je ziet, het is helemaal afhankelijk in wat voor soort project de RB35 motor wordt gebruikt.

Eén opmerking: vergeet niet om de interne pull-ups aan te zetten (PORTB_PULLUPS ON).
Wil je de schakeling gebruiken zonder inschakeling van de PORTB pull-ups, of wil je de optocoupler op een PORTA ingang aansluiten, dan moet je zelf een pull-up weerstand tussen +5V en pin 5 van de optocoupler plaatsen (richtwaarde 47k).
Onderstaande voorbeelden maken wél gebruik van de interne pull-up van PORTB en is de weerstand dus niet geplaatst in het schema.

De werking is simpel.
Als de RB35 motor zwaar belast wordt, stijgt de spanning over de 2E2 weerstand.
Parallel over die weerstand staat de LED van de optocoupler, en bij een bepaalde spanning zal de transistor van de optocoupler voldoende geleiden om PORTB.1 laag te maken.


De waarden van beide weerstanden zijn gebaseerd op de diverse RB35 motoren van Conrad.
Het is mogelijk dat de truc niet werkt als een ander soort motor (met maar weinig vermogen) gebruikt wordt.
Door de 220E (= 220Ω) weerstand te verkleinen wordt een overbelasting nog eerder gedetecteerd.

 

*Voor de eerste paar voorbeelden moeten Cx en Rx niet worden geplaatst.

In de nu volgende voorbeelden zullen de eigengemaakte sleutelwoorden OFF, AAN, UIT, HOOG, LAAG, TRUE en FALSE vet en in de kleur teal worden weergegeven.
Hoe je dát in moet stellen zodat PIC Basic IDE dat ook automatisch voor jouw doet, moet je even hier klikken.


Eerst testen of de overbelastingsdetector werkt.
Compileer het onderstaande programma en programmeer het in de PIC.

'LED moet branden als motor overbelast wordt

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

SYMBOL LED          = PORTA.2 ;Controle LED
SYMBOL Optocoupler  = PORTB.1 ;Optocoupler geeft laag signaal bij overbelasting van motor

;        76543210
PORTA = %10000101             ;A.7 en A.0 hoog = motor draait rechtsom, A.2 = LED aan
TRISA = %00111010             ;PORTA.7, A.6 en A.0 zijn uitgangen voor L293D, A.2 voor LED 

PORTB_PULLUPS ON              ;Voor de optocoupler


;Hoofdprogramma
DELAYMS 1000                  ;Laat LED ter controle een seconde oplichten

WHILE 1 = 1                   ;Oneindige lus
  LED   = ~Optocoupler        ;LED aanduiding dat motor overbelast wordt
WEND

Wanneer de PIC schakeling spanning krijgt moet de LED één seconde oplichten, daarna doven.
Als dat niet gebeurt dan is de LED niet goed aangesloten (onderzoek eerst waarom!).

Ook begint de RB35 motor onmiddellijk te draaien.
Door met een tang de as van de motor tegen te houden moet de LED oplichten.
Gebeurt dat niet dan kun je proberen de 2E2 (= 2,2Ω) weerstand te verhogen naar bijvoorbeeld 2E7 of 3E3.
Vanaf 3E3 begint de RB35 motor wel merkbaar wat aan kracht te verliezen.

Met de 220E weerstand is ook nog invloed uit te oefenen.
Verlagen naar bijvoorbeeld 100E zal de LED eerder doen oplichten (eerder een overbelasting detecteren dus).


Het eerstvolgende voorbeeld laat de motor continu één richting op draaien.
Als je de as van de motor tegenhoudt (bijvoorbeeld met een tang), dan zal de PIC een overbelasting meten en de motor uitschakelen door het L293D IC te disablen.
De LED gaat branden ter indicatie dat er een overbelasting van de motor is geweest.
Door een druk op de resettoets (een maakcontact op PORTB.0) wordt de overbelasting weer uitgeschakeld, de motor zal weer gaan draaien en de LED doven.

'Motor trekt op (0,5 seconden zonder stroommeting)
'Bij overbelast stopt motor en brandt de LED
'Resetten door de resettoets op B.0

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Logische constanten
SYMBOL HOOG         = 1       ;Hoog signaal
SYMBOL LAAG         = 0       ;Laag signaal
SYMBOL OFF          = 0
SYMBOL ON           = 1

;Algemene constanten
SYMBOL OptrekTijd   = 500     ;mSec: Tijd voor optrekken motor (zonder stroommeting)

;Poortnamen
SYMBOL MotorEnable  = PORTA.0 ;Motor aansturing ingeschakeld bij hoog niveau
SYMBOL LED          = PORTA.2 ;Controle LED
SYMBOL MotorRechtsOm= PORTA.7 ;Motor draait rechtsom
SYMBOL Toets        = PORTB.0 ;Resettoets (maakcontact)
SYMBOL Optocoupler  = PORTB.1 ;Optocoupler geeft laag signaal bij overbelasting van motor

;        76543210
PORTA = %00000000             ;Alle PORTA uitgangen laag
TRISA = %00111010             ;PORTA.7, A.6 en A.0 zijn uitgangen voor L293D, A.2 voor LED

PORTB_PULLUPS ON              ;Voor de optocoupler en de pulsschakelaar


;Hoofdprogramma
MotorRechtsOm = HOOG          ;PORTA.7 hoog maken, motor rechtsomdraaiend instellen

WHILE 1 = 1                   ;Oneindige lus
  ;Motor laten draaien
  LED         = OFF           ;LED aanduiding motor overbelast uit
  MotorEnable = HOOG          ;Maak EN1/2 van L293D hoog, OUT1 en OUT2 worden dan actief
  DELAYMS OptrekTijd          ;Even de motor laten draaien zonder stroommeting (optrekken) 
  
  WHILE Optocoupler = HOOG : WEND ;Blijf hier wachten zolang de motor NIET overbelast is

  ;Motor stoppen (wegens overbelasting)
  MotorEnable = LAAG          ;Schakel motoraansturing uit (Disable L293)
  LED         = ON            ;LED aanduiding motor overbelast aanzetten

  WHILE Toets = HOOG : WEND   ;Blijf hier wachten totdat op de resettoets wordt gedrukt
WEND

Bij het optrekken van de motor wordt er de eerste halve seconde geen stroommeting gedaan, anders zou door de hoge piekstroom van het optrekken de motor alweer meteen uitgeschakeld worden.


Het volgende voorbeeld is een aandrijving van een raamopener.
Hier wordt gebruik gemaakt van het overbelastingssignaal om de motor uit te schakelen, zodat eindschakelaars niet nodig zijn.
De RB35 motor doet er bijna 3 seconden over om een klapraam te openen of te sluiten.
De eerste 2 seconden wordt er geen stroommeting gedaan en kan de motor dus overbelast worden zonder dat de spanning meteen wordt uitgeschakeld.
Na die 2 seconden wordt de stroommeting actief.
Het wachten is nu tot het raam geheel geopend of gesloten is waardoor de motor niet verder kan draaien en de optocoupler een overbelasting doorgeeft aan de PIC.
De PIC schakelt nu de motor onmiddellijk uit, dus precies op het moment dat het raam geheel geopend of gesloten is.

'Raamopener (stroommeting 220E voor LED optocoupler, 2E2 shuntweerstand)
'Motor draait na iedere toets indruk andere richting op (raam openen/sluiten)
'Motor trekt op (2 seconden zonder stroommeting)
'Bij raam bijna open gaat stroommeting werken

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Logische constanten
SYMBOL HOOG         = 1       ;Hoog signaal
SYMBOL LAAG         = 0       ;Laag signaal

;Algemene constanten
SYMBOL OptrekTijd   = 2000    ;mSec: Tijd voor (bijna) openen raam (zonder stroommeting)

;Poortnamen
SYMBOL MotorEnable  = PORTA.0 ;Motor aansturing ingeschakeld bij hoog niveau
SYMBOL MotorLinksOm = PORTA.6 ;Motor draait linksom
SYMBOL MotorRechtsOm= PORTA.7 ;Motor draait rechtsom
SYMBOL Toets        = PORTB.0 ;Toets voor starten motor (maakcontact)
SYMBOL Optocoupler  = PORTB.1 ;Optocoupler geeft laag signaal bij overbelasting van motor

;        76543210
PORTA = %00000000             ;Alle PORTA uitgangen laag
TRISA = %00111110             ;PORTA.7, A.6 en A.0 zijn uitgangen voor L293D

PORTB_PULLUPS ON              ;Voor de optocoupler en de pulsschakelaar


;Hoofdprogramma
MotorRechtsOm = HOOG          ;PORTA.7 hoog maken, motor rechtsomdraaiend instellen

WHILE 1 = 1                   ;Oneindige lus
  WHILE Toets = HOOG : WEND   ;Blijf hier wachten totdat op de starttoets wordt gedrukt

  ;Motor laten draaien
  MotorEnable = HOOG          ;Maak EN1/2 van L293D hoog, OUT1 en OUT2 worden dan actief
  DELAYMS OptrekTijd          ;Even de motor laten draaien zonder stroommeting (optrekken)
  
  WHILE Optocoupler = HOOG : WEND ;Blijf hier wachten zolang de motor NIET overbelast is

  ;Motor stoppen
  MotorEnable   = LAAG        ;Schakel motoraansturing uit (Disable L293)
  
  ;Keer draairichting om voor volgende keer (na raam openen komt raam sluiten en andersom) 
  MotorLinksOm  = MotorRechtsOm
  MotorRechtsOm = ~MotorRechtsOm
WEND

Eventueel kun je de motor nog een tiende seconde laten doordrukken na het meten van een overbelasting, zodat het raam echt goed geopend of gesloten is door een DELAYMS 100 vóór het motor uitschakel gedeelte te plaatsen (niet in bovenstaand programmavoorbeeld en in de praktijk (bij mij thuis) ook niet nodig).

Na elke toetsindruk draait de motor de andere richting op (raam openen/sluiten/openen/sluiten/enz.).


Het volgende voorbeeld is ook voor een raamopener, maar is wat uitgebreider dan het vorige voorbeeld.
Wanneer in het vorige voorbeeld geen signaal van overbelasting binnenkomt, zou de motor continu spanning blijven krijgen en nooit stoppen.
Het voorbeeld hieronder laat de motor na een paar seconden alsnog stoppen, óók als er geen signaal van overbelasting binnenkomt.
Kortom: de motor draait 2 seconden zonder stroommeting en mag dus zwaar arbeid verrichten zonder dat ie wordt uitgeschakeld.
Daarna blijft de motor doordraaien, wachtend op een signaal van overbelasting.
Komt dat signaal echter niet binnen de 2 seconden, dan wordt de motor alsnog stilgezet.
De motor draait dus maximaal 4 seconden per keer.

Aan de LED op PORTA.2 is te zien wanneer de stroommeting geactiveerd is (de LED brandt dan).

De poortnamen 'MotorRechtsOm' en 'MotorLinksOm' zijn hier vervangen door 'RaamOpenen' en 'RaamSluiten', wat de duidelijkheid ten goede komt.

'Raamopener (stroommeting 220E voor LED optocoupler, 2E2 shuntweerstand)
'Motor draait na iedere toets indruk andere richting op (raam openen/sluiten)
'Motor trekt op (2 seconden zonder stroommeting)
'Bij raam bijna open gaat stroommeting werken
'EXTRA: Binnen de tijd geen overbelasting dan stopt de motor alsnog
'       LED gaat branden als indicatie dat stroommeting actief is

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Logische constanten
SYMBOL HOOG         = 1       ;Hoog signaal
SYMBOL LAAG         = 0       ;Laag signaal
SYMBOL OFF          = 0
SYMBOL ON           = 1

;Algemene constanten
SYMBOL OptrekTijd   = 2000    ;mSec: Tijd voor (bijna) openen raam (zonder stroommeting)
SYMBOL Tijd         = 200     ;Byte: Na geen overbelasting gemeten motor toch stoppen

;Poortnamen
SYMBOL MotorEnable  = PORTA.0 ;Motor aansturing ingeschakeld bij hoog niveau
SYMBOL LED          = PORTA.2 ;LED indicatie stroommeting actief
SYMBOL RaamSluiten  = PORTA.6 ;Motor draait linksom (raam sluiten)
SYMBOL RaamOpenen   = PORTA.7 ;Motor draait rechtsom (raam openen)
SYMBOL Toets        = PORTB.0 ;Toets voor starten motor (maakcontact)
SYMBOL Optocoupler  = PORTB.1 ;Optocoupler geeft laag signaal bij overbelasting van motor

;Variabele declareren
DIM BD1             AS BYTE   ;Byte Dummy 1

;        76543210
PORTA = %00000000             ;Alle PORTA uitgangen laag
TRISA = %00111010             ;PORTA.7, A.6 en A.0 zijn uitgangen voor L293D, A.2 voor LED

PORTB_PULLUPS ON              ;Voor de optocoupler en de pulsschakelaar


;Hoofdprogramma
RaamOpenen = HOOG             ;PORTA.7 hoog maken, motor rechtsomdraaiend (= raam openen)

WHILE 1 = 1                   ;Oneindige lus
  WHILE Toets = HOOG : WEND   ;Blijf hier wachten totdat op de starttoets wordt gedrukt

  ;Motor laten draaien
  MotorEnable = HOOG          ;Maak EN1/2 van L293D hoog, OUT1 en OUT2 worden dan actief
  DELAYMS OptrekTijd          ;Even de motor laten draaien zonder stroommeting (optrekken)
  
  LED         = ON            ;Indicatie stroommeting actief
  
  FOR BD1 = 1 TO Tijd         ;Als tijd voorbij zonder overbelast dan motor alsnog stoppen
    IF Optocoupler = LAAG THEN BREAK ;Spring uit FOR..NEXT als overbelasting wordt gemeten
    DELAYMS 10                ;Om de 10mSec meten
  NEXT

  ;Motor stoppen
  MotorEnable = LAAG          ;Schakel motoraansturing uit (Disable L293)
  LED         = OFF           ;LED weer uitzetten
  
  ;Keer draairichting om voor volgende keer (na raam openen komt raam sluiten en andersom) 
  RaamSluiten = RaamOpenen
  RaamOpenen  = ~RaamOpenen
WEND

Bij mij thuis wordt de draairichting van de motor (raam openen of sluiten) niet bijgehouden door variabele 'RaamOpenen', maar door een bit van de interne EEPROM van de PIC.
Het voordeel van de EEPROM manier is dat de PIC ook na een stroomuitval nog steeds weet of het raam open of dicht staat.
Bovenstaand voorbeeld weet dat niet en zal na een stroomuitval altijd eerst het raam openen na een druk op de toets, ook als het raam al open zou staan.
De interne EEPROM wordt behandeld in cursus deel 9.


In het voorbeeld hieronder draait de motor even en zal bij een overbelasting een stukje achteruit gaan draaien.
Denk aan bijvoorbeeld een wals, wanneer die geblokkeerd raakt, zal de motor stoppen en daarna heel even in tegengestelde richting draaien om de blokkade op te heffen.
Of bij het automatische handdoekrek, als daar iemand met de vingers tussen zou komen bij het inschuiven, dan zou de motor bij zo'n blokkade weer een stukje kunnen uitschuiven.

'Motor draait na iedere toets indruk een paar seconden
'Motor trekt op (0,5 seconde zonder stroommeting)
'Bij overbelasting van de motor gaat de motor 1 seconde achteruit draaien en stopt dan
'LED brandt als de stroommeting actief is

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Logische constanten
SYMBOL HOOG         = 1       ;Hoog signaal
SYMBOL LAAG         = 0       ;Laag signaal
SYMBOL OFF          = 0
SYMBOL ON           = 1

;Algemene constanten
SYMBOL OptrekTijd   = 500     ;mSec: Tijd voor optrekken motor zonder stroommeting
SYMBOL TerugTijd    = 1000    ;mSec: Tijd dat motor terugdraait na een overbelasting
SYMBOL Tijd         = 200     ;BYTE: Normale motordraai tijd (byte, dus max.255!)

;Poortnamen
SYMBOL MotorEnable  = PORTA.0 ;Motor aansturing ingeschakeld bij hoog niveau
SYMBOL LED          = PORTA.2 ;LED indicatie stroommeting actief
SYMBOL MotorLinksOm = PORTA.6 ;Motor draait linksom
SYMBOL MotorRechtsOm= PORTA.7 ;Motor draait rechtsom
SYMBOL Toets        = PORTB.0 ;Toets voor starten motor (maakcontact)
SYMBOL Optocoupler  = PORTB.1 ;Optocoupler geeft laag signaal bij overbelasting van motor

;Variabele declareren
DIM BD1             AS BYTE   ;Byte Dummy 1

;        76543210
PORTA = %00000000             ;Alle PORTA uitgangen laag
TRISA = %00111010             ;PORTA.7, A.6 en A.0 zijn uitgangen voor L293D, A.2 voor LED

PORTB_PULLUPS ON              ;Voor de optocoupler en de pulsschakelaar


;HoofdProgramma
WHILE 1 = 1                   ;Oneindige lus
  ;Motor stop
  MotorEnable   = LAAG        ;Schakel motoraansturing uit (Disable L293)
  LED           = OFF         ;LED (weer) uitzetten

  WHILE Toets   = HOOG : WEND ;Blijf hier wachten totdat op de starttoets wordt gedrukt

  ;Motor rechtsom laten draaien
  MotorRechtsOm = HOOG        ;PORTA.7 hoog maken, motor rechtsomdraaiend instellen
  MotorEnable   = HOOG        ;Maak EN1/2 van L293D hoog, OUT1 en OUT2 worden dan actief
  DELAYMS OptrekTijd          ;Even de motor laten draaien zonder stroommeting (optrekken) 
  
  LED           = ON          ;Indicatie dat stroommeting actief wordt
  
  FOR BD1 = 1 TO Tijd         ;Als tijd voorbij is dan motor stoppen
    IF Optocoupler = LAAG THEN;Bij overbelasting van motor, dan...
      MotorRechtsOm = LAAG    ;Eerst motor rechtsom uitschakelen
     'DELAYMS 500             ;Eventueel even wachten voordat naar linksom wordt gegaan
      MotorLinksOm  = HOOG    ;PORTA.6 hoog maken, motor gaat linksom draaien
      DELAYMS TerugTijd       ;Terugdraai tijd (terug = linksom)
      MotorLinksOm  = LAAG    ;Linksom uitschakelen
      BREAK                   ;Spring uit de FOR...NEXT lus
    ENDIF

    DELAYMS 20                ;Om de 20mSec meten
  NEXT
WEND

Bij een druk op 'Toets' zal de motor een paar seconden gaan draaien, waarbij de eerste halve seconde geen stroommeting wordt gedaan waardoor de PIC de motor niet meteen zal uitschakelen vanwege de piekstroom bij het starten van de motor.

Zodra de stroommeting actief is gaat de LED branden.

Als de motor nu overbelast wordt zal deze onmiddellijk één seconde de andere richting op gaan draaien en daarna stoppen.
Door de DELAYMS 500, die hier nog niet actief is omdat het als REM regel is gemarkeerd, te activeren zal de motor bij overbelasting eerst een halve seconde stoppen en pas daarna één seconde terugdraaien.


Met het voorbeeld hieronder is de motor in te schakelen met 'Toets'.
De motor blijft net zo lang draaien tot er opnieuw op 'Toets' wordt gedrukt.
Wordt de motor echter te zwaar belast, dan stopt de motor een halve seconde en draait dan 1 seconde de andere kant op.

'Motor aan/uit met dezelfde druktoets
'Bij blokkering van de motor gaat de motor een klein stukje achteruit en stopt dan

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Logische constanten
SYMBOL AAN          = 0       ;Geinverteerd ON
SYMBOL FALSE        = 0       ;Niet waar
SYMBOL HOOG         = 1       ;Hoog signaal
SYMBOL TRUE         = 1       ;Waar
SYMBOL UIT          = 1       ;Geinverteerd OFF

;Algemene constanten
SYMBOL Antidender   = 10      ;mSec: Tijd voor ontdendering van de druktoets
SYMBOL TerugTijd    = 1000    ;mSec: Tijd voor terugdraaien van motor bij blokkering

;Poortnamen
SYMBOL MotorEnable  = PORTA.0 ;Motor aansturing ingeschakeld bij hoog niveau
SYMBOL MotorLinksOm = PORTA.6 ;Motor draait linksom
SYMBOL MotorRechtsOm= PORTA.7 ;Motor draait rechtsom
SYMBOL Toets        = PORTB.0 ;Toets voor starten motor (maakcontact)
SYMBOL Optocoupler  = PORTB.1 ;Optocoupler geeft laag signaal bij overbelasting van motor

;        76543210
PORTA = %00000000             ;Alle PORTA uitgangen laag
TRISA = %00111110             ;PORTA.7, A.6 en A.0 zijn uitgangen voor de L293D

PORTB_PULLUPS ON              ;Voor de optocoupler en de pulsschakelaar


;Hoofdprogramma
MotorEnable   = HOOG          ;L293D uitgangen continu geactiveerd
  
WHILE 1 = 1                   ;Oneindige lus
  WHILE Toets = UIT : WEND    ;Blijf hier wachten totdat op 'Toets' wordt gedrukt

  MotorRechtsOm = TRUE        ;PORTA.7 hoog maken, motor rechtsomdraaiend instellen
  DELAYMS Antidender          ;Antidender
  WHILE Toets = AAN : WEND    ;Zolang 'Toets' is ingedrukt, geen stroommeting

  REPEAT
    IF Optocoupler = AAN THEN ;Als motor overbelast wordt, dan...
      MotorRechtsOm = FALSE   ;Stop rechtsom draaien van de motor (= motor staat stil)
      DELAYMS 500             ;Halve seconde wachten (met motor dus stop)
      MotorLinksOm  = TRUE    ;Motor linksom draaien (motor draait achteruit)
      DELAYMS TerugTijd       ;Eventjes achteruit draaien
      MotorLinksOm  = FALSE   ;Stop linksom draaien van de motor (= motor staat stil)
      BREAK                   ;Spring uit de REPEAT...UNTIL lus
    ENDIF

    DELAYMS 10                ;Check elke 10mSec of motor overbelast is,tevens antidender 
  UNTIL Toets = AAN           ;Doe de REPEAT...UNTIL lus totdat 'Toets' wordt ingedrukt
  MotorRechtsOm = FALSE       ;Stop rechtsom draaien van de motor (= motor staat stil)
  DELAYMS Antidender          ;Antidender voor indrukken van 'Toets'

  WHILE Toets = AAN : WEND    ;Wacht hier zolang de 'Toets' blijft ingedrukt
  DELAYMS Antidender          ;Antidender voor loslaten van 'Toets'
WEND

De constanten TRUE en FALSE helpen mee het programma overzichtelijker te maken.
Als er staat MotorRechtsOm = TRUE, dan drááit de motor ook rechtsom.
Staat er MotorRechtsOm = FALSE, dan draait de motor niet, of draait linksom, maar in ieder geval niet rechtsom.
TRUE en FALSE geven in dit geval de situatie duidelijker weer dan de constantenamen HOOG en LAAG.
De constantenamen AAN en UIT zijn weer duidelijker in het geval van de toets.
Je kan wel schrijven WHILE Toets = FALSE : WEND, maar dat is net iets minder duidelijk dan WHILE Toets = UIT : WEND, hoewel het voor de HEX code en de werking van de PIC niets uitmaakt.


Overbelasting detecteren met PWM sturing
Omdat PWM de motor steeds kleine duwtjes met maximale kracht geeft, zal de overbelast detectie dit onmiddellijk als een overbelasting zien, zelfs als de motor maar heel langzaam hoeft te draaien.
Om de overbelastdetectie geschikt te maken voor PWM moeten daarom condensator Cx en weerstand Rx worden toegevoegd (gestippeld weergegeven in schema 7p).
Hierdoor wordt een overbelasting alleen gedetecteerd als er daadwerkelijk een overbelasting van de motor plaats vindt.
Let wel, de meting werkt alleen bij een lage frequentie.
Dus alleen als de PIC draait op zijn interne (4MHz) oscillator of op een 4MHz kristal (PWM is dan 245Hz).
Neem voor onderstaande voorbeelden met instructie PWM voor Cx een 100n condensator en voor Rx een weerstand van 4k7.

Aangezien weerstand Rx als pull-up staat geschakeld, is het nu niet per sé nodig om de interne pull-ups bij stroommeting ingeschakeld te hebben.
De PORTB pull-ups is nu alleen nog ingeschakeld voor 'Toets'.

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Logische constanten
SYMBOL HOOG         = 1       ;Hoog signaal
SYMBOL LAAG         = 0       ;Laag signaal
SYMBOL OFF          = 0
SYMBOL ON           = 1       

;Poortnamen
SYMBOL MotorEnable  = PORTA.0 ;Motor aansturing ingeschakeld bij hoog niveau
SYMBOL LED          = PORTA.2 ;Controle LED
SYMBOL MotorRechtsOm= PORTA.7 ;Motor draait rechtsom
SYMBOL Toets        = PORTB.0 ;Resettoets (maakcontact)
SYMBOL Optocoupler  = PORTB.1 ;Optocoupler geeft laag signaal bij overbelasting van motor

;Variabele declareren
DIM Duty            AS BYTE   ;'Duty' is de variabele die de snelheid v.d. motor bepaalt

;        76543210
PORTA = %00000000             ;Alle PORTA uitgangen laag
TRISA = %00111010             ;PORTA.7, A.6 en A.0 zijn uitgangen voor L293D, A.2 voor LED 

PORTB_PULLUPS ON              ;Voor de pulsschakelaar


MotorEnable = HOOG            ;Maak EN1/2 van L293D hoog, OUT1 en OUT2 worden dan actief

HoofdProgramma:
  LED      = OFF              ;LED aanduiding motor overbelast uit

  FOR Duty = 1 TO 255         ;Motor gaat steeds sneller draaien tot maximum (= 255)
    PWM MotorRechtsOm, Duty, 5 ;Stuur 5 pulsen met pulsbreedte 'Duty', naar PORTA.7
    IF Optocoupler = LAAG THEN Overbelast ;Bij overbelasting naar 'Overbelast' springen
  NEXT

  FOR Duty = 254 TO 0 STEP -1 ;Motor gaat steeds langzamer draaien tot 0
    PWM MotorRechtsOm, Duty, 5 ;Stuur 5 pulsen met pulsbreedte 'Duty', naar PORTA.7
    IF Optocoupler = LAAG THEN Overbelast ;Bij overbelasting naar 'Overbelast' springen
  NEXT
GOTO HoofdProgramma           ;Oneindige lus

 
Overbelast:
  'MotorRechtsOm = LAAG'  werkt in dit geval niet goed, daarom met LOW! (zie cursustekst)
  LOW MotorRechtsom           ;Motor uitschakelen met instructie LOW! (zie cursustekst)
  LED = ON                    ;LED aanduiding motor overbelast aanzetten

  WHILE Toets = HOOG : WEND   ;Blijf hier wachten totdat op de (reset)toets wordt gedrukt
GOTO HoofdProgramma           ;Terug naar begin van het hoofdprogramma

Ook dit voorbeeld laat de motor onmiddellijk stoppen bij een overbelasting.
Een druk op 'Toets' laat de motor langzaam optrekken.

Nu even opletten.
Als de PWM instructie zijn taak heeft uitgevoerd dan laat deze de gebruikte poort als ingang achter!
Om in de 'Overbelast' routine de motor uit te schakelen volstaat het niet om te schrijven MotorRechtsOm = LAAG, want de PWM instructie heeft van de 'MotorRechtsOm' poort (PORTA.7) immers een ingang gemaakt en zal de poort hoog-ohmig blijven.
Het verraderlijke is nu dat het sóms wél werkt!
De (zwevende) ingangs(!)poort kan bijvoorbeeld een niveau van 1 volt hebben waardoor de L293D dit als laag ziet, maar een andere keer heeft de ingangspoort een niveau van bijvoorbeeld 3 volt en dan ziet de L293D dit als hoog!

Daarom na elke PWM instructie eerst weer van de poort een uitgang maken.
In dit geval moet de poort een uitgang zijn met een laag niveau om de motor te stoppen, dus maken we gebruik van LOW MotorRechtsOm.
Meer info over de instructies HIGH en LOW zie cursus deel 1 en lees het eerste gedeelte van cursus deel 3.


Het laatste voorbeeld met PWM in combinatie met overbelastingdetectie laat de motor weer continu langzaam optrekken en afremmen.
Bij een overbelasting van de motor gaat deze eerst één seconde stilstaan, en daarna een paar seconden langzaam (met 25% snelheid want dutycycle = 63) in tegengestelde richting draaien.
De LED brandt tijdens de overbelasting.
De boel is te resetten door op 'Toets' te drukken.

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Logische constanten
SYMBOL HOOG         = 1       ;Hoog signaal
SYMBOL LAAG         = 0       ;Laag signaal
SYMBOL OFF          = 0
SYMBOL ON           = 1       

;Poortnamen
SYMBOL MotorEnable  = PORTA.0 ;Motor aansturing ingeschakeld bij hoog niveau
SYMBOL LED          = PORTA.2 ;Controle LED
SYMBOL MotorLinksOm = PORTA.6 ;Motor draait linksom
SYMBOL MotorRechtsOm= PORTA.7 ;Motor draait rechtsom
SYMBOL Toets        = PORTB.0 ;Resettoets (maakcontact)
SYMBOL Optocoupler  = PORTB.1 ;Optocoupler geeft laag signaal bij overbelasting van motor

;Variabele declareren
DIM Duty            AS BYTE   ;'Duty' is de variabele die de snelheid v.d. motor bepaalt

;        76543210
PORTA = %00000000             ;Alle PORTA uitgangen laag
TRISA = %00111010             ;PORTA.7, A.6 en A.0 zijn uitgangen voor L293D, A.2 voor LED 

PORTB_PULLUPS ON              ;Voor de pulsschakelaar


;HoofdProgramma
MotorEnable = HOOG            ;Maak EN1/2 van L293D hoog, OUT1 en OUT2 worden dan actief

Lus:
  LED = OFF                   ;LED aanduiding motor overbelast uit

  FOR Duty = 1 TO 255         ;Motor gaat steeds sneller draaien tot maximum (= 255)
    PWM MotorRechtsOm, Duty, 5 ;Stuur 5 pulsen met pulsbreedte 'Duty', naar PORTA.7
    IF Optocoupler = LAAG THEN Overbelast ;Bij overbelasting naar 'Overbelast' springen
  NEXT

  FOR Duty = 254 TO 0 STEP -1 ;Motor gaat steeds langzamer draaien tot 0
    PWM MotorRechtsOm, Duty, 5 ;Stuur 5 pulsen met pulsbreedte 'Duty', naar PORTA.7
    IF Optocoupler = LAAG THEN Overbelast ;Bij overbelasting naar 'Overbelast' springen
  NEXT
GOTO Lus                      ;Oneindige lus

 
Overbelast:
  'MotorRechtsOm = LAAG'  werkt in dit geval niet goed, daarom met LOW! (zie cursustekst)
  LOW MotorRechtsom           ;Motor uitschakelen met instructie LOW! (zie cursustekst)
  LED = ON                    ;LED aanduiding motor overbelast aanzetten

  DELAYMS 1000                ;Tijd van motorstilstand
  PWM MotorLinksOm, 63, 1000  ;Stuur 1000 pulsen met pulsbreedte 63 (= 25%), naar PORTA.6
  LOW MotorLinksom            ;Motor uitschakelen met instructie LOW! (zie cursustekst)

  WHILE Toets = HOOG : WEND   ;Blijf hier wachten totdat op de (reset)toets wordt gedrukt
GOTO Lus                      ;Terug naar begin van het hoofdprogramma

Nogmaals over de instructie LOW.
Grote kans dat het programma ook werkt als de LOW regels worden weggelaten, maar schijn bedriegt.
De stilstand van de motor is niet stabiel en de motor zou zomaar voluit kunnen gaan draaien als bijvoorbeeld de PIC of de L293D met de vingers wordt aangeraakt.
Daarom LOW wél plaatsen, zodat de signalen van de PIC naar de L293D van een stevig laag niveau zijn.
Zie tekst van het vorige voorbeeld.


Geluiden met HPWM

Met HPWM kun je met behulp van een (5 volt) piëzo of een luidspreker ook geluiden maken.
Frequentie bepaalt dan de toonhoogte en Dutycycle bepaalt het volume.
Als je Dutycycle op 127 zet (= puls hoog/laag verhouding 50/50), is de volume op zijn hardst.
Ga je nu langzaam van 50% dutycycle naar 0% (= poort constant laag) óf naar 100% (= poort constant hoog), dan neemt de volume langzaam af naar 0.

Van de volumesterkte van een piëzo moet je niet al te veel voorstellen, de ene piëzo geeft meer geluid dan een andere.
Je kunt ook in plaats van een piëzo een (oude) luidspreker gebruiken, die klinkt zelfs luider.
De impedantie van de luidspreker maakt niet zoveel uit, voor de test van de cursus is een 3,2Ω exemplaar gebruikt.
Het spreekt voor zich dat alleen van PORTB.3 gebruik kan worden gemaakt, dat is immers de uitgang van de CCP module van de PIC16F628A.


Met elco Cx die parallel over de luidspreker staat is het geluid iets mooier te maken, maar is niet per se nodig.
Neem voor Cx een waarde van 10 ... 47µF.

 
De serie elco van 10µF moet bij gebruik van een luidspreker geplaatst worden.
Een 5V piëzo mag zonder deze elco rechtstreeks aan PORTB.3 worden aangesloten.

De 10µF elco zit er tussen om de eventuele DC offset weg te filteren, door een capaciteit komen immers alleen AC signalen.
Een gewone luidspreker vindt het niet leuk om een DC offset te zien want voor DC (= gelijkstroom) is de spoel van de luidspreker gewoon een kortsluiting en als de stroom te hoog wordt (bijvoorbeeld de PIC loopt vast of een programmeerfout waardoor PORTB.3 continu hoog blijft) dan is er zonder capaciteit ertussen een dikke kortsluiting.
Gevolg kan zijn dat de PIC defect raakt en/of de spoel van de luidspreker doorbrandt.

Een piëzo speaker is een capaciteit van zichzelf dus als je die rechtstreeks op de PIC aansluit is er geen serie capaciteit nodig.
 

 
Variabele volume
Onderstaand programma laat een soort gong horen, zoals die ook te horen is op de nieuwste magnetrons (= microgolfovens) van Whirlpool als de pizza klaar is, in plaats van een simpele pieptoon of een belletje.
Steeds als je op de toets drukt van PORTB.0, laat de piëzo 3 "gongs" horen.

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Logische constanten
SYMBOL UIT          = 1       ;Omgekeerd OFF

;Algemene constanten
SYMBOL AantalGongs  = 3       ;Bepaalt aantal gongs na een druk op toets S1
SYMBOL ToonHoogte   = 2100    ;Hz: Toonhoogte van de gong

;Poortnamen
SYMBOL S1           = PORTB.0 ;Puls-toets 1 (Start gong)

;Variabelen declareren       
DIM Volume          AS BYTE   ;'Volume' is de variabele die de volume van de piezo regelt
DIM Gongs           AS BYTE   ;'Gongs' is de variabele die telt hoe vaak een gong is gegaan

HPWM 1, 0, 0                  ;Reset de CCP/PWM module (Op 0% = constant laag)

;        76543210
TRISB = %11110111             ;PORTB.3 is uitgang voor PWM geluid signaal

PORTB_PULLUPS ON              ;Activeer ingebouwde PORTB pull-up weerstanden (voor toets S1)
CLEAR                         ;Wis alle RAM geheugen


;Hoofdprogramma
WHILE 1 = 1                   ;Oneindige lus
  WHILE S1 = UIT : WEND       ;Zolang toets S1 uit is, hier blijven wachten

  FOR Gongs = 1 TO Aantalgongs
    FOR Volume = 165 TO 0 STEP -1;Van 165 (=65% duty) naar constant laag (= piezo uit)
      HPWM 1, Volume, ToonHoogte ;Geef de frequentie 'ToonHoogte' door aan de CCP/PWM module 
      DELAYUS 60 * (~Volume / 2) ;Hoe zachter het volume, hoe langer de tijd duurt (nagalm)
    NEXT
    DELAYMS 250               ;Wachttijd tussen de gongs
  NEXT
WEND                          ;Terug naar WHILE

END

Zodra er op toets 'S1' wordt gedrukt, wordt de eerste FOR ... NEXT lus drie keer uitgevoerd, omdat de constante 'AantalGongs' de waarde 3 heeft gekregen bij SYMBOL.
Hierdoor zijn er steeds drie gongs te horen.
In die FOR ... NEXT lus, staat een andere FOR ... NEXT lus die dus, door die eerste FOR ... NEXT lus, drie keer wordt uitgevoerd.

De binnenste FOR ... NEXT lus telt terug (STEP -1) van 165 naar 0.
165 staat voor 65% dutycycle.
Aangezien 50% dutycycle de maximale volume geeft, zal de volume eerst nog iets stijgen en daarna terugzakken naar 0.

De nagalm duurt steeds langer als het volume zachter wordt.
Dit wordt gedaan door DELAYUS 60 * (~Volume / 2).
(Let op, het is DELAYUS en niet DELAYMS).
1000µSec = 1mSec en 1000mSec = 1 seconde, dus 1000000µSec duurt 1 seconde.
Let wel, de maximale waarde die je achter DELAYMS en DELAYUS kunt plaatsen is 65535.

Welnu, 'Volume' begint dus bij 165.
Door vóór 'Volume' een tilde ( ~ ) te zetten, inverteer je de waarde van 'Volume' (Meer info over de tilde).
Aangezien 'Volume' een BYTE variabele is, is de geïnverteerde waarde van 165 (255 - 165) = 90.

Dus wacht deze regel 60 × (90 / 2) = 2700µSec (= 2,7mSec).
Door de FOR ... NEXT lus wordt 'Volume' steeds kleiner, maar '~Volume' juist steeds groter.
Zo wacht deze regel steeds langer, omdat de geïnverteerde waarde van 'Volume' steeds groter wordt.
Als de volume op zijn hardst is, dan is 'Volume' op dat moment 127.
Dan wacht deze regel 60 × (127 / 2) = 3810µSec (= 3,18mSec).
Aan het eind is de geïnverteerde waarde van de variabele 'Volume' 255.
Dan wacht deze regel 60 × (255 / 2) = 7650µSec (= 7,65mSec).
Je ziet dat, terwijl het volume afneemt, de nagalm zo steeds langer duurt.


Variabele frequentie
Als je op de toets drukt van PORTB.0, start je een sirene.

DEVICE 16F628A                ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
ALL_DIGITAL TRUE              ;Alle ingangen digitaal

;Logische constanten
SYMBOL UIT          = 1       ;Omgekeerd OFF

;Algemene constanten
SYMBOL AantalSnel   = 8       ;Bepaalt aantal maal dat de snelle sirene loeit na S1 indruk
SYMBOL AantalTraag  = 3       ;Bepaalt aantal maal dat de trage sirene loeit na S1 indruk

;Poortnamen
SYMBOL S1           = PORTB.0 ;Puls-toets 1 (Start gong)

;Variabelen declareren
;WORD
DIM Hertz           AS WORD   ;'Hertz' is de variabele toonhoogte (frequentie in Hertz)
;BYTE
DIM Sirene          AS BYTE   ;'Sirene' is de variabele die aantal keer sirenes telt

;        76543210
TRISB = %11110111             ;PORTB.3 is uitgang voor PWM geluid signaal

PORTB_PULLUPS ON              ;Activeer ingebouwde PORTB pull-up weerstanden (voor toets S1) 
CLEAR                         ;Wis alle RAM geheugen


;Hoofdprogramma
WHILE 1 = 1                   ;Oneindige lus
  HPWM 1, 0, 0                ;Reset de CCP/PWM module (Op 0% = constant laag)

  WHILE S1 = UIT : WEND       ;Zolang toets S1 uit is, hier blijven wachten

  FOR Sirene = 1 TO AantalSnel;'Sirene' lus 'AantalSnel' maal uitvoeren
    FOR Hertz = 250 TO 2000 STEP 25 ;Snel (stappen van 25Hz) van 250Hz naar 2000Hz
      HPWM 1, 127, Hertz      ;Geef de frequentie 'Hertz' door op maximale volume (127) 
    NEXT
    FOR Hertz = 2000 TO 250 STEP -7 ;Snel (stappen van 7Hz) van 2000Hz naar 250Hz
      HPWM 1, 127, Hertz      ;Geef de frequentie 'Hertz' door op maximale volume (127) 
    NEXT
  NEXT

  FOR Sirene = 1 TO AantalTraag ;'Sirene' lus 'AantalTraag' maal uitvoeren
    FOR Hertz = 250 TO 2000   ;Van 250Hz naar 2000Hz
      HPWM 1, 127, Hertz      ;Geef de frequentie 'Hertz' door op maximale volume (127) 
      DELAYUS 100             ;Toonhoogte van laag naar hoog gaat sneller
    NEXT
    DELAYMS 300               ;Houdt de sirene 0,3 seconde hoog
    FOR Hertz = 2000 TO 250 STEP -1 ;Van 2000Hz naar 250Hz
      HPWM 1, 127, Hertz      ;Geef de frequentie 'Hertz' door op maximale volume (127) 
      DELAYUS 400             ;Toonhoogte van hoog naar laag gaat langzamer
    NEXT
  NEXT
WEND                          ;Terug naar WHILE

END

De buitenste FOR ... NEXT lus (met 'Sirene' als telvariabele) bepaalt hoe vaak de sirene loeit na iedere toetsindruk.
Binnen in deze FOR ... NEXT lus staan na elkaar twee andere FOR ... NEXT lussen.
De eerste binnenste laat de frequentie hoger worden, de tweede binnenste FOR ... NEXT laat de frequentie weer lager worden.
De telvariabele met de naam 'Hertz' van de binnenste lussen is een WORD variabele, omdat de frequentie natuurlijk verder gaat dan 255 Hertz.

In het eerste FOR ... NEXT blok wordt de snelle sirene opgewekt door de frequentie met stappen van 25Hz te verhogen en met stappen van 7Hz te verlagen.
Deze lus wordt 8 maal uitgevoerd (opgegeven waarde van de constante 'AantalSnel').

In het tweede FOR ... NEXT blok wordt de trage, langzame sirene opgewekt.
De frequentie verhoogt en verlaagt in stappen van 1Hz, met daarbij DELAYUS vertragingen ingevoegd.
Deze lus wordt 3 maal uitgevoerd (opgegeven waarde van de constante 'AantalTraag').

Het resetten van de CCP module staat nu in de lus, omdat steeds als de sirene heeft geklonken, deze weer uit gezet moet worden.
Als deze niet in de lus zou staan dan zou als de laatste sirenetoon naar de CCP module is gestuurd deze de laatst opgegeven frequentie blijven uitsturen.
Een monotoon van 250Hz is dan het resultaat.
Steeds als de sirene heeft geloeid dan springt het programma bij WEND terug naar WHILE 1 = 1.
De eerste instructie die daarna wordt uitgevoerd is eerst de CCP module resetten door deze op 0% dutycycle in te stellen.
Pas daarna wacht het programma weer op een toetsindruk bij WHILE S1 = UIT : WEND.

Experimenteer gerust door de waarden eens te wijzigen en kijken (en horen!) wat er gebeurt.
Denk er aan dat de minimale frequentie een grens heeft, afhankelijk van de gebruikte oscillator (zie tabel).
De inwendige oscillator van de PIC16F628A is, zoals je weet, 4MHz.
De maximale frequentie is 32767Hz.
PIC Basic instructies SOUND, SOUND2, FREQOUT en DTMFOUT zijn er speciaal voor het genereren van geluid en zijn niet gebonden aan de CCP module, en kunnen dus met elke uitgangspoort overweg (zie de PIC Basic help-bestanden).


PIC Basic cursus deel 8 gaat over het aansturen van servomotoren.
Dit deel is gebaseerd op een goedkope servo van Conrad (8 Euro, bestelnr. 22 77 27 ).