分享得到的一个“穿墙王”程序源码完整程序文件
其实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();
}
}
}
4432应该是兼容的吧? Si4438与Si446x收发器产品引脚兼容以及软件兼容哦(是针对全球部署智能电表和智能电网产品而设计的sub-GHz ISM频段产品)。
并不完全兼容,下面是我请世强的杨工提供的采用Si4438的部分代码,大家可以参考下,完整的代码可以找深圳世强的FAE杨工要。大家可以对比研究下。
#include "compiler_defs.h"
#include "c8051f960_defs.h"
#include "hardware_defs.h"
#include "control_IO.h"
#include "spi.h"
#include "Si446x_B0_defs.h"
#include "ezrp_next_api.h"
#include "modem_params.h"
// Define capacitor bank value
#define CAP_BANK_VALUE 0x48 // Capacitor bank value for adjusting the XTAL frequency
// Note that it may varies on different test cards
/*------------------------------------------------------------------------*/
/* GLOBAL variables */
/*------------------------------------------------------------------------*/
// Set up modem parameters database; data is retrieved from modem_params.h header file which is
// automatically generated by the WDS (Wireless Development Suite)
SEG_CODE U8 ModemTrx1[] = {7, MODEM_MOD_TYPE_7};
SEG_CODE U8 ModemTrx2[] = {5, MODEM_CLKGEN_BAND_5};
SEG_CODE U8 ModemTrx3[] = {11, SYNTH_PFDCP_CPFF_11};
SEG_CODE U8 ModemTrx4[] = {12, FREQ_CONTROL_INTE_12};
SEG_CODE U8 ModemRx1[] = {11, MODEM_MDM_CTRL_11};
SEG_CODE U8 ModemRx2[] = {14, MODEM_BCR_OSR_1_14};
SEG_CODE U8 ModemRx3[] = {12, MODEM_AFC_GEAR_12};
SEG_CODE U8 ModemRx4[] = {5, MODEM_AGC_CONTRL_5};
SEG_CODE U8 ModemRx4_1[] = {7, MODEM_AGC_WINDOW_SIZE_7};
SEG_CODE U8 ModemRx5[] = {9, MODEM_FSK4_GAIN1_9};
SEG_CODE U8 ModemRx6[] = {8, MODEM_OOK_PDTC_8};
SEG_CODE U8 ModemRx7[] = {8, MODEM_RAW_SEARCH_8};
SEG_CODE U8 ModemRx8[] = {6, MODEM_ANT_div_MODE_6};
SEG_CODE U8 ModemRx9[] = {13, MODEM_CHFLT_RX1_CHFLT_COE13_7_0_13};
SEG_CODE U8 ModemRx10[] = {13, MODEM_CHFLT_RX1_CHFLT_COE4_7_0_13};
SEG_CODE U8 ModemRx11[] = {13, MODEM_CHFLT_RX2_CHFLT_COE13_7_0_13};
SEG_CODE U8 ModemRx12[] = {13, MODEM_CHFLT_RX2_CHFLT_COE4_7_0_13};
/*------------------------------------------------------------------------*/
/* LOCAL function prototypes */
/*------------------------------------------------------------------------*/
void MCU_Init(void);
/*------------------------------------------------------------------------*/
/* MAIN function */
/*------------------------------------------------------------------------*/
void main(void)
{
SEGMENT_VARIABLE(wDelay, U16, SEG_XDATA);
SEGMENT_VARIABLE(bButtonNumber, U8, SEG_XDATA);
BIT fValidPacket;
//initialize the MCU peripherals
MCU_Init();
InitIO();
// Reset the radio
EZRP_PWRDN = 1;
// Wait ~300us (SDN pulse width)
for(wDelay=0; wDelay
这种穿墙技术能用在RFID读卡器上面吗?
关于Si4438,可以看看这个文章,里面可能有介绍,不过没有讲具体的方案细节——世强Silicon labs方案助力无线抄表从模块到终端的“穿越”
http://www.eeworld.com.cn/wltx/2013/1219/article_12016.html
很好的分享,可惜不做无线抄表好多年~~~
为什么不用世强提供的完整解决方案?收发器+MCU都可以用他们家的方案呗(貌似瑞萨也是他们家在提供分销业务哦,瑞萨的MCU在电表上应用很普及!)
市场的力量强大啊,芯科可以针对中国定制芯片啦,不过国内不少无线电表是针对国际市场的,Si446x和 Si4432或许更适合很多公司的产品项目
PS:我想知道图片上的文字,哪个市非法的
现在也有用超高频RFID手持机来做无线抄表的。