查看: 10796|回复: 15

RT1052——5.串口的发送与接收

[复制链接]
  • TA的每日心情
    慵懒
    2024-2-8 09:39
  • 签到天数: 217 天

    [LV.7]常住居民III

    92

    主题

    1112

    帖子

    29

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    7637

    热心会员

    最后登录
    2024-4-25
    发表于 2018-10-28 16:47:12 | 显示全部楼层 |阅读模式
    今天我们来聊一聊RT1052串口的使用方式,还是之前的程序。既然要自己配置串口,那么肯定要先和官方给的配置说再见。
    首先注释掉
    //#include "fsl_debug_console.h"
    //BOARD_InitDebugConsole();
    //PRINTF("hello world.\r\n");

    这三句。然后添加一个头文件
    #include "fsl_lpuart.h"
    说到初始化,首先想到的就应该是init了吧,先看一下fsl_lpuart.h"里面有关的定义。

    status_t LPUART_Init(LPUART_Type *base, const lpuart_config_t *config, uint32_t srcClock_Hz);

    可以看到,一共要输入三个参数,第一个是配置哪一个串口,第二个是一个lpuart_config_t*类型的量(里面是串口配置的一些信息),第三个是LPUART时钟的主频。
    先来看一下lpuart_config_t,在fsl_lpuart.h"可以找到定义

    /*! @brief LPUART configuration structure. */
    typedef struct _lpuart_config
    {
        uint32_t baudRate_Bps;            /*!< LPUART baud rate  */
        lpuart_parity_mode_t parityMode;  /*!< Parity mode, disabled (default), even, odd */
        lpuart_data_bits_t dataBitsCount; /*!< Data bits count, eight (default), seven */
        bool isMsb;                       /*!< Data bits order, LSB (default), MSB */
    #if defined(FSL_FEATURE_LPUART_HAS_STOP_BIT_CONFIG_SUPPORT) && FSL_FEATURE_LPUART_HAS_STOP_BIT_CONFIG_SUPPORT
        lpuart_stop_bit_count_t stopBitCount; /*!< Number of stop bits, 1 stop bit (default) or 2 stop bits  */
    #endif
    #if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
        uint8_t txFifoWatermark; /*!< TX FIFO watermark */
        uint8_t rxFifoWatermark; /*!< RX FIFO watermark */
    #endif
    #if defined(FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT) && FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT
        bool enableRxRTS;                         /*!< RX RTS enable */
        bool enableTxCTS;                         /*!< TX CTS enable */
        lpuart_transmit_cts_source_t txCtsSource; /*!< TX CTS source */
        lpuart_transmit_cts_config_t txCtsConfig; /*!< TX CTS configure */
    #endif
        lpuart_idle_type_select_t rxIdleType; /*!< RX IDLE type. */
        lpuart_idle_config_t rxIdleConfig;    /*!< RX IDLE configuration. */
        bool enableTx;                        /*!< Enable TX */
        bool enableRx;                        /*!< Enable RX */
    } lpuart_config_t;

    可以看到这里有很多的#if #endif (其他程序也有大量的这个)。这个设计我感觉是一个比较好的设计。这些的定义都在MIMXRT1052_features.h这个头文件里面找到,下图是部分配置

    QQ截图20181028152407.png

    可以看到,可以利用这里面的宏定义对程序进行裁剪,去掉不需要的功能(让它不参与编译)。这样就能提高程序效率(很好的设计)。

    然后模仿它去写一个配置。

        lpuart_config_t lpuart1_config;

        lpuart1_config.baudRate_Bps = 115200;
        lpuart1_config.parityMode = kLPUART_ParityDisabled;      //奇偶校验无
        lpuart1_config.dataBitsCount = kLPUART_EightDataBits;   //8位数据
        lpuart1_config.isMsb = false;                                          //LSB
    #if defined(FSL_FEATURE_LPUART_HAS_STOP_BIT_CONFIG_SUPPORT) && FSL_FEATURE_LPUART_HAS_STOP_BIT_CONFIG_SUPPORT
        lpuart1_config.stopBitCount = kLPUART_OneStopBit;       //1个停止位
    #endif
    #if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
        lpuart1_config.txFifoWatermark = 0; //TX缓存区大小
        lpuart1_config.rxFifoWatermark = 0; //RX缓存大小
    #endif
    #if defined(FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT) && FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT
        lpuart1_config.enableRxRTS = false;                               //不使用RTS
        lpuart1_config.enableTxCTS = false;                               //不使用CTS
        lpuart1_config.txCtsSource = kLPUART_CtsSourcePin;      //CTS信号的来源是CTS脚
        lpuart1_config.txCtsConfig = kLPUART_CtsSampleAtStart; //CTS输入在每个字符的起始处被采样
    #endif
        lpuart1_config.rxIdleType = kLPUART_IdleTypeStopBit;    //停止位之后开始计算多少字节之后进入空闲
        lpuart1_config.rxIdleConfig = kLPUART_IdleCharacter1;   //1个空闲字节进入空闲
        lpuart1_config.enableTx = true;                                     //使能TX
        lpuart1_config.enableRx = true;                                    //使能RX

    这样感觉有点麻烦,不过没问题,官方提供了一个简单的快速配置

    QQ截图20181028152946.png

    可以通过调用它来实现串口的快速配置

        LPUART_GetDefaultConfig(&config);
        config.enableTx = true;                        //使能TX
        config.enableRx = true;                        //使能RX
    这样也能实现配置的效果。

    然后初始化还有一个很关键的要素 LPUART时钟的主频(这里不讨论外设时钟的配置方式,外设时钟的配置方式见(飞凌RT1052——6.PIT中断与外设时钟配置https://www.nxpic.org.cn/module/foru ... 189&fromuid=3469866(出处: 恩智浦技术社区))。

    QQ截图20181028153518.png

    可以看到LPUART时钟的来源有两个 一个是OSC,一个是pll3_sw_clk的6分频,由CSCDR1[UART_CLK_SEL]位选择,然后经过CSCDR1[UART_CLK_PODF]位进行分频,这里直接给出有关寄存器的图

    QQ截图20181028160551.png

    QQ截图20181028154907.png

    上图可以看到pll3_sw_clk的来源,正是PLL3

    我们这次不讨论时钟的配置方式。直接看官方提供给我们的一个时钟获取函数
    uint32_t BOARD_DebugConsoleSrcFreq(void)
    {
        uint32_t freq;

        /* To make it simple, we assume default PLL and divider settings, and the only variable
           from application is use PLL3 source or OSC source */
        if (CLOCK_GetMux(kCLOCK_UartMux) == 0) /* PLL3 div6 80M */
        {
            freq = (CLOCK_GetPllFreq(kCLOCK_PllUsb1) / 6U) / (CLOCK_GetDiv(kCLOCK_UartDiv) + 1U);
        }
        else
        {
            freq = CLOCK_GetOscFreq() / (CLOCK_GetDiv(kCLOCK_UartDiv) + 1U);
        }

        return freq;
    }

    先看一下kCLOCK_UartMux的定义
    kCLOCK_UartMux = CCM_TUPLE(CSCDR1, CCM_CSCDR1_UART_CLK_SEL_SHIFT, CCM_CSCDR1_UART_CLK_SEL_MASK, CCM_NO_BUSY_WAIT),
    很明显是用来操作UART_CLK_SEL位了,这里CLOCK_GetMux(kCLOCK_UartMux) 函数就是为了获取UART_CLK_SEL位状态判断时钟来源

    然后是kCLOCK_PllUsb1
    kCLOCK_PllUsb1 = CCM_ANALOG_TUPLE(PLL_USB1,  CCM_ANALOG_PLL_USB1_ENABLE_SHIFT),

    这里如果按之前分析的话,应该是获取PLL3的主频的,可这PLL_USB1是个啥

    QQ截图20181028154817.png

    不过可以在参考手册中找到,确实是PLL3的别称。CLOCK_GetPllFreq(kCLOCK_PllUsb1) 就是为了获取pll3_sw_clk的频率。

    CLOCK_GetOscFreq() 是为了得到OSC频率(不得不说这名起的很好理解)

    最后是kCLOCK_UartDiv
    kCLOCK_UartDiv = CCM_TUPLE(CSCDR1, CCM_CSCDR1_UART_CLK_PODF_SHIFT, CCM_CSCDR1_UART_CLK_PODF_MASK, CCM_NO_BUSY_WAIT),


    很明显CLOCK_GetDiv(kCLOCK_UartDiv) 可以获取UART_CLK_PODF的取值。


    freq = (CLOCK_GetPllFreq(kCLOCK_PllUsb1) / 6U) / (CLOCK_GetDiv(kCLOCK_UartDiv) + 1U);
    freq = CLOCK_GetOscFreq() / (CLOCK_GetDiv(kCLOCK_UartDiv) + 1U);

    正是一开始观察时钟图可以的到的式子(分频可参考参考手册)

    最终就可以用
    LPUART_Init(LPUART1, &lpuart1_config, BOARD_DebugConsoleSrcFreq());  //初始化串口1

    配置完串口,接下来是处理串口接收中断,下面给出配置

    LPUART_EnableInterrupts(LPUART1, kLPUART_RxDataRegFullInterruptEnable); //设置串口1接收到数据满了触发中断
    EnableIRQ(LPUART1_IRQn);//使能串口1中断


    EnableIRQ(LPUART1_IRQn)没啥好说的,就是使能中断
    然后LPUART_EnableInterrupts有两个参数,第一个是选择串口几,第二个就是选择中断触发源

    enum _lpuart_interrupt_enable
    {
    #if defined(FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT) && FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT
        kLPUART_LinBreakInterruptEnable = (LPUART_BAUD_LBKDIE_MASK >> 8), /*!< LIN break detect. */
    #endif
        kLPUART_RxActiveEdgeInterruptEnable = (LPUART_BAUD_RXEDGIE_MASK >> 8), /*!< Receive Active Edge. */
        kLPUART_TxDataRegEmptyInterruptEnable = (LPUART_CTRL_TIE_MASK),        /*!< Transmit data register empty. */
        kLPUART_TransmissionCompleteInterruptEnable = (LPUART_CTRL_TCIE_MASK), /*!< Transmission complete. */
        kLPUART_RxDataRegFullInterruptEnable = (LPUART_CTRL_RIE_MASK),         /*!< Receiver data register full. */
        kLPUART_IdleLineInterruptEnable = (LPUART_CTRL_ILIE_MASK),             /*!< Idle line. */
        kLPUART_RxOverrunInterruptEnable = (LPUART_CTRL_ORIE_MASK),            /*!< Receiver Overrun. */
        kLPUART_NoiseErrorInterruptEnable = (LPUART_CTRL_NEIE_MASK),           /*!< Noise error flag. */
        kLPUART_FramingErrorInterruptEnable = (LPUART_CTRL_FEIE_MASK),         /*!< Framing error flag. */
        kLPUART_ParityErrorInterruptEnable = (LPUART_CTRL_PEIE_MASK),          /*!< Parity error flag. */
    #if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
        kLPUART_TxFifoOverflowInterruptEnable = (LPUART_FIFO_TXOFE_MASK >> 8),  /*!< Transmit FIFO Overflow. */
        kLPUART_RxFifoUnderflowInterruptEnable = (LPUART_FIFO_RXUFE_MASK >> 8), /*!< Receive FIFO Underflow. */
    #endif
    };


    官方又给了一大堆触发方式,这里选择kLPUART_RxDataRegFullInterruptEnable,就是接收到数据满了触发中断(这里可以根据自己实际需要来配置)而这个满了的概念就是看接收的数据的数量是否大于接收缓存(这里设置为0)

    下面是中断回调函数

    void LPUART1_IRQHandler(void)
    {
        uint8_t data;
        if ((kLPUART_RxDataRegFullFlag) & LPUART_GetStatusFlags(LPUART1)) //判断是不是接收到数据触发中断
        {
            data = LPUART_ReadByte(LPUART1);//读取数据接收区字符
            LPUART_WriteByte(LPUART1, data);//向发送区写入一个字符
        }        
        __DSB();
    }


    RT1052的串口中断有真么多的触发方式,那么我们就要先判断是不是我们需要的触发方式,利用(kLPUART_RxDataRegFullFlag) & LPUART_GetStatusFlags(LPUART1)就可以判断中断触发方式。至于为啥没清中断标志位,这里可以看

    QQ截图20181028163701.png

    只要读取了LPUART_DATA 就可以清空标志位,这里面放的正是接收到的数据。
    这里使用LPUART_ReadByte和LPUART_WriteByte构成一个回显函数。

    最后主程序还有一句

    LPUART_WriteBlocking(LPUART1, "你好世界\n",sizeof("你好世界\n"));//阻塞方式发送一串字符

    三个变量,发送的串口号,发送字符的地址,发送字符的数量,这里sizeof本是获取所占字节数的,但char类型正好就是1个字节,所以直接这样用了。

    实验效果,打印  你好世界  之后回显

    QQ截图20181028164304.png

    话说配置时有时遇到一个小bug,就是有时候下完程序一部分不能正常运行,要手动按下复位键才可以(猜想和软复位有关,有时间再讨论)

    最后附上程序
      MDK版本:5.24
      pack:NXP.MIMXRT1052_DFP.10.0.1.pack
      下载算法:飞凌嵌入式提供的 MIMXRT_QSPIFLASH.FLM
      启动方式:spi flash启动  
      下载方式:STlink
    3.uart.zip (1.46 MB, 下载次数: 123)
    该会员没有填写今日想说内容.
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2024-3-26 15:16
  • 签到天数: 266 天

    [LV.8]以坛为家I

    3299

    主题

    6546

    帖子

    0

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    32024
    最后登录
    2024-4-25
    发表于 2018-10-29 16:02:28 | 显示全部楼层
    谢谢分享
    签到签到
    回复

    使用道具 举报

  • TA的每日心情

    2021-2-4 09:24
  • 签到天数: 190 天

    [LV.7]常住居民III

    38

    主题

    591

    帖子

    28

    金牌会员

    Rank: 6Rank: 6

    积分
    2193
    最后登录
    2023-12-1
    发表于 2018-10-29 16:30:35 | 显示全部楼层
    谢谢分享
    哎...今天够累的,签到来了~
    回复

    使用道具 举报

  • TA的每日心情
    擦汗
    2018-12-16 09:52
  • 签到天数: 1 天

    [LV.1]初来乍到

    1

    主题

    7

    帖子

    0

    新手上路

    Rank: 1

    积分
    38
    最后登录
    2019-1-20
    发表于 2018-12-16 09:19:27 | 显示全部楼层
    楼主你好,请问有没有看过串口的FIFO通讯方式,我一直没找到RT1052的FIFO长度设置,他的寄存器是只读的,还有 FifoWatermark好像只能设置为0,1,2,3这四种,最大就是接收3字节触发一次中断?
    how to set rt1052 LPUART fifo depth????
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    慵懒
    2024-2-8 09:39
  • 签到天数: 217 天

    [LV.7]常住居民III

    92

    主题

    1112

    帖子

    29

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    7637

    热心会员

    最后登录
    2024-4-25
     楼主| 发表于 2018-12-17 19:19:48 | 显示全部楼层
    lk1277185193 发表于 2018-12-16 09:19
    楼主你好,请问有没有看过串口的FIFO通讯方式,我一直没找到RT1052的FIFO长度设置,他的寄存器是只读的,还 ...

    emmmmmm,我简单看了一下,发现你寄存器看错了,应该是 WATER 这个,你先试试,有问题再说
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    2018-12-16 09:52
  • 签到天数: 1 天

    [LV.1]初来乍到

    1

    主题

    7

    帖子

    0

    新手上路

    Rank: 1

    积分
    38
    最后登录
    2019-1-20
    发表于 2018-12-18 08:31:25 | 显示全部楼层
    您看啊,water寄存器有四个标志,其中两个是 RxWatermark  和 TxWatermark  这两个试过了  可以设置为0,1,2,3位  触发,然后FIFO的长度还是没变
    how to set rt1052 LPUART fifo depth????
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    0

    主题

    2

    帖子

    0

    新手上路

    Rank: 1

    积分
    11
    最后登录
    2019-1-10
    发表于 2019-1-9 10:15:48 | 显示全部楼层
    az158 发表于 2018-12-17 19:19
    emmmmmm,我简单看了一下,发现你寄存器看错了,应该是 WATER 这个,你先试试,有问题再说 ...

    楼主您好,我也遇到四楼提到的这个问题,就串口接收来说,WaterMark寄存器的作用是相当于水线的作用,当FIFO缓存大于watermark设置的字节,FIFO中的数据会移到DATA中。但是FIFO的size大小,从参考手册来看,两个寄存器是相关的,PARAM寄存器和FIFO寄存器的FIFOSize位,但是这两个寄存器全是只读寄存器。不知道楼主能不能帮忙看下,谢谢!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    慵懒
    2024-2-8 09:39
  • 签到天数: 217 天

    [LV.7]常住居民III

    92

    主题

    1112

    帖子

    29

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    7637

    热心会员

    最后登录
    2024-4-25
     楼主| 发表于 2019-1-9 21:55:09 | 显示全部楼层
    本帖最后由 az158 于 2019-1-9 21:56 编辑

    我研究了一下,不知道我说的对不对,首先size是不能设置的,固定为4。至少我没有找到可以修改的地方。然后对于RT1052的串口FIFO接收比较特殊,dma没看,有遗漏希望补充
    QQ截图20190109215348.png
    这里说的中断我根本没找到
    只找到了这个
    QQ截图20190109214452.png
    这里讲 从接收缓冲区读取的数据多于当前数据 时,触发置位。一开始我有点不太懂。然后实验了一下。发现这个标志位的触发方式是,你去读缓存,当读不到缓存的时候触发这个标志位。也就是下溢中断

    不过TX倒是溢出中断


    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    慵懒
    2024-4-9 17:01
  • 签到天数: 1478 天

    [LV.10]以坛为家III

    203

    主题

    2万

    帖子

    64

    超级版主

    Rank: 8Rank: 8

    积分
    92619
    最后登录
    2024-4-24
    发表于 2019-1-10 08:23:53 | 显示全部楼层
    感谢分享,支持一下
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

  • TA的每日心情

    2019-10-30 16:37
  • 签到天数: 1 天

    [LV.1]初来乍到

    0

    主题

    2

    帖子

    0

    新手上路

    Rank: 1

    积分
    15
    最后登录
    2019-10-30
    发表于 2019-10-29 21:35:20 | 显示全部楼层
    你好 ,我下载了你的程序  可是怎么不能实现在串口助手输入数据  并发送
    今日份不开心
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2024-4-25 21:17 , Processed in 0.146162 second(s), 29 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表