NUC980 运行 RT-Thread 时使用 UART

这里来体验下 NUC980 跑 RT-Thread 时,怎么使用 uart.

板子上的 UART

来体验下 uart ,手上的板子已经引出了一个 uart,如下:

从图中可以看到使用 2.54 的排针引出了 uart4,很方便使用,不做要对板子做什么变动,

软件上,默认的工程中,先跑起来,看下启用了设备中是否有uart,在 shell 中,使用 list_device 查看:

可以看到工程中已启用了 uart4,也就是说这里可以直接把 uart4 用起来。

RT-Thread 中关于 uart 的 API

RT-Thread 使用了设备驱动框架来驱动 uart,有标准的接口,应用程序只需 RT-Thread提供的 I/O 设备管理接口来访问串口硬件,相关接口如下所示:

函数 描述
rt_device_find() 查找设备
rt_device_open() 打开设备
rt_device_read() 读取数据
rt_device_write() 写入数据
rt_device_control() 控制设备
rt_device_set_rx_indicate() 设置接收回调函数
rt_device_set_tx_complete() 设置发送完成回调函数
rt_device_close() 关闭设备

详细说明,可以查看 rt-Thread 官方文档: 访问串口设备

发送

这里尝试下通过 RT-Thread 的 uart 驱动框架来发送数据,代码如下:

#include <drv_uart.h>

#define USER_UART_DEVNAME "uart4"

int uart4_test(int argc, char **argv)
{
    rt_device_t serial;
    char txbuf[16];
    rt_err_t ret;
    int str_len;

    serial = rt_device_find(USER_UART_DEVNAME);
    if (!serial)
    {
        rt_kprintf("Can't find %s. EXIT.\n", USER_UART_DEVNAME);
        goto exit_test_uart4;
    }

    /* Interrupt RX */
    ret = rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
    RT_ASSERT(ret == RT_EOK);
    rt_kprintf("Open uart success\r\n");
    /* Say Hello */
    ret = rt_device_write(serial, 0, "Hello NUC980 using uart4", rt_strlen("Hello NUC980 using uart4"));
    ret = rt_device_close(serial);
    RT_ASSERT(ret == RT_EOK);

exit_test_uart4:

    return 0;
}
MSH_CMD_EXPORT(uart4_test, test uart4 write);

上述代码流程是,首先是使用 rt_device_find 查找对应的设备,然后使用 rt_device_open 打开设备,打开成功后使用rt_device_write 发送数据即可。

硬件上,使用 usb 转 ttl 连接到 NuMaker-RTU-NUC980 的 uart4,如下:

编译并烧录固件,在电脑中使用串口调试助手打开 usb 转 ttl 对应 COM 口,然后在 shell 中运行 uart4_test,结果如下:

可以看到串口调试助手成功接收到了 nuc980 发送过来的数据。

接收

再来测试下接收,手里刚好有个 uart 接口的 TOF,如下:

TOF 跟 NuMaker-RTU-NUC980 连接为:

相关代码为:

#include <rtthread.h>

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

/* 用于接收消息的信号量 */
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 int read_tof_skz(int argc, char *argv[])
{
    rt_err_t ret = RT_EOK;
    uint8_t rx_buf[18];
    uint8_t rx_index = 0;
    uint16_t count =0 ;
    uint8_t i=0;

    uint8_t temp = 0;
    uint16_t value = 0;
    char ch;
    /* 查找串口设备 */
    serial = rt_device_find(SAMPLE_UART_NAME);
    if (!serial)
    {
        rt_kprintf("find %s failed!\n", SAMPLE_UART_NAME);
        return RT_ERROR;
    }

    /* 以中断接收及轮询发送方式打开串口设备 */
    rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
    /* 初始化信号量 */
    rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
    /* 设置接收回调函数 */
    rt_device_set_rx_indicate(serial, uart_input);
    while (1)
    {
        /* 从串口读取一个字节的数据,没有读取到则等待接收信号量 */
        while (rt_device_read(serial, 0, &ch, 1) != 1)
        {
            /* 阻塞等待接收信号量,等到信号量后再次读取数据 */
            rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
        }
         rt_device_write(serial, 0, &ch, 1);
        if( ch == '~')
        {
            rx_index = 0;
        }
       
        rx_buf[rx_index ] = ch;
        //rt_kprintf("received index:%d\r\n",rx_index);
        if(rx_index >=1)
        {
            if(rx_buf[rx_index] == '\n' && rx_buf[rx_index-1] == '\r' )
            {
                // 9 
                value = 0;
                temp = rx_buf[rx_index - 9] - '0';
                value = (value + temp <<24);

                 temp = rx_buf[rx_index - 8] - '0';
                value = (value + temp <<16);

                temp = rx_buf[rx_index - 7] - '0';
                value = (value + temp <<8);

                temp = rx_buf[rx_index - 6] - '0';
                value = (value + temp );                                               
                rt_kprintf("Value is:%d\r\n",value);

                count ++;
            }
        }          
        rx_index ++;
        if(rx_index >=19)
            rx_index = 0;
        
        if(count > 2500)
            break;
    }
    rt_device_close(serial);
    return ret;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(read_tof_skz, uart device read sample);

代码中前面部分跟之前 发送的一样,首先都是查找所使用设备,找到后打开设备,这里使用中断的方式接收,需要设置中断回调函数,

/* 设置接收回调函数 */
rt_device_set_rx_indicate(serial, uart_input);

接收方式是,使用一个信号量,如果接收到了数据,回调函数中释放信号量,接收处理数据部分阻塞等待接收信号量。

这里使用的 TOF 发送过来的数据的协议为:

这里的处理方式是,如果接收到的数据为 ’~‘,从 0 开始计数,把接收到的数据存入数组,如果接收到了 “\r\n” ,就表示接收到了一个有效的数据包,数据包中有 CRC 校验的,这里只做个体验RT-Thread 串口接收,就不进行 CRC 校验了,直接获取TOF检测到的距离:

            if(rx_buf[rx_index] == '\n' && rx_buf[rx_index-1] == '\r' )
            {
                // 9 
                value = 0;
                temp = rx_buf[rx_index - 9] - '0';
                value = (value + temp <<24);

                 temp = rx_buf[rx_index - 8] - '0';
                value = (value + temp <<16);

                temp = rx_buf[rx_index - 7] - '0';
                value = (value + temp <<8);

                temp = rx_buf[rx_index - 6] - '0';
                value = (value + temp );                                               
                rt_kprintf("Value is:%d\r\n",value);

                count ++;
            }

编译、运行,结果为:

参考:

转载请注明出处:https://www.cnblogs.com/halin/

posted @ 2021-07-01 15:30  哈拎  阅读(711)  评论(0编辑  收藏  举报