Category Archives: Weather

1-wire 18F14K22 C Electronics Interface Microcontrollers PIC Weather

iButtonLink T-Sense 1-wire sensor (Maxim DS18B20) + PIC 18F14K22

I came across a stash of iButton T-sense 1-wire sensors.. so I grabbed a couple and decided to check out 1-wire.

Maxim makes a 1-wire device called the DS18B20. It’s a 9-12 bit temperature sensor with the possibility of being powered by parasitic power from the data line. This cuts the signal path down to a single DQ line and a return. A company called iButtonLink produces a nice little wrapper around this device called a T-Sense. There are a couple pieces of software out there that will allow you to hook these up to monitoring systems, I don’t have any though. These devices come with a 64-bit address code and can be daisy-chained which makes having many of these devices monitored very nice.

At first I thought, ugh.. lame I have to send, and parse 64-bit codes in a little 8 bit micro.. doesn’t sound like a ton of fun for just fooling around on a day off.. thank fully they have a “Skip ROM” feature/command which works similar to a broadcast but can only be used when you have one device on the bus. If there is one thing left in this project I might consider finishing it’d be to add the addressing in and daisy-chain a few of these.

Most of my research came from Microchip’s Application Note AN1199 though the T-Sense Users Manual also helped out including determining the wiring diagram.

For my circuit I hooked up 5VDC (but later ran it on 3.3V just fine) and the 5VDC return on pins 1 & 2. Then the DQ link and return on pins 4&5. The signaling is interesting as the 1-wire bus needs a weak pull and works with an open collector circuits. The master starts all signaling, writes and reads. The 1’s and 0’s are based on how long the master or slave sinks the DQ line. To accomplish this in the PIC microcontroller I switched the port from an output to a three state input when I needed the port to be in weak-pull up mode (which is also hand when I need to sample the port for a response from a slave). The pull up on the resistor in my circuit is 10Kohm but I’ve seen 4.7KOhm and I’m sure anywhere in the neighborhood is fine. Finally if you do some digging you’ll notice I run this in low speed mode, if I remember correctly the “high speed” mode is 4x faster. I don’t think speed of data transfer is really relevant when you’re waiting for 750ms for a temperature conversation though.

T-sense sensor and 18F14k22 PIC Microcontroller on the breadboard
T-sense sensor and 18F14k22 PIC Microcontroller on the breadboard

I initially started with just determining if there was a 1-wire device on the bus. If you perform a “reset” (master sinks the bus low for 480us then releases to hi-z for 70us and then performed a sample.. any (all) device(s) will sink the line slow to prove their presence…then another 410us of delay before continuing. I got this one first try.. better luck than my first time with I2C! I then wrote the code (including sampling tidbits of Microchip AN1199 code to optimize) to do an actual temperature conversion and request it (by commanding a “read scratch pad”). The device dumps all 9 bytes of it’s registers. On that note I just remembered I should mention I did NOTHING with the CRC byte.. that’s all you if you care.

My temperature conversion code looks like this: (bus control m = master or PIC, s=slave or sensor)

m RESET

s PRESENCE flag

m SKIP ROM (0xCC)

m CONV TEMP (0x44)

m HOLD DQ (Hold line high 750ms for 12bit conversion .. I am guessing we hold it high for the parasitic power supply)

m RESET

s PRESENCE flag

m SKIP ROM (0xCC)

m READ SCRATCHPAD (0xBE)

s 9 Bytes of Data

and that looks like…

1-wire data capture on the logic analyzer
1-wire data capture on the logic analyzer

 

The 12-bit conversion is basically 0.0625 deg C for every bit from 0C, The LSB holds a temperature sign.

The output of my program looks like..

Final Results!
Final Results!

There are tons of details on what a “1” is an what a “0” is, the ROM code (READ ROM, MATCH ROM), changing the configuration to 9bit for 94 ms conversions over 12bit 750ms conversions. This is all stuff you can grab out of the DS18B20 specification sheet or AN1199.

I hope you get some use out of this.. I still have enough of these T-Sense modules.. maybe if someone really wants one I’ll drop it in the mail… or perhaps we can set up a big box of electronics to ship around and I can dump some in there.

Items I used to make this happen:

TAUTIC 20-pin Development Board

Microchip PIC 18F14K22

AST Breadboard Buddy Pro

AST tinyLEDx4

iButtonLink T-Sense

CAT5 breakout board (eBay?)

Microchip PICKit 3

Then miscellaneous tools, test equipment, jumpers and a breadboard.

 

The good stuff (my code):

.. also found here on pastebin: http://pastebin.com/HrLg1GqL

 


/*
 * File:   main.c
 * Author: Charles M Douvier
 * Contact at: http://iradan.com
 *
 * Created on Janurary 1, 2015
 *
 * Target Device:
 * 18F14K22 on Tautic 20 pin dev board
 *
 * Project: Maxim 1-Wire Testing
 *
 * Details of 1-wire protocol using Microchip AN1199
 * Field device http://datasheets.maximintegrated.com/en/ds/DS18B20.pdf
 * The 1-Wire Protocol is registered trade mark of Dallas/Maxim semiconductor.
 *
 * Some code was use by the AN1199 App Note Source code; I got stuck looking for a fast way of txing by bit-bang (yes never did this before)
 * The agreement below mentions a license agreement accompaning this software; There was none. I'll note where this software was used if you
 * want to re-write without the Microchip bits.
 * The Microchip licensing as follows:
 *
 *  * FileName:        1wire.c
 * Dependencies:
 * Processor:       PIC18
 * Complier:        MCC18 v3.13
 * Company:         Microchip Technology, Inc.
 *
 * Software License Agreement
 *
 * Copyright © 2004-2007 Microchip Technology Inc.  All rights reserved.
 *
 * Microchip licenses to you the right to use, copy and distribute Software
 * only when embedded on a Microchip microcontroller or digital signal
 * controller and used with a Microchip radio frequency transceiver, which
 * are integrated into your product or third party product (pursuant to the
 * sublicense terms in the accompanying license agreement).  You may NOT
 * modify or create derivative works of the Software.
 *
 *
 * You should refer to the license agreement accompanying this Software for
 * additional information regarding your rights and obligations.
 *
 * SOFTWARE AND DOCUMENTATION ARE PROVIDED “AS IS” WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY
 * OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR
 * PURPOSE. IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR OBLIGATED
 * UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF
 * WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR
 * EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT,
 * PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
 * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY
 * THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER
 * SIMILAR COSTS.
 *
 *
 *
 * Version:
 * 0.1  Configuration, with reset test
 * 0.2
 *
 */
#ifndef _XTAL_FREQ
#define _XTAL_FREQ 16000000 //4Mhz FRC internal osc
#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

#include 
#include 
#include 
#include 


//config bits
#pragma config FOSC=IRC, WDTEN=OFF, PWRTEN=OFF, MCLRE=ON, CP0=OFF, CP1=OFF, BOREN=ON
#pragma config STVREN=ON, LVP=OFF, HFOFST=OFF, IESO=OFF, FCMEN=OFF

#define _XTAL_FREQ 16000000 //defined for delay

/*
 * Variables
 */

    int     device_present;             // 1 = 1-wire device on 1-wire bus
    int     i, x, y, int_temp, an4_value;               //
    long int    decm;
    int     itxdata, txdata;            //int RS232 tx data
    char    rxbuff[10], z[1], buf[4];                 //buffer for T-sense 1-wire device
    float    temperature, f, d;
    volatile unsigned int uart_data;    // use 'volatile' qualifer as this is changed in ISR

/*
 *  Functions
 */

    void interrupt ISR() {

    if (PIR1bits.RCIF)          // see if interrupt caused by incoming data .. unused currently
    {
        uart_data = RCREG;     // read the incoming data
        PIR1bits.RCIF = 0;      // clear interrupt flag
                                //
    }
    // I left this timer interrupt if I needed it later. This is unused.
    if (PIR1bits.TMR1IF)
    {
        //T1CONbits.TMR1ON = 0;
        PIR1bits.TMR1IF = 0;
        //T1CONbits.TMR1ON = 1;

    }
}


     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_send (unsigned int mydata_byte) {      //bytes

    while(!TXSTAbits.TRMT);    // make sure buffer full bit is high before transmitting
    TXREG = mydata_byte;       // transmit data
}

void write_uart(const char *txt)                //strings
{
                                //this send a string to the TX buffer
                                //one character at a time
       while(*txt)
       uart_send(*txt++);
}

//This code if from Microchip but is unused currently.
void uart_send_hex_ascii(unsigned char display_data)
{

	//unsigned char temp;
	//temp = ((display_data & 0xF0)>>4);
	//if (temp <= 0x09)
	//	Putchar(temp+'0');
	//else
	//	Putchar(temp+'0'+0x07);
        //
	//temp = display_data & 0x0F;
	//if (temp <= 0x09)
	//	Putchar(temp+'0');
	//else
	//	Putchar(temp+'0'+0x07);

	//Putchar('\r');
	//Putchar('\n');
}

void serial_init(void)
{

    // calculate values of SPBRGL and SPBRGH based on the desired baud rate
    //
    // For 8 bit Async mode with BRGH=0: Desired Baud rate = Fosc/64([SPBRGH:SPBRGL]+1)
    // For 8 bit Async mode with BRGH=1: Desired Baud rate = Fosc/16([SPBRGH:SPBRGL]+1)



    TXSTAbits.BRGH=1;       // select low speed Baud Rate (see baud rate calcs below)
    TXSTAbits.TX9=0;        // select 8 data bits
    TXSTAbits.TXEN=1;     // enable transmit
    BAUDCONbits.BRG16=0;

    RCSTAbits.SPEN=1;       // serial port is enabled
    RCSTAbits.RX9=0;        // select 8 data bits
    RCSTAbits.CREN=1;       // receive enabled


    SPBRG=25;               //38,400bps-ish
                            //BRG16=0, 7=31.25k, 25=9.615k

    PIR1bits.RCIF=0;        // make sure receive interrupt flag is clear
    PIE1bits.RCIE=1;        // enable UART Receive interrupt


         __delay_ms(10);        // give time for voltage levels on board to settle

}


void init_io(void) {
    ANSEL = 0x00;         
    ANSELH = 0x00;

    TRISAbits.TRISA0 = 0; // output
    TRISAbits.TRISA1 = 0; // output
    TRISAbits.TRISA2 = 0; // output
    TRISAbits.TRISA4 = 0; // output
    TRISAbits.TRISA5 = 0; // output



    TRISBbits.TRISB4 = 0; // output
    TRISBbits.TRISB5 = 1; // input (RX UART)
    TRISBbits.TRISB6 = 0; // output
    TRISBbits.TRISB7 = 0; // output (TX UART)

    LATC = 0x00;

    TRISCbits.TRISC0 = 1; // AN4
    TRISCbits.TRISC1 = 1; // 1-wire data
    TRISCbits.TRISC2 = 0; // 
    TRISCbits.TRISC3 = 0; // 
    TRISCbits.TRISC4 = 0; // 
    TRISCbits.TRISC5 = 0; // output
    TRISCbits.TRISC6 = 1; // input
    TRISCbits.TRISC7 = 1; // input

}


void init_adc (void)
{
    ANSELbits.ANSEL4=1;         //PORTC.0
    ADCON2bits.ADCS = 0x02;     //Fosc/32
    ADCON2bits.ADFM=0;          //left oriented
    ADCON1=0x00;
}

void read_adc (void)
{
    ADCON0bits.CHS0 = 0;        // AD4
    ADCON0bits.CHS1 = 0;
    ADCON0bits.CHS2 = 1;
    ADCON0bits.CHS3 = 0;
    ADCON0bits.ADON = 1;        // A/D ON
    __delay_us(5);

    ADCON0bits.GO   = 1;        // ..GO!

    __delay_us(5);

        while (ADCON0bits.GO) continue;              //wait for conversion
        an4_value = ADRESH;                          //AN4 value
}

void one_wire_reset(void) {
    device_present = 0x00;
    TRISCbits.TRISC1 = 0;
    LATCbits.LATC1 = 0;
    __delay_us(240);        //delay 480 us
    __delay_us(240);
    TRISCbits.TRISC1 = 1;
    __delay_us(70);
    if (!PORTCbits.RC1) {
            device_present = 0x01;
    }
    __delay_us(205);        //delay 410 us
    __delay_us(205);
}

//this looks a lot like the Microchip code, it was not I just happened to be on the right track.
void one_wire_tx_bit(unsigned char txbit) {         // write a bit
    if (txbit) {
    TRISCbits.TRISC1 = 0;
    LATCbits.LATC1 = 0;
    __delay_us(6);    
    TRISCbits.TRISC1 = 1;
    __delay_us(64);      
    }
    else {      
    TRISCbits.TRISC1 = 0;
    LATCbits.LATC1 = 0;
    __delay_us(60);    
    TRISCbits.TRISC1 = 1;
    __delay_us(10);    
    }
}

//from Microchip AN1199 code, renamed and slightly modified to match my software
/**********************************************************************
* Function:        void OW_write_byte (unsigned char write_data)
* PreCondition:    None
* Input:		   Send byte to 1-wire slave device
* Output:		   None
* Overview:		   This function used to transmit a complete byte to slave device.
*				   
***********************************************************************/
void one_wire_tx_byte (unsigned char write_data)
{
	unsigned char loop;
	
	for (loop = 0; loop < 8; loop++) 	{ 		one_wire_tx_bit(write_data & 0x01); 	//Sending LS-bit first 		write_data >>= 1;					// shift the data byte for the next bit to send
	}	
}	


//from Microchip AN1199 code: I gathered the essence of this but seeing as I am not using most of the AN1199 code
//and this would not work with XC8 I had to re-write this.
/**********************************************************************
* Function:        unsigned char OW_read_bit (void)
* PreCondition:    None
* Input:		   None
* Output:		   Return the status of the OW PIN
* Overview:		   This function used to read a single bit from the slave device.
*				   
***********************************************************************/

unsigned char one_wire_rx_bit (void)
{
	unsigned char read_data; 
        read_data = 0x00;
	//reading a bit 
	TRISCbits.TRISC1 = 0;
        LATCbits.LATC1 = 0; 						// Drive the bus low
	__delay_us(6);						// delay 6 microsecond (us)
	TRISCbits.TRISC1 = 1;  						// Release the bus
	__delay_us(9);						// delay 9 microsecond (us)

        if (PORTCbits.RC1) {                                    //read 1 or 0
            read_data = 0x01;
        }

	__delay_us(55);						// delay 55 microsecond (us)	
	return read_data;
}


/**********************************************************************
* Function:        unsigned char OW_read_byte (void)
* PreCondition:    None
* Input:		   None
* Output:		   Return the read byte from slave device
* Overview:		   This function used to read a complete byte from the slave device.
*				   
***********************************************************************/

unsigned char one_wire_rx_byte (void)
{
	unsigned char loop, result=0;
	
	for (loop = 0; loop < 8; loop++)                // here we are reading 8 bits (1 byte) 	{ 		 		result >>= 1; 				// shift the result to get it ready for the next bit to receive
		if (one_wire_rx_bit())
		result |= 0x80;				// if result is one, then set MS-bit
	}
	return result;					
}	

void one_wire_conversion_pulse(void) {
    	TRISCbits.TRISC1 = 0;
        LATCbits.LATC1 = 1; 		 //For T conv we drive the DQ line high for 750ms (12bit)
	__delay_us(250);                 // delay 
	__delay_us(250);                  
        __delay_us(250);                  
	TRISCbits.TRISC1 = 1; 
        LATCbits.LATC1 = 0;             //just in case this causes problems elsewhere                              
}

int main(void) {

    init_io();

    // set up oscillator control register, using internal OSC at 16MHz.
    OSCCONbits.IRCF = 0x07; //set OSCCON IRCF bits to select OSC frequency 16MHz
    OSCCONbits.SCS = 0x02; //set the SCS bits to select internal oscillator block

    //RCONbits.IPEN = 0;          //dsiable priority levels

    INTCONbits.PEIE = 1;        // Enable peripheral interrupt
    INTCONbits.GIE = 1;         // enable global interrupt


    init_adc();                 //unused but AN4 is there if I need it
    serial_init();

    uart_send ('x');

        LATAbits.LATA0 = 0; //this is just for debugging with an LA..
        __delay_us(1);
        LATAbits.LATA0 = 1; //also confirms oscillator setup is correct.. 1us width
        __delay_us(1);
        LATAbits.LATA0 = 0;

    while (1) {

        one_wire_reset();

        if (device_present) {
            LATCbits.LATC2 = 1;             //this is a 1-wire device out there for debugging

            one_wire_tx_byte(0xCC);         //skip-rom (similar to a broadcast)

            one_wire_tx_byte(0x44);         //do a temp conversion

            one_wire_conversion_pulse();    // hold DQ line high for 750ms

            one_wire_reset();

            //add additional check here later

            one_wire_tx_byte(0xCC);         //skip-rom (similar to a broadcast)

            one_wire_tx_byte(0xBE);         //read scratch pad

            for(i = 0; i<9; i++)            //reading all 9 bytes on the T-Sense
   		rxbuff[i] = one_wire_rx_byte();
            // T-Sense
            //  Byte 0 LSB of Temp
            //  Byte 1 MSB of Temp and sign

            // LSB
            //  2^3 2^2 2^1 2^0 2^-1 2^-2 2^-3 s^-4
            // MSB
            // S S S S S 2^6 2^5 2 ^ 4



            temperature = 0;
            f = 0.0625;

            //z[0] = rxbuff[1];
            //x = atoi(z);
            x = rxbuff[1];

            if (x & 0b10000000) {
                uart_send('-');
            } else {
                uart_send('+');
            }
            
            x = x & 0b00000111;

            int_temp = 0;

            int_temp = rxbuff[0];

            if (x & 0b00000001)
                int_temp = int_temp + 0x100;
            if (x & 0b00000010)
                int_temp = int_temp + 0x200;
            if (x & 0b00000100)
                int_temp = int_temp + 0x400;

            temperature = int_temp * f;
            
            int_temp = temperature;

            itoa(z, int_temp, 10);
            write_uart(z);
            uart_send('.');

            d = temperature - int_temp;

            decm = d * 1000;

            //page 374 of XC8 user guide
            ltoa(buf,decm,10);  //long conversion to buffer
            y=strlen(buf);  //uh, adding leading zeros..
            y=3-y;      //probably a better way of doing thing
            while (y)       //first figure out how many zeros
            {
                uart_send('0');  //missed 3-string length
                y=y-1;  //then send them until done
            }   
            write_uart (buf);
        
            uart_send(0x0A);        //LF
            uart_send(0x0D);        //CR

            //temperature   float temperature
            //int_temp      interger value of temperature

            __delay_10ms(254);
        }

    }
    return (EXIT_SUCCESS);
}

 

 

 

 

 

 

Electronics Microcontrollers PIC Weather

A tiny Si4707 WX Radio Project Update

I pulled out the weather radio project today to see what I could get done in a few hours. I was pretty close on finishing off the hardware but I fell a little short right at the end. I found I had forgotten to buy something to convert the regulated 5V to 3.3V for the radio (and PIC since they’re tied together on I2C). I ran into a few issues I totally spaced:1.  The Si4707 requires a reset after power up .. it ignores I2C if you don’t.

2. Pull-ups.. duh, not only on I2C which I had, but don’t forget the Si4707 reset (oops).

I ended up buying a couple random Digikey parts at the ham radio convention and guess what? 10@ MCP1802T-3002I/OT (300mA 3.0V LDO) ..they are SOT23-5 and I had JUST gotten 10 break-out boards in the mail so I ended up having a 5V3.3V converter (close enough anyways, as the PIC and Si4707 work down to 2.7V).. soldered it up but I didn’t have time to pop it in. I used the Weller but I think I’m going to solder another one with the new hot air gun I got this week. I ordered one of those cheap 858D rework stations; I don’t plan on using it too much so hopefully it’ll do the trick. I also got a bunch of SMD protoboards.. so I get to practice reflow this week.

Tomorrow I should be able to finish up the radio and then it’s all software.

Si4707 WX Radio Build - 11MAR14

The photo isn’t the most exciting workbench shot but you can see that 858D in the back corner. The WX radio is the black box right up close to the left.

C Electronics Weather

Project Update : 4D Systems μLCD-43PCT / Si4707 Radio

So as suspected the uLCD-43PCT display worked just fine once I got their USB-RS232 dongle.. it has a RST pin.. maybe it uses it in some way when programming? I didn’t do any research because I just wanted to try the display out but maybe I’ll check that out later.

I used Visi Genie which is one of four options you have for configuring their displays. It’s not bad.. but it’s not great. It gives you a very limited number of switches, buttons, numeric displays, etc.. but it worked. I also haven’t found a way to send text to the screen which I can’t believe I couldn’t do.. I just haven’t found it I hope? You can dig in and actually use some of the other configuration modes in which I imagine you can design your own display in detail…again maybe some time I’ll check that out. It’s all code and looks like it would make for a very long day or two. The Visi Genie took me about 3 hours to figure out and configure the display. I ran into a few issues.. of course some of my time was just picking what colors I liked best. The colors show up on the monitor a little different from the LCD so that took some tweaking.. also I noticed the LCD is a little less readable than their simulated display: no big deal though.

The really REALLY annoying bug that took me about an hour to figure out (while was figuring out the serial protocol) was the “LED Digits” module… I dropped it in, selected 6 digits with the decimal place in the third; check, no problem. When testing I could write 1, …. 2, ….3,… WTF? See photo below.

4D Systems LED Digit 3

 

How did that happen? The serial commands were right… after a while I dropped in the Custom LED display.. this next photo shows both displays with “200” written to them.. note: the larger LED segments has the leading zero’s turned off (hidden), it’s setup at six digits.

AARRG!!!?!?!?
AARRG!!!?!?!?

…… sigh.

I finally switched my display from 6 to 4 digits as a test (well really 2+4 digits). Success! I guess the program doesn’t like over 4 digits which makes sense because after I figured the serial protocol out there is only room for 4 digits  in the packet. Why does the program allow for more than four? The program does a pretty good job of limiting everything else … oh well. It’s finished

The display set up to my satisfaction.
The display set up to my satisfaction.

Next steps … I’m deciding if I want to wait for the Tautic 18F26K22 dev board or order something and use one of my protoboards or even just stick with the 16F1509? I’ll figure this out shortly once I decide how I’m going to mash this all up together. I ordered another Si4707 from Richard @ AIW Industries. Hopefully his board is decent: It has promise with the BNC connector and you can buy a fairly cheap Larson whip from him for 12$ and change for the right band which is pretty nice (no more random-wire antenna!). I’ll probably have to shelf this project for a week until it arrives anyhow.

I started up MPLAB 2.05 after the update… I want going to start programming but didn’t get far before I ran into this..

<3 MPLAB

It looks like it marks “TODO” in tasks!!?…. I don’t know if this was an option before but I usually just //TODO if I have something I need to get to… perhaps the update reset some toolbars? I don’t know but I really like this feature. I love me some MPLAB.

C Electronics Microcontrollers PIC Programming Weather

Project: Si4707 Weather Radio

I purchased a Silicon Labs Si4707 weather band radio break out board (BOB) from Sparkfun a couple of months ago and finally did something with it. The Si4707 has a SAME ( Specific Area Message Encoding ) processor that allows alerting for only for a certain kinds of warnings. The weather band radio board receives from 162.40MHz to 162.55MHz; Its outputs is a 1/8″ jack with enough output to power a small speaker with low volume or earphones at a comfortable level of listening.

LCD Display of Si4707 Weather Band Radio Project
LCD Display of Si4707 Weather Band Radio Project

For my project I used MPLABX 2.0 with the XC8 C compiler. I decide to post this project before I was done programming because I’m about to customize this project for what I want. I thought it was a good time to make it available if a reader was interested in customizing the project without all the work of tearing apart what I had done. The code has all the right nuts and bolts and at most of the hard work done for you. All a person needs to do is a little(?) configuration to make the project meet your needs. You might consider going in another direction; volume up/down (programmable feauture!), tune up/down, and of course working with the SAME information, who knows?

Right now on the bench the PIC powers up, resets and powers up the radio, then tunes the radio via I2C to 162.55MHz. It finishes up by reading back the status and then dumps the Tuned Frequency and RSSI ( Received Signal Strength Indicator ) on to the LCD… then off to infinite loop land. In the next few days I plan on having my seven buttons for “quick tune” to the common frequencies (.40, 425, .45, etc..) and one additional monitor/standby switch. My radio will normally be silent and once it receives a weather alert it will un-mute the speaker and alert the LCD. The Standby/Monitor button will reset my alert.

I’ll throw my finished code up on github and you can download my version in a week or so [I’ll edit this and drop a link in when I’ve actually done this].

Another note of interest: the output of the audio amplifier is kind of weak. I recommend building another amplifier stage if you want the thing to wake you up in a weather emergency.

The attached code this is really rough around the edges.. I lot of hacking went into this and all of the unused functions are totally untested.

The Si4707 WX RX:

Okay, so $30.. not a bad price. And in the end I’m happy with the performance.

HOWEVER! The items I don’t like about it…

1. Sparkfun’s BOB threw pull up resistors on it.. that is annoying. I realize you can cut them out but .. how about some 2mm jumpers or something? I got burnt by them trying to get the I2C working. (RTFM!) 🙂 I noticed lot of people seem to have issues with them being poorly sized according to the feedback I’ve read.

2. Wow it this thing pokey. I was a little confused by the application note for the product to determine worst case tune time, etc… basically I just ended up putting in 1000ms because 300ms was hit and miss for me. If I read it correctly worse case tune time for the AM radio version of the chip is 28 seconds!?

3. I2C! Well it worked fine but I suspect the board is a little noisy? with about 2 inches of wire leads I got enough ringing when the BOB wasn’t loaded by the logic analyzer for comm to fold. I ended up have to enable slew.  I also slowed the unit down to 25KHz from 100KHz because I have to wait for it anyways. It’ll probably work fine at 100KHz with slew on.

Top view of Si4707 Weather Band Radio Project. The power supply sits on the back of the LCD/keypad support board and the weather band sits sandwiched between the TAUTIC dev board and daughter-protoboard. The speaker was just thrown in there for quick testing.
Top view of Si4707 Weather Band Radio Project. The power supply sits on the back of the LCD/keypad support board and the weather band sits sandwiched between the TAUTIC dev board and daughter-protoboard. The speaker was just thrown in there for quick testing.

The circuit in general:

I haven’t included a schematic nor do I have any plans to. The photos show you I really am not using any support components besides LCD 10k pot you normally put on an LCD. I would have had pull up resistors but they were not required because of the BOB having them pre-installed.  You should be able to re-create the circuit just by looking at my TRISx/LATx initialization in the code. I commented it my version of adequate-enough… If you’re stumped, just ask!

5.0V input to run the LCD backlight and LCD main power (a standard 2 line 44780 compatible). The five volts also feeds the switching power supply to supply the PIC and 4707 with 3.3V power. I mistakenly thought the 4707 ran on 3.3V because I had been using an I2C product that was 3.3V only then had done a little switching around, oops… no harm, just a waste of the regulator. The 4707 runs 2.7-5.5V. My push button switches are designed to run in a 2×4 matrix. See the //notes in the code. Finally my PIC. I’m using (again!) the Microchip PIC 16F1509 microcontroller with a Tautic 20 pin development board and it’s daughter-board for a little prototyping space. I could maybe stretch this 20 PIN MCU a little more but I probably should have picked a slightly larger PIC for the IO. It’s enough for me though.

Side view. Note the whole project was just slapped on top of a piece of old PCB.. It's not even FR4.. just some old stuff. I made some "mounts" out of small copper strap and soldered the protoboard to the bare copper clad board.
Side view. Note the whole project was just slapped on top of a piece of old PCB.. It’s not even FR4.. just some old stuff. I made some “mounts” out of small copper strap and soldered the protoboard to the bare copper clad board.

So my final thoughts are I still have a lot of work and a lot of clean up work on this project. My temp mounting doesn’t have me totally won over. I also don’t like my “keypad” … I might by a pre-build “shield” and adapt it or maybe design my own PCB. I haven’t even hooked up the buttons because I haven’t decided if I’m happy-enough if the hardware.

The code:



/*
 * File:   newmain.c
 * Author: Charles M Douvier
 * Contact at: http://iradan.com
 *
 * Created on January 26, 2014, 12:00 PM
 *
 * Target Device:
 * 16F1509 on Tautic 20 pin dev board
 *
 * Project:
 *  I2C Testing with the TCN75A
 *
 * Version:
 * 0.1  Start Bit, and Control Byte ... check
 * 0.2  /ACK NAK and Stop ... check!
 * 0.3  works+232
 *
 */
#ifndef _XTAL_FREQ
#define _XTAL_FREQ 4000000 //4Mhz FRC internal osc
#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

#include 
#include 
#include 
#include 

//config bits
#pragma config FOSC=INTOSC, WDTE=OFF, PWRTE=ON, MCLRE=ON, CP=OFF, BOREN=OFF, CLKOUTEN=OFF, FCMEN=OFF
#pragma config WRT=OFF, STVREN=OFF, LVP=OFF


#define _XTAL_FREQ 4000000 //defined for delay
#define device_address  0b1001000       // unused for now

    unsigned int ACK_bit;
    int i, x;   //garbage flags
    long int tempi, tempn, tempx, tempy, temp10, temp25;
    unsigned char byte, tempbyte1, tempbyte2;
    unsigned char StatusByte;
    unsigned char RESP1Byte, RESP2Byte, RESP3Byte, RESP4Byte, RESP5Byte;
    unsigned char RESP6Byte, RESP7Byte, RESP8Byte, RESP9Byte, RESP10Byte;
    unsigned char RESP11Byte, RESP12Byte, RESP13Byte, RESP14Byte;
    char buf[10];

void init_io(void) {

    ANSELA = 0x00; // all port A pins are digital I/O
    ANSELB = 0x00; // all port A pins are digital I/O
    ANSELC = 0x00; // all port B pins are digital I/O

    TRISAbits.TRISA0 = 0; // keypad strobe 1
    TRISAbits.TRISA1 = 0; // keypad strobe 2
    TRISAbits.TRISA2 = 0; // RADIO /RST
    TRISAbits.TRISA3 = 1; // /MCLR
    TRISAbits.TRISA4 = 0; // LCD RS
    TRISAbits.TRISA5 = 0; // LCD EN

    TRISBbits.TRISB4 = 1; // RB4 I2C SDA, has to be set as an input
    TRISBbits.TRISB5 = 1; // RB5 NC (RESERVED RS232)
    TRISBbits.TRISB6 = 1; // RB6 I2C SCLK, has to be set as an input
    TRISBbits.TRISB7 = 0; // RB7 NC (RESERVED RS232)

    TRISCbits.TRISC0 = 0; // LCD D4
    TRISCbits.TRISC1 = 0; // LCD D5
    TRISCbits.TRISC2 = 0; // LCD D6
    TRISCbits.TRISC3 = 0; // LCD D7
    TRISCbits.TRISC4 = 1; // button col 1
    TRISCbits.TRISC5 = 1; // button col 2
    TRISCbits.TRISC6 = 1; // button col 3
    TRISCbits.TRISC7 = 1; // button col 4
}

/*
 *  LCD Interface Functions
 *  standard 44780 format 2 lines
 */

void lcd_strobe (void)  //TOGGLE LCD_EN
{
    LATAbits.LATA5 = 0;
    __delay_ms(20);
    LATAbits.LATA5 = 1;
}

/* write a byte to the LCD in 4 bit mode */

void lcd_write(unsigned char c)
{
	LATC = c >> 4;
	lcd_strobe();
	LATC = c;
	lcd_strobe();
        __delay_us(100);
}

/*
 * 	Clear and home the LCD
 */

void lcd_clear(void)
{
	LATAbits.LATA4 = 0;
	lcd_write(0x1);
        __delay_ms(2);
}


/* write a string of chars to the LCD */

void lcd_puts(const char * s)
{
	LATAbits.LATA4 = 1;	// write characters
	while(*s)
		lcd_write(*s++);
}

/*
 * Go to the specified position
 */

void lcd_goto(unsigned char pos)
{
	LATAbits.LATA4 = 0;
	lcd_write(0x80+pos);
}

/*
 *      Write 16 spaces on LCD 2 to avoid blanking, (ugly CLEAR effect)
 *      this is slow but work for my needs
 */

void    lcd_clrline1(void)
{
    lcd_goto(0);
    lcd_puts("                ");
    lcd_goto(0);
}

void    lcd_clrline2(void)
{
    lcd_goto(40);
    lcd_puts("                ");
    lcd_goto(40);
}

/* initialise the LCD - put into 4 bit mode */

void lcd_init(void)
{
	LATAbits.LATA4 = 0;	// write control bytes
        LATC = 0x03;
        __delay_ms(150);         //power on delay
	lcd_strobe();
        __delay_ms(5);
	lcd_strobe();
        __delay_ms(5);
	lcd_strobe();
        __delay_ms(5);
	LATC = 0x02;             // set 4 bit mode
        __delay_ms(5);
	lcd_strobe();
        __delay_ms(5);
	lcd_write(0x28);	// 4 bit mode, 1/16 duty, 5x8 font
	lcd_write(0x08);	// display off
	lcd_write(0x0C);	// display on cursor+blink off
	lcd_write(0x06);	// entry mode
}

/*
 *  I2C Functions
 *
 */

void I2C_ACK(void)
{
   PIR1bits.SSP1IF=0;          // clear SSP interrupt bit
   SSP1CON2bits.ACKDT=0;        // clear the Acknowledge Data Bit - this means we are sending an Acknowledge or 'ACK'
   SSP1CON2bits.ACKEN=1;        // set the ACK enable bit to initiate transmission of the ACK bit to the serial eeprom
   while(!PIR1bits.SSP1IF);    // Wait for interrupt flag to go high indicating transmission is complete
}

void Send_I2C_Data(unsigned int databyte)
{
    PIR1bits.SSP1IF=0;          // clear SSP interrupt bit
    SSPBUF = databyte;              // send databyte
    while(!PIR1bits.SSP1IF);    // Wait for interrupt flag to go high indicating transmission is complete
}

unsigned char RX_I2C_Data (void)
{

    RCEN = 1;               //
    while( RCEN ) continue;
    while( !BF ) continue;
    byte = SSPBUF;
   return byte;
}

void I2C_Control_Write(void)
{
    PIR1bits.SSP1IF=0;          // clear SSP interrupt bit
    SSP1BUF = 0xC6;             // send the control byte 4707 Addr w/ SEN=1
    while(!PIR1bits.SSP1IF)     // Wait for interrupt flag to go high indicating transmission is complete
        {
        i = 1;
          // place to add a breakpoint if needed
        }
    PIR1bits.SSP1IF=0;

}

void I2C_Control_Read(void)
{
    PIR1bits.SSP1IF=0;          // clear SSP interrupt bit
    SSP1BUF = 0xC7;             // send the control byte
    while(!PIR1bits.SSP1IF)     // Wait for interrupt flag to go high indicating transmission is complete
        {
        i = 1;
          // place to add a breakpoint if needed
        }
    PIR1bits.SSP1IF=0;
   }

void I2C_Start_Bit(void)
{
    PIR1bits.SSP1IF=0;          // clear SSP interrupt bit
    SSPCON2bits.SEN=1;          // send start bit
    while(!PIR1bits.SSP1IF)    // Wait for the SSPIF bit to go back high before we load the data buffer
        {
        i = 1;
        }
    PIR1bits.SSP1IF=0;
}

void I2C_check_idle()
{
    unsigned char byte1; // R/W status: Is a transfer in progress?
    unsigned char byte2; // Lower 5 bits: Acknowledge Sequence, Receive, STOP, Repeated START, START

    do
    {
        byte1 = SSPSTAT & 0x04;
        byte2 = SSPCON2 & 0x1F;
    } while( byte1 | byte2 );
}
/*
 * Send the repeated start message and wait repeated start to finish.
 */
void I2C_restart()
{
    I2C_check_idle();
    RSEN = 1; // Reinitiate start
    while( RSEN ) continue;
}

void I2C_Stop_Bit(void)
{
    PIR1bits.SSP1IF=0;          // clear SSP interrupt bit
    SSPCON2bits.PEN=1;          // send stop bit
    while(!PIR1bits.SSP1IF)
    {
        i = 1;
        // Wait for interrupt flag to go high indicating transmission is complete
    }
}

void I2C_NAK(void)
{
    PIR1bits.SSP1IF=0;           // clear SSP interrupt bit
    SSP1CON2bits.ACKDT=1;        // set the Acknowledge Data Bit- this means we are sending a No-Ack or 'NAK'
    SSP1CON2bits.ACKEN=1;        // set the ACK enable bit to initiate transmission of the ACK bit to the serial eeprom
    while(!PIR1bits.SSP1IF)     // Wait for interrupt flag to go high indicating transmission is complete
    {
        i = 1;
    }
}

/*
 *  Si4707 WB RX Functions
 *
 */

void Tune400(void)
{
//162400	64960	FDC0

    I2C_Start_Bit();                     // send start bit
    I2C_Control_Write();                 // send control byte

    Send_I2C_Data(0x50);                 //Tune Frequency
    Send_I2C_Data(0x00);                 //0x00
    Send_I2C_Data(0xFD);                 //
    Send_I2C_Data(0xC0);                 //...

    I2C_Stop_Bit();

    __delay_ms(1000);					//tune delay
}

void Tune425(void)
{
//162425	64970	FDCA

    I2C_Start_Bit();                     // send start bit
    I2C_Control_Write();                 // send control byte

    Send_I2C_Data(0x50);                 //Tune Frequency
    Send_I2C_Data(0x00);                 //0x00
    Send_I2C_Data(0xFD);                 //
    Send_I2C_Data(0xCA);                 //...

    I2C_Stop_Bit();

    __delay_ms(1000);					//tune delay
}

void Tune450(void)
{
//162450	64980	FDD4

    I2C_Start_Bit();                     // send start bit
    I2C_Control_Write();                 // send control byte

    Send_I2C_Data(0x50);                 //Tune Frequency
    Send_I2C_Data(0x00);                 //0x00
    Send_I2C_Data(0xFD);                 //
    Send_I2C_Data(0xD4);                 //...

    I2C_Stop_Bit();

    __delay_ms(1000);					//tune delay
}

void Tune475(void)
{
//162475	64990	FDDE

    I2C_Start_Bit();                     // send start bit
    I2C_Control_Write();                 // send control byte

    Send_I2C_Data(0x50);                 //Tune Frequency
    Send_I2C_Data(0x00);                 //0x00
    Send_I2C_Data(0xFD);                 //
    Send_I2C_Data(0xDE);                 //...

    I2C_Stop_Bit();

    __delay_ms(1000);					//tune delay
}

void Tune500(void)
{
//162500	65000	FDE8

    I2C_Start_Bit();                     // send start bit
    I2C_Control_Write();                 // send control byte

    Send_I2C_Data(0x50);                 //Tune Frequency
    Send_I2C_Data(0x00);                 //0x00
    Send_I2C_Data(0xFD);                 //
    Send_I2C_Data(0xE8);                 //...

    I2C_Stop_Bit();

    __delay_ms(1000);					//tune delay
}

void Tune525(void)
{
//162525	65010	FDF2

    I2C_Start_Bit();                     // send start bit
    I2C_Control_Write();                 // send control byte

    Send_I2C_Data(0x50);                 //Tune Frequency
    Send_I2C_Data(0x00);                 //0x00
    Send_I2C_Data(0xFD);                 //
    Send_I2C_Data(0xF2);                 //...

    I2C_Stop_Bit();

    __delay_ms(1000);					//tune delay
}

void Tune550(void)
{
//162550	65020	FDFC

    I2C_Start_Bit();                     // send start bit
    I2C_Control_Write();                 // send control byte

    Send_I2C_Data(0x50);                 //Tune Frequency
    Send_I2C_Data(0x00);                 //0x00
    Send_I2C_Data(0xFD);                 //
    Send_I2C_Data(0xFC);                 //...

    I2C_Stop_Bit();

    __delay_ms(1000);					//tune delay
}

void VolumeUp(void)
{
//future use
}

void VolumeDown(void)
{
//future use
}

void VolumeMAX (void)
{
    // Reset Volume
}
void VolumeMUTE (void)
{
    //Mute Sound

}

void CheckStatus (void)
{
/*
 * STATUS BYTE
 *	[7] CTS	Clear to Send.
 *	0 = Wait before sending next command.
 *	1 = Clear to send next command.

 *	[6] ERR	Error.
 *	0 = No error
 *	1 = Error

 *	5:4 Reserved Values may vary.

 *	[3] RSQINT	Received Signal Quality Interrupt.
 *	0 = Received Signal Quality measurement has not been triggered.
 *	1 = Received Signal Quality measurement has been triggered.

 *	[2] SAMEINT	SAME Interrupt (Si4707 Only).
 *	0 = SAME interrupt has not been triggered.
 *	1 = SAME interrupt has been triggered.

 *	[1] ASQINT	Audio Signal Quality Interrupt.
 *	0 = Audio Signal Quality measurement has not been triggered.
 *	1 = Audio Signal Quality measurement has been triggered.

 *	[0] STCINT	Seek/Tune Complete Interrupt.
 *	0 = Tune complete has not been triggered.
 *	1 = Tune complete interrupt has been triggered.

*/
//0x52 RX_STATUS
//STATUS, RESP1 (VALID), RESP2 FREQ_H, RESP3 FREQ_L, RESP4 RSSI, RESP5 SNR

    I2C_Start_Bit();                     // send start bit
    I2C_Control_Write();
    Send_I2C_Data(0x52);                //TUNE STATUS
    Send_I2C_Data(0x00);                //DONT CLEAR INT

    I2C_restart();
    I2C_Control_Read();

    RX_I2C_Data();                      //STATUS
	StatusByte = byte;
    I2C_ACK();

	RX_I2C_Data();                      //VALID
	RESP1Byte = byte;
    I2C_ACK();

	RX_I2C_Data();                      //FREQ1
	RESP2Byte = byte;
    I2C_ACK();

	RX_I2C_Data();                      //FREQ2
	RESP3Byte = byte;
    I2C_ACK();

	RX_I2C_Data();                      //RSSI
	RESP4Byte = byte;
    I2C_ACK();

    RX_I2C_Data();                      //SNR
	RESP5Byte = byte;
    I2C_NAK();                          //NAK

	I2C_Stop_Bit();                     // Send Stop Bit

//Update Freq Display
//Update RSSI
}



CheckFlag(unsigned value, unsigned bitindex)
{
//1=0x000000_0
//CheckFlag(BYTE,1);

    return (value & (1 << bitindex)) != 0;
}


void CheckSAME(void)
{
//0x54   SAME_STATUS
//STATUS, ARG1, ARG2, STATUS, RESP1-RESP13.
//
//ARG1 0:INTACK 1:CLRBUF
//ARG2 READ_ADDR
//3:RSQINT 2:SAMEINT 1:ASQINT 0:STCINT

    I2C_Start_Bit();                     // send start bit
    I2C_Control_Write();
    Send_I2C_Data(0x54);                //SAME STATUS
    Send_I2C_Data(0x00);                //DONT CLEAR INT
	Send_I2C_Data(0x00);                //Start location

    I2C_restart();
    I2C_Control_Read();

    RX_I2C_Data();                      //STATUS
	StatusByte = byte;
    I2C_ACK();

	RX_I2C_Data();                      //
	RESP1Byte = byte;
    I2C_ACK();

	RX_I2C_Data();                      //
	RESP2Byte = byte;
    I2C_ACK();

	RX_I2C_Data();                      //
	RESP3Byte = byte;
    I2C_ACK();

	RX_I2C_Data();                      //
	RESP4Byte = byte;
    I2C_ACK();

	RX_I2C_Data();                      //
	RESP5Byte = byte;
    I2C_ACK();

	RX_I2C_Data();                      //
	RESP6Byte = byte;
    I2C_ACK();

	RX_I2C_Data();                      //
	RESP7Byte = byte;
    I2C_ACK();

	RX_I2C_Data();                      //
	RESP8Byte = byte;
    I2C_ACK();

	RX_I2C_Data();                      //
	RESP9Byte = byte;
    I2C_ACK();

	RX_I2C_Data();                      //
	RESP10Byte = byte;
    I2C_ACK();

	RX_I2C_Data();                      //
	RESP11Byte = byte;
    I2C_ACK();

	RX_I2C_Data();                      //
	RESP12Byte = byte;
    I2C_ACK();

    RX_I2C_Data();                      //
	RESP13Byte = byte;
    I2C_NAK();                          //NAK

	I2C_Stop_Bit();                     // Send Stop Bit

        if (CheckFlag(StatusByte,2))
            i=1;    //TODO
}


void ResetSAME(void)
{
//0x54   SAME_STATUS
//STATUS, ARG1, ARG2, STATUS, RESP1-RESP13.
//ARG1 0:INTACK 1:CLRBUF
//ARG2 READ_ADDR
//3:RSQINT 2:SAMEINT 1:ASQINT 0:STCINT

    I2C_Start_Bit();                     // send start bit
    I2C_Control_Write();
    Send_I2C_Data(0x54);                //SAME STATUS
    Send_I2C_Data(0x03);                //Dump Buffer and Reset SAME Int.
	Send_I2C_Data(0x00);                //Start location

    I2C_restart();
    I2C_Control_Read();

    RX_I2C_Data();                      //STATUS
	StatusByte = byte;
    I2C_ACK();

	RX_I2C_Data();                      //don't care about the rest..
    I2C_ACK();

	RX_I2C_Data();                      //
    I2C_ACK();

	RX_I2C_Data();                      //
    I2C_ACK();

	RX_I2C_Data();                      //
    I2C_ACK();

	RX_I2C_Data();                      //
    I2C_ACK();

	RX_I2C_Data();                      //
    I2C_ACK();

	RX_I2C_Data();                      //
    I2C_ACK();

	RX_I2C_Data();                      //
    I2C_ACK();

	RX_I2C_Data();                      //
    I2C_ACK();

	RX_I2C_Data();                      //
    I2C_ACK();

	RX_I2C_Data();                      //
    I2C_ACK();

	RX_I2C_Data();                      //
    I2C_ACK();

    RX_I2C_Data();                      //
    I2C_NAK();                          //NAK

	I2C_Stop_Bit();                     // Send Stop Bit
}


void Monitor(void)
{
    //TODO

}

void Standby(void)
{
    //TODO

}

MultiFunction()
{
LATAbits.LATA0=0;   //TODO
LATAbits.LATA1=1;

__delay_ms(2000);

	if (LATCbits.LATC3)
	Monitor();
	else
	Standby();

}

poll_buttons()      //TODO
{
//check buttons for switch. no need for debounce, polling is long in the case of keydown.

LATAbits.LATA0=1;
LATAbits.LATA1=0;
__delay_ms(5);

if (LATCbits.LATC4)
	Tune400();
if (LATCbits.LATC5)
	Tune425();
if (LATCbits.LATC6)
	Tune450();
if (LATCbits.LATC7)
	Tune475();

LATAbits.LATA0=0;
LATAbits.LATA1=1;
__delay_ms(5);

if (LATCbits.LATC4)
	Tune500();
if (LATCbits.LATC1)
	Tune525();
if (LATCbits.LATC2)
	Tune550();
if (LATCbits.LATC3)
	MultiFunction();
}

void RST_4707(void)
{
        LATAbits.LATA2 = 0;
        __delay_ms(50);
        LATAbits.LATA2 = 1;
}

void display_missing(void)
{
    lcd_clrline1();

    lcd_puts("Si4707 missing.");
}

void display_freq(void)
{
    lcd_clrline1();

    lcd_puts("FREQ: ");
    CheckStatus();
    //RESP4Byte
    temp25 = 25;
    temp10 = 10;
    tempn = RESP2Byte;
    tempy = 256;
    tempx = RESP3Byte;
    tempi = tempn*tempy;
    tempi = tempi+tempx;
    tempi = tempi*temp25;
    tempi = tempi/temp10;

    ltoa(buf,tempi,10);  //long conversion to buffer
    lcd_puts(buf);
    lcd_puts(" KHz");
}

int main(void) {

    OSCCONbits.IRCF = 0x0d;     //set OSCCON IRCF bits to select OSC frequency 4MHz
    OSCCONbits.SCS = 0x02;
    OPTION_REGbits.nWPUEN = 0;  //enable weak pullups (each pin must be enabled individually)

    init_io();

    __delay_ms(250);            //let the power settle

     lcd_init();
    __delay_ms(10);
     lcd_clear();

                                //display test message
    lcd_puts("iradan.com");
    lcd_goto(40);

    TRISBbits.TRISB6 = 1;

    SSPSTATbits.SMP = 1;
    SSPCONbits.SSPM=0x08;       // I2C Master mode, clock = Fosc/(4 * (SSPADD+1))
    SSPCONbits.SSPEN=1;         // enable MSSP port
    SSPADD = 0x27;              //figure out which one you can ditch sometime (probably either)
    SSP1ADD = 0x27;             // 100KHz
                                //0x09 = 100KHz
    // **************************************************************************************

    RST_4707();

    __delay_ms(100);                    // let everything settle.

    I2C_Start_Bit();                    // send start bit
    I2C_Control_Write();                // send control byte with read set
 
    x=0;                                // temp feature, TODO
    if (!SSP1CON2bits.ACKSTAT)
    x=1;                 //device there? /ACked?

    Send_I2C_Data(0x01);                //power up
    Send_I2C_Data(0x53);                //command per AN332
    Send_I2C_Data(0x05);
    I2C_Stop_Bit();

    __delay_ms(1000);                     //power up delay...

    I2C_Start_Bit();                     // send start bit
    I2C_Control_Write();                 // send control byte
    Send_I2C_Data(0x50);                 //Tune Frequency
    Send_I2C_Data(0x00);                 //0x00
    Send_I2C_Data(0xFD);                 //65020 (162.550)
    Send_I2C_Data(0xFC);                 //... FDFC
    I2C_Stop_Bit();

    __delay_ms(1000);                    //tuning delay

    if (x==1)
        display_freq();
    else    
        display_missing();

    lcd_clrline2();   //clear LCD line 2 by writting " " and return
    lcd_puts("RSSI: ");
    tempi = RESP4Byte;
    ltoa(buf,tempi,10);  //long conversion to buffer
    lcd_puts(buf);

    while (1) {
        poll_buttons();
        i=1;    //  do nothing for now..
        __delay_ms(100);                      // delay.. just because
    }
    return;
}