MODbus/RTU on a PIC Microcontroller

By request one of my long lost blogs was a MODbus RTU application for a PIC 18F27J53. You could easily plop this onto many of the 18F series micros. It doesn’t do much but it’s a great stepping stone for throwing in your own IO. I’ll probably follow up with an Arduino version in a while.. I’ll put it on my “todo” list.

The code…

/*
 File:   main.c
 Author: Charles M Ihler
 Contact at: http://iradan.com
 *
 Created on November 8, 2014, 2:37 PM
 *
 Target Device:
 18F27J53 Development Board by AtomSoft
 *
 Project: MODbus/RTU slave
 *
 Notes
 We will ignore both query high bytes for now
 TODO:   Pull all hard coded IO out eventually and set it up via USB?
 Maybe a terminal application for enabling points?
 *
 *
 Version:
 0.02     Controlled sends caned reply on request to address on RS-232
 0.03     CRC works on RX
 0.04     No actual IO yet..
 Function 0x02 (Read Input Status) Started
 0.05     Ported to 18F17J53 for expanded IO/USB options.
 12MHz XTAL with CPUDIV set to 16MHz
 *
 / //#ifndef _XTAL_FREQ //#define _XTAL_FREQ 16000000 // //#define __delay_us(x) _delay((unsigned long)((x)(_XTAL_FREQ/4000000.0)))
 //#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))
 //#endif 
 // PIC18F27J53 Configuration Bit Settings
 // 'C' source line config statements
 include 
 // #pragma config statements should precede project file includes.
 // Use project enums instead of #define for ON and OFF.
 // CONFIG1L
 pragma config WDTEN = OFF      // Watchdog Timer (Disabled - Controlled by SWDTEN bit)
 pragma config PLLDIV = 3       // PLL Prescaler Selection (Divide by 3 (12 MHz oscillator input))
 pragma config CFGPLLEN = ON    // PLL Enable Configuration Bit (PLL Enabled)
 pragma config STVREN = ON      // Stack Overflow/Underflow Reset (Enabled)
 pragma config XINST = OFF       // Extended Instruction Set (Enabled)
 // CONFIG1H
 pragma config CPUDIV = OSC3_PLL3// CPU System Clock Postscaler (CPU system clock divide by 3 from 48MHz)
 pragma config CP0 = OFF        // Code Protect (Program memory is not code-protected)
 // CONFIG2L
 pragma config OSC = HSPLL      // Oscillator (HS+PLL, USB-HS+PLL)
 pragma config SOSCSEL = HIGH   // T1OSC/SOSC Power Selection Bits (High Power T1OSC/SOSC circuit selected)
 pragma config CLKOEC = OFF      // EC Clock Out Enable Bit  (CLKO output enabled on the RA6 pin)
 pragma config FCMEN = OFF      // Fail-Safe Clock Monitor (Disabled)
 pragma config IESO = OFF       // Internal External Oscillator Switch Over Mode (Disabled)
 define _XTAL_FREQ 16000000 //defined for delay
 char    ctxt[10], buf1, testcrc[4];    //buff serial string volatile unsigned int     ping, isrcall, index, reading, new_rx; int address, crc_high, crc_low, i, querylength; unsigned int result; //these variables are for fuctions to be enabled/disabled and pushed into application code via later int frame, z, bufferbits, query_reg_address, y; char data_out[64]; char reg_address[255];
 /*
  *
 Interrupt Service
 *
 UART RX and Timer 1
 *
 */
 void interrupt ISR() {
 if (PIR1bits.RCIF)          // see if interrupt caused by incoming data
 {
     isrcall = 0x01;
     char temp;
     temp = RCREG;     // read the incoming data
     buf1 = temp;
     if(temp==address && reading==0)      //if my address..
     {
         index = 0;                  //reset index
         reading = 1;                //from now on go to else if
         LATCbits.LATC1 = 1;
         new_rx = 0;
         ping = 1;
     }
     else if(reading == 1)           //in middle of GPS sentence
     {
         //TODO reset timeout timer
         ctxt[index] = temp;         //load it up
         index++;                    //increment index
         ping = 1;                   //this is for debugging
         if(index > 6)              //1+7 = master frame.
             {
             index = 0;              //reset index
             reading = 0;            //no longer storing the string
             new_rx = 1;             //"ding"
             T1CONbits.TMR1ON = 0;
             }
     }
 }
 //RCSTA2bits.FERR = 0;    //Clear errors
 //RCSTA2bits.OERR = 0;
 //time out timer, if tripped new_rx=0;
 if (PIR1bits.TMR1IF)
 {
     new_rx=0;
     ping = 0;
     T1CONbits.TMR1ON = 0;
     PIR1bits.TMR1IF = 0;
     if (reading) {
     reading = 0;
     LATCbits.LATC0 = 1;
     }
 }
 } 
 void init_io(void) {
 INTCONbits.GIE = 0;         //no interruptions please ADCON0 = 0b00000000;        //don't need any ADC ADCON1 = 0b00000000;        //speed Vref=AVdd, VssRef=AVss LATA = 0x00; LATB = 0x00; LATC = 0x00; TRISAbits.TRISA0 = 1; // address 1 TRISAbits.TRISA1 = 1; // address 2 TRISAbits.TRISA2 = 1; // address 3 TRISAbits.TRISA3 = 0; // output TRISAbits.TRISA5 = 0; // output TRISBbits.TRISB0 = 0; // TRISBbits.TRISB1 = 1; // TRISBbits.TRISB2 = 0; // TRISBbits.TRISB3 = 0; // TRISBbits.TRISB4 = 0; //  TRISBbits.TRISB5 = 1; //  TRISBbits.TRISB6 = 0; //  TRISBbits.TRISB7 = 0; //  TRISCbits.TRISC0 = 0; // timer LED output TRISCbits.TRISC1 = 0; // output TRISCbits.TRISC2 = 0; // LED test output TRISCbits.TRISC3 = 0; // output //TRISCbits.TRISC4 = 1; // USB //TRISCbits.TRISC5 = 1; // USB TRISCbits.TRISC6 = 0; // output TX1 TRISCbits.TRISC7 = 1; // input  RX1
 }
 void __delay_10ms(unsigned char n)     //__delay functions built-in can't be used for much at this speed… so!
  {
      while (n-- != 0) {
          __delay_ms(10);
      }
  }
 void uart_xmit(unsigned int mydata_byte) {
 while(!TXSTAbits.TRMT);    // make sure buffer full bit is high before transmitting TXREG = mydata_byte;       // transmit data
 }
 void write_uart(const char txt) {                                 //this send a string to the TX buffer                                 //one character at a time        while(txt)
        uart_xmit(*txt++);
 }
 void serial_init(void)
 {
     //9600 8N1
 TXSTA1bits.SYNC = 0; TXSTA1bits.BRGH=1;       // select low speed Baud Rate (see baud rate calcs below) TXSTA1bits.TX9=0;        // select 8 data bits TXSTA1bits.TXEN = 1;     // enable transmit RCSTA1bits.SPEN=1;       // serial port is enabled RCSTA1bits.RX9=0;        // select 8 data bits RCSTA1bits.CREN=1;       // receive enabled SPBRG1=102; SPBRGH1=0; PIR1bits.RCIF=0;        // make sure receive interrupt flag is clear PIE1bits.RCIE=1;        // enable UART Receive interrupt INTCONbits.PEIE = 1;    // Enable peripheral interrupt INTCONbits.GIE = 1;     // enable global interrupt  __delay_10ms(5);        // give time for voltage levels on board to settle
 }
 void run_timer (void) {
     T1CONbits.TMR1ON = 0;
     TMR1=0;
     TMR1L=0x00;
     TMR1H=0xAA;
     T1CONbits.TMR1CS = 0x01;
     T1CONbits.T1CKPS = 0x01;
     PIE1bits.TMR1IE = 1;
     T1CONbits.TMR1ON = 1;
 //        PIR1bits.TMR1IF=0;
 }
 void check_my_address(void) {
     /*
      *  Determine what address the unit is based on DIP switches
      *  PORTAbits.RA0   Switch 1
      *  PORTAbits.RA1   Switch 2
     */
 if (PORTAbits.RA0 & PORTAbits.RA1) address = 0x04; if (!PORTAbits.RA0 & PORTAbits.RA1) address = 0x03; if (PORTAbits.RA0 & !PORTAbits.RA1) address = 0x02; if (!PORTAbits.RA0 & !PORTAbits.RA1) address = 0x01;
 }
 /*
 TODO
 Poll the inputs
 *
 I will probably use a 74138 to address banks with 74HC245 for byte/banks of inputs
 I will likely use the same set up for "Coils"
 For input registers (analog inputs) I will consider perhaps some kind of A/D input with CD4066+74HC138
 *
 */ 
 void poll_my_inputs(void) {
 //just stuff it with something for now for (z = 0; z < 64; ++z) { reg_address[z] = z; }
 }
 /*
 did the chicken come before the egg?
 this MODbus CRC bit was gently borrowed from the internet..
 I can't determine who wrote it.. it shows up in an Ardiuno Sketch for MODbus
 Modbus over serial line - RTU Slave Arduino Sketch
 with referenced of Juan Pablo Zometa, Samuel Marco, Andras Tucsni, Philip Costigan
 It also shows up on a number of websites and forums uncredited… many PIC or C based ..
 so who knows, but I didn't write it
 The MODbus CRC-16 function is outlined on the Modicon site for reference
 */
 unsigned int modbus_crc(unsigned char buf[], int start, int cnt)
 {
 int     i,j;
 unsigned temp, temp2, flag;
 temp=0xFFFF;
 for (i=start; i<cnt; i++){
    temp=temp ^ buf[i];
 for (j=1; j<=8; j++){       flag=temp & 0x0001;      temp=temp >> 1;
      if (flag) temp=temp ^ 0xA001;
      }
   }
 /*** Reverse byte order. ***/
 temp2=temp >> 8;
 temp= (temp << 8) | temp2;
 return(temp);
 } 
 int check_master_crc (void) {
 int diff, diff1, diff2;       //what we send back char data[6]; result = 0x0000; crc_high = 0x00; crc_low = 0x00; data[0] = address;  //this is ugly but all master queries are 6bytes+CRC so it'll do data[1] = ctxt[0];  //function data[2] = ctxt[1];  //start_addressH data[3] = ctxt[2];  //start_addressL data[4] = ctxt[3];  //# of regH data[5] = ctxt[4];  //# of regL result = modbus_crc(data,0,6); crc_high = result >> 8; crc_low = result & 0x00FF; diff1 = ctxt[5] ^ crc_high; diff2 = ctxt[6] ^ crc_low; diff = diff1 + diff2; //this spits back an XORed value between calculated and received CRC return(diff);
 }
 void respond_input_status(void) {
         //ctxt[1] start_addressH
         //ctxt[2] start_addressL
         //ctxt[3] # of regH
         //ctxt[4] # of regL
     querylength = ctxt[4];  //ignoring upper byte for now (TODO)
     query_reg_address = ctxt[2]; //ignoring upper address byte (TODO)
 frame = 0;     //data frame counter do {     data_out[frame] = reg_address[query_reg_address];     //TODO  make this do somethng     querylength--;     frame++; } while (querylength>0); querylength = ctxt[4];  //reload so we can count time transmitting data result = modbus_crc(data_out,0,2); crc_high = result >> 8; crc_low = result & 0x00FF; //uart_xmit response address, function, data_out[frames], CRC uart_xmit(address); uart_xmit(ctxt[0]); frame = 0; do {     uart_xmit(data_out[frame]);     //TODO  make this do somethng     querylength--;     frame++; } while (querylength>0); uart_xmit(crc_high); uart_xmit(crc_low);
 }
 int main(void) {
     OSCCONbits.SCS = 0x00;
 new_rx=0; init_io(); serial_init(); run_timer(); check_my_address(); y += address; write_uart("MODBus "); uart_xmit(y); LATCbits.LATC0 = 1; LATCbits.LATC1 = 1; __delay_10ms(50); LATCbits.LATC0 = 0; LATCbits.LATC1 = 0; if (address == 0x01){     LATCbits.LATC0 = 1; } if (address == 0x02) {     LATCbits.LATC1 = 1; } __delay_10ms(50); LATCbits.LATC0 = 0; LATCbits.LATC1 = 0; INTCONbits.GIE = 1; INTCONbits.PEIE = 1; while (1) {     //If read data, not me and then if no 232 traffic for >800us then any xmit over     //104 us (9600) x 8 quiet periods minus some for wiggle.     if (ping) {         run_timer();     }     if (new_rx) {       //this device was polled         //testing response         i = check_master_crc();     //check master query crc         if (i==0x00) {              //CRC Ok?             if (ctxt[0] == 2) {       //coil status query                 respond_input_status();             }             //TODO other types of functions go here         }         //all done, get ready for new query         new_rx = 0;     }     //testcrc[0] = 0xFF;     //testcrc[1] = 0x02;      //right now this is only thing processed     //result = modbus_crc(testcrc,0,2);     //crc_high = result >> 8;     //crc_low = result & 0x00FF;     __delay_10ms(10);     LATCbits.LATC2 = 1; //LED blinky test     __delay_10ms(10);     LATCbits.LATC0 = 0;     LATCbits.LATC1 = 0;     LATCbits.LATC2 = 0; }
 }

WWVB Time Signal Generator Test w/ HEX

[Edit: I’ve added the .asm code in the “Code” page in the menu above. Below you can find the .HEX file for easy programming]

A successful test on my WWVB signal generator. I’m going to shy away from calling it a transmitter because I don’t think there is any allowances for any broadcasting on 60KHz, so to stay legal I would imagine you’d need to conform to part 15, shield everything, use an attenuator and dump the signal into a shielded box with the clock? I somehow doubt the FCC checks up on sub-mW transmissions on 60KHz though.

The concept is simple, 1 baud rate transmission of a 60 frame packet. The amplitude shift keying (ASK) system WWVB transmits is recreated using a CMOS CD4066 switch. Dump a 60KHz sine wave (keeping in mind maximum input/output signal specifications) into one of the switch ports. Use the output on PORTB.0 of the PIC to control the switch and the other side of the switch goes to you device under test (I used a couple feet of wire as an antenna and just placed the wire in the neighborhood of the clock receiver). It’s a no brainer. Check out the NIST site on WWVB if you want more details. I’ll probably re-port the code to a 12F629 when I get my new PICKit3 in and I’ll likely build a board with a 60KHz generator.. maybe I’ll even sell it on Tindie if I’m feeling ambitious.

The Test! I was getting my ass kicked earlier this week as my circuit was not working and it seemed like everything was just right. It did force me to really tweak my timing to make it within my range of error on being able to measure the exact pulse widths, I don’t know how precise it has to be but I assume that’s up to the algorithm decoding the signal. Turns out it wasn’t my code or circuit.. My $15 Fred Meyer “black friday special” atomic clock doesn’t work. It won’t receive the real WWVB (set up aligned with Boulder, CO away from electronics, blah blah). I was getting the proper signals out of the module, so I yanked the module out of the clock and hooked it up to a receiver designed by N0QBH. I mirrored his project here. He has a website for the project here. I used his schematic, ditched the need for the LCD and just grabbed my data off the RS232. Done! You can see a before and after output screenshot in the photos below.

My WWVB signal generator code (HEX) for a 16F628A is found here . Is it lame of my just to provide the HEX? yeah…. but all you need to do is hook up PORTB.0 to switching input of a 4066 with a signal generator feeding a 60KHz sine wave and you’re in business. (And a resistor pulling /MCLR (PORTA.5) up as well if that wasn’t obvious? I’m using the internal oscillator; no xtal needed).  You are stuck with my fixed date of course.. which is why you want my assembly code right? No problem. Just ask… really (comment or e-mail). I don’t want to post it because I don’t really like comment trolls. This code is super BETA but at an acceptable starting point. Lots of opportunity for optimizing it as well.  Why didn’t I improve on this code? Because I don’t need to. I’m just using it to test receivers I’ve purchased from the UK and I’ll be working on a project with those in a little while.

My time/date is static here is a snippet of the main line code:

    CALL    MARKER                      ;MARKER FRAME REFERENCE BIT
    CALL    ONE                         ;40min
    CALL    ZERO                        ;20min
    CALL    ZERO                        ;10min
    CALL    ZERO                        ;Reserved
    CALL    ZERO                        ;8mins
    CALL    ZERO                        ;4mins
    CALL    ONE                         ;2mins
    CALL    ZERO                        ;1mins
    CALL    MARKER                      ;MARKER 1

… and so for some photos

signal from PIC before ASK modulation accomplished by switching a CMOS CD4066 with a 60KHz sine wave from a frequency generator.
signal from PIC before ASK modulation accomplished by switching a CMOS CD4066 with a 60KHz sine wave from a frequency generator.

 

WWVB receiver module removed from clock

The clock with the module removed, luckily they printed the pin diagram on the board. 5V, Gnd, PON, and TCO

WWVB Signal Generator and Receiver on Breadboard

Both the generator and receiver on the breadboard. The transistors form the RS-232 driver for the receiver.

Before and after on the RS232 output of the WWVB receiver
Before and after on the RS232 output of the WWVB receiver

 

PWM on the PIC16F1509 in ASM

[Edit: If you’re looking for NCO (numerically controlled oscillator) usage instead of the PWM module take a look here instead. However note the code is in C (for XC8) not ASM]

Another lazy Sunday… A lot of OT the last few weeks at work and Sunday about the only day I have for relaxation so to clear my mind I wrote some test code for Pulse Width Modulation on a development board I purchased from @TINDE made by @TAUTIC . I’ll attach the code for anyone to use.

MPLAB on the laptop with a @TAUTIC / @TINDE dev board with a PWM test output.
MPLAB on the laptop with a @TAUTIC / @TINDE dev board with a PWM test output.

The code outputs on PWM1 (RC5) at about 1Khz at just under 50% duty cycle but that easy to change if you read the Microchip 16F1508/9 spec sheet section 23.

;*******************************************************************************
;                                                                              *
;    Microchip licenses this software to you solely for use with Microchip     *
;    products. The software is owned by Microchip and/or its licensors, and is *
;    protected under applicable copyright laws.  All rights reserved.          *
;                                                                              *
;    This software and any accompanying information is for suggestion only.    *
;    It shall not be deemed to modify Microchip?s standard warranty for its    *
;    products.  It is your responsibility to ensure that this software meets   *
;    your requirements.                                                        *
;                                                                              *
;    SOFTWARE IS PROVIDED "AS IS".  MICROCHIP AND ITS LICENSORS EXPRESSLY      *
;    DISCLAIM ANY WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING  *
;    BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS    *
;    FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL          *
;    MICROCHIP OR ITS LICENSORS BE LIABLE FOR ANY INCIDENTAL, SPECIAL,         *
;    INDIRECT OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, HARM TO     *
;    YOUR EQUIPMENT, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR    *
;    SERVICES, ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY   *
;    DEFENSE THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER      *
;    SIMILAR COSTS.                                                            *
;                                                                              *
;    To the fullest extend allowed by law, Microchip and its licensors         *
;    liability shall not exceed the amount of fee, if any, that you have paid  *
;    directly to Microchip to use this software.                               *
;                                                                              *
;    MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE OF    *
;    THESE TERMS.                                                              *
;                                                                              *
;*******************************************************************************
;                                                                              *
;    Filename:      main.asm                                                   *
;    Date:          Sept 29 2013                                               *
;    File Version:  1.0                                                        *
;    Author:        Charles Douvier                                            *
;    Company:                                                                  *
;    Description:   Test of PWM1                                               *
;
;    Device 16F1509
;
;
;
;
; PIN DIAGRAM
;
;   RA0                             RC0
;   RA1                             RC1
;   RA2                             RC2     STATUS LED
;                                   RC3
;   RA4             RB4             RC4
;   RA5             RB5             RC5     PWM1
;                   RB6             RC6
;                   RB7             RC7
;
;------------------------------------------------------------           *
;*******************************************************************************
;                                                                              *
;    Notes: In the MPLAB X Help, refer to the MPASM Assembler documentation    *
;    for information on assembly instructions.                                 *
;                                                                              *
;*******************************************************************************
;                                                                              *
;    Known Issues: This template is designed for relocatable code.  As such,   *
;    build errors such as "Directive only allowed when generating an object    *
;    file" will result when the 'Build in Absolute Mode' checkbox is selected  *
;    in the project properties.  Designing code in absolute mode is            *
;    antiquated - use relocatable mode.                                        *
;                                                                              *
;*******************************************************************************
;                                                                              *
;    Revision History:
;           2013-09-28  Initial                                                *
;                                                                              *
;*******************************************************************************

;*******************************************************************************
; Processor Inclusion
;
;*******************************************************************************
    errorlevel -230, -302, -303, -313
    LIST R=DEC
#include "p16f1509.inc"
;*******************************************************************************
;
; Word Setup
;
;
;*******************************************************************************
    __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _CLKOUTEN_OFF
    __CONFIG _CONFIG2, _LVP_OFF & _STVREN_ON
;*******************************************************************************
;
;  Variable Definitions
;
;*******************************************************************************
; TODO PLACE VARIABLE DEFINITIONS GO HERE
;*******************************************************************************
; Reset Vector
;*******************************************************************************
RES_VECT  CODE    0x0000            ; processor reset vector
    GOTO    START                   ; go to beginning of program
;*******************************************************************************
; TODO INSERT ISR HERE
;*******************************************************************************
; MAIN PROGRAM
;*******************************************************************************
MAIN_PROG CODE                      ; let linker place main program
INIT:
                            ;RC5 = PWM1
    BANKSEL LATA            ;Data Latch
    CLRF LATA               ;
    BANKSEL ANSELC          ;
    CLRF ANSELC             ;Digital IO
    BANKSEL PORTC           ;
    BCF PORTC,5             ;Clear PWM1
    BANKSEL TRISC           ;Set all PORTC to outputs
    CLRF TRISC
    BANKSEL PORTC
    BSF PORTC,2
    BANKSEL OSCCON
    MOVLW   0x78            ;16MHZ Clock
    MOVWF   OSCCON
    BANKSEL PWM1CON         ;
    CLRF PWM1CON            ;Disable PWM bits
    BANKSEL PR2
    MOVLW 0xFF
    MOVWF PR2               ;Load PR2 with 0xFF
                            ;Timer/PR set up is 973Hz
    BANKSEL PWM1DCH
    CLRF PWM1DCH
    BANKSEL PWM1DCL
    CLRF PWM1DCL
    BSF PORTC,2
    BANKSEL PWM1DCH
    MOVLW   0x6F
    MOVWF   PWM1DCH

                            ;copied code, havent check this yet.
    ;ENABLE INTERRUPT
    BANKSEL PIE1
    BSF PIE1,1
    bcf        PIR1,2
                    ;-----------------------------------
                    ;Configure and start Timer2
;CONFIGURE TIMER.. copied code review.
    BANKSEL T2CON
    MOVLW B'00000110'   ;MOVLW B'00000110'
    MOVWF T2CON
                    ;Enable PWM output pin and wait until Timer2
                    ;overflows, TMR2IF bit of the PIR1 register is set.
                    ;See note below.
    btfss    PIR1,1                ;Test for T2 interrupt
    goto    $-1
                    ;Enable the PWMx pin output driver(s) by clearing
                    ;the associated TRIS bit(s) and setting the
                    ;PWMxOE bit of the PWMxCON register.
                    ;Configure the PWM module by loading the
                    ;PWMxCON register with the appropriate values.
    BANKSEL TRISC          ;Enable Outputs
    CLRF    TRISC
    BANKSEL PWM1CON        ;Enable PWM1
    MOVLW    B'11000000'
    MOVWF    PWM1CON
    RETURN
START
    CALL INIT
    BANKSEL PORTC            ;select PORTC for heatbeat
LOOP:
    BSF PORTC,2              ;heart beat
    MOVLW 0x55
    NOP                      ;future code
    BCF PORTC,2
    GOTO LOOP                ;loop forever
    END

 

 

TAUTIC’s 20 Pin Development Kit

I am a sucker for development kits/boards; they are cheap and if you have the room in your project they shave tons of room off your development time. Semi-recently, I was looking for a 18 or 20 PIC development board to plug into a main board. There are tons of boards that have various relays and switches and such but I wanted a bare-bones board that was good for bread-boarding and then could be plugged into my Sumo Roomba bot. These are shockingly hard to find for some reason? While I was sniffing around I ran into Jayson Tautic’s website which led me to purchase his 20-pin PIC development board on tinde. This thing was dirt cheap, and came remarkably fast! I put the thing together in a few moments and it sat in my “do-something-with-this-stuff” pile for a a few weeks. This kit comes with a 16F1509 which was great for what I was working on; it’s not-so-great if you still are rocking a PICKit2, it’s time to upgrade to the 3! I build out the “hello world” circuit shown below but in the end I went in a different direction and used a different board with an 18F2331. Did the board end up in the bottom of a drawer soon to be forgotten? (whats in there these days??: Cymbet energy harvesting stuff, a few 8 pin & 14 pin boards from piccircuit & micrcocontrollershop, a little 5/3.3V switcher kit, MMA7361, a few PICKit demo boards.. hmmm some other random stuff lower down)  Nope! While hiking I decided it was destined for a greater purpose. I wanted to build my own barometer for “storm warning” while hiking the cascades this summer. I dug a BMP085 development board I purchased from Sparkfun earlier on this year and went to work; That code is coming along but isn’t quite finished. While working with this TAUTIC board I can say it is very clean, looks nice, and it’s rock solid. I highly recommend this dev board if you want to plop something down on your breadboard and hack away at.

Yeah, I know, another annoying blinking LED. This was just a 'hello world' test before I was going to get serious to make sure I had my osc and such set up right.
Yeah, I know, another annoying blinking LED. This was just a ‘hello world’ test before I was going to get serious to make sure I had my osc and such set up right.

 

 

 

 

 

 

 

 

 

 

If you’re interested in some of the basic code just to get it going, here is what I consider to be the important stuff to get you might like to use:

#include “p16f1509.inc”

__CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _CLKOUTEN_OFF
__CONFIG _CONFIG2, _LVP_OFF & _STVREN_ON

and…

INIT: ;General Init
BANKSEL ANSELA ;All Digital Pins
CLRF ANSELA
CLRF ANSELB
CLRF ANSELC

BANKSEL OSCCON
MOVLW 0x78 ;16MHZ Clock
MOVWF OSCCON

BANKSEL TRISC
CLRF PORTC
CLRF TRISC

BANKSEL 0x00
RETURN