Author Topic: MPLAB X on PIC10F222, getting started.  (Read 19656 times)

0 Members and 1 Guest are viewing this topic.

Offline step_sTopic starter

  • Regular Contributor
  • *
  • Posts: 138
  • Country: dk
MPLAB X on PIC10F222, getting started.
« on: December 10, 2015, 08:46:23 pm »
Hi EEVblog.
I've just started playing around with microcontrollers and i have some PIC10F222 i wanted to try and program.
In my search I've watched some youtube videos, and different tutorials, but they are all different. Maybe it's due to the age of them.
The problem is with the code, and even in the most basic of basics, I get nowhere.
So I understand that TRIS is the register for the pins, and setting them to output or input, but I can't find the specific code for this.
Some videos seem to write "TRISbits", "TRISB" or "TRISIO". None of these work.

I'm completely lost, and there is very little info on MPLAB X IDE. . .
Any suggestions, or examples of simple codes for this chip?

Hope you can help.
 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: MPLAB X on PIC10F222, getting started.
« Reply #1 on: December 10, 2015, 10:06:12 pm »
PIC10F222 doesn't have a TRISB or TRISIO register (it has TRISGPIO, but this is not directly accessible). tutorials may be written to suit different chips. You should read the datasheet to find out what registers your PIC has.

To set I/O directions you load the bits into W and then execute the TRIS GPIO instruction. Bits set to 1 make the corresponding I/O bit an input, while bits set to 0 are outputs (note: GP3 is input only). These bits are often combined in a constant called 'TRISbits' as a convenience and to (perhaps) make the code easier to read.     
« Last Edit: December 10, 2015, 10:07:44 pm by Bruce Abbott »
 

Offline step_sTopic starter

  • Regular Contributor
  • *
  • Posts: 138
  • Country: dk
Re: MPLAB X on PIC10F222, getting started.
« Reply #2 on: December 10, 2015, 10:25:42 pm »
@Bruce
Thank you for your answer Bruce :)
I've read the datasheet and found that it does have a TRISGPIO, but how is this written then?
The datasheet says "TRISGPIO  ---- 1111" how is this written in the C code?
If i need the pins to be outputs, am i suppose to write it as hex, or how so?

Thank you for your help :)
 

Online MarkF

  • Super Contributor
  • ***
  • Posts: 2545
  • Country: us
Re: MPLAB X on PIC10F222, getting started.
« Reply #3 on: December 10, 2015, 10:58:14 pm »
I found some sample code from [solved] simple led blink with pic10f222 and xc8 compiler.
Code: [Select]
#include <xc.h>
/***** CONFIGURATION *****/
__CONFIG(MCLRE_OFF & CP_OFF & WDTE_OFF & MCPU_OFF & IOSCFS_4MHZ );
#define _XTAL_FREQ  4000000     // oscillator frequency for _delay()
/***** MAIN PROGRAM *****/
void main()
{
    // Initialization
    ADCON0 = 0;           // GP0 and GP1 configured as digital I/O
    OPTION = 0b00000111;  // If the T0CS bit is set to ‘1’, it will override the TRIS function on the T0CKI pin
    TRIS = 0b111000;      // configure GP2 (only) as an output

    // Main loop
    for (;;)
    {
        GPIO = 0b000100;        // turn on LED on GP2 (bit 1)
        __delay_ms(250);        // stay on for 200 ms
        GPIO = 0b000110;        // turn on LED on GP2 (bit 1)
        __delay_ms(250);        // stay on for 200 ms
        GPIO = 0b000111;        // turn on LED on GP2 (bit 1)
        __delay_ms(250);        // stay on for 200 ms
        GPIO = 0b000000;        // turn on LED on GP2 (bit 1)
        __delay_ms(250);
    }                           // repeat forever
}

The PIC10F222 does NOT work like a typical PIC.  I would recommend trying a different chip to learn on.  Maybe a PIC16F886 or a PIC18F2550.
 

Offline step_sTopic starter

  • Regular Contributor
  • *
  • Posts: 138
  • Country: dk
Re: MPLAB X on PIC10F222, getting started.
« Reply #4 on: December 10, 2015, 11:25:12 pm »
@Mark
Hi Mark, thank you for the post.
The  ADCON0 = 0; helped me to actually make the PIC work now.
I'm afraid that the MPLAB X IDE is ridden with problems (or so i read everywhere).
The delay function given in this example should work, by doesn't, due to . . . reasons.
The userguide for the XC8 has a command  _delay(40000); as an example, and this doesn't work either.
Would another compiler be better, or?

How is this PIC different from most others?

Thank you.
« Last Edit: December 10, 2015, 11:30:38 pm by step_s »
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12856
Re: MPLAB X on PIC10F222, getting started.
« Reply #5 on: December 10, 2015, 11:39:02 pm »
The PIC10F222 is a very ordinary baseline (12 bit core) PIC device. Its only noticeable quirk is that GP2/T0CKI defaults to being the T0CKI input and you must disable that to use it for ordinary I/O. 
N.B. As with any other PIC, to use analog capable pins GP0/AN), GP1/AN1 for digital I/O you must disable analog mode. See the ADCON0 SFR.

Your best bet is to start from the Gooligum tutorials: http://www.gooligum.com.au/PIC-tutorials/baseline-PIC-tutorial (Free, but requires registration to download)  which introduces the very similar (but less capable) PIC10F200 and the baseline PIC1xF50x family.   You will then be able to understand the sample code MarkF posted.
 

Online MarkF

  • Super Contributor
  • ***
  • Posts: 2545
  • Country: us
Re: MPLAB X on PIC10F222, getting started.
« Reply #6 on: December 10, 2015, 11:50:24 pm »
Here is how I do my delays:

Code: [Select]
#define _XTAL_FREQ 20000000L
#define delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0)))
#define delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))

MPLAB X is not my favorite editor but it gets the job done for me.  I haven't had a major issues with it.
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12856
Re: MPLAB X on PIC10F222, getting started.
« Reply #7 on: December 11, 2015, 12:03:14 am »
The delay defines are in the standard headers included by xc.h.  The only one you need to provide is the _XTAL_FREQ define.

Old versions of MPLAB X had a bug in the syntax hiliter's interaction with the XC8 toolsuite such that it incorrectly hilited the delay macros as errors, if you didn't either redefine them in your own code or use a workaround involving defining __PICC__ before #including xc.h.  MPLAB X v3.15 + XC8 v1.35 have no such issue.
 

Offline 0b01010011

  • Regular Contributor
  • *
  • Posts: 69
  • Country: au
Re: MPLAB X on PIC10F222, getting started.
« Reply #8 on: December 11, 2015, 03:02:45 am »
if you want a simple PIC to learn on but one that is a lot like others then the PIC10F322 is a good one, it has some more up to date peripherals, interrupts, etc.

the 10F2xx isn't a good learning example as they are fairly unique, much unlike all the PIC10F3xx/PIC12/PIC16 series.
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: MPLAB X on PIC10F222, getting started.
« Reply #9 on: December 11, 2015, 08:14:18 am »
Early-architecture PICs (12bit-wide instruction words) had a TRIS instruction rather than TRISx registers (there are TRISx registers mentioned in the datasheet, but if you look carefully, they don't have any "address" and aren't writeable by the normal movwf-type instructions.
When the 14bit PICs came along, the TRIS functions got moved to "regular" file register locations, and the TRISx instructions were deprecated.

I have to agree with others that a bare-minimum PIC like the 10F series is NOT a good place to start for someone just starting to look at microcontrollers.

(In a way, this illustrates a common progression of microcontroller architectures.  Early microcontrollers, like the PIC and 8051, have a lot of their instruction set dedicated to manipulating the IO ports/pins.  As you might expect, since they were explicitly designed to to do IO-like things.  But newer microcontrollers start to favor more general purpose instruction sets, with fewer weird instructions dedicated to IO.  By the time you get to a modern architecture like ARM, there are essentially no IO-specific instructions left at all.)
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12856
Re: MPLAB X on PIC10F222, getting started.
« Reply #10 on: December 11, 2015, 08:48:03 am »
Most importantly, on 12 bit (baseline) PICS, the TRIS register(s) and OPTION register are  WOM.   You cannot read them back.  You must therefore compose the required 8 bit value for all pins on the port or all OPTION flags and write the whole of it at one shot.  The compiler cant help you with an easy way to set/clear one of these flags (e.g.TOSE).on its own, because the hardware cant do that.
 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: MPLAB X on PIC10F222, getting started.
« Reply #11 on: December 11, 2015, 12:19:45 pm »
The datasheet says "TRISGPIO  ---- 1111" how is this written in the C code?
XC8 defines a special variable called 'TRIS'. When the compiler sees this it knows to produce the required code (see section 5.3.9 of the compiler manual for details). All you have to do is write eg:-

TRIS = 0b00001001; // bits 2 and 1 are clear, so GP2 and GP1 are outputs

Quote
If i need the pins to be outputs, am i suppose to write it as hex, or how so?
You can write it any way you like so long as the resulting number has the correct bits cleared. What I usually do is name any input bits and set them like so:-

#define INPUTX  0   // GP0, pin 1
#define INPUTY  3   // GP3, pin 6

TRIS = (1<<INPUTX)|(1<<INPUTY); // set input bits. All other bits are zero, and so will be outputs.
 
This way you can quickly change a pin assignment without having to hunt down and change raw numbers in different parts of your code.
 

Offline step_sTopic starter

  • Regular Contributor
  • *
  • Posts: 138
  • Country: dk
Re: MPLAB X on PIC10F222, getting started.
« Reply #12 on: December 11, 2015, 12:58:53 pm »
Here is how I do my delays:

Code: [Select]
#define _XTAL_FREQ 20000000L
#define delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0)))
#define delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))


Hi Mark. So when you have defined the delays, how to you include them in to the main code?
Are the "x" here just to tell the program that it's for the user to set at a later time?

Your best bet is to start from the Gooligum tutorials: http://www.gooligum.com.au/PIC-tutorials/baseline-PIC-tutorial (Free, but requires registration to download)  which introduces the very similar (but less capable) PIC10F200 and the baseline PIC1xF50x family.   You will then be able to understand the sample code MarkF posted.

Hi Ian. I just downloaded these, and they don't tell me a whole lot that i don't already know. They use the __delay_(ms) function, and this doesn't work. I have tried including delay.h and libpic30.h, but none of these will make the compiler run.

P.S. I just made some kind of progress. . . #define FCY 1, the value here apparently has no real meaning since every number does the same. Then using the _delay(x) code, where the X seems to be the amount of µseconds. The combiler has a small "unable to resolve identifier _delay." but has no errors when running.
Can anyone explain why this works? :P

Thank you.
« Last Edit: December 11, 2015, 01:25:06 pm by step_s »
 

Offline mariush

  • Super Contributor
  • ***
  • Posts: 5022
  • Country: ro
  • .
Re: MPLAB X on PIC10F222, getting started.
« Reply #13 on: December 11, 2015, 01:16:37 pm »
I wrote these for another project of mine, and the C file has delays for 16 Mhz , 8 Mhz and 4 Mhz ... but I only tested thoroughly the 16 Mhz ..see attachment

They probably work well only on PIC16 and newer, but you should check the datasheet to see how much time the instructions take to execute on pic10.. it could be they take the same amount of time.

Basically, it's taking advantage of the NOP and GOTO instructions to make your code do nothing for a period of time. On PIC16, NOP takes one cycle, GOTO takes 2 so by chaining a few of these and taking in account the cycles it takes to enter and exit a function and the time it takes to do  "for" or while .. you can make your program waste lots of time with just a few lines of code.
 

Online MarkF

  • Super Contributor
  • ***
  • Posts: 2545
  • Country: us
Re: MPLAB X on PIC10F222, getting started.
« Reply #14 on: December 11, 2015, 03:06:55 pm »
Here is how I do my delays:

Code: [Select]
#define _XTAL_FREQ 20000000L
#define delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0)))
#define delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))


Hi Mark. So when you have defined the delays, how to you include them in to the main code?
Are the "x" here just to tell the program that it's for the user to set at a later time?


Using the delays in code will look like:
Code: [Select]
void main() {
   while (1) {
      GPIO = 0b000100;        // turn on LED
      delay_ms(100);            // delay 100 ms
      GPIO = 0b000110;        // turn on LED
      delay_ms(200);            // delay 200 ms
      GPIO = 0b000111;        // turn on LED
      delay_ms(300);            // delay 300 ms
      GPIO = 0b000000;        // turn on LED
      delay_ms(400);            // delay 400 ms
   }
}

The compilier will turn this into:
Code: [Select]
void main() {
   while (1) {
      GPIO = 0b000100;        // turn on LED
      _delay((unsigned long)((100)*(_XTAL_FREQ/4000.0)))
      GPIO = 0b000110;        // turn on LED
      _delay((unsigned long)((200)*(_XTAL_FREQ/4000.0)))
      GPIO = 0b000111;        // turn on LED
      _delay((unsigned long)((300)*(_XTAL_FREQ/4000.0)))
      GPIO = 0b000000;        // turn on LED
      _delay((unsigned long)((400)*(_XTAL_FREQ/4000.0)))
   }
}

Think of delay_us(x) and delay_ms(x) as function calls instead of defines.  The difference is that every where in the code you place delay_us() or delay_ms() the complier will replace them with _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0))) or _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0))) respectively. 

The defined code will be repeated every where.  So if you're short on memory, you might want to make them actual functions instead of #defines.  The trade off is that you will save memory at the expense of execution time due to a function call.
 

Offline Delta

  • Super Contributor
  • ***
  • Posts: 1221
  • Country: gb
Re: MPLAB X on PIC10F222, getting started.
« Reply #15 on: December 11, 2015, 03:24:05 pm »
I got started with PICs using only the chip's datasheet and the assembler's user manual (only moved onto C later).  I found this much easier than trying to work through various online tutorials...

I find the Microchip datasheets very very good, if a bit verbose...
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12856
Re: MPLAB X on PIC10F222, getting started.
« Reply #16 on: December 11, 2015, 03:24:58 pm »
RTFM. (the XC8 one).  The compiler's own delay ms/us macros start with a double underscore and take a numeric constant as the parameter (never a variable or a C const).  As long as you have defined _XTAL_FREQ before you use them and don't exceed the max delay limits for _delay() given in the manual in terms of instruction cycles (Fosc/4), they just work, and have ever since XC8 was first released.

The *ONLY* header you need for most programs  is:
Code: [Select]
#include <xc.h>If a library function needs another header included, the manual will tell you.  This is not mainframe or PC hosted C and on a PIC10, you will *NEVER* need to include stdio.h, and scarcely ever stdlib.h.

Be aware that baseline PICs only have a two level hardware stack.   The compiler needs one stack level for reading const arrays using RETLW tables, so if you call graph has more than two levels if you use const strings or arrays, or three levels without such consts, the compiler will have to use a software stack, which will increase the code size.  You cant afford that on a PIC10.  Rule of thumb for baseline C coding:  Apart from main(), don't write a function that calls another function you wrote!
 

Offline step_sTopic starter

  • Regular Contributor
  • *
  • Posts: 138
  • Country: dk
Re: MPLAB X on PIC10F222, getting started.
« Reply #17 on: December 11, 2015, 04:42:57 pm »
Ah, thank you for explaining Mark.
I figured as much, and i see that you are using the _delay(x) command that i got working, and which is a reflection of the clock frequency somehow.
I guess it makes sense to do this trick in order to calibrate the counter to be more accurate, but the _delay(x) command uses less memory as long as you know what number you need to write.

It's beginning to make some more sense now, but is still very confusing xD

So now that i have these things working, can you guys help me on the next problem?
This chip needs to run a voltage indicator, so I need it to read the voltage on one pin, and save that to a string of sorts, so I can use the value elsewhere.
The datasheet states that this chip will use the VDD as voltage reference, and that the analog input will then be converted to a value between 0 and 255, where 5V is supplied and will be 255.
Any help on this one? :)
« Last Edit: December 11, 2015, 04:44:40 pm by step_s »
 

Online MarkF

  • Super Contributor
  • ***
  • Posts: 2545
  • Country: us
Re: MPLAB X on PIC10F222, getting started.
« Reply #18 on: December 11, 2015, 05:06:43 pm »
What voltage range do you need to sample?  As long as it's less than Vdd, the voltage will be the following:
   Vsample = Vdd * (ADRES / 256) where ADRES is the Analog Conversion Result Register.  See paragraph 7.8 of the pic10f222.
If the voltage you want to sample is greater than Vdd, you will need to setup of a resistor voltage divider and then scale Vsample accordingly.

All the information you need is in the data sheet.  Keep re-reading it until you understand what's needed.
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12856
Re: MPLAB X on PIC10F222, getting started.
« Reply #19 on: December 11, 2015, 05:33:35 pm »
IIRC the Gooligum baseline C tutorials includes using the ADC (lesson 7).  You will have to tweak the ADCON 0 ADC setup a bit as you are using a different PIC, but the basics of selecting a channel (ADC input pin), triggering a conversion and reading the result from ADRES will be the same.   

If you get stuck, post your code in code tags, or attach it and if it wont compile, post the compiler error messages in code tags.
 

Offline step_sTopic starter

  • Regular Contributor
  • *
  • Posts: 138
  • Country: dk
Re: MPLAB X on PIC10F222, getting started.
« Reply #20 on: December 11, 2015, 06:14:16 pm »
@Mark
@IAN
I'm really trying to figure out the datasheet, combined with the Googligum tutorials, and setting it up so that the PIC works! xD

Code: [Select]
unsigned int ADCvalue=0;

void main(void) {
   
   TRIS = 0b0001; //Set only GP0 to input
   ADCON0bits.ANS = 0b01; //Setting GP0 to analog
   ADCON0bits.CHS = 0b00; //Select channel ANS0
   ADCON0bits.ADON = 1; //Enable ADC
   
   while (1)
   {
                 
             while (GP3 = 0) //When button is pressed
              {
                ADCON0bits.GO = 1; //Start ADC
                _delay(1000); //Delay to know ADC is done
                ADCvalue = ADRES; //Store ADRES                                                                                           
                 }
              }       
   }
 

This is what I've got so far. This works in the compiler.
The question is now: How do I use the ADRES or the ADCvalue as an integer value for, let's say, a delay?
_delay(ADCvalue), something on these lines? Isn't the ADRES in binary? I would need it in decimals from 0 to 255.
I want to to make the LED blink with a speed set by the voltage on the input, as a start :)

Thank you guys!
« Last Edit: December 11, 2015, 06:34:29 pm by step_s »
 

Online MarkF

  • Super Contributor
  • ***
  • Posts: 2545
  • Country: us
Re: MPLAB X on PIC10F222, getting started.
« Reply #21 on: December 11, 2015, 06:33:11 pm »
This is how I would do it:
Code: [Select]
unsigned int value;

while (1) {
   // Read analog data
   ADCON0bits.GO=1;
   while (ADCON0bits.nDONE);
   value = ADRES;
   // Blink LED
   GPIO = 0b000100;   // Turn on LED
   delay_ms(value*4);   // Delay 0-1 sec
   GPIO = 0b000000;   // Turn off LED
}
« Last Edit: December 11, 2015, 06:36:05 pm by MarkF »
 

Offline step_sTopic starter

  • Regular Contributor
  • *
  • Posts: 138
  • Country: dk
Re: MPLAB X on PIC10F222, getting started.
« Reply #22 on: December 11, 2015, 06:41:48 pm »
This is how I would do it:
Code: [Select]
unsigned int value;

while (1) {
   // Read analog data
   ADCON0bits.GO=1;
   while (ADCON0bits.nDONE);
   value = ADRES;
   // Blink LED
   GPIO = 0b000100;   // Turn on LED
   delay_ms(value*4);   // Delay 0-1 sec
   GPIO = 0b000000;   // Turn off LED
}

It doesn't like that i stick the value directly into the delay. _delay(value) doesn't run.
Isn't the ADRES in binary btw? How is it convertet?
 

Online MarkF

  • Super Contributor
  • ***
  • Posts: 2545
  • Country: us
Re: MPLAB X on PIC10F222, getting started.
« Reply #23 on: December 11, 2015, 06:53:49 pm »
Okay.  It's probably because the #define is done at complie time instead of execution time.
You will need to call the _delay function directly.  Replace delay_ms() with _delay((unsigned long)((value*4)*(_XTAL_FREQ/4000.0))).

The ADRES value is a number between of 0 to 255.  This represents a voltage of 0 - Vdd volts on the input pin.  There are a number things you can do:
  • Convert the number to a voltage (Voltage = ADRES/256).  ADRES / 256 is a fraction of the PIC supply voltage (Vdd).
  • Use the ADRES number for some another function.  In your case, you want a delay in milli-sec.  So if you want a 1 sec delay you need a number of 0 to 1000 ms.  Hence, multiply the ADRES (0-255) value by 4.
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12856
Re: MPLAB X on PIC10F222, getting started.
« Reply #24 on: December 11, 2015, 06:59:35 pm »
@Mark: That wont work.

@O.P.
That is when you *NEED* to use a delay function or routine that will take a variable as a parameter rather than the compiler's built-in _delay() or  __delay_us(), __delay_ms() macros.  Mark's delay macros wrap _delay() so have the same 'no variables' limitation.

You could use one of the variable delay functions for XC8/HiTech C you will find scattered all over the net (and if you want a particularly accurate one for PICs with more memory, ask me), however on a PIC10, I'd do it a bit differently, because of the limited stack depth, RAM and FLASH.
Code: [Select]
   // Blink LED
   GPIO = 0b000100;   // Turn on LED
   for(i=0; i<ADRES; i++) __delay_ms(4);   // Delay 0-1 sec
   GPIO = 0b000000;   // Turn off LED

i should be declared as unsigned char at the start of the main() function.  As xc8 isn't officially C99 compliant yet, avoid the temptation to declare it in the for() statement.  Don't forget the #define _XTAL_FREQ 4000000UL

There's another pitfall here.  If you use i<=ADRES, the loop will never end if ADRES is 255, as i will wrap to zero before it can become greater than ADRES.



 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: MPLAB X on PIC10F222, getting started.
« Reply #25 on: December 12, 2015, 07:44:46 pm »
using the _delay(x) command that i got working, and which is a reflection of the clock frequency somehow.
_delay(x) simply executes a fixed number of CPU instructions which the compiler has pre-calculated will produce the required delay. It works because the PIC always takes the same amount of time to execute each instruction. Of course this timing is dependent on clock speed, so the compiler must be told what clock frequency the chip will be running at.

Note that this delay is not accurate when put into a program, because other code in the loop adds an unknown number of extra instructions. A few lines of C code could add 10s to 100s of microseconds.
     
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: MPLAB X on PIC10F222, getting started.
« Reply #26 on: December 12, 2015, 11:21:29 pm »
 
Quote
this delay is not accurate when put into a program, because other code in the loop adds an unknown number of extra instructions. A few lines of C code could add 10s to 100s of microseconds.
Quote
I want to to make the LED blink with a speed set by the voltage on the input
I doubt that 100 microsecond accuracy is needed for LED blinking :-)

Code: [Select]
    :
   value = ADRES;  // Get A-D value, 0-255
   // Blink LED
   GPIO = 0b000100;   // Turn on LED
   while (value--) {
      delay_ms(4);   // Delay 0-1 sec total. 4 ms for each A-D count.
   }
   GPIO = 0b000000;   // Turn off LED
 

Offline step_sTopic starter

  • Regular Contributor
  • *
  • Posts: 138
  • Country: dk
Re: MPLAB X on PIC10F222, getting started.
« Reply #27 on: December 13, 2015, 12:40:25 am »
@Mark: That wont work.

@O.P.
That is when you *NEED* to use a delay function or routine that will take a variable as a parameter rather than the compiler's built-in _delay() or  __delay_us(), __delay_ms() macros.  Mark's delay macros wrap _delay() so have the same 'no variables' limitation.

You could use one of the variable delay functions for XC8/HiTech C you will find scattered all over the net (and if you want a particularly accurate one for PICs with more memory, ask me), however on a PIC10, I'd do it a bit differently, because of the limited stack depth, RAM and FLASH.


Thank you for the post Ian :)
So what you are saying is that the _delay(x) function is not able to load variables directly. . . I'm a bit confused in trying to find another macro on the net, since all I seem to find is pretty much what Mark has written. If you had a suggestion for putting in a variable directly, it would be much appreciated :)

Quote
Code: [Select]
   // Blink LED
   GPIO = 0b000100;   // Turn on LED
   for(i=0; i<ADRES; i++) __delay_ms(4);   // Delay 0-1 sec
   GPIO = 0b000000;   // Turn off LED

i should be declared as unsigned char at the start of the main() function.  As xc8 isn't officially C99 compliant yet, avoid the temptation to declare it in the for() statement.  Don't forget the #define _XTAL_FREQ 4000000UL

There's another pitfall here.  If you use i<=ADRES, the loop will never end if ADRES is 255, as i will wrap to zero before it can become greater than ADRES.

So basicly this code  compares ADRES to the unsigned char, and if it's lower than ADRES, the char gets +1 and a 4ms delay is added. This will run until I = ADRES, and the LED wil light. Am i right? Is this a good way of doing it, or a necessary evil? :P

Thanks in advance!
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12856
Re: MPLAB X on PIC10F222, getting started.
« Reply #28 on: December 13, 2015, 01:08:28 am »
Its a good way of doing it on a PIC10 due to its limited resources, though you might also call it evil.  On a 14 bit cire PIC18 or an 16 bit core PIC18, a carefully tuned delay function is better: See http://www.microchip.com/forums/m877727.aspx
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: MPLAB X on PIC10F222, getting started.
« Reply #29 on: December 13, 2015, 02:45:38 am »
I would normally do:
Code: [Select]
void delay_ms(int n)  // delay for a variable number of ms
{
   while (n--)
      __delay_ms(1);  // delay that requires a constant.
}

main() {
    :
   value = ADRES;
    :
   delay_ms(value);

And only didn't because of the known limitations of the PIC10 (call stack, variable space, questionable amount of C compiler optimization.)
(It would probably be "educational" to run several of these suggestions through your compiler and compare the assembly code produced.)
(A "reasonably good" compiler would inline the function call and notice that "value" would be overlapped with n, and you'd get the same code.)
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12856
Re: MPLAB X on PIC10F222, getting started.
« Reply #30 on: December 13, 2015, 02:53:57 am »
Code: [Select]
do{ __delay_ms(1); }while(--n);Has less loop overhead provided n is unsigned char, as the loop compiles to a DECFSZ and a GOTO or BRA (under HiTech C or XC8), but it has the disadvantage that n=0 takes 256 loops, and the small overhead doesn't matter if you are running off a +/-1% to 2% internal oscillator.
 

Online MarkF

  • Super Contributor
  • ***
  • Posts: 2545
  • Country: us
Re: MPLAB X on PIC10F222, getting started.
« Reply #31 on: December 13, 2015, 04:43:58 am »
@Mark: That wont work.

@O.P.
That is when you *NEED* to use a delay function or routine that will take a variable as a parameter rather than the compiler's built-in _delay() or  __delay_us(), __delay_ms() macros.  Mark's delay macros wrap _delay() so have the same 'no variables' limitation.

You could use one of the variable delay functions for XC8/HiTech C you will find scattered all over the net (and if you want a particularly accurate one for PICs with more memory, ask me), however on a PIC10, I'd do it a bit differently, because of the limited stack depth, RAM and FLASH.


Thank you for the post Ian :)
So what you are saying is that the _delay(x) function is not able to load variables directly. . . I'm a bit confused in trying to find another macro on the net, since all I seem to find is pretty much what Mark has written. If you had a suggestion for putting in a variable directly, it would be much appreciated :)

Quote
Code: [Select]
   // Blink LED
   GPIO = 0b000100;   // Turn on LED
   for(i=0; i<ADRES; i++) __delay_ms(4);   // Delay 0-1 sec
   GPIO = 0b000000;   // Turn off LED

i should be declared as unsigned char at the start of the main() function.  As xc8 isn't officially C99 compliant yet, avoid the temptation to declare it in the for() statement.  Don't forget the #define _XTAL_FREQ 4000000UL

There's another pitfall here.  If you use i<=ADRES, the loop will never end if ADRES is 255, as i will wrap to zero before it can become greater than ADRES.

So basicly this code  compares ADRES to the unsigned char, and if it's lower than ADRES, the char gets +1 and a 4ms delay is added. This will run until I = ADRES, and the LED wil light. Am i right? Is this a good way of doing it, or a necessary evil? :P

Thanks in advance!

Using --delay_ms(1) inside a loop will be the best and easiest way to implement a delay in most cases.  Another option would be to use one of the timers (if one is available).  However this is quit involved.  I would only use a timer (with or without interrupts) if you need a long delay or have special timing requirements.
 

Offline step_sTopic starter

  • Regular Contributor
  • *
  • Posts: 138
  • Country: dk
Re: MPLAB X on PIC10F222, getting started.
« Reply #32 on: December 13, 2015, 12:10:21 pm »
Okay guys, thanks for all the great answers!
So after looking at your suggestions I have made the following code:

Code: [Select]
#define _XTAL_FREQ 80000000UL
#define delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/40000.0)))

unsigned char i;
unsigned char j;

void main(void) {

   ADCON0bits.ANS = 0b01; //Setting GP0 to analog
   ADCON0bits.CHS = 0b00; //Select channel ANS0
   ADCON0bits.ADON = 1; //Enable ADC
   OPTION = 0b00000000; //Disable all OPTION to enable GP2
   TRISGPIO = 0b00001001; //Set GP0 and GP3 to input
     
   while (1)
   {
       GP1 = 0; //Resets LEDS
       GP2 = 0; //Resets LEDS
       
       while (GP3 = 0); //Button press
       {
          ADCON0bits.GO=1; // Read analog data
          while (ADCON0bits.nDONE); // Wait for A/D to convert 
       
         i = ADRES; // Transfers ADRES to i
         j = ADRES; // Transfers ADRES to j
         GP1 = 1;   // Turn on RED LED
         GP2 = 0;   // Turn off BLUE LED
         for(i=0; i<ADRES; i++) delay_ms(18);   // Delay = 1sec/v
         GP1 = 0;   // Turn off RED LED
         GP2 = 1;   // Turn on BLUE LED
         for(j=255; j>ADRES; j--) delay_ms(18);   // Delay = 1sec/v
       }
     }
   } 
I have a two colored blue/red LED connected, and this will make it blink depending on the voltage.
By raising the divider in (_XTAL_FREQ/40000.0) to give a lower delay, I can make the LED blink with a speed that makes for an intermittent color red->purple->blue.
This is pretty much what i wanted, but now i have two problems:
How can I make the LED switching on/off into a separate delay, so that they will stay flickering in the intermittent color for a short while,
after the button press? A loop inside a loop I would guess? I can't seem to find any PWM functions on this PIC, since this would cut off some code,
and make me explore some new features + make for a better LED driver.
Also, I need some sort of "interval" on the voltage, since this is for a lithium cell, and it will need the color to be red at 3V and go towards blue at 4.2V.

I might be overlooking some simple things right now, but I just got up. . forgive me xD
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12856
Re: MPLAB X on PIC10F222, getting started.
« Reply #33 on: December 13, 2015, 12:36:08 pm »
Its a baseline PIC so there are no interrupts, no PWM and if you want to do anything concurrent at different time scales(e.g. read a button and PWM a LED), your only choice is a state machine in a fast superloop.

If you upgraded to a midrange device you get timer interrupts, so could do software PWM in the background, and in the case of the pin-compatible PIC10F320/322 chips, you also get two hardware PWM modules so can 'set and forget' the LED colour, and the hardware will maintain it while you code does other stuff.

Edit: dead link switched to wayback machine archive
« Last Edit: June 27, 2016, 10:15:39 am by Ian.M »
 

Offline Howardlong

  • Super Contributor
  • ***
  • Posts: 5319
  • Country: gb
Re: MPLAB X on PIC10F222, getting started.
« Reply #34 on: December 13, 2015, 02:03:34 pm »
You could use the watchdog timer to delay turn off, this is the closest you'll get to an "interrupt" on that device, but it resets, so at the beginning on main() you have to check to TO, PD and GPWUF bits of the status register to determine what caused the reset.

All of this is fiddly and makes for difficult to read code. While it can and is done, I'd agree with Ian and jump up to the 10f320/322 if you need the same form factor device for the reasons he cites.

Alternatively, stick with what you have, and if you get it to work reasonably well it will be a great learning experience. Sometimes, though, if there's no need to beat yourself with a stick, then don't!
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12856
Re: MPLAB X on PIC10F222, getting started.
« Reply #35 on: December 13, 2015, 02:32:37 pm »
There's no need to beat yourself with several sticks.

There are perfectly good baseline parts with a lot more pins if you want to learn assembler programming on the 12 bit core as an intellectual 'hair shirt' exercise: e.g. PIC16F527 which has 20 pins including a full 8 bit port C so you can output whole bytes to LEDs to debug it.  e.g. if you are feeling flush, hang two N.O.S. TIL311 Hex decoded 7 segment LEDs off it for direct readout.  Me? I make do with binary readout on a 10 LED bar graph and a 330R resistor array.

The highly pin constrained PIC10 parts should only be used when size and weight are ultimate requirements.  Due to the low pin count it is often difficult to arrange the application circuit to permit in-circuit programming without adding a lot of extra components, so its usual to order them pre-programmed.  Use of the PIC10 DIP packages other than for pure development is a sign of insanity, you might as well use a PIC12 and get two more I/Os, or free ICSP/ICD pins.

The cost savings of using an under-specified chip are usually so small that the added development costs involved with torturing your programming team till the code fits wont be recovered till somewhere between 10K and 100K units have been sold.  Don't do it, especially not for small volume and one-offs.
« Last Edit: December 13, 2015, 03:08:18 pm by Ian.M »
 

Offline Howardlong

  • Super Contributor
  • ***
  • Posts: 5319
  • Country: gb
Re: MPLAB X on PIC10F222, getting started.
« Reply #36 on: December 13, 2015, 02:59:58 pm »
All of what Ian.M stated.

Even with the debug header versions of the very low end devices, debugging is painful, typically with only one breakpoint for example, so you can't single step and have a separate code breakpoint.

As a general rule for these devices, I develop on a near identical device with a few more pins for debugging (blinky pins, and in circuit debugging/programming) and if necessary port back to the real thing.

The only thing I use these the PIC10F2xx for has been to program up chip registers on power up like clock generators. For that they're great, but not for anything much more complex.
 

Offline step_sTopic starter

  • Regular Contributor
  • *
  • Posts: 138
  • Country: dk
Re: MPLAB X on PIC10F222, getting started.
« Reply #37 on: December 13, 2015, 05:19:27 pm »
Thank you all for the great advice. I just leaped in to this with no knowledge at all, so it means a lot!
I see now that the chip is quite inadequate for the task I wanted it to do.
Say I wanted to upgrade to a better suited PIC, and i wanted to make it in to a complete project for the lithium cell. Looking at the PIC16 family with 14 pins, would any of these be able to do the task of:

Have the battery indicator formulated in this thread (Only 2 color LED version is needed).
Be able to run a step up converter for lithium cell to 5V, at a reasonable frequency (500kHz-1MHz).
Be able to run a step down converter for 5V to lithium cell.
Have room for a few other button press features for some extra fun.

My first thought was to just have a step down converter to the cell, to charge it from a 5V source, up to around 4V (since most converters have a 1-1.2V gap from input), and then have a linear chip take over for the last 0.35V. This was in order to prevent overheating when the battery voltage was low in the first part of charging (the batteries are 3200mah 4.35V cell).
Then after that, have a step up converter with a good solid output, from the cell to a 5V output (already played around with some good SOT-23 1.5A ones).
At the end have this small PIC10 run a voltage indicator. For a total of 3 x SOT-23 package chips, and a few other components.

Maybe i should make a new thread on this, but any help is much appreciated! :)
 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: MPLAB X on PIC10F222, getting started.
« Reply #38 on: December 13, 2015, 05:44:12 pm »
By raising the divider in (_XTAL_FREQ/40000.0) to give a lower delay,
Don't do this. The delay_ms() function will then not be milliseconds, but something else.  If you want a shorter delay then change the value of x in delay_ms(x). If 1ms is too long then change the name of your macro to something more appropriate, eg. delay_us() or my_delay().

Use a define so you only have to change the delay value in one place, like this:-

#define  TICK 18
...
         for(i=0; i<ADRES; i++) delay_ms(TICK);   // Delay = 1sec/v


Quote
How can I make the LED switching on/off into a separate delay, so that they will stay flickering in the intermittent color for a short while, after the button press? A loop inside a loop I would guess?
Yes, just create an outside loop that repeats the blinking pattern a certain number of times after the button press.

Quote
I can't seem to find any PWM functions on this PIC, since this would cut off some code, and make me explore some new features + make for a better LED driver.
First get it to work properly, and don't get carried away trying to make it 'better' or adding features unless there is a real need for it.   

The first thing I would look at is ADC accuracy. To get a stable result you will probably have to take several readings and average them.

Quote
Also, I need some sort of "interval" on the voltage, since this is for a lithium cell, and it will need the color to be red at 3V and go towards blue at 4.2V.
Subtract 3V from the ADC reading (or make it zero if already less then 3V). If the analog input is scaled to get a reading 255 at 4.2V then you have 16.5mV per step. 3V/16.5mV = 182. Subtract 182 from the ADC reading and you get a range of 0-73 representing 3.0 to 4.2 Volts.

Make your flicker routine loop 73 times, with a step delay of 1/73 = 13ms giving a 1 second flicker period (or use a shorter delay if you want it to flicker faster). When the loop count is less than or equal to the ranged ADC value turn the Blue LED on and the Red LED off, when it is above do the opposite.

Quote
I see now that the chip is quite inadequate for the task I wanted it to do.
It is quite adequate for what you wanted it to do.
 
Quote
Looking at the PIC16 family with 14 pins, would any of these be able to do the task of:

Have the battery indicator formulated in this thread (Only 2 color LED version is needed).
Be able to run a step up converter for lithium cell to 5V, at a reasonable frequency (500kHz-1MHz).
Be able to run a step down converter for 5V to lithium cell.
Have room for a few other button press features for some extra fun.
Some of the latest chips may be able to do all that, but do you have the programming skills to get it all working properly?

Quote
the batteries are 3200mah 4.35V cell
This is a large cell and potentially very dangerous. I would not consider using a PIC to charge it unless I was very sure that my code was safe.
 

« Last Edit: December 13, 2015, 05:46:30 pm by Bruce Abbott »
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12856
Re: MPLAB X on PIC10F222, getting started.
« Reply #39 on: December 13, 2015, 06:08:48 pm »
A MCP19111 has enough processing power (a 8MHz PIC midrange core) and a realtime analog synchronous buck control loop sufficient to implement LiPO battery charging and management with minimal external components apart from a pair of MOSFETs.  However it cant directly handle boosting the LiPO to 5V unless you want to write a software driven boost converter and certainly cant do that at  >500KHz so would need an external boost converter for the application output  5V regulator, although it could monitor and control one.

It certainly isn't a 14 pin part, and as Bruce has pointed out, DIY LiPO management in software requires excellent programming skills and a high level of justified self-confidence.  Many consultants would be cautious taking that project on.  Its certainly *NOT* novice friendly.

You are going about this the wrong way.   The question shouldn't be "What midrange 14 pin PIC can do all this?", it should be "What PIC or other brand MCU can tie together chips or hardware modules to monitor and control the following tasks, while operating over the full voltage range of a LiPO battery and drawing negligible current when off/quiescent?" and "How is my choice constrained by the T.C.O. of the tools to develop for and debug in-circuit my shortlist of MCUs?".     Finally, beware of feeping creaturitis creeping featuritis!
 

Offline step_sTopic starter

  • Regular Contributor
  • *
  • Posts: 138
  • Country: dk
Re: MPLAB X on PIC10F222, getting started.
« Reply #40 on: December 13, 2015, 06:34:48 pm »
@Bruce
True, it does what I wanted it to do, basicly, and it has still been quite insightful. I understand. . . keep the code understandable. Keep ms in ms and us in us!
How would this outside loop look like? The 3-4.2v range is done! Thanks :)
It does seem like too much work to program a PIC when the fact is that the step-up and step-down IC's can be had in SOT-23 packages (same size as the switching MOSFETs I would need anyway), and it is tried and tested. Reliability over all.
@Ian
I get your point. What works best together, and how simple and effective can it be done. I will try to not catch featuritis xD
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12856
Re: MPLAB X on PIC10F222, getting started.
« Reply #41 on: December 13, 2015, 06:53:27 pm »
Got a PICkit 3?  If so I'd be looking at debug capable (without extra headers) enhanced midrange PIC16F1xxx parts in 14 pin DIP for development and 16 lead QFN for the final version.  The 16 lead QFN package is only 4mm x 4mm which is no larger than a PIC12 SOIC-8 footprint.  There are no other PIC families in such a small package that have *ANY* members with built-in debug support.  Dedicating the ICSP/ICD pins to development that leaves you with 9 I/Os for your application and hopefully not *TOO* much feeping creaturitis.   The internal band-gap references aren't that great so you'll probably have to calibrate the ADC.   Beware: not all PICs with a band-gap FVR module can actually feed that to the ADC module as the +Vref internally.  Check datasheet and errata *BEFORE* designing one in! 
 

Offline Howardlong

  • Super Contributor
  • ***
  • Posts: 5319
  • Country: gb
Re: MPLAB X on PIC10F222, getting started.
« Reply #42 on: December 13, 2015, 07:15:49 pm »
I concur regarding the MCP19111, it seemed like a great part, but when I got into the nitty gritty with it wasn't quite so nice. For example, it talks about being able to deal with supplies/chargers with Vout > 3.6v by using a simple potential divider: it can't, if you want current limiting, unless you use an external current sense device, which you'll then have to somehow interface to the MCP19111 ISEN differential inputs, and a simple pair of potential dividers won't work. I lost a week or two of my life on that part.

Doing buck/boost in not trivial. Start with buck, then move up.

For measuring current beyond the voltage range of your device, typically you either measure it with reference to ground with a current sense resistor (and all the issues you then have with a semi-floating ground) or use an external current sense part.
 

Offline step_sTopic starter

  • Regular Contributor
  • *
  • Posts: 138
  • Country: dk
Re: MPLAB X on PIC10F222, getting started.
« Reply #43 on: December 13, 2015, 07:44:46 pm »
@Ian
Got a Sure PicKit 3 clone. The PIC16F1xxx series seem like a really nice, and small PIC in the SMD version. Sure has lot's of PWM capabilities.
Talking about debugging and calibrating the ADC seems quite confusing right now, that i just learned these other new things!  :P
You have some kind of suggestion for the delay function of the button that Bruce was talking about? The external loop?

@Howardlong
I will try this out in the future :)
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12856
Re: MPLAB X on PIC10F222, getting started.
« Reply #44 on: December 13, 2015, 08:15:44 pm »
Did you read the 'superloop' link I gave in post#33?

To do the Batt status LED active delay from the button push, I'd implement a superloop with a sandwich delay of no greater than 100ms, (preferably in the 10ms to 20ms range), using a hardware timer.   

In the superloop it would have various tasks implemented as state machines so they can all execute and either do nothing or the appropriate action for that moment.  Any delays used would be minimal and only for unavoidable bit-banging of serial bus protocols to control peripheral chips.  If any task needed a delay, it would count passes of the superloop until the time for its next action.  All tasks would return as near immediately as possible.

So with that out of the way, you'd need the following:
* ADC task, responsible for updating a Batt_voltage variable
* Button task, responsible for monitoring and debouncing the button
* LED task, responsible for lighting the LEDs in the correct pattern until its time to turn them off again.

Its then a matter of choice whether you make each task monitor global variables and flags to determine when to run, or whether you minimise such interfaces by having a:

* SYSCON task responsible for timing and deciding when to start/stop other tasks.

On anything except a baseline PIC, I'd use one function per task.  On a baseline PIC, if I couldn't trust the compiler to inline stuff properly, I'd use a compound statement (block enclosed by { }) for each task, carefully commented just inside the {, directly in main().
« Last Edit: December 13, 2015, 08:56:04 pm by Ian.M »
 

Online MarkF

  • Super Contributor
  • ***
  • Posts: 2545
  • Country: us
Re: MPLAB X on PIC10F222, getting started.
« Reply #45 on: December 13, 2015, 08:38:07 pm »
Okay guys, thanks for all the great answers!
So after looking at your suggestions I have made the following code:

Code: [Select]
#define _XTAL_FREQ 80000000UL
#define delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/40000.0)))

unsigned char i;
unsigned char j;

void main(void) {

   ADCON0bits.ANS = 0b01; //Setting GP0 to analog
   ADCON0bits.CHS = 0b00; //Select channel ANS0
   ADCON0bits.ADON = 1; //Enable ADC
   OPTION = 0b00000000; //Disable all OPTION to enable GP2
   TRISGPIO = 0b00001001; //Set GP0 and GP3 to input
     
   while (1)
   {
       GP1 = 0; //Resets LEDS
       GP2 = 0; //Resets LEDS
       
       while (GP3 = 0); //Button press
       {
          ADCON0bits.GO=1; // Read analog data
          while (ADCON0bits.nDONE); // Wait for A/D to convert 
       
         i = ADRES; // Transfers ADRES to i
         j = ADRES; // Transfers ADRES to j
         GP1 = 1;   // Turn on RED LED
         GP2 = 0;   // Turn off BLUE LED
         for(i=0; i<ADRES; i++) delay_ms(18);   // Delay = 1sec/v
         GP1 = 0;   // Turn off RED LED
         GP2 = 1;   // Turn on BLUE LED
         for(j=255; j>ADRES; j--) delay_ms(18);   // Delay = 1sec/v
       }
     }
   } 

A programming note here:
Code: [Select]
         i = ADRES; // Transfers ADRES to i
         j = ADRES; // Transfers ADRES to j
Setting i and j do nothing in your code.  The first thing the "for" loops do is to set i and j to zero.
Also, you don't need two separate variables for the two loops.  You could use either i or j in both loops. 
Your "for" loops will initialize i and j to zero when entering the loop and incrementing them at the end of each pass through the loop.
 

Offline owiecc

  • Frequent Contributor
  • **
  • Posts: 315
  • Country: dk
    • Google scholar profile
Re: MPLAB X on PIC10F222, getting started.
« Reply #46 on: December 13, 2015, 08:53:36 pm »
I ordered a PicKit3 and got a dev board with PIC16F1459 on it. It has a USB port. You get programming templates for OS X, Windows and Linux (MLA) so you can easily make an app to connect to your PIC.
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12856
Re: MPLAB X on PIC10F222, getting started.
« Reply #47 on: December 13, 2015, 09:02:31 pm »
While that is a nice little chip for lightweight I/O via USB,  *NOONE* in their right minds uses an 8 bit or 16 bit USB capable PIC for applications that don't need a USB interface.  There's no need to pay extra for the USB SIE, loose I/O pins to it, and get a crappier set of peripherals due to the die area it takes up.  The *ONLY* excuse is for a hobbyist who is having to settle for what's stocked locally because they cant order internationally.

(The equation's a bit different with PIC32 as the feature set you need may not be availabele *without* USB)
 

Offline step_sTopic starter

  • Regular Contributor
  • *
  • Posts: 138
  • Country: dk
Re: MPLAB X on PIC10F222, getting started.
« Reply #48 on: December 13, 2015, 09:22:48 pm »
Did you read the 'superloop' link I gave in post#33?

To do the Batt status LED active delay from the button push, I'd implement a superloop with a sandwich delay of no greater than 100ms, (preferably in the 10ms to 20ms range), using a hardware timer.   

In the superloop it would have various tasks implemented as state machines so they can all execute and either do nothing or the appropriate action for that moment.  Any delays used would be minimal and only for unavoidable bit-banging of serial bus protocols to control peripheral chips.  If any task needed a delay, it would count passes of the superloop until the time for its next action.  All tasks would return as near immediately as possible.

So with that out of the way, you'd need the following:
* ADC task, responsible for updating a Batt_voltage variable
* Button task, responsible for monitoring and debouncing the button
* LED task, responsible for lighting the LEDs in the correct pattern until its time to turn them off again.

Its then a matter of choice whether you make each task monitor global variables and flags to determine when to run, or whether you minimise such interfaces by having a:

* SYSCON task responsible for timing and deciding when to start/stop other tasks.

On anything except a baseline PIC, I'd use one function per task.  On a baseline PIC, if I couldn't trust the compiler to inline stuff properly, I'd use a compound statement (block enclosed by { }) for each task, carefully commented just inside the {, directly in main().


I read it now and understand the concept, but fail in seeing how to implement it. I see the PIC has a TMR0 internal timer, but how do use this function?
You want to divide all of the tasks in to separate tasks, but defining them or?
Sorry, but I'm a bit confused :P

@Mark
Ye, thanks for keeping an eye out. . I saw the stupidity myself :)
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12856
Re: MPLAB X on PIC10F222, getting started.
« Reply #49 on: December 13, 2015, 10:05:37 pm »
Sticking with your PIC10F222 for the moment, configure Timer 0 for internal (Fosc/4) clock with a prescaler of /128 for 4MHz Fosc or /256 for 8MHz Fosc.  That means that starting from zero, the top bit of timer 0 will toggle every 16.4ms (aprox).  Unfortunately there is no overflow flag for the timer so we cant do it the way we would on a non-baseline PIC.

The superloop and sandwich delay code becomes:
Code: [Select]
while(1){
   TMR0=0; // Start sandwich delay: 16.384ms (nominal) 'ticks'

   // tasks go here

   while(!(TMR0&0x80)); // Wait for TMR0 top bit to end sandwich delay
}

The LED task goes something like:
Code: [Select]
{ // LED blinking task
    static unsigned char LEDtime=0;  // LED timer in complete flickers
    static unsigned char LEDcnt=MAXVOLTS;    // LED counter for flicker

    if(button) LEDtime=5; // five complete flicker cycles per button push

    if(LEDtime) {
        LEDtime--;       
        if(LEDcnt>BattVolts) GPIO=RED; else GPIO=BLUE;
        if(!LEDcnt--) LEDcnt=MAXVOLTS; //reset flicker counter
    }
}
and of course you'll also need #defines for the bits to output for RED and BLUE and the scaled and offset  ADC count MAXVOLTS corresponding to 3.4V on the LiPO. 

Bugfixed: missing ; in if() ... else ... and corrected the TMR0 prescaler ratios. 
« Last Edit: December 14, 2015, 01:05:19 am by Ian.M »
 

Offline step_sTopic starter

  • Regular Contributor
  • *
  • Posts: 138
  • Country: dk
Re: MPLAB X on PIC10F222, getting started.
« Reply #50 on: December 13, 2015, 11:19:05 pm »
Thanks on the code, but I'm afraid it's not really making sense to me. .
The superloop and sandwich delay code becomes:
Code: [Select]
while(1){
   TMR0=0; // Start sandwich delay: 16.384ms (nominal) 'ticks'

   // tasks go here

   while(!(TMR0&0x80)); // Wait for TMR0 top bit to end sandwich delay
}
So i have set the prescaler to 1:256 (max value, should give longer time?), but the last bit: while(!(TMR0&0x80));  what does the ! and the & do?
Quote
The LED task goes something like:
Code: [Select]
{ // LED blinking task
    static unsigned char LEDtime=0;  // LED timer in complete flickers
    static unsigned char LEDcnt=MAXVOLTS;    // LED counter for flicker

    if(button) LEDtime=5; // five complete flicker cycles per button push

    if(LEDtime) {
        LEDtime--;       
        if(LEDcnt>BattVolts) GPIO=RED else GPIO=BLUE;
        if(!LEDcnt--) LEDcnt=MAXVOLTS; //reset flicker counter
    }
}
and of course you'll also need #defines for the bits to output for RED and BLUE and the scaled and offset  ADC count MAXVOLTS corresponding to 3.4V on the LiPO.     
This entire bit went completely over my head. .
Sorry for the n00bishness Ian :/
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: MPLAB X on PIC10F222, getting started.
« Reply #51 on: December 14, 2015, 12:24:23 am »
Irrespective of all the other comments:
Code: [Select]
while (GP3 = 0); //Button pressThat while loop will never execute.  You need an "==" instead of the "=" !
 

Offline Howardlong

  • Super Contributor
  • ***
  • Posts: 5319
  • Country: gb
Re: MPLAB X on PIC10F222, getting started.
« Reply #52 on: December 14, 2015, 12:39:15 am »
Irrespective of all the other comments:
Code: [Select]
while (GP3 = 0); //Button pressThat while loop will never execute.  You need an "==" instead of the "=" !

 :-+

There are those who have, and those who will!
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12856
Re: MPLAB X on PIC10F222, getting started.
« Reply #53 on: December 14, 2015, 12:59:09 am »
If you *don't* have a copy of K&R 2nd ed, you can get by with The C Book, 2nd ed. by Banahan, Brady & Doran.  Its not as well organised but it covers the essentials fairly thoroughly.

Turn to the sections on logical and bitwise operators (2.6 and 2.9 in K&R, 3.3 and 2.8.2.3 in The C Book) and lookup the bitwise AND and logical negation operators.  You will now be equipped to dissect
Code: [Select]
while(!(TMR0&0x80));.   

* First note the trailing ;, this while() loop has no 'payload' - all it does is spin on the spot while its condition is TRUE.  The comment 'Wait for ....' confirms that is my intention.

* Now look in the innermost bracket.  Unfortunately XC8 doesn't define a bitfield for the highest bit of Timer 0 and, unlike any PIC with interrupts, there is no flag set when it rolls over. We need a bitmask to extract the highest bit.  The mask is 0x80 and after ANDING with Timer 0 we have a value that is either 0 0r 0x80. 

* However the requirement is to keep looping till that bit sets, so outside the inner brackets is the negation (NOT) operator.  That converts 0x80 (or any other non-zero value) to 0 (FALSE) and 0 to 1 (TRUE). 

XC8 is fairly smart, and even the free mode recognises this idiom as a test and loop on a single bit  and optimises it to:
Code: [Select]
    85  1FB                     l392:
    86                           ;main222.c: 6: while(!(TMR0&0x80));
    87                           
    88  1FB  7E1                btfss 1,7 ;volatile
    89  1FC  BFB                goto l392
If I'd used the conceptually much simpler:
Code: [Select]
while(TMR0<0x80);it would use far more instructions as it would need to load the constant into W, compare it with TMR0 and then test a STATUS flag to decide what to do:
Code: [Select]
    85  1F9                     l392:
    86                           ;main222.c: 6: while(TMR0<0x80);
    87                           
    88  1F9  C80                movlw 128
    89  1FA  081                subwf 1,w ;volatile
    90  1FB  703                skipc
    91  1FC  BF9                goto l392
You really have to grok the instruction set to get the best out of XC8 on these tiny devices.

The next chunk had a mistake, a missing semicolon in the if() ... else ...:
Code: [Select]
{ // LED blinking task
    static unsigned char LEDtime=0;  // LED timer in complete flickers
    static unsigned char LEDcnt=MAXVOLTS;    // LED counter for flicker

    if(button) LEDtime=5; // five complete flicker cycles per button push

    if(LEDtime) {
        LEDtime--;       
        if(LEDcnt>BattVolts) GPIO=RED; else GPIO=BLUE;
        if(!LEDcnt--) LEDcnt=MAXVOLTS; //reset flicker counter
    }
}
The two static unsigned char variable declarations declare local variables that are initialised on startup then retain their values from one invocation of the task block to the next.

if(button) LEDtime=5;  waits for the flag button to be set by the button task, it then sets the flicker cycke count to five.   The button task will clear the flag on the next pass so this only happens once per debounced press.  Alternatively you could let the flag stay set as long as the button is held and the LED task would keep doing the flicker pattern.

    if(LEDtime) {
        LEDtime--;
checks LEDtime and if TRUE, decrements it to count down flicker cycles remaining.

        if(LEDcnt>BattVolts) GPIO=RED; else GPIO=BLUE; turns on the red LED if the flicker counter is greater than the battery voltage otherwise it turns on the blue LED. It also turns off the other colour LED at the same time.  I'm assuming there are only two output pins and each  LED is on one of them.  Bugfix: inserted ; before else.

        if(!LEDcnt--) LEDcnt=MAXVOLTS; //reset flicker counter
counts down for the flicker level and when it wraps around from zero, does what it says and resets it to MAXVOLTS, which Bruce suggested should be 73 in post#38.


   

« Last Edit: December 14, 2015, 04:19:03 am by Ian.M »
 

Offline step_sTopic starter

  • Regular Contributor
  • *
  • Posts: 138
  • Country: dk
Re: MPLAB X on PIC10F222, getting started.
« Reply #54 on: December 14, 2015, 02:53:23 am »
Thank you for explaining Ian. Much appreciated!
When I'm done with my psychology exams, I will pick up a few books on this  :D
From these last posts, I have made the following code:

Code: [Select]
#define _XTAL_FREQ 80000000UL
#define delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/400000000.0)))
#define delay 1000

unsigned char i;

void main(void) {

   ADCON0bits.ANS = 0b01; //Setting GP0 to analog
   ADCON0bits.CHS = 0b00; //Select channel ANS0
   ADCON0bits.ADON = 1; //Enable ADC
   OPTION = 0b00000110; //Enable GP2, & set TMR0 rate 1:128
   TRISGPIO = 0b00001001; //Set GP0 & 3 to input, GP1 & 2 to input
     
   while (1)
   {
       static unsigned char LEDtime= 0; // Char that stays coded

       GP1 = 0; // Resets LEDS
       GP2 = 0; // Resets LEDS
       
       if (GP3 ==0) LEDtime=252; // Button press
   
       if(LEDtime) // If LEDtime = 0
       {
        LEDtime--; // Decrements LEDtime with 1
          ADCON0bits.GO=1; // Read analog data
          while (ADCON0bits.nDONE); // Wait for A/D to convert 
        // LED color setting, fast switching
         GP1 = 1;   // Turn on BLUE LED
         GP2 = 0;   // Turn off RED LED
         for(i=160; i<ADRES; i++) delay_us(delay);   // Delay, 3.2V ref
         GP1 = 0;   // Turn off BLUE LED
         GP2 = 1;   // Turn on RED LED
         for(i=205; i>ADRES; i--) delay_us(delay);   // Delay, 4.2V ref
         GP1 = 1;   // Turn on BLUE LED
         GP2 = 0;   // Turn off RED LED
         for(i=160; i<ADRES; i++) delay_us(delay);   // Delay, 3.2 V ref
         GP1 = 0;   // Turn off BLUE LED
         GP2 = 1;   // Turn on RED LED
         for(i=205; i>ADRES; i--) delay_us(delay);   // Delay, 4.2V ref
         
         if (ADRES<155) //If V<3.1
         { // Blinks red 4 times if under 3.1V
             LEDtime=LEDtime-62; // Decrements LEDtime with 62
             GP2 = 1; // Turn on RED LED
             delay_us(6000000); // 1sec delay
             GP2 = 0; // Turn off RED LED
             delay_us(6000000); // 1sec delay       
         }
         }
   } 
}
As it says in the descriptions. This will show blue at 4.2V, shift to purple, and end at red at 3.2V, for 2sec when button is pressed. If the battery voltage drops below 3.1V, the LED will blink red 4 times instead.
The LED flicker part with the delay from ADRES is pasted twice, for an easy way to double the time shown.

Please let me know if anything looks silly. Even though this works, that doesn't mean that there isn't room for improvements :)
 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: MPLAB X on PIC10F222, getting started.
« Reply #55 on: December 15, 2015, 07:44:37 pm »
Please let me know if anything looks silly. Even though this works, that doesn't mean that there isn't room for improvements :)
It works, but your code is a bit hacky and hard to follow, and may easily break if you have to change it. You can improve readability by converting 'magic' numbers to descriptive identifiers and letting the compiler do the grunt work.

First thing I would do is assign each LED to its GPIO port with a #define, like this:-

#define RedLED_ON  GP2=1
#define RedLED_OFF GP2=0

Then, instead of having to add a comment to remind you what 'GP2 = 1' does, you can just do this:-
 
        RedLED_ON;
 
It's a bit more effort initially, but makes the code more readable and will save a lot of time if you ever need to change it. Also you avoid introducing bugs due to not changing all instances.

Avoid putting comments in places where they aren't necessary, and make sure they match the code! For example,

             delay_us(6000000); // 1sec delay

is obviously not a 1 second delay.

On the other hand, liberally comment code whose operation is not obvious. It took me a while to figure out how you got the Red LED to reliably blink 4 times on low voltage. You subtract 62 from the count and stop when it gets to 0, which only works because it was previously decremented in the fast switching code and the initial count (252) is an exact multiple of 63.

 LEDtime=LEDtime-62; // Decrements LEDtime with 62
 
...is a useless and misleading comment. That it subtracts 62 is obvious, but why 62? Also the code will break if you change LEDtime and don't adjust this line to match.

I would do something like this:-

#define BLINKTIME 63  /* count to subtract from LEDtime when blinking Red LED on low voltage */

 if (GP3 ==0) LEDtime = BLINKTIME*4; // set count to keep showing LED display after button released
...
 LEDtime = LEDtime - (BLINKTIME-1); // -1 to account for decrement in fast switching

Or, change the algorithm it so that on low voltage it avoids the fast switching code altogether. That way you can adjust the timing of each function separately and don't have to worry about interaction between them.   
 
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf