引言
调试代码过程中经常将变量储存在大数组中,以分析数据的变化趋势。使用TI的ccs时,数组可以方便的导出。但是keil并没有直接导出数组的功能,好在keil提供了其他方法。Keil无法导出watch窗口的内容,但是可以导出memory窗口的内容。那么,怎么从导出的内容中解析出想要的数据呢?
一、导出到文件
导出方式如下:
1、 将需要导出的变量添加到memory窗口
2、 使用sava命令导出内存区域
Save命令格式如下:
SAVE d:data.txt 0x20000924,0x20000924 – 1 + 1000
其中d:data.txt为要导出文件的路径,0x20000924为要导出内存区域的起始地址,0x20000924 - 1+2000为要导出内存区域的结束地址。每个地址1byte;要导出内存区域长度由数组大小决定,如uint32_t debug[1000]占用的内存为1000*4字节,若debug[0]的地址为0x20000924,上述命令可写成SAVE d:data.txt 0x20000924,0x20000924 – 1 + 4000,uint16_t[1000]占用内存为1000 * 2字节,若debug[0]的地址为0x20000924,上述命令可写成SAVE d:data.txt 0x20000924,0x20000924 – 1 + 2000;导出的数据按照HEX386格式保存。
二、HEX386格式解析
HEX386格式也叫intel hex格式,在keil官网可以找到该格式的详细定义,
使用keil导出的hex386格式文本每行以:开头
接下来一个字节为ll,表示有效数据长度
接下来两个字节为aaaa,表示这一行数据的起始地址
接下来一个字节为tt,表示这一行数据的含义,
tt=00表示本行数据为导出的内存数据
tt=01表示本行是文件的结尾
tt=02表示本行记录的是内存段
tt=04表示本行记录的是内存地址
接下来若干字节为数据
最后一个字节为校验
综上,解析hex文件就是找出tt = 00时的数据。
三、合成有效数据
完成hex文件的解析之后,只是实现了按照地址从低到高逐字节读出,还需要根据数组储存数据的类型进行转换。
因为stm32使用小端模式储存数据,对于32位数据aabbccdd,在内存中有低到高储存为ddccbbaa,所以完成hex格式解析后,要根据需要的数据类型重新排列数据,并转换为便于观察的整形数据。
对于有符号数,需要增加正负处理。
四、matlab代码实现
本次实验通过三部实现上述过程:
1) 读取文本文件到字符串数组
具体代码如下:
function strArray = readDataFromTxt(filename)
f = fopen(filename,‘r’);
line_num = 1;
while 1
tmp = string(fgetl(f));
if(tmp) == “-1”
break;
else
strArray(line_num) = tmp;
line_num = line_num + 1;
end
end
函数输入为文件路径。
函数输出为字符串数组。
2) 解析hex格式
代码如下:
function [address,data] = hex386Decode(strArray)
dataIndex = 1;
for rowIndex = 1 : length(strArray)%逐行扫描
charTmp = char(strArray(rowIndex));
byteNum = length(charTmp);
state = 1;
byteIndex = 1;
while 1 %逐字节扫描
switch(state)
case(1)%:
if(charTmp(byteIndex) == ‘:’)
state = 2;
byteIndex = byteIndex + 1;
end
case(2)%ll
dataByteNum = hex2dec(charTmp(byteIndex:byteIndex+1));
state = 3;
byteIndex = byteIndex + 2;
case(3)%aaaa
addr = hex2dec(charTmp(byteIndex:byteIndex+3));
state = 4;
byteIndex = byteIndex + 4;
case(4)%tt
dataType = hex2dec(charTmp(byteIndex:byteIndex+1));
if(dataType == 0)
state = 5;
byteIndex = byteIndex + 2;
else
break;
end
case(5)%[dddddd]
for dataByteCnt = 1 : dataByteNum
address(dataIndex) = addr + dataByteCnt - 1;
data(dataIndex,1:2) = charTmp(byteIndex:byteIndex+1);
byteIndex = byteIndex + 2;
dataIndex = dataIndex + 1;
end
break;
end
end
end
使用状态机控制读取过程。
函数输入为字符串数组,字符串数组的序号对应导出文本的行。
函数输出为内存地址,以及每个地址对应的内容。
3) 转换为真实数据
代码如下:
function data = byte2word(hexByte,bits,isSigned)
data = ‘ff’;
switch(bits)
case(8)
data = hexByte;
case(16)
len = length(hexByte);
cutNum = mod(len,4);
hexByte = hexByte(1:len - cutNum,:);
byte1 = 1 : 2 : length(hexByte);
byte2 = 2 : 2 : length(hexByte);
data = [hexByte(byte2,:),hexByte(byte1,:)];
case(32)
len = length(hexByte);
cutNum = mod(len,4);
hexByte = hexByte(1:len - cutNum,:);
byte1 = 1 : 4 : length(hexByte);
byte2 = 2 : 4 : length(hexByte);
byte3 = 3 : 4 : length(hexByte);
byte4 = 4 : 4 : length(hexByte);
data = [hexByte(byte4,:),hexByte(byte3,:),hexByte(byte2,:),hexByte(byte1,:)];
case(64)
len = length(hexByte);
cutNum = mod(len,4);
hexByte = hexByte(1:len - cutNum,:);
byte1 = 1 : 8 : length(hexByte);
byte2 = 2 : 8 : length(hexByte);
byte3 = 3 : 8 : length(hexByte);
byte4 = 4 : 8 : length(hexByte);
byte5 = 5 : 8 : length(hexByte);
byte6 = 6 : 8 : length(hexByte);
byte7 = 7 : 8 : length(hexByte);
byte8 = 8 : 8 : length(hexByte);
data = [hexByte(byte8,:),hexByte(byte7,:),hexByte(byte6,:),hexByte(byte5,:),hexByte(byte4,:),hexByte(byte3,:),hexByte(byte2,:),hexByte(byte1,:)];
otherwise
err = “不支持的输入”
end
data = hex2dec(data);
if(isSigned 》 0)
switch(bits)
case(8)
data(data 》= 2^7)= -2^8 + data(data 》= 2^7);
case(16)
data(data 》= 2^15)= -2^16 + data(data 》= 2^15);
case(32)
data(data 》= 2^31)= -2^32 + data(data 》= 2^31);
case(64)
data(data 》= 2^63)= -2^64 + data(data 》= 2^63);
end
end
函数输入为hexByte字符数组,每行为一个byte的内存数据。bits为每个输出数据占用的内存字节数,支持8bit,16bit,32bit,64bit,isSigned 》0表示数据为有符号数,否则数据为无符号数。
函数输出为想要导出的数组内容。
发挥matlab矩阵操作的优势,实现了8位、16位、32位、64位有符号整形及无符号整形的处理。
4)调用方式如下:
file = ‘d:data.txt’
strArray = readDataFromTxt(file);
[a,d] = hex386Decode(strArray);
data = byte2word(d,32,0)
引言
调试代码过程中经常将变量储存在大数组中,以分析数据的变化趋势。使用TI的ccs时,数组可以方便的导出。但是keil并没有直接导出数组的功能,好在keil提供了其他方法。Keil无法导出watch窗口的内容,但是可以导出memory窗口的内容。那么,怎么从导出的内容中解析出想要的数据呢?
一、导出到文件
导出方式如下:
1、 将需要导出的变量添加到memory窗口
2、 使用sava命令导出内存区域
Save命令格式如下:
SAVE d:data.txt 0x20000924,0x20000924 – 1 + 1000
其中d:data.txt为要导出文件的路径,0x20000924为要导出内存区域的起始地址,0x20000924 - 1+2000为要导出内存区域的结束地址。每个地址1byte;要导出内存区域长度由数组大小决定,如uint32_t debug[1000]占用的内存为1000*4字节,若debug[0]的地址为0x20000924,上述命令可写成SAVE d:data.txt 0x20000924,0x20000924 – 1 + 4000,uint16_t[1000]占用内存为1000 * 2字节,若debug[0]的地址为0x20000924,上述命令可写成SAVE d:data.txt 0x20000924,0x20000924 – 1 + 2000;导出的数据按照HEX386格式保存。
二、HEX386格式解析
HEX386格式也叫intel hex格式,在keil官网可以找到该格式的详细定义,
使用keil导出的hex386格式文本每行以:开头
接下来一个字节为ll,表示有效数据长度
接下来两个字节为aaaa,表示这一行数据的起始地址
接下来一个字节为tt,表示这一行数据的含义,
tt=00表示本行数据为导出的内存数据
tt=01表示本行是文件的结尾
tt=02表示本行记录的是内存段
tt=04表示本行记录的是内存地址
接下来若干字节为数据
最后一个字节为校验
综上,解析hex文件就是找出tt = 00时的数据。
三、合成有效数据
完成hex文件的解析之后,只是实现了按照地址从低到高逐字节读出,还需要根据数组储存数据的类型进行转换。
因为stm32使用小端模式储存数据,对于32位数据aabbccdd,在内存中有低到高储存为ddccbbaa,所以完成hex格式解析后,要根据需要的数据类型重新排列数据,并转换为便于观察的整形数据。
对于有符号数,需要增加正负处理。
四、matlab代码实现
本次实验通过三部实现上述过程:
1) 读取文本文件到字符串数组
具体代码如下:
function strArray = readDataFromTxt(filename)
f = fopen(filename,‘r’);
line_num = 1;
while 1
tmp = string(fgetl(f));
if(tmp) == “-1”
break;
else
strArray(line_num) = tmp;
line_num = line_num + 1;
end
end
函数输入为文件路径。
函数输出为字符串数组。
2) 解析hex格式
代码如下:
function [address,data] = hex386Decode(strArray)
dataIndex = 1;
for rowIndex = 1 : length(strArray)%逐行扫描
charTmp = char(strArray(rowIndex));
byteNum = length(charTmp);
state = 1;
byteIndex = 1;
while 1 %逐字节扫描
switch(state)
case(1)%:
if(charTmp(byteIndex) == ‘:’)
state = 2;
byteIndex = byteIndex + 1;
end
case(2)%ll
dataByteNum = hex2dec(charTmp(byteIndex:byteIndex+1));
state = 3;
byteIndex = byteIndex + 2;
case(3)%aaaa
addr = hex2dec(charTmp(byteIndex:byteIndex+3));
state = 4;
byteIndex = byteIndex + 4;
case(4)%tt
dataType = hex2dec(charTmp(byteIndex:byteIndex+1));
if(dataType == 0)
state = 5;
byteIndex = byteIndex + 2;
else
break;
end
case(5)%[dddddd]
for dataByteCnt = 1 : dataByteNum
address(dataIndex) = addr + dataByteCnt - 1;
data(dataIndex,1:2) = charTmp(byteIndex:byteIndex+1);
byteIndex = byteIndex + 2;
dataIndex = dataIndex + 1;
end
break;
end
end
end
使用状态机控制读取过程。
函数输入为字符串数组,字符串数组的序号对应导出文本的行。
函数输出为内存地址,以及每个地址对应的内容。
3) 转换为真实数据
代码如下:
function data = byte2word(hexByte,bits,isSigned)
data = ‘ff’;
switch(bits)
case(8)
data = hexByte;
case(16)
len = length(hexByte);
cutNum = mod(len,4);
hexByte = hexByte(1:len - cutNum,:);
byte1 = 1 : 2 : length(hexByte);
byte2 = 2 : 2 : length(hexByte);
data = [hexByte(byte2,:),hexByte(byte1,:)];
case(32)
len = length(hexByte);
cutNum = mod(len,4);
hexByte = hexByte(1:len - cutNum,:);
byte1 = 1 : 4 : length(hexByte);
byte2 = 2 : 4 : length(hexByte);
byte3 = 3 : 4 : length(hexByte);
byte4 = 4 : 4 : length(hexByte);
data = [hexByte(byte4,:),hexByte(byte3,:),hexByte(byte2,:),hexByte(byte1,:)];
case(64)
len = length(hexByte);
cutNum = mod(len,4);
hexByte = hexByte(1:len - cutNum,:);
byte1 = 1 : 8 : length(hexByte);
byte2 = 2 : 8 : length(hexByte);
byte3 = 3 : 8 : length(hexByte);
byte4 = 4 : 8 : length(hexByte);
byte5 = 5 : 8 : length(hexByte);
byte6 = 6 : 8 : length(hexByte);
byte7 = 7 : 8 : length(hexByte);
byte8 = 8 : 8 : length(hexByte);
data = [hexByte(byte8,:),hexByte(byte7,:),hexByte(byte6,:),hexByte(byte5,:),hexByte(byte4,:),hexByte(byte3,:),hexByte(byte2,:),hexByte(byte1,:)];
otherwise
err = “不支持的输入”
end
data = hex2dec(data);
if(isSigned 》 0)
switch(bits)
case(8)
data(data 》= 2^7)= -2^8 + data(data 》= 2^7);
case(16)
data(data 》= 2^15)= -2^16 + data(data 》= 2^15);
case(32)
data(data 》= 2^31)= -2^32 + data(data 》= 2^31);
case(64)
data(data 》= 2^63)= -2^64 + data(data 》= 2^63);
end
end
函数输入为hexByte字符数组,每行为一个byte的内存数据。bits为每个输出数据占用的内存字节数,支持8bit,16bit,32bit,64bit,isSigned 》0表示数据为有符号数,否则数据为无符号数。
函数输出为想要导出的数组内容。
发挥matlab矩阵操作的优势,实现了8位、16位、32位、64位有符号整形及无符号整形的处理。
4)调用方式如下:
file = ‘d:data.txt’
strArray = readDataFromTxt(file);
[a,d] = hex386Decode(strArray);
data = byte2word(d,32,0)
举报