⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rfmodem_cc1000.c

📁 单片无限收发芯片的一些资料
💻 C
字号:
/****************************************************************************/
/* Application note AN015                                                   */
/* Reference design : CC1000 RF Modem                                       */
/*                                                                          */
/* File:      rfmodem_cc1000.c                                              */
/* Revision:  1.0                                                           */
/*                                                                          */
/* Microcontroller:                                                         */
/*          Microchip PIC16F876                                             */
/*                                                                          */
/* Author:  Karl H. Torvmark, Field Applications Engineer, Chipcon          */
/*                                                                          */
/* Contact: Chipcon AS +47 22 95 85 44                                      */
/*          wireless@chipcon.com                                            */
/****************************************************************************/


/****************************************************************************/
/* Description:                                                             */
/*                                                                          */
/* This application note presents a software and hardware reference design  */
/* for the CC1000. This software can serve as a starting point for          */
/* developing custom software. A full protocol is implemented, with         */
/* provisions for addressing, error checking etc.                           */
/*                                                                          */
/* This software contains routines for detecting the preamble, searching    */
/* for the start-of-frame (SOF) marker and doing byte synchronisation,      */
/* and reading and handling header data such as the packet length.          */
/*                                                                          */
/* The software also contains all necessary routines to configure the       */
/* CC1000, and demonstrates how to read and write data to the data          */
/* interface. Configuration data is stored in non-volatile EEPROM memory,   */
/* so that changes are preserved even when power is removed. Easy           */
/* modification of parameters such as RF frequency and data rate is         */
/* supported through a configuration menu.                                  */
/*                                                                          */
/* Please see the main text of application note AN015 for a more detailed   */
/* description.                                                             */
/****************************************************************************/

/*                                                                           *
 * Revision history:                                                         *
 *                                                                           *
 * $Log: rfmodem_cc1000.c,v $
 * Revision 2.5  2003/05/07 15:02:31  tos
 * Modified LOCK monitor in RX/TX setup: wait for LOCK before turning PA on.
 *
 * Revision 2.4  2003/04/25 13:30:06  tos
 * Removed UART baudrate test (baudrate=2.4 kBaud).
 *
 * Revision 2.3  2003/04/25 13:12:47  tos
 * Corrected inconsistent [UART interrupt request flag] monitor.
 *
 * Revision 2.2  2003/04/24 12:44:59  tos
 * Corrected inconsistent monitoring of CC1000: [calibration complete] + [lock].
 *
 * Revision 2.1  2003/03/04 10:43:18  tos
 * Corrected inconsistent AND instruction in CalibrateCC1000().
 *
 *                                                                           *
 ****************************************************************************/

#include "io16f876.h"
#include "inpic.h"
#include "CC1000.h"
#include "modemhw.h"
#include "configure.h"
#include "simpleio.h"
#include <stdio.h>

#define INTERRUPT_VECTOR 0x04

#define HEADER_SIZE 4           // 4 bytes header 

// The wrap-around functionality has been optimised by ANDing with a bit mask. 
// Please note that if RX_BUFFER_SIZE is to be changed, the lines of code which
// do this must also be changed. They are located in the main loop of the program
// and in 

#define TX_BUFFER_SIZE 64       // Size (in bytes) of transmit buffer
#define RX_BUFFER_SIZE 64       // Size (in bytes) of receive ring-buffer

#define PREAMBLE_LENGTH 4       // Number of bytes of preamble to send */
#define PREAMBLE_REQ 4          /* Number of bits required in addition to */
                                /* the initial 8 bits for the preamble to be */
                                /* accepted */

#define UI1 0x33		/* First byte of unique identifier */
#define UI2 0xCC		/* Second byte of unique identifier */

#define FALSE 0
#define TRUE (!FALSE)

#define ON TRUE
#define OFF FALSE


// Macros for turning on and off the LEDs

#define SET_RXLED(STATE) \
  if (STATE)             \
    TRISA&=~0x04;        \
  else                   \
    TRISA|=0x04;         \

#define SET_TXLED(STATE) \
  if (STATE)             \
    TRISA&=~0x20;        \
  else                   \
    TRISA|=0x20;         \



// Variables

// Unit address is not used
extern __eeprom char UnitAddress;

// Union for shifting bits in or out of the CC1000
union {
  char ShiftReg;
  struct {
    unsigned char ShiftRegLSB :1;
    unsigned char :1;
    unsigned char :1;
    unsigned char :1;
    unsigned char :1;
    unsigned char :1;
    unsigned char :1;
    unsigned char ShiftRegMSB :1;
  };
};
                                 
// Buffers for transmitted and received data
// These are put into different banks so that they can be as large as possible
// The TX buffer is filled up with data to be sent in the next data packet
// The RX buffer is a ring buffer in which received data is stored waiting to be
// sent to the UART
                                
volatile __bank1 char TXBuffer[TX_BUFFER_SIZE]; 
volatile __bank2 char RXBuffer[RX_BUFFER_SIZE];

// Index pointers for use with buffers 
volatile char TXBufferIndex;            
char RXBufferReadIndex;
volatile char RXBufferWriteIndex;

// Counter variables
char PreambleCount;
char PreambleError;
char ByteCounter;
char BitCounter;

// Contains the total number of bytes to send in TX, including preamble and header
char BytesToSend;
// The number of bytes of data to receive in RX
char BytesToReceive;



// State variable stores the current state of the state machine
enum StateType {IDLE_STATE=0,RX_STATE=1,TX_STATE=2} State;

// This variable stores the state to switch to
// It is updated by the interrupt routine, while the main program
// does the actual state switch
volatile enum StateType NextState;


// This struct stores various flags in a space-efficient manner
volatile struct
  {
    unsigned char PreambleFound:1;
    unsigned char UI1Found:1;
    unsigned char LastPreambleBit:1;
    unsigned char LockAverage:1;
    unsigned char UnlockAverage:1;
  };


// This routine initialises the TX buffer at startup
void InitializeTXBuffer(void)
{
  char i;
  
  // Put preamble into buffer
  for (i=0;i<PREAMBLE_LENGTH;i++) {
    TXBuffer[i]=0xAA;
  }
 
  TXBuffer[PREAMBLE_LENGTH]=UI1;              // First byte of unique identifier
  TXBuffer[PREAMBLE_LENGTH+1]=UI2;            // Second byte of unique identifier
  TXBuffer[PREAMBLE_LENGTH+2]=UnitAddress;    // Unit address
  TXBuffer[PREAMBLE_LENGTH+3]=0x00;           // Default : no data  
}




// This routine handles setup needed when changing states
void ChangeState(void) 
{
  switch (NextState) {
    case RX_STATE:
      if (State==TX_STATE) {
        OPTION=0xC0;        /* INT on rising edge */
        TRISC|=0x02;        /* Set DIO as input */
        SetupCC1000RX(RXCurrent,RXPLL);
      }
    
      State=RX_STATE;
      
      SET_RXLED(ON); 
      SET_TXLED(OFF);
      READY=1;  // HW Handshake : Not Ready
      
      BitCounter=0;
      ByteCounter=0;
      break;
    case TX_STATE:
      if (State!=TX_STATE) {
        OPTION=0x80;        /* INT on falling edge */
        TRISC&=~(0x02);     /* Set DIO as output */
        SetupCC1000TX(TXCurrent,TXPLL);
      }

      State=TX_STATE;

      SET_RXLED(OFF);
      SET_TXLED(ON);
      READY=1;  // HW Handshake : Not Ready
      RCIE=0;   // Disable UART Interrupts
      
      BytesToSend=TXBufferIndex; // Number of bytes to send
      TXBuffer[PREAMBLE_LENGTH+3]=BytesToSend-HEADER_SIZE-PREAMBLE_LENGTH;

      TXBufferIndex=0;
      BitCounter=0;
      ShiftReg=TXBuffer[TXBufferIndex++];
      break;
    case IDLE_STATE:
      if (State==TX_STATE) {
        OPTION=0xC0;        /* INT on rising edge */
        TRISC|=0x02;        /* Set DIO as input */
        SetupCC1000RX(RXCurrent,RXPLL);
      }

      State=IDLE_STATE;

      SET_RXLED(OFF);
      SET_TXLED(OFF);
      READY=0;  // HW Handshake : Ready
      RCIE=1;   // Enable UART Interrupts
      
      TXBufferIndex=HEADER_SIZE+PREAMBLE_LENGTH;
      PreambleCount=0;
      PreambleError=0;
      PreambleFound=FALSE;
      UI1Found=FALSE;
      break;
  }
}


// Main program
void main(void)
{
  char dummy;
  PORTC=0x00;
  TRISC=0x92;
  
  PORTB=0x00;
  TRISB=0xFD;
  
  PORTA=0x00;
  TRISA=0x0B;
  
  ADCON0=0x89;  
  ADCON1=0x84;
  
  TXSTA=0x24;
  RCSTA=0x90;
  SPBRG=10;  // 10.0000MHz, 57600baud
  
  TMR1L=0x00;
  TMR1H=0x00;
  T1CON=0x31; /* Enable timer 1 */
  #ifdef SPI
  // Configure SPI
  SSPSTAT=0x40; 
  SSPCON=0x30;
  #endif
    
 // PIE1=0x21; // UART and timer 1 enabled

  PIE1=0x00;
  
  /* Timer 2 time-out value */
  /* Set to 10ms at 10MHz = 25000 instructions*/
  T2CON=0x4B;
  PR2=0xFF;
  
  PALE=1;
  
  RXBufferReadIndex=0;
  RXBufferWriteIndex=0;
  SetupCC1000PD();
  ResetCC1000();
  
  SetupCC1000All();
  
  WakeUpCC1000ToTX(TXCurrent,TXPLL);
  SetupCC1000TX(TXCurrent,TXPLL);
  OPTION=0x80;        // INT on falling edge
  TRISC&=~(0x02);     // Set DIO as output
  if (!CalibrateCC1000())
    writeln("TX Calibration failed");
  // Calibration data is stored in the chip indexed by the selected frequency register 
  
  SetupCC1000RX(RXCurrent,RXPLL);
  OPTION=0xC0;        // INT on rising edge
  TRISC|=0x02;        // Set DIO as input
  if (!CalibrateCC1000())
    writeln("RX Calibration failed");
  
  // Now the CC1000 is calibrated for both RX and TX, we do not need to recalibrate
  // unless the frequency is changed, the temperature changes by 40 degrees C
  // or if the supply voltage changes by more than 0.5V 
  
  // Force update
  State=TX_STATE;
  NextState=IDLE_STATE;
  
  InitializeTXBuffer();
  
  // Set all buttons to light, if we want to turn them off, we set them as inputs to avoid
  // the output being shorted to VDD if a button is pressed
   
  CARRIER_LED=0;
  RD_LED=0;
  TD_LED=0;
  
  dummy=TRISA;
  TRISA|=0x24;
  if (BUTTON1==0) {
  }
  if (BUTTON2==0) {
    ConfigurationMode();
  }
  
  TRISA=dummy;
  
  AWAKE=0;
  SYNC=0;
  
  LockAverage=0;
  UnlockAverage=0;
  
  /* Startup message */
  
  writeln("RF Modem ready");
  writestr("Compiled ");
  writestr(__DATE__);
  writestr(" ");
  writestr(__TIME__);
  writeln("");
  
  dummy=ReadFromCC1000Register(CC1000_MODEM0);
  
  switch(dummy) {
    case 0x07:
      writestr("0.3kbit/s Manchester");
      break;
    case 0x03:
      writestr("0.6kbit/s NRZ");
      break;
    case 0x17:
      writestr("0.6kbit/s Manchester");
      break;
    case 0x13:
      writestr("1.2kbit/s NRZ");
      break;
    case 0x27:
      writestr("1.2kbit/s Manchester");
      break;
    case 0x23:
      writestr("2.4kbit/s NRZ");
      break;
    case 0x37:
      writestr("2.4kbit/s Manchester");
      break;
    case 0x33:
      writestr("4.8kbit/s NRZ");
      break;
    case 0x47:
      writestr("4.8kbit/s Manchester");
      break;
    case 0x43:
      writestr("9.6kbit/s NRZ");
      break;
    case 0x57:
      writestr("9.6kbit/s Manchester");
      break;
    case 0x53:
      writestr("19.2kbit/s NRZ");
      break;
    case 0x55:
      writestr("19.2kbit/s Manchester");
      break;
    case 0x51:
      writestr("38.4kbit/s NRZ");
      break;
    case 0x54:
      writestr("38.4kbit/s Manchester");
      break;
    case 0x50:
      writestr("76.8kbit/s NRZ");
      break;
    default:
      writestr("Invalid data rate");
      break;
  }
  
  writeln("");

  AverageFreeRunCC1000();  
  
  INTCON=0x90;
  
  while(1) {    
    /* If state change, handle it */
    if (State!=NextState)
      ChangeState();        
      
    if (UnlockAverage) {
      UnlockAverage=0;
      AverageFreeRunCC1000();
    }
    if (LockAverage) {
      LockAverage=0;
      AverageManualLockCC1000();
    }
      
    /* If data in receive buffer, write it to the serial port */
    if (RXBufferReadIndex!=RXBufferWriteIndex) {
      putchar(RXBuffer[RXBufferReadIndex]);
      // Increase read index, wrap around when reached end of buffer
      //RXBufferReadIndex=(RXBufferReadIndex+1)%RX_BUFFER_SIZE;
      RXBufferReadIndex++;
      RXBufferReadIndex&=0x3F;
    }
    if (RCIF==1) {
    // UART receive interrupt. PC has sent data to us.
      if (State==IDLE_STATE) {  // Only handle data if idle
        TMR2=0;   // Reset time-out timer
        TMR2ON=1; // Start time-out timer
        
        // TODO : Handle framing and overflow errors
        if (OERR) {
          TXEN=0;
          TXEN=1;
          CREN=0;
          CREN=1;
        }
        if (FERR) {
          dummy=RCREG;
          TXEN=0;
          TXEN=1;
        }
        
        TXBuffer[TXBufferIndex++]=RCREG;
        
        // IMPORTANT : We may have another interrupt or two occur before we can change mode
        // Therefore, leave safety margin!
        if (TXBufferIndex>=(TX_BUFFER_SIZE-3)) {  // Change mode early to have safety margin
          NextState=TX_STATE;
        }

        RCIF=0;
      }
    }
  
  if (TMR2IF==1) {
    // Timer 2 interrupt. TX timer has timed out. 
    TMR2ON=0;   // Turn off timer 2
    TMR2IE=0;   // Turn off timer 2 interrupt
    
    NextState=TX_STATE;
    
    TMR2IF=0;
  }
  
  if (TMR1IF==1) {
    // Timer 1 interrupt. Check button status 

    dummy=TRISA;
    TRISA|=0x24;  // Set port to read button status 
    
    
    if (BUTTON1==0) {
      TXBuffer[TXBufferIndex++]=Button1Char;
      NextState=TX_STATE;
    }
    if (BUTTON2==0) {
      TXBuffer[TXBufferIndex++]=Button2Char;
      NextState=TX_STATE;
    }
    
    TRISA=dummy;  // Set port back to LED operation 
    TMR1IF=0;
  }
    
  }

}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -