测试总结
- 1、 如果使用二进制,进行文件读写,写入浮点数618,在从文件读出,读出的结果会出错。浮点数据 = 1.000 、610、620,测试都没问题;浮点数:616 出错,读出来是608,619也出错了,从文件读出是623。暂不知是什么问题,是因为编码问题? 用其他语言读写文件会不会也会遇到这种问题?
- 2、 所以在倍福plc中,读写文件,为了避免上面的问题,读写模式选用字符串模式(也即,读写功能块的sMode = ‘wt’ / ‘rt’) ,给文件写入的数据也用字符串型变量。
官方范例
实际测试
程序框架借鉴 轴控模块的思路,使用功能块与接口结构体的方式(这个坑以后在填),当然这样的思路并不是最简洁的,比如做到类似高级语言 fopen(…)这样的FUNCTION函数,编程体验自然是更好。
- 结构体与功能块之间的数据传输
打开文件:FileOpen
- 关于文件打开模式,参考C语言相关解释
(*******************************************************************************************************)
(*
文件使用方式 意 义
“rt” 只读打开一个文本文件,只允许读数据
“wt” 只写打开或建立一个文本文件,只允许写数据
“at” 追加打开一个文本文件,并在文件末尾写数据
“rb” 只读打开一个二进制文件,只允许读数据
“wb” 只写打开或建立一个二进制文件,只允许写数据
“ab” 追加打开一个二进制文件,并在文件末尾写数据
“rt+” 读写打开一个文本文件,允许读和写
“wt+” 读写打开或建立一个文本文件,允许读写
“at+” 读写打开一个文本文件,允许读,或在文件末追加数 据
“rb+” 读写打开一个二进制文件,允许读和写
“wb+” 读写打开或建立一个二进制文件,允许读和写
“ab+” 读写打开一个二进制文件,允许读,或在文件末追加数据
*)
(*
对于文件使用方式有以下几点说明:
1. 文件使用方式由r,w,a,t,b,+六个字符拼成,各字符的含义是:
r(read): 读
w(write): 写
a(append): 追加
t(text): 文本文件,可省略不写
b(banary): 二进制文件
+: 读和写
2. 凡用“r”打开一个文件时,该文件必须已经存在, 且只能从该文件读出。
3. 用“w”打开的文件只能向该文件写入。 若打开的文件不存在,则以指定的文件名建立该文件,若打开的文件已经存在,则将该文件删去,重建一个新文件。
4. 若要向一个已存在的文件追加新的信息,只能用“a ”方式打开文件。但此时该文件必须是存在的,否则将会出错。
5. 在打开一个文件时,如果出错,fopen将返回一个空指针值NULL。在程序中可以用这一信息来判别是否完成打开文件的工作,并作相应的处理。因此常用以下程序段打开文件:
if((fp=fopen("c:\hzk16","rb")==NULL)
{
printf("error on open c:\hzk16 file!");
getch();
exit(1);
}
这段程序的意义是,如果返回的指针为空,表示不能打开C盘根目录下的hzk16文件,则给出提示信息“error on open c: hzk16file!”,
下一行getch()的功能是从键盘输入一个字符,但不在屏幕上显示。在这里,该行的作用是等待,只有当用户从键盘敲任一键时,
程序才继续执行, 因此用户可利用这个等待时间阅读出错提示。敲键后执行exit(1)退出程序。
6. 把一个文本文件读入内存时,要将ASCII码转换成二进制码, 而把文件以文本方式写入磁盘时,也要把二进制码转换成ASCII码,
因此文本文件的读写要花费较多的转换时间。对二进制文件的读写不存在这种转换。
7. 标准输入文件(键盘),标准输出文件(显示器 ),标准出错输出(出错信息)是由系统打开的,可直接使用。文件关闭函数fclose()文件一旦使用完毕,
应用关闭文件函数把文件关闭, 以避免文件的数据丢失等错误。
*)
(*******************************************************************************************************)
(*打开文件模式,nmode:d 代表着流形态*)
IF File_ITF.sMode = 'r'THEN (* r: 打开只读文件,该文件必须存在*)
File_ITF.nMode := FOPEN_MODEREAD;
ELSIF File_ITF.sMode = 'r+'THEN (* r+: 打开可读写文件,该文件必须存在*)
File_ITF.nMode := FOPEN_MODEREAD OR FOPEN_MODEPLUS;
(*rb+:读写打开1个二进制文件,只允许读写数据*)
(*rt+:读写打开1个文本文件,只允许读写数据*)
ELSIF File_ITF.sMode = 'w'THEN (* w: 打开只写文件,若文件存在,则该文件内容会消失。若文件不存在则建立该文件*)
File_ITF.nMode := FOPEN_MODEWRITE;
ELSIF File_ITF.sMode = 'w+'THEN (* w+: 打开可读写文件,若文件存在,则该文件内容会消失。若文件不存在则建立该文件*)
File_ITF.nMode := FOPEN_MODEWRITE OR FOPEN_MODEPLUS;
ELSIF File_ITF.sMode = 'a'THEN (* a: 以追加的方式打开只写文件,若文件不存在,则新建该文件,如果文件存在,写入的数据会被追加到文件尾,即文件原先的内容会被保留。(EOF符保留)*)
File_ITF.nMode := FOPEN_MODEAPPEND;
ELSIF File_ITF.sMode = 'a+'THEN (* a+: 以追加的方式打开可读写文件,若文件不存在,则新建该文件,如果文件存在,写入的数据会被追加到文件尾,即文件原先的内容会被保留。(原来的EOF符不保留)*)
File_ITF.nMode := FOPEN_MODEAPPEND OR FOPEN_MODEPLUS;
(*wb*)
(*wb+*)
(*wt*)
(*wt+*)
(*at+*)
ELSIF File_ITF.sMode = 'at+'THEN
File_ITF.nMode := FOPEN_MODEAPPEND OR FOPEN_MODEPLUS OR FOPEN_MODETEXT;
(*ab+*)
ELSIF File_ITF.sMode = 'b'THEN
File_ITF.nMode := FOPEN_MODEBINARY;
ELSIF File_ITF.sMode = 't'THEN
File_ITF.nMode := FOPEN_MODETEXT;
ELSE
File_ITF.nMode :=File_ITF.nMode;
END_IF
(*EOF: 文件结束标识符,一般值为-1*)
- 主程序中调用(流程控制可参考自动化编程笔记(一)),在case流程的第10步,打开 Txt618.txt文件。
10:
g_st_TestGroup.stFlieTxt1.st_FileInterface.bExecuteFileOpen:=TRUE;
IF NOT g_st_TestGroup.stFlieTxt1.st_FileInterface.bBusyOpen THEN
stFlow_Auto.st_FlowInterface.nState := 20;
END_IF
- 查看C盘成功新建了该文件。
- FileOpen功能块在成功打开文件后,会产生一个hFile,暂时理解成文件索引,这个值很重要,是因为其他文件功能块都是基于这个值对文件进行操作的;反过来,如果直接使用其他文件操作功能块,没有FileOpen的hFile值做输入,那么操作的是哪个文件就无从得知。
关闭文件:FileClose
- 如果在我们打开文件之后,不使用关闭文件功能块关闭文件,那么我们直接在系统中删除修改保存文件,都会报文件被占用警告。
- 所以我们可以用是否可以用记事本修改或者删除文件,来验证 我们的文件关闭功能块执行是否成功。
g_st_TestGroup.stFlieTxt1.st_FileInterface.bExecuteFileClose:=TRUE;
IF g_st_TestGroup.stFlieTxt1.fb_File.ft_FileClose.Q THEN
stFlow_Auto.st_FlowInterface.nState := 20;
g_st_TestGroup.stFlieTxt1.st_FileInterface.bExecuteFileClose:=FALSE;
END_IF
可改写,可删除
- 在这里,需要注意的是,启动关闭文件,立即就检测功能块Busy信号,会有很大概率导致关闭失败;所以,在这里用下降沿功能块检测busy的下降沿,这样,就可以正确等待功能块执行成功。
当然,也可以使用延时检测Busy信号的方式,达到稳定关闭文件的效果。对于上面打开文件OpenFile操作,也是一样,不推荐立即检测busy信号。
文件读写FileWirte/Puts,FileRead/Gets
- FileRead,按照 open -> close -> close 流程
- FileRead,按照 open -> read -> close 流程
10:
g_st_TestGroup.stFlieTxt1.st_FileInterface.sMode:='wt';
g_st_TestGroup.stFlieTxt1.st_FileInterface.bExecuteFileOpen:=TRUE;
IF g_st_TestGroup.stFlieTxt1.fb_File.ft_FileOpen.Q THEN
stFlow_Auto.st_FlowInterface.nState := 20;
g_st_TestGroup.stFlieTxt1.st_FileInterface.bExecuteFileOpen:=FALSE;
END_IF
20:(* open -> write -> close*)
(*g_st_TestGroup.stFlieTxt1.st_FileInterface.pWriteBuff:=ADR(sVar);
g_st_TestGroup.stFlieTxt1.st_FileInterface.cbWriteLen:=SIZEOF(sVar);*)
(*g_st_TestGroup.stFlieTxt1.st_FileInterface.pWriteBuff:=ADR(nVar);
g_st_TestGroup.stFlieTxt1.st_FileInterface.cbWriteLen:=SIZEOF(nVar);*)
g_st_TestGroup.stFlieTxt1.st_FileInterface.pWriteBuff:=ADR(fVar);
g_st_TestGroup.stFlieTxt1.st_FileInterface.cbWriteLen:=SIZEOF(fVar);
g_st_TestGroup.stFlieTxt1.st_FileInterface.bExecuteFileWrite:=TRUE;
IF g_st_TestGroup.stFlieTxt1.fb_File.ft_FileWrite.Q THEN
stFlow_Auto.st_FlowInterface.nState := 30;
g_st_TestGroup.stFlieTxt1.st_FileInterface.bExecuteFileWrite:=FALSE;
END_IF
30:
g_st_TestGroup.stFlieTxt1.st_FileInterface.bExecuteFileClose:=TRUE;
IF g_st_TestGroup.stFlieTxt1.fb_File.ft_FileClose.Q THEN
stFlow_Auto.st_FlowInterface.nState := 40;
g_st_TestGroup.stFlieTxt1.st_FileInterface.bExecuteFileClose:=FALSE;
END_IF
40:
g_st_TestGroup.stFlieTxt1.st_FileInterface.sMode:='rt';
g_st_TestGroup.stFlieTxt1.st_FileInterface.bExecuteFileOpen:=TRUE;
IF g_st_TestGroup.stFlieTxt1.fb_File.ft_FileOpen.Q THEN
stFlow_Auto.st_FlowInterface.nState := 50;
g_st_TestGroup.stFlieTxt1.st_FileInterface.bExecuteFileOpen:=FALSE;
END_IF
50:(* open -> read -> close*)
(*g_st_TestGroup.stFlieTxt1.st_FileInterface.pReadBuff :=ADR(sVarRead);
g_st_TestGroup.stFlieTxt1.st_FileInterface.cbReadLen :=SIZEOF(sVarRead);*)
(*g_st_TestGroup.stFlieTxt1.st_FileInterface.pReadBuff:=ADR(nVarRead);
g_st_TestGroup.stFlieTxt1.st_FileInterface.cbReadLen:=SIZEOF(nVarRead);*)
g_st_TestGroup.stFlieTxt1.st_FileInterface.pReadBuff:=ADR(fVarRead);
g_st_TestGroup.stFlieTxt1.st_FileInterface.cbReadLen:=SIZEOF(fVarRead);
g_st_TestGroup.stFlieTxt1.st_FileInterface.bExecuteFileRead:=TRUE;
IF g_st_TestGroup.stFlieTxt1.fb_File.ft_FileRead.Q THEN
stFlow_Auto.st_FlowInterface.nState := 60;
g_st_TestGroup.stFlieTxt1.st_FileInterface.bExecuteFileRead:=FALSE;
END_IF
60:
g_st_TestGroup.stFlieTxt1.st_FileInterface.bExecuteFileClose:=TRUE;
IF g_st_TestGroup.stFlieTxt1.fb_File.ft_FileClose.Q THEN
stFlow_Auto.st_FlowInterface.nState := 998;
g_st_TestGroup.stFlieTxt1.st_FileInterface.bExecuteFileClose:=FALSE;
END_IF
998:(* 流程正常结束 *)
;
- 测试 整型618,字符型’618’,浮点型618;结果是浮点型数据会出错
- 测试2:fVal 浮点数据 = 1.000 、610、620,没问题;616 出错,读出来是608;619出错,读是623