📄 radiocontrol.c
字号:
/*
****************************************************************************
*
* 宁波中科集成电路设计中心 版权所有 Copyright 2005
*
*文件名: Radiocontrol.c
*程序员:
*主要内容:射频通信物理层硬件控制
*完成日期:2005.5.25
****************************************************************************
*/
#include "radiocontrol.h"
#include "physical.h"
#include "adc.h"
#include "fun.h"
#include "cc1000.h"
#include "mac.h"
#include "led.h"
enum {
INIT,
SLEEP,
IDLE,
SYNC_START,
RECEIVE,
TRANSMIT
}; // 射频控制模块状态值
enum {
SYNC_WORD = 0x33cc,
NSYNC_WORD = 0xcc33
};
enum {
PREAMBLE_LEN = 18,
VALID_PRECURSOR = 5,
BUSY_THRESHOLD = 0xef, // 表示信道忙的RSSI门限值,值越小,信号强度越大
EW_THRESHOLD = 0x120, // 需要进行扩展监听的门限值
NUM_EXT_BYTES = 3
};
uint8_t state; // 状态变量
uint16_t carrSenTime; // 载波监听次数
uint16_t csVal1; // 上次监听值
uint16_t csValAve; // 上次与本此监听平均值
uint8_t extFlag; // 载波监听扩展标识
uint8_t nextByte; // 缓存下一个要发送的字节
static uint8_t txCount; // 发送字节计数
bool bManchesterBad;
bool bInvertRxData; // CC1000传来的数据是否反转
bool bRSSIEnable; // RSSI使能标识
uint8_t PreambleCount; // 导频计数
uint8_t SOFCount; // 同步偏移计数
union {
uint16_t W;
struct {
uint8_t LSB;
uint8_t MSB;
};
} RxShiftBuf; // 移位缓存,用于同步
char start[2] = {0x33, 0xcc}; // 同步字节
uint8_t RxBitOffset; //同步结果,即偏移的比特数
uint16_t LocalAddr;
/*************************************************************************
*功能描述:射频控制模块初始化,CC1000、SPI初始化
*参数说明:无
*返回值: 成功
**************************************************************************/
result_t RadiocontrolInit()
{
// 状态变量初始化;
state = INIT;
OSH_MAKE_SPI_SCK_INPUT(); // SPI SCK为输入
CC1000ControlStdControlInit(); // CC1000初始化配置
CC1000ControlSelectLock(0x9); // CC1000PLL设置
bInvertRxData = CC1000ControlGetLOStatus(); // CC1000数据是否需要反转
ADCBindPort(OS_ADC_CC_RSSI_PORT, OSH_ACTUAL_CC_RSSI_PORT);
ADCControlInit(); // 打开ADC RSSI通道
RadiocontrolIdle();
return SUCCESS;
}
/*************************************************************************
*功能描述:射频控制进入空闲状态,CC1000、SPI进入接收状态
*参数说明:无
*返回值: 成功
**************************************************************************/
result_t RadiocontrolIdle()
{
if (state == IDLE)
return SUCCESS;
if (state == SYNC_START) {
state = IDLE;
return SUCCESS;
}
if (state == SLEEP) { // 打开CC1000
CC1000ControlStdControlStart();
} else {
* (volatile unsigned char *)(0x0D + 0x20) = 0x00;// 关SPI和SPI中断
}
CC1000ControlRxMode(); //CC1000设为接收模式
// 配置SPI为输入
OSH_MAKE_MISO_INPUT();
OSH_MAKE_MOSI_INPUT();
* (volatile unsigned char *)(0x0D + 0x20) = 0xc0; // 开SPI和SPI中断
state = IDLE;
return SUCCESS;
}
/*************************************************************************
*功能描述:射频控制进入睡眠状态,CC1000、SPI进入关闭状态
*参数说明:无
*返回值: 成功
**************************************************************************/
result_t RadiocontrolSleep()
{
if (state == SLEEP)
return SUCCESS;
* (volatile unsigned char *)(0x0D + 0x20) = 0x00; // 关SPI和SPI中断
CC1000ControlStdControlStop(); // 关CC1000
state = SLEEP;
return SUCCESS;
}
/*************************************************************************
*功能描述:设置载波监听的比特数(实际监听为字节数,因为每次监听的ADC调用由一
* 次SPI中断调用引发,故一次监听为一个字节的RSSI),
*参数说明:要监听的位数
*返回值: 成功
**************************************************************************/
result_t RadiocontrolCarrierSenseStart(uint16_t numBits)
{
if (state != IDLE) // 只有空闲时才允许监听
return FAIL;
extFlag = 0;
carrSenTime = numBits >> 3; // 转化为字节数
csVal1 = 0x180;
return SUCCESS;
}
/*************************************************************************
*功能描述:ADC中断调用,表明RSSI数据到达,判断信道空闲与否
*参数说明:ADC采集到的数据
*返回值: 成功
**************************************************************************/
result_t RadiocontrolRSSIADCDataReady(uint16_t data) // 判断信道是否空闲
{
if (state == IDLE && carrSenTime > 0) {
csValAve = (csVal1 + data) >> 1; // 相邻两次监听的平均值;
if (csValAve < BUSY_THRESHOLD) { // 因为CC1000提供的是反电压值,所以值越小,信号越强;
carrSenTime = 0;
MACChannelBusy();
//加入对上层函数的调用, 通知信道忙
} else {
MACChannelIdle();
}
} else if (state == SYNC_START || state == RECEIVE) {
}
return SUCCESS;
}
/*************************************************************************
*功能描述:启动发送数据包的流程,并准备要发送的导频字节,CC1000、SPI进入发送态
*参数说明:无
*返回值: 成功
**************************************************************************/
result_t RadiocontrolStartTx()
{
char temp;
* (volatile unsigned char *)(0x0D + 0x20) = 0x00; // 关SPI中断
if (state == SLEEP) { // 如果睡眠则唤醒
CC1000ControlStdControlStart();
}
nextByte = 0xaa; // 缓存下一个要发送的字节
txCount = 2;
temp = * (volatile unsigned char *)(0x0E + 0x20); // 清空SPSR寄存器
* (volatile unsigned char *)(0x0F + 0x20) = 0xaa;; //将要发送的第一个字节写入SPDR
//进入发送模式
CC1000ControlTxMode();
OSH_MAKE_MISO_OUTPUT();
OSH_MAKE_MOSI_OUTPUT();
* (volatile unsigned char *)(0x0D + 0x20) = 0xc0; // 开SPI中断
state = TRANSMIT;
return SUCCESS;
}
/*************************************************************************
*功能描述:供上层调用,把下一个要发送的字节存入发送缓冲
*参数说明:要发送的字节
*返回值: 成功
**************************************************************************/
result_t RadiocontrolTxNextByte(char data) // 准备下一个要发送的字节
{
nextByte = data;
// uartDebug_txByte(data);
return SUCCESS;
}
/*************************************************************************
*功能描述:SPI中断服务程序,由CC1000的时钟信号引发,与CC1000同步,即数据率相同
* 根据本地状态进行相应的处理,为上层提供服务
*参数说明:无
*返回值: 成功
**************************************************************************/
void __attribute((signal)) __vector_17(void)
{
uint8_t data;
data = * (volatile unsigned char *)(0x0F + 0x20); // 从SPDR读入字节
if (bInvertRxData) data = ~data;
if (state == TRANSMIT) { // 发送状态
* (volatile unsigned char *)(0x0F + 0x20) = nextByte;// 发送缓存中的字节
if (txCount < PREAMBLE_LEN) { // 继续发送导频
nextByte = 0xaa;
txCount++;
} else if (txCount < PREAMBLE_LEN + sizeof(start)) {// 导频发送完毕
nextByte = start[txCount - PREAMBLE_LEN]; // 发两个同步字节;
txCount++;
} else {
PhysicalTxByteReady();
//加入对上层函数的调用 // 通知上层发送数据包;
}
} else if (state == IDLE) { // 空闲
bManchesterBad = * (volatile unsigned char *)(0x1A + 0x20) & 0x40;// CHP_OUT位
if ((!bManchesterBad) && (data == 0xaa || data == 0x55)) {
PreambleCount++;
if (PreambleCount > VALID_PRECURSOR) { // 接收到足够的导频字节
state = SYNC_START;
if (carrSenTime > 0) { // MAC层正在进行载波监听
carrSenTime = 0; // 停止监听
MACChannelBusy();
}
}
} else {
PreambleCount = 0; // 导频计数置0
}
if (carrSenTime > 0) // 调用ADC采集监听数据
ADCGetData(OS_ADC_CC_RSSI_PORT);
} else if (state == SYNC_START) { // 接收同步字
uint8_t i;
if (data == 0xaa || data == 0x55) {
SOFCount = 0; // 再收到同步字节则丢弃
} else { // 进行同步
uint8_t usTmp;
SOFCount++;
switch (SOFCount) {
case 1:
RxShiftBuf.MSB = data;
break;
case 2:
RxShiftBuf.LSB = data;
if (RxShiftBuf.W == SYNC_WORD) {
state = RECEIVE;
RxBitOffset = 0; // 通知上层检测到起始符号且同步完成
if (PhysicalStartSymDetected() == FAIL) {
RadiocontrolIdle();
}
}
break;
case 3:
usTmp = data;
for(i = 0; i < 8; i++) {
RxShiftBuf.W <<= 1;
if(usTmp & 0x80)
RxShiftBuf.W |= 0x1;
usTmp <<= 1;
if (RxShiftBuf.W == SYNC_WORD) {
state = RECEIVE;
RxBitOffset = 7-i;
RxShiftBuf.LSB = data; // 通知上层检测到起始符号且同步完成
if (PhysicalStartSymDetected() == FAIL) {
RadiocontrolIdle();
}
break;
}
}
break;
default:
RadiocontrolIdle();
break;
}
}
}else if (state == RECEIVE) { // 根据偏移量接收数据
char Byte;
RxShiftBuf.W <<=8; // 移去已经接收的字节
RxShiftBuf.LSB = data; // 存入刚刚收到的字节到低八位
Byte = (RxShiftBuf.W >> RxBitOffset); // 根据偏移量取出字节
PhysicalRxByteDone(Byte); // 通知上层处理接收到的字节
// uartDebug_txByte(Byte);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -