Здрасте, в свое время тоже пытался делать СИФУ(УПП) на основе АТМег - успехом не увенчалось(нагрузка была подключена треугольником), возможно знаний не хватило или терпения, вот пара кусков кода, может поможет -
[spoiler=ATmega32u4 ArduinoIDE]
Код: Выделить всё
/* ------------*/
/* INPUTS PINS */
/* ------------*/
const byte L1_ZC_Pin = 2;
const byte L2_ZC_Pin = 3;
const byte L3_ZC_Pin = 7;
const byte L1_SCR_Pin = 4;
const byte L2_SCR_Pin = 5;
const byte L3_SCR_Pin = 6;
const byte pot_pin = A5;
const byte enable_pin = 12;
const byte lamp_pin = 11;
/* ----------*/
/* CONSTANTS */
/* ----------*/
const long iDelay = 1000; // Sampling delay/interval [µs]
const int SCR_Pulse_Width = 100; // SCR Pulse-width [µs]
const int minimumDelay = 300; // Minimum firing-delay at max power [µs]
const float smoothFactor = 0.95; // Smoothing value for fire delay [0-1].
const long iLamp = 500000; // Blink-intervall for errorlamp
/* ----------*/
/* VARIABLES */
/* ----------*/
int potValue; // Raw value of the potentiometer
int enableState; // State of the enable-switch
int pEnableState; // Previous state of the enable-switch
int enable = 1; // Variable for enabling firing
int errorLampState; // State of error-lamp
int error; // Error-state
volatile byte L1_ZC_Trg; // Variable triggered by ISR for Zero Cross
volatile byte L2_ZC_Trg; // Variable triggered by ISR for Zero Cross
volatile byte L3_ZC_Trg; // Variable triggered by ISR for Zero Cross
float frequency;
float delayValAvg; // Smoothed fire delay from measured samples
int rawFireDelay; // Fire delay mapped from potmeter value and delta time for ZC
volatile unsigned long dT_ZC_INT; // time between zero crosses
unsigned long pDelay; // Previous time a sample happened
volatile unsigned long pL1_ZC; // Previous time zero cross phase L1
volatile unsigned long pL2_ZC; // Previous time zero cross phase L2
volatile unsigned long pL3_ZC; // Previous time zero cross phase L3
unsigned long pL1_SCR; // Previous time L1 SCR was fired
unsigned long pL2_SCR; // Previous time L2 SCR was fired
unsigned long pL3_SCR; // Previous time L3 SCR was fired
unsigned long microsNow; // Time now
unsigned long pErrorLamp; // Previous state change of error-lamp
void setup() {
// Initialize IO-Pins
pinMode(L1_ZC_Pin, INPUT);
pinMode(L2_ZC_Pin, INPUT);
pinMode(L3_ZC_Pin, INPUT);
pinMode(L1_SCR_Pin, OUTPUT);
pinMode(L2_SCR_Pin, OUTPUT);
pinMode(L3_SCR_Pin, OUTPUT);
// Activate interrupt routines
attachInterrupt(digitalPinToInterrupt(L1_ZC_Pin), L1_ZC, RISING);
attachInterrupt(digitalPinToInterrupt(L2_ZC_Pin), L2_ZC, RISING);
attachInterrupt(digitalPinToInterrupt(L3_ZC_Pin), L3_ZC, RISING);
Serial.begin(9600);
}
void loop() {
while(1) {
microsNow = micros(); // Save current time
enableState = digitalRead(enable_pin); // Read pin state of enable-switch
// Sample potmeter and time for zero-cross
if ( microsNow - pDelay >= iDelay ) {
pDelay = microsNow;
potValue = analogRead(pot_pin); // Read value from potensiometer
// Map the delay time from the potentiometer
// from "minimumDelay" to "zero-cross delta time"
// Unit: µseconds
rawFireDelay = map(potValue, 1023, 0, minimumDelay, dT_ZC_INT);
// Low Pass filtering of raw values
delayValAvg = delayValAvg * smoothFactor + rawFireDelay * (1-smoothFactor);
}
// Firing-algorithm
if ( enable ) {
digitalWrite(lamp_pin, HIGH); // Turn on indicator
// Firing L1 SCR if trig'd
if ( L1_ZC_Trg && (microsNow - pL1_ZC) >= (int)delayValAvg ) {
L1_ZC_Trg = 0; // Disable bit for L1 Trigger
digitalWrite(L1_SCR_Pin, HIGH);
}
if ( L2_ZC_Trg && (microsNow - pL2_ZC) >= (int)delayValAvg ) {
L2_ZC_Trg = 0; // Disable bit for L2 Trigger
digitalWrite(L2_SCR_Pin, HIGH);
}
if ( L3_ZC_Trg && (microsNow - pL3_ZC) >= (int)delayValAvg ) {
L3_ZC_Trg = 0; // Disable bit for L3 Trigger
digitalWrite(L3_SCR_Pin, HIGH);
}
} else {
digitalWrite(lamp_pin, HIGH);
}
// Error-function. Blinking if error-bit is enabled
if ( error && (microsNow - pErrorLamp) >= iLamp ){
errorLampState = !errorLampState;
digitalWrite(lamp_pin, errorLampState);
}
}
}
// ISR for Phase L1
void L1_ZC () {
digitalWrite(L1_SCR_Pin, LOW);
L1_ZC_Trg = 1; // Enable bit for L1 Trigger
dT_ZC_INT = microsNow - pL1_ZC; // Calculate current zero cross delta time
pL1_ZC = microsNow; // Set previous zero cross to "now"
}
// ISR for Phase L2
void L2_ZC () {
digitalWrite(L2_SCR_Pin, LOW);
L2_ZC_Trg = 1; // Enable bit for L2 Trigger
pL2_ZC = microsNow; // Set previous zero cross to "now"
}
// ISR for Phase L1
void L3_ZC () {
digitalWrite(L3_SCR_Pin, LOW);
L3_ZC_Trg = 1; // Enable bit for L3 Trigger
pL3_ZC = microsNow; // Set previous zero cross to "now"
}
[/spoiler]
[spoiler=ATmega16 Ассемблер]
Код: Выделить всё
;***************************************************
;Автор
;Дата
;Версия
;Имя файла
;Для AVR:
;Тактовая частота 4МГЦ
;**************************************
; SUT =0 CKsel =1
;Выполняемые функции:
;
.device ATmega16
.Include "m16def.inc"
.List
;===================================
;Объявления:
.Def Temp =r16
.Def Gener =r17
.Def OnImpulsABC =r18
.Def CounterA =r19
.Def CounterB =r20
.Def CounterC =r21
.Def Alfa = r22
.Equ AlfaNach = 100
.Equ ConstGener = 180
.Equ OnA = 1
.Equ OnB = 2
.Equ OnC = 4
.Equ OffA = 6
.Equ OffB = 5
.Equ OffC = 3
;===================================
;Начало программы
.Cseg
.org LARGEBOOTSTART
jmp Init
.ORG OVF0AddR
Rjmp IntTimer0
.ORG OVF1AddR
Rjmp IntTimer1
.ORG OVF2AddR
Rjmp IntTimer2
.org AdccAddr
RJmp AdcDataOk
.Org ErdyAddr
RetI
.Org Int0Addr
; jmp Init
Rjmp Int_0
.Org Int1Addr
Rjmp Int_1
.Org Int2Addr
Rjmp Int_2
; НАЧАЛО ПРОЦЕДУР
;===================================
.Org $100
;инициализация чипа
;======================================================================
Init:
Ldi Temp,0
Out PortA,Temp
Ldi Temp,(1<<PA0)|(1<<PA1)|(1<<PA2) ;импульсные трансфораоры фаз А В С
Out DdrA, Temp ;направление порта A
Ldi Temp,(1<<PB2); прерывание от фазы С - INT 2
Out PortB,Temp
Ldi Temp,0
Out DdrB, Temp ;направление порта B
Ldi Temp,(1<<PC0) ;С0 - выход вкл пускаеля ON = "0"
Out PortC,Temp
Ldi Temp,(1<<PC0)
Out DdrC, Temp ;направление порта C Out24V
Ldi Temp,(1<<PD2)|(1<<PD3) ;прерывание от фазы A - INT 0 и от фазы B - INT 1
Out PortD,Temp
Ldi Temp,0
Out DdrD, Temp ;направление порта D
In Temp,Sfior
Cbr Temp,Pud
Out Sfior,Temp
Ldi Temp,(1<<WDE)|(1<<WDToe)
Ldi r17,16
Out Wdtcr,Temp ;сторожевой таймер
Out Wdtcr,r17
ldi Temp,low(RamEnd)
Out Spl,Temp ;указатель стёка
ldi Temp,high(RamEnd)
Out Sph,Temp ;указатель стёка
Ldi Temp,ConstGener
Out TcNt0,Temp ;регистр счета таймера 0
Ldi Temp,(0<<Cs02)|(0<<Cs01)|(1<<Cs00);1<<Cs00 выбрать предделитель таймера 1
Out Tccr0,Temp;
Ldi Temp,255
Out Tcnt1H,Temp;регистр счета таймера 1
Ldi Temp,100
Out Tcnt1L,Temp
Ldi Temp,(0<<Cs12)|(1<Cs11)|(1<<Cs10); выбрать предделитель таймера 1
Out Tccr1B,Temp ;регистр управления таймер 1
Ldi Temp,0
Out TcNt2,Temp ;регистр счета таймера 2
Ldi Temp,(1<<Toie0)|(1<<Toie1)|(0<<Toie2) ;прерывание таймера 0, таймера 1
Out Timsk,Temp ;регистр прерываний от таймеров
Ldi Temp,(1<<int1)|(1<<Int0)|(1<<Int2)
Out Gimsk,Temp ; рег разрешения внешних прерываний
; INT0 ПО СПАДУ INT1 ПО СПАДУ управление спящим режимом
Ldi Temp,(1<<ISC01)|(0<<Isc00)|(1<<Isc11)|(0<<Isc10) ;прерывание по Cпаду это начало полуволны
Out Mcucr,Temp ;Рег генерации внешних прерываний
Ldi Temp,(0<<ISC2);прерывание по Cпаду это начало полуволны
Out McucSr,Temp ;Рег генерации внешних прерываний
; асп привязоно к INT0
Ldi Temp,(1<<AdpS2)|(1<<AdpS1)|(0<<AdpS0)|(1<<AdIe)|(1<<AdEn)|(0<<AdSc)|(1<<ADate)
Out AdcSr,Temp
Ldi Temp,(0<<Mux3)|(1<<Mux2)|(1<<Mux1)|(0<<Mux0)|(0<<Refs1)|(1<<Refs0)|(0<<Adlar)
Out AdMux,Temp ; асп привязоно к INT0
Ldi Temp,(0<<AdTs2)|(1<<AdTs1)|(0<<AdTs0)
Out SfIor,Temp
SbI AdcSr,AdSc
Ldi Alfa,AlfaNach
Clr OnImpulsABC
Clr Zh ;счетчик для выдержки времени
CLr Zl
Clr Gener
Sei
;*********************************************************************
;*********************************************************************
;*********************************************************************
Loop:
Wdr ;сброс сторожевого таймера
;Проверяем если фаза А,В,С Проходит Через '0' что соответсвует PinD2 = 1, PinD3 = 1, PinB2 = 1
; то отключаем соответствующую фазу
Rjmp Loop
;===================================
;ПРЕРЫВАНИЯ ОТ ТАЙМЕРА 0
IntTimer0:
Push Temp
In Temp,Sreg
Push Temp
Ldi Temp,ConstGener
Out TcNt0,Temp ;регистр счета таймера 0
SbiC PinD,PD2 ;A
AnDi OnImpulsABC,OffA
SbiC PinD,PD3 ;B
AnDi OnImpulsABC,OffB
SbiC PinB,PB2 ;C
AnDi OnImpulsABC,OffC
And Gener,OnImpulsABC
Eor Gener,OnImpulsABC
Out PortA,Gener
Pop Temp
Out Sreg,Temp
Pop Temp
RetI
;===================================
;ПРЕРЫВАНИЯ ОТ ТАЙМЕРА 1
IntTimer1:
Push Temp
In Temp,Sreg
Push Temp
Ldi Temp,255
Out Tcnt1H,Temp;регистр счета таймера 1
Ldi Temp,100
Out Tcnt1L,Temp
Out PortC,OnImpulsABC
Cpi CounterA,0
BrEq TestFazeBC
Cpi CounterA,1
BrNe Desale_A
Ori OnImpulsABC,OnA
Desale_A:
Dec CounterA
TestFazeBC:
Cpi CounterB,0
BrEq TestFazeC
Cpi CounterB,1
BrNe Desale_B
Ori OnImpulsABC,OnB
Desale_B:
Dec CounterB
TestFazeC:
Cpi CounterC,0
BrEq ExitTimer1
Cpi CounterC,1
BrNe Desale_C
Ori OnImpulsABC,OnC
Desale_C:
Dec CounterC
ExitTimer1:
Pop Temp
Out Sreg,Temp
Pop Temp
RetI
;===================================
;ПРЕРЫВАНИЯ ОТ ТАЙМЕРА 2
IntTimer2:
Push Temp
In Temp,Sreg
Push Temp
Pop Temp
Out Sreg,Temp
Pop Temp
RetI
;===================================
;ПРЕРЫВАНИЯ синхронизация фаза А
Int_0:
Push Temp
In Temp,Sreg
Push Temp
Mov CounterA,Alfa
AndI OnImpulsABC,OffA
Pop Temp
Out Sreg,Temp
Pop Temp
RetI
;ПРЕРЫВАНИЯ синхронизация фаза В
Int_1:
Push Temp
In Temp,Sreg
Push Temp
Mov CounterB,Alfa
AndI OnImpulsABC,OffB
Pop Temp
Out Sreg,Temp
Pop Temp
RetI
;ПРЕРЫВАНИЯ синхронизация фаза С
Int_2:
Push Temp
In Temp,Sreg
Push Temp
Mov CounterC,Alfa
AndI OnImpulsABC,OffC
Pop Temp
Out Sreg,Temp
Pop Temp
RetI
;===================================
;ПРЕРЫВАНИЯ ОТ АСП ПО ПРЕОБРАЗОВАНИЮ
AdcDataOk:
Push Temp
In Temp,Sreg
Push Temp
In Alfa,Adcl
In Temp,Adch
Clc
Ror Temp
Ror Alfa
Ror Temp
Ror Alfa ; код АСП
Ser Temp
Eor Alfa,Temp
Pop Temp
Out Sreg,Temp
Pop Temp
RetI
[/spoiler]
Я выходил из положения следующим образом. Находил в коде строки с выходом, который указывал в блоке скоростного счётчика, и подставлял строку с номером пина, который мне нужен.
Неужели работало?
p.s. ИМХО для подобных задач нужна железка посерьезнее.