基于QtPy (PySide6) 的PLC-HMI工程项目(十二)最后的工作

一、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

相关推荐
承渊政道2 小时前
【动态规划算法】(从入门到精通:路径问题)
数据结构·c++·学习·算法·leetcode·macos·动态规划
武帝为此2 小时前
【数据质量校验简介】
人工智能·python·机器学习
MFXWW22 小时前
从 Python 到 3D 开发:Ursina 引擎零基础入门学习路径与核心开发思路
python·游戏引擎·游戏程序·ursina
2301_813599552 小时前
如何处理MongoDB副本集中节点IP变更_rs.reconfig强制更新配置矩阵
jvm·数据库·python
王的宝库2 小时前
【Ansible】变量与敏感数据管理:Vault 加密 + Facts 采集详解
笔记·学习·ansible
2301_796588502 小时前
如何用数据库版本号机制平滑升级前端本地的数据表结构
jvm·数据库·python
盐烟2 小时前
xpath-csv_doban_slider
开发语言·python
中屹指纹浏览器2 小时前
2026浏览器指纹隔离技术深度对比与大规模集群部署性能优化实践
经验分享·笔记
小学生-山海2 小时前
【安卓逆向】WE Learn登录接口iv、pwd参数分析,加密逆向分析
开发语言·python·安卓逆向