迪文科技论坛

 找回密码
 立即注册
搜索
查看: 132|回复: 6

【提问】C51的位解析问题

[复制链接]

1

主题

10

回帖

66

积分

注册会员

Rank: 2

积分
66
发表于 2025-9-22 16:16:48 | 显示全部楼层 |阅读模式
使用C51的MODBUS通讯
目前需要实现一个 04读取输入寄存器,然后有一个解析逻辑去分析这个寄存器的每一个位,实现故障码显示的功能
目前的问题有如下几个
1.if (S_H == 5 && R_OD5 == 1 && T_O5 == 0) 这个判断条件下,我的控件没有任何东西,似乎就是没接受完信息就开始解析了
2..if (S_H == 5)换成这个判断条件,会导致显示的故障信息是错误的,在这个寄存器所有位都是0的情况,还能读取到故障码,不正常
3.采用0x01的发送模式,会导致刷新很频繁,已经加了// 仅当故障值变化时更新显示if (fault_value != last_fault_value)的处理,不知道可行不可行。如果用0x04的发送模式,会导致重试两次直接失败,后续无法进行MODBUS通讯
如何合理的解决上诉问题




0x5A, 0x01, 0x04, 0x01, 0xA0, 0x01, 0x00, 0x05, 0x30, 0x00, 0x00, 0x06,        //006        测试故障码




void Performance_Function()//功能函数
{
                  
    if( Sec_fang1==1)
                {
                        Sec_fang1=0;
               
                }
    // 处理006指令(S_H==5,Modbus功能码04,读取从机0x0006寄存器)
                if (S_H == 5 && R_OD5 == 1 && T_O5 == 0)                {
                                u8 fault_buf[2] = {0, 0}; // 存储故障值的缓冲区,初始化为0
                                u16 fault_value;
                                u8 fault_str[255]; // 存储拼接的故障描述
                                u8 bit_pos;
                                bit fault_found = 0;
                                static u16 last_fault_value = 0xFFFF;
                                // 清空0x3000,避免旧数据干扰
                                u8 clear_buf[2] = {0, 0};
                                write_dgus_vp(0x3000, clear_buf, 2);
                                // 从0x3000读取故障值(2字节)
                                read_dgus_vp(0x3000, fault_buf, 2);
                                fault_value = (fault_buf[0] << 8) | fault_buf[1]; // 大端格式
                               
                                // 仅当故障值变化时更新显示
                                if (fault_value != last_fault_value)
                                {
                                                // 初始化字符串
                                                fault_str[0] = '\0';

                                                // 按位解析fault_value(16位)
                                                for (bit_pos = 0; bit_pos < 16; bit_pos++)
                                                {
                                                                if (fault_value & (1 << bit_pos)) // 该位为1,有故障
                                                                {
                                                                                if (fault_found)
                                                                                {
                                                                                                strcat(fault_str, ", "); // 添加分隔符
                                                                                }
                                                                                strcat(fault_str, fault_descriptions[bit_pos]); // 追加故障描述
                                                                                fault_found = 1;
                                                                }
                                                }

                                                if (!fault_found)
                                                {
                                                                strcpy(fault_str, "No Fault");
                                                }

                                                // 写入DGUS屏0x3000地址
                                                str_len = strlen(fault_str) + 1; // 实际字符串长度(含\0)
                                                if (str_len % 2 != 0) {
                                                                str_len++; // 补齐到偶数
                                                                fault_str[str_len - 1] = 0; // 补齐字节为0
                                                }
                                                write_dgus_vp(0x3000, fault_str, str_len);

                                                // 更新上次故障值
                                                last_fault_value = fault_value;
                                }

                                // 清空接收标志
                                R_OD5 = 0;
                                R_CN5 = 0;
                }               
}




回复

使用道具 举报

0

主题

372

回帖

2477

积分

金牌会员

Rank: 6Rank: 6

积分
2477
发表于 2025-9-22 17:54:49 | 显示全部楼层
可以加入长度判断,小于指令长度不进入解析。
回复

使用道具 举报

1

主题

10

回帖

66

积分

注册会员

Rank: 2

积分
66
 楼主| 发表于 2025-9-23 09:20:58 | 显示全部楼层
紫狐 发表于 2025-9-22 17:54
可以加入长度判断,小于指令长度不进入解析。

我只需要解析一条指令,而且很多指令的长度都一样的,添加长度判断也无法解决这问题
回复

使用道具 举报

0

主题

372

回帖

2477

积分

金牌会员

Rank: 6Rank: 6

积分
2477
发表于 2025-9-23 09:36:15 | 显示全部楼层
这么配置的,模版已经把收到的数据放到0x3000地址里了,只需要判断0x3000地址的值,不需要解析什么串口数据了吧,,还是说是自己写的modbus解析程序。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

1

主题

10

回帖

66

积分

注册会员

Rank: 2

积分
66
 楼主| 发表于 2025-9-23 10:09:16 | 显示全部楼层
紫狐 发表于 2025-9-23 09:36
这么配置的,模版已经把收到的数据放到0x3000地址里了,只需要判断0x3000地址的值,不需要解析什么串口数据 ...

现有需求是需要从0x3000地址,解析存储在里面的值(二进制形式),从而实现判断不同的位对应的故障码是多少,接着反馈到 屏上的Text控件 。我使用的是论坛里面的MODBUS程序。
回复

使用道具 举报

0

主题

372

回帖

2477

积分

金牌会员

Rank: 6Rank: 6

积分
2477
发表于 2025-9-23 11:02:36 | 显示全部楼层
把接收到的数(不做处理的),然后处理的变量都显示出来,进行调试。只是解析0x3000的16个bit位,也不需要什么S_H ,R_OD5,模版都已经把正确的数据放到0x3000了,只需要处理0x3000的数就行了,然后再调试处理的步骤,是哪步出的问题
回复

使用道具 举报

1

主题

10

回帖

66

积分

注册会员

Rank: 2

积分
66
 楼主| 发表于 2025-9-23 17:17:34 | 显示全部楼层
紫狐 发表于 2025-9-23 11:02
把接收到的数(不做处理的),然后处理的变量都显示出来,进行调试。只是解析0x3000的16个bit位,也不需要 ...

好的通过你的方法排查到问题了,因为有的变量忘记初始化了,谢谢
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|迪文科技论坛 ( 京ICP备05033781号-1 )

GMT+8, 2025-10-17 18:13 , Processed in 0.055639 second(s), 23 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表