高性能射频收发器CC1101
简介:
CC1101是一款低于1GHz高性能射频收发器,设计旨在用于极低功耗RF应用。其主要针对工业、科研和医疗(ISM)以及短距离无线通信设备(SRD)。CC1101可提供对数据包处理、数据缓冲、突发传输、接收信号强度指示(RSSI)、空闲信道评估(CCA)、链路质量指示以及无线唤醒(WOR)的广泛硬件支持。CC1101在代码、封装和外引脚方面均与CC1100兼容,可用于全球最为常用的开放式低于1GHz频率的RF设计。
详细介绍:
1. 数据包格式:可以对数据包格式进行配置,其由如下各项组成:前导;同步字;可选长度字节;可选地址字节;有效负载;可选 2 字节 CRC。
2. 接收模式下的数据包滤波:
CC1100E 支持三种不同类型的数据包滤波:地址滤波,最大长度滤波,CRC 滤波。
2.1 地址滤波:
设置 PKTCTRL1.ADR_CHK 为 0 以外的任何值便可开启数据包地址滤波器。该包处理器引擎会将数据包中的目标地址字节与 ADDR 寄存器中的编程节点地址, 以及 PKTCTRL1.ADR_CHK=10 时的 0x00 广播地址或者PKTCTRL1.ADR_CHK=11 时的 0x00 和0Xff 广播地址进行比较。如果接收到的地址匹配一个有效地址,则接收该数据包,并将其写入 RX FIFO。如果地址匹配失败, 则丢弃该数据包, 并重新启动接收模式( 与MCSM1.RXOFF_MODE 设置无关)。当使用无限数据包长度模式并且地址滤波开启时,如果接收到的地址匹配一个有效地址,那么 0xFF 便会被写入 RX FIFO,之后是地址字节,最后是有效负载数据。
2.2 最大长度滤波
在 可 变 数 据 包 长 度 模 式 下 , 即 PKTCTRL0.LENGTH_CONFIG=1 ,PKTLEN.PACKET_LENGTH 寄存器值用于设置最大允许的数据包长度。如果接收到的长度字节具有一个比该允许的长度更大值,则丢弃该数据包,并且重新启动接收模式(与 MCSM1.RXOFF_MODE 设置无关)。
2.3 CRC 滤波
如果 CRC 校验失败,则设置 PKTCTRL1.CRC_AUTOFLUSH=1 来开启数据包滤波。如果 CRC 校验失败,CRC 自动刷新功能将会刷新整个 RX FIFO。自动刷新 RX FIFO 以后,后面的状态则取决于 MCSM1.RXOFF_MODE 的设置。请注意, 开启PKTCTRL1.APPEND_STATUS 之后,最大允许的数据包长度减小 2 字节,目的是在 RX FIFO 中为数据包末尾添加的 2 个状态字节留出空间。由于 CRC校验失败时整个 RX FIFO 被刷新,之前接收到的数据包必须在接收当前数据包以前从 FIFO 读取出来。在 CRC 校验为 OK 以前,MCU 不能读取当前数据包。
3. 发送模式下的数据包处理
必须要将即将要被发送的有效负载写入 TX FIFO 中。开启可变数据包长度以后,长度字节必须最先被写入。长度字节具有一个与数据包有效负载相当的值(包括可选地址字节)。如果接收机端开启了地址识别,则写入 TX FIFO 的第二个字节必须为地址字节。如果开启了固定数据包长度,则写入 TX FIFO 的第一个字节应为地址字节(假设接收机使用了地址识别)。
设计:
1. 本程序运行平台为MSP430 5438:
(1)采用SPI通信方式实现单片机与CC1101之间的通信;
(2)CC1101采用可变长度+地址滤波+CRC校验滤波模式,收发功能均待命;
(3)程序以高精度气压传感器MS5611的测量数据进行传输。
2. 为了充分适配单片机的性能,使用了以下方法:
(1)从气压传感器得到的数据仍需经过后续计算才能得到海拔值,但由于传感节点MSP430性能有限,因此决定将大部分后续计算转移至汇聚节点(ARM)中进行计算:速度快、并且传感节点也能尽可能省电;
(2)由于单片机电量限制,CC1101必须尽量省电,同时也为了尽可能减少丢包率,数据包应当尽可能小。因此,将气压传感器测量得到的经过部分处理后得到的气压值(浮点数)以其在内存中的存储形式(计算机组成原理)进行 发送,以尽可能减小数据包长度;
(3)由于CC1101接收数据和发送数据需要利用中断来处理,并且MSP430不支持多级中断,为了及时响应后续任务,中断函数中的语句应当尽可能少。为此,添加全局变量标识符,在中断中将标识符置位后,退出中断而在主函数中执行所需任务。
3. 所得经验和教训:
(1)若CC1101需要切换模式,则必须先切换至SIDLE(空闲)模式后才能进行切换!
/*-----------退出任何状态或者进入任何状态前先行进行idle状态!*-----------*/ SPI_B2_Strobe(CCxxx0_SIDLE); /*-----------退出任何状态或者进入任何状态前先行进行idle状态!*-----------*/
(2)当将发送任务不是在中断函数中实现,而是在主函数中实现时,CC1101的GDO0将会被置位,此时将会产生莫名的中断!因此必须在进入发送状态和完成发送时关闭总中断,并且将GDO0中断标志位清零!
_DINT(); SPI_B2_Strobe(CCxxx0_STX); // 进入发射状态 while(!(P1IN& GDO0)); // 等待GDO0置高,置高表示数据报头已经发送 while(P1IN& GDO0); // 等待GDO0置低,置低表示数据报已经发送完成 P1IFG &=~ GDO0; _EINT();
例程:
1. 系统初始化函数
/* *@Function name:Init_CLK *@Descriptions: 初始化系统时钟和看门狗模块 ——MCLK=SMCLK=XT2/2=8M; ——看门狗为INTERVAL模式,中断间隔为250ms *@Parameters: NONE *@Returned Value:NONE *@Others: NONE */ void Init_CLK(void) { WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer WDTCTL = WDT_ADLY_250; SFRIE1|= WDTIE; P5SEL |= 0x0C; // Port select XT2 P7SEL |= 0x03; UCSCTL6 &= ~XT2OFF; // Enable XT2 even if not used UCSCTL6 &= ~XT1OFF; UCSCTL6 |= XCAP_3; do { UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG);// Clear XT2,XT1,DCO fault flags SFRIFG1 &= ~OFIFG; // Clear fault flags }while (SFRIFG1&OFIFG); // Test oscillator fault flag UCSCTL4 |= SELS_5 + SELM_5 + SELA_0; // SMCLK=MCLK=XT2-16M,ACLK=XT1 UCSCTL5 |= DIVM__2 + DIVS__2+DIVA__2; //主系统时钟2分频-8M;子系统时钟2分频-8M }
2. SPI端口初始化:
/*---------------------SPI B2相关函数-----------------------------*/ void Init_SPI_B2(void) { P9SEL |= 0x0E; // P9.1-3 SPI option select UCB2CTL1 |= UCSWRST; // 复位SPI状态机 UCB2CTL1 |= UCSSEL__SMCLK; // 选择SCK参考源为SMCLK UCB2CTL0 |= UCMST+UCSYNC+UCCKPH+UCMSB; // 3-pin, 8-bit SPI master, Clock polarity high, MSB UCB2CTL0 &=~UCCKPL; UCB2BR0 = 0x02; UCB2BR1 = 0x00; UCB2CTL1 &= ~UCSWRST; // 复位SPI状态机 P9DIR|=BIT5; P9OUT|=BIT5; } unsigned char SPI_B2_Send_byte(unsigned char byte) { while((UCB2IFG&UCTXIFG)==0); UCB2TXBUF=byte; while((UCB2IFG&UCRXIFG)==0); return(UCB2RXBUF); } unsigned char SPI_B2_Receive_byte(void) { return SPI_B2_Send_byte(0); } void SPI_B2_WriteReg(unsigned char addr, unsigned char value) { CC1101_Enable; //CS=0 CS enable Wait_cc(); // Wait for CCxxxx ready SPI_B2_Send_byte(addr); // Send address SPI_B2_Send_byte(value); // Send data CC1101_Disable; } unsigned char SPI_B2_Read(unsigned char addr) { unsigned char rTemp; CC1101_Enable; // CS=0 CS enabl Wait_cc(); SPI_B2_Send_byte(addr | CCxxx0_READ_SINGLE); // Send address rTemp = SPI_B2_Receive_byte(); CC1101_Disable; // CS=1 CS disable return ( rTemp ); } void SPI_B2_WriteBurstReg(unsigned char addr, unsigned char *buffer, unsigned char count) { unsigned char i; CC1101_Enable; //CS=0 CS enable Wait_cc(); // Wait for CCxxxx ready SPI_B2_Send_byte(addr | CCxxx0_WRITE_BURST);// Send address for (i = 0; i < count; i++) { SPI_B2_Send_byte(buffer[i]); // Send data } CC1101_Disable; //CS=1 CS disable } void SPI_B2_ReadBurstReg(unsigned char addr, unsigned char *buffer, unsigned char count) { unsigned char i; CC1101_Enable; // CS=0 CS enable Wait_cc(); // Wait for CCxxxx ready SPI_B2_Send_byte(addr | CCxxx0_READ_BURST); // Send address for (i = 0; i < count; i++) { buffer[i] = SPI_B2_Receive_byte(); // Read data } CC1101_Disable; //CS=1 CS disable } void SPI_B2_Strobe(unsigned char strobe) { CC1101_Enable; //CS=0 CS enable Wait_cc(); // Wait for CCxxxx ready SPI_B2_Send_byte(strobe); // Send strobe CC1101_Disable; } /*---------------------SPI B2相关函数-----------------------------*/
3. CC1101初始化:
/* *@Function name:Init_1101 *@Descriptions: 初始化CC1101,接收终端使能,上电重启,初始化各寄存器 进入信道为RxChannel=33的接收模式 *@Parameters: NONE *@Returned Value:NONE *@Others: NONE */ void Init_1101() { Init_SPI_B2(); P1DIR&=~GDO0; P1OUT|=GDO0; P1REN|=GDO0; P1IES |= GDO0; //使能GDO0中断发生在下降沿 P1IFG = 0x00; //中断寄存器清零 P1IE |= GDO0; //中断使能 P1IFG=0; PowerupResetCCxxxx(); writeRFSettings(); SPI_B2_Strobe(CCxxx0_SIDLE); //cc1101退出SWOR,唤醒 SPI_B2_WriteReg(CCxxx0_PATABLE, PA_VALE); SPI_B2_WriteReg(CCxxx0_CHANNR,RxChannel); SPI_B2_Strobe(CCxxx0_SFRX); //复位SWORr5 SPI_B2_Strobe(CCxxx0_SRX); }
4. 主函数
/* *@Function name:main *@Descriptions: 主函数,初始化系统时钟、CC1101和MS5611,开总中断,然后进入低功耗模式 若看门狗标志为1,则气压传感器进行测量、1101进行数据发送 *@Parameters: NONE *@Returned Value:NONE *@Others: NONE */ void main(void) { Init_CLK(); Init_1101(); MS5611_Init(); _EINT(); while(1) { //SFRIE1&=~WDTIE;//用于屏蔽发送功能,测试接收功能:经测试正常! if(WDTFlag) { char length=4,address=0x18,ID=1;//十六进制浮点型气压值长度;汇聚节点地址;自身ID地址 float Pressure; unsigned long temp; /*----------------------测量数据-----------------------*/ Pressure=MS5611_getPressure(SamplingPeriod); //int heighth=KalmanFilter(get_altitude(Pressure));//用于检验数据的正确性 /*----------------------转换数据-----------------------*/ temp=*(unsigned long *)&Pressure;//IAR中long型才为32位,int型为16位;而在VC,VS中int型为32位 Buffer[0]=length+2;//地址字节+气压值长度+ID地址字节 Buffer[1]=address;//目标地址长度 Buffer[2]=ID;//自身ID地址 Buffer[3]=temp>>24;//十六进制浮点型气压值 Buffer[4]=temp>>16; Buffer[5]=temp>>8; Buffer[6]=temp; /*----------------------发送数据-----------------------*/ //for(int i=0;i<2;i++) //{ TxData(Buffer,length+3);//长度字节+地址字节+ID字节+气压值长度,标明写进缓冲区的字节数量 //} /*----------------------继续接收-----------------------*/ SPI_B2_Strobe(CCxxx0_SIDLE); SPI_B2_WriteReg(CCxxx0_CHANNR,RxChannel); SPI_B2_Strobe(CCxxx0_SFRX); //SPI_B2_Strobe(CCxxx0_SRX); SPI_B2_Strobe(CCxxx0_SWORRST); //复位SWOR r5 SPI_B2_Strobe(CCxxx0_SWOR); //进入低功耗接收 WDTFlag=0; } LPM4; } }
5. 看门狗中断响应处理函数:
/* *@Function name:WDT_ISR *@Descriptions: 看门狗中断处理函数,将看门狗标志置为1 *@Parameters: NONE *@Returned Value:NONE *@Others: NONE */ #pragma vector=WDT_VECTOR __interrupt void WDT_ISR(void) { WDTFlag=1; LPM4_EXIT; }
6. CC1101接收中断处理函数:
/* *@Function name:P1_ISR *@Descriptions: P1中CC1101中断处理函数,其进行以下操作: 检测CRC校验状态-——>如果正确则接收该数据包,否则丢弃-——>恢复低功耗接收模式 *@Parameters: NONE *@Returned Value:NONE *@Others: NONE */ #pragma vector = PORT1_VECTOR __interrupt void P1_ISR(void) { unsigned char RxBufferLength,addr=3;//addr为命令所在位置 //_DINT(); //5438不支持多级中断? if(P1IFG&GDO0) { if(SPI_B2_Read(0xF8) & CCxxx0_CRC_OK)//判断CRC校验 { /*-----------------------接收数据----------------------*/ RxBufferLength = SPI_B2_Read(0XFB);//读取数据包长度 SPI_B2_ReadBurstReg(CCxxx0_RXFIFO, read, RxBufferLength);//读取数据 CommandProcess(read[addr]);//处理命令函数 } SPI_B2_Strobe(CCxxx0_SFRX); //SPI_B2_Strobe(CCxxx0_SRX); SPI_B2_Strobe(CCxxx0_SWORRST);//复位SWOR r5 SPI_B2_Strobe(CCxxx0_SWOR);//进入低功耗接收 P1IFG &= ~GDO0; } }