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