[攻城狮计划]RT-Thread—详解UART设备(基于RA2E1)

[攻城狮计划]|RT-Thread—详解UART设备(基于RA2E1)

🚀🚀开启攻城狮的成长之旅!这是我参与的由 CSDN博客专家 架构师李肯瑞萨MCU 联合发起的「 致敬未来的攻城狮计划 」的第4天,点击查看活动计划详情

🚀🚀首先非常感谢李老师能给我参加这个计划的机会,让我有机会接触到许多的开发板,同时也感谢瑞萨官方 为我们提供的开发板。在参加活动的期间,结识了许多的大佬,让我收获了许多的知识,我感觉短短的几天,收获的知识与开发经验比自己独自学习几个月的收获还要多。所以,希望各位大佬们也能加入李老师的这个活动,而且,李老师水平真的很高,而且非常耐心,谁来谁知道!!!!

🚀🚀好了,接下来我们开始进入今天的主题,如何在RA2E1上基于RT-Thread优雅地使用UART设备!

🚀🚀本文将会详细介绍有关RT-Thread的UART设备,但是考虑到可能有部分和我一样的初学者,所以有些具体细节并未介绍。其实本文中的内容并不仅仅适用于一款开发板,只要运行了RT-Thread操作系统的开发板,都是一样的。


UART简介

🚀🚀接下来,我们来详细介绍一下UART设备(Universal Asynchronous Receiver/Transmitter,通用异步收发传输器),我们一般也叫其为串口。

🚀🚀UART 是异步串口通信协议的一种,工作原理就是是将传输数据的每个字符一位接一位地传输。它的特点是将数据一位一位地顺序传送,只要 2 根传输线就可以实现双向通信,一根线(TX)发送数据的同时用另一根线(RX)接收数据。UART 串口通信有几个重要的参数:

  • 起始位:表示数据传输的开始,电平逻辑为 “0” 。
  • **数据位:**可能值有 5、6、7、8、9,表示传输这几个 bit 位数据。一般取值为 8,因为一个 ASCII 字符值为 8 位。
  • 停止位: 表示一帧数据的结束。电平逻辑为 “1”。
  • **奇偶校验位:**用于接收方对接收到的数据进行校验,校验 “1” 的位数为偶数 (偶校验) 或奇数(奇校验),以此来校验数据传送的正确性,使用时不需要此位也可以。
  • **波特率:**串口通信时的速率,它用单位时间内传输的二进制代码的有效位 (bit) 数来表示,其单位为每秒比特数 bit/s(bps)。常见的波特率值有 4800、9600、14400、38400、115200 等,数值越大数据传输的越快,波特率为 115200 表示每秒钟传输 115200 位数据。

🚀🚀对于两个使用 UART 串口通信的端口,这些参数必须匹配,否则将无法通信。UART 串口传输的数据格式如下图所示:

串口传输数据格式


串口设备管理

🚀🚀在RT-Thrread中,应用程序可通过通用I/O设备管理接口来访向串口硬件,可以按照轮询、中断或DMA等方式进行串口数据收发,也可以设置串口的波特率、数据位等。

🚀🚀串口设备驱动框架中定义了串口的设备模型,代码如下所示:

struct rt_serial_device
{
    struct rt_device          parent;		/* 继承 rt_device */
    const struct rt_uart_ops *ops;			/* 串口设备的操作方法 */
    struct serial_configure   config;		/* 串口设备的配置参数 */
    void *serial_rx;
    void *serial_tx;
    struct rt_device_notify rx_notify;		/* 通知结构 */
};

🚀🚀注:串口设备驱动程序根据串口设备模型定义,创建出具备硬件访问能力的串口设备实例,将该设备通过rt_ hw_serial_register()接口注册到串口设备驱动框架中。

🚀🚀我们主要的就是需要去实现这些操作方法,我们在下面会介绍。


创建和注册串口设备


🚗创建

🚀🚀接下来,我们需要来创建一个串口设备,而主要需要做的就是实现串口设备的操作方法,也就是将其实例化。

/**
 * uart operators
 */
struct rt_uart_ops
{
    rt_err_t (*configure)(struct rt_serial_device       *serial,
                          struct serial_configure       *cfg);
    rt_err_t (*control)(struct rt_serial_device         *serial,
                                            int          cmd,
                                            void        *arg);
    int (*putc)(struct rt_serial_device *serial, char c);
    int (*getc)(struct rt_serial_device *serial);
    rt_size_t (*transmit)(struct rt_serial_device       *serial,
                                 rt_uint8_t             *buf,
                                 rt_size_t               size,
                                 rt_uint32_t             tx_flag);
};
方法名称方法描述
configure串口配置操作函数
control串口控制函数
putc发送一个字符数据
getc接收一个字符数据
transmit多字节数据的的发送

🚀🚀这部分的实现在drv_usart_v2.c文件里面能看到。

🚀🚀串口设备被创建后,使用如下接口注册到串口设备驱动框架中:

rt_err_t rt_hw_serial_register	(	struct rt_serial_device * 	serial,
const char * 	name,
rt_uint32_t 	flag,
void * 	data 
)	
参数描述
serial串口设备句柄
name串口设备名称
flag串口设备模式标志
data串口设备私有数据
返回描述
RT_EOK成功
-RT_ERROR注册失败,已有其他驱动使用该name注册

访问串口设备

🚀🚀应用程序通过 RT-Thread提供的 I/O 设备管理接口来访问串口硬件,相关接口如下所示:

函数描述
rt_device_open()打开设备
rt_device_read()读取数据
rt_device_write()写入数据
rt_device_control()控制设备
rt_device_close()关闭设备

示例代码

#include <rtthread.h>

#define SAMPLE_UART_NAME       "uart9"      /* 串口设备名称 */

/* 用于接收消息的信号量 */
static struct rt_semaphore rx_sem;
static rt_device_t serial;

/* 接收数据回调函数 */
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
    /* 串口接收到数据后产生中断,调用此回调函数,然后发送接收信号量 */
    rt_sem_release(&rx_sem);

    return RT_EOK;
}

static void serial_thread_entry(void *parameter)
{
    char ch;

    while (1)
    {
        /* 从串口读取一个字节的数据,没有读取到则等待接收信号量 */
        while (rt_device_read(serial, -1, &ch, 1) != 1)
        {
            /* 阻塞等待接收信号量,等到信号量后再次读取数据 */
            rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
        }
        /* 读取到的数据通过串口错位输出 */
        ch = ch + 1;
        rt_device_write(serial, 0, &ch, 1);
    }
}

static int uart_sample(int argc, char *argv[])
{
    rt_err_t ret = RT_EOK;
    char uart_name[RT_NAME_MAX];
    char str[] = "hello RT-Thread!\r\n";

    if (argc == 2)
    {
        rt_strncpy(uart_name, argv[1], RT_NAME_MAX);
    }
    else
    {
        rt_strncpy(uart_name, SAMPLE_UART_NAME, RT_NAME_MAX);
    }

    /* 查找串口设备 */
    serial = rt_device_find(uart_name);
    if (!serial)
    {
        rt_kprintf("find %s failed!\n", uart_name);
        return RT_ERROR;
    }

    /* 初始化信号量 */
    rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
    /* 以中断接收及轮询发送方式打开串口设备 */
    rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
    /* 设置接收回调函数 */
    rt_device_set_rx_indicate(serial, uart_input);
    /* 发送字符串 */
    rt_device_write(serial, 0, str, (sizeof(str) - 1));

    /* 创建 serial 线程 */
    rt_thread_t thread = rt_thread_create("serial", serial_thread_entry, RT_NULL, 1024, 25, 10);
    /* 创建成功则启动线程 */
    if (thread != RT_NULL)
    {
        rt_thread_startup(thread);
    }
    else
    {
        ret = RT_ERROR;
    }

    return ret;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(uart_sample, uart device sample);
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值