In this exercise, you will learn how to
generate Pulse Width Modulation (PWM) signals using the PIC microcontroller and
to use PWM to digitally control the power to a peripheral device, like an LED or
a motor. You will be using a Solarobotics motor, driven by a TI
SN754410 Quad Half Bridge chip.
Exercises:
1. Wire up the TI motor driver
chip to a motor and control it with 2 pushbuttons.
2. Write a C program for the PIC to send a
variable PWM signal to an LED.
3. Generate a
variable PWM signal using the PIC's built-in CCP/PWM hardware.
4. Add direction-control and
reverse-detection to the PWM program and use it to control the solarobotics
motor.
1 proto board with PIC
16F877 microcontroller and 20Mhz crystal
1 TI
SN754410 Quad Half Bridge
1 potentiometer
2 momentary pushbutton switches
2 LEDs
4
1K resistors
4 alligator bridge clips
1 multimeter
1 power supply
1 computer
1 EPIC programmer
1 power strip
Wire and strippers
| In an H-bridge circuit, the motor is placed at the center of an arrangement of transistors laid out in the shape of an "H". This allows bidirectional control of the motor by turning on transistors at opposite corners of the H. One pair switches forward current, the other reverse. | ![]() |
| The SN754410 chip is a little different. Instead of a whole H-bridge, it contains 4 separate outputs, each having the schematic at right. Each output is built from 2 drive transistors and constitues half of an H-bridge. Since the chip contains 4 of them, it can be wired up for to control 2 DC motors or 1 bipolar stepper motor. The second pair of outputs can also be wired in parallel with the first for higher current capacity. We'll only be using 2 outputs, half of the chip, in this exercise. | ![]() |
![]() Logic diagram of the SN754410. Each pair of outputs has an Enable input. |
Note the 2
diodes in the output circuit above. These are a vital component in an
H-bridge or any motor-control application. These diodes are wired in
parallel with the drive transistors to ensure that any switching
transients generated by the motor coils or voltage generated by the
spinning motor don't damage the transistors.
The 4 outputs are grouped into pairs, each with an Enable (En) control pin. When +5V is applied to pin 1,2En, outputs 1 and 2 are activated. When 1,2En receives 0V, outputs 1 and 2 are "tristated," switched off just as though they were disconnected by a physical switch. |
| Wire up the TI driver chip as illustrated. The pushbuttons deliver +5V to the chip's inputs when depressed. When they're released, 1K-Ohm "pulldown" resistors ensure that the inputs get 0V and aren't left floating. As long as 1,2En receives +5V, outputs 1 and 2 are always on. In this configuration, pressing one button or the other will drive the motor either forward or backward. But if the buttons have the same state, no current will flow because both sides of the motor will receive the same voltage. | ![]() |
| PWM, Pulse Width Modulation, involves taking a square wave and, without changing the frequency, changing how long in each cycle the wave spends high and low. The ratio of t-high/t-low is the signal's duty cycle. The higher the duty cycle, the higher the average voltage on the signal line and the higher the power the signal delivers. | ![]() |
| The
easiest way to program a PWM signal is to pick some period, T1, for our
square wave, take an ouput pin high, delay for a time T2 (where T2<T1),
then take the output pin low and delay for a time T1-T2. By varying T2, we
can change the duty cycle without changing the wave's frequency.
Since the read_ADC() function returns an 8-bit integer, if we use T1=255us (microseconds), we can use the analog value returned by read_ADC for our T2. Since the value returned by read_ADC() will vary between 0 and 255, T1 will stay constant: T1=read_ADC() + (255-read_ADC()). This will let us control the duty cycle of our PWM signal with an analog signal. The following program changes an LED's brightness based on the position of a potentiometer. The LED's anode (positive termnial, longer lead) should be attached to Pin A1. The LED's cathode should be grounded through a 1k-Ohm current-limiting resistor. The potentiometer's center lead should attach to Pin A0 and the other 2 leads should go to +5V and ground. |
#include <16F877.h> #fuses HS,NOPROTECT,NOWDT //Set chip configuration. #use delay(clock=20000000) //Tell the compiler we're using a 20Mhz crystal. #bit LEDPin = 5.1 //Place the 1-bit variable LED at byte 5, bit 1 of memory. #use rs232(baud=115200, xmit=PIN_A2, rcv=pin_A4,invert) //setup serial. void main(){ int T2=0; //Local variables must be declared up front. Remember this is C, NOT C++. set_tris_a(0b00010001); //make only pins A0 and A4 inputs. 1=input, 0=output. //ADCs MUST be set up first. Otherwise, nothing will WORK. //Which pins should be analog? If ADCs unused, call with NO_ANALOGS. setup_ADC_ports(RA0_ANALOG); //Make PIN_A0 the only analog input. //Set the clock source for the ADC. Call with ADC_OFF if ADCs are unused. setup_ADC(ADC_CLOCK_INTERNAL); //Use the PIC's internal RC oscillator. set_ADC_channel(0); //Which pin to read from? In this case, AN0, aka PIN_A0. while(true){ //Start infinite loop. T2=read_ADC(); //store analog value in T2. This will set the duty cycle. LEDPin = 1; //Take PIN_A1 high, turning the LED on. delay_us(T2); //LED on-time based on ADC value. LEDPin = 0; //Take PIN_A1 low after T2 microcesonds, turning off LED. delay_us(255-T2); //LED off-time based on 255-ADC value, keeping T1=255. // NOTE: delay_us accepts variable int8 arguments but only const longs. printf("The input value is: %u\r\n", T2); //Send serial data to the PC. } } |