[应用相关] STM32 上移植 FreeModbus RTU

[复制链接]
2464|39
 楼主| stm32jy 发表于 2020-2-27 19:00 | 显示全部楼层 |阅读模式
解压 freemodbus v1.6 源码 看到如下文件目录结构  
708085e57a1496ee2b.png



 楼主| stm32jy 发表于 2020-2-27 19:00 | 显示全部楼层
文件夹 demo 就是官方针对不同平台移植的测试代码
文件夹 doc 是一些说明性文档
文件夹 modbus 就是功能实现的源码所在了
文件夹 tools 是上位机软件
 楼主| stm32jy 发表于 2020-2-27 19:01 | 显示全部楼层
FREEMODBUS V1.6 压缩后 MODBUS 文件夹内容
424655e57a1822f864.png
 楼主| stm32jy 发表于 2020-2-27 19:01 | 显示全部楼层
FREEMODBUS V1.6 压缩后 DEMO 文件夹内容
5005e57a19f0d7ad.png
 楼主| stm32jy 发表于 2020-2-27 19:02 | 显示全部楼层
FREEMODBUS V1.6 压缩后 DEMO\BARE 文件夹内容
574005e57a1bd3c38a.png
 楼主| stm32jy 发表于 2020-2-27 19:02 | 显示全部楼层
FREEMODBUS V1.6 压缩后 DEMO\BARE\port 文件夹内容
632765e57a1d8158e3.png
 楼主| stm32jy 发表于 2020-2-27 19:04 | 显示全部楼层
新 建 一 个 工 程 , 工 程 项 目 所 有 的 文 件 夹 名 为FreeModbus-STM32,在该文件夹内再建立一个文件夹 FreeModbus,然后
在文件夹 FreeModbus 下再分别建立一个 modbus 文件夹和 port 文件夹
工程项目所在文件夹下创建一个 FREEMODBUS 文件夹
2055e57a23c794c1.png
 楼主| stm32jy 发表于 2020-2-27 19:04 | 显示全部楼层
工程项目所在文件夹 FREEMODBUS 下创建 modbus 文件夹和 port 文件夹
396315e57a2570642b.png
 楼主| stm32jy 发表于 2020-2-27 19:36 | 显示全部楼层
将 FreeModbusV1.6 下的 modbus 所有文件夹及文件拷贝到新建工程项目
FreeModbus 文件夹下的 modbus 子文件夹下
995515e57a9c534349.png
 楼主| stm32jy 发表于 2020-2-27 19:38 | 显示全部楼层
进入 FreeModbusV1.6 下的 demo 文件夹,看到有各个平台的测试代码文件夹,没
看到 STM32 的,但是看到 BARE 这个不带任何平台的代码文件,将 FreeModbusV1.6 下
\demo\BARE\port 下的所有文件拷贝到新建工程项目 FreeModbus 文件夹下\port 文件夹中
723495e57aa42185ed.png
 楼主| stm32jy 发表于 2020-2-27 19:39 | 显示全部楼层
其中:
(1)、 port.h 需要修改。
(2)、 porteven.c 不需要任何修改
(3)、 portserial.c 需要修改
(4)、 porttimer.c 需要修改。
(5)、另外还需要在 main 函数增加 4 个回调函数。
(5.1)、操作输入寄存器的回调函数 eMBErrorCode eMBRegInputCB( UCHAR *
pucRegBuffer, USHORT usAddress, USHORT usNRegs )
(5.2)、操作保持寄存器的回调函数 eMBErrorCode eMBRegHoldingCB( UCHAR *
pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )
(5.3 )、 操 作 线 圈 的 的 回 调 函 数 eMBErrorCode eMBRegCoilsCB( UCHAR *
pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )
(5.4)、操作离散寄存器的的回调函数 eMBErrorCode eMBRegDiscreteCB( UCHAR *
pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
 楼主| stm32jy 发表于 2020-2-27 19:39 | 显示全部楼层
打开 MDK,建立工程
855675e57aa8e3d821.png
 楼主| stm32jy 发表于 2020-2-27 19:40 | 显示全部楼层
打开 portserial.c 文件,这个是移植串口的,不管是 ASCII 模式还是 RTU 模式都需
要串口支持的, void vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )函数,使能
或失能串口的,移植代码如下
  1. void
  2. vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
  3. {
  4. /* If xRXEnable enable serial receive interrupts. If xTxENable enable* transmitter empty interrupts.
  5. */
  6. if (xRxEnable) //接收使能
  7. {
  8. USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); //使能接收中断
  9. GPIO_ResetBits(GPIOG, GPIO_Pin_8); //设置 RS485 接收
  10. }
  11. else //失能
  12. {
  13. USART_ITConfig(USART2, USART_IT_RXNE, DISABLE); //失能接收中断
  14. GPIO_SetBits(GPIOG, GPIO_Pin_8); //设置 RS485 发送
  15. }
  16. if (xTxEnable) //发送使能
  17. {
  18. USART_ITConfig(USART2, USART_IT_TC, ENABLE); //使能
  19. GPIO_SetBits(GPIOG, GPIO_Pin_8); //设置 RS485 发送
  20. }
  21. else //失能
  22. {
  23. USART_ITConfig(USART2, USART_IT_TC, DISABLE); //失能
  24. GPIO_ResetBits(GPIOG, GPIO_Pin_8); //设置 RS485 接收
  25. }
  26. }


 楼主| stm32jy 发表于 2020-2-27 19:41 | 显示全部楼层
串口初始化函数 BOOL xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate,UCHAR ucDataBits, eMBParity eParity ),使用的是串口 2 进行通讯
  1. BOOL
  2. xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
  3. {
  4. GPIO_InitTypeDef GPIO_InitStructure;
  5. USART_InitTypeDef USART_InitStructure;
  6. NVIC_InitTypeDef NVIC_InitStructure;
  7. (void)ucPORT; //不修改串口号
  8. (void)ucDataBits; //不修改数据位长度
  9. (void)eParity; //不修改检验格式
  10. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOG, ENABLE);
  11. RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
  12. //
  13. //管脚复用//
  14. GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);
  15. GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2);
  16. //
  17. //发送管脚 PA.02
  18. //接收管脚 PA.03
  19. //
  20. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
  21. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  22. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  23. GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  24. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  25. GPIO_Init(GPIOA, &GPIO_InitStructure);
  26. //
  27. //485 芯片发送接收控制管脚
  28. //
  29. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  30. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  31. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  32. GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  33. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  34. GPIO_Init(GPIOG, &GPIO_InitStructure);
  35. //
  36. //配置串口参数
  37. //
  38. USART_InitStructure.USART_BaudRate = ulBaudRate; //只修改波特率
  39. USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  40. USART_InitStructure.USART_StopBits = USART_StopBits_1;
  41. USART_InitStructure.USART_Parity = USART_Parity_No;
  42. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  43. USART_InitStructure.USART_Parity = USART_Mode_Rx | USART_Mode_Tx;
  44. USART_Init(USART2, &USART_InitStructure);
  45. //
  46. //使能串口
  47. //
  48. USART_Cmd(USART2, ENABLE);
  49. //
  50. //配置中断优先级
  51. //
  52. NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
  53. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  54. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  55. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  56. NVIC_Init(&NVIC_InitStructure);return TRUE;
  57. }


 楼主| stm32jy 发表于 2020-2-27 19:42 | 显示全部楼层
发送一个字节函数 BOOL xMBPortSerialPutByte( CHAR ucByte )
  1. BOOL
  2. xMBPortSerialPutByte( CHAR ucByte )
  3. {
  4. /* Put a byte in the UARTs transmit buffer. This function is called
  5. * by the protocol stack if pxMBFrameCBTransmitterEmpty( ) has been
  6. * called. */
  7. USART_SendData(USART2, ucByte); //发送一个字节
  8. return TRUE;
  9. }




 楼主| stm32jy 发表于 2020-2-27 19:43 | 显示全部楼层
接收一个字节函数 BOOL xMBPortSerialGetByte( CHAR * pucByte )
  1. BOOL
  2. xMBPortSerialGetByte( CHAR * pucByte )
  3. {
  4. /* Return the byte in the UARTs receive buffer. This function is called
  5. * by the protocol stack after pxMBFrameCBByteReceived( ) has been called.
  6. */
  7. *pucByte = USART_ReceiveData(USART2); //接收一个字节
  8. return TRUE;
  9. }


 楼主| stm32jy 发表于 2020-2-27 19:44 | 显示全部楼层
串口中断服务函数 void USART2_IRQHandler(void)
  1. void USART2_IRQHandler(void)
  2. {
  3. if (USART_GetITStatus(USART2, USART_IT_RXNE) == SET) //接收中断
  4. {
  5. prvvUARTRxISR();USART_ClearITPendingBit(USART2, USART_IT_RXNE);
  6. }
  7. if (USART_GetITStatus(USART2, USART_IT_TC) == SET) //发送中断
  8. {
  9. prvvUARTTxReadyISR();
  10. USART_ClearITPendingBit(USART2, USART_IT_TC);
  11. }
  12. }




 楼主| stm32jy 发表于 2020-2-27 19:45 | 显示全部楼层
打开 porttimer.c 文件, RTU 模式需要定时器支持,定时器初始化函数
  1. BOOL
  2. xMBPortTimersInit( USHORT usTim1Timerout50us )
  3. BOOL
  4. xMBPortTimersInit( USHORT usTim1Timerout50us )
  5. {
  6. // return FALSE;
  7. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  8. NVIC_InitTypeDef NVIC_InitStructure;
  9. uint16_t PrescalerValue = 0;
  10. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
  11. //
  12. //HCLK 为 72MHz
  13. //时基频率 72 / (1 + Prescaler) = 20KHz
  14. //
  15. PrescalerValue = (uint16_t)((SystemCoreClock / 20000) - 1);
  16. //
  17. //初始化定时器参数
  18. //
  19. TIM_TimeBaseStructure.TIM_Period = (uint16_t)usTim1Timerout50us;
  20. TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue;
  21. TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  22. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  23. TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
  24. //
  25. //使能预装
  26. //
  27. TIM_ARRPreloadConfig(TIM2, ENABLE);
  28. //
  29. //初始化中断优先级//
  30. NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
  31. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  32. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
  33. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  34. NVIC_Init(&NVIC_InitStructure);
  35. TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
  36. TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE);
  37. TIM_Cmd(TIM2, DISABLE);
  38. return TRUE;
  39. }




 楼主| stm32jy 发表于 2020-2-27 19:45 | 显示全部楼层
定时器使能函数 void vMBPortTimersEnable( )
  1. void
  2. vMBPortTimersEnable( )
  3. {
  4. /* Enable the timer with the timeout passed to xMBPortTimersInit( ) */
  5. TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
  6. TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
  7. TIM_SetCounter(TIM2, 0x00000000);
  8. TIM_Cmd(TIM2, ENABLE);
  9. }


 楼主| stm32jy 发表于 2020-2-27 19:46 | 显示全部楼层
定时器失能函数 void vMBPortTimersDisable( )
  1. void
  2. vMBPortTimersDisable( )
  3. {
  4. /* Disable any pending timers. */
  5. TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
  6. TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE);
  7. TIM_SetCounter(TIM2, 0x00000000);
  8. TIM_Cmd(TIM2, DISABLE);
  9. }


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

本版积分规则

44

主题

1118

帖子

4

粉丝
快速回复 在线客服 返回列表 返回顶部