#define P12F675 #include "allpic.h" #pragma config = 0b000110010100 // grundkonfiguration des PICs // PIOs #define AN_0 0 // analogeingang #define OUT_A0 1 #define OUT_B0 2 // Schrittmotor-Ausgänge #define NC_3 3 #define OUT_A1 4 #define OUT_B1 5 #define RIGHT_STEP 1 // ein step nach rechts #define LEFT_STEP -1 // ein step nach links #define LOG_STEPS 6 // logische steps pro halbschritt #define LOG_STEP_TIME 1000 // logische stepzeit in us #define _GIE 7 const uns8 pow[] = { // (val * val) / 255 // 0 1 2 3 4 5 6 7 8 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 10 11 12 13 14 15 16 17 18 19 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, // 20 21 22 23 24 25 26 27 28 29 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, // 30 31 32 33 34 35 36 37 38 39 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, // 40 41 42 43 44 45 46 47 48 49 6, 6, 6, 7, 7, 7, 8, 8, 9, 9, // 50 51 52 53 54 55 56 57 58 59 9, 10, 10, 11, 11, 11, 12, 12, 13, 13, // 60 61 62 63 64 65 66 67 68 69 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, // 70 71 72 73 74 75 76 77 78 79 19, 19, 20, 20, 21, 22, 22, 23, 23, 24, // 80 81 82 83 84 85 86 87 88 89 25, 25, 26, 27, 27, 28, 29, 29, 30, 31, // 90 91 92 93 94 95 96 97 98 99 31, 32, 33, 33, 34, 35, 36, 36, 37, 38, // 100 101 102 103 104 105 106 107 108 109 39, 40, 40, 41, 42, 43, 44, 44, 45, 46, // 110 111 112 113 114 115 116 117 118 119 47, 48, 49, 50, 50, 51, 52, 53, 54, 55, // 120 121 122 123 124 125 126 127 128 129 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, // 130 131 132 133 134 135 136 137 138 139 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, // 140 141 142 143 144 145 146 147 148 149 76, 77, 79, 80, 81, 82, 83, 84, 85, 87, // 150 151 152 153 154 155 156 157 158 159 88, 89, 90, 91, 93, 94, 95, 96, 97, 99, // 160 161 162 163 164 165 166 167 168 169 100, 101, 102, 104, 105, 106, 108, 109, 110, 112, // 170 171 172 173 174 175 176 177 178 179 113, 114, 116, 117, 118, 120, 121, 122, 124, 125, // 180 181 182 183 184 185 186 187 188 189 127, 128, 129, 131, 132, 134, 135, 137, 138, 140, // 190 191 192 193 194 195 196 197 198 199 141, 143, 144, 146, 147, 149, 150, 152, 153, 155, // 200 201 202 203 204 205 206 207 208 209 156, 158, 160, 161, 163, 164, 166, 168, 169, 171, // 210 211 212 213 214 215 216 217 218 219 172, 174, 176, 177, 179, 181, 182, 184, 186, 188, // 220 221 222 223 224 225 226 227 228 229 189, 191, 193, 195, 196, 198, 200, 202, 203, 205, // 230 231 232 233 234 235 236 237 238 239 207, 209, 211, 212, 214, 216, 218, 220, 222, 224, // 240 241 242 243 244 245 246 247 248 249 225, 227, 229, 231, 233, 235, 237, 239, 241, 243, // 250 251 252 253 254 255 245, 247, 249, 251, 253, 255 }; const uns8 sqrt[] = { // sqrt(qmid * 225) für 360° // 0 1 2 3 4 5 6 7 8 9 0, 15, 21, 26, 30, 33, 36, 39, 42, 45, // 10 11 12 13 14 15 16 17 18 19 47, 50, 52, 54, 56, 58, 60, 62, 64, 65, // 20 21 22 23 24 25 26 27 28 29 67, 69, 70, 72, 73, 75, 76, 78, 79, 81, // 30 31 32 33 34 35 36 37 38 39 82, 83, 85, 86, 87, 89, 90, 91, 92, 93, // 40 41 42 43 44 45 46 47 48 49 95, 96, 97, 98, 99, 101, 102, 103, 104, 105, // 50 51 52 53 54 55 56 57 58 59 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, // 60 61 62 63 64 65 66 67 68 69 116, 117, 118, 119, 120, 121, 122, 123, 124, 124, // 70 71 72 73 74 75 76 77 78 79 125, 126, 127, 128, 129, 130, 131, 131, 132, 133, // 80 81 82 83 84 85 86 87 88 89 134, 135, 136, 137, 137, 138, 139, 140, 141, 141, // 90 91 92 93 94 95 96 97 98 99 142, 143, 144, 145, 145, 146, 147, 148, 148, 149, // 100 101 102 103 104 105 106 107 108 109 150, 151, 151, 152, 153, 154, 154, 155, 156, 157, // 110 111 112 113 114 115 116 117 118 119 157, 158, 159, 159, 160, 161, 162, 162, 163, 164, // 120 121 122 123 124 125 126 127 128 129 164, 165, 166, 166, 167, 168, 168, 169, 170, 170, // 130 131 132 133 134 135 136 137 138 139 171, 172, 172, 173, 174, 174, 175, 176, 176, 177, // 140 141 142 143 144 145 146 147 148 149 177, 178, 179, 179, 180, 181, 181, 182, 182, 183, // 150 151 152 153 154 155 156 157 158 159 184, 184, 185, 186, 186, 187, 187, 188, 189, 189, // 160 161 162 163 164 165 166 167 168 169 190, 190, 191, 192, 192, 193, 193, 194, 194, 195, // 170 171 172 173 174 175 176 177 178 179 196, 196, 197, 197, 198, 198, 199, 120, 200, 201, // 180 181 182 183 184 185 186 187 188 189 201, 202, 202, 203, 203, 204, 205, 205, 206, 206, // 190 191 192 193 194 195 196 197 198 199 207, 207, 208, 208, 209, 209, 210, 211, 211, 212, // 200 201 202 203 204 205 206 207 208 209 212, 213, 213, 214, 214, 215, 215, 216, 216, 217, // 210 211 212 213 214 215 216 217 218 219 217, 218, 218, 219, 219, 220, 220, 221, 221, 222, // 220 221 222 223 224 225 226 227 228 229 222, 223, 223, 224, 224, 225, 225, 226, 226, 227, // 230 231 232 233 234 235 236 237 238 239 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, // 240 241 242 243 244 245 246 247 248 249 232, 233, 233, 234, 234, 235, 235, 236, 236, 237, // 250 251 252 253 254 255 237, 237, 238, 238, 239, 239 }; uns8 int_counter; // interrupt-counter uns16 qmid; // quadratischer mittelwert uns8 eff; // effektivwert #define make_save_regs unsigned char s1, s2 #define save_W { s1 = W;} #define restore_W { s1 = swap(s1); W = swap(s1);} #define save_regs { save_W; s2 = swap(STATUS); } #define restore_regs_return { STATUS = swap(s2); restore_W; return; } #pragma origin 4 interrupt server(void) // ISR, TMR0 { if(GO) return; // wandlung fertig? make_save_regs; // sicherungsregister deklarieren save_regs; // W, STATUS retten uns8 svrPCLATH = PCLATH; // sichern für const-zugriff uns8 val = ADRESH; // wandlung abholen GO = TRUE; // neue wandelung starten if(val) { // positive halbwelle if(int_counter) { // haben wir nen mittelwert? int_counter = 0; // interrupt_counter rücksetzen qmid /= 10; // skalierung if(qmid.high8) qmid.low8 = 255; // überlauf abfangen eff = sqrt[qmid.low8]; // sqrt(qmid * 225), qmid = 255 für 360° qmid = 0; // neue halbwellenrechnung vorbereiten } qmid += pow[val]; // quadratischer mittelwert } else { // kein signal if(int_counter < 0xFF) int_counter++; // ints zählen else if(eff) eff--; // danach: eff-wert reduzieren } T0IF = FALSE; // TMR0-Int restarten PCLATH = svrPCLATH; restore_regs_return; // W and STATUS } #include "math16.h" #include "timeloop.h" const uns8 phys_step[] = { // portsteuertabelle halbschritte (1 << OUT_A0),(1 << OUT_A0) | (1 << OUT_B0), (1 << OUT_B0),(1 << OUT_A1) | (1 << OUT_B0), (1 << OUT_A1),(1 << OUT_A1) | (1 << OUT_B1), (1 << OUT_B1),(1 << OUT_A0) | (1 << OUT_B1) }; uns8 akt_pos; // aktuelle physikalische rotorposition void one_step(int8 clockdir,uns8 time) // physikalischer schritt mit pwm { akt_pos += clockdir; // neue aktpos bestimmen if(!time) return; // nichts zu tun uns8 pio = phys_step[akt_pos & 0x07]; // pio-cash laden do { // variablen burst erzeugen GPIO = pio; // motorstränge bestromen usec(LOG_STEP_TIME / LOG_STEPS - 10); // konstante zeit GPIO = 0; // rückschlagimpuls erzeugen usec(10); // auch konstante zeit } while(--time); // stromlos verlassen } void main(void) { RP0 = 1; // erstmal alle spezialregister... #asm DW /*CALL*/ 0x2000 + /*ADRESSE*/ 0x03FF // oscal abholen #endasm OSCCAL = W; // und osc kalibration speichern OPTION = 0b00001000; // global weak-pullup, 1:1-TMR0 WPU = 0; // eingänge definieren TRISIO = (1 << AN_0) | (1 << NC_3); ANSEL = 0b01010001; // gemütliches AD: 16 TOSC & ANS0 INTCON = (1 << _GIE); // interrupts erlauben RP0 = 0; // nun die normalen register und ram ADCON0 = 0b00000001; // AD-Wandler-config GPIO = 0; // alle ausgänge auf null // das war nur init des pics. jetzt gehts erst richtig los... timeloop_init(); // timer1-config msec10(100); // etwas abwarten wg. power-up akt_pos = 400 / LOG_STEPS; // langsam nach links an den anschlag do {one_step(LEFT_STEP,100);} while(akt_pos); // mit phys. steps pwrdwn: qmid = eff = int_counter = 0; uns8 log_pos = 0; // logische position GO = TRUE; // wandler starten TMR0 = 0; // timer-init T0IF = FALSE; // interupts vorbereiten T0IE = TRUE; // und starten while(!eff); // warte auf Signal FOREVER { uns8 val = eff, pwm; // effektivwert abholen /**** log. position aktualisieren, pwm und phys-position rechnen ****/ if(val > log_pos) { // dann nach rechts drehen pwm = ++log_pos % LOG_STEPS;// immer nur ein mikroschritt if(pwm == 0) akt_pos++; // rechter halbschritt erreicht val = val - log_pos; // restfehler soll/ist berechnen } else if(val < log_pos) { // dann nach links drehen pwm = --log_pos % LOG_STEPS;// immer nur ein mikroschritt if(pwm == LOG_STEPS - 1) akt_pos--; // linker halbschritt erreicht val = log_pos - val; // restfehler soll/ist berechnen } else { // position stimmt pwm = log_pos % LOG_STEPS; // schaltverhältnis berechnen val = 0; // kein fehler vorhanden } if(!log_pos) goto pwrdwn; // power-down? /**** zeitvariable pwm-schleife für die mikroschritte ****/ if(!val) val = 1; // division durch null vermeiden val = 100 / val; // pwm einwirkungszeit if(!val) val = 1; // bei großen fehlern gehts schnell do { // pwm-Schleife one_step(RIGHT_STEP,pwm); // ein pwm-step nach rechts one_step(LEFT_STEP,LOG_STEPS - pwm);// und wieder zurück } while(--val); // ein durchlauf in LOG_STEP_TIME } } /* ENDE */