RF4463F30半双工模组,伪全双工透传方案(STM32平台)(第一章,环境搭建)

前言

经过长期的测试,我惊奇的发现,e70模块在传输距离和质量上多么的不足(心疼我研究的时间,下次一定先测距离),于是我转移了重心到另一组模块上RF4463F30(思为无线),这同样是半双工模块,然后通讯质量却让我震惊,首先是速度,其次是距离,再三是稳定性,最后是可调节性。价格相近,性能优越,再加上充分的技术支持,OMG,买它!!!。
虽然后期官方给我提供了stm32的例程,但是前期我用的官方提供的vc的例程,因此给了我较大的发挥空间和理解工程的机会。本文主要讲解如何将vc的例程转为stm32的例程。

模块介绍

以下信息来自模块的介绍手册,想详细了解的请去官网下载。
链接:官网4463页面

基础信息

首先我放出这个模块的基础工作外围电路
(作为软件开发,我最关心的的就是可操作的IO口了):
在这里插入图片描述
从上图来看,主要的控制IO口一共是7个,这7个IO具体的功能如下:
在这里插入图片描述
其中的SDI,SDO,SCK接入单片机时可以直接配置外设的SPI,nIRQ作为中断信号脚需配置为下拉输入(建议再配置外部中断),
SDN 作为芯片开关,对接单片机时应采用推挽输出,nSEL 同样是推挽输出。

接着附上引脚图:
在这里插入图片描述
最后贴上手册里描述的产品特点:
在这里插入图片描述
这些我觉得跟软件开发没什么关系,我就不介绍了。

参数配置

这个模块的参数可以手动修改初始化程序里的spi写入部分,也可以直接使用厂家提供WDS配置软件,详细操作我不描述了,请购买后自行参照厂家提供的操作手册,我重点说一下几个核心:

通讯频段

在这里插入图片描述
实际通讯频率是:主频率+偏移频率*倍数。 请确保通讯的模块工作频率相同(频率越高速度越快,通讯距离约近,频率越低速度约慢,通讯距离和抗干扰性越强)。具体选择什么频率请根据实际工作需求进行抉择。

空中速率

在这里插入图片描述
空速和频率决定模块的实际通讯速度。 这一部分我只建议修改这两处,其余还是选择默认值为好,其中根据官方技术支持的建议:当空速低于19200时,频率填5khz,当空速高于19200时,频率填10khz,平时建议空速低于38400,如果高于38400则建议提高频率到15khz。 我追求高速传输因此选择了空速是115200,频率为20khz。

配置文件生成

在这里插入图片描述
点击这个按键,然后选择第二项:保存头文件。
然后你就可以获得一个头文件:radio_config_Si4463.h
注意,这个头文件不能直接替换,一共有4处修改地方,两处是在头文件里,两处是在例程里。

头文件修改处1

在这里插入图片描述
这一处要注释掉,很好理解吧。

头文件修改处2

在这里插入图片描述
很关键的修改,千万不能忘记,否则将直接导致模块发烫甚至损毁(我前期操作不当,损失了一块stm32)

扫描二维码关注公众号,回复: 10752270 查看本文章

库函数修改处1

在这里插入图片描述
我也不知道这是什么,反正就是这一处,原来是8,生成的文件里是10

库函数修改处2

在这里插入图片描述

宏定义来源

同理,另外这个high_speed 是我自定义的,原理如下:
在这里插入图片描述
其中_n结尾的是原始的头文件,另一个是我自己生成的头文件我区分了名字都放在一个目录下(能看明白吧)

例程简述

下文将对官方提供的例程做一个简单注解,并重点描述关键函数关键参数

关键函数

sdn_reset //模块复位函数

void sdn_reset(void)
{	
	U8 i;
	i = 0;
	while(i!=0xff)
		i = check_cts();				//新增优化
 	SDN_1;
 	delay_1ms(2);
 	SDN_0;
 	delay_1ms(10);
 
 	nSEL_1;   
	SCK_0;
	nSEL_0;
	for (i = 0; i< 7; i++)
		spi_byte(RF_POWER_UP_data[i]);  
	nSEL_1;
 
 	delay_1ms(20);
}	

sdn_reset 这个函数是用于复位4463模块的其中有一个关键点就是这部分代码:(注释为新增优化的部分)

while(i!=0xff)
	i = check_cts();				//新增优化

这块代码是用于让spi通讯纯净化的,可以防止残留的错误spi数据影响对模块的读写。在例程里对spi操作的所有地方都有这个代码块(我获得的例程里在这一部分没有这个代码块,请自行核对检查)。4463模块有一个特点如果spi初始化参数没有写入成功(一段对IO口电平配置的程序写入失败),按着原始的参数进行工作,那么模块就会发烫。这里也是一处很重要的操作。(原始例程里少了这一块,我恰好环境里噪声多,因此初始化失败,持续发烫导致我损耗一块元器件)

SI4463_init //模块参数配置函数

void SI4463_init(void)
{	
	U8 app_command_buf[20];
				
	//spi_write(0x07, RF_GPIO_PIN_CFG_data);   
	app_command_buf[0] = 0x13;			// SET GPIO PORT
	app_command_buf[1]  = 0x21; 		// gpio 0 ,Rx data//0
	app_command_buf[2]  = 0x20;    		// gpio1, output 0//0
	app_command_buf[3]  = 0x21;  		// gpio2, hign while in receive mode
	app_command_buf[4]  = 0x20; 		// gpio3, hign while in transmit mode 
	app_command_buf[5]  = 0x27;   		// nIRQ
	app_command_buf[6]  = 0x0b;  		// sdo
	spi_write(7, app_command_buf); 
		
	// spi_write(0x05, RF_GLOBAL_XO_TUNE_1_data); 
	app_command_buf[0] = 0x11;  
	app_command_buf[1]  = 0x00;    
	app_command_buf[2]  = 0x01;    
	app_command_buf[3]  = 0x00;  
	app_command_buf[4]  = 98;  			// freq  adjustment
	spi_write(5, app_command_buf);

	// spi_write(0x05, RF_GLOBAL_CONFIG_1_data);
	app_command_buf[0]  = 0x11;  
	app_command_buf[1]  = 0x00;
	app_command_buf[2]  = 0x01; 
	app_command_buf[3]  = 0x03; 
	app_command_buf[4]  = 0x40;  		// tx = rx = 64 byte,PH,high performance mode
	spi_write(5, app_command_buf); 
    
	spi_write(0x08, RF_FRR_CTL_A_MODE_4_data);    // disable all fast response register
     
	// spi_write(0x0D, RF_PREAMBLE_TX_LENGTH_9_data); // set Preamble
 	app_command_buf[0]  = 0x11;  
	app_command_buf[1]  = 0x10;    
	app_command_buf[2]  = 0x09;    
	app_command_buf[3]  = 0x00;   
	app_command_buf[4]  = 0x08;							//  8 bytes Preamble
	app_command_buf[5]  = 0x14;							//  detect 20 bits
	app_command_buf[6]  = 0x00;						
	app_command_buf[7]  = 0x0f;
	app_command_buf[8]  = 0x31;  						//  no manchest.1010.。。
	app_command_buf[9]  = 0x00;
	app_command_buf[10]  = 0x00;
	app_command_buf[11]  = 0x00;
	app_command_buf[12]  = 0x00;
	spi_write(13, app_command_buf);	
	
	//  RF_SYNC_CONFIG_5_data,							// set sync
	app_command_buf[0]  = 0x11;  
	app_command_buf[1]  = 0x11;
	app_command_buf[2]  = 0x05;
	app_command_buf[3]  = 0x00;
	app_command_buf[4]  = 0x01;   						// no manchest , 2 bytes
	app_command_buf[5]  = 0x2d;   						// sync byte3
	app_command_buf[6]  = 0xd4;							// sync byte2
	app_command_buf[7]  = 0x00;							// sync byte1
	app_command_buf[8]  = 0x00;							// sync byte0
	spi_write(9, app_command_buf);
        
	//  packet crc         
  app_command_buf[0]  = 0x11;  
	app_command_buf[1]  = 0x12; 
	app_command_buf[2]  = 0x01; 
	app_command_buf[3]  = 0x00;
	app_command_buf[4]  = 0x81;							// CRC = itu-c, enable crc
	spi_write(5, app_command_buf);  
        
	// packet   gernale configuration        
	app_command_buf[0] = 0x11;  
	app_command_buf[1]  = 0x12;
	app_command_buf[2]  = 0x01;
	app_command_buf[3]  = 0x06;
	app_command_buf[4]  = 0x02;							// CRC MSB, data MSB
    spi_write(5, app_command_buf);
        
	// spi_write(0x07, RF_PKT_LEN_3_data);   
	app_command_buf[0] = 0x11;  
	app_command_buf[1]  = 0x12;
	app_command_buf[2]  = 0x03;
	app_command_buf[3]  = 0x08;
	app_command_buf[4]  = 0x00;
	app_command_buf[5]  = 0x00;
	app_command_buf[6]  = 0x00;						 
	spi_write(7, app_command_buf);         
	
	app_command_buf[0] = 0x11;  
	app_command_buf[1]  = 0x12;
	app_command_buf[2]  = 0x0c;
	app_command_buf[3]  = 0x0d;
	app_command_buf[4]  = 0x00;
	app_command_buf[5]  = payload_length;
	app_command_buf[6]  = 0x04;
	app_command_buf[7]  = 0xaa;
	app_command_buf[8]  = 0x00;
	app_command_buf[9]  = 0x00;
	app_command_buf[10]  = 0x00;
	app_command_buf[11]  = 0x00;
	app_command_buf[12]  = 0x00; 
	app_command_buf[13]  = 0x00;
	app_command_buf[14]  = 0x00;
	app_command_buf[15]  = 0x00;
	spi_write(16, app_command_buf);					// set length of Field 1 -- 4
  
	// spi_write(0x0C, RF_PKT_FIELD_4_LENGTH_12_8_8_data);
	app_command_buf[0] = 0x11;  
	app_command_buf[1]  = 0x12; 
	app_command_buf[2]  = 0x08;
	app_command_buf[3]  = 0x19;
	app_command_buf[4]  = 0x00;
	app_command_buf[5]  = 0x00;
	app_command_buf[6]  = 0x00;
	app_command_buf[7]  = 0x00;
	app_command_buf[8]  = 0x00;
	app_command_buf[9]  = 0x00;
	app_command_buf[10]  = 0x00;
	app_command_buf[11]  = 0x00;
	spi_write(12, app_command_buf);
    
	spi_write(0x10, RF_MODEM_MOD_TYPE_12_data);        
	spi_write(0x05, RF_MODEM_FREQ_DEV_0_1_data);
	
	spi_write(0x10, RF_MODEM_TX_RAMP_DELAY_12_data);    	
	spi_write(0x10, BCR_NCO_OFFSET_2_12_data);
	spi_write(0x10, RF_MODEM_TX_RAMP_DELAY_12_data);			
	spi_write(0x07, RF_MODEM_AFC_LIMITER_1_3_data);	
	//spi_write(0x10, BCR_NCO_OFFSET_2_12_data);

	spi_write(0x05, RF_MODEM_AGC_CONTROL_1_data);		
	spi_write(0x10, AGC_WINDOW_SIZE_12_data);	
	#ifdef high_speed
		spi_write(0x0E, RF_MODEM_RAW_CONTROL_10_data);
	#else
		spi_write(0x0c, RF_MODEM_RAW_CONTROL_8_data);
	#endif

//	spi_write(0x10, AGC_WINDOW_SIZE_12_data);
    
	// spi_write(0x05, RF_MODEM_RSSI_COMP_1_data);
	app_command_buf[0] = 0x11;  
	app_command_buf[1] = 0x20;                                                     
	app_command_buf[2] = 0x01;                                                   
	app_command_buf[3] = 0x4e;             
	app_command_buf[4]  = 0x40;
	spi_write(5, app_command_buf);            	     
 
	spi_write(0x10, COE13_7_0_12_data);
	spi_write(0x10, COE1_7_0_12_data);
	spi_write(0x10, COE7_7_0_12_data);       
        
	// RF_PA
	app_command_buf[0] = 0x11;  
	app_command_buf[1]  = 0x22;                                                    
	app_command_buf[2]  = 0x04;                                               
	app_command_buf[3]  = 0x00;                                                     
	app_command_buf[4]  = 0x08;
	app_command_buf[5]  = 127;							// set max power
	app_command_buf[6]  =0x00;
	app_command_buf[7]  = 0x3d;
	spi_write(8, app_command_buf);        
    
	spi_write(0x0B, RF_SYNTH_PFDCP_CPFF_7_data);
        
	// header match
	app_command_buf[0] = 0x11;  
	app_command_buf[1]  = 0x30;                                                     
	app_command_buf[2]  = 0x0c;                                                   
	app_command_buf[3]  = 0x00;                                                       
	app_command_buf[4]  = 's';
	app_command_buf[5]  = 0xff;
	app_command_buf[6]  = 0x40;
	app_command_buf[7]  = 'w';                                      
	app_command_buf[8]  = 0xff;                                       
	app_command_buf[9]  = 0x01; 
	app_command_buf[10] = 'w';                                   
	app_command_buf[11]  =0xff;                                       
	app_command_buf[12]  =0x02;
	app_command_buf[13]  = 'x';                                  
	app_command_buf[14]  = 0xff;
	app_command_buf[15]  =0x03;
	spi_write(16, app_command_buf);
    
	spi_write(6, RF_MODEM_RAW_SEARCH2_2_data);
	spi_write(12, RF_FREQ_CONTROL_INTE_8_data); 	    // set frequency    	
}        

这个函数是用于载入spi配置的,在其第一段有着配置gpio的功能,用户可以通过操作这部分代码验证spi初始化是否通过。

tx_data //发送数据函数

void tx_data(void)					
{	
	
	Flag.is_tx = 1;
	fifo_reset();  
	spi_write_fifo();  				
	enable_tx_interrupt();	
	clr_interrupt();
	tx_start();
	rf_timeout = 0;
	Flag.rf_reach_timeout = 0;
	delay_10ms();
	while(nIRQr)						
	{
//		//此处需要一个短延时
//		if(Flag.rf_reach_timeout)
//		{
//			sdn_reset();
// 			SI4463_init();  		
//			break;		
//		}			
	}

这个函数是接下来功能操作不可避免使用的函数但是不是很好用,这里对于中断脚信号的读取方式是查询电平高低,并且用死循环进行等待,浪费cpu。因此我简单改良了一下,改为读取标志位。如下:

void test_tx_data2(u8 *pdata)					
{	
	//delay_ms(1);
	Flag.is_tx = 1;
	Flag.run=0;
	fifo_reset();  
	m_spi_write_fifo(pdata); 				
	enable_tx_interrupt();	
	clr_interrupt();
	tx_start();
	rf_timeout = 0;
	Flag.rf_reach_timeout = 0;
	while(Flag.run!=2);					//等待发送成功
	Flag.run=0;	
	//clr_interrupt();
	
	Flag.is_tx=0;				  //转换为接收模式
	rx_init();					 	//接收模式初始化	
	Flag.run=0;	
}

rx_init //接受状态初始化函数

void rx_init(void)				
{
	Flag.is_tx = 0;
	fifo_reset();  					
	enable_rx_interrupt();	
	clr_interrupt();  				
	rx_start();
}	

test_Receive //接受数据函数(源例程是一段代码块,我取出来并稍微修改了一下)

void test_Receive(void)
{
	U8 i,chksum;
	if(!nIRQr)
	{ 
		clr_interrupt();   // clear interrupt	
		printf("---------------get_info-------------\n");

		if((spi_read_buf[4] &0x08) == 0)  // crc error check
		{
			spi_read_fifo();
			fifo_reset();

			chksum = 0;
			for(i=4;i<payload_length-1;i++)// Checksum
				chksum += rx_buf[i];          	 		
						
			if(( chksum == rx_buf[payload_length-1] )&&( rx_buf[4] == 0x41 ))  
			{
				;//LED_GREEN ^= 1;					// data right    	
				printf("***************data ok****************\n");
				for(i=0;i<payload_length;i++)
				{
					printf("%X",rx_buf[i]);
				}
				printf("\n");
			} 
			else
			{
				printf("---------------data wrong-------------\n");
				for(i=0;i<payload_length;i++)
				{
					printf("%X",rx_buf[i]);
				}
				printf("\n");
				rx_init();     				// data wrong
			}
		}
		else
		{
			printf("---------------crc error-------------\n");
			rx_init();   						// crc error
		}		
	}	
}

这个函数过于复杂了,我之后进行了简化

void test_Receive2(void)
{
	U8 i;
	if(Flag.run==2)
	{ 
		Flag.run=0;
		clr_interrupt();   					// clear interrupt	
		if((spi_read_buf[4] &0x08) == 0)  // crc error check
		{
			spi_read_fifo();
			fifo_reset();
			m_test.Count2++;
			for(i=4;i<payload_length;i++)
			{
				printf("%X",rx_buf[i]);
			}
			m_time.recevie_Time=GetTickCount();
			printf(",%d,%d,%d\n",m_time.recevie_Time,m_test.Count,m_test.Count2);
			
			Flag.is_tx=1;							//转换为发送模式
		}
		else
		{
			printf("---------------crc error-------------\n");
			rx_init();   						// crc error
		}		
	}
	i=i;	
}

以上就是获取数据的流程,其中获取到的数据会放在rx_buf里,并且,有前4个字节的帧头区分位,这部分数据也会在rx_buf,请注意隔离,我在代码里就从第4位开始了数据读取,抛弃了0~3这前3个字符。

关键参数/变量

tx_ph_data //发送数据缓存

static unsigned char tx_ph_data[payload_length] = {'s','w','w','x',0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x6d};  // test signal,The 10th data is a former nine checksum

其中前4位是头码,在SI4463_init函数里就有一段配置了头码,我没有尝试过取消头码的操作,如果有这方面需求,请自行联系官方技术支持。总长度14,4位是头码,后10位为自定义的数据,想要进行数据传输,就只能对这几位进行操作

payload_length //通讯包长度

#define payload_length  				PACK_MAX_LEN+4 

SI4463_init函数里有一段配置了数据包长度,因此每一次进行数据收发总包长是一定的。因此收发间隔是稳定且固定的,此处的PACK_MAX_LEN对应例程是10,实际需求可以根据自身的需要进行修改,但是不能超过60,也就是总包长不能大于64.

其余部分

剩下的我觉得没有讲解的必要了,基本都是一些不能动的东西,直接当成黑箱就行,只管用,不管内部的原理

//内部函数
void spi_read(U8 data_length, U8 api_command );						
//读取数据
unsigned char spi_byte(unsigned char data);									
//SPIbyte级别操作?
U8 check_cts(void);																					
//校验SPI通路
void spi_write(unsigned char tx_length, unsigned char *p);	
//spi写入数据
void spi_write_fifo(void);																	
//spi向FIFO写入数据
void spi_read_fifo(void);																		
//spi从FIFO读取数据
void clr_interrupt(void);																		
//清除中断
void fifo_reset(void);																			
//fifo重载入
void enable_tx_interrupt(void);															
//使能4463内部发送中断
void enable_rx_interrupt(void);															
//使能4463内部接受中断

//工作函数
void tx_data(void);																					
//进入发送模式
void tx_start(void);																				
//开始发送

void rx_init(void);																					
//重新进入接受模式
void rx_start(void);																				
//开始接受

//状态改变函数
void rf_standby(void);																			
//进入休眠
void rf_init_freq(void);																		
//?

//模块初始化函数
void port_init(void);																				
//模块IO口初始化
void sdn_reset(void);																				
//4463复位
void SI4463_init(void);																			
//设备初始化
void sdn_all_reset(void);																		
//模块再初始化

//功能函数
void delay_10ms(void);																			
//10ms延时
void delay_x10ms(unsigned int dx10ms);											
//10ms级别延时
void delay_1ms(unsigned int delay_time);										
//毫秒级别延时函数

平台对接

操作其实是很简单的,关键是理解如何使用例程。

第一步-IO口对应

创建一个头文件。写入以下内容

#define   nSEL   				GPIO_Pin_4//GPIOA

#define   SCK   				GPIO_Pin_5//GPIOA 
#define   SDO   				GPIO_Pin_6//GPIOA //out
#define   SDI   				GPIO_Pin_7//GPIOA 

#define   SDN					GPIO_Pin_1//GPIOA 
#define   nIRQ         			GPIO_Pin_0//GPIOA 

#define   nSEL_0				GPIO_ResetBits(GPIOA , nSEL),delay_us(1)
#define   nSEL_1				GPIO_SetBits	(GPIOA , nSEL),delay_us(1)

#define   SDN_0					GPIO_ResetBits(GPIOA , SDN ),delay_us(1)
#define   SDN_1					GPIO_SetBits	(GPIOA , SDN ),delay_us(1)

#define   SCK_0					GPIO_ResetBits(GPIOA , SCK ),delay_us(1)
#define   SCK_1					GPIO_SetBits	(GPIOA , SCK ),delay_us(1)

#define   SDI_0					GPIO_ResetBits(GPIOA , SDI ),delay_us(1)
#define   SDI_1					GPIO_SetBits	(GPIOA , SDI ),delay_us(1)

#define   nIRQr         GPIO_ReadInputDataBit(GPIOA , nIRQ)
#define   SDOr          GPIO_ReadInputDataBit(GPIOA , SDO)

这里的SDI_0和SDI_1对应vc例程里的SDI=0与SDI=1,以此类推
nIRQr对应vc例程里的nIRQ(因为stm32读取IO不是直接读取的)
随后修改关键函数:port_init

//IO function set
void port_init(void)
{
	//GPIO口初始化,nSEL,SDN,nIRQ
	GPIO_InitTypeDef GPIO_InitStructure;
	EXTI_InitTypeDef EXTI_InitStructure; 
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOA, ENABLE );	
 
	GPIO_InitStructure.GPIO_Pin = nSEL ;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	
	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOA, ENABLE );	
	GPIO_InitStructure.GPIO_Pin = SDN ;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
//	
//	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOA, ENABLE );	
//	GPIO_InitStructure.GPIO_Pin = SCK ;
//	GPIO_Init(GPIOA, &GPIO_InitStructure);
//	
//	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOA, ENABLE );	
//	GPIO_InitStructure.GPIO_Pin = SDI ;
//	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE );	
	GPIO_InitStructure.GPIO_Pin = nIRQ  ;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;  		//浮空输入 下拉输入
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	GPIO_ResetBits(GPIOA , nIRQ );
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); //选择EXTI信号源
                                                                                            
	EXTI_InitStructure.EXTI_Line = EXTI_Line0;               //中断线选择
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;      //EXTI为中断模式
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;  //下降沿触发
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;                //使能中断
	EXTI_Init(&EXTI_InitStructure); 

	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	//设置NVIC中断分组2:2位抢占优先级,2位响应优先级

	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;          //中断源:3,位于“stm32f10x.h”中
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级:1
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;        //子优先级:1
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           //使能中断通道
	NVIC_Init(&NVIC_InitStructure);

	
//	
//	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOA, ENABLE );	  //浮空输入
//	GPIO_InitStructure.GPIO_Pin = SDO ;
//	GPIO_Init(GPIOA, &GPIO_InitStructure);

}

/******************************************************************************/
void EXTI0_IRQHandler(void)                       
{
  if(EXTI_GetITStatus(EXTI_Line0)!= RESET)  
  {  
    EXTI_ClearITPendingBit(EXTI_Line0);
		if(nIRQr==0)
			Flag.run=2;
		//Flag.run++;
  }   
}

这里有两种写法一种是硬件spi一种是软件spi,vc的例程是软件spi,因此初步移植的时候可以按着软件spi的写,spi校验通过了,再改成硬件spi。

第二步-启用SPI(如果是软件SPI则忽略这一步)

修改SPI的读写函数

unsigned char spi_byte(unsigned char data)		//核心替换
{
	return SPIx_ReadWriteByte(data);
//	unsigned char i;

//	for (i = 0; i < 8; i++)	
//	{				
//		if (data & 0x80)
//			SDI_1;
//		else
//			SDI_0;
//			
//		data <<= 1;
//		SCK_1;
//		
//		if (SDOr)
//			data |= 0x01;
//		else
//			data &= 0xfe;
//			
//		SCK_0;
//	}	
//	return (data);	
}

配置SPI的初始化和SPI读写函数

SPI_InitTypeDef  SPI_InitStructure;

void SPIx_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
  
	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_SPI1, ENABLE );	
 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);
	
//	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
//	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
//	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
//	GPIO_Init(GPIOB, &GPIO_InitStructure);
//	GPIO_SetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);

	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;		//设置SPI工作模式:设置为主SPI
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;		//设置SPI的数据大小:SPI发送接收8位帧结构
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;		//选择了串行时钟的稳态:时钟悬空高0
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;	//数据捕获于第二个时钟沿1
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;		//NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;		//定义波特率预分频的值:波特率预分频值为256
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;	//指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
	SPI_InitStructure.SPI_CRCPolynomial = 7;	//CRC值计算的多项式
	SPI_Init(SPI1, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
 
	SPI_Cmd(SPI1, ENABLE); //使能SPI外设
//	SPI_Cmd(SPI2, ENABLE); //使能SPI外设
	
//	for(;;)
//	{
//		SPIx_ReadWriteByte(0xff);//启动传输		 
//	}
	
}   
u8 SPIx_ReadWriteByte(u8 TxData)
{		
	u8 retry=0;				 	
	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位
		{
		retry++;
		if(retry>200)return 0;
		}			  
	SPI_I2S_SendData(SPI1, TxData); //通过外设SPIx发送一个数据
	retry=0;

	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET) //检查指定的SPI标志位设置与否:接受缓存非空标志位
		{
		retry++;
		if(retry>200)return 0;
		}	  						    
	return SPI_I2S_ReceiveData(SPI1); //返回通过SPIx最近接收的数据					    
}

第三步-自定义测试函数

//********************************************************
//          测试与调试函数 R
//********************************************************
void read_Version(void)
{
	spi_read(9,0x01);
	for(i=0;i<9;i++)
	{
		printf("%X",spi_read_buf[i]);
	}
	printf("\n");
	delay_ms(500);	
}
void test_Receive2(void)
{
	U8 i;
	if(Flag.run==2)
	{ 
		Flag.run=0;
		clr_interrupt();   					// clear interrupt	
		if((spi_read_buf[4] &0x08) == 0)  // crc error check
		{
			spi_read_fifo();
			fifo_reset();
			m_test.Count2++;
			for(i=4;i<payload_length;i++)
			{
				printf("%X",rx_buf[i]);
			}
			m_time.recevie_Time=GetTickCount();
			printf(",%d,%d,%d\n",m_time.recevie_Time,m_test.Count,m_test.Count2);
			rx_init();   						// rx init
		}
		else
		{
			printf("---------------crc error-------------\n");
			rx_init();   						// crc error
		}		
	}
	i=i;	
}
//********************************************************
//          测试与调试函数 T
//********************************************************
void test_tx_data2()					
{	
	//delay_ms(1);
	Flag.is_tx = 1;
	Flag.run=0;
	fifo_reset();  
	spi_write_fifo(); 		
	enable_tx_interrupt();	
	clr_interrupt();
	tx_start();
	while(Flag.run!=2);					//等待发送成功
	Flag.run=0;	
}

以上函数分别是:测试SPI,持续接受,持续发送

第四步调试模组

主函数:如下

int main(void)
{
	SystemInit();			 //系统时钟初始化
	delay_init(72);	     	 //延时初始化
	NVIC_Configuration();	 //中断组初始化
	TIM_Configuration();     //定时器1生成ms级别时间戳(配置略)
	USART1_Config(); 		 //USART1 配置 	
	SPIx_Init();			 //spi1简单初始化.
	delay_ms(5000);
	SDN_1	;
	printf("int 1 \n");
	port_init();				 //其余IO初始化
	printf("int 2 \n");
	sdn_reset();				 //复位设备
	printf("int 3 \n");
	delay_ms(500);
 	SI4463_init();  		 //RF INIT
	printf("int 4 \n");
	delay_ms(500);
	printf("int finished \n");
	SDN_0	;
	Flag.is_tx=1;	//初始状态为T(此处改为0就是接受方了)
	if(Flag.is_tx==0)
		rx_init();					 //接收模式初始化
	while(1)
	{
		read_Version();  	//读版本号测试
		//--------------------数据收发--------------------
		if(Flag.is_tx)
		{
			test_tx_data2();				//发送
		}
		else
		{
			test_Receive2();				//接受
		}
}

结语

e70_433的开发失败给了我一些感悟:
1,优先研究项目需求
2,积极尝试同类型模块
4463的强劲在我的意料之外,原本还有一款芯片准备顶替4463,但是现现在不需要了。e70的问题就在于长距离传输上和传输协议上,距离差将尽5倍,并且透传模组,协议设计也不方便,4463 自带crc和自行封包解包省去了我自拟协议封装的劳顿,强烈推荐给相关从业人士。
关于本文本来想一口气写完的,但是发现量非常大,因此分两章,本章讲述完毕例程的移植和调试,下一章讲如何实现业务逻辑,会在周末之前发出(绝对不鸽)。
我对模块的研究向来是浅尝辄止,实用为主,如果大家有什么看不明白的地方,或者和自身的了解有冲突,欢迎指正,谢谢。

发布了19 篇原创文章 · 获赞 5 · 访问量 1283

猜你喜欢

转载自blog.csdn.net/ex_xyz/article/details/103660665