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代码我上传到下载资源中可自行下载
作者:绿波电容