关于stm32 smartcard功能调试,官方提供的例程是配合8024芯片进行控制的。程序可从地址:http://www.pudn.com/downloads420/sourcecode/embedded/detail1781544.html下载。
经过摸索,终于调试出不用8024的程序设计。
首先确定电路连接,stm32的USART3_CK(PB12)连接到接触式IC卡的CLK端(触点4),stm32的USART3_TX(PB10)连接到接触式IC卡的IO端(触点3),然后stm32选一个GPIO作为输出连接到接触式IC卡的RST端(触点5)。ic卡的vcc和gnd当然也是要接好的了。
然后是程序设计,
1、设置时钟,关键的有三个地方,
A、在设置系统时钟为72M之后,设置PCLK1频率为36M
RCC_PCLK1Config(RCC_HCLK_Div2);
B、使能GPIOB总线时钟,即USART3的端口所在的IO;并使能复用时钟。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
C、使能USART3总线时钟。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
2、设置IO,
GPIO_InitTypeDef GPIO_InitStructure; /* Configure USART3 CK(PB.12) as alternate function push-pull */ GPIO_InitStructure.GPIO_Pin = SAM0_CLK; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(SAM0_Port, &GPIO_InitStructure); /* Configure USART3 Tx (PB.10) as alternate function open-drain */ GPIO_InitStructure.GPIO_Pin = SAM0_IO; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; GPIO_Init(SAM0_Port, &GPIO_InitStructure); /* Configure Smartcard Reset */ GPIO_InitStructure.GPIO_Pin = SAM0_RST; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(SAM0_Port, &GPIO_InitStructure);
其中已经定义SAM0_CLK为GPIO_Pin_12,定义SAM0_Port为GPIOB,定义SAM0_RST为GPIO_Pin_11,定义SAM0_IO为GPIO_Pin_10,
3、设置USART3
USART_InitTypeDef USART_InitStructure; USART_ClockInitTypeDef USART_ClockInitStructure; /* USART Clock set to 3.6 MHz (PCLK1 (36 MHZ) / 10) */ USART_SetPrescaler(USART3, 0x05); /* USART Guard Time set to 16 Bit */ USART_SetGuardTime(USART3, ); USART_StructInit(&USART_InitStructure); USART_InitStructure.USART_BaudRate = ; USART_InitStructure.USART_WordLength = USART_WordLength_9b; USART_InitStructure.USART_StopBits = USART_StopBits_1_5; USART_InitStructure.USART_Parity = USART_Parity_Even; USART_Init(USART3, &USART_InitStructure); USART_ClockInitStructure.USART_Clock = USART_Clock_Enable; USART_ClockInit(USART3, &USART_ClockInitStructure); /* Enable the USART3 Parity Error Interrupt */ USART_ITConfig(USART3, USART_IT_PE, ENABLE); /* Enable the USART3 Framing Error Interrupt */ USART_ITConfig(USART3, USART_IT_ERR, ENABLE); /* Enable USART3 */ USART_Cmd(USART3, ENABLE); /* Enable the NACK Transmission */ USART_SmartCardNACKCmd(USART3, ENABLE); /* Enable the Smartcard Interface */ USART_SmartCardCmd(USART3, ENABLE);
主要配置USART3的时钟为3.6M,并且使能时钟,波特率为9677(这个值是参考官方例程的,9600也可以),字节长度为9bits(stm32中文参考资料上介绍smartcard功能时,应该设为8bits,但是设为8bits调试不成功,这个郁闷),停止位设为1.5bits,校验位设为偶校验(奇校验也可以的),其它的使能smartcard功能,都要设置好。
4、编写复位程序,ISO7816中,对IC卡的操作,重要的一步就是获取复位返回信息。
以下是我调试好的程序
unsigned char PSAMInit_usart(u8 *card, u8 length) { u8 Data; //u8 card[40]; u8 i; GPIO_WriteBit(SAM0_Port, SAM0_RST, (BitAction));//set the rst to low ;i<length;i++) card[i] = 0x00; Data = 0x00; ;i<length;i++)//for delay Data = 0x00; GPIO_WriteBit(SAM0_Port, SAM0_RST,(BitAction));//set the rst to high ; i < length; i++)//get the atr { if((USART_ByteReceive(&Data, SC_Receive_Timeout)) == SUCCESS) { card[i] = Data; } } ]) { ; } else ; }
这个子函数是复位子函数。
然后参考官方例程中,smartcard.c中的第62行的函数SC_Handler函数,将其中第107行调用的函数SC_AnswerReq(SCState, &SC_ATR_Table[0], 40);改为,自己编写的复位函数,
temp_flag = PSAMInit_usart(&SC_ATR_Table[], ); if(temp_flag == 0x01) *SCState = SC_ACTIVE; else *SCState = SC_POWER_OFF;
然后在测试程序中调用SC_Handler函数,即可调试。
测试程序如下:
SC_State SCState;// = SC_POWER_OFF; u8 i; SCState = SC_POWER_ON; SC_ADPU.Header.CLA = 0x00; SC_ADPU.Header.INS = SC_GET_A2R; SC_ADPU.Header.P1 = 0x00; SC_ADPU.Header.P2 = 0x00; SC_ADPU.Body.LC = 0x00; while(SCState != SC_ACTIVE_ON_T0) { SC_Handler(&SCState, &SC_ADPU, &SC_Responce); } /* Apply the Procedure Type Selection (PTS) */ SC_PTSConfig();
这其中的变量定义,宏定义,都是官方例程中的。
在函数PSAMInit_usart调用完之后,即可看到SC_ATR_Table数组中得到的复位返回信息。
然后是SC_PTSConfig();(smartcard.c第202行)这个函数的修改,主要是要根据SC_ATR_Table返回信息中的第3个字节(即ISO7816中所说TA1),来修改串口波特率,程序中208到284行,是发送并接收PTS,根据本人测试,有些卡可以完全一步一步通过这个过程,有些卡是不行的,但是后面的
if(PTSConfirmStatus == 0x01) { workingbaudrate = apbclock * D_Table[(SC_A2R.T[] & (u8)0x0F)]; workingbaudrate /= F_Table[((SC_A2R.T[] >> ) & (u8)0x0F)]; USART_StructInit(&USART_InitStructure); USART_InitStructure.USART_BaudRate = workingbaudrate; USART_InitStructure.USART_WordLength = USART_WordLength_9b; USART_InitStructure.USART_StopBits = USART_StopBits_1_5; USART_InitStructure.USART_Parity = USART_Parity_Even; USART_InitStructure.USART_Clock = USART_Clock_Enable; USART_Init(USART3, &USART_InitStructure); }
这一段程序是必须要执行的,否则,以后的调试就没有返回值了。所以可以去掉if(PTSConfirmStatus == 0x01)这一句。这个设置好之后,可以根据不同的内部协议进行通信了,手机卡也好,电话卡也好,不同的卡,内部协议不一样,但是发送命令、数据,接收返回数据都可以,将SC_ADPU这个结构体赋值之后,调用SC_Handler(&SCState, &SC_ADPU, &SC_Responce);这个函数。当SCState为SC_ACTIVE_ON_T0时,就可以发送命令,并接收返回值了。