分享一个串口的使用技巧(单字节中断后续字节处理)

串口使用的时候,无非两种办法

一种定长处理,就是发送方以给定的长度发送数据,不足部分以补零处理

一种不定长的,典型的有modbus,还有论坛中的dma不定长或者通过空闲中断处理

以上实际应用中多少都有局限性,

这里举例一种简单通用的处理办法,通过每次接收到一个字节产生中断,然后单独对每个字节进行判断处理,以达到使用的目的

struct RxStruct

{

    uint16_t index;

    uint8_t *buffer_ptr;

    uint16_t buffer_size;

};

void RxStruct_init(struct RxStruct* RxStruct, uint8_t *pool, uint16_t size)

{


    /* 初始化 头 */

    RxStruct->index = 0;


    /* 初始化缓冲区 */

    RxStruct->buffer_ptr = pool;

    RxStruct->buffer_size = size;

}


struct RxStruct RxStruct_data;

//    RxStruct_init(&RxStruct_data, ChannelDataBuff[0],64);

/* USER CODE BEGIN 4 */

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)

{

    switch(RxStruct_data.index)

    {

    case 0:

        if(aRxBuffer[0] == 0xa3)

        {

            RxStruct_data.index++;

        }

        break;

    case 1:

        if(aRxBuffer[0] == 0x50)

        {

            RxStruct_data.index++;

        }

        else

            RxStruct_data.index = 0;

        break;

    case 2:

        switch(aRxBuffer[0])

        {

        case 0x01:

            //user code

            pucRegBuffer[0] = 0x11;

            HAL_UART_Transmit(&huart1 , (uint8_t *)pucRegBuffer, 1, 0xFFFF);

            break;

        case 0x02:

            //user code

            pucRegBuffer[0] = 0x44;

            pucRegBuffer[1] = 0x55;

            HAL_UART_Transmit(&huart1 , (uint8_t *)pucRegBuffer, 2, 0xFFFF);

            break;

        case 0x03:

            //user code

            pucRegBuffer[0] = 0x77;

            pucRegBuffer[1] = 0x88;

            pucRegBuffer[2] = 0x99;

            HAL_UART_Transmit(&huart1 , (uint8_t *)pucRegBuffer, 3, 0xFFFF);

            break;

        default:

            break;

        }

        RxStruct_data.index = 0;

        break;

    default:

        break;

    }

    HAL_UART_Receive_IT(&huart1, (uint8_t*)aRxBuffer, 1);

  }

防吞代码, 下面是截图:

image.png

image.png

以上代码实现的是:

判断发送发是否发送的是:

A3 50 01或者A3 50 02或者A3 50 03

并且根据不同指令返回不同的数据

这个形式,虽然中断比较频繁,但是实际应用中大部分应用都能满足.


代码太简单不再解释了.

抛砖引玉!!

希望大家也能踊跃分享下你比较常用的办法.

已邀请:

admin

赞同来自:

还有我想问下:

modbus的断帧处理方法是超时3.5个字节时间

串口的不定长处理用空闲中断,

上面两种方式,的处理断帧时间,哪个时间更短?

有什么依据?

admin

赞同来自:

也肯定会有人说用FIFO做缓冲.

环形缓冲器,和上面我代码的方法其实是一个原理,

不过缓冲器需要放入取出操作,实时性不是很高

ZOOB - May the force be with UUUUU

赞同来自: 阿昌

很漂亮,思路对。

不用DMA这样是可以的。

不过还是建议在中断中只存储,去外面做判断。

skyhahaha

赞同来自:

亲,我采用这样的方式,可是一组6个字节的帧,会出现只能收到其中几个字节的情况

自带腹肌的西装

赞同来自:

代码很棒,我做过MODBUS的开发,一般串口只是逐个直接数据到缓冲区(用DMA更好点),每接收一个字节更新接收标志位一次,当4个字节时间过去后没有接收到数据就认为此次传输结束,然后主循环中通过接收标志位去进行数据处理。你这样直接在回调函数中处理,实时性会高很多。我的那个处理实时性不是很高,一般通讯时间46ms左右,因为我的主函数中还有数据采集需要处理。所以根据使用情况做一些取舍就行。

要回复问题请先登录注册