?? 復(fù)件 main.c
字號(hào):
// This file has been prepared for Doxygen automatic documentation generation.
/*! \file ********************************************************************
*
* Atmel Corporation
*
* - File : main.c
* - Compiler : IAR EWAAVR 2.28a/3.10c
*
* - Support mail : avr@atmel.com
*
* - Supported devices : ATmega48/88/168
*
* - AppNote : AVR444 - Sensorless control of three-phase brushless
* DC motors with ATmega48.
*
* - Description : Example of how to use the ATmega48 for sensorless
* control of a three phase brushless DC motor.
*
* $Revision: 1.1
* $Date: Monday, October 10, 2005 11:15:46 UTC
*****************************************************************************/
/*
編譯器:GCC
CPU:ATMEGA128
頻率:4M
編譯平臺(tái):VC++
程序流程:
主程序:
1. 端口初始化
詳見P9頁
2. 定時(shí)器初始化
TC0:升序時(shí),比較匹配發(fā)生時(shí),OC0B清零,降序比較匹配發(fā)生時(shí)置位;相位修正PWM模式
TOP值為OCR0A=200
TC1:8分頻
3. ADC初始化
參考電壓AREF;轉(zhuǎn)換結(jié)果左對齊
定時(shí)器/計(jì)數(shù)器0溢出觸發(fā)ADC自動(dòng)轉(zhuǎn)換
允許模擬比較器中斷(上升沿)
4. 換相控制數(shù)據(jù)表格
5. 首次換相輸出--共8次,然后打開TIMSK1的比較器A.
6. 全局中斷開,進(jìn)入循環(huán)
7.循環(huán)程序.
BMEF檢測的思路:
**進(jìn)入TC1的比較器A中斷,換相并復(fù)位換相定時(shí)器,設(shè)定HOLD-OFF定時(shí)器,打開TC1 的比較器B中斷;
打開TCO中斷,關(guān)閉TC1中斷,準(zhǔn)備零點(diǎn)檢測
**進(jìn)入TC0溢出中斷,取出ADC檢測的電壓值(周期中未通電相),根據(jù)上升或下降沿以及和標(biāo)定值比較判斷
是否為過零點(diǎn).
如果是過零點(diǎn),則對換相數(shù)據(jù)進(jìn)行處理,更新TC1的OCR1A,之后關(guān)閉TC0,打開TC1,轉(zhuǎn)入電流檢測通道,打開ADC轉(zhuǎn)換完成中斷.
如果不是過零點(diǎn),檢測電流過后,恢復(fù)到BMEF電壓檢測狀態(tài),打開ADC轉(zhuǎn)換完成中斷.(等待下一次TC0中斷)
*/
/*
疑問:
1.為何程序中多處出現(xiàn)清中斷標(biāo)志位命令:TIFRN.
2.看門狗的GCC中斷程序怎么寫
3.為了快速存取,在GCC中如何定義寄存器變量
IAR是這樣定義的.
__regvar __no_init volatile unsigned int filteredTimeSinceCommutation @14;
4.感覺過零點(diǎn)檢測失敗應(yīng)該恢復(fù)至定時(shí)器/計(jì)數(shù)器0溢出觸發(fā)ADC自動(dòng)轉(zhuǎn)換
*/
#include "BLDC.h"
#include <avr/io.h>
#include <avr/signal.h>
#include <avr/interrupt.h>
//! Array of power stage enable signals for each commutation step.
//驅(qū)動(dòng)功率管的信號(hào)組
unsigned char driveTable[6];
//! Array of ADC channel selections for each commutation step.
//ADC通道選擇組
unsigned char ADMUXTable[6];
//! Array holding the inter commutation delays used during startup.
unsigned int startupDelays[STARTUP_NUM_COMMUTATIONS];//8 啟動(dòng)期間的變換次數(shù)
/*! \brief Filtered commutation timer variable and speed indicator.
* This value equals half the time of one commutation step. It is filtered
* through an IIR filter, so the value stored is not the most recent measuremnt.
* The variable is stored in registers R14-R15 for quicker access.
*/
//該變量數(shù)值為變換步階時(shí)間的一半,是通過IIR得出的。所以儲(chǔ)存的值不是最新測量的數(shù)值
//為了快速存取,將這個(gè)變量被放入R14,R15寄存器中
//__regvar __no_init volatile unsigned int filteredTimeSinceCommutation @14;
volatile unsigned int filteredTimeSinceCommutation;
/*! \brief The power stage enable signals that will be output to the motor drivers
* at next commutation.
*
* This variable holds the pattern of enable signals that will be output to the
* power stage at next commutation. It is stored in register R13 for quick access.
*/
//該變量為下一時(shí)刻功率管的驅(qū)動(dòng)信號(hào)
//為了快速存取,將這個(gè)變量被放入R13寄存器中
//__regvar __no_init volatile unsigned char nextDrivePattern @13;
volatile unsigned char nextDrivePattern;
/*! \brief Polarity of the expected zero crossing.
*
* The polarity of the expected zero crossing.
* Could be eiter \ref EDGE_FALLING or \ref EDGE_RISING.
*/
//過零點(diǎn)的斜率(極性)
//為了快速存取,將這個(gè)變量被放入R12寄存器中
//__regvar __no_init volatile unsigned char zcPolarity @ 12;
volatile unsigned char zcPolarity;
/*! \brief The commutation step that starts at next commutation.
*
* The commutation step that starts at next commutation. This is used to keep
* track on where in the commutation cycle we are. Stored in register R11 for
* quick access
*/
//下一個(gè)變換步階,用于追蹤現(xiàn)在所處的位置
//為了快速存取,將這個(gè)變量被放入R11寄存器中
//__regvar __no_init volatile unsigned char nextCommutationStep @11;
volatile unsigned char nextCommutationStep;
//! ADC reading of external analog speed reference.
//外部速度比較輸入信號(hào)
volatile unsigned char speedReferenceADC;
//! ADC reading of shunt voltage.
//外部分壓輸入信號(hào)
volatile unsigned char shuntVoltageADC = 0;
//! ADC reading of the known external reference voltage.
//外部參考電壓輸入信號(hào)
volatile unsigned char referenceVoltageADC;
//! Flag that specifies whether a new external speed reference
//! and a motor speed measurement is available.
//速度量測結(jié)束標(biāo)志
volatile unsigned char speedUpdated = FALSE;
//! Flag that specifies whether a new current measurement is available.
// 電流量測結(jié)束標(biāo)志
volatile unsigned char currentUpdated = FALSE;
/*! \brief Program entry point.
*
* Main initializes all peripheral units used and calls the startup procedure.
* All commutation control from that point is done in interrupt routines.
*/
void main(void)
{
// Initialize all sub-systems.
//ResetHandler();
InitPorts();
InitTimers();
InitADC();
MakeTables();
InitAnalogComparator();
// Run startup procedure.
StartMotor();
// Turn on watchdog for stall-detection.
//WatchdogTimerEnable();
//__enable_interrupt();
sei();
for(;;)
{
PWMControl();
}
}
/*! \brief Examines the reset source and acts accordingly.
*
* This function is called early in the program to disable watchdog timer and
* determine the source of reset.
*
* Actions can be taken, based on the reset source. When the watchdog is used as
* stall protection, a stall can be detected here. It is possible to e.g. store
* a variable in EEPROM that counts the number of failed restart attempts. After a
* certain number of attempts, the motor could simply refuse to continue until
* an external action happens, indicating that the rotor lock situation could be
* fixed.
*/
//將啟動(dòng)失敗的嘗試次數(shù)寫入EEPROM,達(dá)到一定次數(shù)禁止啟動(dòng),等待處理。
/*static void ResetHandler(void)
{
__eeprom unsigned static int restartAttempts;
// Temporary variable to avoid unnecessary reading of volatile register MCUSR.
unsigned char tempMCUSR;
tempMCUSR = MCUSR;
MCUSR = tempMCUSR & ~((1 << WDRF) | (1 << BORF) | (1 << EXTRF) | (1 << PORF));
// Reset watchdog to avoid false stall detection before the motor has started.
__disable_interrupt();
__watchdog_reset();
WDTCSR |= (1 << WDCE) | (1 << WDE);
WDTCSR = 0x00;
// Examine the reset source and take action.
switch (tempMCUSR & ((1 << WDRF) | (1 << BORF) | (1 << EXTRF) | (1 << PORF)))
{
case (1 << WDRF):
restartAttempts++;
if (restartAttempts >= MAX_RESTART_ATTEMPTS)
{
// Do something here. E.g. wait for a button to be pressed.
//可在此輸入處理 程序,比如按鍵解除。
for (;;)
{
}
}
// Put watchdog reset handler here.
break;
case (1 << BORF):
//Put brownout reset handler here.
break;
case (1 << EXTRF):
restartAttempts = 0;
// Put external reset handler here.
break;
case (1 << PORF):
restartAttempts = 0;
// Put power-on reset handler here.
break;
}
}
*/
/*! \brief Initializes I/O ports.
*
* Initializes I/O ports.
*/
static void InitPorts(void)
{
// Init DRIVE_DDR for motor driving.
DRIVE_DDR = (1 << UL) | (1 << UH) | (1 << VL) | (1 << VH) | (1 << WL) | (1 << WH);
//DDRB=0b00111111;
// Init PORTD for PWM on PD5.
DDRD = (1 << PD5);
//DDRD=0b00100000;
// Disable digital input buffers on ADC channels.
//關(guān)閉ADC輸入數(shù)字緩沖器
DIDR0 = (1 << ADC4D) | (1 << ADC3D) | (1 << ADC2D) | (1 << ADC1D) | (1 << ADC0D);
//DIDR0=0b00011111;
}
/*! \brief Initializes timers (for commutation timing and PWM).
*
* This function initializes Timer/counter0 for PWM operation for motor speed control
* and Timer/counter1 for commutation timing.
*/
static void InitTimers(void)
{
// Set up Timer/counter0 for PWM, output on OCR0B, OCR0A as TOP value, prescaler = 1.
//比較匹配A不與OC0A連接
//TCCROA=0x;//升序時(shí),比較匹配發(fā)生時(shí),OC0B清零,降序比較匹配發(fā)生時(shí)置位;相位修正PWM模式。
TCCR0A = (0 << COM0A1) | (0 << COM0A0) | (1 << COM0B1) | (0 << COM0B0) | (0 << WGM01) | (1 << WGM00);
TCCR0B = (1 << WGM02) | (0 << CS02) | (0 << CS01) | (1 << CS00);//CLK 無分頻
OCR0A = PWM_TOP_VALUE;//8m/20k/2=200 設(shè)置TOP值(TOP=OCR0A)
TIFR0 = TIFR0;//意義何在?
TIMSK0 = (0 << TOIE0);//TC0溢出中斷禁止
// Set up Timer/counter1 for commutation timing, prescaler = 8.
TCCR1B = (1 << CS11) | (0 << CS10);//為何沒有把CS12加進(jìn)去?
}
/*! \brief Initializes the AD-converter.
*
* This function initializes the AD-converter and makes a reading of the external
* reference voltage.
*/
static void InitADC(void)
{
// First make a measurement of the external reference voltage.
//參考電壓AREF;轉(zhuǎn)換結(jié)果左對齊;選取電源通道5
ADMUX = ADMUX_REF_VOLTAGE;// ((0 << REFS1) | (0 << REFS0))|(1<<ADLAR)|0X05;
//ADC使能;ADC開始轉(zhuǎn)換;讀出電源電壓
ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADIF) | (ADC_PRESCALER_16);
while (ADCSRA & (1 << ADSC))
{
}
referenceVoltageADC = ADCH;//讀入VCC電壓值
// Initialize the ADC for autotriggered operation on PWM timer overflow.
//ADC使能|ADC開始轉(zhuǎn)換禁止|自動(dòng)觸發(fā)使能|清中斷標(biāo)志|ADC中斷禁止
ADCSRA = (1 << ADEN) | (0 << ADSC) | (1 << ADATE) | (1 << ADIF) | (0 << ADIE) | ADC_PRESCALER_8;
//定時(shí)器/計(jì)數(shù)器0溢出觸發(fā)ADC轉(zhuǎn)換
ADCSRB = ADC_TRIGGER_SOURCE;
}
/*! \brief Initializes the analog comparator.
*
* This function initializes the analog comparator for overcurrent detection.
*/
static void InitAnalogComparator(void)
{
#ifdef ANALOG_COMPARATOR_ENABLE
// Enable analog comparator interrupt on rising edge.
//允許模擬比較器中斷(上升沿)
ACSR = (0 << ACBG) | (1 << ACI) | (1 << ACIE) | (1 << ACIS1) | (1 << ACIS0);
#endif
}
/*! \brief Initializes the watchdog timer
*
* This function initializes the watchdog timer for stall restart.
*/
/*static void WatchdogTimerEnable(void)
{
__disable_interrupt();
__watchdog_reset();
WDTCSR |= (1 << WDCE) | (1 << WDE);
WDTCSR = (1 << WDIF) | (1 << WDIE) | (1 << WDE) | (1 << WDP2);
__enable_interrupt();
}
*/
/*! \brief Initializes arrays for motor driving and AD channel selection.
*
* This function initializes the arrays used for motor driving and AD channel
* selection that changes for each commutation step.
*/
static void MakeTables(void)
{
#if DIRECTION_OF_ROTATION == CCW//如果定義了方向?yàn)镃CW,則執(zhí)行CCW程序。
driveTable[0] = DRIVE_PATTERN_STEP1_CCW;//UY
driveTable[1] = DRIVE_PATTERN_STEP2_CCW;//UW
driveTable[2] = DRIVE_PATTERN_STEP3_CCW;//YW
driveTable[3] = DRIVE_PATTERN_STEP4_CCW;//YU
driveTable[4] = DRIVE_PATTERN_STEP5_CCW;//WY
driveTable[5] = DRIVE_PATTERN_STEP6_CCW;//WY
ADMUXTable[0] = ADMUX_W;
ADMUXTable[1] = ADMUX_V;
ADMUXTable[2] = ADMUX_U;
ADMUXTable[3] = ADMUX_W;
ADMUXTable[4] = ADMUX_V;
ADMUXTable[5] = ADMUX_U;
#else
driveTable[0] = DRIVE_PATTERN_STEP1_CW;
driveTable[1] = DRIVE_PATTERN_STEP2_CW;
driveTable[2] = DRIVE_PATTERN_STEP3_CW;
driveTable[3] = DRIVE_PATTERN_STEP4_CW;
driveTable[4] = DRIVE_PATTERN_STEP5_CW;
driveTable[5] = DRIVE_PATTERN_STEP6_CW;
ADMUXTable[0] = ADMUX_U;
ADMUXTable[1] = ADMUX_V;
ADMUXTable[2] = ADMUX_W;
ADMUXTable[3] = ADMUX_U;
ADMUXTable[4] = ADMUX_V;
ADMUXTable[5] = ADMUX_W;
#endif
startupDelays[0] = 200;//啟動(dòng)延時(shí)數(shù)組附值
startupDelays[1] = 150;
startupDelays[2] = 100;
startupDelays[3] = 80;
startupDelays[4] = 70;
startupDelays[5] = 65;
startupDelays[6] = 60;
startupDelays[7] = 55;
}
/*! \brief Executes the motor startup sequence.
*
* This function locks the motor into a known position and fires off a
* commutation sequence controlled by the Timer/counter1 overflow interrupt.
*/
static void StartMotor(void)
{
unsigned char i;
//OCR0B =130;TOP=OCR0A=200--在定時(shí)器初始化中定義
SET_PWM_COMPARE_VALUE(STARTUP_PWM_COMPARE_VALUE);
nextCommutationStep = 0;
//Preposition.
DRIVE_PORT = driveTable[nextCommutationStep];
StartupDelay(STARTUP_LOCK_DELAY);//第一次變換持續(xù)時(shí)間
nextCommutationStep++;
nextDrivePattern = driveTable[nextCommutationStep];
for (i = 0; i < STARTUP_NUM_COMMUTATIONS; i++)
{
DRIVE_PORT = nextDrivePattern;
StartupDelay(startupDelays[i]);
//參考電壓VREF,左對齊,選取零點(diǎn)檢測通道
ADMUX = ADMUXTable[nextCommutationStep];
// Use LSB of nextCommutationStep to determine zero crossing polarity.
zcPolarity = nextCommutationStep & 0x01;//大概是判斷零點(diǎn)斜率
nextCommutationStep++;
if (nextCommutationStep >= 6)
{
nextCommutationStep = 0;
}
nextDrivePattern = driveTable[nextCommutationStep];
}
// Switch to sensorless commutation.
// 啟動(dòng)結(jié)束,進(jìn)入無傳感器模式正常運(yùn)行
TCNT1 = 0;
//輸出比較匹配A中斷使能,行使換相功能,復(fù)位換相定時(shí)器,啟動(dòng)HOLD-OFF準(zhǔn)備定時(shí)比較器
TIMSK1 = (1 << OCIE1A);
// Set filteredTimeSinceCommutation to the time to the next commutation.
filteredTimeSinceCommutation = startupDelays[STARTUP_NUM_COMMUTATIONS - 1] * (STARTUP_DELAY_MULTIPLIER / 2);
//不清楚其含義
}
/*! \brief Timer/counter0 bottom overflow. Used for zero-cross detection.
*
* This interrupt service routine is called every time the up/down counting
* PWM counter reaches bottom. An ADC reading on the active channel is
* automatically triggered at the same time as this interrupt is triggered.
* This is used to detect a zero crossing.
*
* In the event of a zero crossing, the time since last commutation is stored
* and Timer/counter1 compare A is set up to trigger at the next commutation
* instant.
*/
//當(dāng)PWM計(jì)數(shù)器歸零時(shí)引起中斷,同時(shí)觸發(fā)AD轉(zhuǎn)換,零點(diǎn)檢測服務(wù)程序
SIGNAL(SIG_OVERFLOW1)
{
unsigned char temp;
// Disable ADC auto-triggering. This must be done here to avoid wrong channel being sampled on manual samples later.
//ADC自動(dòng)觸發(fā)禁止;ADC中斷禁止,開始手動(dòng)轉(zhuǎn)換
ADCSRA &= ~((1 << ADATE) | (1 << ADIE));
// Wait for auto-triggered ADC sample to complete.
while (!(ADCSRA & (1 << ADIF)))
{// 等待自動(dòng)ADC采樣結(jié)束
}
temp = ADCH;
if (((zcPolarity == EDGE_RISING) && (temp > ADC_ZC_THRESHOLD)) || ((zcPolarity == EDGE_FALLING) && (temp < ADC_ZC_THRESHOLD)))
{//上升沿且檢測點(diǎn)電壓高于設(shè)定零點(diǎn)極限電壓或處在下降沿且低于零點(diǎn)極限電壓時(shí)
unsigned int timeSinceCommutation;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -