QT连载4:基于QT和STM32H750的LORA试验平台(3)

前言

    前面已经介绍了QT的制作,包含收发和配置三部分。下面介绍STM32H750的程序架构。

    先将程序的架构大致分为3个部分:

    第一部分:根据收发机制,H750接收串口(暂时这样叫,这样好区分)将QT发送的数据接收,去除报头,提取数据,然后通过发送串口1发送给LORA1。

    第二部分:LORA1发送后,LORA2接收,通过LORA2的接收串口,将数据保存。

    第三部分:将LORA2接收的数据加入报头,通过LORA2的发送串口传递给QT,之后再QT中显示。

    由于QT部分已经在上节中已经详细介绍,现介绍除了QT的剩下部分。

第一部分:初始化

UART_HandleTypeDef UART1_Handler; //UART¾ä±ú
DMA_HandleTypeDef  UART1TxDMA_Handler;      //DMA¾ä±ú

void UART1_Init(u32 bound)
{	
	//UART ³õʼ»¯ÉèÖÃ
	UART1_Handler.Instance=USART1;					    //USART1
	UART1_Handler.Init.BaudRate=bound;				    //²¨ÌØÂÊ
	UART1_Handler.Init.WordLength=UART_WORDLENGTH_8B;   //×Ö³¤Îª8λÊý¾Ý¸ñʽ
	UART1_Handler.Init.StopBits=UART_STOPBITS_1;	    //Ò»¸öֹͣλ
	UART1_Handler.Init.Parity=UART_PARITY_NONE;		    //ÎÞÆæżУÑéλ
	UART1_Handler.Init.HwFlowCtl=UART_HWCONTROL_NONE;   //ÎÞÓ²¼þÁ÷¿Ø
	UART1_Handler.Init.Mode=UART_MODE_TX_RX;		    //ÊÕ·¢Ä£Ê½
	HAL_UART_Init(&UART1_Handler);					    //HAL_UART_Init()»áʹÄÜUART1
	
	HAL_UART_Receive_IT(&UART1_Handler, (u8 *)aRxBuffer, RXBUFFERSIZE);
}

    一块一块解释:

    定义串口中断,定义发送DMA中断;

    串口初始化函数

    中间部分为串口的定义:串口1、波特率等等,这部分可以不用改

    最后一句:将接收中断的数据放进buffer里面,定义buffer数,这里定义为1个。

void MYDMA1_Config(void)
{ 
    __HAL_RCC_DMA2_CLK_ENABLE();//DMA2ʱÖÓʹÄÜ	
    __HAL_LINKDMA(&UART1_Handler,hdmatx,UART1TxDMA_Handler);    
    
    UART1TxDMA_Handler.Instance=DMA2_Stream5;                            //Êý¾ÝÁ÷Ñ¡Ôñ
	UART1TxDMA_Handler.Init.Request=DMA_REQUEST_USART1_TX;			//USART1·¢ËÍDMA
    UART1TxDMA_Handler.Init.Direction=DMA_MEMORY_TO_PERIPH;             //´æ´¢Æ÷µ½ÍâÉè
    UART1TxDMA_Handler.Init.PeriphInc=DMA_PINC_DISABLE;                 //ÍâÉè·ÇÔöÁ¿Ä£Ê½
    UART1TxDMA_Handler.Init.MemInc=DMA_MINC_ENABLE;                     //´æ´¢Æ÷ÔöÁ¿Ä£Ê½
    UART1TxDMA_Handler.Init.PeriphDataAlignment=DMA_PDATAALIGN_BYTE;   
    UART1TxDMA_Handler.Init.MemDataAlignment=DMA_MDATAALIGN_BYTE;      
    UART1TxDMA_Handler.Init.Mode=DMA_NORMAL;                            //ÍâÉèÁ÷¿Øģʽ
    UART1TxDMA_Handler.Init.Priority=DMA_PRIORITY_MEDIUM;               //ÖеÈÓÅÏȼ¶
    UART1TxDMA_Handler.Init.FIFOMode=DMA_FIFOMODE_DISABLE;              
    UART1TxDMA_Handler.Init.FIFOThreshold=DMA_FIFO_THRESHOLD_FULL;      
    UART1TxDMA_Handler.Init.MemBurst=DMA_MBURST_SINGLE;                
    UART1TxDMA_Handler.Init.PeriphBurst=DMA_PBURST_SINGLE;            
    
    HAL_DMA_DeInit(&UART1TxDMA_Handler);   
    HAL_DMA_Init(&UART1TxDMA_Handler);
} 
 
void DMA2_Stream5_IRQHandler(void)
{
  HAL_DMA_IRQHandler(&UART1TxDMA_Handler);

}
void USART1_IRQHandler(void)                	
{ 
	HAL_UART_IRQHandler(&UART1_Handler);	//µ÷ÓÃHAL¿âÖжϴ¦Àí¹«Óú¯Êý

} 

    此处为定义DMA初始化,DMA中断入口,没有中断处理函数。串口1中断入口。

void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
	GPIO_InitTypeDef GPIO_Initure;

	if(huart->Instance==USART1)//Èç¹ûÊÇ´®¿Ú1£¬½øÐд®¿Ú1 MSP³õʼ»¯
	{
		__HAL_RCC_GPIOA_CLK_ENABLE();			//ʹÄÜGPIOAʱÖÓ
		__HAL_RCC_USART1_CLK_ENABLE();			//ʹÄÜUSART1ʱÖÓ
	
		GPIO_Initure.Pin=GPIO_PIN_9;			//PA9
		GPIO_Initure.Mode=GPIO_MODE_AF_PP;		//¸´ÓÃÍÆÍìÊä³ö
		GPIO_Initure.Pull=GPIO_PULLUP;			//ÉÏÀ­
		GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;//¸ßËÙ
		GPIO_Initure.Alternate=GPIO_AF7_USART1;	//¸´ÓÃΪUSART1
		HAL_GPIO_Init(GPIOA,&GPIO_Initure);	   	//³õʼ»¯PA9

		GPIO_Initure.Pin=GPIO_PIN_10;			//PA10
		HAL_GPIO_Init(GPIOA,&GPIO_Initure);	   	//³õʼ»¯PA10
		
		HAL_NVIC_EnableIRQ(USART1_IRQn);				//ʹÄÜUSART1ÖжÏͨµÀ
		HAL_NVIC_SetPriority(USART1_IRQn,3,3);			//ÇÀÕ¼ÓÅÏȼ¶3£¬×ÓÓÅÏȼ¶3	
		
		HAL_NVIC_SetPriority(DMA2_Stream5_IRQn, 3, 4);
        HAL_NVIC_EnableIRQ(DMA2_Stream5_IRQn);
	}
}

    此处为串口初始化自动调用函数,如果定义串口1,那么会直接调用这个函数,里面定义管脚类型,中断类型,以及绑定串口和DMA。

第二部分:中断函数

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance==USART1)//Èç¹ûÊÇ´®¿Ú1
	{
		
		HostSpareSetData();
		
    HAL_UART_Receive_IT(&UART1_Handler, (u8 *)aRxBuffer, RXBUFFERSIZE);
	}
}

    此处为串口接收中断。并配合HostSpareSetData()函数使用。

void HostSpareSetData(void)                  
{
		nSciaRxBuffer[nSciaRxBufHead]=aRxBuffer[0];
		nSciaRxBufHead++;
		if(nSciaRxBufHead>=SCIA_RX_BUF_SIZE)	nSciaRxBufHead=0;
		if(nSciaRxBufHead==nSciaRxBufTail)
		{
			nSciaRxBufTail++;
			if(nSciaRxBufTail>=SCIA_RX_BUF_SIZE)	nSciaRxBufTail=0;
		}
}

    此函数为串口有数据后,进入中断,将中断数据的buffer内容放进一个fifo里面。然后再解析fifo。

第三部分:while执行

void HostSpareSetDataDeal(void)
{
	int i=0;
	nSciaRxLengthTemp = nSciaRxBufHead - nSciaRxBufTail;
	if( nSciaRxLengthTemp < 0 ) nSciaRxLengthTemp = nSciaRxLengthTemp+ SCIA_RX_BUF_SIZE;
	
	switch( nSciaRxCtrlMode )
	{
		case MODE_SCIARXCMD_WAIT:
			nSciaRxVerify = 0xFFFF;							
			if( nSciaRxLengthTemp >= 8 )
			{
				nSciaRxHeadCheck = SciaRdCharRxBuff(); 		
				if( nSciaRxHeadCheck == 0x03 )      
				{
          nSciaRxCtrlMode = MODE_SCIARX_LORA1;
				}
				if( nSciaRxHeadCheck == 0x04 )      
				{
          nSciaRxCtrlMode = MODE_SCIARX_LORA2;
				}				
			}
		break;
		case MODE_SCIARX_LORA1:					
			  nSciaRxOrder = SciaRdCharRxBuff();
				if( nSciaRxOrder == 0x06 )      
				{
          nSciaRxCtrlMode = MODE_SCIARX_LORA1_INIT;
				}
				if( nSciaRxOrder == 0x10 )      
				{
					nSciaRxID = SciaRdWordRxBuff();	
		      nSciaRxDataLength = SciaRdWordRxBuff();
          nSciaRxCtrlMode = MODE_SCIARX_LORA1_SEND;
				}	
		break;			
		case MODE_SCIARX_LORA2:					
			  nSciaRxOrder = SciaRdCharRxBuff();
				if( nSciaRxOrder == 0x06 )      
				{
          nSciaRxCtrlMode = MODE_SCIARX_LORA2_INIT;
				}
				if( nSciaRxOrder == 0x10 )      
				{
					nSciaRxID = SciaRdWordRxBuff();	
		      nSciaRxDataLength = SciaRdWordRxBuff();
          nSciaRxCtrlMode = MODE_SCIARX_LORA2_SEND;
				}	
		break;		
}	

    此部分在while里面执行,具体流程为:中断里放数,这里解析数据。其中03和04代表不同的LORA发送的数据。具体可以看前面文章的通讯协议。当解析完数据后,再添加对应的case,就可以处理不同的数据了。

		case MODE_SCIARX_LORA1_SEND:
			  if( nSciaRxLengthTemp >= (nSciaRxDataLength+2) )
			  {
					for(i=0;i<nSciaRxDataLength;i++)
					{
					  nSciaRxData[i+3] = SciaRdCharRxBuff();
					}
					nSciaRxVerifyTemp = nSciaRxVerify;
				  nSciaRxCheck = SciaRdWordRxBuff();
				  nSciaRxVerifyTemp = HLChange(nSciaRxVerifyTemp);
				  if(nSciaRxVerifyTemp == nSciaRxCheck)
				  {
						nSciaRxData[0] = 0x5A;
						nSciaRxData[1] = 0xA5;
						nSciaRxData[2] = nSciaRxDataLength;
						
						nSciaTxVerify = 0xFFFF;		
						for(i=0;i<nSciaRxDataLength+3;i++)
						{
						  nSciaTxVerify = GetCRC16(nSciaRxData[i], nSciaTxVerify); 
						}		
						nSciaRxData[nSciaRxDataLength+3] = nSciaTxVerify&0x00FF;		
						nSciaRxData[nSciaRxDataLength+4] = (nSciaTxVerify&0xFF00)>>8;
						
						HAL_UART_Transmit_DMA(&UART7_Handler,nSciaRxData,nSciaRxDataLength+5);						
					}
					nSciaRxCtrlMode = MODE_SCIARXCMD_WAIT;
				}
		break;			
		case MODE_SCIARX_LORA2_SEND:					
			  if( nSciaRxLengthTemp >= (nSciaRxDataLength+2) )
			  {
					for(i=0;i<nSciaRxDataLength;i++)
					{
					  nSciaRxData[i+3] = SciaRdCharRxBuff();
					}
					nSciaRxVerifyTemp = nSciaRxVerify;
				  nSciaRxCheck = SciaRdWordRxBuff();
				  nSciaRxVerifyTemp = HLChange(nSciaRxVerifyTemp);
				  if(nSciaRxVerifyTemp == nSciaRxCheck)
				  {
						nSciaRxData[0] = 0x5A;
						nSciaRxData[1] = 0xA5;
						nSciaRxData[2] = nSciaRxDataLength;
						
						nSciaTxVerify = 0xFFFF;		
						for(i=0;i<nSciaRxDataLength+3;i++)
						{
						  nSciaTxVerify = GetCRC16(nSciaRxData[i], nSciaTxVerify); 
						}		
						nSciaRxData[nSciaRxDataLength+3] = nSciaTxVerify&0x00FF;		
						nSciaRxData[nSciaRxDataLength+4] = (nSciaTxVerify&0xFF00)>>8;
						
						
						HAL_UART_Transmit_DMA(&UART4_Handler,nSciaRxData,nSciaRxDataLength+5);						
					}
					nSciaRxCtrlMode = MODE_SCIARXCMD_WAIT;
				}
		break;

    此处就为添加的case,当前面解析的数据解析之后,就可以进入这个case了,也就是进入这个状态机了。进入后,处理数据,然后发送对应发送数据。

HAL_UART_Transmit_DMA(&UART4_Handler,nSciaRxData,nSciaRxDataLength+5);这个就为发送函数。

第四部分:总结

    发送函数比较简单,就上面最后一句话,将数据放好,长度放好,串口中断入口选好,就可以直接发送了。

    接收函数比较麻烦。步骤是在中断里将接收数据放进buffer,再放进fifo,然后循环里解析数据,然后进行一步一步的跳转。这样就将数据解析并按照逻辑发送该发送的数据了。

    上述程序仅仅是截取了一部分,但是大部分逻辑都在,放进去添加相关定义,就能正确运行了。如果需要源代码的话,可以扫描下面订阅号,届时我会把完整的代码放到里面,如果有什么问题也可以留言,到时候会耐心解释。

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值