目录

Ci24R1 简介

Ci24R1是Si24R1的SOP8封装简化版, 厂商为南京中科微, 他们还有一个比较常见的型号是Si24R1, Si24R1就是应用极广的nRF24L1的克隆版. Ci24R1的通信协议和Si24R1, nRF24L01是兼容的, 另外支持蓝牙BLE4.2标准.

具体到参数上, 与nRF24L01类似, 都是2.4GHz频段的无线通信芯片, 官网的介绍: 低成本高性能2.4GHz 无线收发芯片(支持蓝牙版). 专为低功耗无线场合设计,集成嵌入式ARQ基带协议引擎的无线收发器芯片. 工作频率范围为2400MHz-2525MHz,共有126个1MHz带宽的信道, 支持2Mbps,1Mbps,250Kbps三种数据速率, 支持发射BLE4.2标准的数据包,可以方便的向手机传输数据.

主要特性

  • 频段: 2.4GHz ISM
  • 调制方式: GFSK/FSK
  • 数据速率: 2Mbps/1Mbps/250Kbps
  • 关断功耗: 1uA
  • 待机功耗: 15uA
  • 快速启动时间: ≤ 130uS
  • 内部集成高PSRR LDO
  • 宽电源电压范围: 1.9-3.6V
  • 宽数字I/O电压范围:1.9-5.25V
  • 低成本晶振: 16MHz±60ppm
  • 接收灵敏度: -83dBm @2MHz
  • 最高发射功率: 7dBm
  • 接收电流(2Mbps): 15mA
  • 发射电流(2Mbps): 12mA(0dBm)
  • 支持三线SPI接口
  • 内部集成智能ARQ基带协议引擎
  • 收发数据硬件中断输出
  • 支持1bit RSSI 输出
  • 极少外围器件,降低系统应用成本
  • 封装: SOP8, DFN8(220.8mm)

对标的芯片

Ci24R1对标的是2.4G SOP8芯片, 主要是面向廉价的有无线通信需求的产品, 这类芯片主要有 XN297, XN297L, XL2400/WL2400, 都是三线SPI通信, 只需要一个晶振和一两个电容, 外围电路极少. Ci24R1的优势是同时支持 2.4GHz 和 BLE4.2.

这几个型号芯片的管脚布局各有不同, 并且驱动方式也不太一样.

Ci24R1 管脚和典型电路

管脚布局

SOP8封装(左) 和 DFN8封装(右)

管脚定义

PIN Name I/O 说明
1 CSN DI SPI 片选信号
2 SCK DI SPI 时钟信号
3 DATA/IRQ IO SPI 数据输入/输出/中断信号
4 XC1 AI 晶振输入
5 XC2 AO 晶振输出
6 VDD Power 电源(+2.1 ~ +3.6V,DC)
7 ANT RF 天线接口
8 VSS GND

电路

STC8H 驱动 Ci24R1

驱动说明

厂商提供的测试代码, 都是基于GPIO模拟SPI驱动, 开始以为可以用硬件SPI驱动, 后来在STC8H上测试, 发现不可行, 主要存在两个问题

  1. Ci24R1仅仅提供了一个DATA口, 对应SPI的MOSI, 但是还复用IRQ, 所以使用硬件SPI的话, 需要随时切换MOSI pin的工作状态
  2. STC8H的硬件SPI驱动时, 会有一半概率无法正确读取, 得到的全是0xFF
  3. STC8H即使用GPIO模拟驱动SPI, 也必须将IO模式设置为推挽, 使用准双向时读写正常, 但是发送会失败, 尚不清楚原因

接线

示例代码中, 使用了与硬件SPI一样的Pin, 实际上换成其他Pin也一样, 因为都是通过GPIO模拟驱动.

P35(SS, Ignored) => CSN
P34(MOSI) => DATA
P32(SPCLK) => SCK
VDD1 => 3.3V
XC1,XC2 => 16MHz OSC
GND => GND

示例代码

代码下载地址

基础宏定义

切换收发模式, 通过main.c中的

// 0:TX, 1:RX
#define CI24R1_MODE 1

因为涉及到对MOSI Pin的模式切换, 涉及到对CE电平的操作(寄存器写), 这部分都用宏定义保证性能

#define CI24R1_CSN  P35
#define CI24R1_MOSI P34
#define CI24R1_SCK P32 #define CI24R1_DATA_OUT() GPIO_P3_SetMode(GPIO_Pin_4, GPIO_Mode_Output_PP)
#define CI24R1_DATA_IN() GPIO_P3_SetMode(GPIO_Pin_4, GPIO_Mode_Input_HIP)
#define CI24R1_DATA_LOW() CI24R1_MOSI = 0
#define CI24R1_DATA_HIGH() CI24R1_MOSI = 1
#define CI24R1_DATA_READ() CI24R1_MOSI #define CI24R1_CLK_LOW() CI24R1_SCK = 0
#define CI24R1_CLK_HIGH() CI24R1_SCK = 1 #define CI24R1_NSS_LOW() CI24R1_CSN = 0
#define CI24R1_NSS_HIGH() CI24R1_CSN = 1 #define CI24R1_CE_LOW() CI24R1_WriteReg(CI24R1_CMD_CE_OFF, CI24R1_CMD_NOP)
#define CI24R1_CE_HIGH() CI24R1_WriteReg(CI24R1_CMD_CE_ON, CI24R1_CMD_NOP)

模拟SPI基础通信

void CI24R1_WriteByte(uint8_t value)
{
uint8_t i = 0;
CI24R1_CLK_LOW();
CI24R1_DATA_OUT();
for (i = 0; i < 8; i++)
{
CI24R1_CLK_LOW();
if (value & 0x80)
{
CI24R1_DATA_HIGH();
}
else
{
CI24R1_DATA_LOW();
}
CI24R1_CLK_HIGH();
value = value << 1;
}
CI24R1_CLK_LOW();
} uint8_t CI24R1_ReadByte(void)
{
uint8_t i = 0, RxData; CI24R1_DATA_IN();
CI24R1_CLK_LOW();
for (i = 0; i < 8; i++)
{
RxData = RxData << 1;
CI24R1_CLK_HIGH();
if (CI24R1_DATA_READ())
{
RxData |= 0x01;
}
else
{
RxData &= 0xfe;
}
CI24R1_CLK_LOW();
}
CI24R1_CLK_LOW();
return RxData;
}

Ci24R1 单字节命令, 寄存器读写

对nRF24L01熟悉的都知道其寄存器读写的方式, 其实是两个字节的通信, Ci24R1比较特殊的地方在于有一个单字节的写命令, 用于切换DATA Pin的模式

void CI24R1_WriteReg(uint8_t reg,uint8_t value)
{
CI24R1_NSS_LOW();
CI24R1_WriteByte(reg);
CI24R1_WriteByte(value);
CI24R1_NSS_HIGH();
} uint8_t CI24R1_ReadReg(uint8_t reg)
{
uint8_t reg_val;
CI24R1_NSS_LOW();
CI24R1_WriteByte(reg);
reg_val = CI24R1_ReadByte();
CI24R1_NSS_HIGH();
return reg_val;
} void CI24R1_WriteCmd(uint8_t cmd)
{
CI24R1_NSS_LOW();
CI24R1_WriteByte(cmd);
CI24R1_NSS_HIGH();
}

Ci24R1 的多字节读写命令

void CI24R1_WriteFromBuf(uint8_t reg, const uint8_t *pBuf, uint8_t len)
{
uint8_t ctr;
CI24R1_NSS_LOW();
CI24R1_WriteByte(reg);
for (ctr = 0; ctr < len; ctr++)
{
CI24R1_WriteByte(*pBuf++);
}
CI24R1_NSS_HIGH();
} void CI24R1_ReadToBuf(uint8_t reg, uint8_t *pBuf, uint8_t len)
{
uint8_t ctr;
CI24R1_NSS_LOW();
CI24R1_WriteByte(reg);
for (ctr = 0; ctr < len; ctr++)
{
pBuf[ctr] = CI24R1_ReadByte();
}
CI24R1_NSS_HIGH(); }

Ci24R1 的初始化

初始化有几个需要注意的点

  1. CONFIG的最后一个bit标识是TX还是RX
  2. 地址宽度没有特殊情况都用5 bytes
  3. payload是否变宽, 如果是, 则不需要定义每个pipe的payload宽度, 如果否, 则必须定义对应pipe的payload宽度(CI24R1_REG_RX_PW_Px), 否则不会有接收
  4. 是否变宽还会影响到 CI24R1_REG_FEATURE 中的一位
  5. 如果开启ACK, TX地址和RX P0地址一定是一样的, 两个模块之间通信可以使用完全一样的TX和RX P0

开始测试时, 可以使用低码率(250Kbps)加大功率(11dB), 另外模块可以靠的近一点, 例如五六公分, 避免非程序的问题导致调试失败

void CI24R1_Init(void)
{
CI24R1_CE_LOW();
#if (CI24R1_PLOAD_WIDTH == 0)
// Enable dynamic payload length on pipe 0 and pipe 1
CI24R1_WriteReg(CI24R1_CMD_W_REGISTER | CI24R1_REG_DYNPD, 0x03);
CI24R1_WriteReg(CI24R1_CMD_W_REGISTER | CI24R1_REG_FEATURE, 0x07);
#else
// Fixed payload length
CI24R1_WriteReg(CI24R1_CMD_W_REGISTER | CI24R1_REG_DYNPD, 0x00);
CI24R1_WriteReg(CI24R1_CMD_W_REGISTER | CI24R1_REG_FEATURE, 0x03);
// Length of pipe 0
CI24R1_WriteReg(CI24R1_CMD_W_REGISTER | CI24R1_REG_RX_PW_P0, CI24R1_PLOAD_WIDTH);
// Length of pipe 1
CI24R1_WriteReg(CI24R1_CMD_W_REGISTER | CI24R1_REG_RX_PW_P1, CI24R1_PLOAD_WIDTH);
#endif
CI24R1_WriteReg(CI24R1_CMD_W_REGISTER | CI24R1_REG_CONFIG, 0x0E);
// Enable auto ack all pipes
CI24R1_WriteReg(CI24R1_CMD_W_REGISTER | CI24R1_REG_EN_AA, 0x3F);
// Enable all pipes
CI24R1_WriteReg(CI24R1_CMD_W_REGISTER | CI24R1_REG_EN_RXADDR, 0x3F);
// Address width, 0x1:3bytes, 0x02:4bytes, 0x3:5bytes
CI24R1_WriteReg(CI24R1_CMD_W_REGISTER | CI24R1_REG_SETUP_AW, 0x03);
// Resend 500us and 3 times. interval: 250us * ([0, 15] + 1), retries: [0, 15]
CI24R1_WriteReg(CI24R1_CMD_W_REGISTER | CI24R1_REG_SETUP_RETR, (0x01 << 4) | 0x03);
// RF Data Rate 250K 11db
CI24R1_WriteReg(CI24R1_CMD_W_REGISTER | CI24R1_REG_RF_SETUP, CI24R1_RF_SETUP_1M | CI24R1_RF_SETUP_11DB);
CI24R1_CE_HIGH();
}

Ci24R1 发送

发送沿用了厂商给的例子, 在写入发送内容, 拉高CE后, 立即切换IO到输入状态等待发送结果的中断. 如果是MAX_RT中断, 说明发送失败, 需要清空TX_FIFO和标志位.

void CI24R1_SetTxMode(void)
{
uint8_t value;
value = CI24R1_ReadReg(CI24R1_CMD_R_REGISTER | CI24R1_REG_CONFIG);
value &= 0xFE;
CI24R1_WriteReg(CI24R1_CMD_W_REGISTER | CI24R1_REG_CONFIG, value);
} uint8_t CI24R1_Tx(uint8_t *ucPayload, uint8_t length)
{
uint8_t status;
#if (CI24R1_PLOAD_WIDTH == 0)
CI24R1_WriteFromBuf(CI24R1_CMD_W_TX_PAYLOAD, ucPayload, length);
#else
CI24R1_WriteFromBuf(CI24R1_CMD_W_TX_PAYLOAD, ucPayload, CI24R1_PLOAD_WIDTH);
#endif
CI24R1_CE_HIGH();
CI24R1_WriteCmd(CI24R1_CMD_SELIRQ);
CI24R1_DATA_IN();
while (CI24R1_DATA_READ());
CI24R1_DATA_OUT();
CI24R1_WriteCmd(CI24R1_CMD_SELSPI);
status = CI24R1_ReadStatus();
if (status & CI24R1_FLAG_MAX_RT)
{
CI24R1_WriteReg(CI24R1_CMD_FLUSH_TX, CI24R1_CMD_NOP);
}
// Clear status flags
CI24R1_WriteReg(CI24R1_CMD_W_REGISTER | CI24R1_REG_STATUS, status);
return status;
}

Ci24R1 接收

也沿用了厂商的例子, 切换到输入状态后, 阻塞等待接收中断. 如果测试中, SPI读写没问题, 距离也够近, 但是一直没中断, 可以检查一下

两个模块的TX地址和RX_P0地址, RF Channel是否一致, 是否开启了对应RX Pipe, 如果是固定宽度, 是否在对应的接收pipe上正确设置了.

void CI24R1_SetRxMode(void)
{
uint8_t value;
value = CI24R1_ReadReg(CI24R1_CMD_R_REGISTER | CI24R1_REG_CONFIG);
value |= 0x01;
CI24R1_WriteReg(CI24R1_CMD_W_REGISTER | CI24R1_REG_CONFIG, value);
} uint8_t CI24R1_Rx(void)
{
uint8_t i, status, rxplWidth;
CI24R1_WriteReg(CI24R1_CMD_FLUSH_RX, CI24R1_CMD_NOP);
CI24R1_WriteReg(CI24R1_CMD_SELIRQ, CI24R1_CMD_NOP);
CI24R1_DATA_IN();
while(CI24R1_DATA_READ());
CI24R1_DATA_OUT();
CI24R1_WriteReg(CI24R1_CMD_SELSPI, CI24R1_CMD_NOP);
status = CI24R1_ReadStatus();
UART1_TxChar('>');
UART1_TxHex(status);
if (status & CI24R1_FLAG_RX_READY)
{
#if CI24R1_PLOAD_WIDTH == 0
rxplWidth = CI24R1_ReadReg(CI24R1_CMD_R_RX_PL_WID);
#else
rxplWidth = CI24R1_PLOAD_WIDTH;
#endif
// Read RX to buffer
CI24R1_ReadToBuf(CI24R1_CMD_R_RX_PAYLOAD, xbuf, rxplWidth);
// Clear status flags
CI24R1_WriteReg(CI24R1_CMD_W_REGISTER | CI24R1_REG_STATUS, status);
UART1_TxChar('>');
for (i = 0; i < rxplWidth; i++)
{
UART1_TxHex(*(xbuf_data + i));
}
}
return status;
}

结束

测试中Ci24R1的通信还是比较稳定的, 因为IO转换加上模拟SPI, 通信的速率和4线SPI的nRF24L01和Si24R1比肯定会有差距, 好处是省了一个IO.

这种芯片市场指向非常明显, 就是面向成本和尺寸敏感的市场, 仅需要GPIO就能使用, 几乎所有的MCU都能兼容. 廉价的玩具和家用电器的遥控, 这些产品大量使用8pin的8位MCU, 这种MCU总共只有6个可用IO, 省一个IO就能增加不少可能性. 市场上还有同类型集成了MCU的型号, 例如XL2401, XL2402, SOP16封装连无线带MCU不到1.4CNY, 可以将成本控制到非常低, 集成后也利于生产和品控.

STC8H开发(十五): GPIO驱动Ci24R1无线模块的更多相关文章

  1. STC8H开发(十六): GPIO驱动XL2400无线模块

    目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...

  2. STC8H开发(五): SPI驱动nRF24L01无线模块

    目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...

  3. STC8H开发(十二): I2C驱动AT24C08,AT24C32系列EEPROM存储

    目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...

  4. STC8H开发(十四): I2C驱动RX8025T高精度实时时钟芯片

    目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...

  5. STC8H开发(十): SPI驱动Nokia5110 LCD(PCD8544)

    目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...

  6. 嵌入式Linux驱动学习之路(十五)按键驱动-定时器防抖

    在之前的定时器驱动程序中,我们发现在连续按下按键的时候,正常情况下应该是一次按下对应一次松开.而程序有时候会显示是两次按下,一次松开.这个问题是因为在按下的时候,因为是机械按键,所以电压信号会产生一定 ...

  7. Java微信公众平台开发(十五)--微信JSSDK的使用

    转自:http://www.cuiyongzhi.com/post/63.html 在前面的文章中有介绍到我们在微信web开发过程中常常用到的 [微信JSSDK中Config配置] ,但是我们在真正的 ...

  8. SpringBoot开发十五-发布帖子

    需求介绍 使用 AJAX 异步通信实现网页能够增量的更新呈现到页面上而不需要刷新整个页面. 现在基本上都是服务器返回 JSON 字符串来解析 代码实现 使用 JQuery 发送 AJAX 请求. 首先 ...

  9. python运维开发(十五)----JavaScript

    内容目录: HTML补充 javascript HTML补充 1.display标签 display的inline-block 属性会自动带3px的宽度 <span style="di ...

随机推荐

  1. CSAPP 之 ShellLab 详解

    前言 本篇博客将会详细介绍 CSAPP 之 ShellLab 的完成过程,实现一个简易(lou)的 shell.tsh 拥有以下功能: 可以执行外部程序 支持四个内建命令,名称和功能为: quit:退 ...

  2. git clone 问题

    转自 git clone出现 fatal: unable to access 'https://github.com/...'的解决办法(亲测有效) - 山村码农 - 博客园 (cnblogs.com ...

  3. Keil软件下用Jlink无法识别芯片

    Keil软件下用Jlink无法识别芯片 硬件:正点原子探索者 软件:keil J-Link固件版本:V9.40 J-Link V6.94b驱动:下载地址 跟着视频教程走,发现的第一个问题就是这个,记录 ...

  4. [学习笔记]使用Docker+Jenkin自动化流水线发布.Net应用

    ​使用Docker容器方案可以快速安全地将项目部署到客户的服务器上,作为公司项目,需要解决两个问题: 1. 需要搭建一个私有的Docker仓库,以便安全的存储镜像 2. 需要一套自动化发布方案,实现代 ...

  5. 优先队列STL

    引入 优先队列是一种特殊的队列,它的功能是--自动排序. 基本操作: q.size(); //返回q里元素个数 q.empty(); //返回q是否为空,空则返回1,否则返回0 q.push(k); ...

  6. python亲密数设计

    '''亲密数 (如果a的所有正因子和等于b,b的所有正因子和等于a,因子包括1但不包括本身,且a不等于b,则称a,b为亲密数对.一般通过叠代编程求出相应的亲密数对)'''n = 3000def fun ...

  7. Vue-简单安装和运行

    安装Vue CLI 安装nodejs 下载: https://nodejs.org/en/download/ 安装Vue CLI 文档: https://cli.vuejs.org/guide/ins ...

  8. bat-静默安装并配置mysql(windows版)

    mysql版本 mysql-5.6.35-winx64 路径关系 @echo off Setlocal enabledelayedexpansion @REM vscode中自动开启延迟环境变量扩展, ...

  9. 如何用python做出老师看了都给满分的GUI学生管理系统毕设

    序 言 哈喽大家好鸭!我是小熊猫 最近有什么有趣的事情发生吗?快来说给我听听( •̀ ω •́ )✧表弟大学快毕业了,学了一个学期Python居然还不会写学生管理系统,真的给我丢脸啊,教他又不肯学,还 ...

  10. 高仿Android网易云音乐OkHttp+Retrofit+RxJava+Glide+MVC+MVVM

    简介 这是一个使用Java(以后还会推出Kotlin版本)语言,从0开发一个Android平台,接近企业级的项目(我的云音乐),包含了基础内容,高级内容,项目封装,项目重构等知识:主要是使用系统功能, ...