📄 cc1000if.c
字号:
/****************************************************************************/
/* Application note AN009 */
/* CC1000 MCU Interfacing */
/* */
/* File: cc1000if.c */
/* */
/* Microcontroller: */
/* Microchip PIC16F876 (written for the IAR C compiler) */
/* */
/* Note that all RF setting constants in this file are for 868.3MHz default */
/* settings. Use SmartRF(R) Studio to calculate the settings for your */
/* specific application */
/* */
/* Several comments specifying wait routines has been inserted into this */
/* file. As it is impossible to provide this routine without knowing */
/* the compiler and crystal frequency used for the MCU, these comments must */
/* be replaced with wait routines by the user of this code. */
/* */
/* Author: Karl H. Torvmark, Field Applications Engineer, Chipcon */
/* */
/* Contact: Chipcon AS +47 22 95 85 44 */
/* wireless@chipcon.com */
/****************************************************************************/
#include "io16f876.h"
#include "inpic.h"
#include "CC1000.h"
#include <stdio.h>
/* Pin usage definitions */
#define PDATA RC0
#define PCLK RC1
#define PALE RC2
#define DIO RC3
#define DCLK RB0
#define CHP_OUT RC5
/* The location of the interrupt handler vector. Must be changed for */
/* different PIC MCUs */
#define INTERRUPT_VECTOR 0x04
/* Configuration values for registers other than MAIN */
/* Replace these values with new values calculated by */
/* SmartRF(R) Studio for your application */
short Config[28] =
{0x0262, 0x0400, 0x0600, 0x0862, 0x0A03, 0x0C6A, 0x0E03, 0x1055,
0x128F, 0x1432, 0x16FF, 0x1828, 0x1A10, 0x1C25, 0x1E8D, 0x2061,
0x2222, 0x2420, 0x2601, 0x281C, 0x2A16, 0x2C10, 0x2E0A, 0x3006,
0x3203, 0x3401, 0x360D, 0x3800};
/* Contents of CURRENT register for TX and RX, use SmartRF(R) Studio */
/* to find values for your application */
#define TX_CURRENT 0xF3
#define RX_CURRENT 0x8C
/****************************************************************************/
/* This routine sends new configuration data to the CC1000 */
/****************************************************************************/
void ConfigureCC1000(char Count, short Configuration[])
{
char BitCounter;
char WordCounter;
union { /* This union is used to easily access the most significant */
/* bit of the configuration data */
/* Note : This assumes that the C compiler stores bit-fields */
/* with the first field going into the LSB. If this is not the */
/* case, move the MSB definition to the first bit */
unsigned short Data;
struct
{
unsigned short :1;
unsigned short :1;
unsigned short :1;
unsigned short :1;
unsigned short :1;
unsigned short :1;
unsigned short :1;
unsigned short :1;
unsigned short :1;
unsigned short :1;
unsigned short :1;
unsigned short :1;
unsigned short :1;
unsigned short :1;
unsigned short :1;
unsigned short MSB :1;
};
};
PALE=1;
for (WordCounter=0;WordCounter<Count;WordCounter++)
{
Data=Configuration[WordCounter];
PALE=0;
/* Send address bits */
for (BitCounter=0;BitCounter<7;BitCounter++)
{
PCLK=1;
PDATA=MSB;
Data=Data<<1;
PCLK=0;
}
/* Send read/write bit */
/* Ignore bit in data, always use 1 */
PCLK=1;
PDATA=1;
PCLK=0;
Data=Data<<1;
PCLK=1;
PALE=1;
/* Send data bits */
for (BitCounter=0;BitCounter<8;BitCounter++)
{
PCLK=1;
PDATA=MSB;
Data=Data<<1;
PCLK=0;
}
PCLK=1;
} /* Finished with word */
}
/****************************************************************************/
/* This routine writes to a single CC1000 register */
/****************************************************************************/
void WriteToCC1000Register(char addr, char data)
{
short val;
val=(addr&0x7F)<<9 | (data&0xFF);
ConfigureCC1000(1,&val);
}
/****************************************************************************/
/* This routine reads from a single CC1000 register */
/****************************************************************************/
char ReadFromCC1000Register(char addr)
{
char BitCounter;
union { /* This unit is used to easily access the most significant */
/* bit of the configuration data */
/* Note : This assumes that the C compiler stores bit-fields */
/* with the first field going into the LSB. If this is not the */
/* case, switch the MSB and LSB definitions */
unsigned char Data;
struct
{
unsigned char LSB :1;
unsigned char :1;
unsigned char :1;
unsigned char :1;
unsigned char :1;
unsigned char :1;
unsigned char :1;
unsigned char MSB :1;
};
};
PALE=1;
Data=addr<<1;
PALE=0;
/* Send address bits */
for (BitCounter=0;BitCounter<7;BitCounter++)
{
PCLK=1;
PDATA=MSB;
Data=Data<<1;
PCLK=0;
}
/* Send read/write bit */
/* Ignore bit in data, always use 0 */
PCLK=1;
PDATA=0;
PCLK=0;
PCLK=1;
PALE=1;
/* Receive data bits */
PDATA=1;
TRISC|=0x01; /* Set up PDATA as an input */
for (BitCounter=0;BitCounter<8;BitCounter++)
{
PCLK=0;
Data=Data<<1;
LSB=PDATA;
PCLK=1;
}
TRISC&=~0x01; /* Set up PDATA as an output again */
return Data;
}
/****************************************************************************/
/* This routine resets the CC1000, clearing all registers. */
/****************************************************************************/
void ResetCC1000(void)
{
char MainValue;
MainValue=ReadFromCC1000Register(CC1000_MAIN);
WriteToCC1000Register(CC1000_MAIN,MainValue & 0xFE); /* Reset CC1000 */
WriteToCC1000Register(CC1000_MAIN,MainValue | 0x01); /* Bring CC1000 out of reset */
}
/* Configures CC1000 according to values in Config[] array */
void SetupCC1000All(void)
{
ConfigureCC1000(28,Config);
}
/****************************************************************************/
/* This routine calibrates the CC1000 */
/****************************************************************************/
void CalibrateCC1000(void)
{
char PAVal;
PAVal=ReadFromCC1000Register(CC1000_PA_POW); /* Store PA settings */
WriteToCC1000Register(CC1000_PA_POW,0x00); /* Turn off PA to avoid spurs */
/* during calibration in TX mode */
WriteToCC1000Register(CC1000_CAL,0xA5); /* Start calibration */
while((ReadFromCC1000Register(CC1000_CAL)&0x08)==0); /* Wait until calibration finished */
WriteToCC1000Register(CC1000_CAL,0x25); /* End calibration */
WriteToCC1000Register(CC1000_PA_POW,PAVal); /* Restore PA setting */
}
/****************************************************************************/
/* This routine puts the CC1000 into RX mode (from TX). When switching to */
/* RX from PD, use WakeupC1000ToRX first */
/****************************************************************************/
void SetupCC1000RX(void)
{
WriteToCC1000Register(CC1000_MAIN,0x31); /* Switch into RX, switch to freq. reg A */
WriteToCC1000Register(CC1000_CURRENT,RX_CURRENT); /* Program VCO current for RX */
/* Insert 150us wait here */
WriteToCC1000Register(CC1000_MAIN,0x11); /* Switch RX part of CC1000 on */
}
/****************************************************************************/
/* This routine puts the CC1000 into TX mode (from RX). When switching to */
/* TX from PD, use WakeupCC1000ToTX first */
/****************************************************************************/
void SetupCC1000TX(void)
{
WriteToCC1000Register(CC1000_MAIN,0xF1); /* Switch into TX, switch to freq. reg B */
WriteToCC1000Register(CC1000_CURRENT,TX_CURRENT); /* Program VCO current for TX */
/* Insert 150us wait here */
WriteToCC1000Register(CC1000_MAIN,0xA1); /* Switch TX part of CC1000 on */
}
/****************************************************************************/
/* This routine puts the CC1000 into power down mode. Use WakeUpCC1000ToRX */
/* followed by SetupCC1000RX or WakeupCC1000ToTX followed by SetupCC1000TX */
/* to wake up from power down */
/****************************************************************************/
void SetupCC1000PD(void)
{
WriteToCC1000Register(CC1000_MAIN,0x3F); /* Put CC1000 into power-down */
}
/****************************************************************************/
/* This routine wakes the CC1000 up from PD mode to RX mode, call */
/* SetupCC1000RX after this routine is finished. */
/****************************************************************************/
void WakeUpCC1000ToRX(void)
{
WriteToCC1000Register(CC1000_MAIN,0x3B); /* Turn on xtal oscillator core */
WriteToCC1000Register(CC1000_CURRENT,RX_CURRENT); /* Program VCO current for RX */
/* Insert wait routine here, must wait for xtal oscillator to stabilise, */
/* typically takes 2-5ms. */
WriteToCC1000Register(CC1000_MAIN,0x39); /* Turn on bias generator */
/* Insert 200us wait here */
WriteToCC1000Register(CC1000_MAIN,0x31); /* Turn on frequency synthesiser */
/* Insert 250us wait here */
}
/****************************************************************************/
/* This routine wakes the CC1000 up from PD mode to TX mode, call */
/* SetupCC1000TX after this routine is finished. */
/****************************************************************************/
void WakeUpCC1000ToTX(void)
{
WriteToCC1000Register(CC1000_MAIN,0xFB); /* Turn on xtal oscillator core */
WriteToCC1000Register(CC1000_CURRENT,TX_CURRENT); /* Program VCO current for TX */
/* Insert wait routine here, must wait for xtal oscillator to stabilise, */
/* typically takes 2-5ms. */
WriteToCC1000Register(CC1000_MAIN,0xF9); /* Turn on bias generator */
/* Insert 200us wait here */
WriteToCC1000Register(CC1000_MAIN,0xF1); /* Turn on frequency synthesiser */
/* Insert 250us wait here */
}
void AverageManualLockCC1000(void)
{
WriteToCC1000Register(CC1000_MODEM1,0x19);
}
void AverageFreeRunCC1000(void)
{
WriteToCC1000Register(CC1000_MODEM1,0x09);
}
void AverageAutoLockCC1000(void)
{
WriteToCC1000Register(CC1000_MODEM1,0x01);
}
void ReadCurrentCalibration(char *val1, char *val2)
{
*val1=ReadFromCC1000Register(CC1000_TEST0);
*val2=ReadFromCC1000Register(CC1000_TEST2);
}
void OverrideCurrentCalibration(char val1, char val2)
{
WriteToCC1000Register(CC1000_TEST5,(val1&0x0F)|0x10);
WriteToCC1000Register(CC1000_TEST6,(val2&0x1F)|0x20);
}
void StopOverridingCalibration(void)
{
WriteToCC1000Register(CC1000_TEST5,0x00);
WriteToCC1000Register(CC1000_TEST6,0x00);
}
char last;
/****************************************************************************/
/* Interrupt routine which writes new data to the DIO pin each time the */
/* external interrupt occurs. This is an example of how a program can */
/* provide data in TX mode. */
/****************************************************************************/
#pragma vector=INTERRUPT_VECTOR
__interrupt void InterruptHandler(void)
{
/* Time to write DIO */
if (last==0) {
last=1;
DIO=1;
} else {
last=0;
DIO=0;
}
INTF=0;
}
/* Main program starts here */
void main(void)
{
/* Set up the MCU registers */
PORTC=0x00;
TRISC=0xA0;
PORTB=0x00;
TRISB=0xF9;
PORTA=0x00;
TRISA=0x0B;
ADCON1=0x84;
TXSTA=0x24;
RCSTA=0x90;
SPBRG=129;
PORTA=0xFF;
PIE1=0x00;
T1CON=0x00;
OPTION=0x00;
/* Start of recommended power-up routine */
SetupCC1000PD(); /* Initialise MAIN register */
ResetCC1000(); /* Reset CC1000 */
SetupCC1000All(); /* Set up CC1000 registers */
/* Calibrate both RX and TX */
WakeUpCC1000ToRX(); /* Wake up CC1000 to RX mode */
SetupCC1000RX(); /* Put CC1000 into RX mode */
CalibrateCC1000(); /* Calibrate CC1000 */
SetupCC1000TX(); /* Put CC1000 into TX mode */
CalibrateCC1000(); /* Calibrate CC1000 */
SetupCC1000PD(); /* Put CC1000 into PD mode */
/* Wake up into TX mode */
WakeUpCC1000ToTX(); /* Wake up CC1000 from PD */
SetupCC1000TX(); /* Put CC1000 into TX mode */
/* Enable external interrupt */
INTCON=0xD0;
while(1==1) {
/* Infinite loop, insert your code here */
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -