精品国产一区在线_av无码中文字幕无码王_天海翼三点刺激高潮不停_好硬好大好爽视频_欧美高清一区三区在线专区_香蕉黄色片

程序小白
認證:優質創作者
所在專題目錄 查看專題
單片機應用與驅動開發之路:這時的你只需要扣動扳機。
RT-Thread驅動之路:stm32設備驅動開發之uart注冊①
RT-Thread驅動之路:stm32設備驅動開發之uart設備創建②
RT-Thread驅動之路:stm32設備驅動開發之uart操作方法③
RT-Thread驅動之路:stm32設備驅動開發之uart中斷處理④
RT-Thread驅動之路:stm32設備驅動開發之淺析注冊機制⑤
作者動態 更多
基于stm32采用PWM驅動伺服控制器學習筆記
05-13 15:25
基于STM32驅動TM1638學習筆記——軟件篇
04-19 12:42
基于TM1638驅動8位數碼管設計分享
02-24 11:26
RT-Thread驅動之路: Studio創建FAL分區⑤
01-02 08:30
RT-Thread驅動之路: Studio 掛載通用SPI flash④
2024-12-23 13:41

RT-Thread驅動之路:stm32設備驅動開發之uart操作方法③


      接上篇有了uart設備對象及rt_uart_ops結構體以后,我們就需要提供對應的真實的能操控硬件的函數,其實真正操作的硬件的函數并不多,創建的結構體對象如下:

static const struct rt_uart_ops stm32_uart_ops =
{
    .configure = stm32_configure,
    .control = stm32_control,
    .putc = stm32_putc,
    .getc = stm32_getc,
    .dma_transmit = stm32_dma_transmit
};

      先來看下基于hal庫代碼實現的stm32_configure的完整代碼,當你需要更換其它單片機時,再系統沒有提供對應的bsp的情況下,你可以仿照代碼進行重構該函數用于適用于特殊的硬件,系統也提供了很多種不同的芯片的bsp:

static rt_err_t stm32_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
{
    struct stm32_uart *uart;
    RT_ASSERT(serial != RT_NULL);
    RT_ASSERT(cfg != RT_NULL);

    uart = rt_container_of(serial, struct stm32_uart, serial);

    uart->handle.Instance          = uart->config->Instance;
    uart->handle.Init.BaudRate     = cfg->baud_rate;
    uart->handle.Init.HwFlowCtl    = UART_HWCONTROL_NONE;
    uart->handle.Init.Mode         = UART_MODE_TX_RX;
    uart->handle.Init.OverSampling = UART_OVERSAMPLING_16;
    switch (cfg->data_bits)
    {
    case DATA_BITS_8:
        uart->handle.Init.WordLength = UART_WORDLENGTH_8B;
        break;
    case DATA_BITS_9:
        uart->handle.Init.WordLength = UART_WORDLENGTH_9B;
        break;
    default:
        uart->handle.Init.WordLength = UART_WORDLENGTH_8B;
        break;
    }
    switch (cfg->stop_bits)
    {
    case STOP_BITS_1:
        uart->handle.Init.StopBits   = UART_STOPBITS_1;
        break;
    case STOP_BITS_2:
        uart->handle.Init.StopBits   = UART_STOPBITS_2;
        break;
    default:
        uart->handle.Init.StopBits   = UART_STOPBITS_1;
        break;
    }
    switch (cfg->parity)
    {
    case PARITY_NONE:
        uart->handle.Init.Parity     = UART_PARITY_NONE;
        break;
    case PARITY_ODD:
        uart->handle.Init.Parity     = UART_PARITY_ODD;
        break;
    case PARITY_EVEN:
        uart->handle.Init.Parity     = UART_PARITY_EVEN;
        break;
    default:
        uart->handle.Init.Parity     = UART_PARITY_NONE;
        break;
    }

#ifdef RT_SERIAL_USING_DMA
    uart->dma_rx.last_index = 0;
#endif

    if (HAL_UART_Init(&uart->handle) != HAL_OK)
    {
        return -RT_ERROR;
    }

    return RT_EOK;
}

      代碼很長,但是功能很簡單就是對串口進行初始化,設置串口波特率,硬件流控,串口模式、串口采樣、數據位、停止位、DMA相關參數、最后調用HAL_UART_Init()完成串口的初始化功能。


      接下來看下stm32_control函數的代碼,代碼雖長單功能并不復雜:

static rt_err_t stm32_control(struct rt_serial_device *serial, int cmd, void *arg)
{
    struct stm32_uart *uart;
#ifdef RT_SERIAL_USING_DMA
    rt_ubase_t ctrl_arg = (rt_ubase_t)arg;
#endif

    RT_ASSERT(serial != RT_NULL);
    uart = rt_container_of(serial, struct stm32_uart, serial);

    switch (cmd)
    {
    /* disable interrupt */
    case RT_DEVICE_CTRL_CLR_INT:
        /* disable rx irq */
        NVIC_DisableIRQ(uart->config->irq_type);
        /* disable interrupt */
        __HAL_UART_DISABLE_IT(&(uart->handle), UART_IT_RXNE);

#ifdef RT_SERIAL_USING_DMA
        /* disable DMA */
        if (ctrl_arg == RT_DEVICE_FLAG_DMA_RX)
        {
            HAL_NVIC_DisableIRQ(uart->config->dma_rx->dma_irq);
            if (HAL_DMA_Abort(&(uart->dma_rx.handle)) != HAL_OK)
            {
                RT_ASSERT(0);
            }

            if (HAL_DMA_DeInit(&(uart->dma_rx.handle)) != HAL_OK)
            {
                RT_ASSERT(0);
            }
        }
        else if(ctrl_arg == RT_DEVICE_FLAG_DMA_TX)
        {
            HAL_NVIC_DisableIRQ(uart->config->dma_tx->dma_irq);
            if (HAL_DMA_DeInit(&(uart->dma_tx.handle)) != HAL_OK)
            {
                RT_ASSERT(0);
            }
        }
#endif
        break;
    /* enable interrupt */
    case RT_DEVICE_CTRL_SET_INT:
        /* enable rx irq */
        HAL_NVIC_SetPriority(uart->config->irq_type, 1, 0);
        HAL_NVIC_EnableIRQ(uart->config->irq_type);
        /* enable interrupt */
        __HAL_UART_ENABLE_IT(&(uart->handle), UART_IT_RXNE);
        break;

#ifdef RT_SERIAL_USING_DMA
    case RT_DEVICE_CTRL_CONFIG:
        stm32_dma_config(serial, ctrl_arg);
        break;
#endif

    case RT_DEVICE_CTRL_CLOSE:
        if (HAL_UART_DeInit(&(uart->handle)) != HAL_OK )
        {
            RT_ASSERT(0)
        }
        break;

    }
    return RT_EOK;
}

      主要看一下幾個控制參數:RT_DEVICE_CTRL_CLR_INT關閉中斷,如果有使用dma則關閉DMA。RT_DEVICE_CTRL_SET_INT:開啟終端,如果有使用dma則采用dma_config功能打開dma。RT_DEVICE_CTRL_CLOSE:關閉串口,就這幾個功能。


      發送函數功能最簡單,輕松TC中斷標記,將數據放入DR數據寄存器中,while循環等待TC中斷觸發(DR數據寄存器為空):

static int stm32_putc(struct rt_serial_device *serial, char c)
{
    struct stm32_uart *uart;
    RT_ASSERT(serial != RT_NULL);

    uart = rt_container_of(serial, struct stm32_uart, serial);
    UART_INSTANCE_CLEAR_FUNCTION(&(uart->handle), UART_FLAG_TC);
#if defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32F0) \
    || defined(SOC_SERIES_STM32L0) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32H7) \
    || defined(SOC_SERIES_STM32G4)
    uart->handle.Instance->TDR = c;
#else
    uart->handle.Instance->DR = c;
#endif
    while (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_TC) == RESET);
    return 1;
}

      接下來是讀取數據,這里有個有意思的現象,看過源碼你會發現讀取數據和寫入數據訪問的實際的硬件寄存器都是一樣的,DR or RDR,那么你會不會有個疑問,那么某一刻讀取的數據會不會是剛寫入的數據,代碼之后揭曉:

static int stm32_getc(struct rt_serial_device *serial)
{
    int ch;
    struct stm32_uart *uart;
    RT_ASSERT(serial != RT_NULL);
    uart = rt_container_of(serial, struct stm32_uart, serial);

    ch = -1;
    if (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_RXNE) != RESET)
    {
#if defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32F0) \
    || defined(SOC_SERIES_STM32L0) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32H7) \
    || defined(SOC_SERIES_STM32G4)
        ch = uart->handle.Instance->RDR & 0xff;
#else
        ch = uart->handle.Instance->DR & 0xff;
#endif
    }
    return ch;
}

      揭曉答案啦:這里以DR為例,其實它是一對神奇的雙胞胎,一個名字對應著兩個真實的寄存器,當你寫入數據時實際寫入的是發送DR,當你讀取數據時實際訪問的是接收DR,是通過你對硬件的讀or寫操作,硬件自行對應的,當年在這個問題上耗死了好些的腦細胞,也不知道是哪個天才設計的機制。


      最后到了還有連續傳送字節(發送)的實現,借助的硬件的DMA技術實現的:

static rt_size_t stm32_dma_transmit(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, int direction)
{
    struct stm32_uart *uart;
    RT_ASSERT(serial != RT_NULL);
    RT_ASSERT(buf != RT_NULL);
    uart = rt_container_of(serial, struct stm32_uart, serial);

    if (size == 0)
    {
        return 0;
    }

    if (RT_SERIAL_DMA_TX == direction)
    {
        if (HAL_UART_Transmit_DMA(&uart->handle, buf, size) == HAL_OK)
        {
            return size;
        }
        else
        {
            return 0;
        }
    }
    return 0;
}

      帶著問題結束本篇吧,發送很簡單 一個接一個的發送出去,那么接收呢,DR中有沒有數據,是不是需要頻繁的觸發讀取函數,或者讀不及時會不會被下一個來的數據將DR中的數據覆蓋,或者數據直接被丟掉呢?

聲明:本內容為作者獨立觀點,不代表電子星球立場。未經允許不得轉載。授權事宜與稿件投訴,請聯系:editor@netbroad.com
覺得內容不錯的朋友,別忘了一鍵三連哦!
贊 3
收藏 4
關注 153
成為作者 賺取收益
全部留言
0/200
成為第一個和作者交流的人吧
主站蜘蛛池模板: VIDEOSGRAIS欧美另类 | 成年美女黄的视频网站 | 国产免费AV片在线播放唯爱网 | 人人草人人舔 | 香港aa三级久久三级 | 男人边吃奶摸下激烈免费视频 | 欧美三区在线观看 | 国产精品亚洲一区二区三区在线 | 一级片一级片一级片一级片 | 性色AV无码中文AV有码VR | free性黑人娇小vⅰαeos | 女人pissingpiss下部 | 欧美XXXX做受欧美69 | 91老司机精品视频 | 欧美在线一区二区三区四区 | 成人试看120秒体验区视频 | 四川丰满少妇A级毛片 | 国产AV旡码专区亚洲AV | 日本人真人姓交大视频 | 日韩一级网站 | 欧美一区激情视频在线观看 | 国产一区二区三区四区精 | 国产无遮挡免费真人视频在线观看 | 日本精品久久久久久草草 | 狠狠色综合久久久久尤物 | 国产美女视频观看 | 欧美人与按摩师xxxx | 国产精品二区一区二区aⅴ 87kp成人网 免费观看一级视频 | 女教师在办公室被强在线播放 | 精品一区二区三区香蕉蜜桃 | av中文天堂网 | 亚洲午夜精品无码专区在线观看 | 精品欧美一区二区在线观看 | 91人成亚洲高清在线观看 | 黄免费视频 | 成人爽a毛片免费啪啪 | 91视频网入口 | baoyu118在线视频观看 | 国产精品嫩草影院永久一 | 久草热播| 无码人妻aⅴ一区二区三区鲁大师 |