Файл: Microcontroller based applied digital control (D. Ibrahim, 2006).pdf

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 14.06.2025

Просмотров: 3266

Скачиваний: 1

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

258 CONTROLLER REALIZATION

/********************************************************************

DIGITAL CONTROLLER

==================

This program implements a second-order digital controller module on a PIC16F877 (or equivalent) microcontroller. The microcontroller operates with a 4MHz crystal. The analog input AN0 of the microcontroller is connected to the output sensor of the plant (y). The PORT B output of the microcontroller is connected to a AD7302 type D/A converter. The WR input of the controller is controlled from port pin RC0 of the microcontroller. The sampling interval is 0.01s (10ms) and the timer interrupt service routine is used to obtain the required sampling interval.

Program : Second Order Module.C

Date : July 2005

********************************************************************/

#include <pic.h> #define DA Write RC0

float DA LSB,AD LSB,a0,a1,a2, b1,b2,M1,M2,rk,rk 1,rk 2,ek,sk,yk,uk;

/* This function initializes the A/D converter so that analog data can be received from channel AN0 of the microcontroller */

void Initialize AD(void)

{

}

/* This function initilizes the timer TMR0 so that interrupts can be generated at 10ms intervals */

void Initialize Timer(void)

{

}

/* This function reads data from the A/D converter and stores in variable yk */

void Read AD Input(void)

{

}

/* Interrupt Service Routine. The program jumps here every 10 ms */

void interrupt ISR(void)

{

Read AD Input();

/* Read A/D input */

ek = sk - yk;

/* Calculate error term */

rk = ek + M1;

yk = a0*rk + M2;

/* Calculate output */

uk = yk*DA LSB;

PORTB = uk;

/* Send to PORT B */

DA Write = 0;

/* Write to D/A converter */

DA Write = 1;

Figure 10.19 First program attempt (Continued )


MICROCONTROLLER IMPLEMENTATIONS

259

rk 2

= rk 1;

/* Update variables */

rk 1

= rk;

M1

= -b1*rk 1 - b2*rk 2;

M2

= a1*rk 1 + a2*rk 2;

T0IF = 0;

/* Re-enable timer interrupts */

}

/* Main Program. The main program initializes the variables, A/D converter, D/A converter etc. and then waits in an endless loop for timer interrupts to Occur every 10 ms */

main(void)

{

a0

= 1; a1 = 0.8;

a2 = 1.2;

b1

= 1.85;

b2 = 0.92;

M1

= 0;

M2 = 0;

rk = 0;

rk 1 = 0; rk 2 = 0;

sk = 1.0;

DA LSB = 5000.0/1024.0;

TRISA = 1;

/* RA0 (AN0) is input */

TRISB = 0;

/* PORT B is output */

TRISC = 0;

/* RC0 is output */

DA Write = 1;

/* Disable D/A converter */

Initialize AD();

/* Initialize A/D converter */

Initialize Timer();

/* Initialize timer interrupts */

ei();

/* Enable interrupts */

for(;;);

/* Wait for an interrupt */

}

Figure 10.19 (Continued )

Initialize AD. This function initializes the A/D converter so that analog data can be received from channel AN0 of the microcontroller. As described in Chapter 3, the A/D converter is initialized by first selecting the reference voltage and the output data format using the ADCON1 register, and then selecting the A/D converter clock using the ADCON0 register. Thus, channel AN0 is configured by loading 0x8E into the ADCON1 register, and 0x41 into the ADCON0 register. Thus, the Initialize AD function is programmed as follows:

/* This function initializes the A/D converter so that analog data can be received from channel AN0 of the microcontroller */

void Initialize AD(void)

{

ADCON1

=

0

×

8E;

/* Configure

AN0 for +5V reference */

ADCON0

=

0

×

41;

/* Select A/D

converter clock */

}

Read AD Input. This function starts the A/D converter and reads a sample at the end of the conversion. The conversion is started by setting the GO/DONE bit of ADCON0. The program


260 CONTROLLER REALIZATION

should then wait until the conversion is complete, which is indicated by the GO/DONE bit becoming zero. The high 2 bits of the converted data are in ADRESH, and the low 8 bits are in register ADRESL. The 10-bit converted data is extracted and stored in variable yk .

The Read AD Input function is programmed as follows:

/* This function reads data from the A/D converter and stores in variable yk */

void Read AD Input(void)

{

ADCON0 = 0 × 45; while(ADCON0 & 4) != 0); y high = ADRESH;

y low = ADRESL;

yk = 256.0*y high + y low; yk = yk*AD LSB;

}

/* Start A/D conversion */

/* Wait until conversion completes */ /* High 2 bytes of converted data */ /* Low byte of converted data */

/* Converted data in yk */ /* Sensor output in mV */

AD LSB converts the A/D value to into millivolts.

The complete program is shown in Figure 10.20.

10.5.2 Implementing First-Order Modules

In Section 10.2 we saw how a first-order module can be realized using adders, multipliers and delay elements. The first-order module is shown in Figure 10.21. The difference equations describing a first-order module were found to be

rk = ek − b1rk−1

and

uk = a0rk + a1rk−1.

If we let

M1 = −b1rk−1

and

M2 = a1rk−1,

then the difference equations for the first-order module becomes

rk = ek + M1

uk = a0rk + M2

The implementation of the first-order module is similar to the second-order module and an example is given below.


MICROCONTROLLER IMPLEMENTATIONS

261

/****************************************************************************

DIGITAL CONTROLLER

==================

This program implements a second-order digital controller module on a PIC16F877 (or equivalent) microcontroller. The microcontroller operates with a 4MHz crystal. The analog input AN0 of the microcontroller is connected to the output sensor of the plant (y). The PORT B output of the microcontroller is connected to an AD7302 type D/A converter. The WR input of the controller is controlled from port pin RC0 of the microcontroller. The sampling interval is 0.01s (10ms) and the timer interrupt service routine is used to obtain the required sampling interval.

Program : Second Order Module.C

Date : July 2005

*****************************************************************************/

#include <pic.h> #define DA Write RC0

float DA LSB,AD LSB,a0,a1,a2, b1,b2,M1,M2,rk,rk 1,rk 2,ek,sk,yk,uk; float y high,y low;

/* This function initializes the A/D converter so that analog data can be received from channel AN0 of the microcontroller */

void Initialize AD(void)

{

ADCON1

=

0x8E;

/*

Configure AN0 for +5V reference

*/

ADCON0

=

0x41;

/*

Select A/D clock and channel */

}

/* This function initilizes the timer TMR0 so that interrupts can be generated at 10ms intervals */

void Initialize Timer(void)

{

T0CS = 0;

/* Select f/4 clock for

TMR0 */

PSA = 0;

/* Select pre-scaler */

PS0 = 1;

/* Set pre-scaler to 64

*/

PS1 = 0;

/* PS2,PS1,PS0 = 101 */

PS2 = 1;

TMR0 = 100;

/* Load TMR0=100 */

T0IE = 1;

/* Enable TMR0 interrupts */

T0IF = 0;

/* Clear TMR0 interrupt flag */

*/

}

/* This function reads data from the A/D converter and stores in variable yk */

void Read AD Input(void)

{

ADCON0 = 0x45;

/*

Start A/D conversion */

While((ADCON0 & 4) != 0);

/*

Wait until conversion completes */

Figure 10.20 Complete program of the second-order controller (Continued )


262

CONTROLLER REALIZATION

y high = ADRESH;

/* High 2 bits of converted data */

y low = ADRESL;

/* Low byte of converted data */

yk = 256.0*y high + y low;

/* Converted data in yk */

yk = yk*AD LSB;

/* Sensor output in mV */

}

/* Interrupt Service Routine. The program jumps here every 10 ms */

void interrupt ISR(void)

{

TMR0 = 100;

/* Reload TMR0 */

Read AD Input();

/* Read A/D input */

ek = sk - yk;

/* Calculate error term */

rk = ek + M1;

yk = a0*rk + M2;

/* Calculate output */

uk = yk*DA LSB;

PORTB = uk;

/* Send to PORT B */

DA Write = 0;

/* Write to D/A converter */

DA Write = 1;

rk 2 = rk 1;

/* Update variables */

rk 1 = rk;

M1 = -b1*rk 1 - b2*rk 2;

M2 = a1*rk 1 + a2*rk 2;

T0IF = 0;

/* Re-enable timer interrupts */

}

/* Main Program. The main program initializes the variables, A/D converter, D/A converter etc. and then waits in an endless loop for timer interrupts to Occur every 10 ms */

main(void)

{

a0

= 1;

a1 = 0.8;

a2 = 1.2;

b1

= 1.85;

b2 = 0.92;

M1

= 0;

M2 = 0;

rk = 0;

rk 1 = 0; rk 2 = 0;

sk = 1.0;

AD LSB = 5000.0/1024.0;

DA LSB = 256.0/5000.0;

TRISA = 1;

/* RA0 (AN0) is input */

TRISB = 0;

/* PORT B is output */

TRISC = 0;

/* RC0 is output */

DA Write = 1;

/* Disable D/A converter */

Initialize AD();

/* Initialize A/D converter */

Initialize Timer();

/* Initialize timer interrupts */

ei();

/* Enable interrupts */

for(;;);

/* Wait for an interrupt */

}

Figure 10.20 (Continued )