OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 42642|回复: 86

STM32 跟触摸屏modbus-rtu通信问题(485)

[复制链接]

29

主题

486

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3083
金钱
3083
注册时间
2014-7-19
在线时间
413 小时
发表于 2014-7-20 19:27:53 | 显示全部楼层 |阅读模式
5金钱
[mw_shl_code=c,true]void TIM2_IRQHandler(void) { if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)//判断是否发生TIM2更新中断 { TIM_Cmd(TIM2,DISABLE); //关掉定时器2 TIM_SetCounter(TIM2, 0);//重新设初值0 if(recenum >= 8) { Uart1_rev_flag = 1;//接收完毕一帧,置位标志位,通知主函数调用接收处理函数 USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);//失能串口1接收中断 } recenum = 0; GPIO_SetBits(GPIOF,GPIO_Pin_13);//485发送使能 TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//清除TIM2的中断待处理位 TIM_ClearFlag(TIM2, TIM_FLAG_Update);//清除TIM2待处理标志位 } } void USART1_IRQHandler(void) { if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)//接收中断 { USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清除USART1中断待处理位RXNE(RXNE=0) if(Uart1_rev_flag != 1) { if(recenum < 12)//接收分8字节数据 和11字节数据 { ReceBuf[recenum] = USART1->DR; recenum++; TIM_Cmd(TIM2, ENABLE); TIM_SetCounter(TIM2, 0); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); } } } /*if(USART_GetITStatus(USART1,USART_IT_TXE)!=RESET) { USART_ClearITPendingBit(USART1,USART_IT_TXE);//清除USART1中断待处理位RXNE(RXNE=0) USART_SendData(USART1,ReceBuf[sendnum]); sendnum++; if(sendnum == 8) { LED4(ON); sendnum = 0; USART_ITConfig(USART1,USART_IT_TXE,DISABLE); //USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//打开接收中断使能 //GPIO_ResetBits(GPIOF,GPIO_Pin_13);//485使能接收 } }*/ //溢出-如果发生溢出需要先清空SR的溢出位,再读DR寄存器 则可清除不断入中断的问题 if(USART_GetFlagStatus(USART1,USART_FLAG_ORE)!=RESET) { USART_ClearFlag(USART1,USART_FLAG_ORE); //清溢出位 USART_ReceiveData(USART1); //读DR } }[/mw_shl_code]
这是我中断函数,为什么我接收到的第一个数据不是设备地址0x01,但是我用串口监控,看到的是01 03 00 00 00 01 84 0A,但是接收之后就不行了

stm32-modbus.zip

7.05 MB, 下载次数: 57876

最佳答案

查看完整内容[请看2#楼]

哈哈通信成功了,找到关键点了,真的不难只是一开始的方向错误了! 只要知道一点就行了,就是每一帧直接要大于3.5T  T=(数据位+停止位+校验位+起始位)*3.5/波特率; 我用了19200,最好把波特率取高点,只要是大于19200的,3.5T=1750us都行 下面贴上我的代码! [mw_shl_code=c,true]void TIM2_IRQHandler(void) { if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)//判断是否发生TIM2更新中断 { TIM_Cl ...
电子人生!
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

29

主题

486

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3083
金钱
3083
注册时间
2014-7-19
在线时间
413 小时
 楼主| 发表于 2014-7-20 19:27:54 | 显示全部楼层
哈哈通信成功了,找到关键点了,真的不难只是一开始的方向错误了!
只要知道一点就行了,就是每一帧直接要大于3.5T  T=(数据位+停止位+校验位+起始位)*3.5/波特率; 我用了19200,最好把波特率取高点,只要是大于19200的,3.5T=1750us都行
下面贴上我的代码!
[mw_shl_code=c,true]void TIM2_IRQHandler(void) { if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)//判断是否发生TIM2更新中断 { TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//清除TIM2的中断待处理位 TIM_ClearFlag(TIM2, TIM_FLAG_Update);//清除TIM2待处理标志位 TIM_Cmd(TIM2, DISABLE); if(recenum >= 8) { recenum = 0; Uart1_rev_flag = 1;//接收完毕一帧,置位标志位,通知主函数调用接收处理函数 USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);//失能串口1接收中断 GPIO_SetBits(GPIOA,GPIO_Pin_0);//485发送使能,停止接收 } else { recenum = 0; } /*TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//清除TIM2的中断待处理位 TIM_ClearFlag(TIM2, TIM_FLAG_Update);//清除TIM2待处理标志位 TIM_Cmd(TIM2, DISABLE);*/ } } void USART1_IRQHandler(void) { if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)//接收中断 { USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清除USART1中断待处理位RXNE(RXNE=0) if(Uart1_rev_flag != 1) { if(recenum < 11)//接收分8字节数据 和11字节数据 { ReceBuf[recenum] = USART1->DR; recenum++; usDataLen = recenum - 2; TIM_Cmd(TIM2, ENABLE); TIM_SetCounter(TIM2, 0); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); } else { recenum=0; TIM_Cmd(TIM2, ENABLE); TIM_SetCounter(TIM2, 0); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); } } else { USART_ReceiveData(USART1);//如果接收没有处理,放弃接收的数据 } } //溢出-如果发生溢出需要先清空SR的溢出位,再读DR寄存器 则可清除不断入中断的问题 if(USART_GetFlagStatus(USART1,USART_FLAG_ORE)!=RESET) { USART_ClearFlag(USART1,USART_FLAG_ORE); //清溢出位 USART_ReceiveData(USART1); //读DR } }[/mw_shl_code]
这是中断处理函数
电子人生!
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165377
金钱
165377
注册时间
2010-12-1
在线时间
2111 小时
发表于 2014-7-20 23:38:20 | 显示全部楼层
用串口助手看看了.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

29

主题

486

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3083
金钱
3083
注册时间
2014-7-19
在线时间
413 小时
 楼主| 发表于 2014-7-21 08:41:46 | 显示全部楼层
回复【2楼】正点原子:
---------------------------------
我用串口监控看过了,触摸屏发出的数据一直是 01 03 00 00 00 01 84 0A,但是我接收到的数据为什么跟他不一样啊,难道起始位跟停止位也会接收吗?一帧数据要3.5个字符周期 ,我的波特率是19200, 3.5T =  3.5/19200 =1.823 x 10^(-4) S,我设置的TIM2定时是0.2ms,大于3.5T,没接收一个字节,开启TIM2,如果在接下的3.5T没有接收到数据,就进入TIM2中断,置位接收完成标志位,在主函数中进行数据帧解析,感觉思路没有问题啊,为什么就是连不上,原子哥帮我看看有问题,新手才开始!
电子人生!
回复

使用道具 举报

29

主题

486

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3083
金钱
3083
注册时间
2014-7-19
在线时间
413 小时
 楼主| 发表于 2014-7-21 08:43:55 | 显示全部楼层
[mw_shl_code=c,true]#include "stm32f10x.h" #include "misc.h" void Timer_Configuration(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; /*初始化为默认值*/ TIM_DeInit(TIM2); // TIM_InternalClockConfig(TIM2); /* TIM2 clock enable */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); /* TIM2做定时器,基础设置*/ TIM_TimeBaseStructure.TIM_Period = 18; //计数值:18 定时0.18ms 19200 3.5个字符长度 TIM_TimeBaseStructure.TIM_Prescaler =720-1; //预分频,除数:720, 10us TIM_TimeBaseStructure.TIM_ClockDivision = 0; //时钟分频因子为1 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); // Time base configuration /*预先清除更新中断位*/ TIM_ARRPreloadConfig(TIM2, ENABLE);//使能预装载 TIM_ClearFlag(TIM2, TIM_FLAG_Update); // TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //TIM_SetCounter(TIM2, 0); /* 配置溢出中断*/ TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //允许更新中断 TIM_Cmd(TIM2,DISABLE); } [/mw_shl_code]
这是我TIM2初始化,这里是把0.2ms,改成了0.18ms,但是还是不行,感觉就是接收的数据不对!有人做过这方面的吗,求解啊!
电子人生!
回复

使用道具 举报

29

主题

486

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3083
金钱
3083
注册时间
2014-7-19
在线时间
413 小时
 楼主| 发表于 2014-7-21 08:49:05 | 显示全部楼层
回复【2楼】正点原子:
---------------------------------
我用单个变量去接收第一个数据,结果接收到了01
void USART1_IRQHandler(void)
{
num1++;
if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)//接收中断
{
USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清除USART1中断待处理位RXNE(RXNE=0)
if(Uart1_rev_flag != 1)
{
if(num1 == 1)
{
num = USART1->DR;
if(num == 0x01)
{
LED2(ON);
}
}
/*if(recenum < 12)//接收分8字节数据 和11字节数据
{
ReceBuf[recenum] = USART1->DR;
recenum++;
TIM_Cmd(TIM2, ENABLE);
TIM_SetCounter(TIM2, 0);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
}*/
}

}
电子人生!
回复

使用道具 举报

29

主题

486

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3083
金钱
3083
注册时间
2014-7-19
在线时间
413 小时
 楼主| 发表于 2014-7-21 08:50:07 | 显示全部楼层
[mw_shl_code=c,true]void USART1_IRQHandler(void) { num1++; if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)//接收中断 { USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清除USART1中断待处理位RXNE(RXNE=0) if(Uart1_rev_flag != 1) { if(num1 == 1) { num = USART1->DR; if(num == 0x01) { LED2(ON); } } /*if(recenum < 12)//接收分8字节数据 和11字节数据 { ReceBuf[recenum] = USART1->DR; recenum++; TIM_Cmd(TIM2, ENABLE); TIM_SetCounter(TIM2, 0); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); }*/ } } [/mw_shl_code]
LED2亮了,说明第一次进入中断接收到了01,数组为何接收到的跟这不符啊!
电子人生!
回复

使用道具 举报

29

主题

486

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3083
金钱
3083
注册时间
2014-7-19
在线时间
413 小时
 楼主| 发表于 2014-7-21 09:02:05 | 显示全部楼层
[mw_shl_code=c,true]void USART1_IRQHandler(void) { num1++; if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)//接收中断 { USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清除USART1中断待处理位RXNE(RXNE=0) if(Uart1_rev_flag != 1) { if(num1 == 1) { i1 = USART1->DR; } if(num1 == 2) { i2 = USART1->DR; } if(num1 == 3) { i3 = USART1->DR; } if(num1 == 4) { i4 = USART1->DR; } if(num1 == 5) { i5 = USART1->DR; } if(num1 == 6) { i6 = USART1->DR; } if(num1 == 7) { i7 = USART1->DR; } if(num1 == 8) { i8 = USART1->DR; } if((i1 == 0x01) && (i2 == 0x03) && (i3 == 0x00) && (i4 == 0x00) && (i5 == 0x00) && (i6 == 0x01) && (i7 == 0x84) && (i8 == 0x0a)) { LED2(ON); } } } /*if(recenum < 12)//接收分8字节数据 和11字节数据 { ReceBuf[recenum] = USART1->DR; recenum++; TIM_Cmd(TIM2, ENABLE); TIM_SetCounter(TIM2, 0); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); }*/ /*if(USART_GetITStatus(USART1,USART_IT_TXE)!=RESET) { USART_ClearITPendingBit(USART1,USART_IT_TXE);//清除USART1中断待处理位RXNE(RXNE=0) USART_SendData(USART1,ReceBuf[sendnum]); sendnum++; if(sendnum == 8) { LED4(ON); sendnum = 0; USART_ITConfig(USART1,USART_IT_TXE,DISABLE); //USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//打开接收中断使能 //GPIO_ResetBits(GPIOF,GPIO_Pin_13);//485使能接收 } }*/ //溢出-如果发生溢出需要先清空SR的溢出位,再读DR寄存器 则可清除不断入中断的问题 if(USART_GetFlagStatus(USART1,USART_FLAG_ORE)!=RESET) { USART_ClearFlag(USART1,USART_FLAG_ORE); //清溢出位 USART_ReceiveData(USART1); //读DR } } [/mw_shl_code]
这样LED2就不亮了,不知道为什么!
电子人生!
回复

使用道具 举报

43

主题

278

帖子

1

精华

高级会员

Rank: 4

积分
621
金钱
621
注册时间
2013-12-27
在线时间
0 小时
发表于 2014-7-21 09:40:56 | 显示全部楼层
和西门子的触摸屏通讯吗?不错呦!这东西是拿来用的,又不是用来玩儿的,还是多分享一下使用的资料比较好。
水的比较多。
回复

使用道具 举报

29

主题

486

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3083
金钱
3083
注册时间
2014-7-19
在线时间
413 小时
 楼主| 发表于 2014-7-21 10:14:18 | 显示全部楼层
回复【8楼】青苹果PAD:
---------------------------------
是台达的,DOP-BO4S211,问题在于我都没有通信成功,modbus-rtu(485),求高手知道啊,!!
电子人生!
回复

使用道具 举报

29

主题

486

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3083
金钱
3083
注册时间
2014-7-19
在线时间
413 小时
 楼主| 发表于 2014-7-23 15:37:31 | 显示全部楼层
然后是定时器配置
[mw_shl_code=c,true]void Timer_Configuration(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; /*初始化为默认值*/ TIM_DeInit(TIM2); // TIM_InternalClockConfig(TIM2); /* TIM2 clock enable */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); /* TIM2做定时器,基础设置*/ /*T=3.5*( 1 +数据位+奇偶校验+ 停止位)/ 波特率 t=3.5*(1+8+0+1)/波特率 由于t1.5 和 t3.5 的定时,隐含着大量的对中断的管理.在高通信速率下,这导致CPU 负担加 重。因此,在通信速率等于或低于19200 Bps 时,这两个定时必须严格遵守;对于波特率大于 19200 Bps 的情形,应该使用2 个定时的固定值:建议的字符间超时时间(t1.5)为750μs, 帧间的超时时间(t1.5) 为1.750ms。*/ TIM_TimeBaseStructure.TIM_Period = 175; //计数值:175 定时1750us 19200 3.5个字符长度 TIM_TimeBaseStructure.TIM_Prescaler =720; //预分频,除数:720, 10us TIM_TimeBaseStructure.TIM_ClockDivision = 0; //时钟分频因子为1 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); // Time base configuration /*预先清除更新中断位*/ TIM_ARRPreloadConfig(TIM2, ENABLE);//使能预装载 TIM_ClearFlag(TIM2, TIM_FLAG_Update); // TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //TIM_SetCounter(TIM2, 0); /* 配置溢出中断*/ TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //允许更新中断 TIM_Cmd(TIM2,DISABLE); } [/mw_shl_code]

电子人生!
回复

使用道具 举报

29

主题

486

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3083
金钱
3083
注册时间
2014-7-19
在线时间
413 小时
 楼主| 发表于 2014-7-23 15:42:10 | 显示全部楼层
从7月十几号开始搞STM32,2个星期终于弄出来了,建工程硬是弄了一天,看来花点时间总归是对的!哈哈!慢慢进步!
电子人生!
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165377
金钱
165377
注册时间
2010-12-1
在线时间
2111 小时
发表于 2014-7-23 23:04:47 | 显示全部楼层
回复【12楼】翱翔云端的鸟:
---------------------------------
恭喜,付出总有回报.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

0

主题

3

帖子

0

精华

新手入门

积分
31
金钱
31
注册时间
2014-12-19
在线时间
2 小时
发表于 2015-1-27 15:52:24 | 显示全部楼层
回复【5楼】翱翔云端的鸟:
---------------------------------
楼主!不知道你调试出来的还有没有modbus的程序,能让我看看吗?我也刚开始搞modbus,但是一直发送不了数据,中断也能进,不知道那有问题?!
回复

使用道具 举报

1

主题

3

帖子

0

精华

新手入门

积分
27
金钱
27
注册时间
2015-4-24
在线时间
0 小时
发表于 2015-4-24 14:27:31 | 显示全部楼层
回复【12楼】翱翔云端的鸟:
---------------------------------
 我刚开始学MODBUS_RTU,请问我应该怎么测试你的代码,串口调试助手 485电路准备好了,03是上位机读你的CPU的数据,你再按特定格式发回去是吗?
回复

使用道具 举报

1

主题

3

帖子

0

精华

新手入门

积分
27
金钱
27
注册时间
2015-4-24
在线时间
0 小时
发表于 2015-4-24 14:36:19 | 显示全部楼层
回复【11楼】翱翔云端的鸟:
---------------------------------
我串口调试助手向CPU发01 03 00 10 00 02 c5 ce 怎么接收到的是01?
回复

使用道具 举报

1

主题

2

帖子

0

精华

新手入门

积分
26
金钱
26
注册时间
2015-4-24
在线时间
0 小时
发表于 2015-4-24 14:53:12 | 显示全部楼层
翱翔云端的鸟,你好,能否发送下你写的代码,学习下,谢谢
回复

使用道具 举报

29

主题

486

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3083
金钱
3083
注册时间
2014-7-19
在线时间
413 小时
 楼主| 发表于 2015-4-25 22:40:47 | 显示全部楼层
鉴于大家都要看代码,由于程序是整体的,只能把一些C文件的代码全部删除了,上传的是Modbus框架和思想,编译是无法通过的,伸手党就没办法了,主要看main.c     modbus.c     time.c 和中断函数  思想在里面了,需要485通信模块 才能让STM32与触摸屏通信,通信是通过的,稳定无异常!

ModBUS.zip

6.61 MB, 下载次数: 51034

电子人生!
回复

使用道具 举报

0

主题

6

帖子

0

精华

新手上路

积分
26
金钱
26
注册时间
2015-5-11
在线时间
0 小时
发表于 2015-5-25 09:46:32 | 显示全部楼层
回复【10楼】翱翔云端的鸟:
---------------------------------
大神,用modbus poll调试时显示bytes missing errer 和crcerrer是什么情况
回复

使用道具 举报

29

主题

486

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3083
金钱
3083
注册时间
2014-7-19
在线时间
413 小时
 楼主| 发表于 2015-5-26 08:49:32 | 显示全部楼层
回复【19楼】菜鸟stm32:
---------------------------------
没有用过这个虚拟主机端,你用串口调试助手查查看,是不是你的从机没有响应
电子人生!
回复

使用道具 举报

0

主题

4

帖子

0

精华

初级会员

Rank: 2

积分
75
金钱
75
注册时间
2015-5-26
在线时间
6 小时
发表于 2015-6-8 17:53:09 | 显示全部楼层
谢谢了,下载参考一下
回复

使用道具 举报

8

主题

24

帖子

0

精华

初级会员

Rank: 2

积分
159
金钱
159
注册时间
2014-12-9
在线时间
18 小时
发表于 2015-6-10 15:34:57 | 显示全部楼层
回复【19楼】菜鸟stm32:
---------------------------------
串口接收数据 是对的  用定时器 接收帧频就不对了   MODBUS通信不正常
回复

使用道具 举报

0

主题

6

帖子

0

精华

新手上路

积分
26
金钱
26
注册时间
2015-5-11
在线时间
0 小时
发表于 2015-6-26 20:37:57 | 显示全部楼层
回复【20楼】翱翔云端的鸟:
---------------------------------用助手基本调试成功了,可stm32 和海泰克触摸屏通讯如何调试,通过触摸屏往stm32的里写数据,写入数据的地址写什么呢?
回复

使用道具 举报

29

主题

486

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3083
金钱
3083
注册时间
2014-7-19
在线时间
413 小时
 楼主| 发表于 2015-7-7 17:39:06 | 显示全部楼层
回复【23楼】菜鸟stm32:
---------------------------------
触摸屏与STM32对应的地址,  比如你在触摸屏上放了一个数值输入框  设定写入和读取地址都是40001  那么  触摸屏会主动发出 (假设站号是01)  01 03 00 00  00 01 84 0A,然后你STM32响应回发  01 03 02 00 00 00 B8 44,这样你的STM32中的数据就显示上去的


写入是 当你在触摸屏的输入框中输入一个值 后,触摸屏会发出10命令
01 10 00 00 00 01 02 00 0F E6 54然后你需要从这个数据帧中解码出你的数据,放入(一般是数组中),这样就写入了,同时你的STM32回发01 10 00 00 00 01 01 C9,响应触摸屏,这样写入才有效
电子人生!
回复

使用道具 举报

29

主题

486

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3083
金钱
3083
注册时间
2014-7-19
在线时间
413 小时
 楼主| 发表于 2015-7-7 17:40:34 | 显示全部楼层
[mw_shl_code=c,true]发送格式 01 03 00 00 00 01 84 0A 从机地址 功能码 起始地址高|低 寄存器数高 低 CRC低 高 ReceBuf[];//接收缓冲区 Recenum;//接收字节数 响应格式 01 03 02 00 00 ... B8 44 从机地址 功能码 数据字节数 数据1高 数据1低 CRC低 高 数据字节数 = 传送数据个数*2 SendBuf[];//发送缓冲区 Sendnum;//发送字节数 SendBuf[2] = Sendnum - 5; 发送格式: 01 10 00 00 00 01 02 00 0F E6 54 从址 功号 起始地址高低 数量高|低 字节数 数据高|低 CRC低 高 字节数ReceBuf[6] = 2*数据个数 响应格式 01 10 00 00 00 01 01 C9 从机地址 功能码 起始地址高|低 数量高 | 低 CRC低 高[/mw_shl_code]
附上自己写的两个modbus-RTU功能码格式说明  
电子人生!
回复

使用道具 举报

0

主题

2

帖子

0

精华

新手上路

积分
34
金钱
34
注册时间
2015-3-25
在线时间
4 小时
发表于 2015-7-8 09:20:27 | 显示全部楼层
谢谢了,下载参考一下
回复

使用道具 举报

0

主题

6

帖子

0

精华

新手上路

积分
26
金钱
26
注册时间
2015-5-11
在线时间
0 小时
发表于 2015-7-9 22:21:08 | 显示全部楼层
回复【24楼】翱翔云端的鸟:
---------------------------------
1 ”触摸屏会发出10命令 01 10 00 00 00 01 02 00 0F E6 54然后你需要从这个数据帧中解码出你的数据“,10命令是什么,是功能码10?
2 每个功能码的发送和回应格式是怎样的

3“触摸屏会主动发出 (假设站号是01)  01 03 00 00  00 01 84 0A,然后你STM32响应回发  01 03 02 00 00 00 B8 44,这样你的STM32中的数据就显示上去的 ”显示到数值输入框?这个框不是为了写入stm32数据吗?怎么又显示stm32 的数据
回复

使用道具 举报

0

主题

6

帖子

0

精华

新手上路

积分
26
金钱
26
注册时间
2015-5-11
在线时间
0 小时
发表于 2015-7-9 22:22:40 | 显示全部楼层
回复【24楼】翱翔云端的鸟:
---------------------------------
触摸屏显示通讯异常是什么情况?
回复

使用道具 举报

29

主题

486

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3083
金钱
3083
注册时间
2014-7-19
在线时间
413 小时
 楼主| 发表于 2015-7-10 09:09:02 | 显示全部楼层
回复【28楼】菜鸟stm32:
---------------------------------
3“触摸屏会主动发出 (假设站号是01)  01 03 00 00  00 01 84 0A,然后你STM32响应回发  01 03 02 00 00 00 B8 44,这样你的STM32中的数据就显示上去的 ”显示到数值输入框?这个框不是为了写入stm32数据吗?怎么又显示stm32 的数据

这个框 可以是可读可写的   这样就是数值输入显示
也可以是只读的  只显示
电子人生!
回复

使用道具 举报

17

主题

81

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
328
金钱
328
注册时间
2015-7-3
在线时间
68 小时
发表于 2015-8-3 09:21:42 | 显示全部楼层
楼主 你这个是STM32做主机还是从机啊
回复

使用道具 举报

29

主题

486

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3083
金钱
3083
注册时间
2014-7-19
在线时间
413 小时
 楼主| 发表于 2015-8-10 20:10:56 | 显示全部楼层
回复【30楼】培风:
---------------------------------
丛机
电子人生!
回复

使用道具 举报

9

主题

93

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
426
金钱
426
注册时间
2011-7-11
在线时间
49 小时
发表于 2015-9-2 20:02:55 | 显示全部楼层
学习了,绑定!!
回复

使用道具 举报

29

主题

84

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
250
金钱
250
注册时间
2014-9-11
在线时间
8 小时
发表于 2015-10-27 16:24:15 | 显示全部楼层
Modbus是通过485接收完之后对 一帧数据进行解析吗?
回复

使用道具 举报

29

主题

486

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3083
金钱
3083
注册时间
2014-7-19
在线时间
413 小时
 楼主| 发表于 2015-10-27 16:42:12 | 显示全部楼层
回复【33楼】心染红尘:
---------------------------------
对,收到一帧后会进中断,在中断中将一个标志置1,然后在main函数的while循环里  不停的读这个标志,只要标志为1,就对这帧数据进行解析 得到数据  然后在还原继续接收
电子人生!
回复

使用道具 举报

29

主题

84

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
250
金钱
250
注册时间
2014-9-11
在线时间
8 小时
发表于 2015-10-30 19:25:00 | 显示全部楼层
[mw_shl_code=c,true]void ParseRecieve(void) //数据帧解析 { u8 crcDataHi; u8 crcDataLo; if(ReceBuf[0] == 0x01) //设备地址是否匹配 { crcData = crc16(ReceBuf,usDataLen);//从接收到的数据帧中获取CRC crcDataLo = crcData/256; // 132 84 crc低 crcDataHi = crcData%256; // 10 0A crc高 if(usDataLen == 6) { if((crcDataHi == ReceBuf[7])&&(crcDataLo == ReceBuf[6]) )//校验 { if(ReceBuf[1] == 0x03)//功能号0x03 { start_addr = ReceBuf[3] | (ReceBuf[2] << 8); if(ReceBuf[5] == 0x30)//掉电保存按钮 { /*---------------------------------------------------------------------*/ if(usDataLen == 9) //功能号0x10 { if((crcDataHi == ReceBuf[10])&&(crcDataLo == ReceBuf[9])) { if(ReceBuf[1] == 0x10) { switch(start_addr) //判断寄存器起始地址 { case 0x0000://从第一个数值输入窗口开始 sendnum = 8;//回发的字节数 usDataLen = sendnum - 2; SendBuf[0] = ReceBuf[0];//设备地址 SendBuf[1] = ReceBuf[1];//功能号 SendBuf[2] = ReceBuf[2];//返回数据的字节数 SendBuf[3] = ReceBuf[3]; SendBuf[4] = ReceBuf[4]; SendBuf[5] = ReceBuf[5]; /*for(count = 3;ReceBuf[5] > 0;ReceBuf[5]--) { SendBuf[count] = XBuf[count - 3]/256;//回发数据高8位 SendBuf[count+1] = XBuf[count - 3]%256;//回发数据低8位 count = count + 2; }*/ crcData = crc16(SendBuf,usDataLen); crcDataLo = crcData/256; //低 crcDataHi = crcData%256; //高 SendBuf[sendnum - 2] = crcDataLo;//CRC低位F8 SendBuf[sendnum - 1] = crcDataHi;//CRC高位40 for(i = 0;i < 9;i++) { USART_SendData(USART1,SendBuf); while(!(USART1->SR & USART_FLAG_TXE));//等待发送完成 } sendnum = 0; break; } } } } } } } } } }[/mw_shl_code] [mw_shl_code=c,true][/mw_shl_code]
[mw_shl_code=c,true]楼主,crcData = crc16(ReceBuf,usDataLen); 这个函数的usDataLen值在哪赋给的 [/mw_shl_code]
回复

使用道具 举报

29

主题

486

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3083
金钱
3083
注册时间
2014-7-19
在线时间
413 小时
 楼主| 发表于 2015-11-2 10:14:48 | 显示全部楼层
回复【35楼】心染红尘:
---------------------------------
这个实在中断中给的  usDataLen=recenum-2
电子人生!
回复

使用道具 举报

31

主题

104

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
272
金钱
272
注册时间
2013-5-30
在线时间
5 小时
发表于 2015-11-26 12:00:27 | 显示全部楼层
大神  有一点不是太懂啊,在使用usDataLen的时候为什么要减去2呢,数据手册上写的是usDataLen是缓冲器上面的字节数,前面也写了,在CRC校验的时候,起始位停止位和奇偶校验位不加到CRC中,那么是不是可以理解为有三个字节没有参与运算啊,是不是就要减去3?
回复

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
21
金钱
21
注册时间
2015-11-27
在线时间
0 小时
发表于 2015-11-27 11:48:29 | 显示全部楼层
我想 问下  我现在用stm32作主机然后连接触摸屏与从机(pc)通信,想问下思路
回复

使用道具 举报

1

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
58
金钱
58
注册时间
2016-2-23
在线时间
20 小时
发表于 2016-2-23 16:40:49 | 显示全部楼层
这个问题我最近也遇到了   收到的第一个字节从站设备地址一直不对   把波特率设高了也没用啊   
然后想问下楼主
                         sendnum = 5+(aRxBuff[4] * 256 + aRxBuff[5])*2;
                        usDataLen = sendnum - 2;
这两句什么意思   求解释哈!
回复

使用道具 举报

29

主题

486

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3083
金钱
3083
注册时间
2014-7-19
在线时间
413 小时
 楼主| 发表于 2016-2-24 09:28:52 | 显示全部楼层
wan-der 发表于 2016-2-23 16:40
这个问题我最近也遇到了   收到的第一个字节从站设备地址一直不对   把波特率设高了也没用啊   
然后想问 ...

aRxBuff[4] 和 aRxBuff[5]  是寄存器数量的高位和低位   这样是将十六进制转为十进制
这里要乘以2是因为传输是是无符号的16位数据  每个数据占两个字节
(aRxBuff[4] * 256 + aRxBuff[5])*2 =  要返回的数据字节数
前面的5  分开来   从机地址+功能码+数据字节数+CRC低+CRC高
所以:Sendnum = 回发的总字节数


usDataLen = sendnum - 2; 是除去CRC校验的字节数
因为CRC校验是在前面这些数据的基础上计算的   在计算CRC校验时只需要前面的数据
也就是crcData = crc16(ReceBuf,usDataLen);
电子人生!
回复

使用道具 举报

1

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
58
金钱
58
注册时间
2016-2-23
在线时间
20 小时
发表于 2016-2-24 10:26:07 | 显示全部楼层
翱翔云端的鸟 发表于 2016-2-24 09:28
aRxBuff[4] 和 aRxBuff[5]  是寄存器数量的高位和低位   这样是将十六进制转为十进制
这里要乘以2是因为 ...

感谢百忙之中回复!昨天我用仿真看结果,出现一个问题,在判断功能码操作之前的CRC校验不对(我的程序跟你的有所不同,我需要的功能码是写多个寄存器)程序不能继续往下走,所以用调试助手给从机发的数据一直得不到回复,是因为有误码的原因吗?我把波特率设置成9600以上误码率很高啊,相反波特率降低成4800或者2400误码却较少(接收到的数据帧时对时错),我也整的没招了,这是仿真出现错误部分的程序
if (aRxBuff[0] == SlaveID)
        {
            
      crc16tem=((unsigned int)(aRxBuff[CommIndexEnd-1]) << 8) |
      aRxBuff[CommIndexEnd];   //CommIndexEnd是接收长度   
                                                          //CommIndex是数据位置索引
     uIndex=crc16(aRxBuff,CommIndex-1);//(((unsigned int)(temp[0]) *256) | temp[1]) ;
      if(crc16tem==uIndex)  //此处CRC校验一直不对,是有误码存在的原因吗?
                                                       //CRC16这个计算函数与你的程序中是一样的
    {
  此处判断功能码然后数据解析回发;
    }
    }
回复

使用道具 举报

1

主题

3

帖子

0

精华

新手入门

积分
31
金钱
31
注册时间
2016-1-19
在线时间
13 小时
发表于 2016-2-24 10:39:20 | 显示全部楼层
翱翔云端的鸟 兄弟给我一份完整的modbus程序好吗?我的邮箱是 ktye@vip.qq.com 小弟万分感谢
回复

使用道具 举报

1

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
58
金钱
58
注册时间
2016-2-23
在线时间
20 小时
发表于 2016-2-24 20:41:30 | 显示全部楼层
翱翔云端的鸟 发表于 2016-2-24 09:28
aRxBuff[4] 和 aRxBuff[5]  是寄存器数量的高位和低位   这样是将十六进制转为十进制
这里要乘以2是因为 ...

补充一哈,利用ModBus Poll 调试助手给板子发数据时出现Framing error 和checksum error,然后就连接超时了,是误码造成的吗?
回复

使用道具 举报

5

主题

54

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
254
金钱
254
注册时间
2015-8-25
在线时间
27 小时
发表于 2016-2-25 11:33:48 | 显示全部楼层
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
回复

使用道具 举报

1

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
58
金钱
58
注册时间
2016-2-23
在线时间
20 小时
发表于 2016-2-25 16:10:45 | 显示全部楼层
翱翔云端的鸟 发表于 2016-2-24 09:28
aRxBuff[4] 和 aRxBuff[5]  是寄存器数量的高位和低位   这样是将十六进制转为十进制
这里要乘以2是因为 ...

楼主,用你的03功能码程序段进行调试,发现ModBus  Poll调试助手收到的数据为
01 03 02 00 00 B8 44  中间少了个字节,这是怎么回事?
回复

使用道具 举报

29

主题

486

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3083
金钱
3083
注册时间
2014-7-19
在线时间
413 小时
 楼主| 发表于 2016-2-25 18:47:59 | 显示全部楼层
ktye 发表于 2016-2-24 10:39
翱翔云端的鸟 兄弟给我一份完整的modbus程序好吗?我的邮箱是  小弟万分感谢

18楼 已经上传了
电子人生!
回复

使用道具 举报

29

主题

486

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3083
金钱
3083
注册时间
2014-7-19
在线时间
413 小时
 楼主| 发表于 2016-2-25 18:48:20 | 显示全部楼层
wan-der 发表于 2016-2-25 16:10
楼主,用你的03功能码程序段进行调试,发现ModBus  Poll调试助手收到的数据为
01 03 02 00 00 B8 44  中 ...

晚上回去看看 现在有点事!
电子人生!
回复

使用道具 举报

29

主题

486

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3083
金钱
3083
注册时间
2014-7-19
在线时间
413 小时
 楼主| 发表于 2016-2-25 21:03:16 | 显示全部楼层
wan-der 发表于 2016-2-24 10:26
感谢百忙之中回复!昨天我用仿真看结果,出现一个问题,在判断功能码操作之前的CRC校验不对(我的程序跟 ...

波特率不能变    跟你的定时器配置是有关的   就按我上面的19200 和定时器配置


丛机是你的STM32  你要判断接受到的数据帧功能码是不是10(10就是写多个寄存器)

如果是的  就响应对应的数据格式好了   
电子人生!
回复

使用道具 举报

29

主题

486

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3083
金钱
3083
注册时间
2014-7-19
在线时间
413 小时
 楼主| 发表于 2016-2-25 21:05:10 | 显示全部楼层
wan-der 发表于 2016-2-25 16:10
楼主,用你的03功能码程序段进行调试,发现ModBus  Poll调试助手收到的数据为
01 03 02 00 00 B8 44  中 ...

具体是少了哪个字节?  你看看是不是回发的错误了!
电子人生!
回复

使用道具 举报

29

主题

486

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3083
金钱
3083
注册时间
2014-7-19
在线时间
413 小时
 楼主| 发表于 2016-2-25 21:10:27 | 显示全部楼层
无符号16bit读应答函数--功能码03(可以一次性读多个)
[mw_shl_code=c,true]/********************************************************************************
** 功能:MODBUS数据帧16位无符号数读寄存器应答函数
** 参数:u16 index , u16 *p , u16 datanu
** 参数说明:index   起始数组下标
                         *p       数组缓冲区
                         datanum  返回的数据个数
** 说明:
** 发送格式: 01   03     00   00      00  01     84 0A
            从址 功能号 起始地址高低  数量高低    CRC校验低 高
** 响应格式: 01   03     02        00  00         B8 44
                        从址 功能号 数据字节数  数量高低    CRC校验低 高
***************************************************************************************/
void Read_Answer(u16 index,u16 *p,u16 datanum)
{
        u16 crcDataLo,crcDataHi;
        u8 i;
        sendnum = 5+(ReceBuf[4] * 256 + ReceBuf[5])*2;//回发的字节数
        usDataLen = sendnum - 2;
        SendBuf[0] = ReceBuf[0];//设备地址
        SendBuf[1] = ReceBuf[1];//功能号
        SendBuf[2] = sendnum - 5;//返回数据的字节数
        for(i = 3;(i < (2*datanum+3)); i = i+2)
        {
                SendBuf = (*(p+index))/256;//高8位   *(p+i) = MYW_Buf
                SendBuf[i+1] = (*(p+index))%256;//低8位
                index++;
        }
        crcData = crc16(SendBuf,usDataLen);
        crcDataLo = crcData/256; //高
        crcDataHi = crcData%256; //低
        SendBuf[sendnum - 2] = crcDataLo;//CRC校验低
        SendBuf[sendnum - 1] = crcDataHi;//CRC校验高
        for(i = 0;i < sendnum+1;i++)
        {
                USART_SendData(USART1,SendBuf);
                while(!(USART1->SR & USART_FLAG_TXE));//等待发送完成
        }
        sendnum = 0;       
}[/mw_shl_code]


无符号16bit写应答---对应10(可以一次性写多个)
[mw_shl_code=c,true]/**************************************************************************************
** 功能:      Modbus16位无符号数据帧写寄存器应答函数
** 参数:      void
** 返回值:    void
** 说明:      MODBUS数据帧发送响应如下   
** 发送格式: 01   10     00   00      00  01    02     00   0F        E6  54
            从址 功能号 起始地址高低  数量高低 字节数   数据高低    CRC校验低 高
** 响应格式: 01   10     00   00     00    01    01  C9
                        从址 功能号 起始地址高低  数量高低   CRC校验低 高
***************************************************************************************/
void WriteAnswer(void)
{
        u16 crcDataLo,crcDataHi;//CRC低位 和CRC高位
        u8 i;
        sendnum = 8;//回发的字节数
        usDataLen = sendnum - 2;
        SendBuf[0] = ReceBuf[0];//设备地址
        SendBuf[1] = ReceBuf[1];//功能号
        SendBuf[2] = ReceBuf[2];//返回数据的字节数
        SendBuf[3] = ReceBuf[3];
        SendBuf[4] = ReceBuf[4];
        SendBuf[5] = ReceBuf[5];
        crcData = crc16(SendBuf,usDataLen);
        crcDataLo = crcData/256; //低
        crcDataHi = crcData%256; //高
        SendBuf[sendnum - 2] = crcDataLo;//CRC低位F8
        SendBuf[sendnum - 1] = crcDataHi;//CRC高位40
        for(i = 0;i < 9;i++)
        {       
                USART_SendData(USART1,SendBuf);
                while(!(USART1->SR & USART_FLAG_TXE));//等待发送完成
        }
        sendnum = 0;
}[/mw_shl_code]


无符号32bit读应答函数
[mw_shl_code=c,true]/********************************************************************************
** 功能:MODBUS数据帧32位无符号数读寄存器应答函数
** 参数:u16 index1 , u32 *p1 , u16 datanum1,
** 参数说明:index1    起始数组下标
                         *p1       数组缓冲区
                         datanum1  返回的数据个数
** 说明:32位DoubleWord的发送接收格式为 低十六位在前,高十六位在后,与16位数据传输不同
                 例如 32位十进制数  542954855  的十六进制位  20 5C D5 67
         实际发送接收位    D5 67 20 5C
********************************************************************************/
void Double_Word_Read_Answer(u16 index1,u32 *p1,u16 datanum1)
{
        u16 crcDataLo,crcDataHi;
        u8 i;
        sendnum = 5+(ReceBuf[4] * 256 + ReceBuf[5])*4;//回发的字节数
        usDataLen = sendnum - 2;
        SendBuf[0] = ReceBuf[0];//设备地址
        SendBuf[1] = ReceBuf[1];//功能号
        SendBuf[2] = sendnum - 5;//返回数据的字节数
        for(i=3;(i < (4*datanum1+3));i = i+4)
        {
                SendBuf = ((*(p1+index1))%65536)/256 ;//A 对65535取模得到低十六位  然后除256得低十六位中的高8位
            SendBuf[i+1] = ((*(p1+index1))%65536)%256;//B
            SendBuf[i+2] = ((*(p1+index1))/65536)/256;//C
            SendBuf[i+3] = ((*(p1+index1))/65536)%256;//D
                index1++;
        }
        crcData = crc16(SendBuf,usDataLen);
        crcDataLo = crcData/256; //高
        crcDataHi = crcData%256; //低
        SendBuf[sendnum - 2] = crcDataLo;//CRC校验低
        SendBuf[sendnum - 1] = crcDataHi;//CRC校验高
        for(i = 0;i < sendnum+1;i++)
        {
                USART_SendData(USART1,SendBuf);
                while(!(USART1->SR & USART_FLAG_TXE));//等待发送完成
        }
        sendnum = 0;
}[/mw_shl_code]
电子人生!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-2-27 03:02

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表