CSCI 255 — Pulsing with the PIC

Getting ready

You’ll need the follow hardware for this lab.

References

Our objective

We are going to look at four topics today:

Getting started

Putting the Microstick on the board

We continue our use of the Microstick in this lab. Place you Microstick on the breadboard with ground connections to pins 8, 19, and 27 as you did for the Pin I/O on the PIC lab; however, this time use only a single LED and connect the LED and 330 Ω resistor, in series, to pin 15 (RB6) of the Microstick.

Getting MPLABX ready

Start up MPLABX and download the following program as the main C routine.

// pulser lab for CSCI 255

// CSCI 255 clock configuration
#define CSCI255CLOCK FRCPLL80MZ
#include "csci255setup.h"
#pragma config FWDTEN=OFF      // Watch dog timer disabled

// Standard includes
#include <stdlib.h>
#include <stdint.h>

// PIC includes
#include <xc.h>
#include <libpic30.h>

// Output pin
// Pin 15 on PIC24HJ64GP502  --  PGEC3 / ASCL1 / RP6 / CN24 / PMD6 / RB6
#define PULSERTRIS   _TRISB6
#define PULSERVALUE  _LATB6

const int16_t pulseMS  =  800 ;
const int16_t periodMS = 1000 ;

int main() {
   setupClock() ;
   setupAllDigitalOutputWritingZero() ;

   PULSERTRIS  = 0 ;
   PULSERVALUE = 1 ;

   while (1) {
      PULSERVALUE = 1 ;
      __delay_ms(pulseMS) ;
      PULSERVALUE = 0 ;
      __delay_ms(periodMS-pulseMS) ;
   }

   return (EXIT_SUCCESS) ;
}

Can this be right?

MPLABX is not happy. Let’s try to fix the problems. First of all, your program is missing the include file csci255setup.h . Right click on Header Files in the Projects tab and add a new C header file called csci255setup.h .

Delete the initial contents MPLABX has generated for you and replace them with the following definitions.

#ifndef CSCI255SETUP_H
#define	CSCI255SETUP_H

#if CSCI255CLOCK == FRCPLL80MHZ
#define FCY (79227500UL/2)
#elif CSCI255CLOCK == LPRC
#define FCY=(32768UL/2)
#else // assume FRC
#define FCY (7370000UL/2)
#endif

#include <xc.h>

#if CSCI255CLOCK == FRCPLL80MHZ

#pragma config FNOSC=FRC       // Fast RC Oscillator
#pragma config FCKSM=CSECMD    // Clock switching enabled, FSCM disabled
inline void setupClock(void) {
    PLLFBD = 41 ;             // PLL Feedback Divisor
    _PLLPOST = 0 ;            // PLL postscaler
    _PLLPRE = 0 ;             // PLL prescaler
    // Multiplying by (41+2)/((0+2)*2+(0+2)*2) or 10.75
    // 10.75 * 7370000 = 79227500

    // Writes 0x78 then 0x9A to unlock and then updates _NOSC
    __builtin_write_OSCCONH(0b001) ;
    // Writes 0x46 then 0x57 to unlock and then updates _OSWEN
    __builtin_write_OSCCONL(0x1) ;

    while(_COSC != 0b001) ;   // waiting for clock switch

    while(_LOCK != 0b1) ;     // waiting for PLL to lock
}

#elif CSCI255CLOCK == LPRC

#pragma config FNOSC=LPRC
#pragma config IESO=OFF
inline void setupClock(void) {
}

#else // assume FRC

#pragma config FNOSC=FRC
inline void setupClock(void) {
}

#endif

inline void setupAllDigitalOutput(void) {
   AD1PCFGL = 0xFFFF ;    // Set all pins for digital
   CNEN1 = 0 ;            // Disable change notification
   CNEN2 = 0 ;
   CNPU1 = 0 ;            // Disable weak pullup
   CNPU2 = 0 ;
   ODCA = 0 ;             // Disable open drain
   ODCB = 0 ;
   TRISA = 0 ;            // Set all pins for output
   TRISB = 0 ;
}

inline void setupAllDigitalOutputWritingZero(void) {
    setupAllDigitalOutput() ;
    LATA = 0 ;
    LATB = 0 ;
}

#endif	/* CSCI255SETUP_H */

We are going to take a little time now for everyone in the lab to get their LED flashing. If you get yours working quicker than your neighbors, help them out.

The include file

Now set back for a minute for a little lecture on C (and C++) include files. Here are the topics to be covered.

Pulse Width Modulation

Now back to the program. Change your program so that pulseMS is 1 and periodMS is 10. You’ve did something like this in the Pin I/O on the PIC lab. You can’t see the LED flashing on and off; but, because it is only on 10% of the time, it appears to be dimmer.

This is called pulse width modulation. This is pretty much the way the light dimmers in your living room work. They turn the light on and off about 120 times per second, and your eyes just don’t notice the difference. (However, standard fluorescent light (CFL) bulbs do notice the difference, so you need to purchase special dimmable CFLs for those dimmer circuits in your home.)

Modify your program so that it gradually brightens the LED by varying the value of pulseMS with time.

Turn the LED completely off for one second and then increase the pulse width every second until the LED is completely on. Have your program repeat the cycle of dark to light every ten seconds.

Now for sound

First of all, undo some of what you just did. Modify your program so that pulseMS is always 2 and periodMS is always 4. If you can’t bring yourself to delete your old code, follow the practice of the pros as shown below. It’s easier than adding comments.

#ifdef DELETEDCODE
   for (i=0; i<1000; ++i) {
      printf("Annoying message #%d\n", i) ;
   }
#endif

The LED should now be flashing on and off 250 times per second. More formally, we’d say that it has a frequency of 250 Hz and a period of 4 msec. More musically, we’d say that it is close to the B below middle C. (Due to variations in clock frequency of the PIC, neither of these is precisely true; but hopefully, they are almost true.)

Get a speaker and plug it into your breadboard. Just replace the LED with the speaker. You should be able to hear a faint tone.

The tone will be a bit unmusical because it is being generated by a square wave. A sine wave would be more pleasent, but that requires more mathematics and a faster processor. For the most part we are going to concentrate on generating louder, rather than better, sound today. But first we need to work on creating a little music.

A useful function

Right now your are, presumably, writing a doubly nested loop for every tone we generate. Let’s write a C function playTone for generating a note. playTone take two arguments, the frequency of the note given in Hertz and the duration of the note given in milliseconds.

Start by replacing your loop for playing the alternating tones with this much simpler loop.

   while (1) {
       playTone(500, 1000) ;
       playTone(250, 1000) ;
   }

Now add the outline for a function playTone at the end of your program, after main.

void playTone(uint16_t frequency, uint32_t duration) {
    // frequency:  frequency of the tone in cycles per second (Hz)
    //             if frequency is 0, place no tone
    // duration:   length of the tone in milliseconds (msec)
}

In C and C++ it is considered good style to provide prototypes for functions that are used before they are defined. C/C++ prototypes are a bit like method signatures in Java. Add a one-line prototype for playTone before your main function, so that the compiler will know the types of the arguments for playTone when it is compiling main

void playTone(uint16_t frequency, uint32_t duration) ;

Usually functions are written in their own .c files and distributed with corresponding .h files containing prototypes and other useful constant and data structure definitions, but here we are placing the prototype and implementation in the same file.

Complete the playTone procedure. We suggest you work in units of microseconds inside the procedure. Start by computing both the period and duration in microseconds.

16-bit integers are not big enough to deal with units stored in microseconds. You need to move to 32-bit integers.

What about a song?

Let’s take advantage of the work of someone else, even if it was done for an Arduino. In another window open up the Arduino tutorial Play a Melody using the Tone() function written by Tom Igoe. Read the tutorial.

Now download Igoe’s pitches.h and place it into your MPLABX project. You also ought to open another window with the Arduino sketch and take a look at Igoe’s setup function. This looks like something you could use in your main routine.

Make your main function look a lot like Tom Igoe’s setup function. This isn’t that hard. Start with a cut-and-paste and them make the needed adjustments. By the way, this is the sort of thing embedded systems programmers do frequently.

Now play your song over and over and over, but add a delay of about one second between performances. If you wish, you may encode a melody of your own choosing.

Getting louder

The PIC is a control device. It can’t generate the current needed to make a lot of noise.

A few times during these labs we have mentioned the need to read schematics. The time has come. If you think you need a tutorial on schematics, I suggest you look at From Schematic to Reality: Understanding Schematics from Beavis Audio.

Revisiting the 3904 transistor

You used the 3904 transistor for making NOR gates in the transistors lab. This is a odd role for the 3904 these days. It, along with its more powerful colleague 2222, are usually used to switching small current hungry devices off and on.

Do you remember turning a LED on with a 3904 in the Transistors lab? Do the following diagrams revive your memory?
LED schematic   LED on breadboard   transistor

To get this LED controller to run a speaker, you need to replace the LED and collector resistor Rcol with the speaker. However use a 6 volt battery pack to drive the speaker. Otherwise, it will be even more piano. We are going for forte.

So collect one end of the speaker to the battery pack and the other end to the collector of the transistor. Be sure to use a base resistor Rbas to connect the PIC output pin to the base of the transistor. Your 330 Ω resistor will work fine. If you need more information, take a look at Using a Speaker for Audio Output, a tutorial written for the mbed microcontroller development board.

This should make your speaker much louder. By the way, you can also use a 3904 or 2222 in similar configurations to control the speed of motors.

The LM386

The LM386 is a low voltage audio power amplifier that is used in many audio devices, such as the Smokey® Amp. In fact, the Smokey Amp is little more than an LM386 with a couple of capacitors.

Take a look at the schematic in the upper left corner of page 5 of the LM386 datasheet which only appears on the Audio Power Amplifiers with LM386 page of Hobby-Hour.com.

Try to build this on your breadboard. It’s only one potentiometer, one resistor, and a couple of capacitors. Be sure to power the LM386 from your battery holder.

This setup won’t be any louder than the 3904 amplifier, but it can amplify very weak signals through a high resistance channel, such as the 4M Ω human body. Here’s an example of a four-digit device opening and closing the circuit. I suspect this would work even if the entire class held hands to complete the circuit, but this is a Computer Science class.
off    on
The PIC only produces 3.3 v. Do not try this at home with the speaker wires coming out of your 200 watt stereo amplifier.

What to do

Make it loud.