最近在与深圳世强的FAE帮助下在利用他们提供Si4438样片和开发板在开发无线抄表方案。搜Si4438的资料,看到阿莫论坛上有朋友分享的si4432 51调试程序源码(原帖链接http://www.amobbs.com/thread-4969312-1-1.html)
其实Si4438是si4432的升级版,硬件特性上有很多提升,为中国智能电表市场定制的,只支持470-510MHz频段,所以价格、功耗和尺寸都有降低。不知道坛子里有没有熟悉这两款芯片的?有在做这个项目的可以试一试这个程序,还没有认真研读过代码,也不太了解Si4432,不知道代码是否兼容,改天请教世强的专家两款芯片在硬件、寄存器配置、管脚兼容以及软件上的兼容性,也欢迎大家讨论下!~
/* * Copyright (c) 2011, * All rights reserved. * * 当前版本:1.0 * 作者:杨永贞QQ534117529 * 开始日期:2011年8月10日 * */ #include <reg51.h> #include <string.h> #include "radio.h" #include"spi.h" #include"uart.h" #define U8 unsigned char #define SEND_OUT_MESSAGE_WITH_ACK "NEED_ACK" #define SEND_OUT_MESSAGE_NO_ACK "NO_ACK" #define SEND_OUT_ACK "ACK!" #define SEND_OUT_MESSAGE_WITH_ACK_LEN 8 #define SEND_OUT_MESSAGE_NO_ACK_LEN 6 #define SEND_OUT_ACK_LEN 4 #define SNED_OUT_MSG_MAX_LEN 8 //It is the maxium length of the send out packet. extern idata U8 ItStatus1,ItStatus2; void delay_ms(unsigned int ms) { unsigned int i; unsigned char j; for(i=0;i<ms;i++) { for(j=0;j<200;j++); for(j=0;j<102;j++); } } void Init_Device(void) { // Reset_Sources_Init(); // PCA_Init(); // Port_IO_Init(); // Oscillator_Init(); // Timer0_Init(); SPI_Init(); EA = 1; //Enable Gloable interruption. //启动射频模块,模块的SDN引脚拉低后必须延时至少30ms,实际上可以直接把SDN引脚接地,这样就不用在程序中初始化了; RF_SDN=0; delay_ms(30); delay_ms(30); // RF_SDN = 0; // DelayMs(30); // NSEL = 1; // SCLK = 0; SpiWriteRegister(0x0B, 0xCA); SpiWriteRegister(0x0C, 0xCA); SpiWriteRegister(0x0D, 0xCA); //1.Blink the LED to show that the initialization is finished. //2.Wait for more than 16ms to wait for the radio chip to work correctly. // TurnOnAllLEDs(); // DelayMs(20); delay_ms(20); // TurnOffAllLEDs(); } void main(void) { U8 length,temp8, *str, sendLen; U8 payload[10]; //Initialize the MCU: UART_Init(); Init_Device(); UART_Send_Str("MCU初始化完毕....\n"); //读取中断状态寄存器清除中断标志以便释放NIRQ引脚 //如果中断来了,那么NIRQ引脚会被拉低;如果这时候中断状态寄存器0x03和0x04被读取,那么NIRQ引脚会被释放恢复高电平 ItStatus1 = SpiReadRegister(0x03); //read the Interrupt Status1 register ItStatus2 = SpiReadRegister(0x04); //read the Interrupt Status2 register //SW reset,软件复位这个模块主控芯片 SpiWriteRegister(0x07, 0x80); //write 0x80 to the Operating & Function Control1 register // DelayMs(20); delay_ms(20); delay_ms(20); //wait for POR interrupt from the radio (while the nIRQ pin is high) //wait for chip ready interrupt from the radio (while the nIRQ pin is high) //等待软复位完成,当软复位完成后有中断发生。客户也可以在这里直接延时至少20ms而不用等待中断来;等待至少20ms后复位完成,这时候必须读中断状态寄存器释放中断引脚 while ( NIRQ == 1); //read interrupt status registers to clear the interrupt flags and release NIRQ pin ItStatus1 = SpiReadRegister(0x03); //read the Interrupt Status1 register ItStatus2 = SpiReadRegister(0x04); //read the Interrupt Status2 register //根据不同的射频参数初始化射频模块; RF_init(); UART_Send_Str("RF芯片si4432初始化完毕....\n"); //Enable two interrupts: // a) one which shows that a valid packet received: 'ipkval' // b) second shows if the packet received with incorrect CRC: 'icrcerror' //设置中断使能寄存器,这里设置为只有当有效的数据包被接收或者接收到的数据包数据CRC校验出错才来中断;具体设置参考0x05和0x06寄存器 SpiWriteRegister(0x05, 0x03); //write 0x03 to the Interrupt Enable 1 register SpiWriteRegister(0x06, 0x00); //write 0x00 to the Interrupt Enable 2 register //output dummy data. PB1_TX = 1; PB2_TX = 1; str = SEND_OUT_MESSAGE_WITH_ACK; sendLen = SEND_OUT_MESSAGE_WITH_ACK_LEN; //设置模块处于接收状态,当没有按键按下的时候一直处于接收状态,等待接收数据 RFSetRxMode(); UART_Send_Str("模块处于接收状态....\n"); /*MAIN Loop*/ while(1) { //当按键被按下就有一个数据包被发出; if(PB1_TX == 0) { while( PB1_TX == 0 ); UART_Send_Str("按键按下,开始发送....\n"); RFFIFOSendData(sendLen, str); //after packet transmission set the interrupt enable bits according receiving mode //Enable two interrupts: // a) one which shows that a valid packet received: 'ipkval' // b) second shows if the packet received with incorrect CRC: 'icrcerror' //设置中断使能寄存器,这里设置为只有当有效的数据包被接收或者接收到的数据包数据CRC校验出错才来中断;具体设置参考0x05和0x06寄存器 SpiWriteRegister(0x05, 0x03); //write 0x03 to the Interrupt Enable 1 register SpiWriteRegister(0x06, 0x00); //write 0x00 to the Interrupt Enable 2 register //发射完毕后设置模块让它又工作在接收状态下; RFSetRxMode(); UART_Send_Str("发送完毕,恢复到接收状态....\n"); } //check whether interrupt occured //查询中断是否到来,如果中断来了,根据我们前面中断使能寄存器的设置,说明有效数据包已经收到,或者收到的数据包CRC校验出错; //如果客户采用中断触发的方式,那么服务程序必须包括这些内容。在中断服务程序中必须判断被使能的那些中断的状态位是否被置位,然后根据不同的 //状态位进行处理 if( NIRQ == 0 ) { //设置模块处于空闲模式,处理收到的数据包,不继续接收数据 RFSetIdleMode(); UART_Send_Str("中断来了....\n"); /*CRC Error interrupt occured*/ //判断是否由于CRC校验出错引发的中断;在RFSetIdleMode中已经读出了中断状态寄存器的值 if( (ItStatus1 & 0x01) == 0x01 ) { //reset the RX FIFO //如果是CRC校验出错,那么接收FIFO复位; SpiWriteRegister(0x08, 0x02); //write 0x02 to the Operating Function Control 2 register SpiWriteRegister(0x08, 0x00); //write 0x00 to the Operating Function Control 2 register //blink all LEDs to show the error //闪灯提示,客户移植代码的时候这个闪灯操作根据不同客户不同操作 // TurnOnAllLEDs(); // DelayMs(2); UART_Send_Str("CRC校验出错中断....\n"); // TurnOffAllLEDs(); } /*packet received interrupt occured*/ //判断是否是数据包已经被正确接收。 if( (ItStatus1 & 0x02) == 0x02 ) { //Read the length of the received payload //数据包已经被正确接收,读取收到的数据包长度 length = SpiReadRegister(0x4B); //read the Received Packet Length register //根据长度判断相应的操作。客户可以不做这些,而直接从FIFO读出收到的数据; //check whether the received payload is not longer than the allocated buffer in the MCU if(length <= SNED_OUT_MSG_MAX_LEN) { //Get the reeived payload from the RX FIFO //直接从FIFO中读取收到的数据。客户只要读出FIFO的数据就算收到数据。 for(temp8=0;temp8 < length;temp8++) { payload[temp8] = SpiReadRegister(0x7F); //read the FIFO Access register } for(temp8=0;temp8 < length;temp8++) { UART_Send_Byte(payload[temp8]); //向串口发送接收到的数据 } UART_Send_Str("向串口发送接收到的数据....\n"); //check whether the acknowledgement packet received //判断是否是预先设定的数据;一般应用情况客户可以不理会这个,这个判断只是我们demo板的应用。客户只要读出FIFO的数据就算收到数据; if(( length == SEND_OUT_ACK_LEN ) || (length == SEND_OUT_MESSAGE_NO_ACK_LEN)) { if((memcmp(&payload[0], SEND_OUT_ACK, SEND_OUT_ACK_LEN - 1) == 0 ) || (memcmp(&payload[0], SEND_OUT_MESSAGE_NO_ACK, SEND_OUT_MESSAGE_NO_ACK_LEN - 1) == 0)) { //blink LED2 to show that ACK received // RxLEDOn(); //Show the Rx LED for about 10ms UART_Send_Str("数据包已经被正确接收....\n"); // DelayMs(2); // TurnOffAllLEDs(); } } //check whether an expected packet received, this should be acknowledged //判断是否是需要发送回答信号的数据包。这个只是根据收到的数据做的不同操作,在客户那里可能是根据收到的数据做的特定的操作,例如控制某个开关 if( length == SEND_OUT_MESSAGE_WITH_ACK_LEN ) { //必须发送应答信号,启动发送 if( memcmp(&payload[0], SEND_OUT_MESSAGE_WITH_ACK, SEND_OUT_MESSAGE_WITH_ACK_LEN - 1) == 0 ) { //blink LED2 to show that the packet received //RxLEDOn(); //Show the Rx LED for about 10ms // DelayMs(2); UART_Send_Str("发送应答....\n"); // TurnOffAllLEDs(); //发送应答信号。 /*send back an acknowledgement*/ RFFIFOSendData(SEND_OUT_ACK_LEN, SEND_OUT_ACK); //after packet transmission set the interrupt enable bits according receiving mode //Enable two interrupts: // a) one which shows that a valid packet received: 'ipkval' // b) second shows if the packet received with incorrect CRC: 'icrcerror' SpiWriteRegister(0x05, 0x03); //write 0x03 to the Interrupt Enable 1 register SpiWriteRegister(0x06, 0x00); //write 0x00 to the Interrupt Enable 2 register //read interrupt status registers to release all pending interrupts ItStatus1 = SpiReadRegister(0x03); //read the Interrupt Status1 register ItStatus2 = SpiReadRegister(0x04); //read the Interrupt Status2 register } } } } //reset the RX FIFO SpiWriteRegister(0x08, 0x02); //write 0x02 to the Operating Function Control 2 register SpiWriteRegister(0x08, 0x00); //write 0x00 to the Operating Function Control 2 register RFSetRxMode(); } } }