STM32 HAL库实现FreeRTOS+FreeModbus(从机和主机)修改

发布时间:2026/7/18 17:21:04
STM32 HAL库实现FreeRTOS+FreeModbus(从机和主机)修改 STM32 HAL库实现FreeRTOSFreeModbus从机和主机FreeModbus\port\FreeRTOS\port_.cportDISABLE_INTERRUPTS();portENABLE_INTERRUPTS();/* 判断是否进入在中断中 */boolIS_IRQ(void){if(xPortIsInsideInterrupt()){returnTRUE;}returnFALSE;}FreeModbus\port\FreeRTOS\portevent.c xMBPortEventGetdefault:returnFALSE;FreeModbus\port\FreeRTOS\portevent_m.c xMBMasterPortEventGet recvedEvent(uint32_t)(EV_MASTER_READY|EV_MASTER_FRAME_RECEIVED|EV_MASTER_EXECUTE|EV_MASTER_FRAME_SENT|EV_MASTER_ERROR_PROCESS);default:returnFALSE;break;eMBMasterWaitRequestFinish recvedEvent(uint32_t)(EV_MASTER_PROCESS_SUCESS|EV_MASTER_ERROR_RESPOND_TIMEOUT|EV_MASTER_ERROR_RECEIVE_DATA|EV_MASTER_ERROR_EXECUTE_FUNCTION);default:{eErrStatusMB_MRE_REV_DATA;break;}FreeModbus\port\FreeRTOS\portserial.c xMBPortSerialInit serial-InstanceUSART1;serial-InstanceUSART2;serial-InstanceUSART3;serial-Init.ModeUART_MODE_TX_RX;serial-Init.HwFlowCtlUART_HWCONTROL_NONE;serial-Init.OverSamplingUART_OVERSAMPLING_16;if(HAL_UART_Init(serial)!HAL_OK){Error_Handler();}FreeModbus\port\FreeRTOS\portserial_m.c serial-InstanceUSART1;serial-InstanceUSART2;serial-InstanceUSART3;serial-Init.ModeUART_MODE_TX_RX;serial-Init.HwFlowCtlUART_HWCONTROL_NONE;serial-Init.OverSamplingUART_OVERSAMPLING_16;if(HAL_UART_Init(serial)!HAL_OK){Error_Handler();}FreeModbus\port\FreeRTOS\porttimer.c xMBPortTimersInit timerxTimerCreate(Slave timer,(50*usTim1Timerout50us)/(1000*1000/configTICK_RATE_HZ)1,pdFALSE,(void*)2,(TimerCallbackFunction_t)timer_timeout_ind);if(timer!NULL)returnTRUE;elsereturnFALSE;FreeModbus\port\port.h-#includecmsis_os.h-#includecmsis_os2.htypedefenum{MB_LOG_DEBUG,MB_LOG_INFO,MB_LOG_WARN,MB_LOG_ERROR}eMBPortLogLevel;boolIS_IRQ(void);FreeModbus\port\user_mb_app.c eMBRegHoldingCBxTaskNotify(Verity_Task_Handle,/* 任务句柄 */0x10,/* 发送的数据最大为 4 字节 */eSetBits);/* 任务通知可以看成是事件标志的一种轻量型的实现速度更快 */eMBRegCoilsCBxTaskNotify(Verity_Task_Handle,/* 任务句柄 */0x01,/* 发送的数据最大为 4 字节 */eSetBits);/* 任务通知可以看成是事件标志的一种轻量型的实现速度更快 */#includeFreeRTOS.h#includetask.h#includeprojdefs.h#includelimits.h#includeuser_mb_app.h#includestm_flash.h#includemain.h#includestdint.htypedefvoid(*Coil_Handle)(uint8_tcoil_state);typedefvoid(*Hold_Handle)(uint16_t*pHoldAddress);uint8_tAirConditioner_Set_Cmd0;constuint16_tCoil_Address_Index[]{2,// M23,// M3};staticvoidM2_Process(uint8_tcoil_state){if(coil_state){Coil_Write_0(2);}}staticvoidM3_Process(uint8_tcoil_state){if(coil_state){Coil_Write_0(3);}}constCoil_Handle coil_handle_table[]{M2_Process,M3_Process,};voidCoil_Execute(void){for(uint16_ti0;isizeof(coil_handle_table)/sizeof(coil_handle_table[0]);i){coil_handle_table[i](Coil_Get_State(Coil_Address_Index[i]));}}constuint16_tHold_Address_Index[]{5,6,};staticvoidD5_Process(uint16_t*pHoldAddress){}staticvoidD6_Process(uint16_t*pHoldAddress){}constHold_Handle hold_handle_table[]{D5_Process,D6_Process,};voidHold_Execute(void){for(uint16_ti0;isizeof(hold_handle_table)/sizeof(hold_handle_table[0]);i){hold_handle_table[i](Slave_station.usSRegHoldBufHold_Address_Index[i]);}}voidVerity_Task(void*pvParameters){BaseType_t xReturnpdFALSE;/* 定义一个创建信息返回值 */uint32_tflags0;while(1){// 获取任务通知 ,没获取到则一直等待xReturnxTaskNotifyWait(0x0,// 进入函数的时候不清除任务 bitULONG_MAX,// 退出函数的时候清除所有的 bitflags,// 保存任务通知值portMAX_DELAY);// 阻塞时间if(pdTRUExReturn){if(flags0x01){Coil_Execute();}if(flags0x10){Hold_Execute();}}}}modbus-tcpFreeModbus\modbus\mb.cexterneMBErrorCodeMBTCPReceive(UCHAR*pucRcvAddress,UCHAR**ppucFrame,USHORT*pusLength);externeMBErrorCodeMBTCPSend(UCHAR _unused,constUCHAR*pucFrame,USHORT usLength);eMBPoll peMBFrameReceiveCurMBTCPReceive;peMBFrameSendCurMBTCPSend;ucMBAddressMB_TCP_PSEUDO_ADDRESS;// /* Check if the protocol stack is ready. */// if( eMBState ! STATE_ENABLED )// {// return MB_EILLSTATE;// }#includetcp_echoserver.h#includelwip/sockets.h#includelwip/sys.h#includelwip/api.h#includestring.h#includestdlib.h#includestdio.h#includetask.h#includemb.h#includembport.h#includembtcp.h/* ----------------------- Defines ------------------------------------------*//* ----------------------- MBAP Header --------------------------------------*//* * * ------------------------ MODBUS TCP/IP ADU(1) ------------------------- * ----------- MODBUS PDU (1) ---------------- * -------------------------------------------------------------------- * | TID | PID | Length | UID |Code | Data | * -------------------------------------------------------------------- * | | | | | * (2) (3) (4) (5) (6) * * (2) ... MB_TCP_TID 0 (Transaction Identifier - 2 Byte) * (3) ... MB_TCP_PID 2 (Protocol Identifier - 2 Byte) * (4) ... MB_TCP_LEN 4 (Number of bytes - 2 Byte) * (5) ... MB_TCP_UID 6 (Unit Identifier - 1 Byte) * (6) ... MB_TCP_FUNC 7 (Modbus Function Code) * * (1) ... Modbus TCP/IP Application Data Unit * (1) ... Modbus Protocol Data Unit */#defineMB_TCP_TID0#defineMB_TCP_PID2#defineMB_TCP_LEN4#defineMB_TCP_UID6#defineMB_TCP_FUNC7#defineMB_TCP_PROTOCOL_ID0/* 0 Modbus Protocol *//* ----------------------- Defines -----------------------------------------*/#defineMB_TCP_DEFAULT_PORT502/* TCP listening port. */// #define MB_TCP_BUF_SIZE (256 7) /* Must hold a complete Modbus TCP frame. */#defineMB_TCP_BUF_SIZE(600)intsock-1;intconnected-1;charrecv_data[Server_RX_BUFSZ];UCHAR aucTCPBuf[MB_TCP_BUF_SIZE];USHORT usTCPBufPos;BOOLMBTCPPortGetRequest(UCHAR**ppucMBTCPFrame,USHORT*usTCPLength){*ppucMBTCPFrameaucTCPBuf[0];*usTCPLengthusTCPBufPos;/* Reset the buffer. */usTCPBufPos0;returnTRUE;}eMBErrorCodeMBTCPReceive(UCHAR*pucRcvAddress,UCHAR**ppucFrame,USHORT*pusLength){eMBErrorCode eStatusMB_EIO;UCHAR*pucMBTCPFrame;USHORT usLength;USHORT usPID;if(MBTCPPortGetRequest(pucMBTCPFrame,usLength)!FALSE){usPIDpucMBTCPFrame[MB_TCP_PID]8U;usPID|pucMBTCPFrame[MB_TCP_PID1];if(usPIDMB_TCP_PROTOCOL_ID){*ppucFramepucMBTCPFrame[MB_TCP_FUNC];*pusLengthusLength-MB_TCP_FUNC;eStatusMB_ENOERR;/* Modbus TCP does not use any addresses. Fake the source address such * that the processing part deals with this frame. */*pucRcvAddressMB_TCP_PSEUDO_ADDRESS;}}else{eStatusMB_EIO;}returneStatus;}eMBErrorCodeMBTCPSend(UCHAR _unused,constUCHAR*pucFrame,USHORT usLength){eMBErrorCode eStatusMB_ENOERR;UCHAR*pucMBTCPFrame(UCHAR*)pucFrame-MB_TCP_FUNC;USHORT usTCPLengthusLengthMB_TCP_FUNC;/* The MBAP header is already initialized because the caller calls this * function with the buffer returned by the previous call. Therefore we * only have to update the length in the header. Note that the length * header includes the size of the Modbus PDU and the UID Byte. Therefore * the length is usLength plus one. */pucMBTCPFrame[MB_TCP_LEN](usLength1)8U;pucMBTCPFrame[MB_TCP_LEN1](usLength1)0xFF;if(write(connected,pucMBTCPFrame,usTCPLength)FALSE){eStatusMB_EIO;}returneStatus;}err_tMBTCPPortReceive(char*data,uint32_tlen){USHORT usLength0;err_terrorERR_OK;usTCPBufPos0;/* Check for internal buffer overflow. In case of an error drop the * client. */if((usTCPBufPoslen)MB_TCP_BUF_SIZE){errorERR_VAL;}else{memcpy(aucTCPBuf[usTCPBufPos],data,len);usTCPBufPoslen;/* If we have received the MBAP header we can analyze it and calculate * the number of bytes left to complete the current request. If complete * notify the protocol stack. */if(usTCPBufPosMB_TCP_FUNC){/* Length is a byte count of Modbus PDU (function code data) and the * unit identifier. */usLengthaucTCPBuf[MB_TCP_LEN]8U;usLength|aucTCPBuf[MB_TCP_LEN1];/* Is the frame already complete. */if(usTCPBufPos(MB_TCP_UIDusLength)){(void)xMBPortEventPost(EV_FRAME_RECEIVED);}}errorERR_OK;}returnerror;}uint8_tdisconnect_flag0;/** * 函数功能: tcp server线程函数 * 输入参数: 无 * 返 回 值: 无 * 说 明: 无 */staticvoidtcpecho_server_thread(void*arg){structsockaddr_inserver_addr,client_addr;socklen_tsin_size;intrecv_data_len;structtimevaltv_out;tv_out.tv_sec5;tv_out.tv_usec0;fd_set readfds;fd_set errofds;while(1){/* 申请套接字本质是netconn_new函数的封装 */socksocket(AF_INET,SOCK_STREAM,0);if(sock0){printf(Socket error\n);goto__exit;}/* 为sockaddr_in结构体成员赋值用于以下的bind绑定 */server_addr.sin_familyAF_INET;server_addr.sin_addr.s_addrINADDR_ANY;server_addr.sin_porthtons(MB_TCP_DEFAULT_PORT);/* 清空sockaddr_in结构体内存空间 */memset((server_addr.sin_zero),0,sizeof(server_addr.sin_zero));/* 服务器绑定ip地址与端口 */if(bind(sock,(structsockaddr*)server_addr,sizeof(structsockaddr))-1){printf(Unable to bind\n);goto__exit;}/* 服务器进入监听状态 */if(listen(sock,5)-1){printf(Listen error\n);goto__exit;}while(1){sin_sizesizeof(structsockaddr_in);/* 等待远端client的链接 */connectedaccept(sock,(structsockaddr*)client_addr,sin_size);{intflag1;/* 设置套接字的选项 */setsockopt(connected,IPPROTO_TCP,/* set option at TCP level */TCP_NODELAY,/* name of option */(void*)flag,/* the cast is historical cruft */sizeof(int));/* length of option value */}FD_ZERO(readfds);FD_SET(connected,readfds);FD_ZERO(errofds);FD_SET(connected,errofds);while(1){intretselect(connected1,readfds,(fd_set*)0,errofds,tv_out);if(ret0){memset(recv_data,0,sizeof(recv_data));/* 成功接收到数据返回接收的数据长度 */recv_data_lenrecv(connected,recv_data,Server_RX_BUFSZ,0);if(recv_data_len0){disconnect_flag3;break;}if(MBTCPPortReceive(recv_data,recv_data_len)!ERR_OK){disconnect_flag2;break;}}elseif(ret0){disconnect_flag1;break;}else{disconnect_flag4;break;}}if(connected0){closesocket(connected);}connected-1;disconnect_flag0;}__exit:if(sock0)closesocket(sock);}}/** * 函数功能: tcp任务 * 输入参数: 无 * 返 回 值: 无 * 说 明: 无 */voidtcpecho_server_init(void){sys_thread_new(tcpecho_thread,tcpecho_server_thread,NULL,512,53);}