1+ namespace CNC {
2+
3+
4+ struct alignas (uint16_t ) Step {
5+ uint16_t ticks : 13 ;
6+ uint8_t axis : 2 ;
7+ uint8_t dir : 1 ;
8+ };
9+
10+ Step ring[256 ];
11+ uint8_t wr;
12+ uint8_t rd;
13+
14+ enum ErrorBits {
15+ EUNDERFLOW,
16+ EOVERFLOW,
17+ };
18+
19+ uint8_t error;
20+ uint32_t tickPerSec;
21+ float mmPerRevo = 40 ;
22+ float stepPerRevo = 800 ;
23+
24+ enum TickRate : uint32_t {
25+ Tick_2MHz = 2000000 ,
26+ Tick_250kHz = 250000 ,
27+ Tick_62500Hz = 62500 ,
28+ Tick_15625Hz = 15625 ,
29+ };
30+
31+ void begin (TickRate tickRate = Tick_62500Hz) {
32+ cli ();
33+ uint8_t cs = 0 ;
34+ switch (tickRate) {
35+ case Tick_2MHz: cs = _BV (CS11); break ; // 2MHz - 8kHz
36+ case Tick_250kHz: cs = _BV (CS11) | _BV (CS10); break ; // 250kHz - 977Hz
37+ case Tick_62500Hz: cs = _BV (CS12); break ; // 62.5kHz - 244Hz
38+ case Tick_15625Hz: cs = _BV (CS12) | _BV (CS10); break ; // 15625Hz - 61Hz
39+ default : cs = 0 ; break ;
40+ };
41+ tickPerSec = tickRate;
42+
43+ TCCR1A = 0 ;
44+ TCCR1B = _BV (WGM12) | cs;
45+ OCR1A = 255 ;
46+ TIMSK1 = _BV (OCIE1A);
47+ PORTD &= B00000011;
48+ PORTB &= B11001111;
49+ PORTB |= B00000001;
50+ DDRD |= B11111100;
51+ DDRB |= B00110001;
52+ wr = 0 ;
53+ rd = 0 ;
54+ error = 0 ;
55+ sei ();
56+ }
57+
58+ void enable (bool on) {
59+ if (on) {
60+ PORTB &= ~B00000001;
61+ } else {
62+ PORTB |= B00000001;
63+ }
64+ }
65+
66+ bool ringw (Step const &step) {
67+ cli ();
68+ uint8_t p = wr;
69+ if (p + 1 == rd) {
70+ sei ();
71+ return false ;
72+ }
73+ ring[p] = step;
74+ wr = p + 1 ;
75+ sei ();
76+ return true ;
77+ }
78+
79+ bool ringr (Step &step) {
80+ uint8_t p = rd;
81+ if (p == wr) {
82+ error |= _BV (EUNDERFLOW);
83+ return false ;
84+ }
85+ step = ring[p];
86+ rd = p + 1 ;
87+ return true ;
88+ }
89+
90+ void ISR_TIMER1_COMPA_vect () {
91+ cli ();
92+ Step step;
93+ if (!ringr (step)) {
94+ sei ();
95+ return ;
96+ }
97+ OCR1A = step.ticks ;
98+ switch (step.axis ) {
99+ case 0 :
100+ bitWrite (PORTD, PD5, step.dir );
101+ bitToggle (PORTD, PD2);
102+ break ;
103+ case 1 :
104+ bitWrite (PORTD, PD6, step.dir );
105+ bitToggle (PORTD, PD3);
106+ break ;
107+ case 2 :
108+ bitWrite (PORTD, PD7, step.dir );
109+ bitToggle (PORTD, PD4);
110+ break ;
111+ case 3 :
112+ bitWrite (PORTB, PB5, step.dir );
113+ bitToggle (PORTB, PB4);
114+ break ;
115+ }
116+ sei ();
117+ }
118+
119+ void send (uint8_t axis, uint8_t dir, uint16_t ticks) {
120+ Step step;
121+ step.ticks = ticks;
122+ step.axis = axis;
123+ step.dir = dir;
124+ ringw (step);
125+ }
126+
127+ uint8_t lastError () {
128+ cli ();
129+ uint8_t e = error;
130+ error = 0 ;
131+ sei ();
132+ return e;
133+ }
134+
135+ uint16_t mmPerSec_to_tickPerStep (float mmPerSec) {
136+ float mmPerStep = mmPerRevo / stepPerRevo;
137+ float stepPerSec = mmPerSec / mmPerStep;
138+ float tickPerStep = tickPerSec / stepPerSec;
139+ return uint16_t (tickPerStep) - 1 ;
140+ }
141+
142+ }
143+
144+ ISR (TIMER1_COMPA_vect) {
145+ CNC::ISR_TIMER1_COMPA_vect ();
146+ }
147+
148+ void setup () {
149+ Serial.begin (9600 );
150+ CNC::begin ();
151+ CNC::enable (true );
152+ }
153+
154+ void loop () {
155+ long mmps = map (analogRead (SDA), 0 , 1023 , 10 , 200 );
156+ uint16_t tick = CNC::mmPerSec_to_tickPerStep (mmps);
157+ CNC::send (0 , 1 , tick);
158+ uint8_t error = CNC::lastError ();
159+ if (error) {
160+ CNC::enable (false );
161+ Serial.print (" ERROR:" );
162+ Serial.print (error, BIN);
163+ Serial.print (" SPEED:" );
164+ Serial.print (mmps);
165+ Serial.print (" TICKS:" );
166+ Serial.println (tick);
167+ delay (1000 );
168+ CNC::begin ();
169+ CNC::enable (true );
170+ }
171+ }
0 commit comments