📄 avr_vpwm.c
字号:
/*------------------------------------------------------------------------ avrstep.c - Stepper motor test. Create a custom(Virtual)PWM stepper motor controller using an AVR AT90S2313 microcontroller. The technique will require the full attention of the microprocessor, any interrupt activity would throw off the timing. We work around this by not using the any interrupts and try to configure the code to work in a known timing loop. Four other signals are used to step a stepper motor in a unipolar fashion. Logic in timer interrupt steps steppers slow for a while, then at a fast rate. Example 1 of 4 stepper winding interface elements: +Vm +12V | 300 ohm Motor Coil +5v pullup | |10k |_____________||- AVR | | ||- Micro | |/ | MC1A-------| V |\ | V Want: A tight loop which offers a decent virtual pulse width modulation for controlling the power delivered to the motor. For starters we will drive the stepper motor using a timer, but the intent would be to couple the micro to another micro which would coordinate the step timing. Secondary, we would like some way to easily bump up or down the PWM timing. Two input pins will be used to implement a bump up, bump down PWM timing. Results: TBD.Layout: ; Board socket IO; rxd |1 __ 16| +5v; txd |2 15| ; pd2 |3 14| ; pd3 |4 13| pb3,; pd4(485en) |5 12| pb2, MC1A; pd5(led) |6 11| pb1, MC1B; |7 10| pb0, MC2A; Gnd |8 9| pd6, MC2B; AVR2313 IO; /Reset |1 __ 20| Vcc; a rxd,pd0 |2 19| pb7,sck (input, bump up); b txd,pd1 |3 18| pb6,miso ; xtal2,out |4 17| pb5,mosi (input, bump down); xtal1,in |5 16| pb4 (led-main brd); c int0,pd2 |6 15| pb3,oc1 (Motor Coil1-A); int1,pd3 |7 14| pb2 (Motor Coil1-B); (485en) t0,pd4 |8 13| pb1,ain1 (Motor Coil2-A); (led) t1,pd5 |9 12| pb0,ain0 (Motor Coil2-B); Gnd |10 11| pd6,icp; ----------; Copyright 2001 Karl Bongers|------------------------------------------------------------------------*/ #include <io.h>#include <interrupt.h>#include <sig-avr.h>#define INTR_ENABLE() sei()#define INTR_DISABLE() cli()#define MISO_BITNUM 6 // ; pin18, MISO (our output)#define MISO_BIT (1 << MISO_BITNUM)#define MOSI_BITNUM 5 // ; pin17, MISO#define MOSI_BIT (1 << MOSI_BITNUM)#define SCK_BITNUM 7 // ; pin19, SCK#define SCK_BIT (1 << SCK_BITNUM)#define LED_BITNUM 4 // ; pin9, LED, pd5#define LED_BIT (1 << LED_BITNUM)// ; where DDBx=0 PORTBx=0 ---> Tri State// ; DDBx=0 PORTBx=1 ---> Will source current if ext. pulled low// ; DDBx=1 PORTBx=0 ---> push pull zero output// ; DDBx=1 PORTBx=1 ---> push pull one output#define SetLed() { sbi(PORTB, LED_BITNUM); }#define ClrLed() { cbi(PORTB, LED_BITNUM); }#define SetMc1A() { sbi(PORTB, 3); }#define ClrMc1A() { cbi(PORTB, 3); }#define SetMc1B() { sbi(PORTB, 2); }#define ClrMc1B() { cbi(PORTB, 2); }#define SetMc2A() { sbi(PORTB, 1); }#define ClrMc2A() { cbi(PORTB, 1); }#define SetMc2B() { sbi(PORTB, 0); }#define ClrMc2B() { cbi(PORTB, 0); }#define ClrMcAll() {outp(0, PORTB); }#define SetMc1Ap() {outp(8, PORTB); }#define SetMc1Bp() {outp(4, PORTB); }#define SetMc2Ap() {outp(2, PORTB); }#define SetMc2Bp() {outp(1, PORTB); }#define SetMcAll() {outp(0x0f, PORTB); }#define ClrMc1Ap() {outp(0x07, PORTB); }#define ClrMc1Bp() {outp(0x0b, PORTB); }#define ClrMc2Ap() {outp(0x0d, PORTB); }#define ClrMc2Bp() {outp(0x0e, PORTB); } // Clear MISO output to 0 volts.#define ClrMiso() { cbi(PORTB, MISO_BITNUM); }#define SetMiso() { sbi(PORTB, MISO_BITNUM); }#define GetMosi() (inp(PINB) & MOSI_BIT)#define GetSck() (inp(PINB) & SCK_BIT)#define delay_1us() delay(1)#define delay_2us() delay(4)#define delay_4us() delay(9)#define delay_8us() delay(18)#define delay_10us() delay(25)#define delay_20us() delay(50)#define delay_40us() delay(105)#define delay_60us() delay(165)#define delay_80us() delay(215)#define delay_90us() delay(248)#define delay_180us() bdelay(2)#define delay_250us() bdelay(3)#define delay_370us() bdelay(4)#define delay_600us() bdelay(6)#define delay_740us() bdelay(8)#define delay_1ms() bdelay(10)#define delay_10ms() bdelay(120)#define delay_20ms() bdelay(240)#define u08 unsigned char#define u16 unsigned short#define word unsigned short#define byte unsigned shortu08 testtimer;volatile u08 timer0_cnt;volatile u08 stepi; // stepper motor sequenceu08 time_base, max_base, pwm_base;/*---------------------------------------------------------------------------- tim0_ovf - timer0 overflow interrupt handler with timer0 prescaler = CK/1024(TCCR0=5) and our 8 bit counter overflowing every 256 ticks, we have clock_ticks = 256 * 1024 = 262144 ticks, so at 10Mhz, we interrupt every 26.21ms|----------------------------------------------------------------------------*/SIGNAL(SIG_OVERFLOW0)//void tim0_ovf(void){ ++timer0_cnt; if (timer0_cnt == 0xff) timer0_cnt = 0; // this causes the stepper motor to go fast for a while then // slow for a while. We turn the LED on and off as a visual // indicator. if ((timer0_cnt < 0x80) || ((timer0_cnt & 0x0f) == 0)) { ++stepi; if (stepi >= 4) stepi=0; }}/*---------------------------------------------------------------------------- delay -|----------------------------------------------------------------------------*/void delay(u08 delay_time){ u08 register i; // this inner loop is about 4 cycle times in length. // so if 10Mhz, delay_time=4=1us; 40=10us; 80=20us; 160=40us; 200=50us // so if 5Mhz, delay_time=4=2us; 40=20us; 80=40us; 160=80us; 200=100us for (i=0; i<delay_time; i++) { }}/*---------------------------------------------------------------------------- bdelay -|----------------------------------------------------------------------------*/void bdelay(u08 delay_time){ u08 register i; for (i=0; i<delay_time; i++) { delay(0xff); }}/*---------------------------------------------------------------------------- main -|----------------------------------------------------------------------------*/int main(void){ u08 register i; outp(LED_BIT | MISO_BIT | 0x0f, DDRB); // setup output bits(rest are inputs) outp(MOSI_BIT | SCK_BIT | 0x0f, PORTB); // set SCK & MOSI weak pullups active. outp((1<<6), DDRD); //set 0,1,2,3 to output, rest to all input outp(0, PORTD); // hi Z inputs. outp(1, TCCR1B); // timer1, control reg B(no prescaler, start clock) // do some initial blinking of the LED to show signs of life for (i=0;i<20;i++) { bdelay(250); bdelay(250); if (i & 1) {SetLed(); } else {ClrLed(); } } ClrLed(); // lets get our timer interrupts going // timer0 prescaler = CK/1024 outp(5, TCCR0); outp( (1<<TOIE0), TIMSK); // timer0 overflow interrupt enable, r/w time_base = 0; max_base = 40; // 20=100khz @ 11.592Mhz AVR2313 pwm_base = 20; INTR_ENABLE(); for (;;) { ++time_base; if (time_base >= max_base) { time_base = 0; switch(stepi) { case 0: ClrMc1Ap(); break; case 1: ClrMc2Ap(); break; case 2: ClrMc1Bp(); break; case 3: ClrMc2Bp(); break; } } else if (time_base == pwm_base) { SetMcAll(); if (GetMosi() == 0) { SetLed(); if (max_base < 255) ++max_base; else { max_base = 20; pwm_base = 2; } while (GetMosi() == 0) // debounce ; ClrLed(); } if (GetSck() == 0) { SetLed(); if (pwm_base < max_base) ++pwm_base; else pwm_base = 0; while (GetSck() == 0) // debounce ; ClrLed(); } } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -