IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> Modbus xMBUtilSetBits函数注释 -> 正文阅读

[嵌入式]Modbus xMBUtilSetBits函数注释

该方法用来设置线圈的数据,贴上部分代码。
我们知道Modbus为数据为大端模式(高地址放在低位,低地址放在高位),这样可以按着我们的习惯来设置IO数据。如下为设置多个线圈帧。
在这里插入图片描述
今天就以这样的组合看modbus协议如何发送和解析的协议帧的。
下图是我的测试记录,可以看到差异差异就是倒数第3个字节

框选1:发送的报文Tx:008108-01 0F 0B B8 00 10 02 03 00 43 68
框选2:发送的报文Tx:008116-01 0F 0B B8 00 10 02 03 C0 43 38 在这里插入图片描述
下面先了解下 GD32单片机是大端还是小端模式

    {
    uint16_t data= 0x1122;
    uint8_t *usdat = (uint8_t*)&data;
    LOGE("0x%x,%x",(uint8_t*)&usdat[0],usdat[0]);
    LOGE("0x%x,%x",(uint8_t*)&usdat[1],usdat[1]);
    }

打印结果:
在这里插入图片描述
可以看到,针对GD32单片机来说,数据低位保存在低地址上,即“小弟弟”–>小低低模式。

接着上面的,目前我先把3000开始的2个线圈打开了,可以看到协议数据部分是03 00, 由于modbus是大端模式,单片机是小段模式,则低位的3000和3001寄存器对应的状态是0x03,即低位的2个灯亮了。

30003001~~~~3015
eMBErrorCode
eMBRegCoilsCB(MBObj_t *pMbObj, UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode)
{
    //return MB_ENOREG;
    eMBErrorCode    eStatus = MB_ENOERR;
    short           iNCoils = (short)usNCoils;
    unsigned short  usBitOffset;

    //这里主要是MODBUS上层代码把地址+1了,很想I2C的读地址(+1操作),为此这里把地址进行还原
    usAddress = usAddress -1;
    LOGD("codi");
    /* Check if we have registers mapped at this block. */
    if ((usAddress >= REG_COILS_START) &&
        (usAddress + usNCoils <= REG_COILS_START + REG_COILS_SIZE))
    {
        usBitOffset = (unsigned short)(usAddress - REG_COILS_START);
        switch (eMode)
        {
            /* Read current values and pass to protocol stack. */
        case MB_REG_READ:
            while (iNCoils > 0)
            {
                *pucRegBuffer++ =
                    xMBUtilGetBits(ucRegCoilsBuf[pMbObj->portId], usBitOffset,
                    (unsigned char)(iNCoils >
                        8 ? 8 :
                        iNCoils));
                iNCoils -= 8;
                usBitOffset += 8;
            }
            break;

            /* Update current register values. */
        case MB_REG_WRITE:
            LOGD("ncoils:%d",iNCoils);
        {  
            UCHAR *Psrc = ucRegCoilsBuf[pMbObj->portId];
            while (iNCoils > 0)
            {//这个地方为线圈写操作
            //重点说的就是这里,这里我们设置16个bit,
            //usBitOffset:首个线圈的偏移。3000-3000 = 0、iNCoils =16.接下来请看下面这个函数的具体实现
                xMBUtilSetBits(Psrc++, usBitOffset,
                    (unsigned char)(iNCoils > 8 ? 8 : iNCoils),
                    *pucRegBuffer++);
                iNCoils -= 8;
            }
            {
            //add by armwind
            UCHAR *PpduBUf = NULL;
            master_ops->pvGetPduBuffer(&PpduBUf);
            if (MB_FUNC_WRITE_SINGLE_COIL == PpduBUf[MB_PDU_FUNC_OFF]) {
                //用户回调方法
            } else if (MB_FUNC_WRITE_MULTIPLE_COILS == PpduBUf[MB_PDU_FUNC_OFF]) {
                //用户回调方法
                }
            }
        }
            break;
        }
    }
    else
    {
        eStatus = MB_ENOREG;
    }
    return eStatus;
}

//注意这里,我们我们线圈寄存器基地址为3000,假设bitoffset为6,ucNBits为3,ucValue=0x03,
//即3006开始的3个bit

//ucByteBuf:寄存器首地址
//usBitOffset:寄存器偏移地址
//ucNBits:线圈数量
//线圈状态值
void
xMBUtilSetBits( UCHAR * ucByteBuf, USHORT usBitOffset, UCHAR ucNBits,
                UCHAR ucValue )
{
    USHORT          usWordBuf;
    USHORT          usMask;
    USHORT          usByteOffset;
    USHORT          usNPreBits;
    USHORT          usValue = ucValue;

    assert( ucNBits <= 8 );
    assert( ( size_t )BITS_UCHAR == sizeof( UCHAR ) * 8 );

    /* Calculate byte offset for first byte containing the bit values starting
     * at usBitOffset. 偏移地址换算成几个字节,这里usByteOffset=0*/
    usByteOffset = ( USHORT )( ( usBitOffset ) / BITS_UCHAR );

    /* How many bits precede our bits to set. 多出来的bit数,usNPreBits=6*/
    usNPreBits = ( USHORT )( usBitOffset - usByteOffset * BITS_UCHAR );

    /* Move bit field into position over bits to set */
    usValue <<= usNPreBits;  //0x03<<6,数据对准窗口

    /* Prepare a mask for setting the new bits. ?*/
    usMask = ( USHORT )( ( 1 << ( USHORT ) ucNBits ) - 1 );//计算数据bit掩码,1<<3-1,即0x07
    usMask <<= usBitOffset - usByteOffset * BITS_UCHAR; //数据bit掩码,滑动到对应的数据区域

    /* copy bits into temporary storage. */
    usWordBuf = ucByteBuf[usByteOffset]; //获取低地址数据
    usWordBuf |= ucByteBuf[usByteOffset + 1] << BITS_UCHAR; //获取高位地址数据

    /* Zero out bit field bits and then or value bits into them. */
    // 这一步先将数据区域清0,然后再与上赋予的数据
    usWordBuf = ( USHORT )( ( usWordBuf & ( ~usMask ) ) | usValue );

    /* move bits back into storage */
    ucByteBuf[usByteOffset] = ( UCHAR )( usWordBuf & 0xFF );
    ucByteBuf[usByteOffset + 1] = ( UCHAR )( usWordBuf >> BITS_UCHAR );
}
  • 获取数据bit掩码
    在这里插入图片描述

  • 将数据滑动到指定偏移的窗口区
    在这里插入图片描述
    然后想根据掩码,与非后清空数据区,再按位或即可将数据更新进去

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-05-05 11:35:52  更:2022-05-05 11:36:31 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 2:38:40-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码