共3条
1/1 1 跳转至页
IC 接触式IC卡读写问题!求助
问
一、使用LPC2114单片机通过IO口加上拉电阻(4.7K),与SLE4428卡连接读写数据。无法读去数据程序如下希望朋友们看一下:
#include "config.h"
#define IC_rst 1<<2
#define IC_clk 1<<3
#define IC_dat 1<<4
#define IC_IN 1<<11 //IC插入
uint8 IcRead[3]={0x0E,0x20,0x00}; //读卡数据命令
uint8 IcWrite[3]={0x33,0x00,0x00}; //写卡数据命令
uint8 IcCheck1[3]={0xCD,0xFE,0xFF}; //密码校验低位
uint8 IcCheck2[3]={0xCD,0xFF,0xFF}; //密码校验高位
uint8 IcRcume[3]={0xCD,0xFD,0x08}; //错误计数器复位
uint8 EnabWrtIc;//IC卡写使能
uint8 ICAddr;
uint8 IcRcv[10];
void DlayNS(uint32 dly)
{
for(;dly>0;dly--);
}
void Clock(void)
{
uint32 regist;
regist=IO0DIR;
IO0CLR=IC_clk;
DlayNS(10); //时钟高、低至少9us
IO0SET=IC_clk;
DlayNS(10); //10us
IO0DIR=regist;
}
void Uart0Send(uint8 dat)
{
U0THR=dat;
while((U0LSR&0x40)==0);
}
void Uart0Int(uint32 BPS)
{
uint16 Fdiv;
PINSEL0|=0x05;
U0LCR=0x83;
Fdiv=(Fpclk/16)/BPS;
U0DLM=Fdiv/256;
U0DLL=Fdiv%256;
U0LCR=0x03;
}
void SendIC(uint8 *buf,uint8 num)
{
uint32 i;
uint8 j;
uint8 dat;
IO0SET=IC_rst;
for(i=0;i<num;i++)
{
dat=*buf;
for(j=0;j<8;j++)
{
if((dat&0x01)!=0)
{
IO0CLR=IC_clk;
DlayNS(90);
IO0SET=IC_dat;//写1
DlayNS(25000);
IO0SET=IC_clk;
DlayNS(90);
}
else
{
IO0CLR=IC_clk;
DlayNS(90);
IO0CLR=IC_dat;//写0
IO0DIR=IC_dat;
DlayNS(25000);
IO0SET=IC_clk;
DlayNS(90);
}
dat>>=1;
}
buf++;
}
IO0CLR=IC_rst;
}
void RcvIC(uint8 num)
{
uint8 i;
uint8 j;
uint32 iodat;
uint8 dat=0x00;
//
IO0CLR=IC_rst;
for(i=0;i<num;i++)
{
for(j=0;j<8;j++)
{
IO0CLR=IC_clk;//clk由1变为0时,开始接收一位数据
DlayNS(25);//延时
IO0SET=IC_clk;
iodat=IO0PIN;
if((iodat&IC_dat)==IC_dat)
{
dat|=(1<<j);
}
else dat=0<<j;
DlayNS(25);
}
IcRcv[i]=dat;
}
IO0SET=IC_rst;
IO0DIR|=IC_dat;
}
uint8 CheckIcMA(void)
{
uint8 err;
uint8 i;
//密码校验
IcRead[0]=0xCE;
IcRead[1]=0xFD;
SendIC(&IcRead[0],0x03);//读错误计数器当前值
RcvIC(1);
if(IcRcv[0]!=0) //不等于0开始校验密码
{
SendIC(&IcCheck1[0],3);//校验第一字节的密码
RcvIC(1);
if(IcRcv[0]==0)
{
SendIC(&IcCheck2[0],3);//校验第二字节的密码
RcvIC(1);
if(IcRcv[0]==0)
{
SendIC(&IcRcume[0],3);//复位错误计数器为8
for(i=0;i<103;i++) //写卡完延续103个脉冲
{
Clock();
}
err=0;
}
else err=1;
}
}
return(err);
}
void ICTransact(void)
{
uint8 stand;
uint8 err;
uint8 i;
//密码校验
err=CheckIcMA();
if(err==0) EnabWrtIc=1;
else EnabWrtIc=0;
//写站台代码及到站时间
if(EnabWrtIc==1)
{
//LED显示开始给IC卡写到站数据
//预写卡地址校验
IcRead[1]=0x08;
SendIC(&IcRead[0],0x03);
RcvIC(0x01);
ICAddr=IcRcv[0];
IcRead[1]=0x09;
SendIC(&IcRead[0],0x03);
RcvIC(0x01);
ICAddr=IcRcv[0]<<8;
IcWrite[1]=ICAddr+1;
IcWrite[0]|=(ICAddr>>8)&0x0C;
IcWrite[2]=stand; //获取站台代码
SendIC(&IcWrite[0],0x03); //写站台代码
for(i=0;i<103;i++)
{
Clock();
}
IcWrite[1]=ICAddr+1;
IcWrite[0]|=(ICAddr>>8)&0x0C;
IcWrite[2]=stand; //获取年
SendIC(&IcWrite[0],0x03); //写到站时间年
for(i=0;i<103;i++)
{
Clock();
}
IcWrite[1]=ICAddr+1;
IcWrite[0]|=(ICAddr>>8)&0x0C;
IcWrite[2]=stand; //获取月
SendIC(&IcWrite[0],0x03); //写到站时间月
for(i=0;i<103;i++)
{
Clock();
}
IcWrite[1]=ICAddr+1;
IcWrite[0]|=(ICAddr>>8)&0x0C;
IcWrite[2]=stand; //获取日
SendIC(&IcWrite[0],0x03); //写到站时间日
for(i=0;i<103;i++)
{
Clock();
}
IcWrite[1]=ICAddr+1;
IcWrite[0]|=(ICAddr>>8)&0x0C;
IcWrite[2]=stand; //获取时
SendIC(&IcWrite[0],0x03); //写到站时间时
for(i=0;i<103;i++)
{
Clock();
}
}
}
uint8 ICReast(void)
{
uint8 i;
uint8 err=0;
//从上电到IC卡复位操作必须大于100us
IO0SET=IC_dat;
IO0CLR=IC_rst;
IO0CLR=IC_clk;
DlayNS(430);
IO0SET=IC_rst;
DlayNS(23);
IO0SET=IC_clk;
DlayNS(45);
IO0CLR=IC_clk;
DlayNS(23);
IO0CLR=IC_rst;
RcvIC(0x04); //读卡复位后的4个数据
for(i=0;i<4;i++)
{
Uart0Send(IcRcv[i]);
}
IO0SET=IC_clk;
DlayNS(15);
IO0CLR=IC_clk;
DlayNS(1);
IO0SET=IC_dat;
return(err);
}
int main(void)
{
uint8 err;
uint8 i;
uint8 sta=0;
PINSEL0=0x00000005;
PINSEL1=0x00000000;
Uart0Int(115200);
IO0DIR=IC_rst|IC_clk|IC_dat;
while(1)
{
err=ICReast();
if(err==1) ICReast();
else sta=1;
//读IC卡数据
while(sta==1)
{
SendIC(&IcRead[0],0x03);//写命令
RcvIC(3);
for(i=0;i<3;i++)
{
//读数据
Uart0Send(IcRcv[i]);
}
IcRead[1]+=1;
if(IcRead[1]>=0xFF)
{
IcRead[1]=0x00;
}
}
}
}
sle4428卡资料:http://www.21ic.com/news/n1283c78.aspx
二:使用LPC2114单片机通过I2C接口加上拉电阻(4.7K),与AT24C16卡连接读写数据。无法读去IC卡数据,单可以对AT24C01EEPROM芯片进行读写操作。程序如下希望朋友们看一下:
#include "config.h"
#define power 1<<4;
extern void __irq IRQ_I2C(void);
extern uint8 IRcvStr(uint8 sla, uint8 suba, uint8 *s, uint8 no);
extern uint8 ISendStr(uint8 sla, uint8 suba, uint8 *s, uint8 no);
extern uint8 ISendByte(uint8 sla, uint8 dat);
extern uint8 IRcvByte(uint8 sla, uint8 *dat);
void I2Cint(uint32 fi2c)
{
//PINSEL0=0x50;
I2SCLH=(Fpclk/fi2c+1)/2;
I2SCLL=(Fpclk/fi2c)/2;
I2CONCLR=0x2C;
I2CONSET=0x40;
VICIntSelect=0x00000000;
VICVectCntl0=0x29;
VICVectAddr0=(uint32)IRQ_I2C;
VICIntEnable=(1<<9);
}
void Uart0Send(uint8 dat)
{
U0THR=dat;
while((U0LSR&0x40)==0);
}
void Uart0Int(uint32 BPS)
{
uint16 Fdiv;
//PINSEL0|=0x05;
U0LCR=0x83;
Fdiv=(Fpclk/16)/BPS;
U0DLM=Fdiv/256;
U0DLL=Fdiv%256;
U0LCR=0x03;
}
void DelayNS(uint32 dly)
{ uint32 i;
for(; dly>0; dly--)
for(i=0; i<50000; i++);
}
int main(void)
{
uint8 i;
uint8 dat=0x11;
uint8 err0,err1;
uint8 dat2[8];
uint8 dat1[8]={0x05,0x06,0x07,0x08,0x05,0x06,0x07,0x08};
PINSEL0=0x00000055;
PINSEL1=0x00000000;
IO0DIR=0x1C;
I2Cint(9600);
Uart0Int(115200);
while(1)
{
loop:
IO0SET=power;
err0=ISendStr(0xA0, 0x60, &dat1[0],0x08);
IO0CLR=power;
if(err0==0)
{
dat+=0x10;
goto loop;
}
else
{
DelayNS(1);
dat=0x10;
loop1:
IO0SET=power;
err1=IRcvStr(0xA0, 0x60, &dat2[0], 0x08);
IO0CLR=power;
if(err1==0)
{
dat+=0x10;
goto loop1;
}
else
{
for(i=0;i<8;i++)
{
Uart0Send(dat2[i]);
}
}
dat=0x01;
DelayNS(1);
}
}
}
/****************************************************************************
* 文件名:I2CINT.C
* 功能:硬件I2C软件包,利用中断方式操作。
* 说明:主程序要配置好I2C总线接口(I2C引脚功能和I2C中断,并已使能I2C主模式)
****************************************************************************/
#include "config.h"
/* 以下为I2C操作时所需要的变量 */
volatile uint8 I2C_sla; // 从机地址(即器件地址)
volatile uint8 I2C_suba; // 子地址
volatile uint8 *I2C_buf; // 数据缓冲区指针 (读操作时会被更改)
volatile uint8 I2C_num; // 操作数据个数 (会被更改)
volatile uint8 I2C_end; // 操作结束标志,为1时表示操作结束,为0xFF时表示操作失败 (会被设置)
volatile uint8 I2C_suba_en; // 子地址使能控制,读操作时请设置为1,写操作时请设置为2 (会被更改)
void DelayMS(uint32 dly)
{
uint8 i;
for(;dly>0;dly--)
for(i=0;i<100;i++);
}
/****************************************************************************
* 名称:IRQ_I2C()
* 功能:I2C中断,通过判断I2C状态字进行相应的操作。
* 入口参数:无
* 出口参数:无
****************************************************************************/
void __irq IRQ_I2C(void)
{ uint8 sta;
sta = I2STAT; // 读出I2C状态字
switch(sta)
{ case 0x08: // 己发送起始条件
if(1==I2C_suba_en) I2DAT = I2C_sla&0xFE; // 指定子地址读时,先写入地址
else I2DAT = I2C_sla; // 否则直接发送从机地址
I2CONCLR = 0x28; // SI=0
break;
case 0x10:
I2DAT = I2C_sla; // 重启动总线后,发送从地址
I2CONCLR = 0x28; // SI=0
break;
case 0x18: // 已发送SLA+W,并已接收应答
if(0==I2C_suba_en) // 无子地址,则直接发送数据
{ if(I2C_num>0)
{ I2DAT = *I2C_buf++;
I2CONCLR = 0x28;
I2C_num--;
}
else
{ I2CONSET = 0x10; // 无数据发送,结束总线
I2CONCLR = 0x28;
I2C_end = 1; // 设置总线操作结束标志
}
break;
}
if(1==I2C_suba_en) // 发送子地址
{ I2DAT = I2C_suba;
I2CONCLR = 0x28;
}
if(2==I2C_suba_en)
{ I2DAT = I2C_suba;
I2CONCLR = 0x28;
I2C_suba_en = 0; // 子地址己处理
}
break;
case 0x28: // 已发送I2C数据,并接收到应答
if(0==I2C_suba_en) // 无子地址,则直接发送数据
{ if(I2C_num>0)
{ I2DAT = *I2C_buf++;
I2CONCLR = 0x28;
I2C_num--;
}
else
{ I2CONSET = 0x10; // 无数据发送,结束总线
I2CONCLR = 0x28;
I2C_end = 1;
}
break;
}
if(1==I2C_suba_en) // 若是指定地址读,则重新启动总线
{ I2CONSET = 0x20;
I2CONCLR = 0x08;
I2C_suba_en = 0; // 子地址己处理
}
break;
case 0x20:
case 0x30:
case 0x38:
I2CONCLR = 0x28; // 总线进入不可寻址从模式
I2C_end = 0xFF; // 总线出错,设置标志
break;
case 0x40: // 己发送SLA+R,并已接收到应答
if(1==I2C_num) // 最后一字节,接收数据后发送非应答信号
{ I2CONCLR = 0x2C; // AA=0,接收到数据后产生非应答
}
else // 接收数据并发送应答信号
{ I2CONSET = 0x04; // AA=1,接收到数据后产生应答
I2CONCLR = 0x28;
}
break;
case 0x50:
*I2C_buf++ = I2DAT; // 读取数据
I2C_num--;
if(1==I2C_num)
{ I2CONCLR = 0x2C; // AA=0,接收到数据后产生非应答
}
else
{ I2CONSET = 0x04; // AA=1,接收到数据后产生应答
I2CONCLR = 0x28;
}
break;
case 0x58:
*I2C_buf++ = I2DAT; // 读取最后一字节数据
I2CONSET = 0x10; // 结束总线
I2CONCLR = 0x28;
I2C_end = 1;
break;
case 0x48:
I2CONCLR = 0x28; // 总线进入不可寻址从模式
I2C_end = 0xFF;
break;
default:
break;
}
VICVectAddr = 0x00; // 中断处理结束
}
/****************************************************************************
* 名称:ISendByte()
* 功能:向无子地址器件发送一字节数据。
* 入口参数:sla 器件地址
* dat 要发送的数据
* 出口参数:返回值为0时表示出错,为1时表示操作正确。
* 说明:使用前要初始化好I2C引脚功能和I2C中断,并已使能I2C主模式
****************************************************************************/
uint8 ISendByte(uint8 sla, uint8 dat)
{ /* 参数设置 */
I2C_sla = sla; // 写操作的器件地址
I2C_buf = &dat; // 待发送的数据
I2C_num = 1; // 发送1字节数据
I2C_suba_en = 0; // 无子地址
I2C_end = 0;
I2CONCLR = 0x2C;
I2CONSET = 0x60; // 设置为主机,并启动总线
while(0==I2C_end);
if(1==I2C_end) return(1);
else return(0);
}
/****************************************************************************
* 名称:ISendStr()
* 功能:向有子地址器件发送多字节数据。
* 入口参数:sla 器件从机地址
* suba 器件子地址
* s 数据发送缓冲区指针
* no 发送数据个数
* 出口参数:返回值为0时表示出错,为1时表示操作正确。
* 说明:使用前要初始化好I2C引脚功能和I2C中断,并已使能I2C主模式
****************************************************************************/
uint8 ISendStr(uint8 sla, uint8 suba, uint8 *s, uint8 no)
{ /* 参数设置 */
I2C_sla = sla; // 写操作的器件地址
I2C_suba = suba; // 子地址
I2C_buf = s;
I2C_num = no;
I2C_suba_en = 2; // 有子地址写
I2C_end = 0;
I2CONCLR = 0x2C;
I2CONSET = 0x60; // 设置为主机,并启动总线
while(0==I2C_end);
if(1==I2C_end) return(1);
else return(0);
}
/****************************************************************************
* 名称:IRcvByte()
* 功能:向无子地址器件读取一字节数据。
* 入口参数:sla 器件地址
* dat 接收数据的变量指针
* 出口参数:返回值为0时表示操作出错,为1时表示操作正确。
* 说明:使用前要初始化好I2C引脚功能和I2C中断,并已使能I2C主模式
****************************************************************************/
uint8 IRcvByte(uint8 sla, uint8 *dat)
{ /* 参数设置 */
I2C_sla = sla+1; // 读操作的器件地址
I2C_buf = dat;
I2C_num = 1;
I2C_suba_en = 0; // 无子地址
I2C_end = 0;
I2CONCLR = 0x2C;
I2CONSET = 0x60; // 设置为主机,并启动总线
while(0==I2C_end);
if(1==I2C_end) return(1);
else return(0);
}
/****************************************************************************
* 名称:IRcvStr()
* 功能:向有子地址器件读取多字节数据。
* 入口参数:sla 器件地址
* suba 器件子地址
* s 数据接收缓冲区指针
* no 读取数据个数
* 出口参数:返回值为0时表示操作出错,为1时表示操作正确。
* 说明:使用前要初始化好I2C引脚功能和I2C中断,并已使能I2C主模式
****************************************************************************/
uint8 IRcvStr(uint8 sla, uint8 suba, uint8 *s, uint8 no)
{ if(0==no) return(0);
/* 参数设置 */
I2C_sla = sla+1; // 读操作的器件地址
I2C_suba = suba;
I2C_buf = s;
I2C_num = no;
I2C_suba_en = 1; // 有子地址读
I2C_end = 0;
I2CONCLR = 0x2C;
I2CONSET = 0x60; // 设置为主机,并启动总线
while(0==I2C_end);
if(1==I2C_end) return(1);
else return(0);
}
答 1: AT24C01A/02/04/08/16/32/64卡资料1.
这几个型号的IC卡为ATMEL存储卡,是一种不具备加密功能的EEPROM卡,AT24C为系列号,数字部分为K位容量,分别为1K、2K、4K、8k、16K、32K、64K位。它的使用方法与EEPROM完全相同,存储结构简单,只有读写两种操作功能,主要用于存放一些保密性要求不高的数据。
功能:
●容量别为1k/2k/4k/8k/16k/64k bit;
●循环擦写:1,000,000次;
●数据保存期:100年;
●温度范围:-250C-700C;
●结构单一,无分区,只有读、写操作
AT24C系列的工作频率为lMHz(5V),lMHz(2.7V),400KHz(1.8V);工作电压为5V士l0%,根据要求最低可至1.8V;Icc电流读最大为lmA,写最大为3mA:写/擦除次数为l00万次;数据保持lO0年;工作温度为O-70℃,根据要求可超过指定工作温度;通讯协议符合ISO/IEC 7816-3同步协议,双向串行接口。
存储结构:
AT24C系列型号的后两位数字为该型号的最大K位数(1K=1024),8位为1字节,最大字节存储容量的算法为K位数×l024÷8。如:AT24C01A的最大存储容量的1×1024÷8=128,其字节地址空间为O—127(16进制为0x00—0x7F)。
答 2: 用I2C协议给AT24C16卡,读写时总是接收到非ACK应答! 答 3: 对AT24C16卡读写的程序,可以使用。是那个卡座接触不良的原因! 答 4: 4428 io 最低 电压?4428 io h 的最低 电压 和 2114 h 的最到电压 好象不符合。
答 5: 电压的问题卡的高电平最小值》3.3v
答 6: IO口上拉接的是5v电源我给数据线、时钟线、复位线IO口接的上拉电阻电源是5v,IC卡电源也是5v。也没调试通过。现在时间比较急,项目做完了再好好调试一下。
谢谢朋友们了! 答 7: TO:冯广周 AT24C16有分区还是没有分区啊,怎么有人说有而有的说没有呢?怎么回事?郁闷!!
#include "config.h"
#define IC_rst 1<<2
#define IC_clk 1<<3
#define IC_dat 1<<4
#define IC_IN 1<<11 //IC插入
uint8 IcRead[3]={0x0E,0x20,0x00}; //读卡数据命令
uint8 IcWrite[3]={0x33,0x00,0x00}; //写卡数据命令
uint8 IcCheck1[3]={0xCD,0xFE,0xFF}; //密码校验低位
uint8 IcCheck2[3]={0xCD,0xFF,0xFF}; //密码校验高位
uint8 IcRcume[3]={0xCD,0xFD,0x08}; //错误计数器复位
uint8 EnabWrtIc;//IC卡写使能
uint8 ICAddr;
uint8 IcRcv[10];
void DlayNS(uint32 dly)
{
for(;dly>0;dly--);
}
void Clock(void)
{
uint32 regist;
regist=IO0DIR;
IO0CLR=IC_clk;
DlayNS(10); //时钟高、低至少9us
IO0SET=IC_clk;
DlayNS(10); //10us
IO0DIR=regist;
}
void Uart0Send(uint8 dat)
{
U0THR=dat;
while((U0LSR&0x40)==0);
}
void Uart0Int(uint32 BPS)
{
uint16 Fdiv;
PINSEL0|=0x05;
U0LCR=0x83;
Fdiv=(Fpclk/16)/BPS;
U0DLM=Fdiv/256;
U0DLL=Fdiv%256;
U0LCR=0x03;
}
void SendIC(uint8 *buf,uint8 num)
{
uint32 i;
uint8 j;
uint8 dat;
IO0SET=IC_rst;
for(i=0;i<num;i++)
{
dat=*buf;
for(j=0;j<8;j++)
{
if((dat&0x01)!=0)
{
IO0CLR=IC_clk;
DlayNS(90);
IO0SET=IC_dat;//写1
DlayNS(25000);
IO0SET=IC_clk;
DlayNS(90);
}
else
{
IO0CLR=IC_clk;
DlayNS(90);
IO0CLR=IC_dat;//写0
IO0DIR=IC_dat;
DlayNS(25000);
IO0SET=IC_clk;
DlayNS(90);
}
dat>>=1;
}
buf++;
}
IO0CLR=IC_rst;
}
void RcvIC(uint8 num)
{
uint8 i;
uint8 j;
uint32 iodat;
uint8 dat=0x00;
//
IO0CLR=IC_rst;
for(i=0;i<num;i++)
{
for(j=0;j<8;j++)
{
IO0CLR=IC_clk;//clk由1变为0时,开始接收一位数据
DlayNS(25);//延时
IO0SET=IC_clk;
iodat=IO0PIN;
if((iodat&IC_dat)==IC_dat)
{
dat|=(1<<j);
}
else dat=0<<j;
DlayNS(25);
}
IcRcv[i]=dat;
}
IO0SET=IC_rst;
IO0DIR|=IC_dat;
}
uint8 CheckIcMA(void)
{
uint8 err;
uint8 i;
//密码校验
IcRead[0]=0xCE;
IcRead[1]=0xFD;
SendIC(&IcRead[0],0x03);//读错误计数器当前值
RcvIC(1);
if(IcRcv[0]!=0) //不等于0开始校验密码
{
SendIC(&IcCheck1[0],3);//校验第一字节的密码
RcvIC(1);
if(IcRcv[0]==0)
{
SendIC(&IcCheck2[0],3);//校验第二字节的密码
RcvIC(1);
if(IcRcv[0]==0)
{
SendIC(&IcRcume[0],3);//复位错误计数器为8
for(i=0;i<103;i++) //写卡完延续103个脉冲
{
Clock();
}
err=0;
}
else err=1;
}
}
return(err);
}
void ICTransact(void)
{
uint8 stand;
uint8 err;
uint8 i;
//密码校验
err=CheckIcMA();
if(err==0) EnabWrtIc=1;
else EnabWrtIc=0;
//写站台代码及到站时间
if(EnabWrtIc==1)
{
//LED显示开始给IC卡写到站数据
//预写卡地址校验
IcRead[1]=0x08;
SendIC(&IcRead[0],0x03);
RcvIC(0x01);
ICAddr=IcRcv[0];
IcRead[1]=0x09;
SendIC(&IcRead[0],0x03);
RcvIC(0x01);
ICAddr=IcRcv[0]<<8;
IcWrite[1]=ICAddr+1;
IcWrite[0]|=(ICAddr>>8)&0x0C;
IcWrite[2]=stand; //获取站台代码
SendIC(&IcWrite[0],0x03); //写站台代码
for(i=0;i<103;i++)
{
Clock();
}
IcWrite[1]=ICAddr+1;
IcWrite[0]|=(ICAddr>>8)&0x0C;
IcWrite[2]=stand; //获取年
SendIC(&IcWrite[0],0x03); //写到站时间年
for(i=0;i<103;i++)
{
Clock();
}
IcWrite[1]=ICAddr+1;
IcWrite[0]|=(ICAddr>>8)&0x0C;
IcWrite[2]=stand; //获取月
SendIC(&IcWrite[0],0x03); //写到站时间月
for(i=0;i<103;i++)
{
Clock();
}
IcWrite[1]=ICAddr+1;
IcWrite[0]|=(ICAddr>>8)&0x0C;
IcWrite[2]=stand; //获取日
SendIC(&IcWrite[0],0x03); //写到站时间日
for(i=0;i<103;i++)
{
Clock();
}
IcWrite[1]=ICAddr+1;
IcWrite[0]|=(ICAddr>>8)&0x0C;
IcWrite[2]=stand; //获取时
SendIC(&IcWrite[0],0x03); //写到站时间时
for(i=0;i<103;i++)
{
Clock();
}
}
}
uint8 ICReast(void)
{
uint8 i;
uint8 err=0;
//从上电到IC卡复位操作必须大于100us
IO0SET=IC_dat;
IO0CLR=IC_rst;
IO0CLR=IC_clk;
DlayNS(430);
IO0SET=IC_rst;
DlayNS(23);
IO0SET=IC_clk;
DlayNS(45);
IO0CLR=IC_clk;
DlayNS(23);
IO0CLR=IC_rst;
RcvIC(0x04); //读卡复位后的4个数据
for(i=0;i<4;i++)
{
Uart0Send(IcRcv[i]);
}
IO0SET=IC_clk;
DlayNS(15);
IO0CLR=IC_clk;
DlayNS(1);
IO0SET=IC_dat;
return(err);
}
int main(void)
{
uint8 err;
uint8 i;
uint8 sta=0;
PINSEL0=0x00000005;
PINSEL1=0x00000000;
Uart0Int(115200);
IO0DIR=IC_rst|IC_clk|IC_dat;
while(1)
{
err=ICReast();
if(err==1) ICReast();
else sta=1;
//读IC卡数据
while(sta==1)
{
SendIC(&IcRead[0],0x03);//写命令
RcvIC(3);
for(i=0;i<3;i++)
{
//读数据
Uart0Send(IcRcv[i]);
}
IcRead[1]+=1;
if(IcRead[1]>=0xFF)
{
IcRead[1]=0x00;
}
}
}
}
sle4428卡资料:http://www.21ic.com/news/n1283c78.aspx
二:使用LPC2114单片机通过I2C接口加上拉电阻(4.7K),与AT24C16卡连接读写数据。无法读去IC卡数据,单可以对AT24C01EEPROM芯片进行读写操作。程序如下希望朋友们看一下:
#include "config.h"
#define power 1<<4;
extern void __irq IRQ_I2C(void);
extern uint8 IRcvStr(uint8 sla, uint8 suba, uint8 *s, uint8 no);
extern uint8 ISendStr(uint8 sla, uint8 suba, uint8 *s, uint8 no);
extern uint8 ISendByte(uint8 sla, uint8 dat);
extern uint8 IRcvByte(uint8 sla, uint8 *dat);
void I2Cint(uint32 fi2c)
{
//PINSEL0=0x50;
I2SCLH=(Fpclk/fi2c+1)/2;
I2SCLL=(Fpclk/fi2c)/2;
I2CONCLR=0x2C;
I2CONSET=0x40;
VICIntSelect=0x00000000;
VICVectCntl0=0x29;
VICVectAddr0=(uint32)IRQ_I2C;
VICIntEnable=(1<<9);
}
void Uart0Send(uint8 dat)
{
U0THR=dat;
while((U0LSR&0x40)==0);
}
void Uart0Int(uint32 BPS)
{
uint16 Fdiv;
//PINSEL0|=0x05;
U0LCR=0x83;
Fdiv=(Fpclk/16)/BPS;
U0DLM=Fdiv/256;
U0DLL=Fdiv%256;
U0LCR=0x03;
}
void DelayNS(uint32 dly)
{ uint32 i;
for(; dly>0; dly--)
for(i=0; i<50000; i++);
}
int main(void)
{
uint8 i;
uint8 dat=0x11;
uint8 err0,err1;
uint8 dat2[8];
uint8 dat1[8]={0x05,0x06,0x07,0x08,0x05,0x06,0x07,0x08};
PINSEL0=0x00000055;
PINSEL1=0x00000000;
IO0DIR=0x1C;
I2Cint(9600);
Uart0Int(115200);
while(1)
{
loop:
IO0SET=power;
err0=ISendStr(0xA0, 0x60, &dat1[0],0x08);
IO0CLR=power;
if(err0==0)
{
dat+=0x10;
goto loop;
}
else
{
DelayNS(1);
dat=0x10;
loop1:
IO0SET=power;
err1=IRcvStr(0xA0, 0x60, &dat2[0], 0x08);
IO0CLR=power;
if(err1==0)
{
dat+=0x10;
goto loop1;
}
else
{
for(i=0;i<8;i++)
{
Uart0Send(dat2[i]);
}
}
dat=0x01;
DelayNS(1);
}
}
}
/****************************************************************************
* 文件名:I2CINT.C
* 功能:硬件I2C软件包,利用中断方式操作。
* 说明:主程序要配置好I2C总线接口(I2C引脚功能和I2C中断,并已使能I2C主模式)
****************************************************************************/
#include "config.h"
/* 以下为I2C操作时所需要的变量 */
volatile uint8 I2C_sla; // 从机地址(即器件地址)
volatile uint8 I2C_suba; // 子地址
volatile uint8 *I2C_buf; // 数据缓冲区指针 (读操作时会被更改)
volatile uint8 I2C_num; // 操作数据个数 (会被更改)
volatile uint8 I2C_end; // 操作结束标志,为1时表示操作结束,为0xFF时表示操作失败 (会被设置)
volatile uint8 I2C_suba_en; // 子地址使能控制,读操作时请设置为1,写操作时请设置为2 (会被更改)
void DelayMS(uint32 dly)
{
uint8 i;
for(;dly>0;dly--)
for(i=0;i<100;i++);
}
/****************************************************************************
* 名称:IRQ_I2C()
* 功能:I2C中断,通过判断I2C状态字进行相应的操作。
* 入口参数:无
* 出口参数:无
****************************************************************************/
void __irq IRQ_I2C(void)
{ uint8 sta;
sta = I2STAT; // 读出I2C状态字
switch(sta)
{ case 0x08: // 己发送起始条件
if(1==I2C_suba_en) I2DAT = I2C_sla&0xFE; // 指定子地址读时,先写入地址
else I2DAT = I2C_sla; // 否则直接发送从机地址
I2CONCLR = 0x28; // SI=0
break;
case 0x10:
I2DAT = I2C_sla; // 重启动总线后,发送从地址
I2CONCLR = 0x28; // SI=0
break;
case 0x18: // 已发送SLA+W,并已接收应答
if(0==I2C_suba_en) // 无子地址,则直接发送数据
{ if(I2C_num>0)
{ I2DAT = *I2C_buf++;
I2CONCLR = 0x28;
I2C_num--;
}
else
{ I2CONSET = 0x10; // 无数据发送,结束总线
I2CONCLR = 0x28;
I2C_end = 1; // 设置总线操作结束标志
}
break;
}
if(1==I2C_suba_en) // 发送子地址
{ I2DAT = I2C_suba;
I2CONCLR = 0x28;
}
if(2==I2C_suba_en)
{ I2DAT = I2C_suba;
I2CONCLR = 0x28;
I2C_suba_en = 0; // 子地址己处理
}
break;
case 0x28: // 已发送I2C数据,并接收到应答
if(0==I2C_suba_en) // 无子地址,则直接发送数据
{ if(I2C_num>0)
{ I2DAT = *I2C_buf++;
I2CONCLR = 0x28;
I2C_num--;
}
else
{ I2CONSET = 0x10; // 无数据发送,结束总线
I2CONCLR = 0x28;
I2C_end = 1;
}
break;
}
if(1==I2C_suba_en) // 若是指定地址读,则重新启动总线
{ I2CONSET = 0x20;
I2CONCLR = 0x08;
I2C_suba_en = 0; // 子地址己处理
}
break;
case 0x20:
case 0x30:
case 0x38:
I2CONCLR = 0x28; // 总线进入不可寻址从模式
I2C_end = 0xFF; // 总线出错,设置标志
break;
case 0x40: // 己发送SLA+R,并已接收到应答
if(1==I2C_num) // 最后一字节,接收数据后发送非应答信号
{ I2CONCLR = 0x2C; // AA=0,接收到数据后产生非应答
}
else // 接收数据并发送应答信号
{ I2CONSET = 0x04; // AA=1,接收到数据后产生应答
I2CONCLR = 0x28;
}
break;
case 0x50:
*I2C_buf++ = I2DAT; // 读取数据
I2C_num--;
if(1==I2C_num)
{ I2CONCLR = 0x2C; // AA=0,接收到数据后产生非应答
}
else
{ I2CONSET = 0x04; // AA=1,接收到数据后产生应答
I2CONCLR = 0x28;
}
break;
case 0x58:
*I2C_buf++ = I2DAT; // 读取最后一字节数据
I2CONSET = 0x10; // 结束总线
I2CONCLR = 0x28;
I2C_end = 1;
break;
case 0x48:
I2CONCLR = 0x28; // 总线进入不可寻址从模式
I2C_end = 0xFF;
break;
default:
break;
}
VICVectAddr = 0x00; // 中断处理结束
}
/****************************************************************************
* 名称:ISendByte()
* 功能:向无子地址器件发送一字节数据。
* 入口参数:sla 器件地址
* dat 要发送的数据
* 出口参数:返回值为0时表示出错,为1时表示操作正确。
* 说明:使用前要初始化好I2C引脚功能和I2C中断,并已使能I2C主模式
****************************************************************************/
uint8 ISendByte(uint8 sla, uint8 dat)
{ /* 参数设置 */
I2C_sla = sla; // 写操作的器件地址
I2C_buf = &dat; // 待发送的数据
I2C_num = 1; // 发送1字节数据
I2C_suba_en = 0; // 无子地址
I2C_end = 0;
I2CONCLR = 0x2C;
I2CONSET = 0x60; // 设置为主机,并启动总线
while(0==I2C_end);
if(1==I2C_end) return(1);
else return(0);
}
/****************************************************************************
* 名称:ISendStr()
* 功能:向有子地址器件发送多字节数据。
* 入口参数:sla 器件从机地址
* suba 器件子地址
* s 数据发送缓冲区指针
* no 发送数据个数
* 出口参数:返回值为0时表示出错,为1时表示操作正确。
* 说明:使用前要初始化好I2C引脚功能和I2C中断,并已使能I2C主模式
****************************************************************************/
uint8 ISendStr(uint8 sla, uint8 suba, uint8 *s, uint8 no)
{ /* 参数设置 */
I2C_sla = sla; // 写操作的器件地址
I2C_suba = suba; // 子地址
I2C_buf = s;
I2C_num = no;
I2C_suba_en = 2; // 有子地址写
I2C_end = 0;
I2CONCLR = 0x2C;
I2CONSET = 0x60; // 设置为主机,并启动总线
while(0==I2C_end);
if(1==I2C_end) return(1);
else return(0);
}
/****************************************************************************
* 名称:IRcvByte()
* 功能:向无子地址器件读取一字节数据。
* 入口参数:sla 器件地址
* dat 接收数据的变量指针
* 出口参数:返回值为0时表示操作出错,为1时表示操作正确。
* 说明:使用前要初始化好I2C引脚功能和I2C中断,并已使能I2C主模式
****************************************************************************/
uint8 IRcvByte(uint8 sla, uint8 *dat)
{ /* 参数设置 */
I2C_sla = sla+1; // 读操作的器件地址
I2C_buf = dat;
I2C_num = 1;
I2C_suba_en = 0; // 无子地址
I2C_end = 0;
I2CONCLR = 0x2C;
I2CONSET = 0x60; // 设置为主机,并启动总线
while(0==I2C_end);
if(1==I2C_end) return(1);
else return(0);
}
/****************************************************************************
* 名称:IRcvStr()
* 功能:向有子地址器件读取多字节数据。
* 入口参数:sla 器件地址
* suba 器件子地址
* s 数据接收缓冲区指针
* no 读取数据个数
* 出口参数:返回值为0时表示操作出错,为1时表示操作正确。
* 说明:使用前要初始化好I2C引脚功能和I2C中断,并已使能I2C主模式
****************************************************************************/
uint8 IRcvStr(uint8 sla, uint8 suba, uint8 *s, uint8 no)
{ if(0==no) return(0);
/* 参数设置 */
I2C_sla = sla+1; // 读操作的器件地址
I2C_suba = suba;
I2C_buf = s;
I2C_num = no;
I2C_suba_en = 1; // 有子地址读
I2C_end = 0;
I2CONCLR = 0x2C;
I2CONSET = 0x60; // 设置为主机,并启动总线
while(0==I2C_end);
if(1==I2C_end) return(1);
else return(0);
}
答 1: AT24C01A/02/04/08/16/32/64卡资料1.
这几个型号的IC卡为ATMEL存储卡,是一种不具备加密功能的EEPROM卡,AT24C为系列号,数字部分为K位容量,分别为1K、2K、4K、8k、16K、32K、64K位。它的使用方法与EEPROM完全相同,存储结构简单,只有读写两种操作功能,主要用于存放一些保密性要求不高的数据。
功能:
●容量别为1k/2k/4k/8k/16k/64k bit;
●循环擦写:1,000,000次;
●数据保存期:100年;
●温度范围:-250C-700C;
●结构单一,无分区,只有读、写操作
AT24C系列的工作频率为lMHz(5V),lMHz(2.7V),400KHz(1.8V);工作电压为5V士l0%,根据要求最低可至1.8V;Icc电流读最大为lmA,写最大为3mA:写/擦除次数为l00万次;数据保持lO0年;工作温度为O-70℃,根据要求可超过指定工作温度;通讯协议符合ISO/IEC 7816-3同步协议,双向串行接口。
存储结构:
AT24C系列型号的后两位数字为该型号的最大K位数(1K=1024),8位为1字节,最大字节存储容量的算法为K位数×l024÷8。如:AT24C01A的最大存储容量的1×1024÷8=128,其字节地址空间为O—127(16进制为0x00—0x7F)。
答 2: 用I2C协议给AT24C16卡,读写时总是接收到非ACK应答! 答 3: 对AT24C16卡读写的程序,可以使用。是那个卡座接触不良的原因! 答 4: 4428 io 最低 电压?4428 io h 的最低 电压 和 2114 h 的最到电压 好象不符合。
答 5: 电压的问题卡的高电平最小值》3.3v
答 6: IO口上拉接的是5v电源我给数据线、时钟线、复位线IO口接的上拉电阻电源是5v,IC卡电源也是5v。也没调试通过。现在时间比较急,项目做完了再好好调试一下。
谢谢朋友们了! 答 7: TO:冯广周 AT24C16有分区还是没有分区啊,怎么有人说有而有的说没有呢?怎么回事?郁闷!!
共3条
1/1 1 跳转至页
回复
有奖活动 | |
---|---|
【有奖活动】分享技术经验,兑换京东卡 | |
话不多说,快进群! | |
请大声喊出:我要开发板! | |
【有奖活动】EEPW网站征稿正在进行时,欢迎踊跃投稿啦 | |
奖!发布技术笔记,技术评测贴换取您心仪的礼品 | |
打赏了!打赏了!打赏了! |
打赏帖 | |
---|---|
vscode+cmake搭建雅特力AT32L021开发环境被打赏30分 | |
【换取逻辑分析仪】自制底板并驱动ArduinoNanoRP2040ConnectLCD扩展板被打赏47分 | |
【分享评测,赢取加热台】RISC-V GCC 内嵌汇编使用被打赏38分 | |
【换取逻辑分析仪】-基于ADI单片机MAX78000的简易MP3音乐播放器被打赏48分 | |
我想要一部加热台+树莓派PICO驱动AHT10被打赏38分 | |
【换取逻辑分析仪】-硬件SPI驱动OLED屏幕被打赏36分 | |
换逻辑分析仪+上下拉与多路选择器被打赏29分 | |
Let'sdo第3期任务合集被打赏50分 | |
换逻辑分析仪+Verilog三态门被打赏27分 | |
换逻辑分析仪+Verilog多输出门被打赏24分 |