F
IRMWARE PER L
’AT
XMEGA
128
A
1
Per una miglior leggibilità del codice ed un più veloce intervento in fase di
debug, il programma è stato diviso in diversi settori, che tengono conto delle
caratteristiche delle funzioni descritte all’interno di essi. Ad ognuno di questi settori è stato attribuito un simbolo grafico (per esempio alle funzioni di routine è stato assegnato il carattere ‘=’) che, riportato appena prima della dichiarazione della funzione, permette di individuare velocemente le finalità della funzione in esame.
#include <avr/io.h> #include <avr/interrupt.h> #include <math.h> #define Tguardia 100 #define ON_UP_gc(PIN0_bm|PIN1_bm)
#define ON_DOWN_gc (PIN2_bm|PIN3_bm)
#define Vrif 4895 //(Vrif/(LSB*PartitoreVload)^2 #define ADCA_CH0_RESL _SFR_MEM8(0x0224)
//riferimento diretto agli 8 bit meno significativi del
//registro dei risultati dell'ADC, non presente di default nei header //file
#define Tsample 61
//Tsample=(tempo_di_campionamento)/(prescaler_timer) #define MAXIMUM 65535
// --- // dichiarazione variabili globali // ---
typedef enum {ASPETTAINTERRUZIONE0, ASPETTAINTERRUZIONE1} INTERNO;
INTERNO STATO;
unsigned int semiperiodo; unsigned int conduzione;
unsigned int conduzione100; unsigned int correzione; unsigned long int Veff;
unsigned long int sommatoria; unsigned int ADCres;
unsigned int delta; float Rload;
float K100; float Kp;
char RegolazionePassiva;
//flag per la regolazione passiva
// ############################ // funzioni di inizializzazione // ############################ // ########## // processore void AttivaClock32M(void) { OSC_CTRL |= OSC_RC32MEN_bm;
char controllo = (OSC_STATUS & OSC_RC32MRDY_bm); while (!controllo)
{
controllo = (OSC_STATUS & OSC_RC32MRDY_bm); //aspetta che il clock a 32 MHz si pronto
}
CCP = CCP_IOREG_gc;
//abilita la modifica del registro protetto CLK_CTRL CLK_CTRL = CLK_SCLKSEL_RC32M_gc;
//abilita il clock a 32 MHz
OSC_CTRL &= ~OSC_RC2MEN_bm; } void AbilitaInterruzioni(void) { PMIC_CTRL |= (PMIC_LOLVLEN_bm|PMIC_MEDLVLEN_bm|PMIC_HILVLEN_bm); sei(); }
// ## // AC void SettaAC(void) { ACB_AC0MUXCTRL |= (AC_MUXPOS_PIN2_gc|AC_MUXNEG_PIN3_gc); // Vmo-a --> PB2; Vmo-rif --> PB3 ACB_AC0CTRL |= (AC_HSMODE_bm|AC_HYSMODE_SMALL_gc);
//abilita il funzionamento in alta velocità e l'isteresi a 50 //mV
ACB_CTRLA |= AC_AC0OUT_bm;
//manda l'uscita del comparatore su PB7 } // #################### // Interruzioni esterne void SettaInterruzioniEsterne(void) { PORTH_INTCTRL |= PORT_INT1LVL_LO_gc; PORTH_INTCTRL |= PORT_INT0LVL_LO_gc; PORTH_PIN0CTRL |= PORT_ISC_RISING_gc;
//PH0 invia una IRQ durante la transizione 0->1 PORTH_PIN1CTRL |= PORT_ISC_FALLING_gc;
//PH1 invia una IRQ durante la transizione 1->0 PORTH_INT0MASK |= PIN0_bm; //PH0 genera INT0 PORTH_INT1MASK |= PIN1_bm; //PH1 genera INT1 } // ##### // timer void SettaTimer(void) { TCD0_INTCTRLB |= TC_CCAINTLVL_HI_gc; //alta priorità per la IRQ del timer
TCD0_CTRLB |= TC0_CCAEN_bm; //abilita il compare match TCD0_CNT = 0;
// ###### // driver void SettaDriver(void) { PORTJ_DIR |= 0x0F; PORTJ_PIN1CTRL |= PORT_INVEN_bm; //abilita l'inverter del pin PORTJ_PIN3CTRL |= PORT_INVEN_bm; //abilita l'inverter del pin
PORTJ_OUT &= ~(ON_UP_gc|ON_DOWN_gc); //genera i segnali di off_on e off_down } // ### // ADC void SettaADC(void) { ADCA_CTRLB |= ADC_RESOLUTION_8BIT_gc; //Risoluzione a 8 bit ADCA_REFCTRL |= ADC_REFSEL_AREFA_gc; //Riferimento esterno su AREFA
ADCA_PRESCALER |= ADC_PRESCALER_DIV16_gc; //Fclock = 2 MHz ADCA_CH0_CTRL |= ADC_CH_INPUTMODE_SINGLEENDED_gc; ADCA_CH0_MUXCTRL |= (ADC_CH_MUXPOS_PIN3_gc); //ingresso su PA3 ADCA_CH0_INTCTRL |= ADC_CH_INTLVL_MED_gc; //media priorità per la IRQ
} // =================== // funzioni di routine // =================== // == // AC void AttivaAC(void) { ACB_AC0CTRL |= AC_ENABLE_bm; }
// ===== // timer
void AccendiTimer(void) {
TCD0_CTRLA |= TC_CLKSEL_DIV2_gc; //fclock=16 MHz }
void ResettaTimer(void) {
semiperiodo = (unsigned int)TCD0_CNT; TCD0_CNT = 0; } // === // ADC void AccendiADC(void) { ADCA_CTRLA |= (ADC_ENABLE_bm|ADC_CH0START_bm); } void RiavviaADC(void) { ADCA_CH0_CTRL |= ADC_CH_START_bm; } void DisattivaADC(void) {
ADCA_CTRLA &= ~ADC_ENABLE_bm; } // ============= // calcolo Rload void RiferimentoConduzione(void) { conduzione100 = 829.1+semiperiodo*((4.338e-5)* semiperiodo-0.1493); } void StimaCarico(void) {
Rload = 100000/ ((float)(763+delta*(5.883+0.002217*delta))); } // ================= // fattore controllo void Kbase(void) { K100 = (float)(semiperiodo*(semiperiodo* (2.13e-8)+(2.43e-5))-.01044); } void CalcoloK(void) { Kp = K100/(0.445+Rload*((12.6e-3)-(7.157e-5)*Rload)); } // =========== // controllore void controllore(void) { RegolazionePassiva = 0; if (Veff>Vrif) {
correzione = (unsigned int)(Kp*(Veff-Vrif)); PORTD_OUT = 0b11110011; if ((conduzione-correzione)<Tguardia) { conduzione = Tguardia; } else {
conduzione = (unsigned int)(conduzione-correzione);
} }
else {
correzione = (unsigned int)(Kp*(Vrif-Veff)); PORTD_OUT = 0b11111100;
if ((conduzione+correzione)>(semiperiodo-Tguardia)) {
RegolazionePassiva = 1; }
else {
conduzione = (unsigned int)(conduzione+ correzione); } } } ////////// // MAIN // ////////// int main (void)
{
//cambio clock AttivaClock32M();
//inizializzazione led per controllo visivo PORTD_DIR |= 0xFF;
PORTD_OUT |= 0xFF;
//inizializzazione porta Q per il controllo delle //interruzioni
PORTQ_DIR |= (PIN0_bm|PIN1_bm|PIN2_bm|PIN3_bm);
//inizializzazione porte e periferiche PORTB_DIR |= PIN7_bm;
//PB7 è l'uscita del comparatore ACB0 SettaAC(); SettaInterruzioniEsterne(); SettaDriver(); SettaTimer(); SettaADC(); //inizializzazione variabili Veff = 0;
RegolazionePassiva = 0; sommatoria = 0; semiperiodo = MAXIMUM; TCD0_CCA = MAXIMUM; Kp = 0.19; K100 = 0.19; conduzione100 = Tguardia; Rload = 100; //attivazione perififeriche AttivaAC(); AccendiTimer();
//cambio di stato interno e attivazioni interruzioni a //livello globale STATO = ASPETTAINTERRUZIONE0; AbilitaInterruzioni(); while (1) { //ciclo infinito } } /////////////// // FINE MAIN // /////////////// // ++++++++++++++++++++++++++ // vettori delle interruzioni // ++++++++++++++++++++++++++
// ++++++++++++++++++++ // interruzioni esterne ISR(PORTH_INT0_vect){
PORTQ_OUT |= (1<<PIN0_bp); //controllo esecuzione switch (STATO) {
case ASPETTAINTERRUZIONE0: {
//impulsi di off_down
STATO = ASPETTAINTERRUZIONE1; ResettaTimer();
TCD0_CCA = (semiperiodo-conduzione); //memorizzazione del nuovo istante di //chiusura degli interruttori
if (RegolazionePassiva) {
PORTJ_OUT |= ON_UP_gc; AccendiADC();
TCD0_CCA = MAXIMUM; //evita la //generazione di una inutile IRQ da //parte del timer
}
Veff = (sommatoria/semiperiodo)*Tsample; //calcolo del valore efficace di Vload RiferimentoConduzione(); Kbase(); sommatoria = 0; break; } default: { break; } }
PORTQ_OUT &= ~(1<<PIN0_bp); //controllo esecuzione }
ISR(PORTH_INT1_vect) {
PORTQ_OUT |= (1<<PIN1_bp); //controllo esecuzione switch (STATO)
{
case ASPETTAINTERRUZIONE1: {
PORTJ_OUT &= ~(ON_UP_gc); STATO = ASPETTAINTERRUZIONE0; if (RegolazionePassiva)
{
} ResettaTimer(); DisattivaADC(); StimaCarico(); CalcoloK(); controllore(); break; } default: { break; } }
PORTQ_OUT &= ~(1<<PIN1_bp); //controllo esecuzione }
// +++++ // timer
ISR(TCD0_CCA_vect) {
PORTQ_OUT |= (1<<PIN2_bp); //controllo esecuzione switch (STATO) { case ASPETTAINTERRUZIONE1: { PORTJ_OUT |= ON_UP_gc; AccendiADC(); break; } case ASPETTAINTERRUZIONE0: { PORTJ_OUT |= ON_DOWN_gc; break; } default: { break; } }
PORTQ_OUT &=~(1<<PIN2_bp); //controllo esecuzione }
// ++++++++++++ // campionatore ISR(ADCA_CH0_vect)
{
PORTQ_OUT |= (1<<PIN3_bp); //controllo esecuzione switch (STATO)
{
case ASPETTAINTERRUZIONE1: {
RiavviaADC();
Sommatoria += (unsigned int)ADCA_CH0_RESL* (unsigned int)ADCA_CH0_RESL; break; } default: { break; } }
PORTQ_OUT &= ~(1<<PIN3_bp); //controllo esecuzione }