读hex文件 c语言读取十六进制文件.hex(Qt实现)

本文详细介绍了一种在Qt环境下实现的HEX文件解析与转换的方法。通过代码示例,展示了如何读取HEX文件,并将其转换为特定的地址加数据格式。解析过程包括效验算法、数据类型判断及地址计算等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

将HEX文件读写成地址加数据的格式,HEX文件格式可以参考

https://blog.youkuaiyun.com/a1037488611/article/details/43340055

文档中有关与效验算法方面的有点问题,可以参考本人效验代码

 

以下是我在Qt上实现的完整代码

#include<stdio.h>
#include<stdlib.h>
#include<QDebug>
#include<QString>
#include<QByteArray>
#include<QDebug>
#include<QFile>
#include<QDataStream>

static char pq=9;  //规范代码

/****16进制的数据类型*****/
const QString HexTypeTable[6] =
{
    "00","01","02","03","04","05",
};

/****配套数据类型使用的枚举变量*****/
typedef enum __tagHexType
{
    RECORD_DATA = 0,
    RECORD_END_OF_FILE,
    RECORD_EXTENDED_SEGMENT_ADDRESS,
    RECORD_START_SEGMENT_ADDRESS,
    RECORD_EXTENDED_LINEAR_ADDRESS,
    RECORD_START_LINEAR_ADDRESS,
    RECORD_HEX_MAX,
}emHexType;

typedef enum Boolsymbol
{
    DATA_Flase = 0,
    DATA_Ture
}BoolTureFlase;

 //定义字符串的类型格式
typedef struct StringTypes
{
    char Firstsymbolis;
    char StringCrcis;
    char StringSizeis;
    char StringResultis;
    char StringType;
    //QString BaseAddress;
}StringType;

static StringType StringTypeLine={DATA_Ture,DATA_Ture,DATA_Ture,DATA_Ture,RECORD_DATA};   //定义字符串的类型格式

/****函数声明*********/
QString AnalyseHEX(QByteArray dest);
int mystrlen(const char *StrDest);
int HexToDec(char *src);
QString QStringLeftBit(QString src,int num);
QString QStringToAdd(QString dest,QString src);
StringType FormatHexjudge(QByteArray src);
QString BaseAddjudge(QByteArray src);
void ReadWrite(QString filenameread,QString filenameWrite);


/****计算字符串长度*****/
int mystrlen(const char *StrDest)
{
    int i;
    i=0;
    while((*StrDest++)!='\0')
    {
        i++;
    }//这个循环体意思是从字符串第一个字符起计数,只遇到字符串结束标志'\0’才停止计数
    return i;
}

/****16进制转换10进制*****/
int HexToDec(char *src)
{
    //将src中的无符号十六进制字符串转为十进制数
    //如src="001A",则返回26
    //字符串src需要以'\0'作为结束标志
    int value=0,srclen=mystrlen(src);
    int i;
    for(i=0;i<srclen;i++)
    {
        if(src[i]<='9'&&src[i]>='0')
        {
            value=value*16+(int)(src[i]-'0'); //'0'
        }
        else if(src[i]<='f'&&src[i]>='a')
        {
            value=value*16+(int)(src[i]-'a'+10);
        }
        else
        {
            value=value*16+(int)(src[i]-'A'+10);
        }
    }
    return value;//返回转换后的数值
}


/****字符串效验*返回效验的十进制数用来与字符串后两位做比较****/
QString AnalyseHEX(QByteArray dest)
{
   unsigned char i=1;
   int tempsum=0;   //必须初始化,否则乱码
   QString stype;
   QString ZERO="0";
   QString Date0x100="100";
   QString result;
   do
   {
       stype = dest.mid(i,2);    //转换成10进制运算后,再转换成十六进制

       printf(" %d",HexToDec(stype.toLatin1().data()));
       tempsum+=HexToDec(stype.toLatin1().data());
       i+=2;
   } while (i<(mystrlen(dest)-2));

   /***HEX计算公式(0x100-(16进制数据和后两位))再取后两位=字符串后两位*****/
   result=QString::number((HexToDec(Date0x100.toLatin1().data())-HexToDec
                           (QString::number(tempsum,16).right(2).toLatin1().data())),16);

   if(result.size()<2)
   {
      int count=2-result.size();
      //printf("count=2-result.right(2).size()=%d\n",count);
       while(count-->0)
       {
         result.insert(0,ZERO);
       }
   }
   //qDebug()<<"result.right(2).toUpper()"<<result.right(2).toUpper();
   return result.right(2).toUpper();

}


/***0613*****字符串左移num位*****************/
 QString QStringLeftBit(QString src,int num)  //
 {
     QString zero="0";
     while(num-->0)
     {
         src.insert(src.size()-2,zero);  //末尾位加零
         src.remove(0,1);    //删除起始位
     }
     return src;
 }


 /***0613*****字符串以十六进制的形式转换成十进制相加,然后转换成十六进制的字符串形式输出*****/
 QString QStringToAdd(QString dest,QString src)
 {
     QString ResultDate;
     QString ZERO="0";

     int num1,num2,ans;
     int count;
     bool ok;
     num1=dest.toInt(&ok,16);  //转换成10进制
     num2=src.toInt(&ok,16);
     ans=num1+num2;
     ResultDate=QString::number(ans,16);

     /**判断结果字符串与输入的两个字符串的最大差值,用于给结果字符串补零***/
     (dest.size()-ResultDate.size()>src.size()-ResultDate.size())?
                 count=dest.size()-ResultDate.size():count=src.size()-ResultDate.size();

     while(count-->0)
     {
         ResultDate.insert(0,ZERO);
     }

    return  ResultDate.toUpper();//十进制转换成Qstring的形式输出  toUpper() //转换成大写字母
 }


/****文件格式类型判断,有错误打印,返回值为基地址******/
StringType FormatHexjudge(QByteArray src) //QString *resultBaseAddres
{
    QByteArray resultString=":00000001FF";
    static uint32_t count_num=0;
    count_num++;
    /******验证一下传入的数据***********/

    char *pcdata = src.data();

    //printf("Length of src:%d\n",mystrlen(src));   //打印传入数据大小
    while(*pcdata)
    {
        //printf("%c",*pcdata);  //打印原始数据
        ++pcdata;
    }
    //printf("\n");

    if(src.left(1)!=":")
    {//不是以":"开始
            StringTypeLine.Firstsymbolis=DATA_Flase;
            printf("Format FirstSymbol wrong!\n");
            system("Pause");
    }
    else
    {
       StringTypeLine.Firstsymbolis=DATA_Ture;
    }
    if(strlen(src)<11)
    {//字符串长度小于11
            printf("Format length wrong!\n");
            system("Pause");
     }
    else
    {
        StringTypeLine.StringSizeis=DATA_Flase;
    }
    if(strcmp(src,resultString)==0)
    {//结束标志
            StringTypeLine.StringResultis=DATA_Ture;
            printf("End of file\n");

    }
    else
    {
        StringTypeLine.StringResultis=DATA_Flase;
    }

    if(src.right(2)!= AnalyseHEX(src))    //字符效验
    {
        StringTypeLine.StringCrcis=DATA_Flase;  //字符效验失败
        printf("\nSerialcount  is  wrong in  Address=%d\n",count_num);
        printf("XiaoYan_cc:%c%c\n",*src.right(2).data(),*(src.right(2).data()+1));

        printf("\nXiaoYan_calcu_int:%d\n",AnalyseHEX(src).toInt());
        printf("XiaoYan_read_int:%d\n",HexToDec(src.right(2).data()));     //读出来的效验值

        system("Pause");  //如果效验值错误,暂停界面
    }
    else
    {
        StringTypeLine.StringCrcis=DATA_Ture;    //字符效验正确
        //printf("\nFormat Effect Vaild!!!!!\n");
        while(mystrlen(src)-2>pq)   //打印完所有的数据
        {
          QString st = src.mid(pq,2);
          pq+=2;

          printf("%c%c ",*st.toLatin1().data(),*(st.toLatin1().data()+1));
        }
    }

     /****判断数据类型****/

    QString stringtype = src.mid(7,2);
    //printf("\nstringtype: %c%c\n",*stringtype.toLatin1().data(),*(stringtype.toLatin1().data()+1));

    if(stringtype==HexTypeTable[RECORD_DATA])
    {  //00正常数据类型

        StringTypeLine.StringType=RECORD_DATA;

        QString styadd = src.mid(3,4);
       /****只是分割字符串****/
       // printf("styadd:%c%c%c%c\n",*styadd.toLatin1().data(),*(styadd.toLatin1().data()+1),*(styadd.toLatin1().data()+2),*(styadd.toLatin1().data()+3));
    }
    else if (stringtype==HexTypeTable[RECORD_END_OF_FILE])
    {  //01 用来标识文件结束
       StringTypeLine.StringType=RECORD_END_OF_FILE;
       printf("RECORD_END_OF_FILE\n ");

    }
    else if (stringtype==HexTypeTable[RECORD_EXTENDED_LINEAR_ADDRESS])  //TODO:只需要判断一次
    {  //04 扩展线性地址记录

        StringTypeLine.StringType=RECORD_EXTENDED_LINEAR_ADDRESS;
        printf("RECORD_EXTENDED_LINEAR_ADDRESS \n");
        QString styadd = src.mid(3,4);
        QString styaddsub = src.mid(9,4);   //字符串拼接

        styadd.insert(0,styaddsub);
        //printf("StyaddSub04:%c%c%c%c%c%c%c%c\n",*styadd.toLatin1().data(),*(styadd.toLatin1().data()+1),
        //        *(styadd.toLatin1().data()+2),*(styadd.toLatin1().data()+3),*(styadd.toLatin1().data()+4),*(styadd.toLatin1().data()+5),*(styadd.toLatin1().data()+6),*(styadd.toLatin1().data()+7));

       //system("Pause");
    }
    else if(stringtype==HexTypeTable[RECORD_EXTENDED_SEGMENT_ADDRESS])
    {  //02 扩展段地址记录
        StringTypeLine.StringType=RECORD_EXTENDED_SEGMENT_ADDRESS;
        printf("RECORD_EXTENDED_SEGMENT_ADDRESS\n");

    }
    else if(stringtype==HexTypeTable[RECORD_START_LINEAR_ADDRESS])
    {  //05 开始线性地址记录
        StringTypeLine.StringType=RECORD_START_LINEAR_ADDRESS;
        printf("RECORD_START_LINEAR_ADDRESS\n");

    }
    else if(stringtype==HexTypeTable[RECORD_START_SEGMENT_ADDRESS])
    {  //03 开始段地址记录
       StringTypeLine.StringType=RECORD_START_SEGMENT_ADDRESS;
       printf("RECORD_START_SEGMENT_ADDRESS\n");

       system("Pause");    //如果遇到03则暂停,预留处理03的代码  (0613/还未遇到)
    }
    return StringTypeLine;
}


/******判断基地址**如果数据类型为04调用*******/
QString BaseAddjudge(QByteArray src)
{
  QString resultBaseAddres;
  QString stringtype = src.mid(7,2);         /****判断数据类型****/
  if (stringtype==HexTypeTable[RECORD_EXTENDED_LINEAR_ADDRESS])  //TODO:只需要判断一次RECORD_EXTENDED_LINEAR_ADDRESS
  {  //04 扩展线性地址记录
      QString styadd = src.mid(3,4);
      QString styaddsub = src.mid(9,4);   //字符串拼接

      styadd.insert(0,styaddsub);
      printf("StyaddSub04:%c%c%c%c%c%c%c%c\n",*styadd.toLatin1().data(),*(styadd.toLatin1().data()+1),
              *(styadd.toLatin1().data()+2),*(styadd.toLatin1().data()+3),*(styadd.toLatin1().data()+4),*(styadd.toLatin1().data()+5),*(styadd.toLatin1().data()+6),*(styadd.toLatin1().data()+7));

      return styadd;

  }

  if (stringtype==HexTypeTable[RECORD_EXTENDED_SEGMENT_ADDRESS])  //TODO:只需要判断一次RECORD_EXTENDED_LINEAR_ADDRESS
  {  //02 扩展段地址记录

      QString Basezer0 = "0000";
      QString styaddsub = src.mid(9,4);   //字符串拼接

      Basezer0.insert(4,styaddsub);
      Basezer0=QStringLeftBit(Basezer0,1);

      printf("StyaddSub02:%c%c%c%c%c%c%c%c\n",*Basezer0.toLatin1().data(),*(Basezer0.toLatin1().data()+1),
              *(Basezer0.toLatin1().data()+2),*(Basezer0.toLatin1().data()+3),*(Basezer0.toLatin1().data()+4),*(Basezer0.toLatin1().data()+5),*(Basezer0.toLatin1().data()+6),*(Basezer0.toLatin1().data()+7));

      return Basezer0; //在02数据类型的方式下需要左移一位
  }
  return resultBaseAddres;
}


/****新字符串拼接*****/
QString FormatTranQARRYbyte(QByteArray src)
{
    char count=9;
    char newcount=10;
    QString ResultDate;
    static QString resultBaseAddress="00000000";             //static 修饰只初始化一次 //0x08000000
    QString space=" ";

    StringTypeLine=FormatHexjudge(src);

    if(StringTypeLine.StringCrcis==DATA_Ture)   //如果效验码正确
    {
        if(StringTypeLine.StringType==RECORD_EXTENDED_LINEAR_ADDRESS)       //如果是扩展性数据类型 04
        {
                resultBaseAddress=BaseAddjudge(src);            //接收扩展地址
                qDebug()<<"resultBaseAddress"<<resultBaseAddress;
        }

        if(StringTypeLine.StringType==RECORD_EXTENDED_SEGMENT_ADDRESS)       //如果是段数据类型 02
        {
                resultBaseAddress=BaseAddjudge(src);
                qDebug()<<"resultBaseAddress"<<resultBaseAddress;
        }

        ResultDate=resultBaseAddress; //第一个是地址
        ResultDate=QStringToAdd(ResultDate,src.mid(3,4));  //基地址和绝对地址相加

        if(StringTypeLine.Firstsymbolis==DATA_Ture)   //如果字符串的第一个符号是“:”
        {
         ResultDate.insert(8,src.left(1));    //插入符号
         ResultDate.insert(9,space);
        }

        while(mystrlen(src)-2>count)   //打印完所有的数据
        {
          ResultDate.insert(newcount,src.mid(count,2));
          newcount=newcount+3;

          ResultDate.insert(newcount,space);
          count=count+2;
        }

        if(StringTypeLine.StringType==RECORD_DATA)    //当数据类型为00的时候才打印
        {
         printf("\n");
         qDebug()<<"ResultDate  "<<ResultDate<<endl<<endl<<endl;
        }
    }
  return ResultDate;
}


#if 0
/***按行读取HEX文件并进行处理*****/
void read(QString filename)
 {
     QFile file(filename);
     if(!file.open(QFile::ReadOnly | QFile::Text))
     {
         qDebug() << " Could not open the file for reading";
         return;
     }

     QTextStream in(&file);
     while(!in.atEnd())
     {
     QString myText = in.readLine();

     QString str(myText);
     QByteArray bytes = str.toLatin1();   //Qstring 转 QByteArray
     qDebug() << bytes;

     FormatTranQARRYbyte(bytes);

     printf("\n\n\n");
     }

     file.close();
 }

/***按行读取HEX文件并进行处理*****/
void Write(QString filename)
{
    QFile file(filename);
    if(!file.open(QFile::WriteOnly | QFile::Text))
    {
        qDebug() << " Could not open the file for reading";
        return;
    }
    //QTextStream stream(&file);
    //stream.seek(file.size());
    QString resultString=":00000001FF\n";
    QString EnterResul="\n";
    QByteArray AER=":10246200464c5549442050524f46494c4500464c33";

    file.write(FormatTranQARRYbyte(AER).toUtf8());
    file.write(EnterResul.toUtf8());
    file.write(resultString.toUtf8());

   file.close();
   return;
}
#endif

/***按行读取HEX文件并进行处理*****/
void ReadWrite(QString filenameread,QString filenameWrite)
 {
     QString EnterResul="\n";
     QFile fileread(filenameread);
     if(!fileread.open(QFile::ReadOnly | QFile::Text))
     {
         qDebug() << " Could not open the file for reading";
         return;
     }


     QFile filewrite(filenameWrite);
     if(!filewrite.open(QFile::WriteOnly | QFile::Text))
     {
         qDebug() << " Could not open the file for reading";
         return;
     }

     QTextStream in(&fileread);
     while(!in.atEnd())
     {
         QString myText = in.readLine();

         QString str(myText);
         QByteArray bytes = str.toLatin1();   //Qstring 转 QByteArray
         qDebug() << bytes;

         QString ResultText;
         ResultText=FormatTranQARRYbyte(bytes);
         if(StringTypeLine.StringType==RECORD_DATA)        //只将数据类型为 00 的字符串写入
         {
             filewrite.write(ResultText.toUtf8());                 //写入数据
             filewrite.write(EnterResul.toUtf8());                     //写入回车
         }
         printf("\n");
     }

     fileread.close();
     filewrite.close();
 }



/**0613生成成功**/
int main()
{
     QString filename = "C:/Users/Administrator/Desktop/HEX2/VCU_S32K14X.hex";
     //QString filename = "C:/Users/Administrator/Desktop/HEX2/Projec.hex";
     QString filewritename = "C:/Users/Administrator/Desktop/HEX2/Pro1.hex";


    //QByteArray AER=":020000040800F2";
   // QByteArray AER=":105CC00010831C46234618465DF8044B704708B500";
    //FormatTranQARRYbyte(AER);

     ReadWrite(filename,filewritename);

}

以下为Notepad++打开的原Hex文件

经过代码(以上代码C语言)读取生成的文件

通过软件转换的文件

<think>好的,用户的问题是关于如何通过程序或设备读取IC卡的数据,并且希望有示例代码。首先,我需要回忆一下IC卡的基本知识,以及常见的读取方法。根据用户提供的引用内容,他们提到了Qt/C++、STM32和RC522模块,还有Android和Linux系统。这可能意味着用户对嵌入式系统和不同平台的开发感兴趣。 首先,IC卡的数据读取通常涉及硬件写器,比如RC522模块,这在引用[2]中提到过。STM32通过RC522模块进行写,流程包括请求卡、防冲突、选卡、验证密码和操作数据。这些步骤需要按照一定的协议来操作,可能是ISO 14443标准。 用户可能需要具体的代码示例,所以应该考虑给出不同平台的例子。比如,在Arduino环境下使用RC522的代码,或者在STM32上的C语言示例,还有Qt/C++的代码片段。同时,用户可能也需要了解基本的流程,比如如何初始化设备、寻卡、验证密钥、读取数据块等。 另外,引用[1]提到了修改IC卡认证密钥,这可能涉及到每个扇区的访问控制,所以在代码示例中需要注意权限问题,比如密钥验证后才能写数据。每个扇区有多个块,通常最后一块是控制块,存储密钥和存取控制位,这些信息需要正确处理,避免误操作导致卡片锁死。 还需要考虑不同操作系统的支持,比如Windows、国产Linux和Android,可能需要不同的库或驱动。例如,在Qt中可能使用串口通信或特定的库来与卡器交互,而在Android上可能需要使用NFC API。 可能还需要提到注意事项,比如密钥的安全性,操作时的错误处理,以及不同IC卡类型(如MIFARE Classic)的具体操作差异。用户可能需要知道如何获取卡片的UID,如何选择不同的扇区,以及如何解析读取到的数据。 最后,根据用户的要求,生成相关问题,比如性能优化、多平台兼容性处理、数据加密方法等,帮助用户进一步深入了解。</think>### IC卡数据读取方法及示例代码 IC卡数据读取需结合硬件写器和协议指令,下面以MIFARE Classic S50卡为例说明常见操作流程和代码实现。 #### 一、硬件准备 1. 写器模块:RC522、PN532等支持ISO14443-A协议的设备 2. 开发平台:STM32/Arduino/Raspberry Pi 3. 连接方式:SPI/I2C/UART接口(RC522常用SPI) #### 二、基本操作流程 $$ \begin{aligned} &1.\ 寻卡 \rightarrow 2.\ 防冲突 \rightarrow 3.\ 选卡 \\ &4.\ 验证密钥 \rightarrow 5.\ 写数据块 \end{aligned} $$ #### 三、Arduino示例代码(使用MFRC522库) ```cpp #include <SPI.h> #include <MFRC522.h> #define RST_PIN 9 #define SS_PIN 10 MFRC522 mfrc522(SS_PIN, RST_PIN); void setup() { Serial.begin(9600); SPI.begin(); mfrc522.PCD_Init(); } void loop() { // 寻卡 if (!mfrc522.PICC_IsNewCardPresent()) return; // 读取序列号 if (!mfrc522.PICC_ReadCardSerial()) return; // 显示卡号 Serial.print("Card UID:"); for (byte i = 0; i < mfrc522.uid.size; i++) { Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "); Serial.print(mfrc522.uid.uidByte[i], HEX); } Serial.println(); // 验证密钥(默认密钥FF FF FF FF FF FF) MFRC522::MIFARE_Key key; for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF; // 读取第1扇区0块数据 byte sector = 1; byte blockAddr = 4; // 扇区1的第一个数据块 byte buffer[18]; byte size = sizeof(buffer); if (mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, blockAddr, &key, &(mfrc522.uid)) == MFRC522::STATUS_OK) { if (mfrc522.MIFARE_Read(blockAddr, buffer, &size) == MFRC522::STATUS_OK) { Serial.print("Data: "); for (byte i = 0; i < 16; i++) { Serial.print(buffer[i] < 0x10 ? " 0" : " "); Serial.print(buffer[i], HEX); } Serial.println(); } } mfrc522.PICC_HaltA(); } ``` #### 四、STM32操作要点(HAL库) 1. 初始化SPI通信协议 2. 配置RC522寄存器 3. 实现防冲突算法 ```c // 获取卡片类型 res = MFRC522_Request(PICC_REQIDL, &TagType); // 防冲突获取UID res = MFRC522_Anticoll(&serNum); // 选择卡片 MFRC522_SelectTag(serNum); // 验证密钥 MFRC522_Auth(PICC_AUTHENT1A, BlockAddr, KEY, serNum); // 数据 MFRC522_Read(BlockAddr, buffer); ``` #### 五、Qt/C++实现要点 ```cpp // 使用QSerialPort与卡器通信 QSerialPort serial; serial.setPortName("COM3"); serial.setBaudRate(115200); if(serial.open(QIODevice::ReadWrite)){ // 发送APDU指令 QByteArray cmd = QByteArray::fromHex("FF CA 00 00 00"); serial.write(cmd); QByteArray response = serial.readAll(); // 解析返回的UID数据 } ``` #### 六、注意事项 1. 每个扇区包含4个数据块(16字节/块),最后一块为控制块[^2] 2. 修改数据前必须验证密钥(Key A/B)[^1] 3. 块0包含厂商信息,不可修改 4. 写操作建议先验证再操作,避免卡片进入休眠状态
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值