找回密码
 立即注册
楼主: wuzhengmin

有关DMA,山东大学陈桂友教授

[复制链接]
  • 打卡等级:常住居民III
  • 打卡总天数:153
  • 最近打卡:2026-03-30 19:54:03
已绑定手机

22

主题

2426

回帖

3422

积分

论坛元老

积分
3422
发表于 2026-1-28 13:22:43 | 显示全部楼层
偏移 6:此字节为要写入的字节数,0x10 表示要写入 16 个字节(8 个寄存器)。.
偏移7:此16个字节为要写入的数据。.
最后两个字节:CRC16 校验值 0x12CE,低字节在前,高字节在后(算法与电脑通用,小端模式)。
各个从机接收到信息后,有多种方式去判断是否是自己的数据,我一般习惯先校验,校验通过才做数据解
析,然后做出应答。如果校验通过,从机地址正确,则本机一定要做应答(即使是错误的命令)。


截图202601281322406741.jpg
截图202601281323249929.jpg
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:153
  • 最近打卡:2026-03-30 19:54:03
已绑定手机

22

主题

2426

回帖

3422

积分

论坛元老

积分
3422
发表于 2026-1-28 13:27:37 | 显示全部楼层
偏移0:此字节为从机设备地址,同上述描述。
偏移1:此字节为功能码,同上述描述
偏移 2:此 2 字节为要写入的寄存器首地址,同上述描述。
偏移 4:此 2 字节为已经写入的寄存器个数,0x0004 表示已经写入 4个奇存器。
最后两个字节:CRC16 校验值 0x33C0,低字节在前,高字节在后(算法与电脑通用,小端模式)。,

截图202601281327347782.jpg
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:153
  • 最近打卡:2026-03-30 19:54:03
已绑定手机

22

主题

2426

回帖

3422

积分

论坛元老

积分
3422
发表于 2026-1-28 13:31:10 | 显示全部楼层
接着实际操作写多寄存器,读多寄存器:

截图202601281331077157.jpg
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:153
  • 最近打卡:2026-03-30 19:54:03
已绑定手机

22

主题

2426

回帖

3422

积分

论坛元老

积分
3422
发表于 2026-1-28 13:33:34 | 显示全部楼层
好好研究STC的CDC串口助手

可以发送CRC校验:

截图202601281333313133.jpg
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:153
  • 最近打卡:2026-03-30 19:54:03
已绑定手机

22

主题

2426

回帖

3422

积分

论坛元老

积分
3422
发表于 2026-1-28 13:37:04 | 显示全部楼层
双绞线传输,把干扰减低到最大,和网线一样

但是有寄生电容产生,就用9600!

我们接收方是STC link1D :

截图202601281337031169.jpg
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:153
  • 最近打卡:2026-03-30 19:54:03
已绑定手机

22

主题

2426

回帖

3422

积分

论坛元老

积分
3422
发表于 2026-1-28 13:37:55 | 显示全部楼层
读多寄存器也一样:

截图202601281337539140.jpg
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:153
  • 最近打卡:2026-03-30 19:54:03
已绑定手机

22

主题

2426

回帖

3422

积分

论坛元老

积分
3422
发表于 2026-1-28 13:48:10 | 显示全部楼层
程序执行的一般流程:
截图202601281348026554.jpg
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:153
  • 最近打卡:2026-03-30 19:54:03
已绑定手机

22

主题

2426

回帖

3422

积分

论坛元老

积分
3422
发表于 2026-1-28 13:52:09 | 显示全部楼层
校验结果=0为正常

除了自己的地址,还要检查广播地址0

各种错误代码的处理:

while (1)
        {
                if(B_RX1_OK && !B_TX1_Busy)        //收到数据, 进行MODBUS-RTU协议解析
                {
                        if(MODBUS_CRC16(RX1_Buffer, RX1_cnt) == 0)        //首先判断CRC16是否正确, 不正确则忽略, 不处理也不返回信息
                        {
                                if((RX1_Buffer[0] == 0x00) || (RX1_Buffer[0] == SL_ADDR))        //然后判断站号地址是否正确, 或者是否广播地址(不返回信息)
                                {
                                        if(RX1_cnt > 2) RX1_cnt -= 2;        //去掉CRC16校验字节
                                        i = MODBUS_RTU();        //MODBUS-RTU协议解析
                                        if(i != 0)        //错误处理
                                        {
                                                TX1_Buffer[0] = SL_ADDR;        //站号地址
                                                TX1_Buffer[1] = i;                        //错误代码
                                                crc = MODBUS_CRC16(TX1_Buffer, 2);
                                                TX1_Buffer[2] = (u8)crc;        //CRC是小端模式, 先发低字节,后发高字节。
                                                TX1_Buffer[3] = (u8)(crc>>8);
                                                B_TX1_Busy = 1;                //标志发送忙
                                                TX1_cnt    = 0;                //发送字节计数
                                                TX1_number = 4;                //要发送的字节数
                                                TI = 1;                                //启动发送
                                        }
                                }
                        }
                        RX1_cnt = 0;
                        B_RX1_OK = 0;
                }
        }
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:153
  • 最近打卡:2026-03-30 19:54:03
已绑定手机

22

主题

2426

回帖

3422

积分

论坛元老

积分
3422
发表于 2026-1-28 13:53:42 | 显示全部楼层
梁工把CRC校验函数也共享给大家:

/****************************** MODBUS_CRC (shift) *************** past test 06-11-27 *********
        计算CRC,调用方式        MODBUS_CRC16(&CRC,8);        &CRC为首地址,8为字节数
        CRC-16 for MODBUS
        CRC16=X16+X15+X2+1
        TEST: ---> ABCDEFGHIJ        CRC16=0x0BEE        1627T
*/
//========================================================================
// 函数: u16        MODBUS_CRC16(u8 *p, u8 n)
// 描述: 计算CRC16函数.
// 参数: *p: 要计算的数据指针.
//        n: 要计算的字节数.
// 返回: CRC16值.
// 版本: V1.0, 2022-3-18 梁工
//========================================================================
u16        MODBUS_CRC16(u8 *p, u8 n)
{
        u8        i;
        u16        crc16;

        crc16 = 0xffff;        //预置16位CRC寄存器为0xffff(即全为1)
        do
        {
                crc16 ^= (u16)*p;                //把8位数据与16位CRC寄存器的低位相异或,把结果放于CRC寄存器
                for(i=0; i<8; i++)                //8位数据
                {
                        if(crc16 & 1)        crc16 = (crc16 >> 1) ^ 0xA001;        //如果最低位为0,把CRC寄存器的内容右移一位(朝低位),用0填补最高位,
                                                                                                                        //再异或多项式0xA001
                        else        crc16 >>= 1;                                                        //如果最低位为0,把CRC寄存器的内容右移一位(朝低位),用0填补最高位
                }
                p++;
        }while(--n != 0);
        return        (crc16);
}
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:153
  • 最近打卡:2026-03-30 19:54:03
已绑定手机

22

主题

2426

回帖

3422

积分

论坛元老

积分
3422
发表于 2026-1-28 13:55:59 | 显示全部楼层
串口1的初始化:

现在都是STC-ISP自动生成啦

看看传统的串口初始化:

//========================================================================
// 函数: void        UART1_config(u32 brt, u8 timer, u8 io)
// 描述: UART1初始化函数。
// 参数:   brt: 通信波特率.
//       timer: 波特率使用的定时器, timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特率.
//          io: 串口1切换到的IO,  io=0: 串口1切换到P3.0 P3.1,  =1: 切换到P3.6 P3.7, =2: 切换到P1.6 P1.7,  =3: 切换到P4.3 P4.4.
// 返回: none.
// 版本: VER1.0
// 日期: 2018-4-2
// 备注:
//========================================================================
void        UART1_config(u32 brt, u8 timer, u8 io)        // brt: 通信波特率,  timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特率. io=0: 串口1切换到P3.0 P3.1,  =1: 切换到P3.6 P3.7, =2: 切换到P1.6 P1.7,  =3: 切换到P4.3 P4.4.
{
        brt = 65536UL - (MAIN_Fosc / 4) / brt;
        if(timer == 2)        //波特率使用定时器2
        {
                AUXR |= 0x01;                //S1 BRT Use Timer2;
                SetTimer2Baudraye((u16)brt);
        }

        else                //波特率使用定时器1
        {
                TR1 = 0;
                AUXR &= ~0x01;                //S1 BRT Use Timer1;
                AUXR |=  (1<<6);        //Timer1 set as 1T mode
                TMOD &= ~(1<<6);        //Timer1 set As Timer
                TMOD &= ~0x30;                //Timer1_16bitAutoReload;
                TH1 = (u8)(brt >> 8);
                TL1 = (u8)brt;
                ET1 = 0;                        // 禁止Timer1中断
                INT_CLKO &= ~0x02;        // Timer1不输出高速时钟
                TR1  = 1;                        // 运行Timer1
        }

                 if(io == 1)        {S1_USE_P36P37();        P3n_standard(0xc0);}        //切换到 P3.6 P3.7
        else if(io == 2)        {S1_USE_P16P17();        P1n_standard(0xc0);}        //切换到 P1.6 P1.7
        else if(io == 3)        {S1_USE_P43P44();        P4n_standard(0x18);}        //切换到 P4.3 P4.4
        else                                {S1_USE_P30P31();        P3n_standard(0x03);}        //切换到 P3.0 P3.1

        SCON = (SCON & 0x3f) | (1<<6);        // 8位数据, 1位起始位, 1位停止位, 无校验
//        PS  = 1;        //高优先级中断
        ES  = 1;        //允许中断
        REN = 1;        //允许接收
}
回复

使用道具 举报 送花

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

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-4-1 02:44 , Processed in 0.107005 second(s), 75 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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