7816协议时序和采用UART模拟7816时序与智能卡APDU指令协议
7816时序
7816时一个比较早的老通讯时序了,最近项目上需要用UART模拟所以,简单学习时序。
时序比较简单,熟悉UART的一眼看着就像是串口的时序,只是他没有停止位,取而代之的就是保护时间guradtime,一般是两个etu所以可以使用两个停止位来模拟。电路图上就是将RX和TX短接,在发送关闭串口的接受功能反之接收时关闭发送功能就可以了。
APDU指令
1、报文格式。
C-APDU有4字节的必备长度和1个可变长度条件体组成
CLA:命令报文类别字节
INS:命令报文指令字节
P1:参数1
P2:参数2
LC:条件体数据域的实际长度
DATA:数据域
Le:期望返回数据的长度
CLA INS P1 P2 LC DATA Le 这里需注意的就是在物理链路上给卡发送APUD指令时需要按一下时序发送,先发送前5个字节然后等待卡回应INS 后才可继续发送余下的DATA,LE可以没有。
串口模拟7816参考程序
初始化同普通接口初始化相同
初始化代码
GPIO_InitTypeDef GPIO_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; USART_InitTypeDef USART_InitStructure; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); GPIO_InitStructure.GPIO_Pin = FM151_TXD_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(FM151_PORT, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = FM151_RXD_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(FM151_PORT, &GPIO_InitStructure); USART_InitStructure.USART_BaudRate = 9600; USART_InitStructure.USART_WordLength = USART_WordLength_9b;//9位数据 USART_InitStructure.USART_StopBits = USART_StopBits_1;//1位停止位 USART_InitStructure.USART_Parity = USART_Parity_Even;//偶校验 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //硬件流控制失能 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //发送和接受使能 USART_Init(USART3, &USART_InitStructure); //Usart1 NVIC 配置 NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 4 ; //抢占优先级4 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子优先级0 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器 USART_Cmd(USART3, ENABLE); USART_ITConfig(USART3, USART_IT_RXNE, DISABLE); //开始都不允许接受中断
这里采用中断接受,所以需要字节实现自己的中断服务函数。
发送数据
static void UartSendByte(u8 *dat) { while (USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET); USART_SendData(USART3, *dat); while (USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET); USART_ClearFlag(USART3, USART_FLAG_TC); delay_us(guardtime); }
发送一定字节数据
void SendData(u8 *data, u16 datalenth) { u16 i; SetUartDir(TX); for (i = 0; i < datalenth - 1; i++) { UartSendByte(data + i); } UartSendLastByte(data + i); SetUartDir(RX); }
这里注意最后一个字节不需要额外的保护时间。最后就是配置UART的接受和发送的寄存器函数。
void SetUartDir( u8 dir) { u32 reg; //发送时禁止接收,发送完成才开始接收 if (dir == RX) { reg = USART3->CR1; reg |= USART_Mode_Rx; reg &= (~USART_Mode_Tx); USART3->CR1 = reg; USART_ITConfig(USART3, USART_IT_RXNE, ENABLE); } else if (dir == UART_TXD) { reg = USART3->CR1; reg |= USART_Mode_Tx; reg &= (~USART_Mode_Rx); USART3->CR1 = (u16)reg; USART_ITConfig(USART3, USART_IT_RXNE, DISABLE); } }