USB(CH9350)使用笔记-HID设备刷卡机

  • 项目需求添加个刷卡机设备,没有移植USB例程,直接使用了一个外置芯片(CH9350),无需驱动还是挺稳定的;
  • 这个芯片我只使用了其中的一个功能:USB的HID数据转为串口数据,使用的下位机模式,还有许多其他功能具体看手册,开发过程中不太方便的地方是输出的串口数据加了协议,并不是完全的透传,出来的数据解析一下就行。
  • 如果MCU内部不具备USB外设,或不想使用MCU内部的USB,相关USB的处理方案在 南京沁恒 应该都能找到,个别芯片还有测试板可以申请。
  • 相关USB的文档去官网下载就行,非常方便,其他USB的配套资源大部分是51例程(年限原因吧),反正都是.c文件,结合自己的环境修改修改就OK(推荐VS Code打开工程)。

一、概述

在这里插入图片描述
在这里插入图片描述

二、原理电路

  • 需要很少的外围电路,我这里使用的下位机模式,也只使用一个USB即可(DM\DP),
    在这里插入图片描述
    在这里插入图片描述

三、现象

  • 1、使用的是网购的随机一款刷卡机,说实话刷卡灵敏度不是很高,也可能是我用的卡消磁了。
    在这里插入图片描述

  • 2、CH9350上电后会频繁的发出请求帧数据,而且速率很快,使用的时候注意关掉,上电后发送一次如下数据帧就能让其停止。
    在这里插入图片描述

  • 3、刷卡出来的数据如下,只截取了一部分(毕竟是张银行卡,该隐藏得隐藏好,避免不法之徒知道我的卡号想给我汇款罒ω罒,“=”之前是卡号,“=”之后我个人猜是经过加密算法的密码)。

  • 需要解析的数据帧就是中间的部分,其余的根据手册想解析就解析吧,刚开始还比较疑惑,这也不是标准的ASCII码,经过查验是“USB键盘常用码值表”,网上一搜就OK,后面我会展示出我用的一部分,红框中收到的一些0x00这个直接舍弃就行。
    在这里插入图片描述

在这里插入图片描述

四、处理

  • 主要代码就是串口处理的部分,这个很容易解析,我就记录一下这种数据我是怎么处理的吧以及注意事项:
  • 1、刷一次卡会进来上百个字节,而且这些字节是有规律的,都是0x57开头,但其中包含0x00,因此就不能简单的使用C库函数strtok()进行分割;
  • 这种刷卡后突然进来的数据,是没有数据帧头的(指解析后的数字62225210183*******,不知道哪个是开头),因此我这里使用的是超时判断为一帧,超时后清空解析的接收缓冲区,这样就能保证每次进来的数据是全部的卡号,没有与上次黏连或缺失。
  • 串口中断中直接过滤掉其他数据,将需要的卡号数据存到数组中;代码如下,虽然这种过滤写法存在问题(开头出现两次0x57,这帧数据就会被丢掉),图省事也没加校验,但这个可靠度要求不高,在极端丢包情况下,重新刷一次卡就OK。
#define UART4_RxbufSize 128
uint8_t UART4_Rxbuf[UART4_RxbufSize]={0};		//串口4接收缓冲区
uint8_t UART4_RxbufCount=0;  					//串口4接收缓冲区数据存放位置

#define revhead1     1          //等待接收
#define revhead2     2          //等待接收
#define revhead3     3          //等待接收
#define revhead4     4          //等待接收
#define revhead5     5          //等待接收
#define revhead6     6          //等待接收
#define revhead7     7          //等待接收
#define revhead8     8          //等待接收

uint8_t RevState5=revhead1;         	// 接收状态
uint16_t Uart4TimeOut=0;				//在软件定时器中计数,每次接收到中断数据就清0,超时判断为一帧
uint8_t Uart4GetIDFlag=0;


// 串口中断服务函数
void UART4_IRQHandler(void)
{
  	uint8_t ucTemp;
	if(USART_GetFlagStatus(UART4,USART_IT_RXNE)!=RESET)//非空中断
	{		
			ucTemp = USART_ReceiveData(UART4);		//接收完毕自动清除标志位
			Uart4TimeOut=0;							//软件定时器中计数
			Uart4GetIDFlag=0;
			switch(RevState5)
			{
				//等待接收第一个同步头0x57
				case  revhead1:
						if (ucTemp==0x57)
						{
							RevState5=revhead2;
						}
				break;
				//等待接收第二个同步头0xAB
				case  revhead2:
						if (ucTemp==0xAB)
						{
								RevState5=revhead3;
						}
						else
						{
								RevState5=revhead1;      //状态机复位
						}
						break;   
				//等待接收第三个同步头0x88
				case  revhead3:
						if (ucTemp==0x88)
						{
								RevState5=revhead4;
						}
						else
						{
								RevState5=revhead1;      //状态机复位
						}
						break; 
				//等待接收第4个同步头0x0B
				case  revhead4:
						if (ucTemp==0x0B)
						{
								RevState5=revhead5;
						}
						else
						{
								RevState5=revhead1;      //状态机复位
						}
						break;   		
				//等待接收第5个同步头0x10
				case  revhead5:	//注释掉的原因是插在CH9350另一个USB口就变为0x11了,因此干脆跳过
//						if (ucTemp==0x10)
//						{
								RevState5=revhead6;
//						}
//						else
//						{
//								RevState5=revhead1;      //状态机复位
//						}
						break;  
				//等待接收第6个同步头0x01
				case  revhead6:
						if (ucTemp==0x01)
						{
								RevState5=revhead7;
						}
						else
						{
								RevState5=revhead1;      //状态机复位
						}
						break;  
				//等待接收第7个同步头0x00
				case  revhead7:
						if (ucTemp==0x00)
						{
								RevState5=revhead8;
						}
						else
						{
								RevState5=revhead1;      //状态机复位
						}
						break;  
				//等待接收第8个同步头0x00
				case  revhead8:
						if (ucTemp==0x00)
						{
								RevState5=revpakage;
						}
						else
						{
								RevState5=revhead1;      //状态机复位
						}
						break;  						
				//等待接收数据内容
				case revpakage:
						if(UART4_RxbufCount<UART4_RxbufSize&&ucTemp!=0)
						{
							UART4_Rxbuf[UART4_RxbufCount++]=USBDataToASCII(ucTemp);
						}
						RevState5=revhead1;
						break;
			default:
						RevState5=revhead1;              //状态机复位
				break;
			}
	}	




/* 串口4数据接收处理线程入口函数,用于处理刷卡机线程 */
void uart4recv_thread_entry(void *parameter)
{	
	while(1)
	{
		if(Uart4TimeOut>2&&Uart4GetIDFlag==0)	
		{
			Uart4GetIDFlag=1;			//已经超时,判断接收完一帧			
			memcpy(Vision_t.ID,UART4_Rxbuf,strlen((char*)UART4_Rxbuf));
			memset(UART4_Rxbuf,0,UART4_RxbufSize);
			UART4_RxbufCount=0;
		}
		rt_thread_mdelay(50);
	}
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值