Sine control of 1/2-phase asynchronous motor with Attiny13

Status
Not open for further replies.

cicuta

Newbie level 3
Joined
Apr 29, 2016
Messages
4
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
56
Attiny13 generates 2 PWM-modulated sine waves 1..70Hz, shifted by +/-90deg, Fpwm=9375 Hz (4800000 / 256 / 2), RPM controlled by potentiometer, and not stabilized, amplitude changes from 25% at minimal RPM to 100% at maximal RPM. Start/Stop and Reverse controlled by 2 switches.

Cotroller:


Transistors VT2/VT4 and VT1/VT3 control sine 1/2 polarity.

Driver (1 full bridge):


SD pins connected to +5V.

Firmware written in AVR-GCC, controller runs at 4.8MHz, fuses: L=0x79, H=0xF9
.h

Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifndef MAIN_H_
#define MAIN_H_
 
#define F_CPU        4800000uL
#define F_PWM        (F_CPU / 256 / 8)
 
#define RPM_MIN      60
#define RPM_MAX      (4112+RPM_MIN)
 
#define ADC_MAX      255
#define ADC_INC      1
 
#define PIN_IN_MAX   20
 
#define ADDR_ADC_INC 0x3FF
 
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
 
int main();



.c

Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include "main.h"
 
// 0..Pi/2 sine table
const uint8_t sine[64] PROGMEM = {
    0,     6,  13,  19,  25,  31,  37,  44,  50,  56,  62,  68,  74,  80,  86,  92,
    98,  103, 109, 115, 120, 126, 131, 136, 142, 147, 152, 157, 162, 167, 171, 176,
    180, 185, 189, 193, 197, 201, 205, 208, 212, 215, 219, 222, 225, 228, 231, 233,
    236, 238, 240, 242, 244, 246, 247, 249, 250, 251, 252, 253, 254, 254, 255, 255
};
 
// division bits
const uint8_t divs[16] PROGMEM = {4,4,4,4+8,4+8,4+8,2,2,2+8,2+4,2+4,2+4+8,2+4+8,1,1,1};
 
volatile register uint16_t acc     asm("r2");  // phase accumulator
volatile register uint16_t inc     asm("r4");  // phase increment
volatile register uint8_t  rev     asm("r6");  // reverse flag
volatile register uint8_t  div     asm("r7");  // PWM amplitude division flags: 0=x1, 1=/2, 2=/4, 3=/8
volatile register uint8_t  tmr     asm("r8");  // event timer divisor
volatile register uint8_t  foff    asm("r9");  // on/off flag
volatile register uint8_t  frev    asm("r10"); // on/off flag
volatile register uint8_t  adc     asm("r11"); // smoothed ADC
volatile register uint8_t  adc_inc asm("r12"); // ADC increment/decrement rate
 
int main(){
    // GPIO
    DDRB   = (1<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB4);
    // ADC
    ADMUX  = (1<<ADLAR)|(1<<MUX1)|(1<<MUX0);
    ADCSRA = (1<<ADEN)|(1<<ADSC)|(1<<ADATE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
    ADCSRB = 0;
    // T0
    TCCR0A = (1<<WGM00);//|(1<<WGM01);
    TCCR0B = (1<<CS00);//(1<<CS01)
    TIMSK0 = (1<<TOIE0);
    sei();
 
    // PWM
    acc = inc = adc = 0;
    adc_inc = pgm_read_byte(ADDR_ADC_INC);
    if (adc_inc == 0xFF) adc_inc = ADC_INC;
 
    while(1){
        if (!tmr){ tmr = 255;
 
            if (foff >= (PIN_IN_MAX/2)){ // OFF state
                if (adc){
                    if (adc >= adc_inc) adc -= adc_inc;
                    else adc = 0;
                }
            } else { // ON state
                if (rev != (frev >= (PIN_IN_MAX/2))){ // reverse
                    if (adc){                         // slow down to 0 RPM
                        if (adc >= adc_inc) adc -= adc_inc;
                        else adc = 0;
                    } else rev = !rev;
                } else {                              // slow RPM up/down
                    if (adc < ADCH){
                        if (adc <= (ADC_MAX - adc_inc)) adc += adc_inc;
                        else adc = ADC_MAX;
                    } else if (adc > ADCH){
                        if (adc >= adc_inc) adc -= adc_inc;
                        else adc = 0;
                    }
                }
                // get current amplitude divisor
                div = pgm_read_byte(&divs[adc >> 4]);
            }
            // calculate current RPM
            uint16_t rpm = (((uint16_t)adc * ((RPM_MAX-RPM_MIN) >> 4)) >> 4) + RPM_MIN;
            // calculate phase increment
            inc = (!adc) ? 0 : rpm >> 3;
        }
    }
 
    return 0;
}
 
ISR(TIM0_OVF_vect){
    if (tmr) tmr--;                                       // decrement event timer
 
    if (inc == 0){                                        // phase increment == 0 ? PWMs OFF
        TCCR0A &= ~((1<<COM0A1)|(1<<COM0B1));
        if (tmr == 0){
            PORTB |= (1<<PB2);
            DDRB  &= ~(1<<PB2);
            asm volatile ("nop \n nop \n");
            if (!!(PINB & (1<<PB2))){                     // read OFF pin
                if (foff <= (PIN_IN_MAX)) foff++;
            } else if (foff) foff--;
            DDRB  |= (1<<PB2);
        }
    } else {
        // PWMs ON
        TCCR0A |= (1<<COM0A1)|(1<<COM0B1);
 
        // PWM A
        uint8_t phase = acc >> 8;                         // phase MSB: 0..255
        if (phase & 0x80){                                // set bridge polarity
            PORTB |= (1<<PB4);
            DDRB  &= ~(1<<PB4);
            asm volatile ("nop \n nop \n");
            if (!!(PINB & (1<<PB4))){                    // read REV pin
                if (frev <= (PIN_IN_MAX)) frev++;
            } else if (frev) frev--;
            DDRB  |= (1<<PB4);
        } else PORTB &= ~(1<<PB4);
        uint8_t index = phase & 0x7F;                     // index in sine table
        if (index > 63) index = (uint8_t)127 - index;     // 90..180deg ? reverse index
        uint8_t ai = pgm_read_byte(&sine[index]), ao = 0; // undivided / divided amplitude
        if (div & 1) ao = ai; else { ai >>= 1;            // division
            if (div & 2) ao += ai; ai >>= 1;
            if (div & 4) ao += ai; ai >>= 1;
            if (div & 8) ao += ai;
        }
        OCR0A = ao;                                       // set PWM A regiter
 
        // PWM B
        phase += rev ? 192 : 64;                          // phase shifted by -/+90deg
        if (phase & 0x80){                                // set bridge polarity
            PORTB |= (1<<PB2);
            DDRB  &= ~(1<<PB2);
            asm volatile ("nop \n nop \n");
            if (!!(PINB & (1<<PB2))){                     // read OFF pin
                if (foff <= (PIN_IN_MAX)) foff++;
            } else if (foff) foff--;
            DDRB  |= (1<<PB2);
        } else PORTB &= ~(1<<PB2);
        index = phase & 0x7F;                             // index in sine table
        if (index > 63) index = (uint8_t)127 - index;     // 90..180deg ? reverse index
        ai = pgm_read_byte(&sine[index]), ao = 0;         // undivided / divided amplitude
        if (div & 1) ao = ai; else { ai >>= 1;            // division
            if (div & 2) ao += ai; ai >>= 1;
            if (div & 4) ao += ai; ai >>= 1;
            if (div & 8) ao += ai;
        }
        OCR0B = ao;                                       // set PWM B register
 
        acc += inc;                                       // next phase sample
    }
}





Modeling in Proteus:





Controller PCB project in Kicad: View attachment motor_async_t13-01 ().zip
Driver PCB project: View attachment drv-bridge-ir2104x2-th-01 ().zip
Firmware: View attachment motor_async_t13-01 ().hex.zip


Assembled boards:

 
Last edited:

Status
Not open for further replies.

Similar threads

Cookies are required to use this site. You must accept them to continue using the site. Learn more…