Complete 485 line of code and data backhaul, and CRC check

Disclaimer: This article is a blogger original article, shall not be reproduced without the bloggers allowed. https://blog.csdn.net/switch_love_case/article/details/88606874

title: a line of code to complete the 485 communications and data backhaul, and CRC check
Tags: the STM32
DATE: 2019-03-16 21:10:00


Because of the need, I carry on the existing 485 communication a summary, but also contains a number of algorithms to quickly achieve their original and 485 CRC checksum, and the processing of the return value


Facie effect: This method may use a line of code is completed, but also to send and receive 485 includes CRC16Modbus check!


  • RS485 communication

I personally think that 485 is just a rule of protocol only, you can now know how to use, I will not be here long on broad principles to explain, after all, I do not know, you do not know, as a direct combat, to open out!
And from the microcontroller perspective, is 485 serial communication, plus a serial converter module only, so long as the serial port to handle it.


  1. First, look at the serial processing method

I tried a lot of methods and found that now use is the most convenient one.

The first is the establishment of structures for data storage.

/*
初始化串口 
*/
//定义结构体用来存储接收数据
typedef struct {
    u8 USART_BUFF[100];
	  unsigned short RxBuf[100];
    int USART_Length;
    int flag;
}Usart_Struct;

Usart_Struct struct_usart2;

Second is to initialize the hardware configuration (see negligible)

void usart2_init(u32 band)
{
	//GPIO端口设置
  GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	 
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);	//使能USART2
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//  
	
	//重新定义管脚
	//GPIO_PinRemapConfig(GPIO_Remap_USART2,ENABLE);
	//USART2_TX    
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; // 引脚不能更改
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化 
   
  //USART2_RX	   
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA 
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化   

  //Usart NVIC 配置
  NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级3 原3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3     原2
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
  
   //USART 初始化设置

	USART_InitStructure.USART_BaudRate = band;//串口波特率
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式

  USART_Init(USART2, &USART_InitStructure); //初始化串口2
  USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启串口接受中断
  USART_Cmd(USART2, ENABLE);                    //使能串口2
}

Then important that the serial terminal function

/*
串口2中断函数
*/
void USART2_IRQHandler(void)                	//串口2中断服务程序
	{
	 u8 ch; 
    if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET) //接收到数据
    {
        USART_ClearITPendingBit(USART2,USART_IT_RXNE);
        ch = (u8)USART_ReceiveData(USART2);
        struct_usart2.USART_BUFF[struct_usart2.USART_Length++] = ch;
        struct_usart2.flag = 1;
    }
    if( USART_GetITStatus( USART2, USART_IT_IDLE ) == SET )
    {
        USART_ClearITPendingBit(USART2,USART_IT_IDLE);
        struct_usart2.flag = 1;
        ch = (u8)USART_ReceiveData(USART2);
    } 
 }

Explanation: The effect here is that the data can be quickly processed while the data cache to the structure than those two


The most important thing is to send a comprehensive command and data handling functions return of! ! !

/***********************************************************
函数名称:int RS485_SendCmd(u8 *cmd,u8 len,int x,int wait)
函数功能:RS485问询与返回指令
入口参数:cmd:问询指令
         len:数据长度
           x:数据起始位
        wait:问询延时
出口参数:数据点
备 注:
***********************************************************/
 
int RS485_SendCmd(u8 *cmd,u8 len,int x,int wait)
{   
  int Val = 0; 
	int i;
	unsigned short CRC_Tmp;
	unsigned short crc;
  struct_usart2.USART_Length = 0;
  printf("[RS485_SendCmd] %s\r\n","OK");
  uart2_send_buff(cmd, len);
  delay_ms(wait);
  if (struct_usart2.USART_Length != 0) //返回值不为空
  {			
      //for(i=0;i<len+1;i++)  //打印出来接收的包共9个数据
      //{
      //printf("%X@",struct_usart2.USART_BUFF[i]);	
      //}	
      //printf("%d",struct_usart2.USART_Length);			
			crc = ((unsigned short)struct_usart2.USART_BUFF[struct_usart2.USART_Length-2]<<8) + struct_usart2.USART_BUFF[struct_usart2.USART_Length-1]; //收到数据的crc校验值
			CRC_Tmp = CRC_16_HEX(struct_usart2.USART_BUFF,struct_usart2.USART_Length-2); //处理除去最后两位的数据CRC校验,算出crc校验值
			//printf("%X\r\n",crc);
			//printf("%X\r\n",CRC_Tmp);
			if (CRC_Tmp == crc){   //比较CRC校验值是否相等,相等则进行下一步处理
      Val = (struct_usart2.USART_BUFF[x]*256) + (struct_usart2.USART_BUFF[x+1]*1);
			struct_usart2.USART_BUFF[struct_usart2.USART_Length] = '\0'; //清零
			return Val;
			}
			struct_usart2.USART_BUFF[struct_usart2.USART_Length] = '\0'; //清零	
			return Val;
    }  
}

Explanation: The ultimate esoteric here is that a function can complete the data transmission and reception and verification!
Analysis Principle: After the device 485 queries the serial data will enter the reception serial port receive interrupt, received data is stored while the structure, and two CRC check determines whether the data is equal to the return value returned after removal, If you meet the CRC, it is recognized as normal data. Next, the NB may be configured to send.

Source acquired by the blog home page Github
QQ group: 476 840 321

Guess you like

Origin blog.csdn.net/switch_love_case/article/details/88606874