04.TMS570LC43入门指南——串口操作

04.TMS570LC43入门指南——串口操作

一、简介

通过上节的学习,我们使用按键进行操作控制LED亮灭。这节我们将使用MCU中最重要的外设 串口

由于从这里开始,需要的寄存器就开始变多了,我并不能一一介绍,望谅解,另外 HALCoGen 生成的串口方面的代码也较为完整,故大家可以不用重复造轮子了。

通过这篇文章你将学习到以下内容:

  1. TMS570LC43 串口的了解认识
  2. TMS570LC43 的串口(SCI)的使用(基础收发以及 printf 的使用)

开发平台:

  • Windows x64
  • TMS570LC43开发板

二、项目实现

在本小节开始之前,大家需要在 CCSHALCoGen 中新建工程文件,具体操作可以参考我前面的文章,链接如下:

02.TMS570LC43入门指南——点亮LED_tms570lc43xx-CSDN博客

其中也详细描述了如何建立工程,欢迎各位大佬阅读。

关于串口方面要介绍一点知识,在 TMS570LC43 平台上,串口并不是我们所熟知的 UART,而是 SCI/LIN

UARTSCI
介绍UART(Universal Asynchronous Receiver / Transmitter)是一种可以在两台设备之间进行异步数据传输的硬件接口。它是一种多用途的技术,可以用于在计算机、控制器和其他设备之间传输数据。UART可以支持单向和双向的数据传输,允许两台设备之间的无线数据传输。SCI(Serial Communication Interface)是一种可以在两台设备之间进行 高速数据传输的硬件接口。它是一种多用途的技术,可以用于在计算机、控制器和其他设备之间传输数据。SCI可以支持单向和双向的数据传输,允许两台设备之间的无线数据传输。
优点它可以在没有任何外部时钟信号的情况下运行,只需要两台设备之间共享一个时钟即可。此外,UART还具有低成本、低功耗和灵活性等优点它可以实现高速数据传输,其传输速率可达4Mbps。此外,SCI还具有低成本、低功耗和灵活性等优点
缺点它只能传输低速数据。它的传输速率最高可达115200位/秒,而SCI可以传输高达4Mbps的数据。此外,UART还受到距离限制,其最大传输距离不能超过15米。它需要一个外部时钟信号才能正常工作,这会增加系统的成本和复杂性。此外,SCI还受到距离限制,其最大传输距离不能超过50米。

以上内容来自于 UART和SCI:深入了解它们的区别 - 技象科技 (techphant.cn)

通过对上表的理解,我们可以知道,SCIUART 更有优势,其数据传输速度更快,更稳定。而 LIN 接口专业来讲是 局域互联网络(Local Interconnect Network),常用在汽车工业中,而 LIN 仅用于低速网络,如门控制单元等,我们一般都会选用 CAN 总线去代替,因为 CAN 总线在可靠性与传输速度上均优于 LIN

我们在这章中主要介绍SCI的相关操作。

2.1 硬件部分

在本节内容中,将使用板载的串口进行实验。

如没有原理图可点击: TMS570LC43x and RM57Lx LaunchPad Schematic(源自官网可放心跳转)。

可以在芯片侧看到如下所示的引脚:

在这里插入图片描述

注意: 我们使用的是 SCI1,它与 LIN1 是同一个引脚不同功能而已。

跟随查找,我们可以在 XDS110 上找到对应的引脚(当然该开发板也引出了 SCI1),如下所示:

在这里插入图片描述

这里补充说一句话,XDS110 是板载的下载芯片,它同时继承了串口功能。

最终通过 XDS110 的引脚输出到USB接口上,如下所示:

在这里插入图片描述

其在板子上的位置如下所示:

在这里插入图片描述

本文采用图中 ① 所示的USB接口进行实验。通过将USB插入电脑后,大家可以查看电脑设备管理器(步骤不再赘述,不会的朋友可以自行百度),找到串口对应的 COM 接口,如下所示:

在这里插入图片描述

其中我图中对应的 COM22UART 接口,可以通过其设备名字看出,而 COM21 为下载烧录端口。

2.2 软件部分

2.2.1 HALCoGen 配置

生成完工程之后依旧先取消勾选 Driver Enable 中的 Mark/Unmak all drivers,然后按照如下步骤进行:

  1. 勾选 Enbale SCI1 driver

    在这里插入图片描述

  2. SCI1 -> SCI Data Format 菜单中按照所需设置(我这里设置的经典参数:115200 8bits数据位 1bit停止位 无奇偶校验):

    在这里插入图片描述

  3. 配置完上述功能后,即可生成程序。依旧使用快捷键 F5 或依次点击 File -> Generate Code

2.2.2 CCS 代码编写

按照上述步骤后,生成文件,依旧在 CCS 中进行编写逻辑代码的操作。还是先找到我们的 HL_sys_main.c 文件。这里有两部分内容,分为直接使用函数进行输出使用 printf 函数进行输出

2.2.2.1 使用函数输出

这里给出示例代码:

/* USER CODE BEGIN (0) */
/* USER CODE END */

/* Include Files */

#include "HL_sys_common.h"

/* USER CODE BEGIN (1) */
#include "HL_system.h"
#include "HL_sci.h"

#include <stdio.h>
#include <string.h>
/* USER CODE END */

/** @fn void main(void)
*   @brief Application main function
*   @note This function is empty by default.
*
*   This function is called after startup.
*   The user can use this function to implement the application.
*/

/* USER CODE BEGIN (2) */
#define SCI_REG         sciREG1                         // 定义 sci 端口寄存器

#define CNT             5000000

void sci_Printf(char *format, ...);
/* USER CODE END */

int main(void)
{
/* USER CODE BEGIN (3) */
    int i;
    int count = 0;

    sciInit();

    while(1)
    {
        count++;                                                // 计数
        sci_Printf("Hello world! count = %d\r\n", count);       // 使用自定义 printf 函数输出
        for (i = 0; i < CNT; i++);                              // 粗略延时
    }
/* USER CODE END */

    return 0;
}


/* USER CODE BEGIN (4) */
/*
 * @brief       : 自定义SCI printf 函数
 * @param       : 字符串,可实现类似于 printf 的参数输入
 * @return      : void
 * @author      : Liu Jiahao
 * @date        : 2024-03-26
 * @version     : v1.1
 * @copyright   : Copyright By Liu Jiahao, All Rights Reserved
 */
void sci_Printf(char *format, ...)
{
    uint16 i;
    va_list listdata;
    uint8 sci_TxBuff[100];

    va_start(listdata, format);
    vsprintf((char *)sci_TxBuff, format, listdata);
    va_end(listdata);

    for (i = 0; i < strlen((const char*)sci_TxBuff); i++) {
        while ((SCI_REG->FLR & 0x04U) == 4U);
        sciSendByte(SCI_REG, sci_TxBuff[i]);
    }
}
/* USER CODE END */

上述代码并不是使用自带的 printf 函数,而是使用我们自定义的 sci_Printf() 函数,其实现原理可以参考C语言的 printf 实现。大家可以借鉴一下这种写法。

题外话:会使你代码执行更有效率吗?并不,只会更让别人看不懂,显得高级!!!哈哈哈!!!

言归正传,可以在主函数中看到,我调用该函数依旧可以使用类似于 printf 函数的传参形式,这相比于死板的写固定参数更加灵活,当然了,只要是 printf 中能用的参数,这里也可以使用

而通过串口助手,配置我们之前设置的波特率等参数,下载烧录代码运行后即可看到:

在这里插入图片描述

2.2.2.2 使用自带的 pritnf 函数输出

为了方便,这里我就不再重建工程了,仍然使用上面的工程进行修改,首先我们需要一些配置操作:

  1. 依次在项目工程右键后点击 Properties -> Build -> Arm Compiler -> Advanced Options -> Language Options,然后设置 level of printf/scanf ......minimal,如下所示:

    在这里插入图片描述

    在这里插入图片描述

  2. 依旧是刚才的页面,点击 Debug 后使能 CIO,如下所示:

    在这里插入图片描述

  3. 依次点击 Build -> Arm Linker -> Basic Options 增加 heap 空间,保证其大于 320bytes,如下所示:

    在这里插入图片描述

然后点击 Apply and Close 即可配置完成,接下来我给出示例代码:

/* USER CODE BEGIN (0) */
/* USER CODE END */

/* Include Files */

#include "HL_sys_common.h"

/* USER CODE BEGIN (1) */
#include "HL_system.h"
#include "HL_sci.h"

#include <stdio.h>
#include <string.h>
/* USER CODE END */

/** @fn void main(void)
*   @brief Application main function
*   @note This function is empty by default.
*
*   This function is called after startup.
*   The user can use this function to implement the application.
*/

/* USER CODE BEGIN (2) */
#define SCI_REG         sciREG1                         // 定义 sci 端口寄存器

// sci 模式参数,为 0 则为不采用 printf 形式, 为 1 则采用 printf 形式
#define SCI_MODE        1

#define CNT             5000000

#if (!SCI_MODE)
void sci_Printf(char *format, ...);
#endif
/* USER CODE END */

int main(void)
{
/* USER CODE BEGIN (3) */
    int i;
    int count = 0;

    sciInit();

    while(1)
    {
        count++;                                                // 计数
#if (!SCI_MODE)
        sci_Printf("Hello world! count = %d\r\n", count);       // 使用自定义 printf 函数输出
#else
        printf("Hello world! count = %d\r\n", count);           // 使用 printf 函数输出
#endif
        for (i = 0; i < CNT; i++);                              // 粗略延时
    }
/* USER CODE END */

    return 0;
}


/* USER CODE BEGIN (4) */
#if (!SCI_MODE)
/*
 * @brief       : 自定义SCI printf 函数
 * @param       : 字符串,可实现类似于 printf 的参数输入
 * @return      : void
 * @author      : Liu Jiahao
 * @date        : 2024-03-26
 * @version     : v1.1
 * @copyright   : Copyright By Liu Jiahao, All Rights Reserved
 */
void sci_Printf(char *format, ...)
{
    uint16 i;
    va_list listdata;
    uint8 sci_TxBuff[100];

    va_start(listdata, format);
    vsprintf((char *)sci_TxBuff, format, listdata);
    va_end(listdata);

    for (i = 0; i < strlen((const char*)sci_TxBuff); i++) {
        while ((SCI_REG->FLR & 0x04U) == 4U);
        sciSendByte(SCI_REG, sci_TxBuff[i]);
    }
}
#else
/* fputs 函数 */
int fputs(const char *_ptr, FILE *_fp)
{
    unsigned int i, len;

    len = strlen(_ptr);

    for (i = 0; i < len; i++)
    {
        while((SCI_REG->FLR & (uint32)SCI_TX_INT) == 0U);
        sciSendByte(SCI_REG, _ptr[i]);
    }

    return len;
}
/* fputc 函数 */
int fputc(int ch, FILE *f)
{
    while((SCI_REG->FLR & (uint32)SCI_TX_INT) == 0U);
    sciSendByte(SCI_REG, ch);

    return ch;
}
#endif
/* USER CODE END */

这部分就类似于 STM32,依旧要实现 fputsfputc 函数。通过控制 SCI_MODE 宏定义的参数可以实现两种方式的发送。

通过串口助手,得到结果如下所示:

在这里插入图片描述

2.2.2.3 串口接收

既然我们已经通过前两种方式实现了串口发送,那么我们将继续实现接收的相关功能。这里值得注意的是,由于我们未开启中断,故实现过程中,必须要等待接收字节完成后程序才能继续执行。

下一篇文章中,我将介绍如何使用中断进行发送和接收。

我们依旧使用上次的工程,示例代码如下所示:

/* USER CODE BEGIN (0) */
/* USER CODE END */

/* Include Files */

#include "HL_sys_common.h"

/* USER CODE BEGIN (1) */
#include "HL_system.h"
#include "HL_sci.h"

#include <stdio.h>
#include <string.h>
/* USER CODE END */

/** @fn void main(void)
*   @brief Application main function
*   @note This function is empty by default.
*
*   This function is called after startup.
*   The user can use this function to implement the application.
*/

/* USER CODE BEGIN (2) */
#define SCI_REG         sciREG1                         // 定义 sci 端口寄存器

// sci 模式参数,为 0 则为不采用 printf 形式, 为 1 则采用 printf 形式
#define SCI_MODE        0

#define CNT             5000000

uint8 RxDataBuf[2];

#if (!SCI_MODE)
void sci_Printf(char *format, ...);
#endif
void printBuf(uint16 len, uint8 * dat);
/* USER CODE END */

int main(void)
{
/* USER CODE BEGIN (3) */
    int i;
    int count = 0;

    sciInit();

    while(1)
    {
        memset(&RxDataBuf[0], 0, 2);                            // 清空缓冲区
        sciReceive(SCI_REG, 2, RxDataBuf);
        printBuf(2, RxDataBuf);
        for (i = 0; i < CNT; i++);                              // 粗略延时
    }
/* USER CODE END */

    return 0;
}


/* USER CODE BEGIN (4) */
/*
 * @brief       : 打印输出数组
 * @param       : [len]: 数组长度
 *                [dat]: 数组指针
 * @return      : void
 * @author      : Liu Jiahao
 * @date        : 2024-03-26
 * @version     : v1.1
 * @copyright   : Copyright By Liu Jiahao, All Rights Reserved
 */
void printBuf(uint16 len, uint8 * dat)
{
    while (len--) {
        while ((SCI_REG->FLR & 0x04U) == 4U);
        sciSendByte(SCI_REG, *dat++);
    }
}

#if (!SCI_MODE)
/*
 * @brief       : 自定义SCI printf 函数
 * @param       : 字符串,可实现类似于 printf 的参数输入
 * @return      : void
 * @author      : Liu Jiahao
 * @date        : 2024-03-26
 * @version     : v1.1
 * @copyright   : Copyright By Liu Jiahao, All Rights Reserved
 */
void sci_Printf(char *format, ...)
{
    uint16 i;
    va_list listdata;
    uint8 sci_TxBuff[100];

    va_start(listdata, format);
    vsprintf((char *)sci_TxBuff, format, listdata);
    va_end(listdata);

    for (i = 0; i < strlen((const char*)sci_TxBuff); i++) {
        while ((SCI_REG->FLR & 0x04U) == 4U);
        sciSendByte(SCI_REG, sci_TxBuff[i]);
    }
}
#else
/* fputs 函数 */
int fputs(const char *_ptr, FILE *_fp)
{
    unsigned int i, len;

    len = strlen(_ptr);

    for (i = 0; i < len; i++)
    {
        while((SCI_REG->FLR & (uint32)SCI_TX_INT) == 0U);
        sciSendByte(SCI_REG, _ptr[i]);
    }

    return len;
}
/* fputc 函数 */
int fputc(int ch, FILE *f)
{
    while((SCI_REG->FLR & (uint32)SCI_TX_INT) == 0U);
    sciSendByte(SCI_REG, ch);

    return ch;
}
#endif
/* USER CODE END */

对于以上代码,我首先需要解释的是,由于我们没有封装接收处理,故只能按接收到的字节数判断接收是否完成。这里我定义的是接收2个字节,然后在把接收到的数据发送出去。另外值得注意的是,我没有使用之前定义的函数,而是使用了新构建的函数 printBuf,这是由于之前构建的函数对于字符串的发送是较为方便的,而像数组这种,处理起来就不够方便,所以我重新写了这个函数实现数组发送。

然后我们使用串口助手发送两字节数据,得到以下内容:

在这里插入图片描述

如图所示,我采用 16进制 发送两个字节数据,接收到的仍然是这两个数据。图中有三组是因为我发了三次的原因,并不是有 bug。

至此我们就完成了串口操作的基本实验。


三、写在最后

本文介绍了 如何在TMS570LC43上进行串口收发的操作

在后续的文章中,将继续对 TMS570LC43x 进行详细的入门指导,欢迎读者关注!!!

目前暂时没有考虑整合的打算,所以各位读者如果需要看别的教程,可以点进 专栏 进行查找。在后续的更新中,将会逐步加入各个文章的链接,以便大家快速翻阅。另外源码会逐步开源。

欢迎广大读者提出问题以及修改意见,本人看到后会给予回应,欢迎留言,后续会逐步进行开源!!!
另外,由于文章是作者手打的文字,有些地方可能文字会出错,望谅解,也可私信联系我,我对其进行更改。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值