基于STM32Modbusrtu从机代码开源(附上测试⼯程)---------
------。。。
Modbus rtu 从机代码主要包括五组:
modbus.c modbus.h
modbus_485.c modbus_485.h
modbus_crc.c modbus_crc.h
modbus_time.c modbus_time.h
modbus_uart.c modbus_uart.h
#include "modbus.h"
MODBUS modbus;
u16 Reg[] ={0x0001,
0x0002,
0x0003,
0x0004,
0x0005,
appreciate是什么意思0x0006,
0x0007,
};
// Modbus初始化函数
void Modbus_Init()
{
modbus.timrun = 0; //modbus定时器停⽌计算
Modbus_485_Init();
Modbus_Uart_Init();
Modbus_Time_Init();
}
// Modbus 3号功能码函数
// Modbus 主机读取寄存器值
void Modbus_Func3()
{
u16 Regadd,Reglen,crc;
u8 i,j;
/
/得到要读取寄存器的⾸地址
fight什么意思Regadd = buf[2]*buf[3];
//得到要读取寄存器的数据长度
Reglen = buf[4]*buf[5];
//发送回应数据包
i = 0;
modbus.ndbuf[i++] = add; //发送本机设备地址
modbus.ndbuf[i++] = 0x03; //发送功能码
modbus.ndbuf[i++] = ((Reglen*2)%256); //返回字节个数
for(j=0;j<Reglen;j++) //返回数据
mick jagger{
modbus.ndbuf[i++] = Reg[Regadd+j]/256;
modbus.ndbuf[i++] = Reg[Regadd+j]%256;
}
crc = Modbus_CRC16(modbus.ndbuf,i); //计算要返回数据的CRC
modbus.ndbuf[i++] = crc/256;
modbus.ndbuf[i++] = crc%256;
// 开始返回Modbus数据
Modbus_485_TX_Mode;
for(j=0;j<i;j++)
{
Modbus_Send_Byte(modbus.ndbuf[j]);
}
Modbus_485_RX_Mode;
// Modbus 6号功能码函数
// Modbus 主机写⼊寄存器值
void Modbus_Func6()
{
u16 Regadd;
u16 val;
u16 i,crc,j;
i=0;
buf[2]*buf[3]; //得到要修改的地址
buf[4]*buf[5]; //修改后的值
Reg[Regadd]=val; //修改本设备相应的寄存器
入门日语//以下为回应主机
modbus.ndbuf[i++]=add;//本设备地址
modbus.ndbuf[i++]=0x06; //功能码
modbus.ndbuf[i++]=Regadd/256;
modbus.ndbuf[i++]=Regadd%256;
modbus.ndbuf[i++]=val/256;
modbus.ndbuf[i++]=val%256;
crc=Modbus_CRC16(modbus.ndbuf,i);
modbus.ndbuf[i++]=crc/256; //
modbus.ndbuf[i++]=crc%256;
Modbus_485_TX_Mode;
for(j=0;j<i;j++)
{
Modbus_Send_Byte(modbus.ndbuf[j]);
}
Modbus_485_RX_Mode;
}
// Modbus事件处理函数
void Modbus_Event()
{
u16 crc,rccrc;
//没有收到数据包
flag == 0)
{
return;
}
//收到数据包
//通过读到的数据帧计算CRC
crc = Modbus_CRC16(&buf[0],unt-2);
// 读取数据帧的CRC
rccrc = unt-2]*unt-1]; if(crc == rccrc) //CRC检验成功开始分析包
{
buf[0] == add) // 检查地址是否时⾃⼰的地址
{
buf[1]) //分析modbus功能码
{
ca 0: break;
ca 1: break;
ca 2: break;
ca 3: Modbus_Func3(); break;
ca 4: break;
ca 5: break;
ca 6: Modbus_Func6(); break;
ca 7: break;
ca 8: break;
ca 9: break;
}
}
el buf[0] == 0) //⼴播地址不予回应
}
}
}
// Modbus_TIM Modbus_USART中断函数配置
void ISR_Init()
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //分组
//Moubud TIM NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = Modbus_Time_IRQn; //Modbus_TIM中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //先占优先级1级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //从优先级2级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器 //Moubud USART NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = Modbus_USART_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;//抢占优先级1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //⼦优先级0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
}
#ifndef _modbus_h_
#define _modbus_h_
#include "stm32f10x.h"
#include "modbus_crc.h"
#include "modbus_uart.h"
#include "modbus_485.h"
#include "modbus_time.h"
26个大写字母typedef struct
{
u8 myadd; //本设备从机地址
u8 rcbuf[100]; //modbus接受缓冲区
u8 timout; //modbus数据持续时间
u8 recount; //modbus端⼝接收到的数据个数
u8 timrun; //modbus定时器是否计时标志
u8 reflag; //modbus⼀帧数据接受完成标志位
belt怎么读u8 ndbuf[100]; //modbus接发送缓冲区
}MODBUS;
extern MODBUS modbus;
extern u16 Reg[];
void Modbus_Init(void);
void Modbus_Func3(void);
void Modbus_Event(void);
void ISR_Init(void);
#endif
#include "modbus_485.h"
void Modbus_485_Init()
{
//Modbus_485_RT GPIO端⼝设置
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(Modbus_485_RT_Clock, ENABLE); //使能485_RT时钟
GPIO_InitStructure.GPIO_Pin = Modbus_485_RT_Pin; //485_RT端⼝配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO⼝速度为50MHz
GPIO_Init(Modbus_485_RT_Port, &GPIO_InitStructure); //根据设定参数初始化
Modbus_485_RX_Mode; //初始化为接收状态
}
#ifndef _modbus_485_h_
#define _modbus_485_h_
#include "stm32f10x.h"
// modbus信号控制端⼝
#define Modbus_485_RT_Port GPIOC
#define Modbus_485_RT_Pin GPIO_Pin_2
#define Modbus_485_RT_Clock RCC_APB2Periph_GPIOC
#define Modbus_485_RX_Mode GPIO_RetBits(Modbus_485_RT_Port,Modbus_485_RT_Pin) #define Modbus_485_TX_Mode GPIO_SetBits(Modbus_485_RT_Port,Modbus_485_RT_Pin)
void Modbus_485_Init(void);
#endif
#include "modbus_crc.h"
/* CRC ⾼位字节值表 */
const u8 auchCRCHi[] = {
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
液体比重计0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
spellman0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,local是什么意思
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
} ;
/* CRC低位字节值表*/
const u8 auchCRCLo[] = {
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 0
x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
0x43, 0x83, 0x41, 0x81, 0x80, 0x40
} ;
/******************************************************************
功能: CRC16校验
输⼊:
输出:
******************************************************************/
u16 Modbus_CRC16( u8 *puchMsg, u16 usDataLen )
{
u8 uchCRCHi = 0xFF ; // ⾼CRC字节初始化
u8 uchCRCLo = 0xFF ; // 低CRC 字节初始化
unsigned long uIndex ; // CRC循环中的索引
while ( usDataLen-- ) // 传输消息缓冲区
{
uIndex = uchCRCHi ^ *puchMsg++ ; // 计算CRC
uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ;
uchCRCLo = auchCRCLo[uIndex] ;
}
西安石油大学研究生院return ( uchCRCHi << 8 | uchCRCLo ) ;
}