0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于MODBUS协议用STM32F103做从机接收发送数据包实验

汽车电子技术 来源:qq_34471646 作者:qq_34471646 2022-06-14 17:47 次阅读

给大家分享一个网友qq_34471646做的实验,用STM32做从机接收主机发送过来的数据包(也是基于modbus协议),而后从机将一些数据发送给主机。

首先呢还是介绍下modbus协议。其实modbus协议你不需要了解太多。既然是要使用,那么你只需要明白一点,modbus协议就是在你要发送的数据的基础上,在数据前面加上一个帧头,数据后面加一个帧尾。嗯,是不是还是有点迷?举个例子吧。


寄存器108的内容表示为两个十六进制字节值02 2B,或十进制555. 将寄存器109--110的内容分别表示为十六进制的00 00和 00 64;或十进制的0 和100.

所以主机会发过来一帧数据:01 03 00 6B 00 03 17 74(这个01是我假设主机的地址,这个域名的作用就是用来判断是否是主机发送过来的数据。因为通信过程可能因为各种原因而导致主机发送过来的数据异常,故而我们从机接收到数据之后会先对数据进行分析主机发过来的数据是否正常,正常从机再发送数据过去,异常则不对这帧数据进行响应即从机不发数据。17 74是根据01 03 00 6B 00 03计算出来的CRC校验值。)

当从机接收到这串数据,并且判断数据正常则发送一帧数据到主机:02 03 06 02 2B 00 00 00 64 11 8A(同样的02是我假设的这个从机的地址,需注意的是咱们假设自己的从机地址不要与主机的地址相同。)在这帧数据中帧头就是02 03 06,11 8A是根据02 03 06 02 2B 00 00 00 64计算出来的CRC 校验值也是帧尾。

那么问题来了。。。程序中我们怎么去计算CRC校验值呢???这个嘛 ,下方我会贴上整个实验的例程,其中CRC.c中h函数unsigned int GetCRC16(unsigned char *ptr, unsigned char len)我们只需要调用这个函数就可以算出CRC校验值了。有兴趣的也可以去额外了解下CRC校验具体是怎么实现的。

整个实验例程如下:

main.c:

#include "stm32f10x.h"
#include "bsp_485.h"
#include "bsp_led.h"
#include "crc16.h"
/*描述:硬件RS485接口 协议:Modbus RTU
*功能:采用DMA方式发送数据,中断方式接收数据。
*注: 接收到指令之后,判断是否是相应指令而进行DMA数据发送。
*/
/*DMA:开启DMA,DMA发送完一帧数据后产生发送完成中断,
* 在DMA发送完成中断中,开启USART接收中断(字节)
* 在USART接收中断中保存接收到的数据。
*注: 本程序额外开启了USART空闲中断,在空闲中断中将
* USART接收中断中接收到的数据发送至串口调试助手显示
* 并开启DMA请求
*/
extern uint8_t u3Temp;
extern uint16_t uart3_p;
extern uint16_t ReceivedUsart3Flag,tempU3,uart3_RXbuff[];
extern uint8_t SendU3Buff[SENDU3BUFF_SIZE];
uint16_t len,iU3;
uint8_t u2_Temp;
char *pbuf;
void SendUsart3Buff(void);
void SendU3DatatoDebug(void);
void load_U3_SendBuff(void);
int main(void)
{
load_U3_SendBuff();
LED_GPIO_Config();
USART3_Config();
while(1)
{
}
}
/*Description:调试通信程序专用,用于将接收到的数据再发送到串口调试助手显示*/
void SendU3DatatoDebug()
{
for(uart3_p= 1; uart3_p <= u3Temp; uart3_p++)
{
Usart_SendByte(USART3,uart3_RXbuff[uart3_p]);
}
uart3_p = 1;
RS485_RX_EN();
ReceivedUsart3Flag = 0;
}
/*将USART3需要发送的数据存放在SendU3Buff[]中*/
void load_U3_SendBuff()
{
uint16_t CRCtemp;
SendU3Buff[0]=0x01;//ID
SendU3Buff[1]=0x03;//功能码
SendU3Buff[2]=0x0C;//内容数据字节数
/*填充将要发送的数据(两个字节为一个寄存器的值)*/
SendU3Buff[3]=0x00; //数据1(slave地址0,网站上地址40001)
SendU3Buff[4]=0x64;
SendU3Buff[5]=0x00;//数据2(slave地址1,网站上地址40002)
SendU3Buff[6]=0x96;
SendU3Buff[7]=0x00;//数据3
SendU3Buff[8]=0xC8;
SendU3Buff[9]=0x00; //4
SendU3Buff[10]=0xFA;
SendU3Buff[11]=0x01;//5页面未添加该数据
SendU3Buff[12]=0x2B;
SendU3Buff[13]=0x01;//6
SendU3Buff[14]=0x5E;
CRCtemp = GetCRC16(SendU3Buff, 15);
/*CRC校验值*/
SendU3Buff[15] = CRCtemp;//存放CRCl
SendU3Buff[16] = (CRCtemp >> 8); //保存CRCh//SendBuff[i] = ((CRCtemp<<8)|(CRCtemp>>8)); //保存CRCh
}
485.c:

#include "bsp_485.h"
uint8_t SendU3Buff[SENDU3BUFF_SIZE];
static void NVIC_USART3_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* 嵌套向量中断控制器组选择 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
/* 配置USART为中断源 */
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
/* 抢断优先级*/
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
/* 子优先级 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
/* 使能中断 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
/* 初始化配置NVIC */
NVIC_Init(&NVIC_InitStructure);
}
static void NVIC_DMA1_2_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* 嵌套向量中断控制器组选择 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
/* 配置USART为中断源 */
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_IRQn;
/* 抢断优先级*/
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
/* 子优先级 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
/* 使能中断 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
/* 初始化配置NVIC */
NVIC_Init(&NVIC_InitStructure);
}
//static void NVIC_DMA1_2_Configuration(void)
//{
// NVIC_InitTypeDef NVIC_InitStructure; /* Configure one bit for preemption priority */
// NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
// NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_IRQn;
// NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
// NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
// NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
// NVIC_Init(&NVIC_InitStructure);
//}
/**
* U3:TX:PB10 RX:PB11 TXRXEN:PD3
* U5:TX:PC12 RX:PD1 TXRXEN:PD0
*
*/
void USART3_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
// 打开串口GPIO的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//TX、RX是时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);//EN时钟
// 打开串口外设的时钟
DEBUG_USART_APBxClkCmd(RCC_APB1Periph_USART3, ENABLE);//USART时钟
// 将USART Tx的GPIO配置为推挽复用模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 将USART Rx的GPIO配置为浮空输入模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* 设置485收发控制管脚为推挽输出Out_PP */
GPIO_InitStructure.GPIO_Pin = RS485_RE_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD , &GPIO_InitStructure);
// 配置串口的工作参数
// 配置波特率
USART_InitStructure.USART_BaudRate = 115200;
// 配置 针数据字长
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
// 配置停止位
USART_InitStructure.USART_StopBits = USART_StopBits_1;
// 配置校验位
USART_InitStructure.USART_Parity = USART_Parity_No ;
// 配置硬件流控制
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
// 配置工作模式,收发一起
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
// 完成串口的初始化配置
USART_Init(USART3, &USART_InitStructure);
// 串口中断优先级配置
NVIC_USART3_Configuration();
// 使能串口接收中断
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
// 使能串口空闲中断(用于检测一帧数据接收完毕)
USART_ITConfig(USART3, USART_IT_IDLE, ENABLE);
// 使能串口
USART_Cmd(USART3, ENABLE);
/*控制 485 芯片进入接收模式*/
RS485_RX_EN();//
}
void USART3_DMA_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;
// 开启DMA时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
/* 复位初始化 DMA 数据流 */
DMA_DeInit(DMA1_Channel2);
// 设置DMA外设地址:串口数据寄存器地址*/
DMA_InitStructure.DMA_PeripheralBaseAddr = USART_DR_ADDRESS;
// 内存地址(要传输的变量的指针)
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendU3Buff;
// 方向:从内存到外设
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
// 传输大小
DMA_InitStructure.DMA_BufferSize = SENDU3BUFF_SIZE;
// 外设地址不增
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
// 内存地址自增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
// 外设数据单位
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
// 内存数据单位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
// DMA模式,一次或者循环模式
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;
//DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
// 优先级:中
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
// 禁止内存到内存的传输
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
// 配置DMA通道
DMA_Init(USART_TX_DMA_CHANNEL, &DMA_InitStructure);
NVIC_DMA1_2_Configuration();
//开启DMA通道的TC中断:传输完成中断
DMA_ITConfig(DMA1_Channel2,DMA_IT_TC,ENABLE);
// 使能DMA
DMA_Cmd (DMA1_Channel2,ENABLE);
}
/***************** 发送一个字符 **********************/
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
/* 发送一个字节数据到USART */
USART_SendData(pUSARTx,ch);
/* 等待发送数据寄存器为空 */
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
/***************** 发送字符串 **********************/
void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{
unsigned int k=0;
do
{
Usart_SendByte( pUSARTx, *(str + k) );
k++;
} while(*(str + k)!='\0');
/* 等待发送完成 */
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET)
{}
}
/***************** 发送一个16位数 **********************/
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch)
{
uint8_t temp_h, temp_l;
/* 取出高八位 */
temp_h = (ch&0XFF00)>>8;
/* 取出低八位 */
temp_l = ch&0XFF;
/* 发送高八位 */
USART_SendData(pUSARTx,temp_h);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
/* 发送低八位 */
USART_SendData(pUSARTx,temp_l);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
/*
Desc:接收中断时,将接收到的所有数据用数组保存。
*/
//中断缓存串口数据
#define UART_BUFF_SIZE 1024
uint16_t uart3_p = 1;
uint16_t uart3_RXbuff[UART_BUFF_SIZE];
uint8_t u3Temp;
uint8_t tempU3;
uint8_t ReceivedUsart3Flag = 0;
uint16_t clr;
uint16_t a=0x00;
void bspU3_RS485_IRQHandler(void)
{
if (USART_GetITStatus( USART3, USART_IT_RXNE) != RESET) //收到一个字节的数据
{//保存接收到的数据
uart3_RXbuff[uart3_p] = USART_ReceiveData(USART3);
uart3_p++;
}
if (USART_GetITStatus(USART3, USART_IT_IDLE) != RESET) //收到一帧的数据
{//将接收到的数据发送到串口调试助手上以便观察数据是否正确
u3Temp = uart3_p-1;
clr = USART3->SR;
clr = USART3->DR;
ReceivedUsart3Flag = 1;
RS485_TX_EN() ;
// for(uart3_p= 1; uart3_p <= u3Temp; uart3_p++)//调试通信程序专用,用于将接收到的数据再发送到串口调试助手显示
// {
// Usart_SendByte(USART3,uart3_RXbuff[uart3_p]);
// }
uart3_p = 1;
// LED1_OFF;
// LED2_OFF;
// LED3_OFF;
// LED4_OFF;
LED1_ON;
LED2_ON;
LED3_ON;
LED4_ON;
if(uart3_RXbuff[1]==0x01&&uart3_RXbuff[2]==0x03&&uart3_RXbuff[3]==0x00&&uart3_RXbuff[4]==0x00&&
uart3_RXbuff[5]==0x00&&uart3_RXbuff[6]==0x06&&uart3_RXbuff[7]==0xC5&&uart3_RXbuff[8]==0xC8)
// uart3_RXbuff[9]==0x00&&uart3_RXbuff[10]==0x01&&uart3_RXbuff[11]==0x03&&uart3_RXbuff[12]==0x9C&&
// uart3_RXbuff[13]==0x41&&uart3_RXbuff[14]==0x00&&uart3_RXbuff[15]==0x02&&uart3_RXbuff[16]==0x17&&
{
/* DMA发送使能 */
USART3_DMA_Config();
RS485_TX_EN() ;
USART_DMACmd(USART3, USART_DMAReq_Tx, ENABLE);//这个放在最后
}
}
}
void bspU3_RS485_DMA_IRQHandler()
{
if(DMA_GetITStatus(DMA1_IT_TC2))
{
//清TC标志
DMA_ClearITPendingBit(DMA1_IT_GL2); //清除全部中断标志 //DMA_ClearFLAG(DMA1_FLAG_TC2); //清除全部中断标志(这种写法也可以)
while(USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET); //等待USART1发送完成标志TC置1
USART_ClearFlag(USART3, USART_FLAG_TC); //清除发送完成标志
}
//关闭DMA通道
DMA_Cmd(DMA1_Channel2, DISABLE);
RS485_RX_EN();
}

CRC16.c:

#include "crc16.h"
unsigned int GetCRC16(unsigned char *ptr, unsigned char len)
{
uint16_t index;
uint8_t crcl = 0xFF; //高CRC字节
uint8_t crch = 0xFF; //低CRC字节
uint8_t TabH[] = { //CRC高位字节值表
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,
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
} ;
u8 TabL[] = { //CRC低位字节值表
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,
0x22, 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
} ;
while (len--) //计算指定长度的CRC
{
index = crcl ^ *ptr++;
crcl = crch ^ TabH[index];
crch = TabL[index];
}
return ((crch<<8) | crcl);  
}

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • MODBUS
    +关注

    关注

    27

    文章

    1437

    浏览量

    75691
  • STM32
    +关注

    关注

    2239

    文章

    10671

    浏览量

    348733
  • ModBus协议
    +关注

    关注

    3

    文章

    148

    浏览量

    33196
  • STM32F103
    +关注

    关注

    33

    文章

    474

    浏览量

    62571
收藏 人收藏

    评论

    相关推荐

    STM32F030串口IDLE中断接收不定长度数据包,中断异常的原因?

    ;CR1 ~(1<<4); //清除IDLE中断 rxne_num=0; } STM32F103:当串口调试工具,发送E1E2E3E4数据时,接收到第四个字节E4时,程序
    发表于 04-12 06:08

    Modbus协议网关是什么?Modbus协议网关的功能

    数据的互联互通。Modbus协议作为一种广泛应用于工业控制领域的通信协议,主要用于在主设备(如PLC、SCADA系统)与从设备(如传感器、执行器、智能仪表等)之间交换数据
    的头像 发表于 04-11 15:51 125次阅读

    stm32f103如何实现spi接收不定长数据

    stm32f103 如何实现spi接收不定长数据数据首字节说明了
    发表于 03-28 07:47

    STM32F103C8T6 SPI发送数据错误的原因?

    主机的是STM32F103C8T6,SPI1,的是STM32F051C8T6,SPI2,
    发表于 03-11 08:24

    STM32H7接收数据包异常,一接收数据出现两发送的内容怎么解决?

    );__HAL_UART_DISABLE_IT( huart1, DMA_IT_HT); 2、发送数据包1
    发表于 03-08 08:05

    modbus协议功能码分类 modbus协议功能码是什么,有什么作用

    Modbus协议是一种用于工业领域常见的通信协议,它基于主从结构,用于在不同设备之间实现数据交换。Modbus协议的功能码是决定数据交换类型
    的头像 发表于 01-31 14:47 1475次阅读

    modbus协议与485协议区别

    Modbus协议与485协议是工业通信领域中常用的两种协议,它们在不同的层面上具有不同的功能和设计理念。本文将对Modbus协议与485协议
    的头像 发表于 01-11 11:06 5410次阅读

    在消防预警系统中Modbus协议和EthernetIP协议都发挥着重要的作用

    Modbus协议是一种串行通信协议,最初是为PLC(可编程逻辑控制器)之间的通信而设计的。如今,Modbus协议在消防预警系统中应用广泛。它可以实现主从通信,主设备发送请求,
    发表于 01-02 19:34

    modbus协议应用指南

    modbus协议
    发表于 12-04 09:45 1次下载

    如何将FreeMODBUS协议栈移植到AT32F43x单片

    本应用笔记介绍了如何将FreeMODBUS协议栈移植到AT32F43x单片方法。本文档提供的源代码演示了使用Modbus的应用程序。单片
    发表于 10-26 06:18

    怎么MODBUS协议实现开关量采集与控制采集?

    怎么MODBUS协议实现开关量采集与控制采集
    发表于 10-23 08:17

    接收CAN公共汽车上数据包的代码

    应用程序: 这个样本代码接收 CAN 公共汽车上的数据包, 使用协议中断的检测来与 CAN 公共汽车通信的失败率匹配, 并动态调整 M253 CANFD 的失败率 。 BSP 版本:M253系列
    发表于 08-29 06:24

    如何“直接”ESP8266发送接收tcp/ip数据包“?

    /我的 CPU 发送/接收 ascii。所以它基本上创建了 一个到 CPU 的远程终端接口。 相反,我需要的是让 CPU 能够直接指示 ESP8266 向 IP 地址发送
    发表于 05-15 07:05

    Modbus协议的理解

    秒,否则,接受设备将认为是传送错误。   功能码是主站告诉站要执行的功能。例如运行命令,读取监控状态,修改参数,读取参数等。MODBUS协议制定了相关的功能代码,数据区为功能码的内容,执行什么运行
    发表于 05-05 16:47

    RS485和Modbus通信协议让工业自动化更高效

    的可靠性,该协议采用了循环冗余校验(CRC)方法来检查数据包的完整性。CRC校验码是基于收发数据包计算出的,并且在发送端和
    发表于 05-05 16:25