搜索
bottom↓
回复: 27

Modbus从机,怎么把Reg与变量对应,征求方法

[复制链接]

出0入0汤圆

发表于 2015-12-7 11:46:19 | 显示全部楼层 |阅读模式
如题,下位机板子,用modbus协议通讯,参照资料,已经把freemodbus移植完成,测试通过。
现在到了定义modbus寄存器地址功能的阶段,征求好的办法。

自己想到了几个方法,1、在原项目文件中,将需要与外界沟通的变量,与modbus寄存器数组地址对应赋值; 2、另起定时器,周期性的完成变量与寄存器数组的对应赋值;3、使用指针数组 4、其它方案,盼有相关经验的指教下

阿莫论坛20周年了!感谢大家的支持与爱护!!

曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……

出0入0汤圆

发表于 2015-12-7 12:13:31 | 显示全部楼层
字典模式,不再定义其他变量,直接用REG当变量

出0入0汤圆

发表于 2015-12-7 12:23:20 | 显示全部楼层
这还用选??
肯定3啊

出0入0汤圆

发表于 2015-12-7 12:24:01 | 显示全部楼层
3、使用指针数组->3.使用指针

出0入0汤圆

发表于 2015-12-7 13:12:14 | 显示全部楼层
定义一个大数组,全局变量定义成数组里的单元,MODEDUB取数组的值就行了.

出0入0汤圆

 楼主| 发表于 2015-12-7 14:48:45 | 显示全部楼层
danfeidie 发表于 2015-12-7 12:24
3、使用指针数组->3.使用指针

我也主观上倾向于3,觉得实现最为简单,而且维护方便。
但数组指针不熟悉,而且用不好的话, 很容易跑飞死机。

另外还有一个难点,就是比特位,和数组的某一位建立对应关系

出0入0汤圆

 楼主| 发表于 2015-12-7 14:50:56 | 显示全部楼层
3DA502 发表于 2015-12-7 12:13
字典模式,不再定义其他变量,直接用REG当变量

字典模式? 愿闻其详
直接用REG当变量,这个方法最直观,但工作量最大,需要改动原项目的程序,是个麻烦事情。

出0入0汤圆

 楼主| 发表于 2015-12-7 14:54:45 | 显示全部楼层
本帖最后由 cgzasa 于 2015-12-7 15:04 编辑
Firman 发表于 2015-12-7 13:12
定义一个大数组,全局变量定义成数组里的单元,MODEDUB取数组的值就行了.


我原项目建立了一个结构体,把用到的相关参数,全部打包进去了,使用起来也方便。
现在要解决的,是把结构体的成员,和modbus的寄存器地址建立对应关系。

项目原功能已经基本成型,如果为了通讯, 推翻前面程序,这个想法不敢去想啊

出0入0汤圆

发表于 2015-12-7 15:09:04 | 显示全部楼层
cgzasa 发表于 2015-12-7 14:54
我原项目建立了一个结构体,把用到的相关参数,全部打包进去了,使用起来也方便。
现在要解决的,是把结 ...

做指针指向你的结构体不就能提取变量了么?

出0入0汤圆

 楼主| 发表于 2015-12-7 15:31:41 | 显示全部楼层
本帖最后由 cgzasa 于 2015-12-7 15:46 编辑
Firman 发表于 2015-12-7 15:09
做指针指向你的结构体不就能提取变量了么?


是有这个想法
16位访问的变量,用指针应该好处理
那种比特位访问的reg,不好操作啊

出0入0汤圆

发表于 2015-12-7 15:50:38 | 显示全部楼层
1.MODBUS用数组开区。
2.定义指针变量,指向数组中的某个地址。
3.从此,该指针变量就当做你平时用的变量。
就这么简单,别搞复杂了。

出0入0汤圆

 楼主| 发表于 2015-12-7 16:26:41 | 显示全部楼层
danfeidie 发表于 2015-12-7 15:50
1.MODBUS用数组开区。
2.定义指针变量,指向数组中的某个地址。
3.从此,该指针变量就当做你平时用的变量。 ...

懂了,我刚开始考虑的思路,是保持原项目程序不动的基础上,加入实现modbus协议功能。在原程序结构体定义并开区,modbus用指针数组指向定义。
经你这么一说,明白了,这样应该更合理,自己去考虑怎么实现吧,谢谢

出0入8汤圆

发表于 2015-12-7 16:44:37 | 显示全部楼层
本帖最后由 bujie8010 于 2015-12-7 16:46 编辑

我的做法是用宏定义联系变量和reg,int Parameter[256]定义在global.c中,下面是global.h中的内容:
extern int Parameter[256];
#define Baudrate Parameter[1]
#define MBAddress Parameter[2]
#define TBCCR0_PARA Parameter[3]
#define ADCMode Parameter[4]
#define ADCChanHi Parameter[5]
#define ADCChanMi Parameter[6]
#define ADCChanLo Parameter[7]
#define TBCCR_ADCHi Parameter[8]
#define TBCCR_ADCMi Parameter[9]
#define TBCCR_ADCLo Parameter[10]
#define DAC0Factor Parameter[11]
#define DAC1Factor Parameter[12]

下位机的程序包含global后直接用宏来操作reg,上位机要知道具体reg的对应关系。

出0入0汤圆

发表于 2015-12-7 16:46:31 | 显示全部楼层
cgzasa 发表于 2015-12-7 15:31
是有这个想法
16位访问的变量,用指针应该好处理
那种比特位访问的reg,不好操作啊 ...

MODEBUS 定义BYTE传输,若BIT提取,也就是提取0或1.
省RAM的做法,你可以把每个BIT都定义好标志.
extern UC BitFlag4;            //bit flag ram
#define F_BackLight            (((bits*)&BitFlag4)->bit0) //=1 backlight on
#define F_BackupManu       (((bits*)&BitFlag4)->bit1) //backup F_ManualAuto
#define F_ErrorMode          (((bits*)&BitFlag4)->bit2) //error mode
#define F_500msChPump  (((bits*)&BitFlag4)->bit3) //change pump timing toggle
#define F_KeyBuzzer          (((bits*)&BitFlag4)->bit4) //press key have a buzzer
#define F_ErrorBuzzer        (((bits*)&BitFlag4)->bit5) //error status buzzer
#define F_T30s                  (((bits*)&BitFlag4)->bit6) //timing keep pressure 30s
#define F_ScanBp             (((bits*)&BitFlag4)->bit7) //backup scan 10ms

败家的做法,每个BIT独立占一个BYTE.

出0入0汤圆

 楼主| 发表于 2015-12-7 16:58:49 | 显示全部楼层
bujie8010 发表于 2015-12-7 16:44
我的做法是用宏定义联系变量和reg,int Parameter[256]定义在global.c中,下面是global.h中的内容:
extern ...


这个方法,节省程序空间,也节省ram,是个好办法。缺陷是,变量多了,看起来不太清晰。要是能用结构体打包一下,可读性会好一些

出0入0汤圆

 楼主| 发表于 2015-12-9 20:31:20 | 显示全部楼层
Firman 发表于 2015-12-7 16:46
MODEBUS 定义BYTE传输,若BIT提取,也就是提取0或1.
省RAM的做法,你可以把每个BIT都定义好标志.
extern UC  ...

BitFlag4() 这个子函数是实现什么功能?
另外,这个是只能提取bit值,还是说能提取,也能赋值bit位?

出0入0汤圆

发表于 2015-12-9 21:12:36 | 显示全部楼层
我用第2种,定时器刷新,改动最小,移植最方便,多耗资源,但一般也不差这么点资源;

出0入0汤圆

 楼主| 发表于 2015-12-9 23:26:44 | 显示全部楼层
chinaboy25 发表于 2015-12-9 21:12
我用第2种,定时器刷新,改动最小,移植最方便,多耗资源,但一般也不差这么点资源; ...

这个方式有个疑问,比如是可读写的数据类型,如保持寄存器,你的定时器刷新时,从哪边往哪边刷新? 单向刷新,要么只能读,要么只能写,而双向刷新如何实现?

出0入0汤圆

发表于 2015-12-10 08:06:23 | 显示全部楼层
danfeidie 发表于 2015-12-7 15:50
1.MODBUS用数组开区。
2.定义指针变量,指向数组中的某个地址。
3.从此,该指针变量就当做你平时用的变量。 ...

我也觉得不错,现在维护前人写的程序,整个程序都是REG,大概有1000来个,而且REG还是全局的,直接操作REG,全部糊在一起,那个维护痛苦啊,其他同事都不太愿意维护这样的程序

出0入0汤圆

发表于 2015-12-10 08:09:06 | 显示全部楼层
cgzasa 发表于 2015-12-7 16:58
这个方法,节省程序空间,也节省ram,是个好办法。缺陷是,变量多了,看起来不太清晰。要是能用结构体打 ...

结构体打包适合那些寄存器不多的情况,多了还是别这样搞,REG容易错位

出0入0汤圆

发表于 2015-12-10 09:05:22 | 显示全部楼层
cgzasa 发表于 2015-12-9 20:31
BitFlag4() 这个子函数是实现什么功能?
另外,这个是只能提取bit值,还是说能提取,也能赋值bit位? ...

BitFlag4是一个BYTE的全局变量.
#define ..........是指向BitFlag4的每一位,可用位操作.

出0入0汤圆

 楼主| 发表于 2015-12-10 10:04:02 | 显示全部楼层
mangoes 发表于 2015-12-10 08:06
我也觉得不错,现在维护前人写的程序,整个程序都是REG,大概有1000来个,而且REG还是全局的,直接操作RE ...


弄清楚思绪,用结构体重定义打包,用结构体方式替换一下,前期头痛一点,后续会方便很多

出0入0汤圆

 楼主| 发表于 2015-12-10 10:13:05 | 显示全部楼层
mangoes 发表于 2015-12-10 08:09
结构体打包适合那些寄存器不多的情况,多了还是别这样搞,REG容易错位

我到现在为止,用结构体感觉不错啊,主要是关系清晰。
而且那些有共性的功能,用结构体就更好用了。

        MtrA.Ctrl_Status=STOP;
        MtrA.PIN_CLK=&PCout(8);  //PC8
        MtrA.PIN_DIR=&PCout(9);  //PC9
        MtrA.PIN_EN =&PCout(6);  //PC6  
        MtrA.PIN_ORI=&PCin(7);   //PC7  
        MtrA.TIM_ARR=&MEM_ADDR(&TIM2->ARR); //指向TIMx->ARR
        MtrA.Para_S_Type=FULL_S_WAVE;       //启停曲线模式
        MtrA.Run_S_Len=10;                                  //steps
        MtrA.S_Wave=&S_Wave_TeamA[0];       //曲线地址
        MtrA.Para_OriginDir=CW;     //回原点的转动方向
        MtrA.Para_OriginSteps=10;   //原点探测后,继续多少步为逻辑真实原点
        MtrA.Para_ClkPerStep=64;  

       。。。

        MtrE.Ctrl_Status=STOP;   
        MtrE.PIN_CLK=&PBout(6);   //PB6
        MtrE.PIN_DIR=&PBout(7);   //PB7
        MtrE.PIN_EN =&PBout(4);   //PB4  
        MtrE.PIN_ORI=&PBin(5);    //PB5  
        MtrE.TIM_ARR=&MEM_ADDR(&TIM2->ARR); //指向TIMx->ARR
        MtrE.Para_S_Type=FULL_S_WAVE;       //启停曲线模式
        MtrE.Run_S_Len=10;                                  //steps
        MtrE.S_Wave=&S_Wave_TeamA[0];       //曲线地址
        MtrE.Para_OriginDir=CW;     //回原点的转动方向
        MtrE.Para_OriginSteps=10;   //原点探测后,继续多少步为逻辑真实原点
        MtrE.Para_ClkPerStep=64;  
你说的reg错位,暂时还没出现过,如果涉及到指针的操作,需要注意,否则程序会跑飞而出现HardFault

出0入0汤圆

 楼主| 发表于 2015-12-10 10:27:42 | 显示全部楼层
Firman 发表于 2015-12-10 09:05
BitFlag4是一个BYTE的全局变量.
#define ..........是指向BitFlag4的每一位,可用位操作. ...

折腾好久,终于基本实现功能了,可能还有不合理的地方,暂时也没法找出。用modbus Poll连机测试,达到了预计功能。

//数组定义  后面的是指针,方便调用
uint8_t ucRegCoilsBuf[REG_COILS_SIZE / 8]__attribute__(( at(0x20000000) )) = {0x00,0x00};
uint8_t * const pucRegCoilsBuf=(void*)(0x22000000+0x0*8*4);

这个是结构体中,指针变量的类型
        。。。
        BOOL *Update_Flag;
        BOOL *Calc_Flag;
        。。。

//这里是用指针变量,指向bit空间。

DL.Update_Flag =        (BOOL *)&pucRegCoilsBuf[0*4];           //地址1   因为位带是32位操作,所以需要乘以4
DL.Calc_Flag   =        (BOOL *)&pucRegCoilsBuf[1*4];                //地址2

测试读写bit位都正常,也就是说,不是单向赋值,而是双向的赋值。上位机可读该线圈的值,也可以更改。

另外,需要注意一点,数组定义的初始值,=0x0,会报错,
Error: L6971E: systick.o(.data) type RW incompatible with port.o(.ARM.__AT_0x20000000) type ZI in er RW_IRAM1.
初始值为非0,就不出错,更改IRAM1的Start地址(如地址+0x10),则初始值=0x0,也不会报错了。

出0入0汤圆

 楼主| 发表于 2015-12-10 10:34:47 | 显示全部楼层
这中间涉及到位带操作的一些概念,可以参照这个  STM32位带操作
http://blog.sina.com.cn/s/blog_779edb0b01018nu9.html

出0入0汤圆

发表于 2015-12-11 09:50:28 | 显示全部楼层
本帖最后由 chinaboy25 于 2015-12-11 09:56 编辑
cgzasa 发表于 2015-12-9 23:26
这个方式有个疑问,比如是可读写的数据类型,如保持寄存器,你的定时器刷新时,从哪边往哪边刷新? 单向 ...


加个历史纪录,你刷新的历史纪录也刷新,协议刷新的就会和历史纪录不同,至于刷新时间看根据系统应用来,不过一般很只把保持寄存器当输入用,没必要做成双向的;

出0入0汤圆

发表于 2015-12-11 23:08:34 | 显示全部楼层
mangoes 发表于 2015-12-10 08:09
结构体打包适合那些寄存器不多的情况,多了还是别这样搞,REG容易错位

看晕了!
这样是不是很简单??
u16 Area4[1000];
u16 *p_reg1=&Area4[100];         // 假设用在第100个地址处;
以后调用这个变量直接*p_reg1;
完了。

出0入0汤圆

发表于 2015-12-12 09:52:50 | 显示全部楼层
danfeidie 发表于 2015-12-11 23:08
看晕了!
这样是不是很简单??
u16 Area4[1000];

以前的同事喜欢用宏定义 “#define COM3_SETFORMAT ArryReg[100]”这样的形式去弄,弄到程序要调试的话很麻烦,现在我也是用你所说的这种方法去做的,想不到其他更好的方法了
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-8-25 20:08

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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