Modbus编程实践

一、网络协议深入了解。练习wireshark抓取网络数据包。在两台的电脑(笔记本电脑win10 主机与ubuntu虚拟机。网卡选择桥接模式,可得到两个子网IPv4地址)上运行 “疯狂聊天室”程序,通过wireshark抓包:
一、建立自己的房间
双击crazychat.exe,创建聊天室
二、更改适配器设置
留下连接的网络,禁用其他网关。
控制面板->网络和Internet->网络和共享中心->更改适配器设置
三、成功发送消息
在这里插入图片描述
在wireshake中找到,可以看到 Ip address为广播地址255.255.255.255。
在这里插入图片描述
双击打开后可以看到端口号和发送的信息明文显示及字节编码。
在这里插入图片描述
由上述实验操作可以得知是通过广播方式向其他电脑发送数据,就可以使用筛选器将目的地址设为255.255.255.255,在过滤器框内输入ip.addr==255.255.255.255即可筛选出来所有发送的信息。
在这里插入图片描述
可以看出数据包中的文字不是明文。
在这里插入图片描述
总结
由筛选出来的抓包文件可以看出,软件使用的协议是UDP。发送消息的方式是使用广播。
二、c语言完成modbus协议从云端服务器读取信息
新建一个TCP客户端项目
在这里插入图片描述
初始化socket dll,通过IP连接服务器对应端口

// 初始化socket dll。
	WORD winsock_version = MAKEWORD(2,2);
	WSADATA wsa_data;
	if (WSAStartup(winsock_version, &wsa_data) != 0) {
		printf("Failed to init socket!\n");
		return 1;
	}
	
	SOCKET client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (client_socket == INVALID_SOCKET) {
		printf("Failed to create server socket!\n");
		return 2;
	}
	
	struct sockaddr_in server_addr;
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(PORT);
	server_addr.sin_addr.S_un.S_addr = inet_addr(SERVER_IP);
	if (connect(client_socket, (LPSOCKADDR)&server_addr, sizeof(server_addr)) == SOCKET_ERROR) {
		printf("Failed to connect server: %ld !\n", GetLastError());
		return 3;
	}

输入指令格式

	uint8_t data[length_8];
	printf("具体指令给格式为0+传感器编号(1,2,3,4,5)0300010002");
	printf("请输入采集传感器的指令):\r\n");
	scanf("%s",data);

生成将输入指令转化为hex格式并生成crc16校验码

uint16_t crc;
        unsigned char * cmd;
        char crc1[8];
        cmd = fromhex(data);
        crc = CRC_16(cmd);
        uint8_t a = 0xFF;
        for(int i=0;i<6;i++){
            //TODO
            crc1[i] = cmd[i];
        }
        crc1[6] = a & crc;
        crc1[7] = (crc >> 8) & a;

发送,接收数据并使用wireshark对发送数据进行抓包分析

    if (send(client_socket, crc1, 8, 0) < 0) {
            printf("Failed to send data!\n");
            break;
        }
        
        int ret = recv(client_socket, recv_data, BUFFER_SIZE, 0);
        if (ret < 0) {
            printf("Failed to receive data!\n");
            break;
        }
        recv_data[ret]=0; // correctly ends received string
        char yb[4],wd[4];
        for(int i=0;i<4;i++){
            //TODO
            yb[i] = recv_data[4+i];
            wd[i] = recv_data[8+i];
            
        }
        float mic = hexToDec(yb)/100.0;
        float strain_temp = hexToDec(wd)/100.0;
        printf("应变:%f\r\n",mic);
        printf("温度:%f\r\n",strain_temp);
        
        
//        printf("Receive data from server: \"%x\"\n",recv_data);
        if (strcmp(data,kExitFlag)==0) {
            printf("Exit!\n");
            break;
        }

添加过滤信息(ip.dst ==123.56.90.74 and ip.src == 192.168.1.115) or (ip.dst ==192.168.1.115 and ip.src == 123.56.90.74) 只显示服务器发送回来的包以及发送过去的包
运行结果
在这里插入图片描述
三、用stm32最小​​​​​​核心板+AHT20模块,完成一modbus接口的温湿度Slave设备,能够让上位机PC通过modbus协议获取温湿度。主程序采用多任务框架,比如RT-thread Nano。

一、代码
1.通过CubeMX配置stm32
配置RCC
在这里插入图片描述
配置时钟
在这里插入图片描述
配置串口二波特率4800
在这里插入图片描述
配置串口二DMA
在这里插入图片描述

配置串口一
在这里插入图片描述
配置中断
在这里插入图片描述
2.主要代码
重定向输出串口一

usart.c

#include <stdio.h>
int fputc(int ch,FILE *f)
 
{
    HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xFFFF);    
        //等待发送结束    
    while(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_TC)!=SET){
    }        
 
    return ch;
}

添加中断处理

stm32f1xx_it.c的串口2中断处理函数
 
void USART2_IRQHandler(void)
{
  /* USER CODE BEGIN USART2_IRQn 0 */
    uint32_t tmp = 0;
    tmp =__HAL_UART_GET_FLAG(&huart2,UART_FLAG_IDLE); //获取IDLE标志位
    if((tmp != RESET))//idle标志被置位
    { 
        //清除标志位
        //__HAL_UART_CLEAR_IDLEFLAG(&huart2);
        //清除状态寄存器SR,读取SR寄存器可以实现清除SR寄存器的功能
        huart2.Instance->SR;  
        //读取数据寄存器中的数据
        huart2.Instance->DR; 
        HAL_UART_DMAStop(&huart2); //
        // 获取DMA中未传输的数据个数
        dataLength=hdma_usart2_rx.Instance->CNDTR;
        // 接受完成
        isDataEnd = 1;    
        //清除标志位
        __HAL_UART_CLEAR_IDLEFLAG(&huart2);
    }
 
  /* USER CODE END USART2_IRQn 0 */
  HAL_UART_IRQHandler(&huart2);
  /* USER CODE BEGIN USART2_IRQn 1 */
 
  /* USER CODE END USART2_IRQn 1 */
}

main.c
添加变量

extern DMA_HandleTypeDef hdma_usart2_rx;
 
//modbus问询帧
uint8_t commands[3][8]={
{0x01,0x03,0x00,0x00,0x00,0x02,0xC4,0x38},
{0x02,0x03,0x00,0x00,0x00,0x02,0xC4,0x38},
{0x03,0x03,0x00,0x00,0x00,0x02,0xC5,0xE9},
}; 
//modbus应答帧
uint8_t dataBuff[20];
//中断完成标志
uint8_t isDataEnd=0;
//应答帧长度
uint8_t dataLength;
 
//温度
uint16_t temperature;
//湿度
uint16_t humidity;

main函数

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_DMA_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
  //使能idle中断
  __HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);
  //打开串口DMA接收
  HAL_UART_Receive_DMA(&huart2,dataBuff,sizeof(dataBuff));
  //传感器地址
  uint8_t i=0;
  while (1)
  {
 
      //中断完成,解析应答帧
    if(isDataEnd){
        //提取湿度
        humidity=(dataBuff[3] << 8) + (dataBuff[4]);
        //提取温度
        temperature=(dataBuff[5] << 8) + (dataBuff[6]);
        //串口一发送解析结果
        printf("温度: %.1f\t 湿度: %.1f\r\n",temperature/10.0,humidity/10.0);
        memset(dataBuff,0,sizeof(dataBuff));//清空接收数组
        isDataEnd=0;//清除接收结束标志位
    }
    //发送第 i 个传感器的 modbus 问询帧
    HAL_UART_Transmit(&huart2,commands[i],sizeof(commands),0xFFFF);
    //轮询读取三个传感器
    i=(i+1)%3;
    //打开串口DMA接收
    HAL_UART_Receive_DMA(&huart2,dataBuff,sizeof(dataBuff));
    
    //程序运行标志,闪灯
    HAL_Delay(1000);
    HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);
 
}

效果
由于没有硬件,没法上板实验。
总结
这里只是简单的采用了静态指令进行访问数据,没有使用CRC校验。当采用动态指令的时候需要对编号进行自增以及对数据进行CRC校验,并且还需要对各种错误进行解析以及判断。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在工控上位机编程实践中,.NET框架是一个常用的选择。.NET是一个由微软开发的软件框架,它提供了一个稳定和可扩展的平台,用于开发各种应用程序,包括工控上位机。 首先,使用.NET框架进行编程可以提供更高的开发效率和灵活性。.NET框架使用面向对象的编程范例,这意味着可以更好地组织和管理代码。此外,.NET框架提供了许多强大的工具和类库,可以简化常见任务的处理,减少编写代码的工作量。 其次,使用.NET框架可以轻松实现与其他工控设备和系统的通信。工控上位机通常需要与各种外部设备和传感器进行数据交换,以确保系统的正常运行。.NET框架提供了强大的网络编程功能,可以方便地与其他设备进行通信,并处理各种数据格式和传输协议。 此外,使用.NET框架可以轻松创建用户友好的界面。工控上位机通常需要一个直观和易于使用的界面,供操作员监视和控制系统。.NET框架提供了丰富的图形用户界面(GUI)工具,可以方便地创建各种界面元素,并实现交互功能。从简单的按钮和文本框到复杂的图表和数据可视化,.NET框架提供了丰富的控件库,可以满足各种界面设计的需求。 最后,使用.NET框架进行编程还可以提供更高的安全性和可维护性。.NET框架提供了强大的安全功能,可以帮助开发者保护工控系统的机密性和完整性。此外,.NET框架还提供了良好的代码组织和维护功能,使得开发者可以更方便地理解和修改现有的代码。 总之,.NET框架在工控上位机编程实践中具有许多优点。它提供了高效的开发工具、强大的通信功能、友好的用户界面和高水平的安全性。因此,选择使用.NET框架来编写工控上位机应用程序是一个明智的选择。 ### 回答2: .NET工控上位机编程实践是指利用.NET框架进行工业控制系统上位机开发的实践过程。工控上位机是工业自动化系统中的一种关键组成部分,通过与底层设备通信和控制,实现对生产过程的监控和管理。 在编程实践方面,首先需要掌握.NET框架的基本知识,包括C#编程语言以及相关的库和工具。了解面向对象编程的概念和原则,并能够灵活运用在工控上位机编程中。 其次,需要了解工业控制系统的特点和需求,掌握常用的工控通信协议和通信方式,如OPC、Modbus、CAN等。这些通信协议与.NET框架的集成,可以实现与底层设备的数据交互和控制。 然后,需要设计和开发用户界面,以便操作人员可以方便地监控和控制生产过程。.NET框架提供了丰富的可视化开发工具和控件,如Windows Forms、WPF等,可以通过拖拽和代码编写的方式,快速创建界面元素并设置其属性和事件。 另外,对于数据处理和分析功能,可以利用.NET框架中的数据库和数据操作工具,进行数据存储、查询和分析。通过与数据库的连接,可以实现对生产数据的采集和分析,为生产决策提供依据。 最后,需要进行测试和调试,确保上位机系统稳定可靠。利用.NET框架提供的调试工具和单元测试框架,对上位机系统进行全面的验证,发现并解决潜在的问题和错误。 综上所述,.NET工控上位机编程实践是一项复杂而有挑战性的工作。通过掌握.NET框架基础知识和工控系统的特点,合理设计和开发界面和功能,可以实现稳定高效的工业控制系统上位机。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值