#C51 serial communication 5-# a string of data # interrupt timing + timeout reception + CRC verification

Catalogue of series articles

Tip: you can add the directories of all articles in the series here. You need to add the directories manually
For example:

Tip: after writing the article, the directory can be generated automatically. For how to generate it, please refer to the help document on the right

preface

Introduction:
1. On the basis of #3 chapter, interrupt timing + timeout reception
2. Add CRC verification method and receive response processing
3. Instruction analysis, control nixie tube + led in the main function

Tip: the following is the main content of this article. The following cases can be used for reference

1, Scene

Example:
The host sends a command, the slave parses and responds, and CRC checks

2, Programming implementation

1. Custom agreement

For example:

addressdata typeData areaCRCLCRCH
0101~03

##1
Data type (function code):
Control nixie tube display 0x01, buzzer control 0x02

##2. Slave handshake response:
b. Address error:

Ignore

a.CRC check is correct:

Full data return
The value in the data area is displayed on the nixie tube, for example, only the maximum two groups are displayed

b.CRC check error:

Address + [data type high position 1] + data area + CRC

2. Code design

Step 1: #C51 serial communication 2-# a string of data # timing interrupt to realize timeout reception (recommended)
Continue to develop based on the sample project to verify the correctness of data sending and receiving.
Step 2: add nixie tube display and led functions
Step 3: verify CRC verification. The example uses CRC16-MODBUS (8005, FFFF,0000)
Attach CRC code (look-up table method):

 unsigned int GetCRC16(unsigned char *puchMsg, unsigned int usDataLen) 
 { 
	unsigned char uchCRCHi = 0xFF ;	//*High CRC byte initialization 
	unsigned char uchCRCLo = 0xFF ;	//*Low CRC byte initialization  
	unsigned long uIndex ;			// Index in CRC cycle 

	 // CRC high byte value table
	unsigned char code auchCRCHi[260] = { 
	0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 
	0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
	0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 
	0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 
	0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 
	0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 
	0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 
	0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
	0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 
	0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 
	0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 
	0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 
	0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 
	0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 
	0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 
	0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 
	0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 
	0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
	0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 
	0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
	0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 
	0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 
	0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 
	0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
	0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 
	0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 
	} ; 
	// CRC low byte value table
	unsigned char code  auchCRCLo[260] = { 
	0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 
	0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 
	0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 
	0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 
	0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 
	0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 
	0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 
	0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 
	0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 
	0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 
	0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 
	0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 
	0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 
	0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 
	0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 
	0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 
	0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 
	0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, 
	0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 
	0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 
	0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 
	0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 
	0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 
	0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, 
	0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 
	0x43, 0x83, 0x41, 0x81, 0x80, 0x40 
	} ;

	while (usDataLen--)               //Transmit message buffer 
	{ 
		uIndex = uchCRCLo ^ *puchMsg++ ; // Calculate CRC  
		uchCRCLo = uchCRCHi ^ auchCRCHi[uIndex] ; 
		uchCRCHi = auchCRCLo[uIndex] ; 
	} 
	return (uchCRCHi << 8 | uchCRCLo);
}

Step 3:
”The "interrupt timing + timeout sending and receiving" code is no longer posted. See basic routine 3 for details#

void uart_ISR() interrupt 4{}
void Timer0_ISR() interrupt 1{}

Step 4:
1. Buffer data CRC verification 2. Verification judgment 3. Receiving response 4. Parsing

if(recv_flag)
	{
		recv_flag = 0;
		timer_start = 0;		//Turn off the timer to prevent T0 from executing all the time
		for (i = 0; i < cRealLen; i++)
		{
			uart_Recv[i] = vbuf[i];
		}

		// 1.CRC verification
		CRC = GetCRC16(uart_Recv, cRealLen-2);	//CRCL/CRCH		
		CRCL = CRC & 0x00FF;
		CRCH = CRC >> 8;
// 2. Verification judgment
		
		if((CRCL == uart_Recv[cRealLen - 2]) && (CRCH == uart_Recv[cRealLen - 1]))
		{
			sendData(uart_Recv,cRealLen);	//@@@@Discard and use sendString(), otherwise it will stop when it meets 0, including 0 of the check code@@@@
			if(0x01 != uart_Recv[0])		//If the address is correct, execute the command, otherwise it will not respond
			{
				;
			}
			else
			{
				Exchange_Func();
				fLedShine = 1;
			}
		}
		else										//3. Verification error, data type high position 1, return the whole data
		{
			uart_Recv[1] |= 0x80;								
			CRC = GetCRC16(uart_Recv, cRealLen-2);	//CRCL/CRCH 	
			CRCL = CRC & 0x00FF;
			CRCH = CRC >> 8;
			uart_Recv[cRealLen - 2] = CRCL;
			uart_Recv[cRealLen - 1] = CRCH;
			sendData(uart_Recv,cRealLen);
		}		
//		sendString(vbuf); //test
//		sendString(uart_Recv);
		clr_recvbuffer(vbuf);		
	}
void Exchange_Func(void)
{
	if(0x01 == uart_Recv[0])		//For demonstration only, data type 01 controls nixie tube display
	{
		
		switch(uart_Recv[1])		//The data length represents the number of digits displayed
		{
			case 1:
				SEG_DisBuf[0] = 23;
				SEG_DisBuf[1] = 23; 		
				SEG_DisBuf[2] = uart_Recv[2] >> 4;
				SEG_DisBuf[3] = uart_Recv[2] & 0x0F;
				break;
			case 2:
				SEG_DisBuf[0] = uart_Recv[2] >> 4;
				SEG_DisBuf[1] = uart_Recv[2] & 0x0F; 	
				SEG_DisBuf[2] = uart_Recv[3] >> 4;
				SEG_DisBuf[3] = uart_Recv[3] & 0x0F;
				break;
			case 3:
				break;
			default:break;
		}
	}

3. Test verification

@1 correct response:
@2 verification error response
@3 data length change

summary

1. Nixie tube dynamic scanning in T0 timing interrupt, priority processing of shadow elimination, WX_DIS = 0xFF, swith / case statement is used for the test.
2. The number of nixie tubes * scanning interval shall be controlled within 10ms, and the display processing function shall be placed in T0 timing interrupt service function. Therefore, ms level delay shall not be made. Time difference will cause serial port data error
3. modular design, calling after testing.
If the code CRC found on the Internet is wrong in the actual high and low positions, printf() can be used to print the results on the serial port to observe the problem.

Previous chapter: #C51 serial communication 4-# a string of data # interrupt real-time analysis user-defined protocol (handshake receiving response)

Keywords: C Single-Chip Microcomputer

Added by marukochan on Sun, 05 Dec 2021 01:16:35 +0200