全部文档
概述 硬件支持 快速开发指南 内核 驱动 通用组件 专业组件 常见问题

Serial设备用户开发


基础BSP配置--以STM32为例

建立工程文件

如果在提供的 oneos 源码中已经有适合的工程 DEMO 工程,则可以直接使用;如果没有请参照快速上手中的操作指南,新建一个适合的工程。

使用STM32CUBEMX配置硬件

  1. 打开 oneos\projects\xxxxx(project文件夹)\board\CubeMX_Config 下 的 CUBE 工程文件;
  2. 在 CUBE 工程中进行 Serial 配置,如下图所示,选中 UART,配置工作模式,分配引脚; adc_cube
  3. 配置UART的接收中断功能; adc_cube
  4. 若需要使用DMA功能,配置DMA功能; adc_cube adc_cube adc_cube
  5. 点击 GENARATE CODE 生成代码。 adc_cube

使用 Menuconfig 配置工程选项

  1. 在对应的 oneos\projects\xxxxx(project文件夹) 目录下打开 OneOS-Cube 工具,在命令行输入 menuconfig 打开可视化配置界面;

  2. 如下图所示,通过空格或向右方向键选择 Drivers->Serial 下的 Enable serial drivers 选项;

(Top) → Drivers→ Serial
                                                       OneOS Configuration
[*] Enable serial drivers
(64) Set RX buffer size
(64) Set TX buffer size
  1. 如下图所示,通过空格或向右方向键选择 Drivers->HAL 选项,“ Configure base hal in STM32CubeMX ”提示在STM32CubeMX中配置HAL,因前面已完成硬件配置,此处无需操作;
    (Top) → Drivers→ HAL  
                                                        OneOS Configuration
    [ ] Enable Ethernet  ----
    [ ] default system clock config
     *** Configure base hal in STM32CubeMX ***
    
  2. 若是没有配置工具的芯片工程,则Drivers->HAL选项显示如下图所示,通过空格键选中Enable UART --->;
    (Top) → Drivers→ HAL
                                                        OneOS Configuration
    -*- Enable GPIO
    [*] Enable LED
    [*] Enable UART  --->
    [ ] Enable on-chip FLASH
    [ ] Enable SPI BUS  ----
    [ ] Enable I2C BUS  ----
    [ ] Enable timer  ----
    [ ] Enable pwm  ----
    [ ] Enable ADC  ----
    [ ] Enable RTC  ----
    [ ] Enable Watchdog Timer
    
  3. 在上一菜单中,通过向右方向键进入Drivers→ HAL→ Enable UART选项,如下图所示,选中需要开启的串口;
    (Top) → Drivers→ HAL→ Enable UART
                                                        OneOS Configuration
    [*] Enable UART0
    [ ] Enable UART1
    
  4. Esc键退出menuconfig,注意保存所修改的设置。

使用 Scons 构建工程

在上一步打开的 OneOS-Cube 工具命令行输入 scons --ide=mdk5 构建工程。

工程编译及实现

  1. 打开对应的 oneos\projects\xxxxx(project文件夹) 目录下的 project.uvprojx 工程文件;

  2. 在工程中将原有或自己编写的serial_test文件加入到application子文件夹中;

  3. 编译并下载工程,运行程序;

  4. 打开串口工具如xshell、SecureCRT等,通信成功后,即可通过serial_int_tx_test,sereial_test,serial_rx_test命令测试serial的数据接收和发送功能;

  5. 通过修改serial_test.c中serial的波特率,发送数据值等,查看运行效果;

  6. 如不再使用serial设备,可再次使用STM32CubeMX配置工具,或者OneOS-Cube工具取消,在Drivers->HAL 下取消Enable UART的选择,保存设置后重新生成工程即可。

Serial设备


API列表

接口 说明
os_device_find() 查找设备
os_device_open() 打开设备
os_device_read_block() 读取数据(阻塞)
os_device_read_nonblock() 读取数据(非阻塞)
os_device_write_block() 写入数据(阻塞)
os_device_write_nonblock() 写入数据(非阻塞)
os_device_control() 控制设备
os_hw_serial_isr_rxdone() 设置接收回调函数
os_hw_serial_isr_txdone() 设置发送完成回调函数
os_device_close() 关闭设备

os_device_find

该函数根据串口名查找对应的串口设备,函数原型如下:

os_device_t *os_device_find(const char *name);
参数 说明
name 串口名(uart1,uart2 等)
返回 说明
设备指针 成功返回对应的设备指针
OS_NULL 没有找到指定的串口

os_device_open

该函数用于打开设备,第一次打开设备会调用设备初始化接口,函数原型如下:

os_err_t os_device_open(os_device_t *dev);
参数 说明
dev 设备指针
返回 说明
OS_EOK 设备打开成功
OS_EBUSY 设备忙,即:串口设备在一次发送完成之前,处于OS_EBUSY状态,不允许再次打开串口设备
其他错误码 设备打开失败

os_device_read_block

该函数用于从串口中阻塞地读取数据,函数原型如下:

os_size_t os_device_read_block(os_device_t *dev, os_off_t pos, void *buffer, os_size_t size);
参数 说明
dev 设备指针
pos 读取数据偏移量,此参数串口设备未使用
buffer 缓冲区指针,读取的数据将会被保存在缓冲区中
size 读取数据的大小
返回 说明
大于0 如果是字符设备,返回大小以字节为单位
小于0 错误码

os_device_read_nonblock

该函数用于从串口中非阻塞地读取数据,函数原型如下:

os_size_t os_device_read_nonblock(os_device_t *dev, os_off_t pos, void *buffer, os_size_t size);
参数 说明
dev 设备指针
pos 读取数据偏移量,此参数串口设备未使用
buffer 缓冲区指针,读取的数据将会被保存在缓冲区中
size 读取数据的大小
返回 说明
大于0 读到数据的实际大小(字符设备,单位是 字节;块设备,单位是 块)
小于0 错误码
等于0 设备没有数据可读

os_device_write_block

该函数用于向串口阻塞地中写入数据,函数原型如下:

os_size_t os_device_write_block(os_device_t *dev, os_off_t pos, const void *buffer, os_size_t size);
参数 说明
dev 设备指针
pos 写入数据偏移量,此参数串口设备未使用
buffer 内存缓冲区指针,放置要写入的数据
size 写入数据的大小
返回 说明
大于0 写入数据的实际大小(字符设备,单位是 字节;块设备,单位是 块)
小于0 错误码

os_device_write_nonblock

该函数用于向串口中非阻塞地写入数据,函数原型如下:

os_size_t os_device_write_nonblock(os_device_t *dev, os_off_t pos, const void *buffer, os_size_t size);
参数 说明
dev 设备指针
pos 写入数据偏移量,此参数串口设备未使用
buffer 内存缓冲区指针,放置要写入的数据
size 写入数据的大小
返回 说明
大于0 写入数据的实际大小(字符设备,单位是 字节;块设备,单位是 块)
小于0 错误码
等于0 设备没有空间可写

os_device_control

该函数用于对串口设备进行配置,如波特率、数据位、校验位、接收缓冲区大小、停止位等参数,函数原型如下:

os_err_t os_device_control(os_device_t *dev, int cmd, void *arg);
参数 说明
dev 设备指针
cmd 命令控制字,可取值:OS_DEVICE_CTRL_CONFIG
arg 控制的参数,可取类型: struct serial_configure
返回 说明
OS_EOK 函数执行成功
OS_ENOSYS 执行失败,设备不支持 control 接口
其他错误码 执行失败

控制参数结构体 struct serial_configure 原型如下:

struct serial_configure
{
    os_uint32_t baud_rate;

    os_uint32_t data_bits               :4;
    os_uint32_t stop_bits               :2;
    os_uint32_t parity                  :2;
    os_uint32_t bit_order               :1;
    os_uint32_t invert                  :1;
    os_uint32_t rx_bufsz                :16;
    os_uint32_t tx_bufsz                :16;
    os_uint32_t reserved                :6;
};

配置参数可取值如下:

#define BAUD_RATE_2400                  2400
#define BAUD_RATE_4800                  4800
#define BAUD_RATE_9600                  9600
#define BAUD_RATE_19200                 19200
#define BAUD_RATE_38400                 38400
#define BAUD_RATE_57600                 57600
#define BAUD_RATE_115200                115200
#define BAUD_RATE_230400                230400
#define BAUD_RATE_460800                460800
#define BAUD_RATE_921600                921600
#define BAUD_RATE_2000000               2000000
#define BAUD_RATE_3000000               3000000

#define DATA_BITS_5                     5
#define DATA_BITS_6                     6
#define DATA_BITS_7                     7
#define DATA_BITS_8                     8
#define DATA_BITS_9                     9

#define STOP_BITS_1                     0
#define STOP_BITS_2                     1
#define STOP_BITS_3                     2
#define STOP_BITS_4                     3

os_hw_serial_isr_rxdone

该函数用于设置数据接收回调,当串口收到数据时,通知上层应用线程有数据到达,函数原型如下:

os_err_t os_hw_serial_isr_rxdone(struct os_serial_device *serial, int count);
参数 说明
serial serial设备指针
count 接收字符字节计数
返回 说明
void

os_hw_serial_isr_txdone

该函数用于设置数据发送完毕回调,当串口数据发送完毕时,通知上层应用线程,函数原型如下:

void os_hw_serial_isr_txdone(struct os_serial_device *serial);
参数 说明
seria serial设备指针
返回 说明
viod

os_device_close

该函数用于关闭设备,函数原型如下:

os_err_t os_device_close(os_device_t *dev);
参数 说明
dev 设备指针
返回 说明
OS_EOK 关闭设备成功
OS_ERROR 设备已经完全关闭,不能重复关闭设备
其他错误码 关闭设备失败

使用示例

串口阻塞收发数据

本例中将测试串口 uart2 的 tx rx 信号线环回,使用阻塞接口进行自收自发。

static int32_t  rx_thread_status = 0;
static int32_t  rx_total_cnt     = 0;
static uint16_t rx_crc           = 0;

static void rx_thread(void *parameter)
{
    int            rx_cnt;
    unsigned char *rx_buff = os_calloc(1, OS_SERIAL_RX_BUFSZ);
    os_device_t   *uart = (os_device_t *)parameter;

    OS_ASSERT(rx_buff);

    /* set device timeout */
    os_ubase_t timeout = OS_TICK_PER_SECOND;
    os_device_control(uart, OS_DEVICE_CTRL_SET_RX_TIMEOUT, &timeout);
    os_device_control(uart, OS_DEVICE_CTRL_SET_TX_TIMEOUT, &timeout);

    while (rx_thread_status == 0)
    {        
        rx_cnt = os_device_read_block(uart, 0, rx_buff, OS_SERIAL_RX_BUFSZ);
        if (rx_cnt <= 0)
            continue;

        rx_total_cnt += rx_cnt;
        os_kprintf("<%d>rx: %d/%d\r\n", os_tick_get(), rx_cnt, rx_total_cnt);
        hex_dump(rx_buff, rx_cnt);
        rx_crc = crc16(rx_crc, rx_buff, rx_cnt);
    }

    /* last pack */
    rx_cnt = os_device_read_block(uart, 0, rx_buff, OS_SERIAL_RX_BUFSZ);
    if (rx_cnt > 0)
    {
        rx_total_cnt += rx_cnt;
        os_kprintf("<%d>rx: %d/%d\r\n", os_tick_get(), rx_cnt, rx_total_cnt);
        hex_dump(rx_buff, rx_cnt);
        rx_crc = crc16(rx_crc, rx_buff, rx_cnt);
    }

    os_free(rx_buff);

    rx_thread_status = 2;
}

static int serial_block_test(int argc, char *argv[])
{
    int            ret, i, j, loops = 1;
    uint32_t       tx_index, rand_tx_cnt;
    unsigned char *tx_buff = os_calloc(1, OS_SERIAL_RX_BUFSZ);
    os_device_t   *uart;
    uint16_t       tx_crc = 0;

    OS_ASSERT(tx_buff);

    if (argc != 2 && argc != 3)
    {
        os_kprintf("usage: serial_block_test <dev> [times]\r\n");
        os_kprintf("       serial_block_test uart1 (default 1 times)\r\n");
        os_kprintf("       serial_block_test uart1 10000\r\n");
        return -1;
    }

    uart = os_device_find(argv[1]);
    OS_ASSERT(uart);

    if (argc == 3)
    {
        loops = strtol(argv[2], OS_NULL, 0);
    }

    os_device_open(uart);

    /* uart config */
    struct serial_configure config = OS_SERIAL_CONFIG_DEFAULT;
    config.baud_rate = BAUD_RATE_2000000;
    ret = os_device_control(uart, OS_DEVICE_CTRL_CONFIG, &config);
    if (ret != 0)
    {
        os_kprintf("serial baud 115200\r\n");
        config.baud_rate = BAUD_RATE_115200;
        ret = os_device_control(uart, OS_DEVICE_CTRL_CONFIG, &config);
        if (ret != 0)
        {
            os_kprintf("serial control fail %d\r\n", ret);
            return -1;
        }
    }

    rx_thread_status = 0;
    rx_total_cnt     = 0;
    rx_crc           = 0;

    os_task_t *task = os_task_create("rx_thread", rx_thread, uart, 512, 4);
    OS_ASSERT(task);
    os_task_startup(task);

    for (i = 0; i < loops; i++)
    {
        tx_index = 0;

        for (j = 0; j < OS_SERIAL_RX_BUFSZ; j++)
        {
            tx_buff[j] = rand();
        }
        os_task_msleep(50);

        tx_crc = crc16(tx_crc, tx_buff, OS_SERIAL_RX_BUFSZ);

        while (tx_index < OS_SERIAL_RX_BUFSZ)
        {
            rand_tx_cnt = (OS_SERIAL_RX_BUFSZ - tx_index) * (rand() & 0xff) / 256 + 1;
            rand_tx_cnt = min(OS_SERIAL_RX_BUFSZ - tx_index, rand_tx_cnt);
            tx_index += os_device_write_block(uart, 0, tx_buff + tx_index, rand_tx_cnt);

            os_kprintf("<%d>uart tx loop:%d/%d, buff:%d/%d\r\n", os_tick_get(), i, loops, tx_index, OS_SERIAL_RX_BUFSZ);
        }
    }

    /* wait rx thread exit */
    os_task_msleep(300);
    rx_thread_status = 1;
    while (rx_thread_status != 2)
    {
        os_kprintf("wait rx thread exit..\r\n");
        os_task_msleep(300);
    }

    os_device_close(uart);

    os_kprintf("\r\n");
    os_kprintf("stat:\r\n");
    os_kprintf("    tx size %d\r\n", OS_SERIAL_RX_BUFSZ * loops);
    os_kprintf("\r\n");
    os_kprintf("    rx size %d\r\n", rx_total_cnt);
    os_kprintf("\r\n");
    os_kprintf("    %s tx_crc:%04x, rx_crc:%04x\r\n", (tx_crc == rx_crc) ? "success" : "failed", tx_crc, rx_crc);

    os_free(tx_buff);

    return 0;
}
SH_CMD_EXPORT(serial_block_test, serial_block_test, "serial_block_test");

运行结果如下:


sh />serial_block_test uart2
<2124>uart tx loop:0/1, buff:20/64
<2124>rx: 5/5
00000000: 49 68 07 45 c8
<2124>rx: 15/20
00000000: 7f 13 c4 6c 2b ba 61 65  a1 72 64 39 3d ee d2
<2125>uart tx loop:0/1, buff:59/64
<2125>rx: 5/25
00000000: b5 5a 39 68 e8
<2126>rx: 34/59
00000000: c9 aa 5c 9f 30 c1 58 da  59 bf dd dc 1b 71 bb 23  
00000010: 25 9c 75 7d 8e a2 cf e3  be b3 e1 a0 e0 8c a1 42  
00000020: 60 04
<2127>uart tx loop:0/1, buff:64/64
<2128>rx: 5/64
00000000: a5 5b 2e 35 27
wait rx thread exit..
wait rx thread exit..
wait rx thread exit..
wait rx thread exit..
wait rx thread exit..
wait rx thread exit..

stat:
    tx size 64

    rx size 64

    success tx_crc:12fb, rx_crc:12fb

串口非阻塞收发数据

本例中将测试串口 uart2 的 tx rx 信号线环回,使用非阻塞接口进行自收自发。

static os_sem_t rx_sem;
static os_sem_t tx_sem;

static os_err_t rx_done(os_device_t *uart, struct os_device_cb_info *info)
{
    os_sem_post(&rx_sem);
    return 0;
}

static os_err_t tx_done(os_device_t *uart, struct os_device_cb_info *info)
{
    os_sem_post(&tx_sem);
    return 0;
}

static int serial_nonblock_test(int argc, char *argv[])
{
    int           ret;
    int           tx_cnt;
    int           rx_cnt;
    unsigned char rx_buff[32];
    os_device_t  *uart;
    const char   *dev_name;

    if (argc != 2)
    {
        os_kprintf("usage: serial_nonblock_test <dev> \r\n");
        os_kprintf("       serial_nonblock_test uart2 \r\n");
        return -1;
    }

    dev_name = argv[1];

    uart = os_device_find(dev_name);
    OS_ASSERT(uart);

    /* open serial device */
    os_device_open(uart);

    /* uart config */
    struct serial_configure config = OS_SERIAL_CONFIG_DEFAULT;
    config.baud_rate = BAUD_RATE_115200;
    ret = os_device_control(uart, OS_DEVICE_CTRL_CONFIG, &config);
    if (ret != 0)
    {
        os_kprintf("serial control fail %d\r\n", ret);
        return -1;
    }

    /* nonblock callback sem */
    os_sem_init(&rx_sem, "nblk_rx", 0, 1);
    os_sem_init(&tx_sem, "nblk_tx", 0, 1);

    /* nonblock callback */
    struct os_device_cb_info cb_info;

    cb_info.type = OS_DEVICE_CB_TYPE_TX;
    cb_info.cb   = tx_done;
    os_device_control(uart, OS_DEVICE_CTRL_SET_CB, &cb_info);

    cb_info.type = OS_DEVICE_CB_TYPE_RX;
    cb_info.cb   = rx_done;
    os_device_control(uart, OS_DEVICE_CTRL_SET_CB, &cb_info);

    os_task_msleep(1);

    /* tx */
    tx_cnt = os_device_write_nonblock(uart, 0, "Hello World!\r\n", sizeof("Hello World!\r\n"));

    /* wait tx complete */
    os_sem_wait(&tx_sem, OS_WAIT_FOREVER);

    /* wait rx complete */
    os_sem_wait(&rx_sem, OS_WAIT_FOREVER);

    rx_cnt = os_device_read_nonblock(uart, 0, rx_buff, sizeof(rx_buff));

    os_kprintf("tx_cnt: %d, rx_cnt: %d\r\n", tx_cnt, rx_cnt);

    if (rx_cnt == sizeof("Hello World!\r\n"))
    {
        os_kprintf("rx buff:%s\r\n", rx_buff);
    }
    else
    {
        os_kprintf("rx failed\r\n");
    }

    os_device_close(uart);

    os_sem_deinit(&rx_sem);
    os_sem_deinit(&tx_sem);

    return 0;
}
SH_CMD_EXPORT(serial_nonblock_test, serial_nonblock_test, "serial_nonblock_test");

通过串口发送字符串:hello world! 运行结果如下:

sh />serial_nonblock_test uart2
tx_cnt: 15, rx_cnt: 15
rx buff:Hello World!

results matching ""

    No results matching ""