?? rfmodem_cc1020.c
字號:
/****************************************************************************/
/* Reference design : CC1020 RF Modem */
/* */
/* File: rfmodem_cc1020.c */
/* */
/* Microcontroller: */
/* Microchip PIC16F876 */
/* */
/* Author: Karl H. Torvmark, Field Applications Engineer, Chipcon */
/* Torgeir Sundet, FAE - Software */
/* */
/* Contact: Chipcon AS +47 22 95 85 44 */
/* support@chipcon.com */
/****************************************************************************/
/****************************************************************************/
/* Description: */
/* */
/* This application note presents a software and hardware reference design */
/* for the CC1020. 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 */
/* CC1020, 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. */
/* */
/****************************************************************************/
/* *
* Revision history: *
* *
* $Log: rfmodem_cc1020.c,v $
* Revision 1.2 2003/09/17 15:03:07 tos
* Mod's:
* - introduced new menu option ('J'): access (w/r) CC1020 register.
* - update EEPROM variable+table upon register write access ('J').
* - introduced new configuration option ('I'): preamble length.
* - moved TX buffer initialisation after configuration.
* - corrected inconsistent number conversion funtion.
*
* Revision 1.1 2003/07/31 13:17:30 tos
* Initial version in CVS.
*
*
* *
****************************************************************************/
#include "io16f876.h"
#include "inpic.h"
#include "CC1020.h"
#include "modemhw.h"
#include "configure.h"
#include "main.h"
#include "simpleio.h"
#include <stdio.h>
#define INTERRUPT_VECTOR 0x04
// 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.
// Variables
// Unit address is not used
extern __eeprom char UnitAddress;
// Union for shifting bits in or out of the CC1020
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
volatile enum StateType 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 FreezeAGCLevel:1;
unsigned char ReleaseAGCLevel:1;
unsigned char LastDataBit:1;
};
// This routine initialises the TX buffer at startup
void InitializeTXBuffer(void)
{
char i;
// Put preamble into buffer
for(i=0;i<PreambleLength;i++){
TXBuffer[i]=PREAMBLE_BYTE;
}
TXBuffer[PreambleLength+0]=UI1; // First byte of unique identifier
TXBuffer[PreambleLength+1]=UI2; // Second byte of unique identifier
TXBuffer[PreambleLength+2]=UnitAddress; // Unit address
TXBuffer[PreambleLength+3]=0x00; // Data length, 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
SetupCC1020RX(RXANALOG, PA_POWER);
}
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
SetupCC1020TX(TXANALOG, PA_POWER);
}
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[PreambleLength+3]=BytesToSend-HEADER_SIZE-PreambleLength;
LastDataBit = FALSE;
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
SetupCC1020RX(RXANALOG, PA_POWER);
}
State=IDLE_STATE;
SET_RXLED(OFF);
SET_TXLED(OFF);
READY=0; // HW Handshake : Ready
RCIE=1; // Enable UART Interrupts
TXBufferIndex=HEADER_SIZE+PreambleLength;
PreambleCount=0;
PreambleError=0;
PreambleFound=FALSE;
UI1Found=FALSE;
break;
}
}
// Main program
void main(void)
{
char dummy;
volatile int i;
volatile char PacketCount = 0;
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
SetupCC1020ForSPI();
#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;
PSEL=1;
RXBufferReadIndex=0;
RXBufferWriteIndex=0;
SetupCC1020PD();
ResetCC1020();
SetupCC1020All();
WakeUpCC1020ToTX(TXANALOG);
OPTION=0x80; // INT on falling edge
TRISC&=~(0x02); // Set DIO as output
if (!CalibrateCC1020(PA_POWER))
writeln("TX Calibration failed");
// Calibration data is stored in the chip indexed by the selected frequency register
WakeUpCC1020ToRX(RXANALOG);
OPTION=0xC0; // INT on rising edge
TRISC|=0x02; // Set DIO as input
if (!CalibrateCC1020(PA_POWER))
writeln("RX Calibration failed");
// Now the CC1020 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;
// 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();
}
InitializeTXBuffer();
TRISA=dummy;
AWAKE=0;
SYNC=0;
ReleaseAGCLevel=FALSE;
FreezeAGCLevel=FALSE;
LastDataBit = FALSE;
// Startup message
writeln("RF Modem ready");
writestr("Compiled ");
writestr(__DATE__);
writestr(" ");
writestr(__TIME__);
writeln("");
if((ReadFromCC1020Register(CC1020_ANALOG)&0x80)==0x80){
writestr("804-940 MHz band");
}else{
writestr("402-470 MHz band");
}
writestr(", 4.8 kbit/s");
if((ReadFromCC1020Register(CC1020_MODEM)&0x03)==0x01){
writestr(", Manchester mode");
}else{
writestr(", NRZ mode");
}
writeln("");
INTCON=0x90;
// Monitor input from UART+RF+BUTTONS and select corresponding state:
while(1){
// If new state requested, enter requested state
if(State!=NextState){
ChangeState();
}
// If received RF data, send it to the serial port
if(RXBufferReadIndex!=RXBufferWriteIndex){
putchar(RXBuffer[RXBufferReadIndex]);
//RXBufferReadIndex=(RXBufferReadIndex+1)%RX_BUFFER_SIZE;
RXBufferReadIndex++;
RXBufferReadIndex&=0x3F;
}
// If received UART data and RF in IDLE state, copy UART data into RF packet
if(RCIF==1){
if(State==IDLE_STATE){
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)){
NextState=TX_STATE;
}
RCIF=0;
}
}
// If Timer-2 timeout (since received last UART data)
if(TMR2IF==1){
// Request TX state to send last UART data via RF
TMR2ON=0;
TMR2IE=0;
NextState=TX_STATE;
TMR2IF=0;
}
// If Timer-1 timeout and buttons pressed
if(TMR1IF==1){
// Copy fixed character into RF packet and request TX state:
dummy=TRISA;
TRISA|=0x24; // Set port to read button status
if(State==IDLE_STATE){
if(BUTTON1==0){
PacketCount = ((PacketCount+1 > 9) ? 0 : (PacketCount+1));
TXBuffer[TXBufferIndex++]=Button1Char;
TXBuffer[TXBufferIndex++]=PacketCount+'0';
TXBuffer[TXBufferIndex++]=' ';
NextState=TX_STATE;
}
if(BUTTON2==0){
PacketCount = ((PacketCount+1 > 9) ? 0 : (PacketCount+1));
TXBuffer[TXBufferIndex++]=Button2Char;
TXBuffer[TXBufferIndex++]=PacketCount+'0';
TXBuffer[TXBufferIndex++]=' ';
NextState=TX_STATE;
}
}
TRISA=dummy; // Set port back to LED operation
TMR1IF=0;
}
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -