freemodbus 在STM32上的移植
来源:互联网 发布:阿里云 深信服 编辑:程序博客网 时间:2024/05/14 12:56
这几天,研究了freemodbus通信协议,然后在stm32上移植。关于freemodbus通信原理,以及通信过程(状态机转换),这里就不说了。
freemodbus使用的库是最新版本freemodbus-v1.5.0,把相应的库文件加载在STM32工程中。移植时,需要用户改写的文件有两个,一个是porttimer.c文件,一个是portserial.c文件。porttimer.c文件主要用于超时判断,本例使用的是定时器2,portserial.c主要使用串口通信的实现,本例使用的是RS485.porttimer.c修改如下
/* ----------------------- Platform includes --------------------------------*/#include "port.h"/* ----------------------- Modbus includes ----------------------------------*/#include "mb.h"#include "mbport.h"#include "..\..\include\nvic.h"#include "..\..\include\stm32f10x_reg.h"/* ----------------------- Start implementation -----------------------------*/BOOLxMBPortTimersInit( USHORT usTim1Timerout50us ) //配置50us时钟{uint16_t PrescalerValue = 0;/* TIM2 clock enable */RCC->CFGR.B.PPRE1 = 4; //APB1预分频系数 //100:HCLK 2分频 //APB1 不超过36MHzRCC->APB1ENR.B.TIM2EN = 1;/* Compute the prescaler value */PrescalerValue = (uint16_t) (36000000 / 20000) - 1; // 1/20000=50us /* Time base configuration */TIM2->ARR=(uint16_t) usTim1Timerout50us;TIM2->PSC= PrescalerValue;TIM2->CR1.B.URS = 1; MY_NVIC_Init(3,3,28,2); /* TIM IT DISABLE */TIM2->SR.B.UIF = 0;TIM2->DIER.B.UIE = 0;TIM2->CR1.B.CEN = 0;/* TIM2 DISABLE counter */return TRUE;;}void vMBPortTimersEnable( ) //打开时钟{ TIM2->SR.B.UIF = 0;TIM2->DIER.B.UIE = 1;TIM2->CNT= 0;TIM2->CR1.B.CEN = 1; }void vMBPortTimersDisable( ) //关闭时钟{TIM2->CR1.B.CEN = 0;TIM2->CNT= 0;TIM2->DIER.B.TIE = 0;TIM2->DIER.B.UIE = 0;}/* Create an ISR which is called whenever the timer has expired. This function * must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that * the timer has expired. */void prvvTIMERExpiredISR( void ) //在时钟中断内调用{ ( void )pxMBPortCBTimerExpired( );}void TIM2_IRQHandler(void){ /* Clear TIM4 Capture Compare1 interrupt pending bit*/ TIM2->SR.B.UIF = 0;TIM2->SR.B.TIF = 0;prvvTIMERExpiredISR( );}
portserial.c文件修改如下
/* ----------------------- Modbus includes ----------------------------------*/#include "mb.h"#include "mbport.h"#include "..\..\include\nvic.h"#include "..\..\include\stm32f10x_reg.h"#include "mb.h"#include "mbport.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include <math.h>#include <stdarg.h>#defineRS485_T GPIOA->BSRR.B.SETIO4=1#define RS485_R GPIOA->BSRR.B.CLRIO4=1/* ----------------------- Start implementation -----------------------------*/voidvMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable ) //控制串口的收发中断{if(TRUE==xRxEnable){USART2->CR1.B.RXNEIE = 1; }else{USART2->CR1.B.RXNEIE = 0;}if(TRUE==xTxEnable){USART2->CR1.B.TXEIE = 1;}else{ USART2->CR1.B.TXEIE = 0; }}/****************************************** 配置串口 目前除了波特率其他参数无效 * Usart1 9600-8-N-1*****************************************/BOOL xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity ){float temp; float temp2; AFIO->MAPR.B.USART2_REMAP=0; //无重映像 RCC->APB1ENR.B.USART2EN = 1; //USART2时钟开启GPIOA->CRL.B.MODE2 = 3;// Configure USART2 Tx (PA.2) as alternate function push-pull GPIOA->CRL.B.CNF2 = 2;GPIOA->CRL.B.MODE3 = 0;// Configure USART2 Rx (PA.3) as input floating GPIOA->CRL.B.CNF3 = 1; temp= (72000000.0/2)/(16*ulBaudRate);temp2=floor(temp);temp=temp-temp2;temp*=16;USART2->BRR.B.DIV_Fraction=temp;//DIV_Fraction[3:0]:USARTDIV的小数部分//这4位定义了USART分频器除法因子(USARTDIV)的小数部分。// 6 9600USART2->BRR.B.DIV_Mantissa=temp2;//DIV_Mantissa[11:0]:USARTDIV的整数部分//这12位定义了USART分频器除法因子(USARTDIV)的整数部分。//234 9600USART2->CR1.B.PCE = 0; //0:校验控制被禁止;USART2->CR1.B.M = 0; //0:一个起始位,8个数据位,n个停止位;USART2->CR1.B.RE = 1; //1:接受被使能。USART2->CR1.B.TE = 1; //1:发送被使能。USART2->CR1.B.RXNEIE = 1; //1:当USART_SR中的ORE或者RXNE为1时,产生USART中断。USART2->CR1.B.PEIE = 1; //1:当USART_SR中的PE为1时,产生USART中断。USART2->CR1.B.UE = 1; //1:USART模块使能。USART2->CR2.B.LBCL = 0; //0:最后一位数据的时钟脉冲不从SCLK输出;USART2->CR2.B.CPOL = 0; //0:总线空闲时SCLK引脚上保持低电平;USART2->CR2.B.CLKEN = 0; //0:SCLK引脚被禁止。USART2->CR2.B.STOP = 0; //00:1个停止位;USART2->CR2.B.CPHA = 1; //1:时钟二个第边沿进行数据捕获。USART2->CR3.B.RTSE = 0; //0:RTS硬件流控制被禁止;USART2->CR3.B.CTSE = 0; //0:CTS硬件流控制被禁止; MY_NVIC_Init(3,3,38,2);//组2,最低优先级 GPIOA->CRL.B.MODE4 = 3;GPIOA->CRL.B.CNF4 = 0; RS485_R; return TRUE;}// 串口发BOOLxMBPortSerialPutByte( CHAR ucByte ){int i;RS485_T; for(i=0;i<1000;i++); USART2->DR.W= ucByte; while (!(USART2->SR.B.TC == 1)) ; RS485_R; return TRUE;}// 串口收BOOLxMBPortSerialGetByte( CHAR * pucByte ){ *pucByte = USART2->DR.W; return TRUE;}/* Create an interrupt handler for the transmit buffer empty interrupt * (or an equivalent) for your target processor. This function should then * call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that * a new character can be sent. The protocol stack will then call * xMBPortSerialPutByte( ) to send the character. */ void prvvUARTTxReadyISR( void ){ pxMBFrameCBTransmitterEmpty( );}/* Create an interrupt handler for the receive interrupt for your target * processor. This function should then call pxMBFrameCBByteReceived( ). The * protocol stack will then call xMBPortSerialGetByte( ) to retrieve the * character. */void prvvUARTRxISR( void ){ pxMBFrameCBByteReceived( );}void USART2_IRQHandler(void){if(USART2->CR1.B.RXNEIE==1) {prvvUARTRxISR();//接收完成中断USART2->SR.B.RXNE=0; }if(USART2->CR1.B.TXEIE==1){prvvUARTTxReadyISR();//发送完成中断USART2->SR.B.TC=0;}}
另外在主函数中,加入测试函数如下
#include "mb.h" #include "..\..\include\adc.h" #include "..\..\include\lm75.h" #include "..\..\include\timer.h" unsigned short int usRegInputBuf[10]={0x0000,0xfe02,0x1203,0x1304,0x1405,0x1506,0x1607,0x1708,0x1809};unsigned short int *usRegHoldingBuf=usRegInputBuf;//一个测试用的 寄存器数组 地址0-7unsigned char REG_INPUT_START=0,REG_HOLDING_START=0;unsigned char REG_INPUT_NREGS=8,REG_HOLDING_NREGS=8;unsigned char usRegInputStart=0,usRegHoldingStart=0;//读数字寄存器 功能码0x04eMBErrorCodeeMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs ){eMBErrorCode eStatus = MB_ENOERR;int iRegIndex; if( ( usAddress >= REG_INPUT_START )&& ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) ) { iRegIndex = ( int )( usAddress - usRegInputStart ); while( usNRegs > 0 ) { *pucRegBuffer++ = ( unsigned char )( usRegInputBuf[iRegIndex] >> 8 ); *pucRegBuffer++ = ( unsigned char )( usRegInputBuf[iRegIndex] & 0xFF ); iRegIndex++; usNRegs--; } } else { eStatus = MB_ENOREG; } return eStatus;}// 寄存器的读写函数 支持的命令为读 0x03 和写0x06eMBErrorCodeeMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode ){ eMBErrorCode eStatus = MB_ENOERR; int iRegIndex; if( ( usAddress >= REG_HOLDING_START ) && ( usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS ) ) { iRegIndex = ( int )( usAddress - usRegHoldingStart ); switch ( eMode ) { case MB_REG_READ: if(usAddress==1) { *pucRegBuffer++ = ( unsigned char )( adc.read(1) >> 8 ); *pucRegBuffer++ = ( unsigned char )( adc.read(1) & 0xFF ); }if(usAddress==2) { *pucRegBuffer++ = ( unsigned char )( adc.read(0) >> 8 ); *pucRegBuffer++ = ( unsigned char )( adc.read(0) & 0xFF ); }if(usAddress==3) { *pucRegBuffer++ = ( unsigned char )( adc.read(7) >> 8 ); *pucRegBuffer++ = ( unsigned char )( adc.read(7) & 0xFF ); }if(usAddress==4) { *pucRegBuffer++ = ( unsigned char )( lm75.read() >> 8 ); *pucRegBuffer++ = ( unsigned char )( lm75.read() & 0xFF ); } if(usAddress==5) {timer.refresh();*pucRegBuffer++ = ( unsigned char )( tim_parameter.Position_relative >> 8 ); *pucRegBuffer++ = ( unsigned char )( tim_parameter.Position_relative &0xFF );} if(usAddress==6) {timer.refresh();*pucRegBuffer++ = ( unsigned char )( TIM1->CCR2>> 8 ); *pucRegBuffer++ = ( unsigned char )( TIM1->CCR2&0xFF );} break; case MB_REG_WRITE: while( usNRegs > 0 ) { usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8; usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++; iRegIndex++; usNRegs--; } } } else { eStatus = MB_ENOREG; } return eStatus;}//读/写开关寄存器 0x01 x05eMBErrorCodeeMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode ){ ( void )pucRegBuffer; ( void )usAddress; ( void )usNCoils; ( void )eMode; return MB_ENOREG;}//读开关寄存器 0x02eMBErrorCodeeMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete ){ ( void )pucRegBuffer; ( void )usAddress; ( void )usNDiscrete; return MB_ENOREG;}
经过,测试,本次移植可以读取节点的温度,AD转换值,等参数,实现了预期的效果。
csdn好像不支持工程的上传,有需要的话联系我 qq 1109503213,一起交流学习
- freemodbus 在STM32上的移植
- FreeModbus在STM32上移植。
- Freemodbus RTU在stm32上的移植分析
- Freemodbus RTU在stm32上的移植分析
- Freemodbus RTU在stm32上的移植分析
- freemodbus 在stm32+W5500平台上的移植
- 在STM32上移植FreeModbus RTU的一点经验总结
- Freemodbus RTU在stm32上的移植分析
- 在STM32上移植FreeModbus RTU的一点经验总结
- Freemodbus RTU在stm32上的移植分析
- freemodbus在STM32F100C8上的移植
- 基于EncEthernet的FreeModbus-TCP 在stm32上的移植与测试
- 基于EncEthernet的FreeModbus-TCP 在stm32上的移植与测试
- STM32 上移植FreeModbus详细过程(学习总结)
- STM32 移植FreeModbus 详细过程
- ucose ii 在stm32上的移植
- uCos在stm32上的移植总结
- ucosii在stm32上的移植详解
- 一个mongo php sdk长连接的问题
- PHP $_SERVER详细参数和说明
- 如何根据meta-data内容杀指定应用
- 查询表主键、外键
- 顺时针打印矩阵
- freemodbus 在STM32上的移植
- hadoop-改进的wordcount
- VB.NET机房个人重构版-磨刀篇(一)
- 【转】物联网跟我动手做系列教程—第三篇 实验三如何用arduino+ethernet shield与yeelink结合5分钟实现web远程家电控制(代码已更新)
- MPLS Terminology & Label Operations
- VC 资源和函数调用
- cxf获取本地IP
- Linux 多线程应用中的信号处理
- Unrecognized xbean element mapping: beans in namespace http://xfire.codehaus.org