简介
Ci24R1芯片工作在2.4GHz ISM频段,集成嵌入式ARQ基带协议引擎。
工作频率范围:2400MHz~2525MHz
信道数:126
带宽:1MHz
兼容 BLE4.2 PHY&MAC
调制与解调技术:GFSK/FSK
数据速率:2Mbps/1Mbps/250Kbps
最高发射功率:11dBm
接收灵敏度: -80dBm @2Mbps
通信接口:两线SPI ,@10MHz
电压范围:2.1-3.6V
RSSI值:1bit输出,-50dBm
关断功耗:2uA
快速启动时间:<160us
外接晶体:16MHz ±60ppm
硬件框架:
PA:无线信号从芯片发射端的功率放大器
Power Management:电源管理
LNA:无线信号从芯片接收端的低噪声放大器, 噪声系数很低的放大器
RF PLL:射频锁相环,利用相位同步产生的电压,去调谐压控振荡器以产生目标频率的负反馈控制系统。
GFSK/FSK Modulator:调制器
GFSK/FSK Demodulator:解调器
ARQ Engine:ARQ协议引擎
TX FIFO:发射队列
RX FIFO:接收队列
SPI:串行接口
Regs Map:寄存器表图
应用范围
无线遥控,无线鼠标,无线键盘,无线电子标签,遥控无人机,遥控玩具等。
芯片引脚定义
端口号 | 端口名称 | 功能描述 |
---|---|---|
1 | CSN | SPI片选信号 |
2 | SCK | SPI时钟信号 |
3 | DATA/IRQ | SPI输入输出及中断信号 |
4 | XC1 | 晶体输入引脚 |
5 | XC2 | 晶体输出引脚 |
6 | VDD | 电源引脚 |
7 | ANT | 天线接口 |
8 | GND | 地 |
工作模式:
Ci24R1芯片供电电压至少大于2.1V,典型值3.3V,需延时100ms让芯片稳定工作。
关断模式:CONFIG寄存器的PWR_UP位清0,该模式下所有寄存器值与FIFO值保持不变,功耗<0.7uA。也可以通过SPI实现寄存器的读写。芯片的时钟稳定时间一般在1.5~2ms。
待机模式:通过该SPI配置寄存器CE脚拉低,CONFIG寄存器的PWR_UP位置1,该模式下时钟保持工作,功耗<15uA,切换收发时间小于130us。也可以通过SPI实现寄存器的读写。
发射空闲模式:通过该SPI配置寄存器CE脚拉高,CONFIG寄存器的PRIM_RX位清0,不发包(TX FIFO无数据)。也可以通过SPI实现寄存器的读写。
发射模式:通过该SPI配置寄存器CE脚拉高,CONFIG寄存器的PRIM_RX位清0,发包(TX FIFO有数据)。数据发射完成,会产生发射完成中断。
接收模式:通过该SPI配置寄存器CE脚拉高,CONFIG寄存器的PRIM_RX位置1。该模式收包通过数据包的地址和芯片地址比对,CRC检查,然后收到的数据自动存入RX FIFO,并产生数据接收中断。
数据包处理协议
ARQ包格式:
前导码字段:用于接收同步,发射时芯片自动附上,接收时芯片自动去掉(对用户不可见)
地址字段:作为接收数据方地址,与芯片的地址寄存器中地址相同时才会接收。
包控制字段:长度为9bit,
数据包长度指定数据包的长度可为0-32Byte;PID是发射方告知接收方发的包是新包还是重发的包;NO_ACK是发射方告知接收方是否回ACK确认信号。
负载数据字段:发射数据内容,最大32Byte。
CRC字段:包的CRC值,支持8bit和16bit两种,通过CONFIG寄存器中的CRCO位配置。
蓝牙包格式
蓝牙数据包是只有在兼容模式下可用,数据包包括前导码、地址、负载数据以及CRC,兼容蓝牙 4.2。广播地址固定为 0x6B7D9171。数据包最短 10 字节,最长 40 字节。
写寄存器 BLUE_EN=1 使能蓝牙功能,蓝牙信道可通过 blue_index 配置选择。蓝牙的数据信道、广播信道和射频信道的映射如下。
通信模式:
(TX)发射模式:自动将ARQ格式的数据包打包,输出信号进行调制由天线发射。
(RX)发射模式:不断侦测解调信号中的有效地址,一旦检测到地址与接收地址相同时,开始接收数据。接收到的负载数据存放在RX FIFO中,并由芯片的IRQ引脚产生中断通知MCU。MCU通过SPI接口随时访问RX FIFO寄存器,读取数据。
ACK模式:回复ACK信号
NO_ACK模式:不回复ACK信号
动态负载长度模式:字符长度可调的数据发送和接收,发射段即对TX FIFO(最大32字节)写入数据,然后拉搞CE启动传输,并打包传输。接收端需检查接收长度并按照接收长度读取数据。这里要DYNPD、FEATURE配置这两个寄存器。
静态负载长度模式:固定32字节长度的数据发送和接收,传输不够灵活。
多管道通信模式:支持多发一收(最多6发1收),接收方的接收管道地址设置与对应的发射管道地址设置相同。
SPI数据与控制接口:
芯片采用标准的四线SPI接口,读写速度最大支持10Mb/s。
SPI常见操作命令:
主要寄存器操作:
CONFIG:配置寄存器值0x00
收发配置在第0位: 0:发射模式 1:接收模式
开关机配置在第1位: 0:关断模式 1:开启模式
EN_AA:使能自动确认寄存器
SETUP_RETR:自动重发配置寄存器值0x04
高4位(7:4):自动重发延时配置 0x00-0xFF(250~4000us,250的倍数)
低4位(3:0):最大重发次数配置
0x00:关闭重发次数
0x01、0x02、0x04、…0xff:开启(1~15)重发次数。
RF_CH:射频信道寄存器值0x05
信道配置 0x00-0x7D (2400MHz~2525MHz)
RF_SETUP:射频配置寄存器
低3位(2:0):设置发射功率 0x00~0x07,共8个等级
第3位和第5位:设置数据速率
STATUS:状态寄存器
DYNPD:配置使能动态负载长度
0x01 使能通道1的动态负载长度
FEATURE:配置使能动态负载
0x04 使能动态负载长度特性
典型芯片电路图:
Ci24R1芯片外围电路包含外接16MHz晶振时钟电路,RF射频π型匹配电路,电源滤波电路。
驱动程序应用:
Ci24r1.c文件内容:
#include "CI24R1.h"
#include "delay.h"
u8 TR_ADDRESS[TR_ADR_WIDTH] = {0x0A,0x01,0x07,0x0E,0x01};
static u8 SPI_RD()
{
u8 bit_ctr,byte;
SCK = 0;
for(bit_ctr=0; bit_ctr<8; bit_ctr++)
{
byte = byte << 1;
SCK = 1;
if(MOSI == 1)
{
byte |= 0x01;
}
else
{
byte &= 0xfe;
}
SCK = 0;
}
SCK = 0;
return byte;
}
void SPI_WT(u8 byte)
{
u8 bit_ctr;
SCK = 0;
for(bit_ctr=0; bit_ctr<8; bit_ctr++)
{
SCK = 0;
if(byte&0x80)
{
MOSI = 1;
}
else
{
MOSI = 0;
}
SCK = 1;
byte=byte<<1;
}
SCK = 0;
}
void CI24R1_Init(void)
{
CSN = 0;
CSN = 1;
SCK = 0; //SPIʱÖÓÏßÀµÍ
CSN = 0;
SPI_WT(SELSPI);
CSN = 1;
}
u8 CI24R1_Write_Reg(u8 reg, u8 value)
{
CSN = 0;
SPI_WT(reg);
SPI_WT(value);
CSN = 1;
return 0;
}
u8 CI24R1_Write_Buf(u8 reg, u8 *pBuf, u8 bytes)
{
u8 byte_ctr;
CSN = 0;
SPI_WT(reg);
for(byte_ctr=0; byte_ctr<bytes; byte_ctr++)
{
SPI_WT(*pBuf++);
}
CSN = 1;
return 0;
}
u8 CI24R1_Read_Reg(u8 reg)
{
u8 value;
CSN = 0;
SPI_WT(reg);
value = SPI_RD();
CSN = 1;
return value;
}
u8 CI24R1_Read_Buf(u8 reg, u8 *pBuf, u8 bytes)
{
u8 byte_ctr;
CSN = 0;
SPI_WT(reg);
for(byte_ctr=0;byte_ctr<bytes;byte_ctr++)
{
pBuf[byte_ctr] = SPI_RD(); //¶ÁÈ¡Êý¾Ý£¬µÍ×Ö½ÚÔÚÇ
}
CSN = 1;
return 0;
}
void CI24R1_RX_Mode(void)
{
CI24R1_Write_Reg(CE_OFF,0xff); // CE = 0;
CI24R1_Write_Buf(WRITE_REG + RX_ADDR_P0, TR_ADDRESS, TR_ADR_WIDTH); // ½ÓÊÕÉ豸½ÓÊÕͨµÀ0ʹÓúͷ¢ËÍÉ豸ÏàͬµÄ·¢Ë͵ØÖ·
CI24R1_Write_Reg(WRITE_REG + SETUP_AW, 0x02); // ÉèÖýÓÊÕµØÖ·¿í¶ÈΪ4¸ö×Ö½Ú£»
CI24R1_Write_Reg(WRITE_REG + EN_AA, 0x01); // ʹÄܽÓÊÕͨµÀ0×Ô¶¯Ó¦´ð
CI24R1_Write_Reg(WRITE_REG + EN_RXADDR, 0x01); // ʹÄܽÓÊÕͨµÀ0
CI24R1_Write_Reg(WRITE_REG + FEATURE, 0x01);
CI24R1_Write_Reg(WRITE_REG + RF_CH, 40); // ÉèÖÃRFƵÂÊΪ2500MHz
CI24R1_Write_Reg(WRITE_REG + RX_PW_P0, TR_PLOAD_WIDTH); // ½ÓÊÕͨµÀ0Ñ¡ÔñºÍ·¢ËÍͨµÀÏàͬÓÐЧÊý¾Ý¿í¶È
CI24R1_Write_Reg(WRITE_REG + RF_SETUP, 0x0F); // Êý¾Ý´«ÊäÂÊ2Mbps£¬·¢É书ÂÊ11dBm £¨×¢£ºÊý¾Ý´«ÊäÂÊ2Mbps 16½øÖÆ µÍλ+8£©
CI24R1_Write_Reg(WRITE_REG + CONFIG, 0x0f);
CI24R1_Write_Reg(WRITE_REG + 0x02,0x01);
CI24R1_Write_Reg(WRITE_REG + 0x01,0x81);
CI24R1_Write_Reg(WRITE_REG + 0x0f,0xA0); //22.5pf
//CI24R1_Write_Reg(WRITE_REG + STATUS, 0xff); // Çå³ýËùÓеÄÖжϱê־λ
CI24R1_Write_Reg(CE_ON,0xff);
}
void CI24R1_TX_Mode(void)
{
CI24R1_Write_Reg(CE_OFF,0xff);
CI24R1_Write_Reg(WRITE_REG + SETUP_AW, 0x02);
CI24R1_Write_Buf(WRITE_REG + TX_ADDR, (u8 *)TR_ADDRESS, TR_ADR_WIDTH); // дÈë·¢Ë͵ØÖ·
CI24R1_Write_Buf(WRITE_REG + RX_ADDR_P0, TR_ADDRESS, TR_ADR_WIDTH); // дÈë·¢Ë͵ØÖ·
CI24R1_Write_Reg(WRITE_REG + EN_AA, 0x01); // ΪÁËÓ¦´ð½ÓÊÕÉ豸£¬½ÓÊÕͨµÀ0µØÖ·ºÍ·¢Ë͵ØÖ·Ïàͬ
CI24R1_Write_Reg(WRITE_REG + EN_RXADDR, 0x01); // ʹÄܽÓÊÕͨµÀ0×Ô¶¯Ó¦´ð
CI24R1_Write_Reg(WRITE_REG + FEATURE, 0x01); // ʹÄܽÓÊÕͨµÀ0
//CI24R1_Write_Reg(WRITE_REG + SETUP_RETR, 0x0a); // ×Ô¶¯ÖØ·¢ÑÓʱµÈ´ý250us+86us£¬×Ô¶¯ÖØ·¢10´Î
/*Ä£ÄâµçÈÝ*/
CI24R1_Write_Reg(WRITE_REG + 0x02,0X01);
CI24R1_Write_Reg(WRITE_REG + 0x01,0X81);
CI24R1_Write_Reg(WRITE_REG + 0x0f,0XA0);
CI24R1_Write_Reg(WRITE_REG + RF_CH, 40); // ÉèÖÃRFƵÂÊΪ2500MHz
CI24R1_Write_Reg(WRITE_REG + RF_SETUP, 0x0F);
CI24R1_Write_Reg(WRITE_REG + CONFIG, 0x5e); //
}
u8 CI24R1_RxPacket(u8 *rxbuf)
{
u8 state;
CSN = 0;
SPI_WT(SELSPI);
CSN = 1;
state = CI24R1_Read_Reg(STATUS); //¶Áȡ״̬¼Ä´æÆ÷µÄÖµ
CI24R1_Write_Reg(WRITE_REG+STATUS,state); //Çå³ýRX_DSÖжϱêÖ¾
if(state & RX_DR) //½ÓÊÕµ½Êý¾Ý
{
while((state&RX_P_NO)!=0x0e) //ÅжÏRX_FIFOÊÇ·ñΪ¿Õ£¬²»Îª¿Õ¼ÌÐø¶Á
{
CI24R1_Read_Buf(RD_RX_PLOAD,rxbuf,TR_PLOAD_WIDTH); //¶ÁÈ¡Êý¾Ý
state=CI24R1_Read_Reg(WRITE_REG+STATUS); //¼ÌÐø¶Á״̬¼Ä´æÆ÷ÅжÏRX_FIFO±ê־λ
}
CI24R1_Write_Reg(FLUSH_RX,0xff); //Çå³ýRX FIFO¼Ä´æÆ÷
return 0;
}
return 1; //ûÊÕµ½ÈκÎÊý¾Ý
}
/********************************************************
º¯Êý¹¦ÄÜ£º·¢ËÍÒ»¸öÊý¾Ý°ü
Èë¿Ú²ÎÊý£ºtxbuf:Òª·¢Ë͵ÄÊý¾Ý
·µ»Ø Öµ£º0x10:´ïµ½×î´óÖØ·¢´ÎÊý£¬·¢ËÍʧ°Ü
0x20:·¢Ëͳɹ¦
0xff:·¢ËÍʧ°Ü
*********************************************************/
extern void SendString(char *s);
u8 CI24R1_TxPacket(u8 *txbuf)
{
u8 state;
CI24R1_Write_Reg(CE_OFF,0xff);
CI24R1_Write_Buf(W_TX_PAYLOAD_NOACK,txbuf,TR_PLOAD_WIDTH);
CI24R1_Write_Reg(CE_ON,0xff); //CEÀ¸ß£¬CI24R1¿ªÊ¼·¢Éä
delay_ms(20);
CSN=0;
SPI_WT(SELIRQ);
CSN=1;
CI24R1_Read_Reg(READ_REG+STATUS);
while(IRQ != 0);
CSN=0;
SPI_WT(SELSPI);
CSN=1;
//µÈ´ý·¢ËÍÍê³É
state = CI24R1_Read_Reg(READ_REG+STATUS); //¶Áȡ״̬¼Ä´æÆ÷µÄÖµ
CI24R1_Write_Reg(WRITE_REG+STATUS, state); //Çå³ýTX_DS»òMAX_RTÖжϱêÖ¾
if(state&MAX_RT) //´ïµ½×î´óÖØ·¢´ÎÊý
{
CI24R1_Write_Reg(FLUSH_TX,0xff); //Çå³ýTX FIFO¼Ä´æÆ÷
return MAX_RT;
}
if(state&TX_DS) //·¢ËÍÍê³É
{
return TX_DS;
}
return 0xFF; //·¢ËÍʧ°Ü
}
ci24r1.h头文件内容:
#ifndef __CI24R1__
#define __CI24R1__
#include "config.h"
//CI24R1 RF MODE
#define Carrier_Mode 0xA0//ÔØ²¨Ä£Ê½
#define Modulation_Mode 0xB0//µ÷ÖÆÄ£Ê½
//CI24R1 PIN DEFINITION
#define CSN P15 // Slave Select pin, (output to CSN)
#define SCK P12 // Serial Clock pin, (output)
#define IRQ P10 // Interrupt signal, from nRF24L01 (input)
#define MOSI P10 // Master Out, Slave In pin (output)
#define TR_ADR_WIDTH 4 //4¸ö×ֽڵķ¢ËÍ/½ÓÊÕµØÖ·³¤¶È
#define TR_PLOAD_WIDTH 32 //PLOAD³¤¶È
//********************************************************************************************************************//
// SPI(CI24R1) commands
#define READ_REG 0x00 // Define read command to register
#define WRITE_REG 0x20 // Define write command to register
#define RD_RX_PLOAD 0x61 // Define RX payload register address
#define WR_TX_PLOAD 0xA0 // Define TX payload register address
#define FLUSH_TX 0xE1 // Define flush TX register command
#define FLUSH_RX 0xE2 // Define flush RX register command
#define REUSE_TX_PL 0xE3 // Define reuse TX payload register command
#define R_RX_PL_WID 0x60 // Define Read RX payload width for the R_RX_PAYLOAD in the RX FIFO
#define W_ACK_PAYLOAD 0xA8 // Define Write Payload to be transmitted together with ACK packet on PIPExxx xxx valid in the range from 000 to 101)
#define W_TX_PAYLOAD_NOACK 0xB0 // Define Write TX Disables AUTOACK on this specific packet
#define NOP 0xFF // Define No Operation, might be used to read status register
//======================================================================
//SPI commands (Ci24R1) (newly increased!!!!)
#define CE_ON 0x70 //´ò¿ªCE CE=1,CE_STATE=1
#define CE_OFF 0x71 //¹Ø±ÕCE CE=0,CE_STATE=0
#define SELSPI 0x74 //Ñ¡ÔñDATAÒý½ÅΪSPI¹¦ÄÜ
#define SELIRQ 0x75 //Ñ¡ÔñDATAÒý½ÅΪÊä³öIRQÖµ
//======================================================================
//********************************************************************************************************************//
// SPI(CI24R1) registers(addresses)
#define CONFIG 0x00 // 'Config' register address
#define EN_AA 0x01 // 'Enable Auto Acknowledgment' register address
#define EN_RXADDR 0x02 // 'Enabled RX addresses' register address
#define SETUP_AW 0x03 // 'Setup address width' register address
#define SETUP_RETR 0x04 // 'Setup Auto. Retrans' register address
#define RF_CH 0x05 // 'RF channel' register address
#define RF_SETUP 0x06 // 'RF setup' register address
#define STATUS 0x07 // 'Status' register address
#define OBSERVE_TX 0x08 // 'Observe TX' register address
#define RSSI 0x09 // 'Received Signal Strength Indecator' register address
#define RX_ADDR_P0 0x0A // 'RX address pipe0' register address
#define RX_ADDR_P1 0x0B // 'RX address pipe1' register address
#define RX_ADDR_P2 0x0C // 'RX address pipe2' register address
#define RX_ADDR_P3 0x0D // 'RX address pipe3' register address
#define RX_ADDR_P4 0x0E // 'RX address pipe4' register address
#define RX_ADDR_P5 0x0F // 'RX address pipe5' register address
#define TX_ADDR 0x10 // 'TX address' register address
#define RX_PW_P0 0x11 // 'RX payload width, pipe0' register address
#define RX_PW_P1 0x12 // 'RX payload width, pipe1' register address
#define RX_PW_P2 0x13 // 'RX payload width, pipe2' register address
#define RX_PW_P3 0x14 // 'RX payload width, pipe3' register address
#define RX_PW_P4 0x15 // 'RX payload width, pipe4' register address
#define RX_PW_P5 0x16 // 'RX payload width, pipe5' register address
#define FIFO_STATUS 0x17 // 'FIFO Status Register' register address
#define DYNPD 0x1C
#define FEATURE 0x1D
// STATUS Register
#define RX_DR 0x40 /**/
#define TX_DS 0x20
#define MAX_RT 0x10
#define RX_P_NO 0x0E
//CI24R1 API Functions
void CI24R1_Init(void); //CI24R1 Pin Init
u8 CI24R1_Write_Reg(u8 reg, u8 value);
u8 CI24R1_Write_Buf(u8 reg, u8 *pBuf, u8 bytes);
u8 CI24R1_Read_Reg(u8 reg);
u8 CI24R1_Read_Buf(u8 reg, u8 *pBuf, u8 bytes);
void CI24R1_RX_Mode(void);
void CI24R1_TX_Mode(void);
u8 CI24R1_RxPacket(u8 *rxbuf);
u8 CI24R1_TxPacket(u8 *txbuf);
#endif
main.c文件内容:
#include "CI24R1.h"
#include "delay.h"
#include "string.h"
#define LED3 P16
#define LED4 P35
#define KEY1 P12
#define KEY2 P14
unsigned char tx_data[32]={0};
unsigned char rx_data[32]={0};
#define FOSC 22118400L
#define BAUD 115200//9600
#define UART_RX_FIFO 32
unsigned char UART_RX_Data[UART_RX_FIFO];
/*串口函数初始化*/
void uart_init(void)
{
SCON = 0x50;
T2L = (65536 - (FOSC/4/BAUD));
T2H = (65536 - (FOSC/4/BAUD)) >> 8;
AUXR = 0x14;
AUXR |= 0x01;
ES = 1;
EA = 1;
}
/*串口发送字符函数*/
void SendData(unsigned char Data)
{
SBUF = Data;
while(TI == 0);
TI = 0;
}
/*串口发送字符串函数*/
void SendString(char *s)
{
while(*s)
{
SendData(*s++);
}
}
/*串口接收字符函数*/
void RecvData(unsigned char Data)
{
unsigned int i;
for(i=0;i<UART_RX_FIFO;i++)
{
UART_RX_Data[i] = Data;
}
while(RI == 0);
RI = 0;
}
/*设置串口响应中断*/
void UART_i() interrupt 4
{
if(RI)
{
RI = 0;
RecvData(SBUF);
}
if(TI)
{
TI = 0;
}
}
void main(void)
{
unsigned char udata=0,rssi;
uart_init(); //串口初始化
CI24R1_Init();//2.4G SPI初始化
#if 0
CI24R1_TX_Mode(); //设置发射模式
#else
CI24R1_RX_Mode(); //设置接收模式
#endif
while(1)
{
#if 0
udata = CI24R1_TxPacket(tx_data);//发包
#else
udata = CI24R1_RxPacket(rx_data);//收包
rssi=CI24R1_Read_Reg(RSSI); //获取接收信号强度
if(rssi == 0)
{
SendString("<-50dBm\r\n");
}
else
{
SendString(">-50dBm\r\n");
}
#endif
delay_ms(50); // Broadcasting interval
if(udata == 0xff)
{
LED4=0;//SendString("send fail\r\n");
LED3=0;
SendString("send or recv fail\r\n");
}
else
{
LED4=1;//SendString("send ok\r\n");
LED3=1;
SendString("send or recv ok\r\n");
}
}
}
认证指南:
随着国家强制对无线产品的认证要求,针对CI24R1这款芯片,一般过的认证频率为:2402MHz 2440MHz 2480MHz。可以通过下面的代码来完成定频中的功率等级、速率、信道频率、单载波及调制模式的设置:
#include "CI24R1.h"
#include "delay.h"
#define RF_POWER_F12 0x00//-12dBm
#define RF_POWER_F6 0x01//-6dBm
#define RF_POWER_F4 0x02//-4dBm
#define RF_POWER_0 0x03//0dBm
#define RF_POWER_1 0x04//1dBm
#define RF_POWER_3 0x05//3dBm
#define RF_POWER_4 0x06//4dBm
#define RF_POWER_7 0x07//7dBm
#define RF_FREQ_250K 0x20//250Kbps
#define RF_FREQ_1M 0x00//1Mbps,对应带宽1MHz
#define RF_FREQ_2M 0x08//2Mbps,对应带宽2MHz
#define RF_CH_2525 0x7D//125
#define RF_CH_2500 0x64//100
#define RF_CH_2482 0x52//82
#define RF_CH_2480 0x50//80 2480MHz
#define RF_CH_2463 0x3F//63
#define RF_CH_2462 0x3E//62
#define RF_CH_2442 0x2A//42
#define RF_CH_2440 0x28//40 2440MHz
#define RF_CH_2402 0x02//02 2402MHz
#define RF_CH_2400 0x00//00
#define Single_Carrier_MODE 1 //单载波模式
#define Modulated_Wave_MODE 0 //调制波模式
#define ADV_INTERVAL_MS 50 //广播间隔
供认证测试设置使用的函数
void Set_CERTIFIED_Mode(unsigned charrf_Ch,unsigned char rf_Power,unsigned char rf_Freq ,unsigned char rf_Mode)
{
static unsigned char RF_value = 0;
CI24R1_Write_Reg(CE_OFF,0xff);
CI24R1_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH);
CI24R1_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH);
CI24R1_Write_Reg(WRITE_REG + EN_AA, 0x01);
CI24R1_Write_Reg(WRITE_REG + EN_RXADDR,0x01);
CI24R1_Write_Reg(WRITE_REG + SETUP_RETR,0x0a);
rf_Ch = rf_Ch&0xff;
CI24R1_Write_Reg(WRITE_REG + RF_CH,rf_Ch);
RF_value |= rf_Power;
RF_value |= rf_Freq;
switch(rf_Mode)
{
case Single_Carrier_MODE:
RF_value |= 0x80;//cont_wave
RF_value |= 0x10;//pll_lock
break;
case Modulated_Wave_MODE:
break;
}
RF_value = RF_value&0xff;
CI24R1_Write_Reg(WRITE_REG + RF_SETUP,RF_value);
CI24R1_Write_Reg(WRITE_REG + CONFIG,0x0e);
/*Ä£ÄâµçÈÝ*/
CI24R1_Write_Reg(WRITE_REG + EN_RXADDR,0x01); //
CI24R1_Write_Reg(WRITE_REG + EN_AA,0x81); //Ñ¡Ôñ
CI24R1_Write_Reg(WRITE_REG + 0x0f,0xa0); //ĿǰÊÇ22.5pf
}
void send_packet(unsigned int interval_ms,unsigned char *data_value)
{
CI24R1_TxPacket(data_value);
delay_ms(interval_ms); // Broadcasting interval
}
设置认证参数
unsigned char adv_data[32]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xF0,0xE0,0xD0,0xC0,0xB0,0xA0,0x90,0x80,0x70,0x60,0x50,0x40,0x30,0x20,0x10,0x00};//数据包
void main(void)
{
CI24R1_Init();
Set_CERTIFIED_Mode(RF_CH_2402,RF_POWER_0,RF_FREQ_1M,Single_Carrier_MODE);//设置频率、功率、速率、模式
while(1)
{
send_packet(ADV_INTERVAL_MS,adv_data);//定时发包
}
}
认证常见问题
1)、杂散问题
在不影响传输距离的情况下,适当降低功率,可以改善RF匹配的滤波电路。
2)、EMC问题
注意VCC端加滤波电容电路。
模拟BLE信号
BLE是用的2.4G ISM频段,由于Si24r1的调制方式接近,我们可以使用Ci24R1来模拟BLE的广播信号(仅仅只能模拟BLE的广播信号)。首先,我们解析一下BLE的包的结构。
1、前导码1Byte,0x55或0xAA,硬件根据访问地址的第一个bit自动添加生成
2、访问地址4Byte,固定为0x8E89BED6
3、帧头1Byte,广播包类型
4 、负载长度1Byte
5、 负载数据0~37Byte
6、 帧尾1Byte,CRC校验和,Ci24R1硬件会自动计算出CRC,由于BLE使用LFSR生成的24位的CRC值,故需要禁止掉CI24R1的硬件自动CRC算法。如下图:
使用多项式的CRC算法生成蓝牙的3-bytes CRC。BLE的收发包过程如下图:
切入正题,主要的实现函数如下:
/*************** BLE ***************/
#define GAP_ADTYPE_MESH_TYPE_ADVDATA 0x2A
#define GAP_ADTYPE_LOCAL_NAME_COMPLETE 0x09 //!< Complete local name
#define GAP_ADTYPE_MANUFACTURER_SPECIFIC 0xFF //!< Manufacturer Specific Data: first 2 octets contain the Company Identifier Code followed by the additional manufacturer specific data
/*BLE的CRC校验函数,24bit-CRC算法*/
static void LeLfsrCrc(const unsigned char* Data, unsigned char Len, unsigned char* Dst)
{
unsigned char _v, _t, _d;
while(Len--)
{
_d = *Data++;
for(_v = 0; _v < 8; _v++, _d >>= 1)
{
_t = Dst[0] >> 7;
Dst[0] <<= 1;
if(Dst[1] & 0x80) Dst[0] |= 1; Dst[1] <<= 1;
if(Dst[2] & 0x80) Dst[1] |= 1; Dst[2] <<= 1;
if(_t != (_d & 1))
{
Dst[2] ^= 0x5B;
Dst[1] ^= 0x06;
}
}
}
}
/*单字节高低位互换函数,大小端*/
static unsigned char Bit_Swap(unsigned char Byte)
{
unsigned char Value = 0,i;
unsigned char Data[8];
for(i=0;i<8;i++)
{
Data[i] = 0x01<<i;
if(Byte & Data[i])
Value |= 0x80>>i;
}
return Value;
}
/*BLE LFSR白化实现*/
static void LeLfsrWhite(unsigned char* Data, unsigned char Len, unsigned char Coeff)
{
unsigned char i;
while(Len--)
{
for(i = 1; i; i <<= 1)
{
if(Coeff & 0x80)
{
Coeff ^= 0x11;
(*Data) ^= i;
}
Coeff <<= 1;
}
Data++;
}
}
/*加密BLE包*/
static void EncodeBlePacket(unsigned char* Packet, unsigned char Len, unsigned char Chan)
{
unsigned char i, DataLen = Len - 3;
LeLfsrCrc(Packet, DataLen, Packet + DataLen);
for(i = 0; i < 3; i++, DataLen++) Packet[DataLen] = Bit_Swap(Packet[DataLen]);
LeLfsrWhite(Packet, Len, Bit_Swap(Chan)|2);
for(i = 0; i < Len; i++) Packet[i] = Bit_Swap(Packet[i]);
}
/*设置BLE模式*/
void CI24R1_BLE_Mode(void)
{
CI24R1_Write_Reg(CE_OFF,0xff);
CI24R1_Write_Reg(WRITE_REG+CONFIG,0x12);//关闭最大重发计数中断,关闭CRC,开机模式,发射模式
CI24R1_Write_Reg(WRITE_REG+EN_AA,0x00); /* no ack ,不使能自动确认*/
CI24R1_Write_Reg(WRITE_REG+EN_RXADDR,0x00); /* no rx,不使能接收数据管道地址 */
CI24R1_Write_Reg(WRITE_REG+SETUP_AW,0x02); /* 4-byte addr,发射地址宽度4字节 */
CI24R1_Write_Reg(WRITE_REG+SETUP_RETR,0x00); /* no auto-retransmit,关闭自动重发 */
CI24R1_Write_Reg(WRITE_REG+RF_SETUP,0x06); /* 1Mbps at 0dbm */
CI24R1_Write_Reg(WRITE_REG+STATUS,0x3e); /* clear flags,清除标志 */
CI24R1_Write_Reg(WRITE_REG+DYNPD,0x00); /* no dynamic payloads,不使能动态负载长度 */
CI24R1_Write_Reg(WRITE_REG+FEATURE,0x00); /* no features,不使能动态负载*/
CI24R1_Write_Reg(WRITE_REG+RX_PW_P0,32); /* always rx 32 bytes,接收数据管道0数据字节数32字节 */
CI24R1_Write_Reg(WRITE_REG+EN_RXADDR, 0x01); /* rx on pipe 0 ,使能接收数据管道0地址*/
TX_ADDRESS[0] = Bit_Swap(0x8E);
TX_ADDRESS[1] = Bit_Swap(0x89);
TX_ADDRESS[2] = Bit_Swap(0xBE);
TX_ADDRESS[3] = Bit_Swap(0xD6);
CI24R1_Write_Buf(WRITE_REG+TX_ADDR,(u8*)TX_ADDRESS, 4);//set wirte address 设置发射方的发射地址
CI24R1_Write_Buf(WRITE_REG+RX_ADDR_P0,(u8*)TX_ADDRESS, 4);//set wirte address 数据管道0的接收地址,发射方需要接收ACK信号,需设一样的地址。
}
/*低8位校验和计算*/
static unsigned char check_lockkey(unsigned char *Data,unsigned char Len)
{
unsigned char result;
int i,num = 0;
for (i = 0; i < Len; i++)
{
num = (num + Data[i]) % 256;
}
result = (char)num;
return result;
}
/*模拟BLE广播包*/
static unsigned char Imitate_Ble_Packet(unsigned char *data_value,unsigned char *data_mac,unsigned char *data_name)
{
unsigned char Value=0;
buf[Value++] = 0x42|0x40; //PDU type, random address; Android:0x42 iPhone:0x40
buf[Value++] = 21; // payload length
buf[Value++] = data_mac[0];
buf[Value++] = data_mac[1];
buf[Value++] = data_mac[2];
buf[Value++] = data_mac[3];
buf[Value++] = data_mac[4];
buf[Value++] = data_mac[5];
#if 0
buf[Value++] = 2; //flags (LE-only, general discoverable mode)
buf[Value++] = 0x01;
buf[Value++] = check_lockkey(data_value,5);//0x06;//A9;//0x06;
buf[Value++] = 4; // length of the name, including type byte
buf[Value++] = GAP_ADTYPE_LOCAL_NAME_COMPLETE;//0x09
buf[Value++] = data_name[0];//'A';
buf[Value++] = data_name[1];//'X';
buf[Value++] = data_name[2];//'K';
buf[Value++] = 6; // length of custom data, including type byte
buf[Value++] = GAP_ADTYPE_MANUFACTURER_SPECIFIC;//0xFF
buf[Value++] = data_value[0];//0x11;
buf[Value++] = data_value[1];//0x22;
buf[Value++] = data_value[2];//0x33;// some test data
buf[Value++] = data_value[3];//0x44;
buf[Value++] = data_value[4];//0x55;
#else
buf[Value++] = 14; //flags (LE-only, general discoverable mode)
buf[Value++] = GAP_ADTYPE_MESH_TYPE_ADVDATA;
buf[Value++] = check_lockkey(data_mac,6);
buf[Value++] = data_mac[0];
buf[Value++] = data_mac[1];
buf[Value++] = data_mac[2];
buf[Value++] = data_mac[3];
buf[Value++] = data_mac[4];
buf[Value++] = data_mac[5];
buf[Value++] = check_lockkey(data_value,6);
buf[Value++] = data_value[0];//0x11;
buf[Value++] = data_value[1];//0x22;
buf[Value++] = data_value[2];//0x33;// some test data
buf[Value++] = data_value[3];//0x44;
buf[Value++] = data_value[4];//0x55;
#endif
buf[Value++] = 0x55;//55; //CRC start value: 0x555555
buf[Value++] = 0x55;//55;
buf[Value++] = 0x55;//55;
return Value;
}
/*BLE发包函数*/
void send_ble_packet(unsigned int interval_ms,unsigned char *data_value,unsigned char *data_mac,unsigned char *data_name)
{
static unsigned char Len=0;
for(ch=0; ch<sizeof(chRf); ch++)
{
Len = Imitate_Ble_Packet(data_value,data_mac,data_name);
CI24R1_Write_Reg(WRITE_REG+RF_CH, chRf[ch]);//hop channel设置信道
CI24R1_Write_Reg(WRITE_REG+STATUS, 0x6E); // clear flags
EncodeBlePacket(buf, Len, chLe[ch]);
CI24R1_Write_Reg(FLUSH_TX,0xff); //Clear TX Fifo
CI24R1_Write_Reg(FLUSH_RX,0xff); //Clear RX Fifo
CI24R1_TxPacket(buf);
delay_ms(2);
}
delay_ms(interval_ms); // Broadcasting interval
}``
Ci24R1通信异常问题集锦
2.4G通信异常一般都有如下问题:
1、一次也不能收到数据
(初诊:硬件接线和软件配置问题)
2、在发射端或接收端重新上电的时候,可接收到一次
(初诊:没有及时清空RX FIFO和接收中断标志)
3、由发送模式切换为接收模式后,就不能接收了
(初诊:没有及时清空TX FIFO,RX FIFO和接收中断标志)
4、设置高功率等级之后,就不能接收了
(初诊:供电电流不足)
5、无规律偶发不能接收
(初诊:存在电源干扰)
6、通信距离短,远距离容易丢包
(初诊:硬件结构和PCB设计影响了天线净空区,造成了信号衰减)
7、接收数据后,进入待机模式下,功耗比较大,达到了mA级
(初诊:CE脚没有被拉低)
8、一发多收的时候,存在丢包问题
(初诊:广播通信数量过多的情况下,需要设置更高的信道,适当调整发包间隔)
硬件部分排查
我们在写Ci24R1通信代码前,一定要首先保证硬件原理图、PCB以及结构设计是正常的。
(1)、MCU SPI和Ci24R1 SPI的IO引脚连接无误。
(2)、Ci24R1模块电源脚附近放大小电容10uF和0.1uF。
(3)、处于接收模式时,Ci24R1模块的CE寄存器配置为为高电平。
(4)、稳定3.3V,纹波<30mV为宜,供电电流要充足。
(5)、Ci24R1的天线净空区要做好,禁止靠近高频器件,金属结构件,电路电线。
(6)、用示波器检测CI24R1的IRQ引脚是否有波形变化。
软件部分排查
(1)、保证收发端的设备地址、射频信道、射频传输速率、地址宽度、传输数据宽度设置值是一致的。
(2)、发送完成要及时清空TX FIFO和发送中断标志以及最大发射中断标志,接收完成要及时清空RX FIFO和接收中断标志。
(3)、检测通过SPI读写Ci24R1的寄存器是否正常。
(4)、熟悉Ci24R1芯片手册的工作模式状态机切换过程。