Stm32下的激光传输数据

做出来没有什么实际用途数据,传输速率不快..不过能够学到很多东西

Stm32下的激光传输数据_第1张图片


原理

将数据使用Biphase mark coding(BMC)加码, 激光亮代表1灭代表0,使用接受器接收激光并解码


什么是BMC?

BMC是一种数据加码方式,有两种状态:

1.全周期固定反转,0变1,1变0

2.半周期基于数据反转,0不反转,1反转

看下图应该会明白(图片来自维基百科)

Stm32下的激光传输数据_第2张图片

不懂的带你走一下..

请看图片中的Encoded(BMC)这行

最开始的反转是全周期,全周期固定反转,0变1(它上面画的是中位,其实应该是低位)

之后是半周期,半周期按照数据反转,数据第一位是1,所以要反转

之后全周期,固定反转,低位变高位--第一bit的数据已经传输完毕

然后到了半周期,数据是0,不反转,保持高位

之后全周期,固定反转,高变低

....于是就有了上面那个图


具体介绍可以到维基百科看一下

http://en.wikipedia.org/wiki/Differential_Manchester_encoding


解码

激光可以传输数据,我们就可以用接收器分析并且解码

将D0与Tim3链接,设置触发为TIM_ICPolarity_BothEdge(上升沿和下降沿),这样每次触发就会读到这次触发和上次触发的时差

比如上面图的度数就会类似于

0.5 0.5 1 1 0.5 0.5 0.5 0.5 1 0.5 0.5 1 1 0.5 0.5,

数值的大小基于你tim3的频率,数值代表上一次触发和这一次触发tim3走过了多少tick,我在实验中半周期的度数是300tick左右,全周期大概在600tick左右


需要注意的是,不能够直接在激光中传输原始数据,因为解码程序不知道那里是开始与结束

所以这里用了按字节传输的方法,将数据用汉明加密,并且在每字节前面加上11,后面加上0

比如传入字节是0xff

汉明加密后变为两字节:

ffff --也就是 1111,1111, 1111,1111

然后在每字节前面和后面加上修饰位11和0,便成了

11,1111,1111,0     11,1111,1111,0

一个11,dddd,ddddd,0的组合是一个码块,可解码出4位原始数据

这样我们按照每个码块来传输,如果出现了错误,我们也可以知道下一个码块从哪里开始


关于汉明加密

汉明加密可以给予数据自我恢复的能力,这里使用的是8,4加密法, 4bit数据加密后将变为8bit

如果这8bit中有一位在传输过程中由于错误反转,在解码的时候也可以找出错误位并纠正

但是多余1位的错误是无法纠正的(不过几率很小)

具体请看wiki

http://en.wikipedia.org/wiki/Hamming_code

没接触过的可以看下这个图(图片来自维基百科)

Stm32下的激光传输数据_第3张图片

d1到d4代表数据位,是原始的数据

p1到p4是校验位,根据原始数据算出的

如何算呢?看图可知,

p1 = d1^d2^d4

p2 = d1^d4^d3

p3 = d2^d3^d4

p4 = p1^p2^p3^d1^d2^d3^d4 也就是一个奇偶校验位

加密后,如果这8位其中任意一位反转,你都可以计算出反转位哪里(自我恢复能力).


实现

需要注意的是,真实读出来的时差并不是十分准确,不会像这样:

300,300,600,600,300

因为激光每次发光会有一个冲能时间,在冲能时间里,光缓慢变亮,只有亮到一定程度后才能够被捕获

看下图:

Stm32下的激光传输数据_第4张图片


由于激光会冲能,高位的时候会有延迟,频率越高越干扰明显

红色的是读数半周期有: 30 110 40 110

全周期有 125 150

于是我们定义一个界限, 小与117的为半周期,大于117的为全周期

如果能够吧接受器灵敏度调高一些,这样的情况会有缓解


附上部分解码部分初始化和实现代码:

void hwInit_D0Tim3(){
	

	GPIO_InitTypeDef GPIO_InitStructure;

	TIM_ICInitTypeDef  TIM_ICInitStructure;

	NVIC_InitTypeDef   NVIC_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;


	uint16_t PrescalerValue = 0;



  	/* TIM3 clock enable */

  	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);



  	/* Enable the D0 Clock */

  	RCC_AHB1PeriphClockCmd(NP2_D0_GPIO_CLK, ENABLE);



  	/* Configure the D0 pin */

  	GPIO_InitStructure.GPIO_Pin = NP2_D0_PIN;

  	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

  	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

  	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

  	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;

  	GPIO_Init(NP2_D0_GPIO_PORT, &GPIO_InitStructure); 

  

  	/* Connect TIM3 output to D0 pin */  

  	GPIO_PinAFConfig(NP2_D0_GPIO_PORT, NP2_D0_PINSOURCE, GPIO_AF_TIM3);


	//--Compute the prescaler value

  	PrescalerValue = (uint16_t) ((SystemCoreClock /2)/TIM3_PRESCALER) - 1;

  	//--Time base configuration

  	TIM_TimeBaseStructure.TIM_Period = TIM3_PERIOD;

  	TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue;

  	TIM_TimeBaseStructure.TIM_ClockDivision = 0;

  	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

  	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);


	// Configure TIM3 Input capture for channel 2

  	TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;

  	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_BothEdge;

  	TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;

  	TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;

  	TIM_ICInitStructure.TIM_ICFilter = 0x0;



	TIM_ICInit(TIM3, &TIM_ICInitStructure);


	TIM_UpdateRequestConfig(TIM3,TIM_UpdateSource_Regular);

	// Select the TIM3 Filter Input Trigger: TI2FP2

  	TIM_SelectInputTrigger(TIM3, TIM_TS_TI2FP2);



	/* Enable the TIM3 global Interrupt */

  	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;

  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;

  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  	NVIC_Init(&NVIC_InitStructure);



  	/* Select the slave Mode: Reset Mode */

  	TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);

  	TIM_SelectMasterSlaveMode(TIM3,TIM_MasterSlaveMode_Enable);



  	/* Enable the CC2 Interrupt Request */

  	TIM_ITConfig(TIM3, TIM_IT_CC2, ENABLE);

	//enable overflow flag
	//TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); 


	//clear overflow flag
	TIM_ClearFlag(TIM3, TIM_FLAG_Update);
  
	//disable arp preload 
	//TIM_ARRPreloadConfig(TIM3, DISABLE); 


  	/* TIM3 enable counter */

 	TIM_Cmd(TIM3, ENABLE); 
}

void TIM3_IRQHandler(void) {

//bug: if data is continuous (without idle time) then any error will lead to infinate wait state

	uint16_t read_value;



	if (TIM_GetITStatus(TIM3, TIM_IT_CC2) != RESET) {

    		TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);
		laser_recv_ttl = 10;
		read_value = TIM_GetCapture2(TIM3);
		//debug_printf("readval = %d\r\n", read_value);

		if (  TIM_GetFlagStatus(TIM3,TIM_FLAG_Update) == SET || read_value > full_idle_gate ){
			//overflow or idle end state, reset counter..
			TIM_ClearFlag(TIM3,TIM_FLAG_Update);
			read_enc_hchar = 0;
			//hbyte_counter = 0;
			rx_bit_counter = 0;
			last_state = PERIOD_FULL;
			//debug_printf("idle end\r\n");
			return;//idle end
		}

		if ( last_state == PERIOD_FULL ){

			if ( read_value < half_full_gate ){
				//last state is full, interval is half, this state is half, read 1
				rx_bit_counter++;
				if ( rx_bit_counter != 1 && rx_bit_counter != 2 && rx_bit_counter != 11 ){
					read_enc_hchar = read_enc_hchar << 1;
					read_enc_hchar |= 1;
					//debug_printf("read 1 at half state, last is full\r\n");
				}else if ( rx_bit_counter == 11 ){
					//11th bit should be 0, error occurs, wait for another block
					last_state = PERIOD_WAIT;
					debug_printf("error :bit 11 is 1 \r\n");
					return;//error
				}
				last_state = PERIOD_HALF;

				
			}else{
				//last state is full, interval is full, this state is full, read 0
				rx_bit_counter++;
				if ( rx_bit_counter != 1 && rx_bit_counter != 2 && rx_bit_counter != 11 ){
					//read 0
					read_enc_hchar = read_enc_hchar << 1;
					//debug_printf("read 0 at full state, last is full \r\n");
				}else if ( rx_bit_counter == 1 || rx_bit_counter == 2 ) {
					//1st and 2nd bit should be 1, error occurs, wait for another block
					debug_printf("error :bit 1 or 2 is 0 \r\n");
					last_state = PERIOD_WAIT;
					return;//error
				}
				last_state = PERIOD_FULL;

				//this state is full and reads 0, lets check the bit counter
				if ( rx_bit_counter == 11 ){
					//out put result
					hbyte_push( read_enc_hchar );
					//debug_printf("out halfbit at full state \r\n");
					//clear counter and read_enc_hchar
					read_enc_hchar = 0;
					rx_bit_counter = 0;
				}
			}

		}else if ( last_state == PERIOD_HALF ){
			//last state is half, interval must be half, this state must be full, read nothing.
			if ( read_value < half_full_gate ){
				//interval is half
				last_state = PERIOD_FULL;
				//debug_printf("last is half, this is full \r\n");
				//last state read 1, this state is full, but last bit must be 0, don't check the bit counter
				//if ( rx_bit_counter == 11 ){
				//	//out put result
				//	hbyte_push( hamming_hbyte_decoder(read_enc_hchar) );
				//	//clear counter and read_enc_hchar
				//	read_enc_hchar = 0;
				//	rx_bit_counter = 0;
				//}
			}else{
				//some thing is wrong..wait for next block
				last_state = PERIOD_WAIT;
				debug_printf("err:last half this read whole period \r\n");
				return;//error
			}
		}else{
			//wait state do nothing
			//debug_printf("wait/....\r\n");
			return;//error
		}
		




	}

}



你可能感兴趣的:(嵌入式)