Category Archives: PIC Programming

PIC LED Controller – PWM capture

The LED controller for my quadcopter will be controlled by by the remote control on one of the PWM channels. The last step of preparation before writing the LED controller itself is to understand how to listen on a remote control (RC) channel and detect the PWM “value” that is transmitted on the channel.

I decided to connect my cheap Minima receiver to the circuit and write a small program to display the PWM value, that I’lll transmit to it, on my 3-digit, 7-segment display. The Minima is sold by Hobbyking.com here. It is compatible with my Hitec transmitter and the price is just 19.73 euros, which is cheap compared to the original Hitec Optima receiver.

I had to come up with a method for communicating between the two PIC16F1825 controllers because the application controller has to transmit the PWM value to the 7-segment controller. I thought of using the USART serial interface but I decided to use the DAC (Digital to Analog Conversion) feature of the PIC16F1825. In this mode, the chip can output 32 voltage levels on pin RA0 – the DACOUT pin. This pin is connected to input pin RA2 on the 7-segment controller. The 7-segment controller displays a number between 0 and 99 that corresponds to the voltage on its input pin so it will display a number that corresponds to the PWM value. I decided to use this method because accuracy is not important in this project.

Set up

The circuit is shown in the picture below.

PWMTest_Setup

The RC transmitter at the top is my Hitec Aurora 9. On the right side, outside the breadboard is the Minina receiver. Its red LED is on indicating that it is connected to the transmitter. The receiver is connected with 3 cables from its channel 3 output to the breadboard:

  • Red cable connected to +5V
  • Black cable connected to GND
  • White/Yellow cable – the signal cable (white on the Minima side and yellow on the breadboard side) connected to pin RA5 of the application controller.

There are 2 PIC16F1825 controllers on the board:

  • Application controller (top) – runs the PWM capture function
  • 7-Segment controller (bottom) – drives the 7-segment display.

Application controller

The application controller is connected to 4 LEDs that are not part of this project. They are there because I don’t want to take them out for every picture that I take of the breadboard and eventually they will be part of the LED controller.

The application controller is also connected to the PICKit3 data cable that connects to RA0, RA1, RA3 as I described in a previous post.

The two connections relevant to this project are RA5 – the PWM input, and RA0 – the output of the analog signal to the 7-Segment controller. RA0 functions as the DACOUT pin (Digital to Analog Converter Out).

7-Segment controller

The 7-segment controller is described in a previous post. It receives an input voltage, between 0V and +5V) on pin RA2 and displays a number between 0 and 99 that corresponds to the input. The input pin, RA2 is connected to the DACOUT pin on the application controller (RA0).

Code

The code is quite simple. I use the IOC (interrupt on change) feature that calls the ISR whenever a rising or falling edge is detected on an input pin. I also use Timer 1 to time the PWM duty cycle – the time the line is high.

The I use the DAC (digital to analog converter) to pass a value to the 7-segment display controller.

/*
* File: main.c
* Author: Eli Gurvitz – Quadcopter Blog
*
* Created on February 26, 2015, 10:59 PM
*/

#include <xc.h>

The rising and falling edge #defines are used in the ISR. The LOWPWM is the value of the lowest PWM reading. I found it by using the debugger.

#define LOWPWM 8800
#define RISING_EDGE 0
#define FALLING_EDGE 1

Skipping the settings of the configuration bytes which usually goes here.

unsigned int pwmvalue = 0;

/****************************************
*
****************************************/
void interrupt ISR()
{

The state variable indicates if we are dealing with a rising edge or a falling edge.

    static int state = RISING_EDGE;
    unsigned int newvalue;

    if (IOCAF5 == 1) {

If the ISR is called for a rising edge then we reset timer 1 and change the IOC setting to interrupt on a falling edge (the IOCAP and IOCAN registers).

        if (state == 0) { // rising edge
            TMR1L = 0;
            TMR1H = 0;
            IOCAP5 = 0;
            IOCAN5 = 1;
            state = FALLING_EDGE;
        }
        else { // falling edge

If the ISR is called for a falling edge then we read the value of timer 1. If the value is different from the previous value then we update the PWM value. Then we set IOC to be called on a rising edge.
            newvalue = (TMR1H << 8) + TMR1L;
            if (newvalue != pwmvalue) {
                pwmvalue = newvalue;
            }
            state = RISING_EDGE;
            IOCAP5 = 1;
            IOCAN5 = 0;
        }
        IOCAF5 = 0;
    }
}

/****************************************
*
****************************************/
void main()
{
    int i;
    int j;

    OSCCON = 0xF0; // set internal osc to 32Mhz

Timer1 settings

    TMR1ON = 1;
    TMR1GE = 0;

Setting RA0 for output and RA5 for input.

    TRISA0 = 0;
    TRISA5 = 1;

Setting the IOC for pin 5. The initial setting is for detecting a rising edge.

    IOCAP5 = 1;
    IOCAN5 = 0;
    IOCAF5 = 0;
    IOCIE = 1;

GIE must be enabled in order to receive the IOC interrupts.

    GIE = 1;

DAC settings – enable DAC and enable the DACOUT pin.

    DACEN = 1;
    DACOE = 1;

Main loop – I decided to update the 7-segment display only periodically (on a count to 10000). This

    while(1) {
        if (i > 10000) {

Initially, I tried to calculate the DACOUT value (which is set by writing to the 5 LSBits of DACCON1) by a simple function (see below) but it didn’t work. Therefore I compare the PWM value to each possible value from the lowest  (LOWPWM) and up to 32 increments (of 200 in this case) and set DACOUT to the index of the increment. This is good enough for the purpose of this sample.

            for (j = 0; j < 32; j++) {
                if (pwmvalue < (LOWPWM + (j * 200))) {
                    DACCON1 = j;
                    break;
                }
            }
            i = 0;
        }
        i++;
    };
}

Running

 Issues that I still need to understand

  1. I tried using the PWM capture feature of the PIC16F1825 but it didn’t work. It never stopped in the ISR (Interrupt Service Routine).
  2. At first I tried to calculate the output value in the following way but it never worked. The DACOUT value varied between 3 and 8 and never corresponded to the value of the function described below.
    1. Divide the PWM input range into 32 groups. Each group has a size of (PWMHIGH – PWMLOW) / 32
    2. Normalise the PWM input by subtracting the min value from it.
    3. Divide the normalised PWM input by the group size.
    4. Or, in other words: DACOUT = (pwmvalue – PWMLOW) / group size = (pwmvalue-PWMLOW) * 32 / (PWMHIGH – PWMLOW).

 

PIC LED Controller – 7-Segment driver

While working on the LED controller I decided that it would be nice if the blinking interval (the length of time a LED is on or off) will be controlled by a potentiometer. Then I remembered that I bought a few 3-digit 7-segment displays (see footnote) and it would be even nicer if I’ll show the pot setting on the display. It will add some color to the LED controller. I also bought some new PIC16F1825 controllers with 14 pins which are perfectly suited for the job. So I had everything ready and to my surprise it took me much longer to get it working than I anticipated.

I had to learn a few new things to make this work:

  • Using the ADC (Analog to digital feature of the PIC16F1826)
  • Connecting the display to power and to the controller
  • Driving the 7-segment display.

First of all, here is the final system. Notice how the numbers on the display change as I turn to pot with the screwdriver.

I’ll start by describing the wiring of the circuit.

Wiring

See Important update to the wiring scheme below

The image below shows the wiring of the potentiometer (marked), the PIC16F1825 controller and the display.

Wiring

Wiring

The VDD and VSS pins are connected to the power via the two grey wires at the right side.

The two wires marked “control” – a purple one connected to RA0 and a brown one connected to RA1 – control which digit is “displayed”, or more correctly – powered up. This display is a common anode display. This means that all the segments of a digit are connected to a single positive pin. There are three such pins, one for each digit. In order to light up a segment, the digit’s control pin must be positive and the segment’s pin must be negative. In order to display two or three digits at the same time, the program must switch the control pins on and off rapidly. In this project I’m using only two digits – to display numbers in the range 0 – 99.

Pin RA2 is connected to the potentiometer.

The yellow and orange wires connect each of the 7 segments to a pin on the controller according to the table below. The table shows the assignment of the controller’s pins to segments (segments are marked by the letters A – G) and the segments that must be lit to display each digit. For example, to display the number one, segments B and C must be on. This table is actually good for a common cathode display – I made it before I realized that I have a common anode display. So you’ll see that in the code the bits are negated.

7-segment-table

 

Pin RA4 is connected to segment G.

The problems

I had to take care of several issues in the code and I’ll explain how each one is handled. The main problems were:

  • The display is of the common anode type, meaning that to light a segment, its pin must be low (0)
  • The display has only 11 pins to control 3 digits, each with 8 segments (the 8th is the decimal dot). This means that the controller needs to turn them on and off in a round-robin way.
  • The pot is completely not stable – it sends different readings continuously. I had to “smooth” out the constantly changing readings

The initial, naive implementation was really dumb and had all the mistakes possible in such small program. When I ran it all the segments on both digits were flickering wildly and one of the digits was brighter than the other. The problems were:

  • I assumed that a positive voltage on a pin will light a segment but my display was of the common anode type, so a pin must actually be low to light a segment. The lighted segments didn’t resemble any number of course.
  • I understood that I have to switch each digit on and off, but the code first switched on digit 1, then switched it off and right after that, in the same function, switched digit 2 on and only after that changed the lit segments to show digit 2. This implementation really had all the possible errors and it caused one digit to be bright and the second to be dim.
  • I didn’t remember that the pot keeps sending different readings all the time, so the digits never stabilised (and of course, I couldn’t make out any digit because of the confusion with common anode vs. common cathode).

Solutions that didn’t work

I first thought that the controller can’t source enough current to light up the digits, so I connected the control pins to the 5V input via a transistor. This of course made no difference.

I realised that the pot is fluctuating wildly so I installed a low-pass filter – a resistor and capacitor in series. This was an interesting exercise and I played with various combinations of resistors and capacitors and watched the effects. This help a little but not much. I understood finally that a low pass filter is not a solution to the problem because even if it smooths out the input a little bit, some readings will pass through and make the display flicker.

So I started simplifying the circuit and the code and trying to isolate problems – first light up a single hard-coded digit, then two digits and then connect it to the pot.

Solutions that did help

I read the display’s data sheet to the end and found that the duty cycle of each digit is 1/10 and the actual time that it must be lit was 0.1 millisecond. So I understood that the correct way to drive the display was the following:

  1. Turn digit 1 on
  2. Wait 0.1 ms
  3. Turn digit 1 off
  4. Wait 0.1 ms
  5. Turn digit 2 on
  6. Wait 0.1 ms
  7. Turn digit 2 off
  8. Wait 0.9 ms

I did a few more changes:

  1. I fixed the segment table to match a common anode display
  2. I added code that discarded pot readings if they were within 10 points from the previous reading.
  3. The main change – driving the segments correctly.

I will highlight these areas in the code.

The code

We will describe the code in section. I skipped the configuration byte definition in order to save space.

#define INTERVAL1 4
#define INTERVAL2 40

Interval 1 is more or less 0.1 millisecond – it determines the time that  a digit is lit.
Interval 2 is the interval when both digits are off. Since the duty cycle is 1/10 interval 2 is ten times interval 1.

unsigned int adcvalue; // The input value from the pot
int timer0count;       // counts timer 0 interrupts
int state;             // state – moves the system between states.

The states are:

  •  0 – turn digit 1 on
  •  1 – turn digit 1 off
  •  2 – turn digit 2 on
  •  3 – turn digit 2 off
  •  4 – read the value on ADC

each state lasts interval 1 ticks

  • 5 – wait interval 2

// pin to segment assignment is:
// C0-C1-C2-C3-C4-C5-A4
// A -B -C -D -E -F -G
// Pin A2 used for ADC
// Pin A0 used for display pin 8 – digit 1 – ones
// Pin A1 used for display pin 9 – digit 2 – tens

unsigned char digits[] = {
0b01000000, // 0 

  0b01111001, // 1
  0b00100100, // 2
  0b00110000, // 3
  0b00011001, // 4
  0b00010010, // 5
  0b00000010, // 6
  0b01111000, // 7 
  0b00000000, // 8
  0b00011000  // 9
};

Note that in the digits array above a segment is lit if its value is 0. Hence the value for the number 8 is all zeros.

Next is the interrupt service routine – it increments the time tick counter and reads the pot value from the A2 pin.

void interrupt ISR()
{
  if (INTCONbits.TMR0IF) {
    timer0count++;
    INTCONbits.TMR0IF = 0;
    TMR0 = 0;
  }

  if (PIR1bits.ADIF) {
    adcvalue = (short) ADRES;
    PIR1bits.ADIF = 0;
    ADCON0bits.GO = 1;
  }
}

The show_number function sets the individual segments on or off according to their setting in the digits array above.

void show_number(unsigned char number)
{
  LATC0 = ((number & 0x1) > 0) ? 1 : 0;
  LATC1 = ((number & 0x2) > 0) ? 1 : 0;
  LATC2 = ((number & 0x4) > 0) ? 1 : 0;
  LATC3 = ((number & 0x8) > 0) ? 1 : 0;
  LATC4 = ((number & 0x10) > 0) ? 1 : 0;
  LATC5 = ((number & 0x20) > 0) ? 1 : 0;
  LATA4 = ((number & 0x40) > 0) ? 1 : 0;
}

And now to the main function. I will skip the set up code of the input/output directions of pins and the register settings for Analog-to-digital converter (ADC) and the timer 0 interrupt counter.

state = 0;
timer0count = 0;

adcvalue = 0;
previous_value = 0;
while(1)  {
  if (state == 5) {
    if (timer0count >= INTERVAL2) {
    timer0count = 0;
    state = 0;
  }
  else 
    continue;
  }
  if (timer0count < INTERVAL1) {
    continue;
  }

  switch (state) {
    case 0:
      LATA0 = 0;
      LATA1 = 1;
      show_number(digits[digit1index]);
      break;
    case 1:
LATA1 = 0;
       break;
    case 2:
      LATA0 = 1;
      LATA1 = 0;
      show_number(digits[digit2index]);
      break;
    case 3:
      LATA0 = 0;
      break;
    case 4:
      if (adcvalue > 990)
        adcvalue = 990;
      if (adcvalue < 10)
        adcvalue = 10;
      if (adcvalue >= previous_value)
        delta = adcvalue – previous_value;
      else
delta = previous_value – adcvalue;
if (delta > 10) {

        value = adcvalue / 10;
        previous_value = adcvalue;
      }
      digit1index = value / 10;
      digit2index = value % 10;
      ADCON0bits.GO = 1;
      break;
    }
    state++;
    timer0count = 0;
};

Updated wiring scheme

My good friend Tomer pointed out to me that I must add resistors to protect the chip from running at maximum current output from the chip. The wiring above is identical to short-circuit between the output chips and it will lead to damaging the chip.

So I added 220 Ohm resistors on all the segment pins to limit the current to around 22mA (5 / 220 according to Ohm’s law. Here is the updated wiring photo.

7-segment-updated

 

========

Data sheet for the 7-segment display can be found here. They are manufactured by Wayjun and cost me $2.55 for 10 units on Ali Express.

PIC LED Controller – Stage 2

After completing stage 1 and reviewing it with my friends I decided that it needs the following changes and additions – hence stage 2:

  • Manage 4 LEDs and not only two as in the code of stage 1
  • Allow the app to change the state of each LED to OFF, ON or BLINKING while the app is running. This is a fundamental feature for the full LED controller because the user will be changing the state of the LEDs by the remote control.
  • Allow the app to set the intensity of each LED
  • Change the  LED Controller API functions to start with LC in order to avoid namespace collisions with the client app (although I realise that this is for a tiny PIC and not a desktop).

In short, I wanted my application code (main.c) to look like this:

[file]http://www.qcptr.com/code-snippets/led-controller-stage-2/main.c[/file]

The file starts with the regular setting of the configuration words and then defines an array of “state” structures:

 

struct {
  LEDState state;
  short blinkCount;
  short intensity;
} states[] = {
  {LEDON, 0, 10},
  {LEDBLINKING, 1, 5},
  {LEDBLINKING, 3, 15},
  {LEDOFF, 0, 15},
  {LEDON, 0, 15},
  {LEDBLINKING, 4, 10}
};

 

Each state consists of an action – Off, On or Blinking. If the state is “blinking” then the second member is the number of blinks and the third member is intensity – a number between 1 and 15 where 15 is brightest and 1 is the least bright.

The array contains six different states and LED 1 (the rightmost LED will cycle through these states.

The main function itself sets up LEDConfig structs, sets the initial states for each LED (note that LED 2 – the second from right) is OFF throughout and enters the main loop. In the main loop LED 2 will remain off. LEDs 3, and 4 will blink at a fixed rate and LED 1 will move through the states above.

This is how it looks like:

The header file now contains some #ifdefs that allow it to compile and run on an iOS device (more about that later). The LEDConfig structure was changed from stage 1 and the functions are prefixed with LC.

Here is the header file.

[file]http://www.qcptr.com/code-snippets/led-controller-stage-2/ledcontrol.h[/file]

The LED controller C file is here:

[file]http://www.qcptr.com/code-snippets/led-controller-stage-2/ledcontrol.c[/file]

A word on the (free) XC8 compiler

 It seems that the free XC8 compiler is extremely inefficient in transforming the C code to assembly. I noticed that dereferencing a member in a struct requires countless assembly commands. For example, the command (from main.c):

946 ;main.c: 56: short b = states[index].blinkCount;

maps to the following assembly code:

947   02F3   3005   movlw 5
948   02F4   00A2   movwf ??_set_state
949   02F5   0822   movf ??_set_state,w
950   02F6   00F1   movwf ___bmul@multiplicand
951   02F7   0820   movf set_state@index,w
952   02F8   23D5   fcall ___bmul
953   02F9   3E01   addlw 1
954   02FA   3EA0   addlw _states& (0+255)
955   02FB   0086   movwf 6
956   02FC   0187   clrf 7
957   02FD   3F40   moviw [0]fsr1
958   02FE   0020   movlb 0 ; select bank0
959   02FF   00A4   movwf set_state@b
960   0300   3F41   moviw [1]fsr1
961   0301   00A5   movwf set_state@b+1

When the compiler finishes it gives me the following statistics:

Memory Summary:
Program space used      3FEh ( 1022) of 800h words ( 49.9%)
Data space used         7Eh  ( 126) of 80h bytes ( 98.4%)
EEPROM space used       0h   ( 0) of 100h bytes ( 0.0%)
Data stack space used   0h   ( 0) of 1h byte ( 0.0%)
Configuration bits used 2h   ( 2) of 2h words (100.0%)
ID Location space used  0h   ( 0) of 4h bytes ( 0.0%)

This means that not much is left for the rest of my controller code on this chip. The compiler also says that if I’ll buy the PRO version it will shrink the code by 40% and I will save 408 words.

Other areas of inefficiency in my code are the modulo-6 operation (index = (index + 1) % 6) and all the function calls that are an inherent part of the “pseudo object oriented programming” that I use here

Despite of all this inefficiency, I think it is worth writing in C because it it much more readable (to most of us) and allows us to give the program some structure. I think it is possible to overcome the memory capacity problem in several ways:

  1. Use a larger chip – the price difference is probably negligible
  2. Write some parts of the code in efficient assembly (will take me ages)
  3. Buy the PRO version of XC8
  4. Buy another compiler for the PIC processor. I found one for $50.
  5. Check out the GPUTILS – Gnu PIC utilities – I’m going to do this right after I finish this post.

The next steps towards the final LED controller are:

  1. Add a potentiometer that will control the length of the blink of the LEDs
  2. Learn how to receive a PWM signal into the PIC
  3. Revisit the product requirements and modify (I have some ideas for modifications already)
  4. Write a good specification of the init and initial configuration stage. This is not simple as it sounds.
  5. Implement the init and configuration stage
  6. Define the states and update the main function
  7. Test on the breadboard with regular LEDs – add the transistors to the circuit for driving the LEDs
  8. Build the real circuit with the high-power LEDs that I ordered
  9. Build a few more kits and try to sell them

In-circuit programming of PIC12F1822

In-circuit programming means that the PICKit3 programming tool is connected in parallel to the active circuit. This allows debugging and is very convenient in general since there’s no need to take the chip out and put it into the ICSP adaptor.

This is also useful for programming the chips when they are already mounted on a production board.

I will explain the connections and SW configuration in this post.

Wiring and connections

The following photo shows how the PICKit3 is connected to the chip.

PIC in-circuit connections

The PICKit3 header has six pins and pin number 1 is identified by an arrow as can be seen in the  next photo.

PICKit3 marking

The pins have the following functions:

1 – VPP/MCLR

2 – VDD

3 – VSS (Ground)

4 – ICSP data

5 – ICSP clock

6 – LVP (low voltage programming)

We use only the first five pins since we are not working in low voltage programming mode.

The table below shows where each PICKit3 pin is connected to the chip.

[table id=3 /]

The last connection is a 10K pull-up resistor connected from VSS to VPP – pin 4 – of the chip.

Configuring the MPLab IPE (Integrated Programming Environment)

Open the “Advanced mode” window in the Settings menu and select “Power” on the left pane. Make sure that VDD is correct (it is not correct in the screen shot below) and uncheck the “Power target circuit from tool” check box, so that the chip will be powered from the power supply. The reason is that the tool can not provide enough power for programming when it is in-circuit.

PICKit3 settings

 

Possible problems

I encountered the following errors before I found how to set this up correctly:

“Too much power drawn on VDD” – the VDD and VSS are not connected to the power supply but instead draw power from the PICKit3.

 

PIC LED Controller – Stage 1

My first PIC project is a LED controller (henceforth referred to as “LC”) for my Quadcopter 1. The LC will receive commands over a RC channel and control four high intensity LEDs that I will connect to the underside of the arms of the quadcopter. I will describe the features of the LC in a separate post. This post describes the first stage of programming the LC.

In this stage I wrote code that allows me to control any number of LEDs (well, in practice I can attach only four LEDs to the PIC12F1822) by defining different properties for each LED. The code is object-oriented in the sense that the behaviour of each LED is defined in an instance of a struct (=an object) and functions operate on these objects. I considered implementing a full object oriented model in which the functions are also included in the struct, but I FEEL that the overhead of this approach is too much for the tiny PIC controller and the inefficient compiler (the free XC8) that I use.

The following video shows the LC in use with two LEDs that blink at a different rate. The yellow LED blinks three times and then waits while the green LED blinks five times and waits. These two LEDs can be used as indicators to the internal state of the LC which has a major state (yellow LED) and a sub-state (green Led).

So let’s describe the code.

The application consists of three files:

  • Main function with the main loop
  • LED Controller header file
  • LED Controller implementation

Main

I will start with the main function because it shows how the LC code is used.

[file]http://www.qcptr.com/code-snippets/led-controller-stage-1/main.c[/file]

Main.c starts with setting up the configuration bits. Then the ISR counts the number of times Timer0 overflows where each overflow happens every 0.25 of a millisecond. The calculation is as follows:

  1. Timer 0 prescaler (PSA) is set to 8 which means that the timer counts at a rate of 1Mhz
  2. On each overflow TMR0 is set to 6 so it counts 250 ticks before it overflows again.

Then the main function starts with initialising the ports and defining the LEDConfig instances for the two LEDs. Finally the main loop starts. After every 4 overflows of Timer 0 (which are more or less equivalent to 1ms) the main loop calls the HandleLEDs function that updates the state of the LEDs.

Note that main needs only instantiate the LEDConfig structs, pass them to the LC and then notify the LC once every 1ms.

LED Controller header file

The header file defines the “blink interval” and “off interval”, the LEDConfig struct and declares the functions that operate on instances of LEDConfig. The “blink” and “off” intervals specify the amount of time a LED is on or off while blinking and the amount of time it is off between bursts of blinking.

[file]http://www.qcptr.com/code-snippets/led-controller-stage-1/ledcontrol.h[/file]

LED Control C file

The C file manages the array of LEDConfig structs so that the user of this code (i.e. the main function in this example) needs only create these structs and pass them to the LC. Main must also notify the LED controller of every “tick” of the clock and the LC takes care of everything else.

[file]http://www.qcptr.com/code-snippets/led-controller-stage-1/ledcontrol1.c[/file]

Credits

I found this site somewhat useful to understand how Timer 0 should be used.

 

My first PIC project

My first PIC project is very simple, kind of a PIC “hello world” program. My program reads the state of a push button and turns on a LED if the button is pressed.

This is the circuit:

test1schematic

And this is how it looks on the breadboard:

PIC Test 1 Breadboard

Note that the 10K Ohm pull up resistor is not on the breadboard and the button is connected to negative. The reason for this is that the PIC12F1822 (and I assume all other PICs) has an internal pull up resistor. The pull up resistor connects the input pin (called RA3) to the +5V VDD pin and keeps it high. When the button is pressed it switches the input pin to low. Therefore the program turns the output pin (RA0) to high when the input (RA3) is low.

Page 3 of the data sheet contains a table that describes all the pins of the PIC12F1822. Note that all the input/output pins have internal pull ups.

This is the program:

#include <xc.h>

// CONFIG1

#pragma config FOSC = INTOSC // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)

#pragma config WDTE = OFF // Watchdog Timer Enable 
#pragma config PWRTE = ON // Power-up Timer Enable 
#pragma config MCLRE = OFF // MCLR Pin Function Select 
#pragma config CP = ON // Flash Program Memory Code Protection 
#pragma config CPD = ON // Data Memory Code Protection 
#pragma config BOREN = ON // Brown-out Reset Enable 
#pragma config CLKOUTEN = OFF // Clock Out Enable 
#pragma config IESO = ON // Internal/External Switchover 
#pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable 

// CONFIG2
#pragma config WRT = OFF // Flash Memory Self-Write Protection 
#pragma config PLLEN = ON // PLL Enable 
#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (
#pragma config BORV = HI // Brown-out Reset Voltage Selection 
#pragma config LVP = OFF // Low-Voltage Programming Enable 

void main()
{
    TRISA3 = 1;
    TRISA0 = 0;

    OPTION_REG = OPTION_REG & 0x7f;
    WPUA3 = 1;

    PORTAbits.RA0 = 0;

    while (1) {
        if (PORTAbits.RA3 == 0)
            PORTAbits.RA0 = 1;
        else
            PORTAbits.RA0 = 0;
    }
}

I will not describe all the configuration bits at this stage. Note only that I disabled the watchdog because I still don’t know how to keep it alive. I will definitely turn it on in one of the next projects.

Note also the OPTION_REG assignment and the WPUA3 assignment. These lines turn on the internal pull up resistor on pin RA3.

This small program gave me an opportunity to understand what “pull up” is about and I summarise it in the following short video. The video starts with the internal pull up disabled and without an external pull up resistor. You can see that the LED is on even when the button is open. Additionally, the voltage on RA3 is affected by moving my finger near it and we see that the LED flickers.

Then I place a 10K Ohm resistor between RA3 and +5v. This immediately stabilises the LED and it goes on only when the button is pressed.

Next I remove the resistor and replace the chip with another one that runs the program with the internal pull up enabled on pin RA3. In this case the LED behaves as expected and lights up only when the button is pressed.

Here is the video:

PIC – Motivation and Preparation

Learning to program and work with micro controllers is the fundamental step towards developing applications for quadcopters. Therefore I am going to spend some time on micro controller programming and share my new knowledge with my dear readers.

This first post will describe the micro controller that I chose to use and the preparation steps – what to buy and how to set it up.

I chose to work with the Microchip family of PIC micro controllers.

Why use Microchip PIC controllers?

I decided to accept my friend’s advice and start using PICs from the beginning. The main reasons for using PICs and not other controllers are:

  1. Price – they are cheaper then Atmel chips for example
  2. They exist for many years and are very reliable and stable
  3. Variety – there is a large number of controllers with different capabilities, so it should be possible to find a cost-effective controller for every application. Or, as Microchips says on their site: “Microchip provides solutions for the entire performance range of 8-bit, 16-bit, and 32-bit microcontrollers, with a powerful architecture, flexible memory technologies, comprehensive easy-to-use development tools, complete technical documentation and post design in-support”. And no, I don’t work for Microchip (but maybe I’ll ask them to put a link to my blog from their site).
  4. Tomer, my friend, uses PICs for his projects, so I can learn from him and ask for help when I get stuck. I think that at the end, this is the main reason for choosing PICs.

Preparations

We have to buy a few things and set them up before writing the first line of code for a PIC.

Stuff to buy

First of all you should decide which PIC micro controller you want to use and then buy one or two. You can get them from many sites on the net and in real stores. I decided to accept Tomer’s advice and use the PIC12F1822 just because it is cheap, simple and sufficient for my first project (a LED controller for my quadcopter) and … Tomer gave me two of them so I didn’t have to buy any.

The full shopping list is:

[table id=2 /]

Regarding the PICKit 3 programmer – Instead of buying the original Microchip product I bought a clone from eBay. It is cheaper but my MAC OS on two computers (Yosemite – running on a Mac Mini (mid 2011) and on a Macbook Pro 15 mid 2012) does not recognise it. I will describe a bad workaround below.

Tomer suggests putting the chip in a socket and moving it around inside the socket.

This is how this stuff looks like:

PIC Programming kit

Installation and set up

Download and install the Microchip MPLab X IDE and the XC 8 compiler. Both are free.

IDE: http://www.microchip.com/pagehandler/en-us/family/mplabx/

Compiler: http://www.microchip.com/pagehandler/en_us/devtools/mplabxc/

Download the data sheet for the PIC and start reading it. It is a fascinating ~400-page reading. In fact, you don’t have to read it all at once, but at least find the locations of the following pins of the chip that you need for programming:

  • VDD – power
  • VSS – ground
  • MCLR – I’m still figuring out what this is
  • ICSPDAT – programming data
  • ICSPCLK – programming clock

Download the PICKit3 user’s guide from here.

The IDE installer will offer to install the IDE and the IPE – the Integrated Programming Environment. Install both.

Connect the 6-wire programming connector to the PICKit 3 module (the red box) and connect the PICKit3 to the USB port of your PC.

Place the chip into the ICSP adapter and connect 5 wires of the programming connector to the corresponding pins of the adapter. The pinout of the programming interface are listed in page 10 of the PICKit3 user’s guide.

Then start the IPE – the integrated programming environment. Here is a screen shot of my IPE.

IPE screen shot

You should select the correct chip (Device) by first selecting the family and then selecting the chip from the drop-down menu. In the “Tool” field you should see the serial number of your PICKit 3. As you can see, the program does not identify my fake PICKit 3 so it says “Default_pk3”. This is not good but I have a work around for now and I intend to find the reason later.

Press on “connect” and it should connect (unlike my IPE above).

Once it is connected you are ready to go.

Workaround for using my clone PICKit3 on a MAC

The only workaround I found so far is to run a virtual Windows 7 guest on VirtualBox on my Mac. I place the project in a folder that is permanently shared with the guest machine. I run the IDE on the MAC and the IPE on the virtual Windows machine. I hope to find a solution before I need to use the debugger features of the PICKit 3.