200 smart的PLC使用modbus rtu和自研单板通讯

发布于:2022-12-02 ⋅ 阅读:(1408) ⋅ 点赞:(1)

200 smart的PLC使用modbus rtu和stm32单板通讯

1. 200 smart的PLC部分程序

  1. modbus初始化部分:
    EN:使能,一直为ON;
    Mode:模式,1=modbus,0=PPI;
    Baud:波特率,9600,19200等;
    Parity:奇偶校验;0=无校验,1=奇校验,2=偶校验;
    Port:端口;0=端口0,1=端口1。
    Timeout:通信超时,1ms到32767ms 之间的任何值;典型值是1000ms (1 s),一般要足够大,让从站有足够的反应时间;
    Done:完成位;
    Error:错误字节。
    在这里插入图片描述
  2. modbus消息发送:
    EN,使能一直为1;
    First,触发,使用沿指令;
    Slave,从站地址;
    RW,读写;0读,1写;
    Addr,从站的数据区:
    Count,是个数;
    DataPtr,主站的数据区;如果RW处是写,则是把该引脚处数据写到从站,如果RW处是读,则是把从站数据读到该引脚处;必须使用指针符号(&)
    在这里插入图片描述

注意事项:

离散量输出(线圈)和保持寄存器支持读请求和写请求。
离散量输入(触点)和输入寄存器仅支持读请求。

参数地址 (Addr) 是起始 Modbus 地址。S7?200 SMART 支持以下地址范围:
对于离散量输出(线圈),为 00001 至 09999
对于离散量输入(触点),为 10001 至 19999
对于输入寄存器,为 30001 至 39999
对于保持寄存器,为 40001 至 49999 和 400001 至 465535

Modbus 从站设备支持的地址决定了 Addr 的实际取值范围。

2.STM32 部分程序

使用9600波特率:加大通讯距离,项目本身对速率要求不高。
在这里插入图片描述
使用DMA方式,目的:减小CPU负担
在这里插入图片描述
中断开始处理函数

//注意,空闲中断,串口rx配置上拉
//stm32f1xx_it.c 文件中 USART3_IRQHandler()接口
//空闲中断是接收到一个数据以后,接收停顿超过一字节时间  认为桢收完,总线空闲中断是在检测到在接收数据后,数据总线上一个字节的时间内,没有再接到数据后发生。
void __MODBUS_UART_DMA_Recv_Begin_Handler(UART_HandleTypeDef *huart)
{
	uint32_t tmp_flag = 0;
	uint32_t dma_idle_num ;
	uint32_t valid_num ;


	tmp_flag =__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE); //获取IDLE标志位
	if((tmp_flag != RESET))//idle标志被置位
	{ 
		__HAL_UART_CLEAR_IDLEFLAG(huart);//清除标志位
		//temp = huart4.Instance->SR;  //清除状态寄存器SR,读取SR寄存器可以实现清除SR寄存器的功能
		//temp = huart4.Instance->DR; //读取数据寄存器中的数据
		//这两句和上面那句等效
		//关闭串口接收的DMA通道。一是防止又有数据接收到,产生干扰;二是便于DMA重新配置赋值。
		HAL_UART_DMAStop(huart); //
		dma_idle_num = __HAL_DMA_GET_COUNTER(&hdma_usart3_rx);// 获取DMA中未传输的数据个数   
		//temp  = hdma_usart4_rx.Instance->NDTR;//读取NDTR寄存器 获取DMA中未传输的数据个数,
		//这句和上面那句等效

		//总计数减去未传输的数据个数,得到已经接收的数据个数
		/// 使用RS485发送数据测试,该长度准确
		valid_num = sizeof(modbus_dma_rx_buf) - dma_idle_num;
		MODBUS_Package_Copy_2_buf(valid_num);

	}

	//中断退出时
	//HAL_UART_Receive_DMA(p_huart_modbus, huart4_rx_buffer, huart4_BUF_SIZE);	
	return;
}

中断完成处理函数

//中断完成触发
//stm32f1xx_it.c 文件中 USART3_IRQHandler()接口
void __MODBUS_UART_DMA_Recv_Complete_Handler(UART_HandleTypeDef *huart)
{
	//且此时接收到的数据长度为缓存器的数据长度
	HAL_UART_Receive_DMA(p_huart_modbus, modbus_dma_rx_buf, sizeof(modbus_dma_rx_buf));
}

DMA接收完成二分之一处理函数

/*
通过对HAL库中HAL_UART_RxCpltCallback这个弱函数的重写可以实现对DMA完成中断的处理,
这个函数虽然声明在stm32f4xx_hal_uart.c中,其实DMA完成中断最后调用的是串口接收完成的回调函数。
*/

/*    |half  a      |        half  b  |*/
void __MODBUS_UART_RxHalfCpltCallback(void)
{
	
	//DMA接收函数,此句一定要加,不加接收不到第一次传进来的实数据,是空的,
	//且此时接收到的数据长度为缓存器的数据长度
	HAL_UART_Receive_DMA(p_huart_modbus, modbus_dma_rx_buf, sizeof(modbus_dma_rx_buf));
}

3 .协议解析部分

读数据:

注意:本项目地址主要为寄存器,使用 40001-49999; 地址有要求,详见plc编程帮助。
slave=10,rw =0, addr=40001, count=1
数据:0A 03 00 00 00 01 85 71
slave=10,rw =0, addr=40002, count=1
数据:0A 03 00 01 00 01 D4 B1

总结:读1个字(不是字节)的格式:
slave地址+ 功能(03读)+寄存器地址(减去40001的值)+读取数量+CRC校验
1字节-------1字节------------- 2字节--------------------------------- 2字节------- 2字节
在这里插入图片描述### 写数据:
写1个字:
slave=10,rw =1, addr=40001, count=1, 写入值:0 (如下图)
数据:0A 06 00 00 00 00 88 B1
slave=10,rw =1, addr=40001, count=1, 写入值:11
数据:0A 06 00 00 00 0B C9 76
slave=10,rw =1, addr=40003, count=1, 写入值:11
数据:0A 06 00 02 00 0B 68 B6

总结:写1个字(不是字节)的格式:
slave地址+ 功能(06写)+寄存器地址(减去40001的值)+写入值+CRC校验
1字节-------1字节------------- 2字节--------------------------------- 2字节------- 2字节
在这里插入图片描述写2个字
slave=10,rw =1, addr=40003, count=2, 写入值:11 (如下图)
0A 10 00 02 00 02 04 00 0B 00 00 26 90
slave=10,rw =1, addr=40005, count=2, 写入值:11
0A 10 00 04 00 02 04 00 0B 00 00 A6 BA
写3个字
slave=10,rw =1, addr=40005, count=3, 写入值:11
0A 10 00 04 00 03 06 00 0B 00 00 00 00 18 1F
slave=10,rw =1, addr=40006, count=3, 写入值:11
0A 10 00 05 00 03 06 00 0B 00 00 00 00 49 DA

总结:写多个字(不是字节)的格式:
slave地址+ 功能(16)+寄存器地址(减去40001的值)+寄存器数量+ 写入字节数+写入值+CRC校验
1字节------- 1字节--------- 2字节---------------------------------- 2字节-----------1字节----------2n字节— 2字节
在这里插入图片描述参考:
值得收藏 Modbus RTU 协议详解
Modbus调试软件–ModbusPoll、ModbusSlave使用详解

本文含有隐藏内容,请 开通VIP 后查看