Dit circuit stuurt een stapmotor aan om iets van positie te laten veranderen.
Bij toepassing als vergrendeling moet je de persoonsveiligheid niet uit het oog verliezen. Denk bijv. wat te doen bij brand of onwel worden. Zijn er genoeg andere vluchtwegen. Kan iemand anders er nog in. Ga er niet vanuit dat deze schakeling altijd zal werken.
Er zijn 2 buttons A en B.
A: 1 x drukken motor zorgt voor gaan naar eindpunt 1 en neemt dan weer een stukje terug.
Nog een keer drukken idem dan voor eindpunt 2. Het stukje terug is om een (opzettelijke grote) speling toe te
laten daardoor kun je met de hand de positie veranderen zonder de motorweerstand en eventuele
tandwielvertragingweerstand te ondervinden via een soort koppelstuk. ( <-> ), ( en ) zitten aan elkaar vast en is de
uiteindelijke positieverplaatsing, <-> motorbeweging, spaties ertussen is de speling.
B: ijken, is om eindpunten 1( en )2 te zetten. 1-----( <-> )----2
Schakeling wordt gevoed uit een beltrafo met als backup 8 x 1,2V NiMh cellen. De backup kan bij weinig gebruik dagen lang mee.
Als stappenmotor driver kun je een TMC2209 of LV8729 nemen maar geen A4988 vanwege beperkte spanningsrange.
De PIC 12F675 genereert step en richting signalen voor de driver. Zelf kan hij in het circuit zelf geprogrammeerd worden via een zgn ISP interface. R8,R11,R4,C4 en D6 zijn daarbij noodzakelijk.
Naast de button signalen gebruiken we ook 2 analoge ingangen om resp. de motorstroom en de ( ) positie te meten.
Motorstroom meten via weerstanden R9 en R13 waar de groundstromen doorheen gaan. D8 voorkomt dat de driver nooit te weinig spanning krijgt. De driver veroorzaakt veel storing die gefilterd/gemiddeld wordt door R12 en C10. GP2 wordt zowel gebruikt om de stroom te meten als ook om de buzzer aan te sturen mocht die een grens overgaan bij bijv. blokade. De PIC bepaald de grens samen met RV1. Door het tweevoudig gebruik zijn D9,D19,R7,R19 en C12 noodzakelijk. De buzzer heeft een controlingang C, buzzed indien hoger dan 3V maar moet wel minimaal 150ms aan staan.
10k potentiometer bij j4 geeft de positie door. In plaats van de potentiometer kan men ook 2 buttonschakelaars bij de eindpunten plaatsen plus een aantal weerstanden.
Om in rust geen motorstroom te laten lopen is het circuit rond Q1 nodig. Zolang de steps komen is de laag actieve enable laag. Echter bij opstarten blijkt er toch motorstroom te lopen bij no steps, de LV8729 krijgt geen resetsignaal. Slechts 1 step is nodig om dit recht te zetten.
Het programma is met MPLAB X 6.20 ontwikkeld, je kan dan nog PICkit3 gebruiken, met C als programmeertaal.
Ik kan MPLAB X niemand aanbevelen. C is leuk als je pointers wil gebruiken of vreemde datatypen.
Omdat deze PIC geen pwm uitgang bezit en ik geen interrupts wou gebruiken doe ik moeilijk met telkens 40 steps. Ik gebruik een motorvertraging van 1/17 zodat beweging niet al te groot is. Na 40 steps wordt dan telkens de motorstroom en de positie gemeten. Indien de motorstroom te hoog is gaat de buzzer af zodat men weet dat er iets speelt.
Met button B callibratie worden de eindpunten gezet. Druk op B tot je bij een eindpunt bent laat dan los en druk op button A. Doe dit nog een keer om het andere eindpunt te zetten.
Het geheel werkt nog niet helemaal zoals zou moeten. De buzzer gaat vaak de mist in misschien door storing pieken. De motorstroom neemt slechts 10% toe bij veel weerstand. De drivers hebben natuurlijk een ingebouwde stroombegrenzing en er zal ook voor de hoogte van de voedingsspanning gecompenseerd moeten worden. .
Een betere indicatie is positie verandering tgv aantal steps te volgen. Zonder de mechanica kun je dat niet testen.
Gebruikte stapmotor is ACT MOTOR 17HS5425, 0,48 Nm, 1,8mH, 1,25 Ohm, 3V, 2,5A. Er loopt ongeveer 0,8A voedingstroom. In rust 6 mA, kan het niet goed meten.
Bij lage voedingspanningen 2,7-10,8V kan de driver DRV8833 gebruikt worden. Deze heeft echter geen indexer aan boord, geen step en direction, maar gelijk brugaansturing. Voor full step kun je een makkelijke routine gebruiken. Zie dan voor timing van de stromen een driver datasheet.
Het 1e scoopplaatje geeft het moment aan wanneer de buzzer aan gaat (geel verspringt). Het groen komt van de tracer 500µs voor en 500µs na referentie pulsen. Daar tussenin kunnen we zien hoe groot ADRESL is nml. 1100µs/18,5µs=59 is ongeveer Ilimit=60. Het is 18,5 en geen 10µs tgv. extra FOR loop vertraging. Dit is uitgerekend door naar de pulslengte van de loper te kijken. Loper was 1,68V/5V *256=86 en pulsduur loper is 1600µs, 1600/86=18,5µs. 2e plaatje is van zonder buzzen tussen 2 x40 steps in (blauw). Je ziet nu 2 treintjes 1e van de stroommeting gevolgd door de lopermeting. Rood is spanning over C10.
/*
* File: Deu1.c
* Author: deluxe
*
* Created on July 24, 2026, 11:03 PM
*/
// 'C' source line config statements
// PIC12F675 Configuration Bit Settings
#pragma config FOSC = INTRCIO // Oscillator Selection bits (INTOSC oscillator: I/O function on GP4/OSC2/CLKOUT pin, I/O function on GP5/OSC1/CLKIN)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-Up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF // GP3/MCLR pin function select (GP3/MCLR pin function is digital I/O, MCLR internally tied to VDD)
#pragma config BOREN = OFF // Brown-out Detect Enable bit (BOD disabled)
#pragma config CP = OFF // Code Protection bit (Program Memory code protection is disabled)
#pragma config CPD = OFF // Data Code Protection bit (Data memory code protection is disabled)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#include <xc.h>
//#include <pic12f675.h>
//#include <builtins.h>
//#include <stdint.h>
/*
* GP0 --> "DIR" LV8729 (U3) / "PGD" PICkit (Pin5)
* GP1 --> "Open/Close" Switch (S1,S2) / "PGC" PICkit (Pin4)
* GP2 --> "AN2" Current Sense (R9) / Buzzer
* GP3 --> "Calibration" Switch (S3) / "VPP" PICkit (Pin1)
* GP4 --> "AN3" Potmeter (P1)
* GP5 --> "STEP" LV8729 /
*/
//int _XTAL_FREQ=4000000;
#define _XTAL_FREQ 4000000
#define Dir GP0 // 0=openen / 1=sluiten
#define DoCycle GP1 // open or close / 0 if button pressed
#define Buzzer GP2 // 1 to buzz
#define Calibrate GP3 // 0 if button pressed
#define Potmeter GP4 //
#define Step GP5 // Step level
char k=0;
char l=0;
void trace(char K , char L) // voor debugging / K aantal perioden / L duur
{
TRISIO=0b00011100 ; //GP1 temp output
GP1=0;
__delay_us(500);
for (k=1;k<=K;k++)
{
GP1=1;
for (l=1;l<=L;l++) __delay_us(10);
GP1=0;
for (l=1;l<=L;l++) __delay_us(10);
};
GP1=1;
__delay_us(500);
TRISIO=0b00011110 ; //GP1 is weer input
}
unsigned int n=0;
const unsigned int period=2500; // in microseconds
void steps(unsigned int N) // N aantal stappen
{
//trace(2,10);
for (n=1;n<=N;n++)
{
GP5=1;
__delay_us(period/2);
GP5=0; // met 0 eindigen zodat driver gedisabled wordt
__delay_us(period/2);
}
}
const char Isense =2;
const char Loper =4;
char result =0;
char meet(char bron) // 2=current / 4=loper potmeter
{
ANSEL=0b01101100;//0 110=4MHz>16us clock 1100 AN3 and AN2 selected as analog
if (bron==Isense) ADCON0=0b10001000;//resultaat rechts, Vdd=ref, meet AN2
if (bron==Loper) ADCON0=0b00001100;//resultaat links, Vdd=ref, meet AN3
ADON=1; // Enable ADC
__delay_us(100); // setup sample hold time
GO=1; // converteer
while (GO_nDONE==1); // wacht tot conversie klaar is / zie pic12f675.h
if (bron==Isense){result= ADRESL;trace(1,ADRESL);}//bereik 0 tot 256*5mV/8bit
if (bron==Loper) {result= ADRESH;trace(1,ADRESH);}//bereik 0 tot VDD=5V/8bit
ANSEL = 0;
return result;
} //wat ook kan int result = ((ADRESH<<8)+ADRESL);
void buzz(void)
{
//trace(3,10);
TRISIO = 0b00011010; // GP2 tijdelijk output
Buzzer=1; //buzzer aan
__delay_ms(150); // minimum aan tijd
Buzzer=0; //buzzer uit
TRISIO = 0b00011110; // GP2 nu input om current te sensen
__delay_ms(150); //ingang settle time 10uF
}
__bit GoOn ; // __bit type kun je niet initializen
//binnen main, static gebruiken er buiten is het global
__eeprom char LLower=70; // voor stroomuitval eindpunten behoeden
__eeprom char UUpper=180; // ongeveer 128 apart = 1/3 omwenteling =20mm
void main(void)
{
//////////////////////////////
// MCU I/O initialization
//////////////////////////////
// GPIO = 0b00001010 ; //
OPTION_REG = 0b11010001; // 1101 0001 tmr0 enabled prescale 4 internal clock = 1MHz
INTCON = 0b00000000; //0000 0000 no interupts
TRISIO = 0b00011110; // 0001 1110 only DIR and Step are outputs
// during buzz GP2 is temp output
ADCON0 = 0b10001001; // 1000 10=AN2 11=AN3 0= no start 1=AD is ON
//ANSEL = 0b01101100 ; // 0 110=4MHz/64=62,5kHz`16us 1100 AN3 and AN2 selected as analog
ANSEL = 0;
CMCON = 0b00000111 ; // zet compare analog interfere uit
const unsigned int Turn1Third =17*66;// vertraging x 1/3 omwenteling / van motor tot omwenteling
const char Ilimit=60; // =60*5V/1024, 0,3V/0,5Ohm=0,6A
const char lowermin=60;
const char lowerplus=100;
const char uppermin=150;
const char upperplus=190;
char result;
char Lower; //ondereindpunt
char Upper; //boveneindpunt
steps(1); // stepper driver resets to off state
Lower=LLower;
Upper=UUpper;
while(1)
{
GoOn=0;
//GP1=1; kunnen GP1 niet setten want het is een input
//GP3=1;
if (!GP3) //callibratie Lower, Upper
{
//trace(6,10);
__delay_ms(200); //anti dender
while (!GP3)
steps(20); //beweeg voorzichtig naar een eindpunt, stop zelf
while (GP1); //wacht op cycle button om eindpunt te zetten
result=meet(Loper);
if ((GP0==0)&(result>=lowermin)&(result<=lowerplus))
{Lower=result;LLower=result;};
if ((GP0==1)&(result>=uppermin)&(result<=upperplus))
{Upper=result;UUpper=result;};
GP0=!GP0; //richting verandert om tot andere eindpunt te komen
__delay_ms(200); // anti dender GP1
};
while (!GP1 | GoOn) // openen en sluiten
{
//trace(5,10);
GoOn=1; //beweeg tot cycle afgelopen is
steps(40); //beweeg voorzichtig 0,1s = 40 steps
if (meet(Isense)>Ilimit) buzz(); //alarm bij teveel weerstand
// kom je bij een eindpunt keerom en beweeg 1/3 omwenteling terug
result=meet(Loper);
if (result<Lower|result>Upper) {GP0=!GP0;steps(Turn1Third);GoOn=0;};//Turn1Third
};
}
}
Roland van Leusden
It's the rule that you live by and die for It's the one thing you can't deny Even though you don't know what the price is. It is justified.
Motorstroom meten via weerstanden R9 en R13 waar de groundstromen doorheen gaan. D8 voorkomt dat de driver nooit te weinig spanning krijgt. De driver veroorzaakt veel storing die gefilterd/gemiddeld wordt door R12 en C10. GP2 wordt zowel gebruikt om de stroom te meten als ook om de buzzer aan te sturen mocht die een grens overgaan bij bijv. blokade. De PIC bepaald de grens samen met RV1. Door het tweevoudig gebruik zijn D9,D19,R7,R19 en C12 noodzakelijk.
Waarom ? De TMC2209 met StallGuard4 doet dat zelf. Met je PIC hoef je alleen maar DIAG te monitoren.
En waarom niet verder in het originele topic?
Kijk dit is geen optimaal ontwerp. Er wordt onnodig moeilijk gedaan. De gebruikte PIC en aanvankelijk A4988 zijn allang achterhaald door betere ontwerpen. Ook het pollen ipv. een interrupt gebruiken laat de motor niet helemaal soepel lopen maar soepel genoeg.
Ik wou dit al 5 jaar geleden ontwerpen maar geen zin in voornamelijk door MPLABX. Het leek mij leuk om de motorstroom te meten. Ook bij het gebruik van een grotere PIC hoef je niet van alles te bedenken om het binnen 8pins te houden. Als je enkel van eindpunt 1 naar eindpunt 2 gaat hoef je ook geen positie te weten.
Hou het er maar op dat het een hobby is met bepaalde ideeen hoe je iets wil oplossen. Er komen hier vaak genoeg mensen op het forum met niet echt eenvoudige oplossingen. Het is voor hun leuker dat hun ideeen werken dan te weten hoe het allemaal veel beter kan. Het schrikt ze af.
Ik bezit toevallig de TMC2209 maar die zijn nodig voor mijn 3d printer update waar ik waarschijnlijk ook al weer jaren achterloop. 
Het orginele topic gaat over debuggen.
De TMC2209 is een goede keuze.
https://github.com/bigtreetech/docs/blob/master/docs/TMC2209.md
De diagnose pin steekt naar boven uit. Zie plaatje. Het is de pin die het dichtst bij de instelpotmeter staat.
Diagnostic and StallGuard output. High level (kan minstens 2mA trekken) upon stall detection or driver error . Reset error condition by ENN=high. Dus kan gelijk op een buzzer met control ingang aangesloten worden.
Reset gebeurt elke keer als steppen ophoud omdat enable dan hoog wordt.
Zie pagina 58 datasheet voor meer info.
Beter alternatief dan stroom sensen.
Roland bedankt.
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
C is leuk als je pointers wil gebruiken of vreemde datatypen.
Die kun je in (bijna) iedere taal gebruiken, heb je geen C voor nodig...
De sterkte van C is dat je perfect leesbare en verstaanbare code kan schrijven, maar dit progamma lijkt eerder assembler !