stm32的modbus主机,读取电表等

一、简介及进展
modbus的从机就看了不少的文章了,不过主机的文章比较少,在这里我贡献出我的项目经验,自己做的第一个项目。还是需要继续学习。
首先定义一个发送的数组,data[7],data[8]是crc校验码,这个时候有人会有疑问了,为什么不做发送时间的判断,因为发送时间不能超过3.5ms。一旦超过3.5ms的话,modbus主机是不会处理这段数据的。我在这是按实测的来,仿真和实际操作都没问题

首先,看发送和接收的数据格式

主机发送码::地址 03 00 00 00 02 CRC低位 CRC高位(共8字节)
(1) 地址(1字节):与仪器设置地址相同 1~247
(2) 功能码(1字节):03 使用03功能码读数据
(3) 数据寄存器地址(2字节):0000 
(4) 数据数量(2字节):0002  读2个16位数据
(5) CRC(2字节):校验码
仪器发送码:地址 03 04 XX XX XX XX CRC低位 CRC高位(共9字节)
(1) 地址(1字节):仪器设置地址1~247
(2) 功能码(1字节):03 使用03功能码读数据
(3) 数量(1字节):4  发送数据字节数
(4) 数据(4字节):32位标准IEEE754浮点数
(5) CRC(2字节):校验码

例:EXAMPLE 
逻辑地址为1的表
读电量:10度
发送
01 03 00 00 00 02 c4 0b 
接收
01 03 04 00 00 03 e8 crc16 

c4 0b就是crc校验位,可以使用CRCTool工具进行计算

下面具体介绍数据的发送和接收,
定义发送的数组

    modbus.databuf[0]=0x01; 
    modbus.databuf[1]=0x03; 
    modbus.databuf[2]=0x00; 
    modbus.databuf[3]=0x00; 
    modbus.databuf[4]=0x00; 
    modbus.databuf[5]=0x02;
    modbus.databuf[6]=0xc4;
    modbus.databuf[7]=0x0b;

发送16位数据,这里要用寄存器来操作,不能使用printf来发送16进制的数组。

void UartASendStr (u8 *pucStr, u8 ulNum) 
{ 
    u8 i; 
    for(i = 0;i<ulNum;i++) 
    { 
    while ((USART2->SR & USART_FLAG_TC) == (uint16_t)RESET);
    USART_SendData(USART2,*pucStr++); 
    }  
} 

发送数据,放在了main函数里,目前是调试用。
加了延时,

UartASendStr(modbus.databuf,8);
delay_ms(200);

接收中断

void USART2_IRQHandler(void)
{   
    if(USART_GetITStatus(USART2,USART_IT_RXNE)!=RESET)
    {   

        modbus.rcbuf[modbus.recount++] = USART_ReceiveData(USART2);


    }    
}

接收到的数据进行处理
在这里调用了crc校验的算法,可以参考从机的ModbusCRC.c,我是直接用的。

#include "modbusCRC.h"
void Modbud_fun3()  
{
  u16 Regadd;
    u16 Reglen;
    u16 i=0;
    u16 crc;
    u16 rccrc;
    Reglen=modbus.rcbuf[2];  
    if(Reglen==0x04)
    {
    Regadd=modbus.rcbuf[3]*256+modbus.rcbuf[4];
        Regadd=modbus.rcbuf[5]*256+modbus.rcbuf[6];
    }
        if(Reglen==0x02)
    {
    Regadd=modbus.rcbuf[3]*256+modbus.rcbuf[4];
        Regadd=modbus.rcbuf[5]*256+modbus.rcbuf[6];
    }
    crc= crc16(&modbus.rcbuf[0], modbus.recount-2);       
    rccrc=modbus.rcbuf[modbus.recount-2]*256 + modbus.rcbuf[modbus.recount-1];  
    if(crc ==  rccrc)  
    { 
     i++;//如果校验的crc和发送的数据相同,证明了接收的数据正常,可以使用
    }

    modbus.recount=0;  
  modbus.reflag=0;  
}

目前已经调通。下面将所有的代码放了上来,供学习用。
主要功能

  1. 串口一是接GPRS模块的,代码还没有添加进来,已调通,能进中断。
  2. 串口二接485转ttl的,还不能用于产品用。
  3. modbusCRC.c是直接使用了从机的代码,可以参考网上的例程。
  4. dds238-1电表是可以直接使用本代码的。

main函数

#include "bsp_usart.h"
#include "modbus.h"
#include "stm32f10x.h"
int main(void)
{   
  USART1_Config();
      USART2_Config();
    shuzu();
  //Modbud_fun3();
  while(1)
    {   
//          RS485_byte();
            UartASendStr(modbus.databuf,8);
        delay_ms(200);
        Modbud_fun3();
    }   
}

modbus.c

#include "modbus.h"
#include "modbusCRC.h"
#include "bsp_usart.h"
MODBUS modbus;

void UartASendStr (u8 *pucStr, u8 ulNum) 
{ 
    u8 i; 
    for(i = 0;i<ulNum;i++) 
    { 
    while ((USART2->SR & USART_FLAG_TC) == (uint16_t)RESET);
    USART_SendData(USART2,*pucStr++); 
    }  
} 
void Modbud_fun3() 
{
  u16 Regadd;
    u16 Reglen;
    u16 i=0;
    u1
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值