stm32与昆仑通态modbus通讯(已验证)

昆仑通态(主机)与stm32(从机)rs485modbus通讯

Modbus tcp:硬件接口是以太网  ;传输网络数据

Modbus rtu:硬件接口rs485 rs232  ;传输二进制数据

Modbus ascll:串口

无论哪种模式都是主机先发报文请求从机通讯进行读或写


1.modbus以03和06功能码为例

该通讯例程只需用到0x03和0x06

03读单/多,主机发送起始地址后为要读的数据长度、

06写单,主机发送起始地址后则为要写的单个数据内容

报文格式

2.昆仑通态组态

先在工作台添加变量

选择串口modbusrtu

连接前面创建的变量,注意该通讯驱动使用03和06功能码时需要选择4区

注意配置屏幕时使用不同的com口引脚定义都不同,另外如果和电脑调试时使用的ttl转rs485不同产品的dp9定义也不同,当时我卡这非常久硬是通讯不上。。。结果是这问题

3.stm32

单片机空闲时需要时刻保持在接收状态,才能随时响应主机发送的请求,单片机发送时先将RE和DE置高,进入发送使能,发送完再拉低,回到接收状态

void Modbus_SendData(u8 *buff,u8 len)
{
	GPIO_SetBits(GPIOA,GPIO_Pin_11);
	u8 t;
	for(t=0;t<len;t++)	
	{
		while(USART_GetFlagStatus(MODUBS_UART,USART_FLAG_TC)==RESET);
		USART_SendData(MODUBS_UART,buff[t]); 
	}	 
	while(USART_GetFlagStatus(MODUBS_UART,USART_FLAG_TC)==RESET);
	GPIO_ResetBits(GPIOA,GPIO_Pin_11);
}

调试过程中掉入了一个误区,就是发现在屏幕修改占空比时,单片机能接收到并修改,就是不能调用10功能码(同时写多个寄存器)发送一串数据里面包含第0个寄存器占空比和第1个寄存器频率的值,每次屏幕修改完都会立刻发送06写单个寄存器的报文,仔细查看功能码发现06功能码已经满足项目需求,从机每次接收到主机写寄存器报文时,只需要判断报文寄存器的地址是否对应即可

modbus核心代码

case 06:即为接收到主机请求写寄存器报文时执行

一个数据把高八位和低八位分别存放在两个数组内,防止数据长度不够导致数据丢失

void Modbus_Service(void)
{
	u16 recCRC;
	if(Modbus_FrameFlag==1)
	{
		calCRC = GetCRC16(Modbus_RX_BUFF,Modbus_RX_LEN-2);
		recCRC=Modbus_RX_BUFF[Modbus_RX_LEN-1]|(((u16)Modbus_RX_BUFF[Modbus_RX_LEN-2])<<8);
		if(calCRC==recCRC)//CRC校验正确
		{
			if(Modbus_RX_BUFF[0]==Modbus_Addr)//地址正确
			{
				startRegAddr=(((u16)Modbus_RX_BUFF[2])<<8)|Modbus_RX_BUFF[3];//获取寄存器起始地址
				switch(Modbus_RX_BUFF[1])//根据不同的功能码进行处理
				{
					case 03: //读多个寄存器
					{
						Modbus_03_Solve();
						break;
					}
					case 06: //写单个寄存器
					{
						Modbus_06_Solve();
						if((u16)Modbus_RX_BUFF[3] == 0)
						{
						  TIM_SetCompare1(TIM8,(((u16)Modbus_RX_BUFF[4])<<8)|Modbus_RX_BUFF[5]); //占空比50
							//Tx:01 06 00 00 00 32 08 1F 设置0寄存器占空比为50时主机报文
						}
			    	if((u16)Modbus_RX_BUFF[3] == 1)
						{
						  PWM_SetPrescaler(((((u16)Modbus_RX_BUFF[4])<<8)|Modbus_RX_BUFF[5])*10) ; //单位HZ
							//Tx:01 06 00 01 07 D0 DB A6  设置1寄存器2k
						}
					  break; 
			  	}
					case 16: //写多个寄存器
					{
						Modbus_16_Solve();
						break;
					}
				}
			}
		}
		Modbus_FrameFlag=0;//复位帧结束标志
		Modbus_RX_CNT=0;//接收计数器清零
		Modbus_RX_LEN = 0;
	}
}

RTU通讯每一帧数据之间没有固定的包头和包尾,即需要添加毫秒定时器定时3.5个字节来作为包尾,以9600波特率为例,传输一个字节需要的时间是1/9600*10=1.04ms ,3.5个字节即为3.5ms


另外在调试过程中要多使用调试工具和示波器,通讯不上时可用示波器查看抓包发送的报文(使用方法上篇文章提到),然后就是把屏幕和stm32分开分别和电脑modbus助手调试,都通讯成功后再整机测试

完整stm32代码我上传到下载资源中可自行下载

  • 14
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值