一、PLC中创建FC,处理下行数据。
FC接口:
接口 数据类型 备注
Input
frameHeader1 Byte 帧头字节1
frameHeader2 Byte 帧头字节2
frameEnd1 Byte 帧尾字节1
frameEnd2 Byte 帧尾字节2
rsv_area_var "AreaVar" 接收下行报文的DB块
DB_CRC_TABLE Array[0..255] of Word
Output
DONE Bool
Temp
i DInt
pos DInt 字节临时指针
tmp_head Byte
tmp_end Byte
tmp_areaVar "AreaVar"
bTemp Byte
wTemp Word
wCRC Word
nIndex Int
#DONE := FALSE;
////////////////////////////解析帧头///////////////////////////
#pos := 0; // 字节指针
#tmp_head := PEEK(area := #rsv_area_var.Area, dbNumber := #rsv_area_var.DBNum, byteOffset := #pos); //帧头1
IF #frameHeader1 <> #tmp_head THEN
#DONE := FALSE;
RETURN;
END_IF;
#pos := #pos + 1;
#tmp_head := PEEK(area := #rsv_area_var.Area, dbNumber := #rsv_area_var.DBNum, byteOffset := #pos); //帧头2
IF #frameHeader1 <> #tmp_head THEN
#DONE := FALSE;
RETURN;
END_IF;
#pos := #pos + 1;
IF PEEK(area := #rsv_area_var.Area, dbNumber := #rsv_area_var.DBNum, byteOffset := #pos) = #frameEnd1 THEN
IF PEEK(area := #rsv_area_var.Area, dbNumber := #rsv_area_var.DBNum, byteOffset := #pos + 1) = #frameEnd2 THEN
#DONE := TRUE;
RETURN;
END_IF;
END_IF;
/////////////////////////解析区域变量的参数////////////////////
#tmp_areaVar.Area := PEEK(area := #rsv_area_var.Area, dbNumber := #rsv_area_var.DBNum, byteOffset := #pos); //帧区域
#pos := #pos + 2;
#tmp_areaVar.DBNum := DWORD_TO_DINT(IN:=PEEK_DWORD(area := #rsv_area_var.Area, dbNumber := #rsv_area_var.DBNum, byteOffset := #pos)); //帧DB号
#pos := #pos + 4;
#tmp_areaVar.Offset := DWORD_TO_DINT(PEEK_DWORD(area := #rsv_area_var.Area, dbNumber := #rsv_area_var.DBNum, byteOffset := #pos)); //帧字节偏移
#pos := #pos + 4;
#tmp_areaVar.byteCount := DWORD_TO_DINT(PEEK_DWORD(area := #rsv_area_var.Area, dbNumber := #rsv_area_var.DBNum, byteOffset := #pos)); //帧字节长度
#pos := #pos + 4;
#tmp_areaVar.bit := DWORD_TO_DINT(PEEK_DWORD(area := #rsv_area_var.Area, dbNumber := #rsv_area_var.DBNum, byteOffset := #pos)); //帧位(bit)
#pos := #pos + 4; //pos目前位于数据区之前
////////////////////////////解析数据内容和CRC//////////////////////////
//解析CRC
#wCRC := 16#FFFF;
FOR #i := 0 TO #pos+#tmp_areaVar.byteCount+1 DO //读取接收DB从0到数据长度,再多读4位(帧尾)
#bTemp := PEEK(area := #rsv_area_var.Area,
byteOffset := #i,
dbNumber := #rsv_area_var.DBNum);
#wTemp := #wCRC XOR BYTE_TO_WORD(IN := #bTemp);
#wTemp := #wTemp AND 16#00FF;
#nIndex := WORD_TO_INT(IN := #wTemp);
#wCRC := SHR(IN := #wCRC, N := 8) XOR #DB_CRC_TABLE[#nIndex];
END_FOR;
#wCRC := #wCRC;
#pos := #pos + #tmp_areaVar.byteCount; //pos目前位于数据区之后,帧尾之前
IF #wCRC <> PEEK_WORD(area := #rsv_area_var.Area, byteOffset := #pos + 2, dbNumber := #rsv_area_var.DBNum) THEN //CRC失败
#DONE := FALSE;
RETURN;
END_IF;
////////////////////////////解析帧尾///////////////////////////////////
#tmp_end := PEEK(area := #rsv_area_var.Area, dbNumber := #rsv_area_var.DBNum, byteOffset := #pos); //帧尾1
IF #frameEnd1 <> #tmp_end THEN
#DONE := FALSE;
RETURN;
END_IF;
#pos := #pos + 1;
#tmp_end := PEEK(area := #rsv_area_var.Area, dbNumber := #rsv_area_var.DBNum, byteOffset := #pos); //帧尾2
IF #frameEnd2 <> #tmp_end THEN
#DONE := FALSE;
RETURN;
END_IF;
#pos := #pos + 1; //此时的pos位于帧尾后,CRC前
#pos := #pos -#tmp_areaVar.byteCount - 2; //把pos移回到数据区的起始
/////////////////////////////////如果是bool//////////////////////////////
IF #tmp_areaVar.bit <> 16#FFFFFFFF THEN
POKE_BOOL(area := #tmp_areaVar.Area, ////写一个bool位
dbNumber := #tmp_areaVar.DBNum,
byteOffset := #tmp_areaVar.Offset,
bitOffset := DINT_TO_INT(IN:=#tmp_areaVar.bit),
value := PEEK_BOOL(area := #rsv_area_var.Area, dbNumber := #rsv_area_var.DBNum, byteOffset := #pos, bitOffset := #tmp_areaVar.bit));
/////////////////////////////////如果不是bool//////////////////////////////
ELSE //写块数据
POKE_BLK(area_src := #rsv_area_var.Area,
dbNumber_src := #rsv_area_var.DBNum,
byteOffset_src := #pos,
area_dest := #tmp_areaVar.Area,
dbNumber_dest := #tmp_areaVar.DBNum,
byteOffset_dest := #tmp_areaVar.Offset,
count := #tmp_areaVar.byteCount);
END_IF;
#DONE := TRUE;
二、颜色系统
python
class COLOR:
底色 = "#e1e1e1"
白色 = "#ffffff"
亮灰 = "#f8f8f8"
浅灰 = "#cccccc"
中灰 = "#aaaaaa"
深灰 = "#808080"
暗黑 = "#303030"
深黑 = "#aaa"
黑色 = "#000"
亮红 = "#ffc8c8"
浅红 = "#ff6262"
红色 = "#fa1717"
深红 = "#ca3333"
暗红 = "#a52929"
# 0bb60b
亮绿 = "#c8ffc8"
浅绿 = "#46ff46"
绿色 = "#0bb60b"
中绿 = "#3e8e41"
深绿 = "#267133"
浅蓝 = "#6e95ff"
蓝色 = "#0609b3"
亮青 = "#e5f1fb"
浅青 = "#cce4f7"
亮黄 = "#fafadc"
橙色 = "#ff8000"
绿圆渐变 = f"qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.3, fy:0.3, stop:0 {亮绿}, stop:0.2 {浅绿}, stop:1 {绿色})"
红圆渐变 = f"qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.3, fy:0.3, stop:0 {亮红}, stop:0.2 {浅红}, stop:1 {红色})"
##########################################app.styleSheet
APP_STYLE_SHEET = f"""
QPushButton {{
background-color: {COLOR.底色};
font-size: 20px;
padding: 8px 16px;
border-radius: 4px;
border-top: 1px solid {COLOR.亮灰};
border-left: 1px solid {COLOR.亮灰};
border-right: 1px solid {COLOR.暗黑};
border-bottom: 1px solid {COLOR.暗黑};
}}
QPushButton:hover{{
background-color: {COLOR.亮青};
border-top: 2px solid {COLOR.浅灰};
border-left: 2px solid {COLOR.浅灰};
border-right: 2px solid {COLOR.暗黑};
border-bottom: 2px solid {COLOR.暗黑};
}}
QPushButton:pressed{{
background-color: {COLOR.浅青};
border-top: 1px solid {COLOR.暗黑};
border-left: 1px solid {COLOR.暗黑};
border-right: 1px solid {COLOR.浅灰};
border-bottom: 1px solid {COLOR.浅灰};
}}
"""
##########################################QWidget
# 闪烁的小部件,闪烁颜色由"blink"控制
widget = "QWidget"
ORG_BLINKING_WIDGET = f"""
{widget}[blink="true"] {{
background-color: {COLOR.橙色};
color: {COLOR.白色};
}}
"""
RED_BLINKING_WIDGET = f"""
{widget}[blink="true"] {{
background-color: {COLOR.红色};
color: {COLOR.白色};
}}
"""
GRE_BLINKING_WIDGET = f"""
{widget}[blink="true"] {{
background-color: {COLOR.绿色};
color: {COLOR.白色};
}}
"""
##########################################QPushButton
# ##########################绿色按钮,颜色由"light"控制
widget = "QPushButton"
GRE_PUSHBUTTON = f"""
{widget}[light="true"] {{
background-color: {COLOR.绿色};
color: {COLOR.白色};
}}
{widget}[light="true"]:hover {{
background-color: {COLOR.中绿};
}}
{widget}[light="true"]:pressed {{
background-color: {COLOR.深绿};
}}
{widget}[light="false"] {{
background-color: {COLOR.底色};
color: {COLOR.黑色};
border-right: 1px solid {COLOR.绿色};
border-bottom: 1px solid {COLOR.绿色};
}}
{widget}[light="false"]:hover {{
background-color: #e5f1fb;
border-right: 2px solid {COLOR.绿色};
border-bottom: 2px solid {COLOR.绿色};
}}
{widget}[light="false"]:pressed {{
background-color: {COLOR.浅青};
border-right: 1px solid {COLOR.绿色};
border-bottom: 1px solid {COLOR.绿色};
/*border: 1px solid {COLOR.绿色};*/
}}
{widget}:disabled {{
color: {COLOR.深灰};
border-right: 1px solid {COLOR.暗黑};
border-bottom: 1px solid {COLOR.暗黑};
}}
"""
# ##########################红色按钮,颜色由"light"控制
RED_PUSHBUTTON = f"""
{widget}[light="true"] {{
background-color: {COLOR.红色};
color: {COLOR.白色};
}}
{widget}[light="true"]:hover {{
background-color: {COLOR.暗红};
}}
{widget}[light="true"]:pressed {{
background-color: {COLOR.深红};
}}
{widget}[light="false"] {{
background-color: {COLOR.底色};
color: {COLOR.黑色};
border-right: 1px solid {COLOR.红色};
border-bottom: 1px solid {COLOR.红色};
}}
{widget}[light="false"]:hover {{
background-color: #e5f1fb;
border-right: 2px solid {COLOR.红色};
border-bottom: 2px solid {COLOR.红色};
}}
{widget}[light="false"]:pressed {{
background-color: {COLOR.浅青};
border-right: 1px solid {COLOR.红色};
border-bottom: 1px solid {COLOR.红色};
/*border: 1px solid {COLOR.红色};*/
}}
{widget}:disabled {{
color: {COLOR.深灰};
border-right: 1px solid {COLOR.暗黑};
border-bottom: 1px solid {COLOR.暗黑};
}}
"""
##########################################QRadioButton
# 单选按钮
widget = "QRadioButton"
GRE_RADIOBUTTON = f"""
{widget} {{
font-size: 18px;
spacing: 10px;
}}
/*设置复选框的指示器尺寸*/
{widget}::indicator {{
width: 18px;
height: 18px;
border: 1px solid {COLOR.深黑};
border-radius: 2px;
background-color: #fff;
}}
/*选中状态*/
{widget}::indicator:checked {{
background-color: {COLOR.绿色};
border-left: 1px solid {COLOR.浅灰};
border-top: 1px solid {COLOR.浅灰};
border-right: 1px solid {COLOR.暗黑};
border-bottom: 1px solid {COLOR.暗黑};
}}
/* 鼠标悬停 */
{widget}::indicator:hover {{
border: 2px solid {COLOR.浅蓝};
}}
"""
##########################################QLabel
# 展示标签
widget = "QLabel"
SHOW_LABEL = f"""
{widget} {{
background-color:{COLOR.亮黄};
color: {COLOR.蓝色};
font-size: 18px;
padding: 8px 16px;
border: 1px solid {COLOR.中灰};
border-left: 1px solid {COLOR.暗黑};
border-top: 1px solid {COLOR.暗黑};
border-right: 1px solid {COLOR.浅灰};
border-bottom: 1px solid {COLOR.浅灰};
border-radius: 4px;
}}
"""
# 绿色圆灯background-color: {COLOR.绿色};
# 26px
GRE_ROUND_LAMP = f"""
{widget} {{
background-color: {COLOR.浅灰};
border: 1px solid {COLOR.深绿};
border-radius: 13px;
}}
{widget}[light="true"] {{
background-color: {COLOR.绿圆渐变};
border: 1px solid {COLOR.暗黑};
}}
"""
RED_ROUND_LAMP = f"""
{widget} {{
background-color: {COLOR.浅灰};
border: 1px solid {COLOR.浅红};
border-radius: 13px;
}}
{widget}[light="true"] {{
background-color: {COLOR.红圆渐变};
border: 1px solid {COLOR.暗黑};
}}
"""
至此,完成了一个PLC的HMI项目基础框架。
运行截图:

通过网盘分享的文件:UI_Project.rar
链接: https://pan.baidu.com/s/18SBz4wM2G3Od4hidv6FHmQ 提取码: qwya