嵌入式技术论坛
直播中

贾埃罗

7年用户 1605经验值
私信 关注
[经验]

使用单片机GD32F303RET6中断串口接收部分代码解析

该部分不写初始化部分,直接从接收到代码后开始分析。

使用单片机GD32F303RET6,同时使用该单片机的库进行分析。

要解决的疑问:

Q1:在接收数据接收一半的时候,应用代码读取数据会怎么样?

在读取的时候,会导致前面一半的数据被读取出来,但是后面的数据会继续接收,在下一次读取数据的时候读取出来。

//代码接收,在isr代码中进行数据处理,同时进入中断标记。

void USART0_IRQHandler(void)

{

/* enter interrupt */

rt_interrupt_enter();

uart_isr(&serial0);

/* leave interrupt */

rt_interrupt_leave();

}

static void uart_isr(struct rt_serial_device *serial)

{

//user_data代码中保存的是设备的结构体的指针

struct gd32_uart *uart = (struct gd32_uart *) serial->parent.user_data;

RT_ASSERT(uart != RT_NULL);

/* UART in mode Receiver */

if ((usart_interrupt_flag_get(uart->uart_periph, USART_INT_FLAG_RBNE) != RESET) &&

        (usart_flag_get(uart->uart_periph, USART_FLAG_RBNE) != RESET))

{

//在该部分代码里面进行了数据的读取

rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);

    /* Clear RXNE interrupt flag */

    usart_flag_clear(uart->uart_periph, USART_FLAG_RBNE);

}

}

在void rt_hw_serial_isr(struct rt_serial_device *serial, int event)函数里面通过 ch = serial->ops->getc(serial);获取接收到的数据。getc在初始化的时候,初始为了下面的这个函数。

static int gd32_getc(struct rt_serial_device *serial)

{

int ch;

struct gd32_uart *uart;

RT_ASSERT(serial != RT_NULL);

uart = (struct gd32_uart *)serial->parent.user_data;

ch = -1;

if (usart_flag_get(uart->uart_periph, USART_FLAG_RBNE) != RESET)

//获取数据

ch = usart_data_receive(uart->uart_periph);

return ch;

}

在进行初始化的时候,通过下面结构体将该函数初始化到结构指针里面。

static const struct rt_uart_ops gd32_uart_ops =

{

gd32_configure,

gd32_control,

gd32_putc,

gd32_getc

};

uarts[i].serial->ops = &gd32_uart_ops;

在void rt_hw_serial_isr(struct rt_serial_device *serial, int event)函数里面,通过下面代码将接收到的数据写入串口接收缓冲区。

/* disable interrupt */

//关闭全局中断

level = rt_hw_interrupt_disable();

            rx_fifo->buffer[rx_fifo->put_index] = ch;

            rx_fifo->put_index += 1;

            if (rx_fifo->put_index >= serial->config.bufsz) rx_fifo->put_index = 0;

            /* if the next position is read index, discard this 'read char' */

            if (rx_fifo->put_index == rx_fifo->get_index)

            {

                rx_fifo->get_index += 1;

                rx_fifo->is_full = RT_TRUE;

                if (rx_fifo->get_index >= serial->config.bufsz) rx_fifo->get_index = 0;

                _serial_check_buffer_size();

            }

            /* enable interrupt */

//开启全局中断

rt_hw_interrupt_enable(level);

在上面的那个函数中,下面的这段代码实现了,回调函数。serial->parent.rx_indicate这个是回调函数的指针。

/* invoke callback */

if (serial->parent.rx_indicate != RT_NULL)

        {

            rt_size_t rx_length;

            /* get rx length */

            level = rt_hw_interrupt_disable();

//在这里,使用了环形缓冲区,通过判断写入指针和读出指针的位置,判断使用哪种方法计算接收数据的大小

rx_length = (rx_fifo->put_index >= rx_fifo->get_index)? (rx_fifo->put_index - rx_fifo->get_index):

                (serial->config.bufsz - (rx_fifo->get_index - rx_fifo->put_index));

            rt_hw_interrupt_enable(level);

            if (rx_length)

            {

//在这里进行了函数的回调

serial->parent.rx_indicate(&serial->parent, rx_length);

            }

        }

原作者:于周斐

更多回帖

发帖
×
20
完善资料,
赚取积分