FreeMb移植到STM32F103Word格式.docx
- 文档编号:16488728
- 上传时间:2022-11-24
- 格式:DOCX
- 页数:26
- 大小:27.70KB
FreeMb移植到STM32F103Word格式.docx
《FreeMb移植到STM32F103Word格式.docx》由会员分享,可在线阅读,更多相关《FreeMb移植到STM32F103Word格式.docx(26页珍藏版)》请在冰豆网上搜索。
接下来就可以处理数据了,首当其冲的就是判断帧的合法性。
Modbus通过时间来判断帧是否接受完成,自然需要单片机中的定时器配合。
三
整体代码
下面给出一个STM32平台上使用FREEMODBUS最简单的例子,操作保持寄存器,此时操作指令可以为03,06和16;
1.<
FONTsize=3>
#include"
stm32f10x.h"
2.#include<
stdio.h>
3.#include"
mb.h"
4.#include"
mbutils.h"
5.
6.//保持寄存器起始地址
7.#defineREG_HOLDING_START0x0000
8.//保持寄存器数量
9.#defineREG_HOLDING_NREGS8
10.//保持寄存器内容
11.uint16_tusRegHoldingBuf[REG_HOLDING_NREGS]
12.={0x147b,0x3f8e,0x147b,0x400e,0x1eb8,0x4055,0x147b,0x408e};
13.
14.intmain(void)
15.{
16.//初始化RTU模式从机地址为1USART19600无校验
17.eMBInit(MB_RTU,0x01,0x01,9600,MB_PAR_NONE);
18.//启动FreeModbus
19.eMBEnable();
20.while
(1)
21.{
22.//FreeMODBUS不断查询
23.eMBPoll();
24.}
25.}
26.
27./**
28.*@brief保持寄存器处理函数,保持寄存器可读,可读可写
29.*@parampucRegBuffer读操作时--返回数据指针,写操作时--输入数据指针
30.*usAddress寄存器起始地址
31.*usNRegs寄存器长度
32.*eMode操作方式,读或者写
33.*@retvaleStatus寄存器状态
34.*/
35.eMBErrorCode
36.eMBRegHoldingCB(UCHAR*pucRegBuffer,USHORTusAddress,USHORTusNRegs,
37.eMBRegisterModeeMode)
38.{
39.//错误状态
40.eMBErrorCodeeStatus=MB_ENOERR;
41.//偏移量
42.int16_tiRegIndex;
43.
44.//判断寄存器是不是在范围内
45.if(((int16_t)usAddress>
=REG_HOLDING_START)\
46.&
&
(usAddress+usNRegs<
=REG_HOLDING_START+REG_HOLDING_NREGS))
47.{
48.//计算偏移量
49.iRegIndex=(int16_t)(usAddress-REG_HOLDING_START);
50.
51.switch(eMode)
52.{
53.//读处理函数
54.caseMB_REG_READ:
55.while(usNRegs>
0)
56.{
57.*pucRegBuffer++=(uint8_t)(usRegHoldingBuf[iRegIndex]>
>
8);
58.*pucRegBuffer++=(uint8_t)(usRegHoldingBuf[iRegIndex]&
0xFF);
59.iRegIndex++;
60.usNRegs--;
61.}
62.break;
63.
64.//写处理函数
65.caseMB_REG_WRITE:
66.while(usNRegs>
67.{
68.usRegHoldingBuf[iRegIndex]=*pucRegBuffer++<
<
8;
69.usRegHoldingBuf[iRegIndex]|=*pucRegBuffer++;
70.iRegIndex++;
71.usNRegs--;
72.}
73.break;
74.}
75.}
76.else
77.{
78.//返回错误状态
79.eStatus=MB_ENOREG;
80.}
81.
82.returneStatus;
83.}
84.<
/FONT>
复制代码
先给大家一个整体的印象,先让大家会使用FREEMODBUS,再详细描述细节
//保持寄存器起始地址
#defineREG_HOLDING_START
0x0000
//保持寄存器数量
#defineREG_HOLDING_NREGS
8
这两个宏定义,决定了保持寄存器的起始地址和总个数。
需要强调的是,modbus寄存器的地址有两套规则,一套称为PLC地址,为5位十进制数,例如40001。
另一套是协议地址,PLC地址40001意味着该参数类型为保持寄存器,协议地址为0x0000,这里面有对应关系,去掉PLC地址的最高位,然后剩下的减1即可。
这会存在一个问题,PLC地址30002和PLC地址40002的协议地址同为0x0001,此时访问时是不是会冲突呢。
亲们,当然不会了,30001为输入寄存器,需要使用04指令访问,而40001为保持寄存器,可以使用03、06和16指令访问。
所以,用好modbus还是要熟悉协议本生,切不可着急。
//保持寄存器内容
uint16_tusRegHoldingBuf[REG_HOLDING_NREGS]
={0x147b,0x3f8e,0x147b,0x400e,0x1eb8,0x4055,0x147b,0x408e};
接下来定义了保持寄存器的内容,在这里请大家注意了,保持寄存器为无符号16位数据。
在测试的情况下,我随便找了一些数据进行测试。
看数据的本质似乎看不出说明规律,但是usRegHoldingBuf却是以16进制保存了浮点数。
1.intmain(void)
2.{
3.//初始化RTU模式从机地址为1USART19600无校验
4.eMBInit(MB_RTU,0x01,0x01,9600,MB_PAR_NONE);
5.//启动FreeModbus
6.eMBEnable();
7.while
(1)
8.{
9.//FreeMODBUS不断查询
10.eMBPoll();
11.}
12.}
接下来就进入主函数部分。
有三个FREEMODBUS提供的函数,eMBInit,eMBEnable和eMBPoll。
eMBInit为modbus的初始化函数,eMBEnable为modbus的使能函数,而eMBPoll为modbus的查询函数,eMBPoll也是非常单纯的函数,查询是否有数据帧到达,如果有数据到达,便进行相依的处理。
再次观察这几个函数,只有eMBInit有很多的参数,这些参数和位于系统底层的硬件有关,这个应该引起移植过程的更多关注。
下面几个章节再议。
eMBErrorCode
2.eMBRegHoldingCB(UCHAR*pucRegBuffer,USHORTusAddress,USHORTusNRegs,
3.eMBRegisterModeeMode)
4.{
5.//错误状态
6.eMBErrorCodeeStatus=MB_ENOERR;
7.//偏移量
8.int16_tiRegIndex;
9.
10.//判断寄存器是不是在范围内
11.if(((int16_t)usAddress>
12.&
13.{
14.//计算偏移量
15.iRegIndex=(int16_t)(usAddress-REG_HOLDING_START);
16.
17.switch(eMode)
18.{
19.//读处理函数
20.caseMB_REG_READ:
21.while(usNRegs>
22.{
23.*pucRegBuffer++=(uint8_t)(usRegHoldingBuf[iRegIndex]>
24.*pucRegBuffer++=(uint8_t)(usRegHoldingBuf[iRegIndex]&
25.iRegIndex++;
26.usNRegs--;
27.}
28.break;
29.
30.//写处理函数
31.caseMB_REG_WRITE:
32.while(usNRegs>
33.{
34.usRegHoldingBuf[iRegIndex]=*pucRegBuffer++<
35.usRegHoldingBuf[iRegIndex]|=*pucRegBuffer++;
36.iRegIndex++;
37.usNRegs--;
38.}
39.break;
40.}
41.}
42.else
43.{
44.//返回错误状态
45.eStatus=MB_ENOREG;
46.}
47.
48.returneStatus;
49.}
50.<
最后,如果收到一个有效的数据帧,那么就可以开始处理了。
第一步,判断寄存器的地址是否在合法的范围内。
if(((int16_t)usAddress>
第二步,判断需要操作寄存器的偏移地址。
给个例子可以迅速的说明问题,例如访问寄存器的起始地址为0x0002,保持寄存器的起始地址为0x0000,那么这个访问的偏移量为2,程序就从保持寄存器数组的第2个(从0开始)开始操作。
第三步,读写操作分开处理
caseMB_REG_READ:
while(usNRegs>
{
*pucRegBuffer++=(uint8_t)(usRegHoldingBuf[iRegIndex]>
*pucRegBuffer++=(uint8_t)(usRegHoldingBuf[iRegIndex]&
iRegIndex++;
usNRegs--;
}
break;
以读操作为例,代码不多说了,请大家注意操作的顺序。
保持寄存器以16位形式保存,但是modbus通信时以字节为单位,高位字节数据在前,低位数据字节在后。
四
串口相关部分代码编写
串口部分的代码编写比较常规,主要有三个函数,串口初始化,串口数据发送和串口数据接收。
除了以上三个函数之外,还有串口中断服务函数。
1./**
2.*@brief串口初始化
3.*@paramucPORT串口号
4.*ulBaudRate波特率
5.*ucDataBits数据位
6.*eParity校验位
7.*@retvalNone
8.*/
9.BOOL
10.xMBPortSerialInit(UCHARucPORT,ULONGulBaudRate,UCHARucDataBits,eMBParityeParity)
11.{
12.(void)ucPORT;
//不修改串口
13.(void)ucDataBits;
//不修改数据位长度
14.(void)eParity;
//不修改校验格式
15.
16.GPIO_InitTypeDefGPIO_InitStructure;
17.USART_InitTypeDefUSART_InitStructure;
18.
19.//使能USART1,GPIOA
20.RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|
21.RCC_APB2Periph_USART1,ENABLE);
22.
23.//GPIOA9USART1_Tx
24.GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
25.GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
26.GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
//推挽输出
27.GPIO_Init(GPIOA,&
GPIO_InitStructure);
28.//GPIOA.10USART1_Rx
29.GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;
30.GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
31.GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
//浮动输入
32.GPIO_Init(GPIOA,&
33.
34.USART_InitStructure.USART_BaudRate=ulBaudRate;
//只修改波特率
35.USART_InitStructure.USART_WordLength=USART_WordLength_8b;
36.USART_InitStructure.USART_StopBits=USART_StopBits_1;
37.USART_InitStructure.USART_Parity=USART_Parity_No;
38.USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
39.USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
40.//串口初始化
41.USART_Init(USART1,&
USART_InitStructure);
42.//使能USART1
43.USART_Cmd(USART1,ENABLE);
44.
45.NVIC_InitTypeDefNVIC_InitStructure;
46.NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
47.//设定USART1中断优先级
48.NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn;
49.NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
50.NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
51.NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
52.NVIC_Init(&
NVIC_InitStructure);
53.
54.//最后配置485发送和接收模式
55.RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);
56.//GPIOD.8
57.GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8;
58.GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
59.GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
60.GPIO_Init(GPIOD,&
61.
62.returnTRUE;
63.}
64.
传入的参数有端口号,波特率,数据位和校验位,可以根据实际的情况修改代码。
在这里我并没有修改其他参数,至于传入的波特率是有效的。
除了配置串口的相关参数之外,还需要配置串口的中断优先级。
最后,由于使用485模式,还需要一个发送接收控制端,该IO配置为推挽输出模式。
/**
2.*@brief控制接收和发送状态
3.*@paramxRxEnable接收使能、
4.*xTxEnable发送使能
5.*@retvalNone
6.*/
7.void
8.vMBPortSerialEnable(BOOLxRxEnable,BOOLxTxEnable)
9.{
10.if(xRxEnable)
12.//使能接收和接收中断
13.USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
14.//MAX485操作低电平为接收模式
15.GPIO_ResetBits(GPIOD,GPIO_Pin_8);
16.}
17.else
19.USART_ITConfig(USART1,USART_IT_RXNE,DISABLE);
20.//MAX485操作高电平为发送模式
21.GPIO_SetBits(GPIOD,GPIO_Pin_8);
22.}
23.
24.if(xTxEnable)
25.{
26.//使能发送完成中断
27.USART_ITConfig(USART1,USART_IT_TC,ENABLE);
28.}
29.else
30.{
31.//禁止发送完成中断
32.USART_ITConfig(USART1,USART_IT_TC,DISABLE);
33.}
34.
35.}
36.<
由于485使用半双工模式,从机一般处于接收状态,有数据发送时才会进入发送模式。
在FreeModbus中有专门的控制接收和发送状态的函数,在这里不但可以打开或关闭接收和发送中断,还可以控制485收发芯片的发送接收端口。
代码非常简单,但是还是建议各位使用发送完成中断。
BOOL
2.xMBPortSerialPutByte(CHARucByte)
3.{
4.//发送数据
5.USART_SendData(USART1,ucByte);
6.returnTRUE;
7.}
8.BOOL
9.xMBPortSerialGetByte(CHAR*pucByte)
10.{
11.//接收数据
12.*pucByte=USART_ReceiveData(USART1);
13.returnTRUE;
14.}
15.xMBPortSerialPutByte和xMBPortSerialGetByte两个函数用于串口发送和接收数据,在这里只要调用STM32的库函数即可。
17.staticvoidprv
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- FreeMb 移植 STM32F103
![提示](https://static.bdocx.com/images/bang_tan.gif)