#include "modbus_rec_send.h" #include "hardware.h" MODBUS_RX_STATE ModbusRxState = MODBUS_RX_RECEIVING; /*USART接收空闲中断*/ void USART1_IRQHandler(void) { uint32_t temp; uint16_t rxLenRemain; OSIntEnter(); /*进入中断*/ if(USART_GetITStatus(USART1, USART_IT_IDLE) == SET) { /*清除IDLE中断标志位*/ temp = USART1->SR; temp = USART1->DR; (void)temp; /*判断是否接收到帧,触发TIM计时*/ rxLenRemain = DMA_GetCurrDataCounter(DMA2_Stream2); ModbusRxLen = MODBUS_RX_BUF_SIZE - rxLenRemain; if(ModbusRxLen != 0) { switch (ModbusRxState) { /*正常接收数据*/ case MODBUS_RX_RECEIVING: ModbusRxState = MODBUS_RX_CHECK_T15; TimRestart(MODBUS_IDLE_TO_T15_US); break; /*在t1.5定时还未到达时又接收到了数据*/ case MODBUS_RX_CHECK_T15: ModbusRxState = MODBUS_RX_CHECK_T15; TimRestart(MODBUS_IDLE_TO_T15_US); break; /*在判断t1.5~t3.5是否出现字符时,t3.5定时中断还未触发,又接收到了数据*/ case MODBUS_RX_CHECK_T35: ModbusRxState = MODBUS_RX_DISCARD_CHECK_T35; /*判断为错误帧*/ TimRestart(MODBUS_IDLE_TO_T35_US); /*等待3.5字符该帧结束之后丢失该帧*/ break; /*在t1.5~t3.5中出现字符,随后又接收到数据*/ case MODBUS_RX_DISCARD: ModbusRxState = MODBUS_RX_DISCARD_CHECK_T35; /*判断为错误帧*/ TimRestart(MODBUS_IDLE_TO_T35_US); /*等待3.5字符该帧结束之后丢失该帧*/ break; /*在等待3.5字符该帧结束期间又接收到数据*/ case MODBUS_RX_DISCARD_CHECK_T35: ModbusRxState = MODBUS_RX_DISCARD_CHECK_T35; TimRestart(MODBUS_IDLE_TO_T35_US); /*再等待3.5字符该帧结束之后丢失该帧*/ break; } } } OSIntExit(); /*退出中断*/ } /*TIM定时器中断*/ void TIM5_IRQHandler(void) { uint16_t rxLenRemain; OSIntEnter(); rxLenRemain = DMA_GetCurrDataCounter(DMA2_Stream2); if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET) { switch (ModbusRxState) { /*检查在t1-t1.5期间是否接收到数据*/ case MODBUS_RX_CHECK_T15: /*在t1-t1.5期间接收到了数据,正常继续接收*/ if (MODBUS_RX_BUF_SIZE - rxLenRemain != ModbusRxLen) { ModbusRxState = MODBUS_RX_RECEIVING; TimOff(); } /*在t1-t1.5期间没收到,开始检查t1.5-t3.5期间是否接收到数据*/ else { ModbusRxState = MODBUS_RX_CHECK_T35; TimRestart(MODBUS_T15_TO_T35_US); } break; /*检查在t1.5-t3.5期间是否接收到数据*/ case MODBUS_RX_CHECK_T35: /*在t1.5-t3.5期间接收到了数据,判断为错误帧,等待串口空闲中断开启3.5字符等待定时器计时*/ if (MODBUS_RX_BUF_SIZE - rxLenRemain != ModbusRxLen) { ModbusRxState = MODBUS_RX_DISCARD; TimOff(); } /*在t1.5-t3.5之间都没接收到数据,该帧结束,开始帧解析*/ else { ModbusRxState = MODBUS_RX_RECEIVING; ModbusParseWakeUp(); } break; /*接收到错误帧,等待3.5字符之后丢弃该帧*/ case MODBUS_RX_DISCARD_CHECK_T35: /*在等待3.5字符期间又接收到了数据,等待串口空闲中断重新开启3.5字符等待定时器计时*/ if (MODBUS_RX_BUF_SIZE - rxLenRemain != ModbusRxLen) { ModbusRxState = MODBUS_RX_DISCARD_CHECK_T35; TimOff(); } /*在等待3.5字符期间没接收到数据,该错误帧结束,丢弃该帧,准备开始下一帧的接收*/ else { ModbusRxState = MODBUS_RX_RECEIVING; ModbusDmaRestart(); } break; } } OSIntExit(); } void TimRestart(uint32_t timArr) { /*启动TIM计时*/ TIM_Cmd(TIM5, DISABLE); TIM_SetCounter(TIM5, 0); /*清除计数值*/ TIM_SetAutoreload(TIM5, timArr); TIM_ClearITPendingBit(TIM5, TIM_IT_Update); /*清除中断标志位*/ TIM_Cmd(TIM5, ENABLE); } void TimOff(void) { TIM_Cmd(TIM5, DISABLE); TIM_SetCounter(TIM5, 0); /*清除计数值*/ TIM_ClearITPendingBit(TIM5, TIM_IT_Update); /*清除中断标志位*/ } void ModbusParseWakeUp(void) { uint16_t rxLenRemain; TimOff(); /*关闭DMA*/ DMA_Cmd(DMA2_Stream2, DISABLE); /*清除传输已经完成TCIF2、传输已经完成一半HTIF2标志位*/ DMA_ClearFlag(DMA2_Stream2, DMA_FLAG_TCIF2 | DMA_FLAG_HTIF2); /*计算数据长度*/ rxLenRemain = DMA_GetCurrDataCounter(DMA2_Stream2); ModbusRxLen = MODBUS_RX_BUF_SIZE - rxLenRemain; /*释放接收到数据帧信号量,唤醒帧解析任务*/ if(ModbusRxLen >= 4) /*4字节(1字节地址、1字节功能、2字节CRC)*/ { OSSemPost(ModbusReceived); } /*重新指定接收地址*/ DMA_MemoryTargetConfig(DMA2_Stream2, (uint32_t)ModbusRxBuf, DMA_Memory_0); /*重启DMA*/ DMA_SetCurrDataCounter(DMA2_Stream2, MODBUS_RX_BUF_SIZE); DMA_Cmd(DMA2_Stream2, ENABLE); } void ModbusDmaRestart(void) { TimOff(); /*关闭DMA*/ DMA_Cmd(DMA2_Stream2, DISABLE); /*清除传输已经完成TCIF2、传输已经完成一半HTIF2标志位*/ DMA_ClearFlag(DMA2_Stream2, DMA_FLAG_TCIF2 | DMA_FLAG_HTIF2); /*重新指定接收地址*/ DMA_MemoryTargetConfig(DMA2_Stream2, (uint32_t)ModbusRxBuf, DMA_Memory_0); /*重启DMA*/ DMA_SetCurrDataCounter(DMA2_Stream2, MODBUS_RX_BUF_SIZE); DMA_Cmd(DMA2_Stream2, ENABLE); } /*modbus响应帧发送*/ void ModbusSend(uint8_t *txBuf, uint16_t len) { if(DMA_GetCmdStatus(DMA2_Stream7) == ENABLE) { /*等待DMA发送完成*/ while(DMA_GetFlagStatus(DMA2_Stream7, DMA_FLAG_TCIF7) == RESET); } /*先关闭DMA发送通道*/ DMA_Cmd(DMA2_Stream7, DISABLE); /*等待DMA关闭*/ while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE); /*清除传输已经完成TCIF7、传输已经完成一半HTIF7、FIFO错误FEIF7标志位*/ DMA_ClearFlag(DMA2_Stream7, DMA_FLAG_FEIF7 | DMA_FLAG_HTIF7 | DMA_FLAG_TCIF7); /*配置发送地址和长度*/ DMA_MemoryTargetConfig(DMA2_Stream7, (uint32_t)txBuf, DMA_Memory_0); DMA_SetCurrDataCounter(DMA2_Stream7, len); /*等待串口发送完成*/ while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); /*启动 DMA 发送*/ DMA_Cmd(DMA2_Stream7, ENABLE); } /*crc16校验*/ uint16_t Crc16(const uint8_t *data, uint16_t length) { uint16_t crc; uint16_t byteInd; uint8_t bitInd; crc = 0xFFFFu; for (byteInd = 0u; byteInd < length; byteInd++) { crc ^= (uint16_t)data[byteInd]; for (bitInd = 0u; bitInd < 8u; bitInd++) { if ((crc & 0x0001u) != 0u) { crc >>= 1; crc ^= 0xA001u; } else { crc >>= 1; } } } return crc; } /*crc16检查*/ int8_t ChcekCrc16(uint16_t recCrc16, uint8_t *data, uint16_t length) { uint16_t crc16 = Crc16(data, (length - 2)); if(recCrc16 == crc16) { return 0; } else { return -1; } } void AddCrc16(uint8_t *data, uint16_t length) { uint8_t *dataT = data; uint16_t crc16 = Crc16(data, length); /*低前高后*/ dataT[length] = (uint8_t)(crc16 & 0x00FF); dataT[length + 1] = (uint8_t)(crc16 >> 8); }