tterev3's PIC quickstart guide

You and me both!

The BLF SRK - RGBWUVKLMNOXYZ Edition or “The dial a light” :smiley:

Yes, the 12F1822 is the perfect choice for writing in C on a tiny 8-pin part. I haven’t used them much in my mods simply because my work throws away lower-level parts (12F617) by the boatload, so I use those since I hate to see them go to landfill. If you pursue a project with the 12F1822 we would be able to port pieces of my MELD code right over to it (if that’s the kind of functionality you’re looking for)

Thank you again tterev3. I purchased the flasher you recommended above. So I will be flashing and that MCU you discussed is very affordable. I think I will first attempt to adapt my favorite Attiny13a FW to the 12F1822 first. I have to study to the 12F1822 datasheet more so that I can figure out what adjustments I would need to make to the code.

MELD looks like an incredible program. It just has so much more functionality that I feel I should tackle at this time. I really like your concept of having all those colors and UV in one light. I have separate, green, red and UV lights. It would be really cool to have all that available in one light. It's just too much for me at the moment. I need baby steps.

Thanks again for your very gracious sharing of your knowledge and efforts.

Here's an example program I put together for the 1822. It's a very simple flashlight with 3 brightnesses and a randomized strobe that changes modes on power cycle. This should help you get started with the 1822:

//v0 4/21/2014 by Everett
    //initial version
    //simple flashlight controller. mode change on power cycle

#include <htc.h>
#include <pic12f1822.h>

#define _XTAL_FREQ 8000000

__CONFIG(FOSC_INTOSC & WDTE_SWDTEN & PWRTE_ON & MCLRE_ON & CP_OFF & CPD_OFF & BOREN_ON & CLKOUTEN_OFF & IESO_OFF & FCMEN_OFF);
__CONFIG(WRT_BOOT & PLLEN_OFF & STVREN_ON & BORV_LO & LVP_OFF);

persistent unsigned char mode; //must be declared persistent for ram retention trick to work
enum mode{
max=0,
med=1,
low=2,
strobe=3,
};
#define max_mode 3
#define default_mode 0

#define on_time 15 //milliseconds

unsigned int strobe_timer;
unsigned char strobe_position;
bit on_off;
persistent unsigned int key;

void delayms(int milliseconds);
void configure(void);
unsigned char stun_rate_lookup(unsigned char input);

void interrupt isr(void)
{
if(TMR1IF){
TMR1IF=0;
}

if(TMR0IF){ //fires at 1kHz
    TMR0IF=0;
    if(strobe_timer){strobe_timer--;}   //count down milliseconds
}

}

void main(void)
{
configure(); //set up hardware peripherals

delayms(15);    //short delay to avoid power glitches incrementing mode

if(key==12345){     //RAM retention trick to detect quick power cycles
    mode++;         //go to next mode
    if(mode&gt;max_mode){mode=0;}
}   
else{           //long power loss. default to first mode
    mode=default_mode;
    key=12345;
}       


switch(mode){   //initialize current mode
    default:
    case max:
        CCPR1L=255;
        break;
    case med:
        CCPR1L=25;
        break;
    case low:
        CCPR1L=1;
        break;
    case strobe:
        strobe_timer=0;
        on_off=0;
        CCPR1L=0;
        break;
}       


GIE=1;  //turn on interrupts

while(1){
    
    if(mode==strobe){   //no other modes need active tasks while running
        if(strobe_timer==0){    //timer ran out
            on_off=~on_off; //flip it
            if(on_off){
                CCPR1L=255;
                strobe_timer=on_time;   //set on time
            }
            else{
                CCPR1L=0;
                strobe_position++;
                strobe_timer=stun_rate_lookup(strobe_position); //set off time
            }   //set output
        }   
    }
    
    
    
}   

}

unsigned char stun_rate_lookup(unsigned char input)
{
static const char table[72]=28,30,33,31,12,24,28,33,29,23,19,33,33,23,14,26,9,18,15,29,15,10,19,31,9,27,33,10,15,26,16,28,30,24,14,23,10,24,30,10,23,31,25,33,9,15,19,17,19,18,32,23,33,17,31,13,31,18,20,8,24,33,17,21,20,14,9,20,26,16,22,16;
if(input>71){input-=71;}
if(input>71){input-=71;}
if(input>71){input-=71;}
return table[input];
}

void delayms(int milliseconds)
{
while(milliseconds!=0){ __delay_ms(1); milliseconds–;}
}

void configure(void)
{
INTCON=0b01100000;
PIR1=0;
PIR2=0;
T1CON=0b00110001;
T2CON=0b00000101;
PR2=255;
TMR2=0;

LATA=0;
TRISA=0b11111011;
ANSELA=0b00000000;  //
WPUA=0b11111011;
APFCON=0;

OSCCON=0b01110011;  //8MHz
PIE1=0b00000000;
PIE2=0;
OPTION_REG=0b00000010;  //8 prescale for 1ms interrupts

// FVRCON=0b11000001; //1.024v to adc
// ADCON0=0b00001101; //
// ADCON1=0b00010000; //1/8, left justify, vref from vdd

CCPR1L=0;
CCP1CON=0b00001100;

}

__EEPROM_DATA(0,0,0,0,0,0,0,0);

__EEPROM_DATA(0, 0, 0, 0, 0, 0, 0, 0);
__EEPROM_DATA(0, 0, 0, 0, 0, 0, 0, 0);

__EEPROM_DATA('1','8','2','2',' ','f','l','a');
__EEPROM_DATA('s','h','l','i','g','h','t',' ');
__EEPROM_DATA('b','y',' ','E','v','e','r','e');
__EEPROM_DATA('t','t',' ','e','v','e','r','e');
__EEPROM_DATA('t','t','.','b','r','a','d','f');
__EEPROM_DATA('o','r','d','@','g','m','a','i');
__EEPROM_DATA('l','.','c','o','m',' ',' ',' ');

Simply amazing , great work tterev3 these mode settings are off the charts on the epic scale.

Thank you. Very good idea to start with code that works since someone new to PIC programing/flashing (like me) will probably be dealing with other first time issues. One less potential complication. Looks like the code is for a normal clickie type switch (on/off, half click to interrupt power). Is that correct?

That’s right, it will work with any light that interrupts power to cycle modes. The pwm output is on pin 5

Received my programmer today. Excited to start going down this path, but I will have to be patient as I have quite a few demands for my time right now, plus the Scratch Build Contest.

Thanks for the write up. In my brief experimentation with PIC, I found MPLAB-8 much clearer than MPLAB-X, and that was coming into it with ZERO experience. I might have to start using my PICKit 3 again...

Great info …on your third day. I’m going to go in to the corner and shudder remembering the one time I had to not just have a basic understanding of assembler on the mainframe but actually got stuck having to get in the code.

I'm doing a bit of reading and I'm really interested in using that little 6-pin PIC10F322. I've been looking at making a really small 3 mode flashlight driver for years, but don't want to use QFN parts. The PIC10F322 is actually small enough for my project! Obviously it can do PWM out, and I'm assuming it can accept a voltage divider input for battery monitoring (on it's single input-only pin). However, can I by any chance use the internal voltage reference to estimate the supply voltage (less parts required)?

Yes, an a-d conversion, with no resistor divider solution, per this thread Anybody doing custom UIs for 12F629 PIC?

Oh, sweet. Thanks.

Another question. I note in the OP that ttreve3 lists assembly beside the PIC10F322. Does this mean it will only work with assembly code, or does it simply mean there probably won't be enough room to use C on it? I was going to take the code supplied in post #18, remove the strobe and see if I could get that working on the PIC10F322.

No eeprom on the 10f322, although it can self write for a pseudo eeprom. A no nonsense driver shouldn’t be a problem using C, or even Basic.

This may give you an idea about who you're dealing with here, but I don't know what that means in regards to my application lol. So is this a waste of time? It's ttreve3's code with the strobe removed (I think...I would be grateful if someone would check it over). Will I be able to compile that in MPLAB 8 and flash it using my PICkit 3?

Edit: note I have not taken the time as yet to check things like registers line up etc. And seen as there is no eeprom the last section is likely a waste of time.

Correct on the _eeprom_data code, it is irrelevant, so just get rid of it. I don’t play with C, so can’t say what compiler problems you may encounter, if any, with MPLAB 8. The htc.h include file will give an indication on what compiler is being used, and compatibility.

Hi Matt, pastebin is blocked for me so I can't check your code, but here's an adaptation for the 10F322 that I've tested to work. only uses 33% of the code space as is. I also added in the voltage monitor to demonstrate that; it will force the mode from high to medium if battery goes below 3.0V. You can't use the input-only pin for ADC on this part, but the internal fixed voltage reference makes it possible to monitor supply voltage without using the pin.

//v0 5/1/2014 by Everett
    //initial version
    //simple flashlight controller. mode change on power cycle

#include <htc.h>
#include <pic10f322.h>
#define _XTAL_FREQ 8000000
__CONFIG(CP_OFF & BOREN_OFF & LVP_OFF & MCLRE_ON & WDTE_OFF & PWRTE_OFF & FOSC_INTOSC & WRT_HALF);

#define pwm PWM1DCH

persistent unsigned char mode; //must be declared persistent for ram retention trick to work
enum mode{
max=0,
med=1,
low=2,
};
#define max_mode 2
#define default_mode 0

persistent unsigned int key;
unsigned int v_timer;
bit v_sample;
#define voltage_rate 100 //milliseconds

void delayms(int milliseconds);
void configure(void);
unsigned char read_voltage(void);
void initialize_mode(void);

void interrupt isr(void)
{

if(TMR0IF){ //fires at 1kHz
    TMR0IF=0;
    if(++v_timer==voltage_rate){v_timer=0; v_sample=1;}
}

}

void main(void)
{
configure(); //set up hardware peripherals
delayms(15); //short delay to avoid power glitches incrementing mode
if(key==12345){ //RAM retention trick to detect quick power cycles
mode++; //go to next mode
if(mode>max_mode){mode=0;}
}
else{ //long power loss. default to first mode
mode=default_mode;
key=12345;
}

initialize_mode();  
GIE=1;  //turn on interrupts

while(1){
    
    if(v_sample){
        v_sample=0;
        if(mode==max){              //if battery goes below 3.0V in max mode, force down to medium mode
            if(read_voltage()&gt;87){
                mode=med;
                initialize_mode();
            }
        }
    }           
    
}   

}

void initialize_mode(void)
{
switch(mode){ //initialize current mode
default:
case max:
pwm=255;
break;
case med:
pwm=25;
break;
case low:
pwm=1;
break;
}
}

unsigned char read_voltage(void)
{
//fvr is at 1.024V. ADRES = 1.024/Vin*255. Vin = 1.024/(ADRES/255). voltage limit set to 3.0V -> 87. values below this correspond to voltage above 3.0V
GO_nDONE=1;
while(GO_nDONE);
return ADRES;
}

void delayms(int milliseconds)
{
while(milliseconds!=0){ __delay_ms(1); milliseconds–;}
}

void configure(void)
{
INTCON=0b00100000; //tmr0 only

T2CON=0b00000100; //on, no prescale
PR2=255; 
TMR2=0;
    
LATA=0;
TRISA=0b11111110;   //GP0 output
ANSELA=0b11110000;  //
WPUA=0b11111110;

OSCCON=0b01100000;  //8MHz

OPTION_REG=0b00000010;  //8 prescale for 1ms interrupts

FVRCON=0b10000001;  //1.024v to adc
ADCON=0b10111101;   // fvr

PWM1DCH=0;
PWM1CON=0b11000000; //on, output

}

 

Probably a dumb question, but here goes. Wouldn't a "C" program and an "Assembly" program, both written with the same functionality and same basic approach, compile about into the same sized "Machine" language program?

Depends on a lot of factors including programmer skill, how good the compiler is, mcu architecture, etc.
Also as a clarification, assembly doesn’t get compiled, it gets assembled (hence the name) because it is actually machine language, but with mnemonics to make it human-readable

Ah, thank you.