------------------紧接上一帖----------------
4.freemodbus在stm32平台测试与调试
一个不会打仗的士兵不是好士兵,整天在兵营里吹牛x,偶尔还放空枪,这样的还放下狠话,要灭人家一个师,就没见过这么厚脸皮的。我们要学习独立团团长李云龙,别扯那多没有用的,有真本事“亮剑”见识一下。So,我们今天就来试一试移植的效果,一起调一调主函数。
先来分析一下,想要能请得动FreeModbus这位大佬,要想让它为我们服务,首先需要给它伺候舒服了,也就是需要先对FreeModbus进行初始化。初始化的步骤其实就是调用eMBInit函数和eMBEnable函数,温馨补充一下照顾一下腼腆的孩子们:eMBInit函数函数是设置硬件的,有五个参数,分别是:
参数1.Modbus的模式:这里可以选择RTU、ASCII、TCP,这里我们选择RTU模式(MB_RTU);
参数2.设备的地址:这里可以直接写死(0x01),也可以通过拨码开关来设置;
参数3.Modbus选择的串口号:这里默认是串口2(0x02);
参数4.波特率:默认写115200,我们这里配置为9600;
参数5.校验位:默认不效验(MB_PAR_NONE)。
然后在主循环中调用eMBPoll函数不断查询。int main()函数具体代码如下:
int main(void) { delay_init(); //延时函数初始化 //初始化 RTU模式 从机地址为1 USART2 9600 无效验 eMBInit(MB_RTU, 0x01, 0x02, 9600, MB_PAR_NONE); //启动FreeModbus eMBEnable(); while(1) { //FreeMODBUS不断查询 eMBPoll(); } } |
01.当然,仅仅拿个main函数出来,是不能够证明FreeModbus就跑起来了,我们再来添加点测试部分代码,以观其效吧!测试代码部分,主要添加输入寄存器、保持寄存器、线圈的起始地址和定义的内容,以及输入寄存器、保持寄存器、线圈的处理函数,具体如下:
/* ----------------------- Defines ------------------------------------------*/ //添加输入寄存器、保持寄存器、线圈的起始地址和定义的内容 //保持寄存器起始地址 #define REG_HOLDING_START 0x0001 //保持寄存器数量 #define REG_HOLDING_NREGS 8 //保持寄存器内容 uint16_t usRegHoldingBuf[REG_HOLDING_NREGS] ={0x147b,0x3f8e,0x147b,0x400e,0x1eb8,0x4055,0x147b,0x408e}; //输入寄存器起始地址 #define REG_INPUT_START 0x0001 //输入寄存器数量 #define REG_INPUT_NREGS 8 //输入寄存器内容 uint16_t usRegInputBuf[REG_INPUT_NREGS] ={0x1111,0x2222,0x3333,0x4444,0x5555,0x6666,0x7777,0x8888}; //线圈寄存器起始地址 #define REG_COILS_START 0x0001 //线圈寄存器数量 #define REG_COILS_SIZE 16 //线圈寄存器内容 uint8_t ucRegCoilsBuf[REG_COILS_SIZE/8] = {0x00,0xFF}; /***********************************************************************/ 输入寄存器、保持寄存器、线圈的处理函数 // 保持寄存器的读写函数 支持的命令为读 0x03 和写0x06 可读可写 eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs,eMBRegisterMode eMode ) { //错误状态 eMBErrorCode eStatus = MB_ENOERR; //偏移量 int16_t iRegIndex; //判断寄存器是不是在范围内 if( ( (int16_t)usAddress >= REG_HOLDING_START )&& ( usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS ) ) { //计算偏移量 iRegIndex = ( int16_t )( usAddress - REG_HOLDING_START); switch ( eMode ) { //读处理函数 case MB_REG_READ: while( usNRegs > 0 ) { *pucRegBuffer++ = ( uint8_t )( usRegHoldingBuf[iRegIndex] >> 8 ); *pucRegBuffer++ = ( uint8_t )( usRegHoldingBuf[iRegIndex] & 0xFF ); iRegIndex++; usNRegs--; } break; //写处理函数 case MB_REG_WRITE: while( usNRegs > 0 ) { usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8; usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++; iRegIndex++; usNRegs--; } break; } } else { //返回错误状态 eStatus = MB_ENOREG; } return eStatus; } //读输入寄存器函数 支持的命令为读 0x04 eMBErrorCode eMBRegInputCB( 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 - REG_INPUT_START ); while( usNRegs > 0 ) { *pucRegBuffer++ = ( unsigned char )( usRegInputBuf[iRegIndex] >> 8 ); *pucRegBuffer++ = ( unsigned char )( usRegInputBuf[iRegIndex] & 0xFF ); iRegIndex++; usNRegs--; } } else { eStatus = MB_ENOREG; } return eStatus; } //线圈处理函数 可读可写 支持的命令为读 0x01 0x05 eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode ) { //错误状态 eMBErrorCode eStatus = MB_ENOERR; //寄存器个数 int16_t iNCoils = ( int16_t )usNCoils; //寄存器偏移量 int16_t usBitOffset; //判断寄存器是不是在范围内 if( ( (int16_t)usAddress >= REG_COILS_START ) &&( usAddress + usNCoils <= REG_COILS_START + REG_COILS_SIZE ) ) { //计算寄存器偏移量 usBitOffset = ( int16_t )( usAddress - REG_COILS_START ); switch ( eMode ) { //读操作 case MB_REG_READ: while( iNCoils > 0 ) { *pucRegBuffer++ = xMBUtilGetBits( ucRegCoilsBuf, usBitOffset, ( uint8_t )( iNCoils > 8 ? 8 : iNCoils ) ); iNCoils -= 8; usBitOffset += 8; } break; //写操作 case MB_REG_WRITE: while( iNCoils > 0 ) { xMBUtilSetBits( ucRegCoilsBuf, usBitOffset, ( uint8_t )( iNCoils > 8 ? 8 : iNCoils ), *pucRegBuffer++ ); iNCoils -= 8; } break; } } else { eStatus = MB_ENOREG; } return eStatus; return MB_ENOREG; } |
02.好了,测试代码准备就绪,下面就是见证奇迹的时刻?我们使用ModbusPoll软件测试版来完成对移植FreeModbus rtu的测试,如下图,该代码能够成功的读出输入寄存器、保持寄存器、线圈的数据。
03. 通信正常,则可以看到USB转串口工具的TX和RX指示灯不停闪烁着。想象一下突然有一天,人类的眼睛可以分辨出100MHz以上的闪烁频率时,我们的世界将会如何?emmmm....这个脑洞可能开的有点大,留给大家去发挥想象力吧。如果我们能够分辨更高的频率,那么我们的电脑手机显示器的144Hz的刷新率,就再也不香了吧,哈哈~!
综上可以看出,本次对FreeModbus的移植工作已经完成了,该平台虽然是基于STM32F1xx,但是使用其他STM32的芯片也非常的方便,过程大致相同,简单改一下就好了。从通过ModbusPoll工具进行测试的结果看来,整个工程基本能够达到预期效果,当然本人技术有限,还请各位大佬们不吝赐教。最后贴上main测试完整代码供大家参考。
#include "sys.h" #include "delay.h" #include "usart.h" #include "led.h" #include "mb.h" #include "mbport.h" /* ----------------------- Defines ------------------------------------------*/ //保持寄存器起始地址 #define REG_HOLDING_START 0x0001 //保持寄存器数量 #define REG_HOLDING_NREGS 8 //保持寄存器内容 uint16_t usRegHoldingBuf[REG_HOLDING_NREGS] ={0x147b,0x3f8e,0x147b,0x400e,0x1eb8,0x4055,0x147b,0x408e}; //输入寄存器起始地址 #define REG_INPUT_START 0x0001 //输入寄存器数量 #define REG_INPUT_NREGS 8 //输入寄存器内容 uint16_t usRegInputBuf[REG_INPUT_NREGS] ={0x1111,0x2222,0x3333,0x4444,0x5555,0x6666,0x7777,0x8888}; //线圈寄存器起始地址 #define REG_COILS_START 0x0001 //线圈寄存器数量 #define REG_COILS_SIZE 16 //线圈寄存器内容 uint8_t ucRegCoilsBuf[REG_COILS_SIZE/8] = {0x00,0xFF}; int main(void) { delay_init(); //延时函数初始化 //初始化 RTU模式 从机地址为1 USART2 9600 无效验 eMBInit(MB_RTU, 0x01, 0x02, 9600, MB_PAR_NONE); //启动FreeModbus eMBEnable(); while(1) { //FreeMODBUS不断查询 eMBPoll(); } } // 保持寄存器的读写函数 支持的命令为读 0x03 和写0x06 可读可写 eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs,eMBRegisterMode eMode ) { //错误状态 eMBErrorCode eStatus = MB_ENOERR; //偏移量 int16_t iRegIndex; //判断寄存器是不是在范围内 if( ( (int16_t)usAddress >= REG_HOLDING_START )&& ( usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS ) ) { //计算偏移量 iRegIndex = ( int16_t )( usAddress - REG_HOLDING_START); switch ( eMode ) { //读处理函数 case MB_REG_READ: while( usNRegs > 0 ) { *pucRegBuffer++ = ( uint8_t )( usRegHoldingBuf[iRegIndex] >> 8 ); *pucRegBuffer++ = ( uint8_t )( usRegHoldingBuf[iRegIndex] & 0xFF ); iRegIndex++; usNRegs--; } break; //写处理函数 case MB_REG_WRITE: while( usNRegs > 0 ) { usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8; usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++; iRegIndex++; usNRegs--; } break; } } else { //返回错误状态 eStatus = MB_ENOREG; } return eStatus; } //读输入寄存器函数 支持的命令为读 0x04 eMBErrorCode eMBRegInputCB( 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 - REG_INPUT_START ); while( usNRegs > 0 ) { *pucRegBuffer++ = ( unsigned char )( usRegInputBuf[iRegIndex] >> 8 ); *pucRegBuffer++ = ( unsigned char )( usRegInputBuf[iRegIndex] & 0xFF ); iRegIndex++; usNRegs--; } } else { eStatus = MB_ENOREG; } return eStatus; } //线圈处理函数 可读可写 支持的命令为读 0x01 0x05 eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode ) { //错误状态 eMBErrorCode eStatus = MB_ENOERR; //寄存器个数 int16_t iNCoils = ( int16_t )usNCoils; //寄存器偏移量 int16_t usBitOffset; //判断寄存器是不是在范围内 if( ( (int16_t)usAddress >= REG_COILS_START ) &&( usAddress + usNCoils <= REG_COILS_START + REG_COILS_SIZE ) ) { //计算寄存器偏移量 usBitOffset = ( int16_t )( usAddress - REG_COILS_START ); switch ( eMode ) { //读操作 case MB_REG_READ: while( iNCoils > 0 ) { *pucRegBuffer++ = xMBUtilGetBits( ucRegCoilsBuf, usBitOffset, ( uint8_t )( iNCoils > 8 ? 8 : iNCoils ) ); iNCoils -= 8; usBitOffset += 8; } break; //写操作 case MB_REG_WRITE: while( iNCoils > 0 ) { xMBUtilSetBits( ucRegCoilsBuf, usBitOffset, ( uint8_t )( iNCoils > 8 ? 8 : iNCoils ), *pucRegBuffer++ ); iNCoils -= 8; } break; } } else { eStatus = MB_ENOREG; } return eStatus; return MB_ENOREG; } //开关输入寄存器处理函数 可读 支持的命令为读 0x02 eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete ) { return MB_ENOREG; } //针对 assert错误添加的函数 #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t* file, uint32_t line) { /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* Infinite loop */ while (1) { } } #else void __aeabi_assert(const char * x1, const char * x2, int x3) { } #endif |
本系列到此就全部结束了,大家好,我是大Z,感谢大家支持~