5974|10

71

帖子

0

TA的资源

一粒金砂(初级)

楼主
 

【求助】单片机直接读写SIM卡,遇到困难 [复制链接]

我现在用STC的单片机(基本上兼容51)在做一个直接操作SIM卡的项目。用的是KEIL编程环境。
如果哪位高手有单片机直接读写SIM卡的程序,希望能提供一下,非常感谢。

现在进展的情况:

SIM卡上电复位后,似乎是能读到返回值了,返回值的第一个字节是“3B”,这个应该差不多是正确的,但后面的一些字节就有问题了,有的字节都通不过奇偶校验。(后面会附上测试程序及SIM卡的返回值)

但不管怎么说,SIM卡的复位应该是成功了吧,虽然接收到的复位响应有点问题。那就继续操作吧,我又试了一下select命令。即向SIM卡发送“A0 A4 00 00 02”,这次接收到的是“6E 00 FF”。看了一下ISO7816的说明,好像是说我的CLA(就是A0那个字节)发的不对。我现在怀疑是不是我的发送字节的函数写的不好,延时有问题,以至于时序错误,SIM卡识别不出来呢?

下面是我的完整测试程序,用KEIL2编写的,单片机是用的STC的,这个单片机的速度比51快,所以延时程序部分也相应做了调整。

/*************************************************************
*                       sim_test.c
* 程序功能:
* 测试单片机与SIM卡的读写操作
*************************************************************/
#include
#include

typedef unsigned char uint8;


sbit SIM_CLK = P1^0;                //接SIM卡的CLK引脚,这里用单片机的P1.0为SIM卡提供时钟(2.7648MHz)
sbit SIM_IO = P2^5;                //接SIM卡的I/O引脚
sbit SIM_RST = P0^6;                //接SIM卡的RST引脚
sbit SIM_VCC_ENABLE = P0^4;        //SIM卡的电源使能

//为P1.0管脚输出时钟信号而定义(这部分是STC单片机特有的吧,目的是为了从P1.0输出时钟)
sfr WAKE_CLK0         = 0x8F;       
sfr AUXR        = 0X8E;
sfr BRT                = 0X9C;

uint8 buf[32]={0x55};    //从SIM卡接收到的数据,先存放在buf中,然后再发至串口显示
uint8 i=0;               //指向buf的起始
uint8 j=sizeof(buf);     //指向buf的结束
/************************************************************
* 初始化单片机相关寄存器
***********************************************************/
void UartInit()
{
        SCON  = 0x50;  
        TMOD |= 0x21;  
        PCON |= 0x80;  

        TH1   = 0xE8;   // Baud:2400  fosc=11.0592MHz
        TL1   = 0xE8;       

        IE   |= 0x90;   
        TR1   = 1;      
}
/**************************************************
*        初始化CLK时钟,该时钟用来向SIM卡提供时钟信号
***************************************************/
void SIM_CLK_Init()
{
        AUXR = (AUXR | 0x04);        //独立波特率发生器工作在1T模式
        BRT = 254;                //输出频率CLKOUT2=(Fosc/2)/(256-BRT)=(11.0592MHz/2)/(256-254)=2.7648MHz
        WAKE_CLK0 = WAKE_CLK0 | 0x04;        //允许独立波特率发生器输出时钟
}

/**************************************************
*                延时半个ETU(134.55us/2=67.275)
***************************************************/
void delay_half_ETU()
{
        #pragma asm
                               
                        MOV R2,#9
        ETUhalf_DELAY2:        MOV R3,#19
        ETUhalf_DELAY1:        DJNZ R3,ETUhalf_DELAY1
                        DJNZ R2,ETUhalf_DELAY2
                        RET
        #pragma endasm
}

/**************************************************
*                延时四分之一个ETU(134.55us/4=33.6375us)
***************************************************/
void delay_quarter_ETU()
{
        #pragma asm       
                        MOV R2,#11
        ETUquar_DELAY2:        MOV R3,#7
        ETUquar_DELAY1:        DJNZ R3,ETUquar_DELAY1
                        DJNZ R2,ETUquar_DELAY2
                        RET
        #pragma endasm
}

/**************************************************
*                延时五分之一个ETU(134.55us/5=26.91us)
***************************************************/
void delay_one_fifth_ETU()
{
        #pragma asm                                       
                        MOV R2,#6
        ETUfif_DELAY2:        MOV R3,#11
        ETUfif_DELAY1:        DJNZ R3,ETUfif_DELAY1
                        DJNZ R2,ETUfif_DELAY2
                        RET
        #pragma endasm
}

/**************************************************
*        延时1个ETU
*(ETU:基本时间单位,如SIM卡时钟频率为2.7648MHz,则ETU为372/2.7648M=134.55us)
***************************************************/
void delay_1_ETU()
{
        #pragma asm                       
                    MOV R2,#19
        ETU1_DELAY2:MOV R3,#18
        ETU1_DELAY1:DJNZ R3,ETU1_DELAY1
                    DJNZ R2,ETU1_DELAY2
                    RET
        #pragma endasm
}
/**************************************************
*400个ETU为 400*134.55us=53.820ms
*(10*(91*(3+2*162)+3)+3)*(12/11.0592)/6=53819.99us
***************************************************/
void delay_400_ETU()
{
        #pragma asm
                        MOV R1,#10
        ETU400_DELAY3:        MOV R2,#91
        ETU400_DELAY2:        MOV R3,#162
        ETU400_DELAY1:        DJNZ R3,ETU400_DELAY1
                        DJNZ R2,ETU400_DELAY2
                        DJNZ R1,ETU400_DELAY3
                        RET
        #pragma endasm
}

/**********************************************
*                        向COM1发送一个字符
**********************************************/
void SendChar(uint8 byteToSend)
{
        SBUF=byteToSend;
        while(!TI);
        TI=0;
}
/************************************************************
*        SIM卡初始化
***********************************************************/
void SIM_Init()
{
        SIM_RST = 0;                        //初始化时为低电平
        SIM_CLK = 0;                        //初始化时为低电平
        SIM_IO = 0;                        //初始化时为低电平
        SIM_VCC_ENABLE = 0;                //初始化时为低电平
        delay_400_ETU();                //待电压稳定
}

/************************************************************
*        SIM卡冷复位
***********************************************************/
void SIM_Cold_Reset()
{
        SIM_VCC_ENABLE = 1;                //初始时,电源电压先上电
        delay_400_ETU();                //待电压稳定
        SIM_IO = 1;                                //将I/O端口置为接收方式
        AUXR = (AUXR | 0x10);        //启动独立波特率发生器开始计数工作,对系统时钟进行分频输出
        delay_400_ETU();                //RST复位信号需在提供CLK信号后400个时钟周期内保持低电平
        SIM_RST = 1;                        //之后才可置为高电平

//提供复位信号后400~40000个时钟周期内,I/O口有复位应答
}

/************************************************************
*        从SIM卡读取一个字节
***********************************************************/
uint8 read_SIM_byte()
{
        uint8 loop;
        uint8 recvdata = 0;
        bit Parity = 0;                        //奇偶校验位

        while(SIM_IO);                        //等待起始位

        delay_1_ETU();                        //延时一个etu
//        delay_half_ETU();                //延时半个etu
//        delay_quarter_ETU();        //延时四分之一个etu
        delay_one_fifth_ETU();        //延时五分之一个etu


        for(loop=0;loop<8;loop++)
        {
                recvdata >>= 1;
                if (SIM_IO)
                {
                        recvdata |= 0x80;
                }
                Parity ^= SIM_IO;
                delay_1_ETU();                        //延时一个etu
        }
        Parity ^= SIM_IO;
//        if (!Parity)   //此字节如通过奇偶校验则原样显示,通不过则显示0x99
//        {

                buf[i++] = recvdata;
//        }
//        else
//        {
//                buf[i++] = '\x99';
//        }

        return recvdata;
}

/************************************************************
*        向SIM卡发送一个字节
***********************************************************/
void write_SIM_byte(uint8 dataToSend)
{
        uint8 loop;
        bit Parity = 0;                        //奇偶校验位

        SIM_IO = 0;                                //发送起始位
        delay_1_ETU();                        //延时一个etu

        for(loop=0;loop<8;loop++)
        {
                SIM_IO = (bit)dataToSend;
                Parity ^= (bit)dataToSend;
                dataToSend >>= 1;
                delay_1_ETU();                        //延时一个etu
        }

        SIM_IO = Parity;                        //如果前8位异或的结果是1,则校验位发1,如果前8位异或的结果是0,则校验位发0
        delay_1_ETU();                                //延时一个etu,等待校验位发送出去

        SIM_IO = 1;                                        //将IO拉高
        delay_1_ETU();
        if(SIM_IO)//测试,如果一个etu后SIM_IO仍为高电平,则将'\xab'补充到buf的最末尾,如低电平则添加'\xac'
        {
                buf[--j] = '\xab';
        }
        else
        {
                buf[--j] = '\xac';
        }
}
/**************************************************
*                                        主   程   序
***************************************************/
int main()
{
        UartInit();                                        //串口初始化
        SIM_CLK_Init();                                //单片机向SIM卡提供的工作时钟初始化
        SIM_Init();                                        //SIM卡初始化
        SIM_Cold_Reset();                        //SIM卡复位

//读取复位返回数据(因为之前测试时,冷复位返回数据共15个字节,所以这里写了15个read_SIM_byte()用来接收)
        read_SIM_byte();read_SIM_byte();read_SIM_byte();read_SIM_byte();read_SIM_byte();
        read_SIM_byte();read_SIM_byte();read_SIM_byte();read_SIM_byte();read_SIM_byte();
        read_SIM_byte();read_SIM_byte();read_SIM_byte();read_SIM_byte();read_SIM_byte();

//对SIM卡写入select命令(A0 A4 00 00 02),但没加后面的文件ID
        write_SIM_byte('\xA0');delay_1_ETU();delay_1_ETU();
        write_SIM_byte('\xa4');delay_1_ETU();delay_1_ETU();
        write_SIM_byte('\x00');delay_1_ETU();delay_1_ETU();
        write_SIM_byte('\x00');delay_1_ETU();delay_1_ETU();
        write_SIM_byte('\x02');delay_1_ETU();delay_1_ETU();

//从SIM卡端接收select命令的返回值,故意多写了一些read_SIM_byte()
        read_SIM_byte();read_SIM_byte();read_SIM_byte();read_SIM_byte();read_SIM_byte();
        read_SIM_byte();read_SIM_byte();read_SIM_byte();read_SIM_byte();read_SIM_byte();
}

//串口中断处理,当用串口调试工具随便发送一个字节给单片机时,buf中存放的数据就在串口调试工具的接收端显示出来
void chuankou() interrupt 4
{
        if (RI)
        for (i=0;i         {
                SendChar(buf);
        }
        RI = 0;
}


************************************************************
这就是我上电之后,发送select,然后收到的全部内容。
其中红色字体的部分为SIM卡的上电复位返回信息(貌似也不太正确,我现在没有加奇偶校验部分,如果加上的话,第四个字节(07)就会奇偶校验不正确),那个6E 00 FF应该就是对select的响应了
[接收]3B 98 11 07 38 E0 01 06 67 3C D0 03 87 39 80 6E 00 FF 00 00 00 00 00 00 00 00 00 AB AB AB AB AB


6E应该是说我的CLA(即select命令的第一个字节A0)发送不正确,大家帮忙看一下,是因为发送字节程序和接收字节程序有错误吗,或者程序的其他地方有错误呢?因为是第一次做单片机直接和SIM卡通信的部分,很多内容都还很糊涂,望大家多多指教。

最新回复

ISP写入程序时是用6T还是12T的?为什么我用您的程序无法启动SIM卡? 在计算400个ETU时最后为什么还要除以6? (10*(91*(3+2*162)+3)+3)[297603]*(12/11.0592)/6=53819.99us 我不除以6的话,勉强可以获取到数据,但数据是不正确的。 另外想问一下,您的SIM卡的6个脚是怎么与单片机相联的?是直接相联就可以了吗?要不要加滤波电容和上接电阻?  详情 回复 发表于 2010-2-26 16:50
点赞 关注

回复
举报

72

帖子

0

TA的资源

一粒金砂(初级)

沙发
 
如果哪位大虾以前做过这方面的内容,希望能够指点一下。搞了一个多星期,现在都还很迷糊。ISO7816也看了。感觉我的时序也没有问题啊。怎么就是读到的内容和写入的内容不正确呢?要都不正确也就罢了,从返回的值看,似乎还是有的地方正确有的地方不正确,这真是晕死了。

=======================================
//对SIM卡写入select命令(A0 A4 00 00 02),但没加后面的文件ID
write_SIM_byte('\xA0');delay_1_ETU();delay_1_ETU();
write_SIM_byte('\xa4');delay_1_ETU();delay_1_ETU();
write_SIM_byte('\x00');delay_1_ETU();delay_1_ETU();
write_SIM_byte('\x00');delay_1_ETU();delay_1_ETU();
write_SIM_byte('\x02');delay_1_ETU();delay_1_ETU();

这一部分又做了一些测试,发现把上面的A0 A4 00 00 02改成任意5个字节的内容,返回值都是6E 00 FF,但是如果是改为发送4个字节或者6个字节,返回值又混乱了。看来SIM卡能认得我发的是5个字节,但是在字节的内容识别时,不认为我发的是A0。。。。
 
 

回复

69

帖子

0

TA的资源

一粒金砂(初级)

板凳
 
另外,看冷复位的返回值,也是有问题的
[接收]3B 98 11 07 38 E0 01 06 67 3C D0 03 87 39 80

第一个字节和第三个字节应该没有问题,3B表明了是“正向约定”,11表明了F=372,D=1,时钟最大频率为5MHz。
既然第一个字节和第三个字节正确,那么猜测第二个字节可能也正确。如果是这样的话,98代表了TA1和TD1存在,历史字符的数量是8。

那么第四位就有问题了,07表示TA2\TB2\TC2\TD2都不存在,并且T=7。这个肯定不对吧,一般T=0或T=1,等于7的协议好像不存在吧。。。何况在加入偶校验的情况下(就是1楼那段绿色的代码),这个字节会出现校验错误。

那怎么会有的字节(如第1、3字节)正确,有的字节(如第4字节)错误呢,如果是延时的时序不对,那应该全部的字节都不对啊。
 
 
 

回复

82

帖子

0

TA的资源

一粒金砂(初级)

4
 
你的SIM没有和无线模块配合使用啊例如SIM300
 
 
 

回复

71

帖子

0

TA的资源

一粒金砂(初级)

5
 
回答楼上的朋友:没有,这个是单片机直接和SIM卡通信的,没有经过GSM模块,只是用了个卡座转接了一下,就接到单片机板上了。
 
 
 

回复

70

帖子

0

TA的资源

一粒金砂(初级)

6
 
不认CLA的问题解决了,但是又有了新问题。
经过程序检查,发现write_SIM_byte(uint8 dataToSend) 函数的定义中存在错误

把下面这一段
for(loop=0;loop <8;loop++)
{
SIM_IO = (bit)dataToSend;
Parity ^= (bit)dataToSend;
dataToSend >>= 1;
delay_1_ETU(); //延时一个etu
}
修改为
        for(loop=0;loop<8;loop++)
        {
                SIM_IO = dataToSend & 0x01;
                Parity ^= dataToSend & 0x01;
                dataToSend >>= 1;
                delay_1_ETU();                        //延时一个etu
        }

不认CLA的问题就解决了,SIM卡不再返回6E 00 FF,而是变成了如下的A4 67 00 FF。

[接收]3B 98 11 03 38 E0 01 06 B3 3C E8 03 43 39 C0 A4 67 00 FF 00 00 00 00 00 00 00 00 AB AB AB AB AB

查了一下GSM11.11,返回67 00表示错误的参数P3,也就是那个02错了,再查,得知, P3为后续数据单元的长度。而我的程序中只用了5个write_SIM_byte,向SIM卡写了5个字节,02说明其后面应该还有两个字节,用来表示要选中(select)的文件。我就在原有的5个字节后面又加入了2个write_SIM_byte,总共发送的内容变成了“A0 A4 00 00 02 7F 20”。但是返回却是:

[接收]3B 98 11 03 38 E0 01 06 B3 3C E8 03 43 39 C0 94 04 00 00 00 00 00 00 00 00 AC AB AB AB AB AB AB

94 04代表“文件ID没有发现”或“特征字串没有发现”。可是7F 20表示的应该是DFGSM文件啊。
还有,我用ABAC分别表示某一字节发送过程中是否有错误(见程序),从返回来看,前6个字节的发送都没有问题,都是AB,但第七个字节却出现了AC,这是怎么回事呢?如果是发送函数的问题,应该要出错都出错才对啊。

前面的94 04错误提示,也有可能是因为我的第七个字节(20)发送错误,以至于SIM卡认不出来。但是怎么会单这个字节错呢?怪哉。
 
 
 

回复

67

帖子

0

TA的资源

一粒金砂(初级)

7
 
以下是我发送的另一个命令,用来选择根目录的,以及相应的返回

发送:A0 A4 00 00 02 3F 00
[接收]3B 98 11 03 38 E0 01 06 B3 3C E8 03 43 39 C0 94 04 00 00 00 00 00 00 00 00 AC AB AB AB AB AB AB

=========================================================
另外,刚才又发现了一个问题。究竟向SIM写完命令多长时间之后,才应该开始读取命令返回值呢?
因为我发现在发送命令的最后一个write_SIM_byte函数后面的delay_1_ETU()的个数不同(即延时时间不同),那么读到的命令返回值也不一样。
发送命令完毕后,到底应该延时几个ETU再开始读取命令返回值呢?
 
 
 

回复

68

帖子

0

TA的资源

一粒金砂(初级)

8
 
对不起各位大侠,如果您需要用单片机实现液晶显示的话,可以dwin99@live.cn索取资料。
 
 
 

回复

84

帖子

0

TA的资源

一粒金砂(初级)

9
 
请问楼主不认CLA的问题是怎么解决的
 
 
 

回复

80

帖子

0

TA的资源

一粒金砂(初级)

10
 
具体是什么思路的
 
 
 

回复

72

帖子

0

TA的资源

一粒金砂(初级)

11
 
ISP写入程序时是用6T还是12T的?为什么我用您的程序无法启动SIM卡?
在计算400个ETU时最后为什么还要除以6?
(10*(91*(3+2*162)+3)+3)[297603]*(12/11.0592)/6=53819.99us
我不除以6的话,勉强可以获取到数据,但数据是不正确的。


另外想问一下,您的SIM卡的6个脚是怎么与单片机相联的?是直接相联就可以了吗?要不要加滤波电容和上接电阻?
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表