Parcourir la source

实现modbus协议规范帧间隔必须在1.5~3.5字符之间判断功能

main
the_deepest il y a 2 jours
Parent
révision
c17db5359a
7 fichiers modifiés avec 1567 ajouts et 835 suppressions
  1. +14
    -3
      app/inc/hardware.h
  2. +2
    -2
      app/src/hardware.c
  3. +9
    -9
      iar/settings/F407_uCOSii_Modbus.wsdt
  4. +20
    -20
      iar/settings/uCOS_Modbus.dnx
  5. +1367
    -775
      iar/uCOS_Modbus.dep
  6. +142
    -26
      modbus/modbus_rec_send.c
  7. +13
    -0
      modbus/modbus_rec_send.h

+ 14
- 3
app/inc/hardware.h Voir le fichier

@@ -6,15 +6,26 @@
#if (MODBUS_USART_BAUDRATE > 19200U)

/*固定等待1750us,再减去IDLE中断等待的1个字符时间*/
/*1.5个字符=750us-1个字符时间*/
#define MODBUS_IDLE_TO_T15_US \
((750UL * MODBUS_USART_BAUDRATE - 10000000UL + MODBUS_USART_BAUDRATE - 1UL) / MODBUS_USART_BAUDRATE)
/*2个字符=1000us*/
#define MODBUS_T15_TO_T35_US 1000UL
/*3.5个字符=1750us-1个字符时间*/
#define MODBUS_IDLE_TO_T35_US \
((1750UL * MODBUS_USART_BAUDRATE - 10000000UL + MODBUS_USART_BAUDRATE - 1UL) / MODBUS_USART_BAUDRATE)

((1750UL * MODBUS_USART_BAUDRATE - 10000000UL + MODBUS_USART_BAUDRATE - 1UL) / MODBUS_USART_BAUDRATE)
#else

/*IDLE中断已经过了1个字符的时间,还需等待2.5个字符*/
/*1.5个字符-1个字符时间=0.5个字符时间*/
#define MODBUS_IDLE_TO_T15_US \
((5000000UL + MODBUS_USART_BAUDRATE - 1UL) / MODBUS_USART_BAUDRATE)
/*2个字符时间*/
#define MODBUS_T15_TO_T35_US \
((20000000UL + MODBUS_USART_BAUDRATE - 1UL) / MODBUS_USART_BAUDRATE)
/*3.5个字符-1个字符时间=2.5个字符时间*/
#define MODBUS_IDLE_TO_T35_US \
((25000000UL + MODBUS_USART_BAUDRATE - 1UL) / MODBUS_USART_BAUDRATE)

#endif




+ 2
- 2
app/src/hardware.c Voir le fichier

@@ -110,7 +110,7 @@ void ModbusTimInit(void)

TIM_DeInit(TIM5);
TIM_TimeBaseStructure.TIM_Prescaler = 84U - 1U; /*84Mhz/84=1Mhz,1us计时*/
TIM_TimeBaseStructure.TIM_Period = MODBUS_IDLE_TO_T35_US - 1U; /*计时周期1664us*/
TIM_TimeBaseStructure.TIM_Period = MODBUS_IDLE_TO_T15_US - 1U; /*计时周期1664us*/
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; /*向上计数*/
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
@@ -136,7 +136,7 @@ void ModbusNvicInit(void)

/*定时器中断*/
NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 4;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);


+ 9
- 9
iar/settings/F407_uCOSii_Modbus.wsdt
Fichier diff supprimé car celui-ci est trop grand
Voir le fichier


+ 20
- 20
iar/settings/uCOS_Modbus.dnx Voir le fichier

@@ -16,15 +16,15 @@
<ShowSource>1</ShowSource>
</Trace1>
<StLinkDriver>
<stlinkResetStyle>0</stlinkResetStyle>
<stlinkResetStrategy>0</stlinkResetStrategy>
<stlinkserialNo>30303031</stlinkserialNo>
<stlinkfoundProbes />
<CStepIntDis>_ 0</CStepIntDis>
<LeaveTargetRunning>_ 0</LeaveTargetRunning>
<stlinkserialNo>24230357</stlinkserialNo>
<stlinkfoundProbes />
<stlinkResetStyle>0</stlinkResetStyle>
<stlinkResetStrategy>0</stlinkResetStrategy>
</StLinkDriver>
<DebugChecksum>
<Checksum>2912698606</Checksum>
<Checksum>3570680553</Checksum>
</DebugChecksum>
<Exceptions>
<StopOnUncaught>_ 0</StopOnUncaught>
@@ -120,11 +120,26 @@
<ShowTimeSum>1</ShowTimeSum>
<SumSortOrder>0</SumSortOrder>
</EventLog>
<DisassembleMode>
<mode>0</mode>
</DisassembleMode>
<Breakpoints2>
<Bp0>_ 1 "EMUL_CODE" "{d:\IAR_Project\TrainCamp_fubowen_Modbus\modbus\modbus_parse.c}.67.13" 0 0 1 "" 0 "" 0</Bp0>
<Count>1</Count>
</Breakpoints2>
<TermIOLog>
<LoggingEnabled>_ 0</LoggingEnabled>
<LogFile>_ ""</LogFile>
</TermIOLog>
<LogFile>
<LoggingEnabled>_ 0</LoggingEnabled>
<LogFile>_ ""</LogFile>
<Category>_ 0</Category>
</LogFile>
<Aliases>
<Count>0</Count>
<SuppressDialog>0</SuppressDialog>
</Aliases>
<DriverProfiling>
<Enabled>0</Enabled>
<Mode>3</Mode>
@@ -138,19 +153,4 @@
<CallStackStripe>
<ShowTiming>1</ShowTiming>
</CallStackStripe>
<DisassembleMode>
<mode>0</mode>
</DisassembleMode>
<Breakpoints2>
<Bp0>_ 1 "EMUL_CODE" "{$PROJ_DIR$\..\modbus\modbus_parse.c}.67.13" 0 0 1 "" 0 "" 0</Bp0>
<Count>1</Count>
</Breakpoints2>
<Aliases>
<Count>0</Count>
<SuppressDialog>0</SuppressDialog>
</Aliases>
<TermIOLog>
<LoggingEnabled>_ 0</LoggingEnabled>
<LogFile>_ ""</LogFile>
</TermIOLog>
</settings>

+ 1367
- 775
iar/uCOS_Modbus.dep
Fichier diff supprimé car celui-ci est trop grand
Voir le fichier


+ 142
- 26
modbus/modbus_rec_send.c Voir le fichier

@@ -1,4 +1,7 @@
#include "modbus_rec_send.h"
#include "hardware.h"

MODBUS_RX_STATE ModbusRxState = MODBUS_RX_RECEIVING;


/*USART接收空闲中断*/
@@ -17,13 +20,36 @@ void USART1_IRQHandler(void)

/*判断是否接收到帧,触发TIM计时*/
rxLenRemain = DMA_GetCurrDataCounter(DMA2_Stream2);
if(rxLenRemain != MODBUS_RX_BUF_SIZE)
ModbusRxLen = MODBUS_RX_BUF_SIZE - rxLenRemain;

if(ModbusRxLen != 0)
{
/*启动TIM计时*/
TIM_Cmd(TIM5, DISABLE);
TIM_SetCounter(TIM5, 0); /*清除计数值*/
//TIM_ClearITPendingBit(TIM5, TIM_IT_Update); /*清除中断标志位*/
TIM_Cmd(TIM5, ENABLE);
switch (ModbusRxState)
{
/*正常接收数据*/
case MODBUS_RX_RECEIVING:
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(); /*退出中断*/
@@ -35,33 +61,123 @@ void TIM5_IRQHandler(void)
uint16_t rxLenRemain;

OSIntEnter();

rxLenRemain = DMA_GetCurrDataCounter(DMA2_Stream2);

if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)
{
/*清除TIM5更新中断标志*/
TIM_ClearITPendingBit(TIM5, TIM_IT_Update);
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;

/*关闭DMA*/
DMA_Cmd(DMA2_Stream2, DISABLE);
/*清除传输已经完成TCIF2、传输已经完成一半HTIF2标志位*/
DMA_ClearFlag(DMA2_Stream2, DMA_FLAG_TCIF2 | DMA_FLAG_HTIF2);
/*检查在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();
}

/*计算数据长度*/
rxLenRemain = DMA_GetCurrDataCounter(DMA2_Stream2);
ModbusRxLen = MODBUS_RX_BUF_SIZE - rxLenRemain;
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);
}

/*释放接收到数据帧信号量,唤醒帧解析任务*/
if(ModbusRxLen >= 4) /*4字节(1字节地址、1字节功能、2字节CRC)*/
{
OSSemPost(ModbusReceived);
}
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);

/*重新指定接收地址*/
DMA_MemoryTargetConfig(DMA2_Stream2, (uint32_t)ModbusRxBuf, DMA_Memory_0);
/*重启DMA*/
DMA_SetCurrDataCounter(DMA2_Stream2, MODBUS_RX_BUF_SIZE);
DMA_Cmd(DMA2_Stream2, ENABLE);
/*计算数据长度*/
rxLenRemain = DMA_GetCurrDataCounter(DMA2_Stream2);
ModbusRxLen = MODBUS_RX_BUF_SIZE - rxLenRemain;

/*释放接收到数据帧信号量,唤醒帧解析任务*/
if(ModbusRxLen >= 4) /*4字节(1字节地址、1字节功能、2字节CRC)*/
{
OSSemPost(ModbusReceived);
}
OSIntExit();

/*重新指定接收地址*/
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响应帧发送*/


+ 13
- 0
modbus/modbus_rec_send.h Voir le fichier

@@ -4,10 +4,23 @@
#include "stm32f4xx.h"
#include "modbus_parse.h"

typedef enum ModbusRxStateType
{
MODBUS_RX_RECEIVING = 0, /*正在正常接收*/
MODBUS_RX_CHECK_T15, /*等待第一次DMA检查,判断新字符是否在t1.5前开始*/
MODBUS_RX_CHECK_T35, /*等待第二次DMA检查,判断t1.5~t3.5是否出现字符*/
MODBUS_RX_DISCARD, /*当前帧已经确认错误,继续丢弃后续数据*/
MODBUS_RX_DISCARD_CHECK_T35 /*已收到错误帧的IDLE,等待连续t3.5静默*/
}MODBUS_RX_STATE;



int8_t ChcekCrc16(uint16_t recCrc16, uint8_t *data, uint16_t length);
void AddCrc16(uint8_t *data, uint16_t length);
void ModbusSend(uint8_t *txBuf, uint16_t len);
void TimOff(void);
void TimRestart(uint32_t timArr);
void ModbusParseWakeUp(void);
void ModbusDmaRestart(void);

#endif

Chargement…
Annuler
Enregistrer