Wednesday, May 9, 2012

Lab 21: Servo motor control


Discription :

A servo motor is a special geared DC motor equipped with an electronic circuit for controlling the direction of rotation, as well as the position, of the motor shaft. Because servo motors allows precise angular positioning of their output shaft, they are used extensively in robotics and radio-controlled cars, airplanes, and boats to control the motion of their various parts. In this lab session, we will first explore what a servo motor consists of and how it works and then illustrate how to interface it with a PIC microcontroller.
Servo motor control using PIC microcontroller
Theory
A servo motor (or servo) is a little box that contains a DC motor, an output shaft (servo arm) which is connected to the motor through a series of gears, and an electronic circuit to control the position of the shaft. The objective of using a servo is to achieve precise angular positioning of an object.
In order to accomplish a servo function, an instantaneous positioning information of the output shaft is fed back to the control circuit using a transducer. A simplest way of doing this is by attaching a potentiometer to the output shaft or somewhere in the gear train. The control electronics compares the feedback signal (which contains the current position of the shaft) from the potentiometer to the control input signal (which contains information of the desired position of the shaft), and any difference between the actual and desired values (known as an error signal) is amplified and used to drive the DC motor in a direction necessary to reduce or eliminate the error. The error is zero when the output shaft gets to the desired position. The functioning block diagram of a typical servomotor is shown below.
Principle of a servomotor
Servo parts (Source: http://tutorial.cytron.com.my/2011/09/19/how-rc-servo-works/)
The control input to a servo is a pulse width modulated (PWM) signal, generally of frequency 50 Hz. This means the pulse should repeat every 20ms. The width of the pulse determines the angular position of the output shaft. An electronic circuit inside the servo converts the PWM signal to a proportional output voltage which is compared with the feedback voltage from the potentiometer. If a difference exists between the two, the control circuit drives the motor in an appropriate direction until the difference becomes zero. A typical value of the pulse width is somewhere in the range of 1.0 to 2.0 milliseconds (ms). For a standard servo, a pulse width between 1.0 ms to 1.5 ms makes the servo to turn clockwise (CW), between 1.5 ms to 2.0 ms makes it to turn counterclockwise (CCW), and a 1.5 ms pulse width turns the servo motor to its center. However, these values could vary depending on the brand and make of the motor. It is advised to read the datasheet of the servo to find the true values of the pulse widths required for positioning the servo at different angles.
Most servos rotate through 180°. However. there are some that could rotate through a full 360° or more. Servos are widely used as the moving joints in robotic arms for their precise angular positioning. They also finds applications in radio controlled (RC) toys. For example, in RC cars they are used in the steering mechanisms, and in RC boats to control the rudder.
A servomotor has three wires: two are designated for power supply (Vcc and Ground) and the third wire is for the control signal.The Vcc wire is usually red and the ground one is either black or brown. The control signal wire comes in white, yellow, or orange color. The servomotor used in this experiment is from iCircuit technologies and has red, brown, and yellow color wires for Vcc, Gnd, and control signal, respectively. It operates at 5.0 V power supply and provides angular rotation through 180°
A typical servo motor
The pulse width values for different angular positions of this servo are provided in the table below. Remember that the repetition rate of the pulse should be 50 Hz (period of 20 ms).
Servo timing information for different anglular positions
Different angular positions of the servo arm
Circuit
The circuit diagram of this experiment is depicted below. The control input for the servo is derived from the RB1 pin of the PIC16F628A microcontroller that operates at 4.0 MHz using an external ceramic resonator. A tact switch is connected to the RB0 pin to provide user input to control the position of the servo arm. The operation part of this experiment is described in the software section below.
Circuit diagram for servo motor control demonstration
Circuit setup on breadboard
Software
The firmware for PIC16F628A is written in MikroC Pro for PIC compiler. The Timer0 module is operated as timer with prescaler 1:256 to generate an approximate 20 ms gap between the two successive PWM pulses. Keep in mind that the clock frequency is 4.0 MHz, which results into 1 μs machine cycle, thus simplifying the math involved in calculating the delay using Timer0. MikroC provides a built-in library function, Delay_Cyc(), that generates a variable clock cycles delay. This function is used to vary the width of the control pulse from 0.7 to 2.3 ms. When the circuit is first powered up or reset, a 50 Hz PWM signal with 0.7 ms pulse width is continuously generated at RB1 pin. This control signal moves the servo arm clockwise all the way to the end, which is considered as 0 angular position. When the tact switch connected to the RB0 pin is pressed, the width of the pulse is increased by 0.2 ms, which turns the shaft counterclockwise (CCW) by approximately 22.5°. So each time the switch is pressed, the pulse width is increased by 0.2 ms, and the shaft further rotates in CCW direction. After 8 successive presses of the switch, the pulse width becomes 2.3 ms and the shaft reaches the other end (180° angular position). On 9th press, the pulse width is reset to 0.7 ms, and the motor shaft rotates in clockwise direction until it gets at 0 angular position back.
/*
  Lab 21: Servo motor Control using PIC16F628A
  MCU: PIC16F628A running at 4.0 MHz, MCLR enabled, WDT is OFF, Brown out detect disabled
  Written by: Rajendra Bhatt (www.embedded-lab.com)
  2012/03/29
  Description: User input switch is connected to RB0 and Servo Control signal
  is generated from RB1 pin.
*/

sbit SW1 at RB0_bit;
sbit Control at RB1_bit;

unsigned short i=7, delay;

void interrupt() {
  delay = i*10;
  Control = 1;
  Delay_Cyc(delay);  // Generates delay equal to (10*delay) clock cycles
  Control = 0;
  TMR0 = 180;        // TMR0 returns to its initial value
  INTCON.T0IF = 0;   // Bit T0IF is cleared so that the interrupt could reoccur
}

void main() {
 CMCON = 0x07;    // Disable Comparators
 TRISB = 0b00000001;
 PORTB = 0;
 OPTION_REG = 0x07; // Prescaler (1:256) is assigned to the timer TMR0
 TMR0 = 180;        // Timer T0 counts from 180 to 255 to create ~20 ms period
 INTCON = 0xA0;     // Enable interrupt TMR0 and Global Interrupts
 do{
  if(!SW1){         // Change pulse width when Switch is pressed
   Delay_ms(300);
   i = i+2;
   if(i>23) i=7;
  }
 }while(1);
}
Output
After loading the HEX file into the PIC16F628A microcontroller, you can watch the servo controller in action. Watch the demo video at the bottom to see the output of this experiment.

Serial four digit 7-segment LED display module



Discription

Seven segment LED displays are a very popular mean of displaying numerical information and finds application in front panel display boards of microwave ovens, washers and dryers, digital clocks, frequency counters, and many other gadgets. Compared to the LCD displays, the seven segment LED displays are brighter and provide a far viewing distance and a wide viewing angle. However, the downside is they are resource-hungry. It requires at least 12 I/O pins of a microcontroller to drive a standard 4-digit seven segment LED module. Consequently, their use with low pin-count microcontrollers (such as PIC12F series) is not practically feasible. Here’s a solution for that. The following 4-digit seven segment LED module features a serial interface that requires only 3 I/O pins of a microcontroller and provides full control of all digits and decimal points .
Four digit serial 7-segment LED display
Description
This display module is based on the MAX7219 display driver chip from MAXIM. It provides a serial interface to drive 7-segment LED displays (common-cathode type) up to 8 digits. Included on-chip are a BCD decoder, multiplex scan circuitry, segment and digit drivers, and an 8×8 static RAM to store the digit values. The segment current for all LEDs is set through only one external resistor. However, the device also provides a digital control of the display brightness (16 steps from minimum to maximum) through an internal pulse-width modulator.
Finished
The display module is powered with +5V supply applied to its Vcc pin. Data can be transferred to the display module through SPI interface. Connections are available on the board to access the required signal lines (MOSI, CLK, and CS) for communication between the SPI Master (microcontroller) and the MAX7219 chip. Data is sent in 16-bit packets (two bytes) which is shifted into the internal 16-bit shift register with each rising edge of CLK. The 16-bit packet is labeled as D0-D15, where D0-D7 contain the data, D8-D11 contain the register address, and D12-D15 are don’t care bits. D15 is the most significant bit (MSB) and is the first bit to receive. Although the MAX7219 chip can drive up to 8 digits, only 4 digits are implemented here. They are DIG0 through DIG3, arranged in sequence from the right to the left. The 4-bit addresses (D8-D11) of their corresponding digit registers are 0×01, 0×02, 0×03, and 0×04, respectively. The digit registers are realized with an on-chip 8×8 SRAM, and are addressed directly so that individual digits can be updated at any time. The following table lists the complete addressable digit and control registers of the MAX7219 device.
Register address map of MAX7219
Control Registers
The MAX7219 contains 5 control registers: decode mode, display intensity, scan limit (number of scanned digits), shutdown, and display test (all LEDs on).
Shutdown
On initial power-up, all control registers are reset, and the MAX7219/MAX7221 enters into Shutdown mode. In the shutdown mode, the display is blanked. The D0 bit of the Shutdown register (address 0x0C) must be set to bring the display to normal operation. The same bit can be cleared anytime during operation to enter back into the Shutdown mode. During Shutdown, the contents of the data and control registers are unaltered. Shutdown can be used to save power or as an alarm to flash the display by successively entering and leaving the Shutdown mode.
The MAX7219 device can be put in the Shutdown mode by sending two bytes 0x0C (address) and 0×00 (data) in sequence. Similarly, 0x0C followed by 0×01 brings it back to normal operation.
Decode-Mode
The decode-mode register (address 0×09) sets BCD code B (0-9, E, H, L, P, and -) or no-decode operation for each digit. Each bit in the register corresponds to one digit. A logic high selects code B decoding while logic low bypasses the decoder. When the code B decode mode is used, the decoder looks only at the lower nibble of the data in the digit registers (D3–D0), disregarding bits D4–D6. The D7 bit is independent of the decoder and turns the decimal point on if it is set (D7=1). For example, sending bytes 0×02 and 0×05 in sequence sets the DIG1 (second digit from the right) to display decimal 5. Similarly, 0×01 followed by 0×89 displays decimal 9 at DIG0 with its decimal point set. The following table provides the complete list of the code B font.
Code B font
When no-decode is selected, data bits D7–D0 correspond to the segment lines (A-G and DP) of the seven segment display.
No-Decode Mode Data Bits and Corresponding Segment Lines
Intensity control
The MAX7219 allows display brightness to be controlled through software by an internal pulse-width modulator (PWM). The PWM output is controlled by the lower nibble (D3-D0) of the intensity register (address 0x0A) and allows 16 brightness levels. The zero nibble value sets the display intensity to minimum, whereas all nibble bits set to 1 selects the maximum intensity level for the display.
Scan-Limit
The scan-limit register (address 0x0B) sets how many digits are to be displayed from 1 to 8. For a 4-digit display, the scan-limit register value should be set to 0×03.
Display-Test
The display-test register has address 0x0F and allows to turn all LEDs on by overriding, but not altering, the values of the control and digit registers. In order to enable the display-test mode, the D0 bit of the display-test register must be set. The same bit must be cleared to get back to the normal operation.
Interfacing with a microcontroller
The serial 7-segment LED display module can be interfaced with any microcontroller that has 3 I/O pins available. If the microcontroller features a built-in hardware SPI, then the display module can be interfaced as a SPI slave device. In that case the SPI signal lines SDO (serial data out), SCLK (serial clock), and SS (slave select) from the microcontroller can be directly connected to the MOSI, CLK, and CS pins labeled on the display module. CS is active low signal.
In case the host microcontroller doesn’t have a hardware SPI module, the interface can be implemented in software. The SPI communication starts with holding CS pin LOW and then sending 16 bits of data serially (MSB first) over the MOSI pin at the rising edge of CLK signal, and finally pulling the CS pin back to HIGH. The following example illustrates how to write a software SPI routine to drive the display module with three general purpose I/O pins of the PIC12F683 microcontroller. The program is written in mikroC Pro for PIC compiler but can be easily modified for other high-level compilers. The GP0, GP1, and GP2 pins of the PIC12F683 drives the CS, MOSI, and CLK pins, respectively, of the 7-segment display module to create a 4-digit up-counter. The counter counts from 0000 to 9999 and then reset to zero and start again.
// Define Soft-SPI connections
#define CS_Pin       GP0_bit
#define MOSI_Pin     GP1_bit
#define CLK_Pin      GP2_bit

void SPI_Write_Byte(unsigned short num){
 unsigned short t, Mask, Flag;
 CLK_Pin = 0;
 Mask = 128;
 for (t=0; t<8; t++){
  Flag = num & Mask;
  if(Flag == 0) MOSI_Pin = 0;
  else MOSI_Pin = 1;
  CLK_Pin = 1;
  CLK_Pin = 0;
  Mask = Mask >> 1;
 }
}

void MAX7219_INIT() {
  // Disable Shutdown mode
  CS_Pin = 0;              // CS pin is pulled LOW
  SPI_Write_Byte(0x0C);    // Select Shutdown register
  SPI_Write_Byte(0x01);    // Set D0 bit to return to normal operation
  CS_Pin = 1;              // CS pin is pulled HIGH

  // Set BCD decode mode for digits DIG0-DIG3
  CS_Pin = 0;              // CS pin is pulled LOW
  SPI_Write_Byte(0x09);    // Select Decode Mode register
  SPI_Write_Byte(0x0F);    // Select BCD mode for digits DIG0-DIG3
  CS_Pin = 1;              // CS pin is pulled HIGH

  // Set display brighness
  CS_Pin = 0;              // CS pin is pulled LOW
  SPI_Write_Byte(0x0A);    // Select Intensity register
  SPI_Write_Byte(0x0F);    // Set maximum brightness
  CS_Pin = 1;              // CS pin is pulled HIGH

   // Set display refresh
  CS_Pin = 0;              // CS pin is pulled LOW
  SPI_Write_Byte(0x0B);    // Select Scan-Limit register
  SPI_Write_Byte(0x03);    // Select digits DIG0-DIG3
  CS_Pin = 1;              // CS pin is pulled HIGH

 // Enable Display-Test
  CS_Pin = 0;              // CS pin is pulled LOW
  SPI_Write_Byte(0x0F);    // Select Display-Test register
  SPI_Write_Byte(0x01);    // Enable Display-Test
  CS_Pin = 1;              // CS pin is pulled HIGH

  Delay_ms(1000);
 // Disable Display-Test
  CS_Pin = 0;              // CS pin is pulled LOW
  SPI_Write_Byte(0x0F);    // Select Display-Test register
  SPI_Write_Byte(0x00);    // Disable Display-Test
  CS_Pin = 1;              // CS pin is pulled HIGH

}

 void Display_Counter(unsigned int j){
  CS_Pin = 0;                    // CS pin is pulled LOW
  SPI_Write_Byte(4);             // Send thousands digit
  SPI_Write_Byte((j/1000)%10);
  CS_Pin = 1;                    // CS pin is pulled HIGH

  CS_Pin = 0;                    // CS pin is pulled LOW
  SPI_Write_Byte(3);             // Send hundreds digit
  SPI_Write_Byte((j/100)%10);
  CS_Pin = 1;                    // CS pin is pulled HIGH

  CS_Pin = 0;                    // CS pin is pulled LOW
  SPI_Write_Byte(2);             // Send tens digit
  SPI_Write_Byte((j/10)%10);
  CS_Pin = 1;                    // CS pin is pulled HIGH

  CS_Pin = 0;                    // CS pin is pulled LOW
  SPI_Write_Byte(1);             // Send ones digit
  SPI_Write_Byte(j%10);
  CS_Pin = 1;                    // CS pin is pulled HIGH
 }

unsigned short i;
unsigned int counter = 0;

void main() {
  TRISIO=0b00001000;        // GP3 is input only
  CMCON0 = 0x07;
  ANSEL = 0x00;
  MAX7219_INIT();           // Initialize  MAX7219
  do{
   for (counter=0; counter<10000; counter++) {
    Display_Counter(counter);
    Delay_ms(1000);
   }
  }while(1);
}
The PIC12F683 microcontroller runs at 4.0 MHz internal clock and MCLR is disabled. In the picture below, the tiny PIC12F683 board is from iCircuit Technologies.
4-digit UP-counter using PIC12F683
The LED display module can also be interfaced with Arduino board using the LedControl library.
Interfacing with Arduino
Summary
This MAX7219 based LED display module allows you to interface a 4-digit 7-segment LED display to low-pin count microcontrollers using only three I/O pins. It gives you full control of all digits, decimal points, and the display brightness.
This display module is available for purchase as a kit. The price of the kit is $10.99 and includes free shipping (regular USPS) within the continental United States. The payment will be through Paypal. If you want this kit, email me first at admin (at) embedded-lab.com, and I will send you my Paypal information.
The picture below shows what you will get in the kit. A 5-pin male header (straight) is included in the kit. Here are the assembly instructions.
4-digit serial seven segment LED display kit