dc motor final report

Upload: -

Post on 02-Jun-2018

220 views

Category:

Documents


0 download

TRANSCRIPT

  • 8/11/2019 Dc Motor Final Report

    1/30

    LAB 4

    DC motor speed control using pulse

    width modulation (PWM)

    Submitted by

    Vishal Bharam and Bicky Shakya

    ENGR 323

    Prof. Taikang Ning

  • 8/11/2019 Dc Motor Final Report

    2/30

    Introduction

    As we saw in the previous projects, 8051 microcontroller embedded into other systems can perform

    multiple complicated operations at the same time. 8051 microcontrollers are used in a wide spectrum of

    applications, such as in the field of automobiles, video games, microwaves and many others. In this

    laboratory, we use the 8051 microcontroller to design an embedded system that would run according to

    allowable target speed desired by the user.

    Problem Statement: This design laboratory is to help us learn and become familiar with designing and

    implementing a DC motor speed control embedded system, which involves Pulse-Width Modulation

    (PWM) and the proportional, integral and derivative (PID) controller design.

    Specific Design Goal:The design goal of this lab is to use the SilliconLab-C8051F120 kit to implement a

    PID controller that allows the user to enter the desired target speed. With feedback, the PID controller can

    make timely adjustment to the PWM to accommodate the changing shaft-load to maintain the desired

    rotating speed. The system block diagram for the system is given in fig.1.

    Fig 1: System configuration of DC motor speed control

    Following constrains are to be taken into the consideration while designing the lab:

    Allow users to easily adjust the desired motor rpm speed

    Use the PWM signal to control the DC motor speed

    Use the pushbutton to control the rotating direction

    Implement a properly working adjustable feedback controller

    Display the system information (desired speed and actual speed of the DC motor ) using a

    16x2 LCD

  • 8/11/2019 Dc Motor Final Report

    3/30

    Hardware:

    Silicon Laboratories C8051F500DK:

    For this lab, we used the SiliconLabs C8051F500DK evaluation board. The board consists of the 8051

    microcontroller but with a lot of added features. Some of the features include a 12 bit analog-to-digital

    converter, comparators, built in clock (24 MHz), 40 input/output pins and more. All in all, the

    C8051F500 is designed to be a stand-alone system on a chip solution, as claimed by the manufacturer.

    The C8051F500board was connected to the PC using the USB Debug Adapter to DEBUG_A on the

    target board with the 10-pin ribbon cable as shown in the figure 2.

    Fig.2: Hardware Setup of C8051F500using a USB DEBUG Adapter

    The C8051F500 also has two 12-bit Analog to Digital Converters (ADC). We connected one of the

    ADCs to the 1k potentiometer via P1.2 pin (A-22 on C8051F500 Female Socket). This allowed us to

    easily adjust the desired speed. Also, the PWM generated from the C8051F500 was sent through P0.2

    (A-12, CEX0) to the EN1,2 (Enable pin) on the H-Bridge. The pulses generated by the motor amplified

    from the op-amp were to be counted using the counter 0. Thus, counter 0 which was counting the pulses

    was connected to the pin P0.3 (C-11).

  • 8/11/2019 Dc Motor Final Report

    4/30

    DC Motor:

    For this lab, we used a 9V DC motor (model # ESCAP 28 D2R 11) with a built in optical encoder,

    consisting of a slotted disk and a phototransistor-LED pair. The phototransistor outputs a pulse whenever

    the slot in the disk passes by the phototransistor-LED pair. The phototransistor/LED sensor pair is

    powered by 5 volts and generates a sinusoidal signal with 80 counts per turn and 0.22V peak-to-peak.

    The DC motor itself, is rated at 9V and has a maximum continuous torque of 3.32 oz-in and maximum

    continuous current of 1.5A at 1.5 oz-in load. Under normal operating conditions, the motor drains about

    650 mA of current at 3000 rotations per minute (RPM).

    The motor came with the following six wires whose specifications are mentioned below:

    - Motor +, Motor

    These two pins connect to the outputs (1Y and 2Y) of the H-bridge chip and supply the motor

    with current from the H-bridge chip.

    - Collector

    This pin connects to a voltage source of 5V through a 1k resistor to generate a current (max of 5

    mA) for the phototransistor in the encoder,

    - Anode

    This pin connects to a voltage source of 5V through a 220k resistor, so that about 27 mA of

    current (max recommended is 30 mA) is allowed to flow through the photodiode in the encoder.

    - Emitter, Cathode

    Both of these pins were connected to ground.

    Fig.3: DC Motor with Encoder

  • 8/11/2019 Dc Motor Final Report

    5/30

    H-Bridge:

    In order to allow control of the motor through PWM, we need a motor controller chip. For this lab, we

    employed the SN754410 IC chip. This chip, like all H-Bridges, inputs PWM and direction and outputs

    high voltage power supply to the motors.

    Fig.4: Pin Configuration for the SN754410

    The chip consists of two separate H-Bridge circuits and can be used to drive up to 2 DC motors. For

    directional control, a signal from +5V was connected to pin 2 (1A) and the same +5V signal was put

    through an inverter (74LS04) and the output of the inverter was connected to pin 7 (2A). This +5V comes

    from a logic switch on the CADET board and flipping the switch will cause the motor to change its

    direction of rotation. Pin 1 (1,2 EN) was connected to the PWM output from the C8051F500board so that

    the duty cycle of the motor could be changed. Pins 3 and 6 (1Y and 2Y) were connected to the two

    terminals of the DC motor and were the actual pins that powered up the DC motor. Pins 4,5,12 and 13

    were all connected to ground. Also, pins 8 (VCC2, to power the motors) and 16 (VCC1, logic supply

    voltage) were both connected to +5V. Overall, when an enable input was high, the associated drivers

    were enabled and their outputs became active and in phase with their inputs. When the enable input was

    low, the drivers were disabled and their outputs were off and in a high-impedance state.

    As for the technical specifications, the chip can provide directional current to motors at up to 1A and from

    4.5V to 36V. It also has an operating temperature of -40oC to 85

    oC.

  • 8/11/2019 Dc Motor Final Report

    6/30

    Signal Conditioning Circuit:

    To interface the encoder from the motor with the C8051F500board, we would need a signal conditioning

    circuit that can be used to detect and remove the non-zero DC offset voltage of the signal. Analog

    comparators compare two analog voltage values where one input is typically a reference voltage and the

    other the unknown value. When the unknown voltage exceeds the reference, the output of the comparator

    switches from one binary state to another. A DC-Level detection comparator circuit was built using the

    LM741 op amp. The oscilloscope was used to measure the sine waves from the DC motor and an

    appropriate reference voltage was determined for detection.

    Parts Needed for Conditioning Circuit: LM741 (Op Amp), 1k Potentiometer to adjust the reference

    voltage or a voltage divider as shown in the figure 5.

    Fig.5: Signal Conditioning Circuit Used

    LCD Display:

    Fig.6: Regular 16x2 LCD Display

    We made use of the LCD display in this lab to display actual and target RPM of the motor. The LCD that

    we used was 16x2, meaning it could display an array of characters that was 16 columns by 2 rows (total

    32 characters) as shown in fig 6. The LCD display (CFAH1602A-YYH-JPE) had the following pins:

  • 8/11/2019 Dc Motor Final Report

    7/30

    - Vss: Ground

    -

    Vdd: Supply Voltage (5V)

    - VO: Operating voltage for LCD (for adjusting contrast of display through 10K potentiometer)

    - RS: Flag, High for Data, Low for Instruction Code, Connected to P3.0

    -

    R/W: High for Read, Low for Write, Connected to P3.1

    - E: Chip Enable, Connected to P3.2

    - DB0 => DB7: Data Bit 0 to Data Bit 7, where DB7 is also the busy flag, Connected to P2.0

    P2.7, Where busy flag is P2.7

    The operating voltage (VO) for the LCD contrast was connected to a potentiometer circuit to easily adjust

    the contrast (brightness of the pixels of the LCD). It was to be noted that if Vowas set too high, there

    would be a chance of burning out the LCD display. Also, the grounds of the LCD and the supply line (the

    CADET board) were shorted. The LCD interacting circuit that was built on the small CADET board is

    given in figure 7.

    Fig.7: Wiring Diagram for the 16x2 LCD Display

  • 8/11/2019 Dc Motor Final Report

    8/30

    Software:

    For this lab, there were many components that were to be used for the software configuration. Initially,

    we had to make sure that the LCD display was working properly. After confirming with working LCD

    display, PCA initialization to implement PWM generation, implementation of analog to digital

    conversion and pulse-counting using a timer as a counter was configured. Finally, to maintain the same

    motor speed when load varies, a stable PID feedback control system was designed and employed to

    provide acceptable speed control. While configuring the software, the programs for each part were written

    in small step and next part was approached only after making sure that previous part was working

    perfectly. The whole software configuration for the system was programmed using C8051F500board, in

    C. The details of each part in given below:

    LCD Operation

    The LCD consists of two registersthe Instruction Register (IR), to which commands are sent to control

    the LCD actions and Data Register (DR), where the display data is sent. The IR can store instructional

    codes such as display clear and cursor shift, and address information for display data RAM (DDRAM)

    and character generator RAM (CGRAM). Also, the IR can be programmed from the 8051.

    Table 1: Register Selection

    RS R/W Enable Operation

    0 0 H,H -> L IR- write as internal operation

    (Display clear, etc.)

    0 1 H Read Busy Flag (DB7) and

    Address Counter (DB0-DB6)

    1 0 H,H -> L DR => write as internal

    operation DR to DDRAM or

    CG RAM

    1 1 H DR-read as internal operation

    (DDRAM or CGRAM to DR)

    The IR is chosen by setting the Register Select (RS) to 0 and DR with 1. The LCD is also equipped

    with a busy flag (DB7). When it is 1, the LCD is in internal operation mode and the next instruction will

    not be accepted. As per the Register selection table, the busy flag is output to DB7 when RS = 0 and R/W

    = 1. The next instruction cannot be written unless the busy flag is set to 0.

  • 8/11/2019 Dc Motor Final Report

    9/30

    In our program, a function, LCD_Init() was created. In this function, the busy flag was constantly checked

    to ensure that the commands are being accepted by the LCD.

    Fig. 8: LCD Busy_flag configuration

    Within the LCD_Init() function, a sequence of six steps were performed one after the other. In each step,

    the enable was set to high and then to low because the internal operations work only when the enable is

    high and there is a high to low transition. The six steps of initialization and the pattern of data bus lines

    and select bits are shown below in the table.

    Table 2: Instructions and Their Corresponding Codes

    DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 RS R/W E

    ClearDisplay

    0 0 0 0 0 0 0 1 0 0 1->0

    FunctionSet

    0 0 1 1 1 1 0 0 0 0 1->0

    DisplayOff

    0 0 0 0 1 0 0 0 0 0 1->0

    Entry

    Mode

    0 0 0 0 0 1 1 0 0 0 1->0

    DisplayOn

    0 0 0 1 1 1 1 1 0 0 1->0

    ReturnHome

    0 0 0 0 0 0 1 0 0 0 1->0

    For the checking part, another function,

    LCD_busy_flag() was created, which

    selected the IR and set the R/W and LCD

    Enable to high to read the busy flag from

    the IR. The busy flag at line DB7 was read

    from P2.7 and returned as an integer

    (configured as input).

  • 8/11/2019 Dc Motor Final Report

    10/30

    It is to be noted that before the instructions are executed, the status of the busy flag should be checked so

    that it is clear. Given below is the initialization code:

    /* --------------------------------------------------

    LCD_Init_ISR

    setup Timer_0 overflow interrupt service routine

    to perform LCD initialization Function

    -------------------------------------------------

    */

    void LCD_Init_ISR(void) interrupt 1

    {char SFRPAGE_SAVE = SFRPAGE;

    EA = 0;

    TH0 = RTH0;

    TL0 = RTL0;

    EA = 1;

    if(LCD_init_flag == 0)

    {

    msec_count++;SFRPAGE = CONFIG_PAGE;

    switch(msec_count)

    {

    case 5:case 10:case 11:case 12:

    //function set four times

    LCD_en = 1;

    RS = 0;

    RW = 0;

    P2 = 0x3F;

    //Pulse enable

    LCD_en = 0;

    break;

    case 13:

    //send display off

    LCD_en = 1;

    RS = 0;

    RW = 0;

    P2 = 0x08;

    //pulse enable

    LCD_en = 0;

    break;

    case 14:

    //send display clearLCD_en = 1;

    RS = 0;

    RW = 0;

    P2 = 0x01;

    //pulse enable

    LCD_en = 0;

    break;

    case 16:

    //send entry mode set

    LCD_en = 1;

    RS = 0;

    RW = 0;

    P2 = 0x06;

    // pulse enable

    LCD_en = 0;

    break;

    case 18:

    //send display ON

    LCD_en = 1;

    RS = 0;

    RW = 0;

    P2 = 0x0F;

    //pulse enable

    LCD_en = 0;

    //set the LCD_init_flag

    LCD_init_flag = 1;

    break;

    default:

    break;

    } //end of switch-case

    } //end of if

    if(LCD_init_flag == 1){

    SFRPAGE = ACTIVE_PAGE;

    TR0 = 0; //disable Timer_0 overflow interrupt, LCD is

    initailized

    ET0 = 0;

    } //end of if

    SFRPAGE = SFRPAGE_SAVE;

    } //LCD_Init()

  • 8/11/2019 Dc Motor Final Report

    11/30

    Fig. 9: LCD initialization Function using timer 0 overflow interrupt

    After the initialization was complete, the LCD needed to be setup for writing. For our application

    purposes, we were only writing to the data lines. For displaying, the LCD needs to be refreshed

    constantly to update the display. The refreshing was achieved by using Timer 1 Overflow

    Interrupt and the advised refresh rate was 50Hz. We also needed to specify the cursor to move to

    the next line when the 16th

    character was reached in a row. When the 32nd

    character was

    displayed, the LCD was instructed to return to the home position. The position of this cursor was

    monitored using a LCD_pointer variable.

    Fig.10: The LCD Display Refresh Function

    For the actual display of the text, we implemented the following numeric to character data type

    function:

  • 8/11/2019 Dc Motor Final Report

    12/30

    Fig. 11: Numeric to Character Data Type Function

    As we can see above in figure 11, the TARGET RPM and ACTUAL in RPM were assigned as

    four bit signed decimal numbers. In the part of the program with those numbers, we can see the

    conversion of numeric data type to character data type.

  • 8/11/2019 Dc Motor Final Report

    13/30

    PWM Generation using Programmable CounterArray (PCA)

    PWN is used to control the duty cycle of a square wave, varying between 0% to 100%, and provides the

    necessary flexibility for many application. In this lab, the SiliconLab-C8051F500is being employed to

    generate the appropriate PWM signal to control motor rotation speed. The PWM output is connected

    directly to an intelligent PWM control H-Bridge chip that will translate the duty cycle information to

    drive the DC motor accordingly.

    In order to this, C8051F500provides a Programmable Counter Array (PCA0) consisting of a dedicated

    16-bit counter/timer and six 16-bit capture/compare modules. Each capture/compare module has its own

    associated I/O line (CEXn), which is routed through the crossbar to port I/O when enabled. For this lab,

    we were using capture/compare module 0, where CEX0 was used to generate PWM pulses, while PCA0

    timer was driven by the system clock divided by 12. The mode of the PWM was set to 8-bit pulses. Thus,

    when the value in the low byte of the PCA counter/timer (PCA0L) was equal to the value in PCA0CPL0,

    the PWM signal switches to high and the output on the CEX0 pin will be set. When the count value in

    PCA0L overflows, the CEX0 output will be reset. This process will repeat to generate PWM signal with

    intended duty cycle. The duty cycle of PWM signal was modulated by changing the value stored in

    PCA0CPL0 register as shown:

    Setting ECOM0 and PWM0 bits in the PCA0CPM0 register, and setting CLSEL bits in register PCA0PWM to

    00b, 8-Bit Pulse Width Modulator mode was enabled using configuration wizard as shown in fig. 12.

    Fig. 12: PCA initialization to generate PWM

    Initially, the internal oscillator frequency was set at 750000 and we were still able to generate the PWM

    pulses. After measuring the frequency of the PWM signal in oscilloscope, we found it to be ~245 Hz.

    However, according to Prof. Nings instructions, the H-bridge works best at PWM signal frequency of 1

    KHz. Thus, internal oscillator frequency was set to 3 MHz using configuration wizard.

  • 8/11/2019 Dc Motor Final Report

    14/30

    Fig.13: Oscillator Initialization with SYSCLK of 3MHz

    As soon as clock was changed from the 0.75MHz to 3 MHz, the LCD display started acting weird as

    expected as it was not getting enough time to settle down. Thus, we increased the setting time for the

    LCD display refreshing from 25 TIMER-1 overflow interrupts to 100 TIMER-1 overflow interrupts, as

    the clock was also changed by a factor of 4.

    Hence, in the LCD display refresh function, this part :

    was changed to:

    However, it was still unable to get to the best condition. Thus, we decided to create same delay in the

    LCD Busy_flag function, (fig, 14) which did the trick for us to bring the LCD was back to normal.

    Fig. 14: Adding a delay to let LED settle before going to to original position

  • 8/11/2019 Dc Motor Final Report

    15/30

    Analog-Digital Conversion:

    As specified in the design contains, the most important design goal of this lab was to Allow the users to

    easily adjust the desired motor rpm speed. In order to do so, A/D converter (ADC0 for 12-bit A/D) on the

    Silicon-Lab C8051F500 microcontroller was used. The ADC0 on the C8051F50x/F51x consists of an

    analog multiplexer (AMUX0) with 35/28 total input selections and a 200 kilo-samples-per-second (ksps),

    12-bit successive-approximation-register (SAR) ADC with integrated track-and-hold, programmable

    window detector, programmable attenuation (1:2), and hardware accumulator.

    In order to initiate the conversion, we chose TIMER 2 overflow interrupt as repeated A/D conversions

    can be achieved in fixed intervals. Fig. 12 shows the configuration of TIMER 2 interrupt:

    Fig 12: Timer 2 overflow interrupt used to initiate A/D conversion

    The conversion mode is determined by the programmed states of the ADC0 bits (AD0CM1, AD0CM0) in

    bit-adorable SFR ADC0CN. ADC0CNwas set to 11, representing the conversion initialization to TIMER

    2 overflow interrupt. AD0BUSY bit in the ADC0CN SFR was set to 1 during conversion and cleared

    when conversion complete. The falling edge of the AD0BUSY bit triggers an interrupt and sets the

    ADOINT interrupt flag. The converted data then become available in the ADC0H and ADC0L. Output in

    our case is right-justified in our case, so the most significant 8 bits of the converted data would reside in

    ADC0L and ADC0H would carry the least significant 4 bits.

    While configuring ADC0, the example program from the Silicon-Lab library proved to be very helpful.

    ADC0 on the C8051F500 implements a selectable gain adjustment option because input sources have

    small part-to-part variations that must be accounted for to achieve accurate results and the programmable

    gain value could be used as a calibration value to eliminate these part-to-part variations. Thus, gain was

    initialized to account for a 5V input and Vref was set to ground. The gain value was calculated using the

    following formula, which is represented as a 12-bit frame ranging from 0x000 to 0Xfff.

  • 8/11/2019 Dc Motor Final Report

    16/30

    The gain enable bit [ADC0CF.0] was set and ADC0H were loaded with ADC0GNH, ADC0GNL, or

    ADC0GNA addresses. As mentioned earlier, ADC0L was then loaded with the upper bytes GAIN value,

    which is 0x6C in this case. However, an ADC conversion should not be performed while the GAINEN bit is set .

    Thus the gain bit is set to 0 after proper configuration. ADC0 is then disabled and normal tracking conversion is triggered on

    TIMER 2 overflow interrupt by setting ADC0CN to 0x03. P1.2 is used as the analog input pin and ADC0 conversion complete

    interrupt was enabled by setting EIE1 to 0x04 and AD0EN to 1. The detailed code is given in fig. 13.

    Fig. 13: Analog-digital conversion configuration using A/D converter

    Pulse-Counting of actual RPM signal:

  • 8/11/2019 Dc Motor Final Report

    17/30

    In order to find the actual RPM of running DC motor, the pulse counts per second is required to

    be measured. In order to measure the pulses, we needed to use a timer that can be used as a counter.

    However, as described already, all four timers were already being used. Then we realized that we are not

    using TIMER 0 after the LCD display is initialized once. Thus, we decided use TIMER 0 after the LCD

    display initialization was completed to count the pulses generated. In order to measure the current RPM

    of the motor, we configured Timer 0 as an 8 bit auto-reload counter. In the configuration wizard, we set

    T0 to P0.3 in order to record the number of pulses. The pulses, as explained earlier, could not be directly

    used by the C8051F120, therefore we had to send the signal through the comparator circuit. The output of

    the comparator circuit was then sent to the C8051F120 in order to count the pulses. While loading the

    TIMER 2 overflow values, we had to take care of internal oscillator frequency. As mentioned earlier, the

    internal oscillator clock used in this system was 3MHz. Thus, when we were loading the values for the

    auto-reload mode, we had to make sure that they were properly calculated. The TIMER-2 was configured

    as SYSCLK/12, so I took 4 s (1/(3000000/12)) for one machine cycle. Thus, when we trying to measure

    pulse-counts per 100 ms, actual delay was supposed to be (100 ms/4) = 25 ms. Hence, (65535-25000 =

    40535) 10= (9E57)16 was loaded in the TIMER-2 registers as shown in the fig. 14.

    else if(LCD_init_flag == 1)

    {

    EA = 0;

    TMR3CN = 0x04; //Start running Timer 3

    TMOD = 0x15; //Timer_0 set as event counter and Timer_1 still in 16-bit mode

    TH0 = 0x00; //Timer 0 high and low bytes set

    TL0 = 0x00;

    ET0 = 0; //Disable Timer 0 interrupt, Timer 0 will now be used to count pulses

    EIE1 |= 0x40; //Timer 3 interrupt enabled and used to record pulses counted by Timer0

    TMR3L= 0x57; //Timer 3 high and low bytes set to record pulse every 100 msec

    TMR3H = 0x9E;

    TMR3RLL = 0x57; //Timer 3 auto reload values set

    TMR3RLH = 0x9E;

    EA = 1;}

    Fig. 14: Configuration of TIMER 0 and TIMER 2 overflow interrupt

  • 8/11/2019 Dc Motor Final Report

    18/30

    After configuring TIMER 0 as a counter to count pulses and TIMER 3 overflow interrupt to record the

    counted pulses, which is equal to (total_pulse_count = TH0*256 + TL0). The total_pulse_count is then

    used to measure the actual speed of the running DC motor in rpm using the following formula.

    where total_pulse_count is in x-msec.

    As suggested by prof. Ning, mechanical devices like DC motor is not fast enough to adjust the speed in

    very small time frame like 100 msec. Thus, we decided to record the pulses after 500 ms or second. A

    small counter was used to count the 100 ms delay set by TIMER 3 overflow interrupt and after such 5

    interrupt, total_pulses_counts were recorded using the above equation.

    However, after trying multiple combinations of TIMER-3 overflow delay, we were not getting the resultexpected. Then we decided to measure the frequency of the pulses recorded and we noticed the counter in

    the TIMER-3 overflow interrupt subroutine was not going through. After going through the manual, we

    got to know that in TMR3CN (Timer 3 control) register, bit TF3H and bit TF3L are not automatically

    cleared by the hardware (fig. 15). Therefore, when first TIMER-3 overflow happened, the timer was not

    going back to reset and was not running again. In order to do so, we had to clear TF3H and TF3L to start

    the timer again. Hence, the TIMER-3 was enabled after each overflow interrupt.

    Fig. 15: TMR3CN: Timer 3 Control

  • 8/11/2019 Dc Motor Final Report

    19/30

    After enabling TIMER-3 again in TIMER-3 overflow interrupt subroutine, we were getting the results

    expected. However, though we were getting better result, the values were still fluctuating so much. Thus,

    we decided to record the pulses after 1000ms or 1 second. Therefore, after 10 TIMER-2 overflow

    interrupts (each with 100ms), total_pulses_counts were recorded and used to find current speed of motor

    in rpm as shown in following equation. Fig. 16 gives details about TIMER-3 overflow interrupt

    subroutine.

    ----------------------------------------------------------

    Timer _Overflow_ISR

    The Routine will count the number of pulses. The number

    of pulses comes from TL0 and TH0 because Timer 0 was set to

    record pulses

    ----------------------------------------------------------

    */

    void Timer3_Overflow_ISR(void) interrupt 13 //Interrupts every 100msec (auto reload)

    {

    TMR3CN = 0x04; //Timer-3 is enabled again

    ISRT3_count++;

    if (ISRT3_count == 10) //refreshes actual_rpm every 100*10 = 1000 msec

    {

    pulse_count = TH0*256 + TL0; // the number of pulses

    TH0 = 0x00; //Timer 0 high and low bytes reset

    TL0 = 0x00;

    //Routine convert pulses into RPM here

    //rpm = pulse_count(1/1000msec)(1000msec/1sec)(60sec/1min)(1turn/80counts)

    actual_rpm = pulse_count * 0.75;

    ISRT3_count = 0;

    target_rpm = ADC0;

    FEEDBACK_Init();

    }}

    Fig. 16: Timer -3 Overflow Interrupt Service Routine

  • 8/11/2019 Dc Motor Final Report

    20/30

    After configuring the LCD display, PWM generation using Programmable Counter Array (PCA), desired

    speed target using A/D converter and calculating the actual rpm, everything was placed together to check

    the whole embedded system. We were able to change the desired target speed and thus, the actual speed

    of the motor. The change in the target speed and actual speed was successfully displaced on the LCD

    display. However, there was no proper correlation between the desired target speed and actual speed. In

    order to adjust the PWM signal to achieve a desired target speed a feedback controller was necessary.

    Thus, feedback control was designed using the difference between the desired target speed and the actual

    speed of the motor. Thus, when the desired target speed was different than the actual speed, duty cycle of

    the PWM signal was adjusted accordingly by the controller to maintain the desired speed. When target

    speed was higher than actual speed of the motor, duty cycle of PWM signal was increased accordingly by

    decreasing the value of PCA0CPH0 in programmable counter array (PCA) and vice versa.

    /*--------------------------------------------------------Feedback

    --------------------------------------------------------*/void FEEDBACK_Init(void)

    { rpm_change = target_rpm - actual_rpm

    if(rpm_change > 0 && PCA0CPH0 > 0x05)

    {PCA0CPH0 = PCA0CPH0 - 0x01;}

    else if(rpm_change < 0 && PCA0CPH0

  • 8/11/2019 Dc Motor Final Report

    21/30

    /*--------------------------------------------------------Feedback Control

    --------------------------------------------------------*/void FEEDBACK_Init(void)

    {rpm_change = target_rpm - actual_rpm;

    //If desired target speed is higher than actual speed of motor if duty cycle is less than 100%

    if((rpm_change>0) && (PCA0CPH0> 0x00))

    {

    if((rpm_change>=1200))

    { PCA0CPH0 = PCA0CPH0 - 0x05;}

    else if((rpm_change>=1000) && (rpm_change=800) && (rpm_change=500) && (rpm_change=300) && (rpm_change=100) && (rpm_change=50) && (rpm_change10) && (rpm_change0) && (rpm_change

  • 8/11/2019 Dc Motor Final Report

    22/30

    Implementation

    As mentioned already, there were many components that were to be employed for the hardware as well as

    software configuration. Thus, while configuring the whole system, each part was configured in small step

    and next part was approached only after making sure that previous part was working perfectly. Initially,

    given LCD display was properly wired using the wiring diagram given in fig.7. It was a good advantage

    for us that an almost working code for the LCD was provided. Modifying the code a bit, we were able to

    make our LCD display desired output. While I was working on the programming, Bicky finished building

    the circuitry consisting of H-bridge, DC motor with optical encoder, comparator, inverter and op-amp.

    With the LCD screen working with one set of code, we referenced the PWM example code given in the

    lab handout. This helped us to set up PCA and to generate varying duty cycles of the PWM. Before we

    hooked up the H-Bridge, we connected the PCA directly to the Port 0.2 (CEX0), which was configured

    using the configuration wizard. In order to obtain a stable PWN signal, we needed to measure the actual

    speed of the DC motor. Thus, timer 0 was configured as 16-bit counter while timer-3 overflow interrupt

    was used for count the pulses measured by counter 0. However, the pulses we obtained from the PWM

    were not being counted by Timer 0. To increase the current of the PWM pulses, we passed the output of

    the comparator through a buffer. This solved the problem and enabled the timer to count the pulses.

    Working with the PWM code, we then passed the PWM to the input of the H-Bridge to power the motor.

    When we connected the pulses from the motor to the oscilloscope, we were able to get expected signal.

    The desired rpm speed was then set using the Analog to Digital Converter with help of example code

    given in the SILABs documentation. We used GND as reference voltage for VREF (P0.0). Using the

    value of total-pulses obtained using counter 0 and TIMER-3 overflow interrupt, actual rotating spped was

    found. Using actual and target speed, feedback control loop was finally employed to adjust actual speed

    of the motor accordingly to the desired target speed. Multiple tests were performed to design the best

    possible feedback control system.

    When we thought we were almost done one week ago, we decided to check the progress with professor.

    Then we realized that the H-bridge works best with the oscillator frequency that leads to the PWM signal

    frequency of 1KHz. Hence, we had to change our clock from 0.75 MHz to 3 Mhz. This change brought us

    back to the same place where we started. Nothing including LCD display, actual-rpm courting or

    feedback-control was working. Three-four days were spent without any significant progress. However,

    things started to be on track after we figured out the timing conflict with the delays in the timer overflow

    interrupt due to the change in oscillator. After multiple tests with different values of almost every single

    variable, the DC motor speed control embedded system was finalized.

  • 8/11/2019 Dc Motor Final Report

    23/30

    Results and Discussion

    As per the design goal of the lab, we were able to construct DC-motor based embedded system, where

    PID feedback controller was designed that would allow the user to enter the desired target speed and

    timely adjustment to the PWM would be made to accommodate the changing shaft-load to maintain the

    desired rotating speed. As mentioned above in the fig.17, while demonstrating the lab to professor, the

    feedback control was designed to slowly adjust the actual rotating speed of the motor according to desired

    target speed. However, after the professors concern, we implemented the feedback using the code given

    in fig.18, which was able to make quick adjustment in the actual rotating speed according to the target

    speed when load was applied.

    This lab opened the doors for what we can do with the 8051-based microcontrollers. While learning about

    the Automatic Control System (ACS), I never thought that I could even use it literally. However, this lab

    demonstrated practical ways of implementing closed-loop feedback systems. Furthermore, this lab also

    helped a lot to improve our command on C/C++ language.

  • 8/11/2019 Dc Motor Final Report

    24/30

    //____________________________________________________________________//LAB 4: DC motor control using PWM and PID Controller//Vishal Bharam//Bicky Shakya//Engr 323: MicroProcessor Systems//Professor: Dr. Taikang Ning//____________________________________________________________________/*This program is written to control the speed of the DC motor based on the feedbackfrom the C8051F500 microcontroller. First, the ADC converts the signal from the

    potentiometer. Due to various reasons, the desired rpm speed and the current rpm speedmay not be equal. Therefore the program counts the number of pulses within a certaintime period.Then the current rpm speed of the DC motor is calculated. The program takes thedifference between the two values and adjusts the duty cycle of the PWM signal accordingly.The current rpm speed as wells as the desired rpm speed will be displayed on the LCD.*/

    //-----------------------------------------------------------------------------// Includes//-----------------------------------------------------------------------------#include "compiler_defs.h"#include "C8051F500_defs.h"#include

    //-----------------------------------------------------------------------------// Function Prototypes//-----------------------------------------------------------------------------void Oscillator_Init(void);void Port_Init(void);void Timer_Init(void);void LCD_Init_ISR(void);void Display_String(void);

    void ADC_Init(void);void PCA_Init(void);void TIMER2_Init(void);void DISPLAY_ISR(void);int LCD_busy_flag (void);void FEEDBACK_Init(void);void AD0_ISR(void);void Timer3_Overflow_ISR(void);

    //-----------------------------------------------------------------------------// Global Constants//-----------------------------------------------------------------------------#define SYSCLK 3000000sbit LED = P1^6;sbit RS = P3^0;sbit RW = P3^1;sbit LCD_en = P3^2;sbit DB7 = P2^7;

    //-----------------------------------------------------------------------------// Global Variables//-----------------------------------------------------------------------------char xdata LCD_display[32]; //hold the data to be shown on an LCDunsigned char LCD_pointer = 0;char indicator;char LCD_init_flag = 0;

    short msec_count = 0; //each delay is about 1 msecshort RTH0, RTL0, RTH1, RTL1; //reload values for Timer_0 and Timer_1short i, k;short target_rpm = 500;short actual_rpm = 0;short pulse_count = 0;short count = 0;short ISRT3_count = 0;short rpm_change;

    //-----------------------------------------------------------------------------// main() Routine//-----------------------------------------------------------------------------

    void main(void) //calling functions here{

    PCA0MD &= ~0x40; // Disable the watchdog timerLCD_Init_ISR();Oscillator_Init();Port_Init();Timer_Init();PCA_Init();ADC_Init();TIMER2_Init();DISPLAY_ISR();FEEDBACK_Init();Display_String();

    IP= 0x2A; //timer 1,2,3 prioritizedwhile(1);

    }

  • 8/11/2019 Dc Motor Final Report

    25/30

    //-----------------------------------------------------------------------------// Initialization Subroutines//-----------------------------------------------------------------------------

    /*--------------------------------Oscillator_InitThis routine initializes the system clock to usethe precision internal oscillator as its clocksource

    ---------------------------------------------------*/

    void Oscillator_Init(void){

    SFRPAGE = CONFIG_PAGE;

    OSCICN = 0xC4; //Select the internal oscillator as system clock 12.25 MHzCLKSEL = 0x00; //Select the internal oscillator as SYSCLK source

    SFRPAGE = ACTIVE_PAGE;}

    /*-------------------------------------------------------PORT_Init()

    -------------------------------------------------------*/

    void Port_Init(void){

    char SFRPAGE_SAVE = SFRPAGE;SFRPAGE = CONFIG_PAGE;

    P0SKIP |= 0x03; // Skip P0.0 (VREF)P0MDIN = 0xFC;P0MDOUT = 0x0C; // Set External Timer 0 (P0.0) to push-pullXBR1= 0x44; //CEX0 at port0.2, timer0 pin at p0.1P1SKIP |= 0x04; // Skip P1.2 (ADC input)P1MDIN &= ~0x04; // Set P1.2 as an analog inputP1MDOUT |= 0x08; //P1.6(LED)P3MDOUT = 0x07; //LCD-en(P6.2) RS(P6.0) and RW(P6.1) are setP2MDOUT = 0xFF; //DB0-DB7 are set push-pullXBR2 = 0x40; //Enable Crossbar

    SFRPAGE = SFRPAGE_SAVE;}

    //-----------------------------------------------------------------------------// TIMER2_Init//-----------------------------------------------------------------------------//// Return Value: None// Parameters: None//// Configure Timer2 to 16-bit auto-reload and generate an interrupt at 100uS// intervals. Timer 2 overflow automatically triggers ADC0 conversion.////-----------------------------------------------------------------------------

    void TIMER2_Init (void){

    U8 SFRPAGE_save = SFRPAGE;SFRPAGE = ACTIVE_PAGE;TMR2CN = 0x00; // Stop Timer2; Clear TF2;

    // use SYSCLK as timebase, 16-bit auto-reloadTMR2RL = 65535 - (SYSCLK / 10000); // Init reload value for 10uSTMR2 = 0xFFFF; // Set to reload immediatelyTR2 = 1; // Start Timer2

    SFRPAGE = SFRPAGE_save;}//-----------------------------------------------------------------------------//-----------------------------------------------------------------------------// ADC_Init//-----------------------------------------------------------------------------//// Return Value: None// Parameters: None//// Configures ADC0 to make single-ended analog measurements on pin P1.2// Also enabled the gain and the voltage reference////-----------------------------------------------------------------------------

    void ADC_Init(){

    U8 SFRPAGE_save = SFRPAGE;SFRPAGE = ACTIVE_PAGE;

    // Initialize the Gain to account for a 5V input and 2.25 VREF// Solve the equation provided in Section 9.3.1 of the Datasheet

  • 8/11/2019 Dc Motor Final Report

    26/30

    // The 5V input is scaled by a factor of 0.44 so that the maximum input// voltage seen by the pin is 2.2V

    // 0.44 = (GAIN/4096) + GAINADD * (1/64)

    // Set GAIN to 0x6CA and GAINADD to 1// GAIN = is the 12-bit word formed by ADC0GNH[7:0] ADC0GNL[7:4]// GAINADD is bit ADC0GNA.0

    ADC0CF |= 0x01; // Set GAINEN = 1ADC0H = 0x04; // Load the ADC0GNH address

    ADC0L = 0x6C; // Load the upper byte of 0x6CA to// ADC0GNHADC0H = 0x07; // Load the ADC0GNL addressADC0L = 0xA0; // Load the lower nibble of 0x6CA to

    // ADC0GNLADC0H = 0x08; // Load the ADC0GNA addressADC0L = 0x01; // Set the GAINADD bitADC0CF &= ~0x01; // Set GAINEN = 0

    ADC0CN = 0x03; // ADC0 disabled, normal tracking,// conversion triggered on TMR2 overflow// Output is right-justified

    REF0CN = 0x33; // Enable on-chip VREF and buffer// Set voltage reference to GND

    ADC0MX = 0x0A; // Set ADC input to P1.2

    ADC0CF = ((SYSCLK / 3000000) - 1)

  • 8/11/2019 Dc Motor Final Report

    27/30

    msec_count++;switch(msec_count){

    case 5:case 10:case 11:case 12://function set four times

    LCD_en = 1;RS = 0;RW = 0;P2 = 0x3F;

    // pulse enableLCD_en = 0;

    break;

    case 13://send display off

    LCD_en = 1;RS = 0;RW = 0;P2 = 0x08;

    //pulse enableLCD_en = 0;break;

    case 14://send display clear

    LCD_en = 1;RS = 0;P2 = 0x01;

    //pulse enableLCD_en = 0;break;

    case 16:

    //send entry mode setLCD_en = 1;RS = 0;RW = 0;P2 = 0x06;

    //pulse enableLCD_en = 0;break;

    case 18://send display ON

    LCD_en = 1;RS = 0;RW = 0;P2 = 0x0F;

    //pulse enableLCD_en = 0;

    //set the LCD_init_flagLCD_init_flag = 1;break;

    default:break;

    } //end of switch-case

    } //end of ifelse if(LCD_init_flag == 1){

    EA = 0;TMR3CN = 0x04; //Start running Timer 2TMOD = 0x15; //Timer_0 set as event counter and Timer_1 still in 16-bit modeTH0 = 0x00; //Timer 0 high and low bytes setTL0 = 0x00;ET0 = 0; //Disable Timer 0 interrupt, Timer 0 will now be used to count pulses and Timer 2

    records

    EIE1 |= 0x40; //Timer 2 interrupt enabledTMR3L = 0x57; //Timer 2 high and low bytes set to record pulse count every 5 msecTMR3H = 0x9E;TMR3RLL = 0x57; //Timer 2 auto reload values setTMR3RLH = 0x9E;EA = 1;

    }

    // SFRPAGE = SFRPAGE_SAVE;} //LCD_Init()

  • 8/11/2019 Dc Motor Final Report

    28/30

    /* ---------------------------------------------------

    LCD Display Refresh Function

    ---------------------------------------------------*/

    void DISPLAY_ISR(void) interrupt 3{

    //EA = 0;TL1 = RTL1; //Refresh rate of 50Hz

    TH1 = RTH1; //20-msec intervalDisplay_String();

    //The program will not refresh the LCD until the intialization is completeif((LCD_init_flag == 1) && (LCD_busy_flag() == 0)){

    switch(LCD_pointer){

    case 16:LCD_en = 1;RS = 0;RW = 0;P2 = 0xC0; //set DD RAM address to 40H (A7 = 1 100 0000)LCD_en = 0;

    for(k=0;k

  • 8/11/2019 Dc Motor Final Report

    29/30

    /*--------------------------------------------------------Feedback Control

    --------------------------------------------------------*/void FEEDBACK_Init(void){rpm_change = target_rpm - actual_rpm;

    //If desired target speed is higher than actual speed of motor if duty cycle is less than 100%if((rpm_change>0) && (PCA0CPH0> 0x00))

    {if((rpm_change>=1200))

    { PCA0CPH0 = PCA0CPH0 - 0x05;}

    else if((rpm_change>=1000) && (rpm_change=800) && (rpm_change=500) && (rpm_change=300) && (rpm_change=100) && (rpm_change=50) && (rpm_change10) && (rpm_change0) && (rpm_change

  • 8/11/2019 Dc Motor Final Report

    30/30

    /*----------------------------------------------------------Display_String()

    Initializes the LCD array [32]----------------------------------------------------------*/void Display_String(void){//first line display data

    LCD_display[0] = 'T';

    LCD_display[1] = 'A';LCD_display[2] = 'R';LCD_display[3] = 'G';LCD_display[4] = 'E';LCD_display[5] = 'T';LCD_display[6] = ' ';LCD_display[7] = 'R';LCD_display[8] = 'P';LCD_display[9] = 'M';LCD_display[10] = '-';LCD_display[11] = ' ';

    //generate the rpm numberLCD_display[12] = '0'+target_rpm/1000;LCD_display[13] = '0'+(target_rpm%1000)/100;LCD_display[14] = '0'+((target_rpm%1000)%100)/10;LCD_display[15] = '0'+((target_rpm%1000)%100)%10;

    //second line display dataLCD_display[16] = 'A';LCD_display[17] = 'C';LCD_display[18] = 'T';

    LCD_display[19] = 'U';LCD_display[20] = 'A';LCD_display[21] = 'L';LCD_display[22] = ' ';LCD_display[23] = 'R';LCD_display[24] = 'P';LCD_display[25] = 'M';LCD_display[26] = '-';LCD_display[27] = ' ';

    //generate the rpm numberLCD_display[28] = '0'+actual_rpm/1000;LCD_display[29] = '0'+(actual_rpm%1000)/100;LCD_display[30] = '0'+((actual_rpm%1000)%100)/10;LCD_display[31] = '0'+((actual_rpm%1000)%100)%10;

    }