单片机:stm32f103c8t6  

实现方式:纯IO口模拟(RST、I/O、CLK均为普通IO口)

实现功能:接触式CPU卡、PSAM、SIM读(写)

网上有很多相关的代码,有的是用自带的智能卡接口,有的使用了外部晶振和分频电路,多数都没讲清具体的软件实现方式.

这是ISO7816手册上对CLK要求的原话:

CLK提供时钟信号至少在复位应答期间,时钟f的频率值应在以下范围内:
1-5MHz:A类
1-4MHz:B类

其实这也讲明了CLK的要求,而不是类似模拟SPI那种需要同步给时钟,此处的时钟类似一个外部晶振电路给卡提供基准频率。

嵌入智能卡的芯片没有内部时钟发生器,这样就需要外部设备为芯片提供时钟。时钟是提供数据传输速率的基准。它是通过 C3 触点提供给卡的。卡时钟的最低频率为 1MHz,而在激活和冷复位期间,时钟频率的最大频率为5MHz。在没有特殊说明的情况下,稳定工作时的时钟信号的占空比为 40%至60%。当时钟从一个频率切换到另一个被卡支持的频率时,应当注意最短时钟周期的占空比不能小于 40%。当切换时钟时,不应有数据的交换发生。在下面的两个时刻可以切换时钟:复位应答后,卡在等待一个字符时;PPS 交换后,卡在等待字符时。建议在这两个时刻进行时钟的切换。施加到触点的时钟并不需要与提供给芯片内部的时钟信号完全一样,因为芯片的内部含有可选的时钟分频器。本文的 7816 接口包含有一个 8 位的寄存器,它用来设置芯片时钟的分频系数。『这段话来自某位同学的论文

所以对于7816协议卡的CLK,只需要外部提供1~4M频率(B类卡)的稳定时钟即可,而不需要在发送数据时同步送出,默认的频率是3.579M,因为这个频率经过卡内部分频器分频之后正好是9600bps。至于为什么要得到9600bps,这个放在后面讲。首先讲下,stm32单片机如何产生f=3.579M的方波。

最简单的方式就是利用定时器产生PWM:

//TIM4_PWM_Init(20-1,0);//3.4Mhz 50%Duty  输出  void TIM4_PWM_Init(u16 arr,u16 psc)
{  GPIO_InitTypeDef GPIO_InitStructure;TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;TIM_OCInitTypeDef  TIM_OCInitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);// 使能TIM4时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);  //使能GPIOB时钟//设置该引脚为复用输出功能,输出TIM4 CH1的PWM脉冲波形GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //TIM_CH1GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);//PB6TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值    80KTIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  不分频TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_timTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式2TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能TIM_OCInitStructure.TIM_Pulse = 10; //设置待装入捕获比较寄存器的脉冲值TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高TIM_OC1Init(TIM4, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx//TIM_CtrlPWMOutputs(TIM4,ENABLE);  //MOE TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);  //CH1预装载使能  TIM_ARRPreloadConfig(TIM4, ENABLE); //使能TIMx在ARR上的预装载寄存器TIM_Cmd(TIM4, ENABLE);  //使能TIM4}

psc = 0 ,预分频系数为0,即定时器不分频,输入时钟为72Mhz,

arr = 20-1,定时器周期为20,定时器的CNT值达到20即会清0,重新开始计数;

TIM_Pulse = 10 ,比较寄存器的值为10,即CNT达到10便会将当前已经使能通道引脚(此处是PB6)翻转一次,由于arr = 20 ,所以PWM的占空比就是50%,定时器周期=((1+psc) * (1+arr) )/72= 20/72 ≈0.278us = 3.6Mhz

数据I/O引脚:

在数据 I/O 上,一位数据所持续的时间叫做“基本时间单位”,简写为 etu。etu是由 F 
和 D 共同决定的,这两个值是在复位应答中给出的,F 为时钟分频因子,D为波特率调整因子。其大小为 F/D 个时钟周期,这里的时钟指的是 CLK 触点上的时钟,即

1etu =(F/D) * (1/f)   ,卡上电时默认F = 372, D = 1,所以1etu = 372/3.579Mhz= 103us,也就是每一位是103us,对应波特率为9600.


 在这种情况下可以直接利用串口发送和接收数据,网上很多代码也都是这种使用方式:(格式:1位起始位+8位数据+1位偶校验位)

当然也可以不用串口,直接读取IO口,按位接收数据,每次读完延时103us再读取下一位,依次读完一个字节数据和奇偶位即可。我就是直接读取IO口方式接收的:

unsigned char  Psam_RecvByte(u8 cChannel)
{unsigned char i,data=0;unsigned int  j=0;SAM_DATA_DIR(GP_IO_Data[cChannel],GP_Pin_Data[cChannel],GPIO_Mode_IN_FLOATING); //DATA脚配置为输入//INTX_DISABLE();                   //close EA  while((SAM_DATA_GET[cChannel]()!=0) /*&& (j++<65000)*/ );//等待IO口为低,超时退出  起始位//delay_us(GCDELAYTIME);for(i=0; i<8; i++)                   {   data >>= 1;        delay_us(GCDELAYTIME);if(SAM_DATA_GET[cChannel]() != 0)  data |= 0x80;}delay_us(GCDELAYTIME);delay_us(GCDELAYTIME/2);return data;
}

下面是调试通过的7816协议时序图 :采用热复位方式,卡片返回ATR

 RST信号:

卡片热复位代码: 

void Psam_Reset(u8 cChannel)
{Set_SAM_RST[cChannel]();//拉高RSTdelay_ms(20);Clr_SAM_RST[cChannel]();//拉低RSTdelay_ms(10);Set_SAM_RST[cChannel]();//拉高RST 完成热复位
}

STM32 IO口模拟ISO7816(PSAM卡)协议相关推荐

  1. STM32 IO口模拟串口通讯

    转自:http://ziye334.blog.163.com/blog/static/224306191201452833850647 前阵子,调项目时需要用到低波特率串口通讯(300的波特率),才发 ...

  2. 【STM32】IIC的基本原理(实例:普通IO口模拟IIC时序读取24C02)(转载)

    版权声明:本文为博主原创文章,允许转载,但希望标注转载来源. https://blog.csdn.net/qq_38410730/article/details/80312357 IIC的基本介绍 I ...

  3. STC15单片机读写大容量SD卡(IO口模拟SPI模式)

    使用的芯片是STC15系列的IAP15F2K61S2,开发板是51的xl2000.把芯片座上的51芯片拔掉换成STC的,混合模式.(配置够低吧) 源码由51开发板例程的实验26修改而来. 浏览了网上的 ...

  4. STM32+MAX6675利用io口模拟SPI获取实时温度数据程序及代码

    STM32+MAX6675利用io口模拟SPI获取实时温度数据程序及代码 本文采用的芯片为STM32F103RCT6 温度芯片为MAX6675 因为芯片的spi口只有3个,有部分需要外接W25Q128 ...

  5. 国产单片机IO口模拟IrDA1.0协议

    单片机IO口模拟IrDA1.0协议 IrDA1.0协议是一种利用红外通信的无线传输协议,可以很好的解决一些便携式设备与主机之间通信的问题,具有携带方便,低功耗,成本低,传输可靠等特点,缺点是传输距离较 ...

  6. STM32 IO口的8中配置方式解读(推挽输出、开漏输出、复用开漏输出、复用推挽输出以及上拉输入、下拉输入、浮空输入、模拟)

    转自:http://blog.csdn.net/u010592722/article/details/45746079 STM32  IO口的8中配置方式: (1)GPIO_Mode_AIN 模拟输入 ...

  7. linux下IO口模拟I2C的一些总结

    2019独角兽企业重金招聘Python工程师标准>>> 以前一直在用I2C接口,因为总是有线程的例子就一直没有去深入的了解,今天分析了一下在linux下通用GPIO模拟I2C的程序. ...

  8. 基于s32k146的IO口模拟串口

    zhe最近在搞一个IO口模拟LIN的代码,其中包括IO口模拟UART的部分,就记录一下,希望对像我们这样的初学者能有所帮助. 1. 串口协议 串口的特点:全双工,串行,异步 串口协议(我这里选用最常见 ...

  9. 使用IO口模拟PWM设计呼吸灯

    <<<<<正文>>>>> <硬件设计> 控制灯的IO口接芯片即可: <软件架构> <软件设计> 我的呼吸 ...

最新文章

  1. RANet : 分辨率自适应网络效果和性能的best trade-off | CVPR 2020
  2. 完整的Web应用程序Tomcat JSF Primefaces JPA Hibernate –第1部分
  3. mysql 更新错误1062_mysql 出现1062错误怎么办
  4. PHP的stdClass
  5. 前端学习-css(一)
  6. 苹果手机电量剩余多少冲电对电池最好?
  7. java.lang.IllegalArgumentException: addChild: Child name '/SSHE' is not unique
  8. 排序算法--希尔排序
  9. 你真的了解 MySQL 数据库的运行状况吗?
  10. 中艺人脸识别考勤机使用方法_人脸识别考勤机说明书及使用方法
  11. 安卓文件管理神器--X-plore
  12. Roy Li的学习和成长自传
  13. 为何电动汽车没未来感?设计和生产线无根本性改变 | 行业
  14. ubuntu8.10显卡驱动安装(8500gt)
  15. iconfont图标无法显示的问题
  16. 深度学习: 数据扩充 (Data Augmentation)
  17. Android简易老虎机(转动式)
  18. Iterator patten 读书笔记
  19. 《抗压力-逆境生存法则》读后感
  20. 西瓜书课后题4.7(队列控制决策树深度)

热门文章

  1. Reading Comprehension必读paper汇总
  2. Jquery如何去掉复选框的勾
  3. intel32/ctor.dll mysql_ctor.dll,下载,简介,描述,修复,等相关问题一站搞定_DLL之家
  4. 缺少编译器要求的成员“System.Runtime.CompilerServices.ExtensionAttribute..ctor” 解决方案
  5. python \xe6\xb5解码
  6. 我的北京生活,2018面向新的开始
  7. 想做出高级又好看的PPT,这8个窍门你别错过
  8. 惊了!这里竟然有你的生日和银行卡密码?
  9. wating for network configuration unity恢复
  10. 天地波超视距雷达在远洋无人航运中的运用