- The project needs to add a card reader device without transplanting USB routines. An external chip (CH9350) is directly used, which is very stable without driving;
- I only use one of the functions of this chip: the conversion of HID data from USB to serial port data, the lower computer mode used, and many other functions. See the manual for details. The inconvenient place in the development process is that the output serial port data is added with a protocol, which is not completely transparent. Just analyze the data.
- If the MCU does not have USB peripherals or does not want to use the USB inside the MCU, the relevant USB processing scheme should be found in Nanjing qinheng, and individual chips and test boards can be applied.
- Relevant USB documents can be downloaded from the official website, which is very convenient. Most of the supporting resources of other USB are 51 routines (for the reason of age), anyway c file and modify it in combination with your own environment. It is OK to modify it (it is recommended to open the project with VS Code).
1, Overview
2, Principle circuit
- It requires few peripheral circuits. The lower computer mode I use here only uses one USB (DM\DP),
3, Phenomenon
-
1. I use a random card swiping machine purchased online. To be honest, the card swiping sensitivity is not very high, or the card I use is degaussed.
-
2. CH9350 will frequently send request frame data after power on, and the rate is very fast. Pay attention to turn it off when using. After power on, send the following data frames to stop it.
-
3. The data from swiping the card is as follows, and only a part of it is intercepted (after all, it is a bank card, which should be hidden well to prevent criminals from knowing my card number and want to remit money to me, "=" before is the card number, "=" after that, I guess it is the password through encryption algorithm).
-
The data frames that need to be parsed are the middle part. The rest can be parsed according to the manual. At the beginning, I was still confused. This is not a standard ASCII code. After verification, it is the "USB keyboard common code value table". Once I search online, I will be OK. Later, I will show some of the data frames I use. Just discard some 0x00 received in the red box.
4, Handle
- The main code is the serial port processing part, which is easy to analyze. Let me record how I process this data and precautions:
- 1. Swiping the card once will bring in hundreds of bytes, and these bytes are regular, starting with 0x57, but containing 0x00, so you can't simply use the C library function strtok();
- The data that comes in suddenly after swiping the card has no data frame header (referring to the parsed number 622225210183 ******** and I don't know which is the beginning). Therefore, I use the timeout judgment here as a frame, and empty the parsed receiving buffer after timeout, so as to ensure that the data that comes in each time is all the card numbers and is not stuck or missing from the last time.
- Directly filter out other data in the serial port interrupt, and save the required card number data into the array; The code is as follows. Although there are problems with this filter writing method (0x57 appears twice at the beginning, and this frame of data will be lost), it is easy to save trouble and there is no verification, but the reliability requirement is not high. In case of extreme packet loss, it is OK to swipe the card again.
#define UART4_RxbufSize 128 uint8_t UART4_Rxbuf[UART4_RxbufSize]={0}; //Serial port 4 receive buffer uint8_t UART4_RxbufCount=0; //Serial port 4 receiving buffer data storage location #Redefine / / wait for Rev1 #Define revhead2 / / wait for receiving #Define revhead3 / / wait to receive #Define revhead4 / / wait for receiving #Define revhead5 / / wait to receive #Define revhead6 / / wait to receive #Define revhead7 / / wait to receive #Define revhead8 / / wait to receive uint8_t RevState5=revhead1; // Receiving status uint16_t Uart4TimeOut=0; //Count in the software timer, clear 0 every time the interrupt data is received, and the timeout is judged as one frame uint8_t Uart4GetIDFlag=0; // Serial port interrupt service function void UART4_IRQHandler(void) { uint8_t ucTemp; if(USART_GetFlagStatus(UART4,USART_IT_RXNE)!=RESET)//Non null interrupt { ucTemp = USART_ReceiveData(UART4); //The flag bit is automatically cleared after receiving Uart4TimeOut=0; //Count in software timer Uart4GetIDFlag=0; switch(RevState5) { //Waiting to receive the first synchronization header 0x57 case revhead1: if (ucTemp==0x57) { RevState5=revhead2; } break; //Waiting to receive the second synchronization header 0xAB case revhead2: if (ucTemp==0xAB) { RevState5=revhead3; } else { RevState5=revhead1; //State machine reset } break; //Waiting to receive the third synchronization header 0x88 case revhead3: if (ucTemp==0x88) { RevState5=revhead4; } else { RevState5=revhead1; //State machine reset } break; //Waiting to receive the 4th synchronization header 0x0B case revhead4: if (ucTemp==0x0B) { RevState5=revhead5; } else { RevState5=revhead1; //State machine reset } break; //Waiting to receive the 5th synchronization header 0x10 case revhead5: //The reason for the comment is that it becomes 0x11 when it is inserted into another USB port of CH9350, so it is simply skipped // if (ucTemp==0x10) // { RevState5=revhead6; // } // else // { // RevState5=revhead1; // State machine reset // } break; //Waiting to receive the 6th synchronization header 0x01 case revhead6: if (ucTemp==0x01) { RevState5=revhead7; } else { RevState5=revhead1; //State machine reset } break; //Waiting to receive the 7th synchronization header 0x00 case revhead7: if (ucTemp==0x00) { RevState5=revhead8; } else { RevState5=revhead1; //State machine reset } break; //Waiting to receive the 8th synchronization header 0x00 case revhead8: if (ucTemp==0x00) { RevState5=revpakage; } else { RevState5=revhead1; //State machine reset } break; //Waiting to receive data content case revpakage: if(UART4_RxbufCount<UART4_RxbufSize&&ucTemp!=0) { UART4_Rxbuf[UART4_RxbufCount++]=USBDataToASCII(ucTemp); } RevState5=revhead1; break; default: RevState5=revhead1; //State machine reset break; } } /* Serial port 4 data receiving and processing thread entry function, which is used to process the card reader thread */ void uart4recv_thread_entry(void *parameter) { while(1) { if(Uart4TimeOut>2&&Uart4GetIDFlag==0) { Uart4GetIDFlag=1; //It has timed out. It is judged that one frame has been received memcpy(Vision_t.ID,UART4_Rxbuf,strlen((char*)UART4_Rxbuf)); memset(UART4_Rxbuf,0,UART4_RxbufSize); UART4_RxbufCount=0; } rt_thread_mdelay(50); } }