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

万耦开发板实验手册

开发板及操作系统简介

万耦开发板

万耦开发板,是中国移动推出的基于STM32,NXP等芯片的一个系列开发板,其由不同处理核心的核心板与万耦底板组成。万耦底板是通用的,核心板当前有STM32L475VGT6、STM32F401VET6与NXPLPC55S69三个型号,用户可根据需求选择不同的核心板。

oneos_board

以STM32L475VGT6为核心的万耦开发板为例,资源如下:

资源类别 资源说明
MCU STM32L475VGT6,主频 80MHz,1024KB FLASH ,128KB SRAM;
存储 外部 FLASH W25Q64(SPI,64Mbit);
人机交互 5个按键(1个RESET按键),RGB灯,电源指示LED灯,呼吸灯,串口指示灯,
4G模组指示灯,WIFI指示灯,4G电源指示灯,1.3寸LCD显示器,1个蜂鸣器;
板载模块 AHT10温/湿度传感器,AP3216C光强/接近位置传感器,IRM-56384红外接收传感器,IR12-21C/TR8红外发送传感器,
ICM-20602六轴传感器,ESP8266Wi-Fi模组,ES8388音频解码芯片,GMI4015P-2C麦克风模块,SN65HVD230DR CAN通信模块,
ST7789VW LCD显示器,LP5907MFX-3.3/NOPB稳压器(4G,WIFI,SENSOR,AUDIO可控供电);
关键接口 USB接口:可用于连接USB设备;20 Pin JTAG接口:可用于代码调试下载;
Mini PCI-E接口:可用于连接4G模组;USB转UART接口,可用于串口通信;
CAN通信接口;TF卡接口;耳机接口;

注意,表中MCU与存储资源位于核心板上,其他资源均位于万耦开发板底板上。

OneOS物联网操作系统

OneOS 是中国移动针对物联网领域推出的轻量级操作系统,具有可裁剪、跨平台、低功耗、高安全等特点,支持ARM Cortex-M、MIPS、RISC-V等主流芯片架构,兼容POSIX、CMSIS等标准接口,支持MicroPython语言开发,提供图形化开发工具,能够有效提升开发效率并降低开发成本,帮助用户开发稳定可靠、安全易用的物联网应用。您可以通过中国移动物联网操作系统官网了解更多关于物联网操作系统的信息。

进入到OneOS操作系统代码根目录下,我们可以看到有多个文件夹和文件,如下图:

oneos_root_introduce

各个目录或文件的作用描述见下表。

目录或文件名称 描述
arch 存放和 MCU(或 CPU )架构体系相关的代码
common 存放一些通用的没有具体业务指向的程序代码,所有模块都可以使用,不通过编译选项控制是否编译,采用默认编译进工程的方式
components 存放组件代码,可进行裁剪
demos 存放内核或组件的对外接口如何使用的示实验序
docs 存放一些文档,如编码规范、编程指南等
drivers 存放驱动的抽象层代码和具体外设的驱动代码
kernel 存放内核代码,如任务管理及调度、任务间同步以及通信、内存管理等代码
libc Libc 库部分硬件相关接口的底层适配
osal OneOS操作系统接口抽象层,支持Posix接口、CMSIS接口、RT-Thread接口等
projects 存放用户调试工程
scripts 存放OneOS-Cube工具在编译构造时所需要的脚本文件
templates 各种开发板的示例工程
thirdparty 存放第三方开源社区或第三方厂家的程序,包括组件、工具、协议实现或对接平台的代码等
Kconfig Menuconfig配置文件,代码工程(如projects目录下的示例工程)中的Kconfig文件会引用此文件
SConscript OneOS操作系统使用Scons构建工具时的根编译脚本,该脚本会引用其它目录的SConscript脚本,若在OneOS操作系统根目录增加新的代码目录,需要修改此文件(参见“从零开始构建代码工程”章节)
LICENSE License 授权说明

工程目录介绍

打开OneOS目录下的templates文件夹,找到其中的stm32l475-cmcc-oneos文件夹,其文件列表如图所示:

oneos_project_files_list

各个目录或文件的作用描述如下:

目录或文件名称 描述
application 存放main及客户应用文件
board 存放STM32CubeMX工程、编译链接脚本、板级支持文件、启动文件等
.config 存放配置工具配置信息
.gitignore 配置工具文件
Kconfig 配置目录文件
oneos_config.h 工程配置宏定义头文件
osconfig.py 配置工具文件
project.uvoptx 工程配置信息
project.uvprojx 工程
SConscript 链接文件
SConstruct 链接文件
template.uvoptx demo工程配置信息
template.uvprojx demo工程

基本使用流程

首先,用户需要在projects目录下打开OneOS-Cube命令行界面。

project_base_flow_1

然后进入命令行界面,输入指令“project”,在弹出的新界面中,选择需要的模板工程。

project_base_flow_2

模板工程选择的逻辑如下:

1、MANUFACTOR :选择芯片厂商,如NXP, STM32 ...等;

2、SERIES :选择芯片系列,如STM32F4, STM32L4 ...等;

3、MODEL :选择芯片大型号,如F401, L475 ...等;

4、SUB MODEL:选择具体的芯片型号,如F401VE, stm32l475-cmcc-oneos ...等;

需要注意的是,SUB MODEL中除了具体的芯片,还有相关芯片的开发板工程等选择,如此处选择的万耦开发板stm32l475-cmcc-oneos工程。退出保存配置后,即可生成相应的工程。

generate_project

此时,在projects目录中就可以看见我们选择的工程了。

project_base_flow_3

注:OneOS-Cube的安装及使用方式请参照文档《OneOS-Cube环境搭建》。

第一章 点亮RGB灯实验

1.1 简介

实验实现了RGB灯的循环闪烁。

1.2 硬件说明

RGB LED灯与MCU连接的引脚如下:

rgb_schematic

名称 管脚 作用
LED_R PE7 LED红灯控制引脚
LED_G PE8 LED绿灯控制引脚
LED_B PE9 LED蓝灯控制引脚

RGB_LED采用共阳极接法,单片机输出低电平时LED亮,高电平LED灭;

rgb__schematic1

1.3 软件说明

RGB_LED程序源码在main.c文件中,创建的一个任务来运行RGB_LED程序,在程序中先将RGB连接的芯片IO引脚配置为输出模式,然后在while循环中对3个灯依次进行开关,开和关之间间隔200ms。

RGB灯的引脚定义在board.c中,代码如下:

const led_t led_table[] = 
{
    {GET_PIN(E, 7), PIN_LOW},
    {GET_PIN(E, 8), PIN_LOW},
    {GET_PIN(E, 9), PIN_LOW},
};

const int led_table_size = ARRAY_SIZE(led_table);

main.c中RGB循环闪烁代码:

static void user_task(void *parameter)
{
    int i = 0;

    for (i = 0; i < led_table_size; i++)
    {
        os_pin_mode(led_table[i].pin, PIN_MODE_OUTPUT);
    }

    while (1)
    {
        for (i = 0; i < led_table_size; i++)
        {
            os_pin_write(led_table[i].pin, led_table[i].active_level);
            os_task_msleep(200);

            os_pin_write(led_table[i].pin, !led_table[i].active_level);
            os_task_msleep(200);
        }
    }
}

int main(void)
{
    os_task_t *task;

    task = os_task_create("user", user_task, NULL, 512, 3);
    OS_ASSERT(task);
    os_task_startup(task);

    return 0;
}

1.4 生成MDK工程

在工程目录下,打开project.uvprojx工程,编译成功后,下载程序到开发板,按RESET键复位,开发板重新启动后RGB灯将循环闪烁。

rgb_board

1.5 注意事项

本文档中,所有实验均使用STM32L475VGT6核心板完成,如用户使用其他核心板进行开发,需要注意下管脚的对应关系。

第二章 串口使用实验

2.1 简介

本实验介绍了如何使用串口(UART2)实现数据的发送和接收,并介绍如何将串口(UART3)配置为OneOS的SHELL工具控制台,实时输出开发板的运行日志信息,实现人机交互,提高开发效率。

2.2 硬件说明

万耦开发板上,串口3通过USB转换,可实现与PC设备的便捷连接。

uart_to_usb_schematic

将串口2引出到JP2排母上,供用户使用。

uart2_schematic

名称 管脚 作用
PC4 PC4 UART3 TX引脚
PC5 PC5 UART3 RX引脚
EXT_USART_RX PD6 UART2 RX引脚
EXT_USART_TX PD5 UART2 TX引脚

串口在开发板上的位置如下图所示:

uart_position

2.3 软件说明

串口测试代码serial_test.c,在中\demos\driver路径下。

如下所示,为阻塞模式下串口测试代码:

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_int_tx_test <dev> [times]\r\n");
        os_kprintf("       serial_int_tx_test uart1 (default 1 times)\r\n");
        os_kprintf("       serial_int_tx_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", sizeof(tx_buff) * 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");static int serial_test(int argc, char *argv[])

串口测试代码行数较多,此处仅粘贴了其中部分代码。

2.4 编译运行

2.4.1 STM32CubeMX配置

在工程目录\board\CubeMX_Config下,打开STM32CubeMx工程STM32L475VG.ioc,并按照以下方式进行配置。

1.管脚设置

如图所示,此处以串口2的配置为例进行演示。根据原理图,将PD5,PD6设置为串口2功能引脚。

uart2_mxcube1

2.DMA设置

串口使用DMA进行数据收发有利于提高通信的效率,但用户可根据需求进行选择配置。

在对数据实时性,完整性有较高要求的场景,如网络通信模组的AT指令收发,网络数据收发,建议用户开启串口接收DMA的循环模式。

uart2_mxcube2-3

如串口1,作为WIFI模组的通信串口,需要将其设置为循环DMA模式,以防止数据丢失。

3.中断设置

在OneOS中串口默认采取中断方式进行数据接收,因此,需要使能串口中断。

4.参数设置

串口的初始化参数设置,设置波特率,数据长度,奇偶校验位等,一般采用默认设置。

5.保存设置并生成代码

2.4.2 OnsOS-Cube配置

OneOS物联网操作系统默认提供一个串口用于打印系统信息,使用前需要进行如下配置:

1.使能UART串口功能

除了在CubeMX工具中配置串口基本信息并生成代码,还需要在OneOS-Cube在工程中勾选使用串口驱动。在projects\stm32l475-cmcc-oneos工程目录下打开命令行窗口,输入menuconfig指令进入系统配置界面,如图,在 Drivers→ Serial下使能串口功能,同时,根据实际需求,设置串口的缓存大小。

oneos_cube_uart1

2.选择控制台选择使用串口

在Drivers→ CONSOLE路径下,设置控制台所用的串口。在万耦开发板中,我们一般选取串口3作为控制台串口。

完成设置后,按ESC或Q退出配置界面,保存配置信息。

2.4.3 生成MDK工程

在OnsOS-Cube命令行界面,使用scons指令:scons --ide=mdk5编译生成keil工程。

oneos_cube_scons1

2.4.4 运行

1、在工程目录projects\stm32l475-cmcc-oneos中,打开工程project.uvprojx ;

2、添加serial_test.c串口测试代码,编译,下载程序;

在keil中添加测试文件的方法如下,鼠标双击application弹出对话框,在demos/driver目录下选中需要添加的测试文件,点“add”添加。

add_file_keil

3、打开了串口调试工具(波特率115200),输入help,可查看当前配置下OneOS的指令信息,如下:

sh>help
OneOS shell commands:
serial_block_test - serial_block_test
serial_nonblock_test - serial_nonblock_test
serial_rx_test   - serial_rx_test
serial_tx_test   - serial_tx_test
reboot           - reboot
device           - show device information
pinMode          - set hardware pin mode
pinWrite         - write value to hardware pin
pinRead          - read status from hardware pin
show_event       - show event information
show_mb          - Show mailbox information
show_mempool     - Show mempool information
show_heap        - show memheap information
show_mem         - show memory usage information
check_mem        - check memory data
show_mq          - Show message queue information
show_mutex       - Show mutex information
show_sem         - show semaphore information
show_task        - Show task information
version          - show oneos version
set_prompt       - Set shell prompt
help             - Obtain help of commands
sh>

输入device命令,可查看当前系统中挂载了哪些设备。

sh>device
device                  type         ref count
--------------- -------------------------------
uart3           Character Device     1
uart2           Character Device     0
uart1           Character Device     0
uart4           Character Device     0
pin_0           Miscellaneous Device 0
sh>

显然,此时串口3已正常运行,用户可通过控制台与开发板进行交互。

为了测试串口2,需要将JP2的9,10号接口短接,对串口2进行回环测试。在控制台中,通过help指令可查看串口测试指令,然后再输入相应指令进行测试,如下:

sh>serial_block_test
usage: serial_int_tx_test <dev> [times]
       serial_int_tx_test uart1 (default 1 times)
       serial_int_tx_test uart1 10000
sh>serial_block_test uart2 1
<287266>uart tx loop:0/1, buff:64/1024
<287266>rx: 5/5
00000000: fa 8f 09 e4 53
<287266>rx: 24/29
00000000: 42 3a e7 85 ea 8f 33 44  65 8d e1 a7 b4 f9 83 5c
00000010: 40 83 43 63 3d 2c 89 e2
<287268>rx: 35/64
00000000: e0 b7 87 7a aa e4 57 70  0f 8e 3b 91 c8 6a 1b ec
00000010: ed 82 18 0e cb ad f5 08  d6 4a 81 09 b3 c8 aa b2
00000020: 49 75 c0
<287269>uart tx loop:0/1, buff:128/1024
...
...
<287325>rx: 6/1017
00000000: c2 d9 79 53 ec 53
<287325>rx: 3/1020
00000000: af e5 5b
<287326>uart tx loop:0/1, buff:1020/1024
<287326>uart tx loop:0/1, buff:1024/1024
<287327>rx: 4/1024
00000000: 9b ab b8 4f
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 1024

    rx size 1024

    success tx_crc:9048, rx_crc:9048
sh>

查看打印信息,可见发送与接收校验码一致,串口通信正常。

非阻塞模式下测试:

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

2.5注意事项

为了正常使用控制台与串口,还需要在OneOS-Cube中对以下项进行配置:

1.打开调试功能

uart_debug_oscube

2.使能shell功能

如图,在components -> shell目录下,使能shell功能,配置相关参数。

shell的配置可根据情况调整,如优先级,指令大小等。

第三章 按键与蜂鸣器实验

3.1 简介

本实验主要是演示在OneOS中如何对开发板中的一些I/O引脚进行控制,如按键,蜂鸣器的使用。万耦开发板上,一共有5个按键,除了系统RESET键,其他键均可根据需求自己设计功能,实现led灯的控制,蜂鸣器的控制等等。

3.2 硬件说明

按键的硬件设计如图所示,其中KEY1采用的是按键上拉方式,其他按键则采用下拉方式。

key_hardware

蜂鸣器原理图:

buzzer_hardware

由图可知,蜂鸣器是引脚高电平时发声。

按键与蜂鸣器的引脚信息如下表:

名称 管脚 作用
KEY1 PD0 KEY1引脚
KEY2 PC13 KEY2引脚
KEY3 PD8 KEY3引脚
KEY4 PD9 KEY4引脚
RESET NRST 复位引脚
BEEP PB2 蜂鸣器引脚

3.3 软件说明

3.3.1按键代码说明

为了方便使用,在push_button.h中定义了按键的类型结构体。

typedef struct push_button
{
    int pin;
    int mode;
    int irq_mode;
} push_button_t;

根据开发板按键的硬件设计,在board.c中创建按键表对key1~key4进行统一管理。

const struct push_button key_table[] = 
{
    {GET_PIN(D, 10),    PIN_MODE_INPUT_PULLUP,      PIN_IRQ_MODE_FALLING},
    {GET_PIN(C, 13),    PIN_MODE_INPUT_PULLUP,      PIN_IRQ_MODE_FALLING},
    {GET_PIN(D, 9),     PIN_MODE_INPUT_PULLUP,      PIN_IRQ_MODE_FALLING},
    {GET_PIN(D, 8),     PIN_MODE_INPUT_PULLUP,      PIN_IRQ_MODE_FALLING},
};

按键测试程序key_test.c,主要功能是在运行测试程序后10s内,检测引脚电压变化,同时,当有按键按下时,在按键中断回调函数中打印按键PIN脚逻辑编号。

static void pin_callback(void *args)
{
    os_kprintf("----------------------pin_callback:%d\r\n", (int)(unsigned long)args);
}

static int key_test(int argc, char *argv[])
{
    int i, j;

    for (i = 0; i < key_table_size; i++)
    {
        os_pin_mode(key_table[i].pin, key_table[i].mode);
        os_pin_attach_irq(key_table[i].pin, key_table[i].irq_mode, pin_callback, (void *)key_table[i].pin);
        os_pin_irq_enable(key_table[i].pin, PIN_IRQ_ENABLE);
    }

    for (j = 0; j < 10; j++)
    {
        for (i = 0; i < key_table_size; i++)
        {
            os_kprintf("<%u> pin[%d] : %d\r\n", (unsigned int)os_tick_get(), key_table[i].pin, os_pin_read(key_table[i].pin));
        }

        os_task_msleep(1000);
    }

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

3.3.2 蜂鸣器代码说明

在buzzer.h中定义了蜂鸣器类型结构体。

typedef struct buzzer
{
    int pin;
    int active_level;
} buzzer_t;

const int key_table_size = ARRAY_SIZE(key_table);

在board.c中创建蜂鸣器表。

const buzzer_t buzzer_table[] =C
{
    {GET_PIN(B, 2), PIN_HIGH},
};

const int buzzer_table_size = ARRAY_SIZE(buzzer_table);

蜂鸣器测试则是通过改变控制引脚的电平状态,控制蜂鸣器的发声,测试代码buzzer_test.c如下:

static void buzzer_init(void)
{
    int i;

    for (i = 0; i < buzzer_table_size; i++)
    {
        os_pin_mode(buzzer_table[i].pin, PIN_MODE_OUTPUT);
    }
}

static void buzzer_test(int argc, char **argv)
{
    unsigned int    buzzer_index;
    char           *on_off;
    const buzzer_t *buzzer;
    os_base_t       value;

    if (argc != 3)
    {
    help:
        os_kprintf("\r\n");
        os_kprintf("buzzer_test <index> <on,off>\r\n");
        os_kprintf("buzzer_test 0 on\r\n");
        os_kprintf("buzzer_test 0 off\r\n");
        return;
    }

    on_off = argv[2];

    /* Buzzer index */
    buzzer_index = strtol(argv[1], NULL, 0);

    if (buzzer_index >= buzzer_table_size)
    {
        goto help;
    }

    buzzer = &buzzer_table[buzzer_index];

    /* Value */
    if (strcmp("on", on_off) == 0)
    {
        value = buzzer->active_level;
    }
    else if (strcmp("off", on_off) == 0)
    {
        value = !buzzer->active_level;
    }
    else
    {
        goto help;
    }

    buzzer_init();
    os_pin_write(buzzer->pin, value);
}

SH_CMD_EXPORT(buzzer_test, buzzer_test, "buzzer_test");

注:测试代码均在demos/driver目录下。

3.4 编译运行

3.4.1 STM32CubeMX配置

按键功能实现较简单,不用单独配置管脚功能。

3.4.2 OnsOS-Cube配置

在Drivers→ MISC路径下,选则使用按键(push button)与蜂鸣器(buzzer)设备驱动:

key&buzeer_oscube

退出配置界面,保存配置信息。

3.4.3 生成MDK工程

配完成置后,使用scons指令:scons --ide=mdk5编译生成keil工程。

3.4.4 运行

1、使用keil5打开工程project.uvprojx ,编译下载程序;

2、双击打开\projects\stm32l475-cmcc-oneos\ project.uvprojx工程文件;

3、添加按键与蜂鸣器测试代码;

4、编译成功后烧写到设备,连接串口到电脑,打开串口工具,输入命令行指令key_test;

程序运行后,按下对应按键,会在控制台中显示其状态(高低电平),并触发中断,打印触发中断的引脚号。

sh>key_test
<1030473> pin[58] : 1
<1030473> pin[45] : 0
<1030473> pin[56] : 1
<1030473> pin[57] : 1
<1030574> pin[58] : 1
<1030574> pin[45] : 0
<1030574> pin[56] : 1
<1030574> pin[57] : 1
----------------------pin_callback:58
<1030674> pin[58] : 1
<1030674> pin[45] : 0
<1030674> pin[56] : 1
<1030674> pin[57] : 1
----------------------pin_callback:45
<1030774> pin[58] : 1
<1030774> pin[45] : 0
<1030774> pin[56] : 1
<1030774> pin[57] : 1
<1030874> pin[58] : 1
<1030874> pin[45] : 0
<1030874> pin[56] : 1
<1030874> pin[57] : 1
----------------------pin_callback:56
<1030974> pin[58] : 1
<1030974> pin[45] : 0
<1030974> pin[56] : 1
<1030974> pin[57] : 1
sh>

5、输入蜂鸣器测试指令。

输入buzzer_test 0 on指令时,蜂鸣器响起,输入buzzer_test 0 off时关闭蜂鸣器。

sh>buzzer_test
buzzer_test <index> <on,off>
buzzer_test 0 on
buzzer_test 0 off
sh>buzzer_test 0 on
sh>
sh>buzzer_test 0 off

3.5 注意事项

1、Drivers→ MISC路径下的button,led,buzzer驱动默认勾选。

2、按键和蜂鸣器引脚不能配置为其他功能。

第四章 看门狗实验

4.1 简介

看门狗是程序运行错误时的一个纠正机制,用来检测和解决由软件错误引起的故障。启用看门狗,为看门狗设置最大超时时间,当计数器计数到超时,会产生一个复位信号复位芯片。在超时之前重新激活(喂狗), 看门狗的超时值就会被重新加载到计数器,从而避免产生看门狗复位。

本实验将介绍如何使用独立看门狗(IWDG)。

看门狗的溢出时间计算方式为:

$$ Tout=((42^p)r)/32

$$ 其中:Tout 为看门狗溢出时间(单位为 ms);2^p 为看门狗时钟预分频值(IWDG counter clock prescaler值),p值范围为 0~7;r为看门狗的重装载值(IWDG down-counter reload value 的值)。

4.2 硬件说明

独立看门狗是由芯片内部专门的低速时钟(LSI)驱动,即使主时钟发生故障,它也仍然有效。需要注意的是由于使用的内部时钟,所以时钟会有些偏差。

4.3 软件说明

看门狗测试程序源码位于demos\drivers\wdt_test.c中。此处,看门狗不支持直接在代码中设置溢出时间,具体的时间需要用户在STM32CubeMX进行配置(相关操作会在后续的看门狗配置中进行说明)。

static int wdg_test(int argc, char *argv[])
{
    os_err_t    ret     = OS_EOK;
    os_uint32_t timeout = 10;
    char        device_name[OS_NAME_MAX];
    int         count = 0;
    os_device_t *wdg_dev;

    if (argc == 2)
    {
        strncpy(device_name, argv[1], OS_NAME_MAX);
    }
    else
    {
        strncpy(device_name, WDT_DEVICE_NAME, OS_NAME_MAX);
    }

    wdg_dev = os_device_find(device_name);
    if (!wdg_dev)
    {
        os_kprintf("find %s failed!\r\n", device_name);
        return OS_ERROR;
    }

    ret = os_device_open(wdg_dev);
    if (ret != OS_EOK)
    {
        os_kprintf("initialize %s failed!\r\n", device_name);
        return OS_ERROR;
    }

    ret = os_device_control(wdg_dev, OS_DEVICE_CTRL_WDT_SET_TIMEOUT, &timeout);
    if (ret != OS_EOK)
    {
        os_kprintf("%s not support set timeout!\r\n", device_name);
    }

    ret = os_device_control(wdg_dev, OS_DEVICE_CTRL_WDT_START, OS_NULL);
    if (ret != OS_EOK)
    {
        os_kprintf("start %s failed!\r\n", device_name);
        return OS_ERROR;
    }

    os_device_control(wdg_dev, OS_DEVICE_CTRL_WDT_KEEPALIVE, NULL);
    while (count < 11)
    {
        os_task_msleep(1000);
        count++;
        os_kprintf("watch dog keep alive for :%ds\r\n", count);
        os_device_control(wdg_dev, OS_DEVICE_CTRL_WDT_KEEPALIVE, NULL);
    }
    count = 0;
    os_kprintf("\r\n");
    while (1)
    {
        os_kprintf("watch dog stop feed for :%d.%ds\r\n", count / 10, count % 10);
        os_task_msleep(100);
        count++;
    }
}

SH_CMD_EXPORT(wdg_test, wdg_test, "test Independent watchdog!");

4.4 编译运行

4.4.1 STM32CubeMX配置

首先,需要在STM32CubeMX激活使能IWDG,然后在参数设置栏中设置相关参数,如时钟分频系数64(查看手册,此时p = 4),重新装载值4095(计数器从零开始计数,代入公式计算时取4096)。

同时,可在clock configuration页查看看门狗时钟信息。如图,其时钟为32KHz,根据前文中的公式,可计算出此配置下的溢出时间为:

Tout = (4 16 4096)/32 = 8192ms

wdt_clock_cubemx

其次,在需要在Project Manager→ Advanced Settings下,勾选不生成函数回调选项,否则工程上电后会不停的触发看门狗进行系统复位。

4.4.2 OnsOS-Cube配置

在Drivers→ WDG路径下,勾选上使用看门狗驱动选项,如下图所示:

选中后使用Q退出,然后选中Y保存配置。

4.4.3 生成MDK工程

完成配置后,使用scons指令:scons --ide=mdk5编译生成mdk5工程。

4.4.4 运行

1、双击打开oneos\projects\stm32l475-cmcc-oneos\ project.uvprojx;

2、添加看门狗测试文件wdg_test.c;

3、编译成功后烧写到设备,连接串口到电脑,打开串口工具,在串口输入device指令和help指令。

输入device指令,查看看门狗设备是否添加成功。

sh>device
device                  type         ref count
--------------- -------------------- ----------
iwdg            Miscellaneous Device 0
uart3           Character Device     2
uart2           Character Device     0
uart1           Character Device     0
uart4           Character Device     0
pin_0           Miscellaneous Device 0
sh>

输入help可以查看到我们新加入的测试程序wdt_test:

sh>help
OneOS shell commands:
wdg_test         - test Independent watchdog!
reboot           - reboot
device           - show device information
pinMode          - set hardware pin mode
pinWrite         - write value to hardware pin
pinRead          - read status from hardware pin
show_event       - show event information
show_mb          - Show mailbox information
show_mempool     - Show mempool information
show_heap        - show memheap information
show_mem         - show memory usage information
check_mem        - check memory data
show_mq          - Show message queue information
show_mutex       - Show mutex information
show_sem         - show semaphore information
show_task        - Show task information
version          - show oneos version
set_prompt       - Set shell prompt
help             - Obtain help of commands
sh>

4、输入wdt_test运行测试程序,可以看到,8s后开发板就重启了,和预期基本一致。

sh>wdg_test
iwdg not support set timeout!
watch dog keep alive for :1s
watch dog keep alive for :2s
watch dog keep alive for :3s
...
...
watch dog stop feed for :0.0s
watch dog stop feed for :0.1s
watch dog stop feed for :0.2s
watch dog stop feed for :0.3s
...
watch dog stop feed for :7.6s
watch dog stop feed for :7.7s
watch dog stop feed for :7.8s
watch dog stop feed for :7.9s
watch dog stop feed for :8.0s
sh>

4.5 注意事项

1.因为独立看门狗使用的是内部时钟,所以时钟打印的结果可能会有些偏差。

2.看门狗溢出时间需要在STM32CubeMX中进行配置。

第五章 RTC实验

5.1 简介

在本实验中,我们将使用STM32L475 的内部实时时钟(RTC)实现日历功能。

5.2 硬件说明

STM32L475VGT6的RTC是一个独立的 BCD 定时器/计数器。RTC提供一个日历时钟(包含年月日时分秒信息)、两个可编程闹钟(ALARM A和 ALARM B)中断,以及一个具有中断功能的周期性可编程唤醒标志。RTC还包含用于管理低功耗模式的自动唤醒单元。两个32位寄存器(TR和DR)包含二进码十进数格式 (BCD) 的秒、分钟、小时(12 或24 小时制)、星期、日期、月份和年份。此外,还可提供二进制格式的亚秒值,自动将月份的天数补偿为 28、29(闰年)、30 和 31 天,进行夏令时补偿。RTC 模块和时钟配置是在后备区域,即在系统复位或从待机模式唤醒后RTC的设置和时间维持不变,只要后备区域供电正常,那么RTC将可以一直运行。

RTC_hardware

5.3 软件说明

RTC测试代码rtc_test.c位于demos\driver中,用户可以在代码中设置日期与时间。

static int rtc_set_test(int argc, char *argv[])
{
    os_err_t ret = OS_EOK;
    time_t   now;

    /* Set date */
    ret = set_date(2020, 6, 1);
    if (ret != OS_EOK)
    {
        LOG_EXT_E("set RTC date failed %d", (int)ret);
        return ret;
    }
    os_task_mdelay(200);

    /* Set time */
    ret = set_time(9, 30, 0);
    if (ret != OS_EOK)
    {
        LOG_EXT_E("set RTC time failed %d", (int)ret);
        return ret;
    }

    os_task_mdelay(3000);

    /* Get time */
    now = rtc_get();
    os_kprintf("%s\n", ctime(&now));
    return ret;
}

SH_CMD_EXPORT(rtc_set_test, rtc_set_test, "set rtc time");

static void rtc_get_test(int argc, char *argv[])
{
    time_t now;

    /* Get time */
    now = rtc_get();

    os_kprintf("%s\n", ctime(&now));
}
SH_CMD_EXPORT(rtc_get_test, rtc_get_test, "get rtc time");

5.4 编译运行

5.4.1 STM32CubeMX配置

设置RTC参数。

5.4.2 OnsOS-Cube配置

在Drivers→ RTC路径下,选择使用RTC驱动:

选中后使用Q退出,然后选中Y保存配置

5.4.3 生成MDK工程

完成配置后,使用scons指令:scons --ide=mdk5编译生成mdk5工程。

5.4.4 运行

1、使用keil5打开工程project.uvprojx ,编译下载程序;

2、添加RTC测试代码;

3、编译成功后烧写到设备,连接串口到电脑,打开串口工具,输入help查看RTC测试指令;

sh>help
OneOS shell commands:
rtc_set_test     - set rtc time
rtc_get_test     - get rtc time
device           - show device information
pinMode          - set hardware pin mode
pinWrite         - write value to hardware pin
pinRead          - read status from hardware pin
event            - show event information
mb               - show mailbox information
memp             - show memory pool information
mem              - show memory usage information
mq               - show message queue information
mutex            - show mutex information
sem              - show semaphore information
task             - show task information
timer            - show timer information
version          - show oneos version
help             - Obtain help of commands
sh>

4、输入测试指令,查看结果。

sh>rtc_set_test
Mon Jun  1 09:30:02 2020

sh>rtc_get_test
Mon Jun  1 09:30:08 2020

sh>

5.5 注意事项

1、因为开发板上没有额外的电池进行持续性的供电,所以在开发板掉电后,RTC设置的日期与时间将不会保留,需要再次进行设置。

2、RTC部分时间获取功能需要用到标准C库,因此,需要将标准C库的适配功能勾选上。

rtc_libc_oscube

第六章 PWM输出实验

6.1简介

在本实验中,我们将使用一路 PWM 点亮LED 灯,并通过改变PWM占空比,调节LED灯的亮度。

6.2 硬件电路连接

呼吸灯D5连接到MCU的管脚上。

led_breath_schematic

led_breath_schematic1

管脚定义和作用:

名称 管脚 作用
Breath PD12 呼吸灯控制引脚

6.3 软件说明

在本实验中,使用TIMER4的channel1来输出PWM。测试代码位于demos\driver\pwm_test.c中,用户可以通过改变PWM的占空比,控制led灯的暗灭变换。

static void pwm_pin_callback(void *args)
{
    int pin = (int)(unsigned long)args;

    os_kprintf("<%d>   <%d>----------------------pin:%d value:%d\r\n", (int)os_tick_get(), (int)(os_clocksource_gettime() & 0x7fffffff), pin, os_pin_read(pin));
}

int pwm_sample(int argc, char **argv)
{
    os_uint32_t pin;

    char *dev_name;

    os_device_t *pwm_dev = OS_NULL;

    struct os_pwm_configuration *config;

    config = os_calloc(1, sizeof(struct os_pwm_configuration));
    if (argc < 3)
    {
        os_kprintf("usage: pwm_sample <dev> <channel> [period(ns)] [duty(ns) def 1000000] [pin]\r\n");
        os_kprintf("       pwm_sample pwm_tim1 1 default: 5000000, 1000000\r\n");
        os_kprintf("       pwm_sample pwm_tim1 1 5000000 1000000 0x3e\r\n");
        os_kprintf("       pwm_sample pwm_tim1 1 1000000000 1000000000 0x3e\r\n");
        os_kprintf("       pwm_sample pwm_tim1 1 1000000000 0 0x3e\r\n");
        return -1;
    }

    dev_name = argv[1];
    config->channel  = strtol(argv[2], OS_NULL, 0);

    if (argc > 3)
    {
        config->period = strtol(argv[3], OS_NULL, 0);
    }

    if (argc > 4)
    {
        config->pulse = strtol(argv[4], OS_NULL, 0);
    }

    if (argc > 5)
    {
        pin = strtol(argv[5], OS_NULL, 0);

        os_pin_mode(pin, PIN_MODE_INPUT_PULLUP);
        os_pin_attach_irq(pin, PIN_IRQ_MODE_RISING_FALLING, pwm_pin_callback, (void *)pin);
        os_pin_irq_enable(pin, PIN_IRQ_ENABLE);
    }

    pwm_dev = os_device_find(dev_name);
    if (pwm_dev == OS_NULL)
    {
        os_kprintf("pwm sample run failed! can't find %s device!\r\n", dev_name);
        return OS_ERROR;
    }

    os_device_control(pwm_dev, OS_PWM_CMD_SET_PERIOD, &config->period);

    os_device_control(pwm_dev, OS_PWM_CMD_SET_PULSE, config);

    os_device_control(pwm_dev, OS_PWM_CMD_ENABLE, &config->channel);

    os_task_msleep(10000);

    os_device_control(pwm_dev, OS_PWM_CMD_DISABLE, &config->channel);

    return 0;
}

SH_CMD_EXPORT(pwm_sample, pwm_sample, "test_pwm_sample!");

6.4 编译运行

6.4.1 STM32CubeMX配置

根据电路原理图定位到呼吸灯使用的是TIMER4的1号通道,因此,其配置如下:

6.4.2 OnsOS-Cube配置

在Drivers→ MISC路径下,勾选使用PWM设备驱动。

使用Q退出,然后选中Y保存配置。

6.4.3 生成MDK工程

完成配置后,使用scons指令:scons --ide=mdk5编译生成mdk5工程。

6.4.4 运行

1、双击打开projects\stm32l475-cmcc-oneos\ project.uvprojx;

2、添加PWM测试代码;

3、编译成功后烧写到设备,连接串口到电脑,打开串口工具;

4、输入指令device,查看pwm设备是否已注册到设备框架中;

sh>device
device                  type         ref count
--------------- -------------------------------
iwdg            Miscellaneous Device 0
rtc             RTC                  0
pwm_tim4        Miscellaneous Device 0
uart3           Character Device     1
uart2           Character Device     0
uart1           Character Device     0
uart4           Character Device     0
pin_0           Miscellaneous Device 0
sh>

5、输入pwm_sample测试指令,调整PWM占空比,改变呼吸灯的亮度。

sh>pwm_sample
usage: pwm_led_sample <dev> <channel> [period(ns)] [duty(ns) def 1000000] [pin]
       pwm_led_sample pwm_tim1 1 default: 5000000, 1000000
       pwm_led_sample pwm_tim1 1 5000000 1000000 0x3e
       pwm_led_sample pwm_tim1 1 1000000000 1000000000 0x3e
       pwm_led_sample pwm_tim1 1 1000000000 0 0x3e
sh>pwm_sample pwm_tim4 1
sh>
sh>pwm_sample pwm_tim4 1 5000000 2000000
sh>
sh>pwm_sample pwm_tim4 1 5000000 3000000
sh>
sh>pwm_sample pwm_tim4 1 5000000 4000000
sh>
sh>pwm_sample pwm_tim4 1 5000000 5000000
sh>

6.5 注意事项

呼吸灯D5的位置,处于RGB灯的正下方。

第七章 传感器实验

7.1 简介

本实验主要介绍了如何使用万耦开发板底板上的三个传感器(AP3216C,AHT10与ICM20602),并利用I2C总线实现通信,读取相应的传感器数据。其中,AP3216C芯片集成了环境光的强度(ALS, ambient light sensor)检测和接近感应(PS,proximity sensor),AHT10芯片集成了温度和湿度检测,ICM20602集成了三轴加速度计(three accelerater)与三轴陀螺仪(three gyroscoper)。

以上传感器和MCU之间均通过I2C通信,更多芯片相关信息请查阅芯片手册。

7.2 硬件电路连接

万耦开发板底板上的三个传感器挂载到了同一个I2C总线(I2C3)上。

  1. AP3216C光强传感器原理图

AP3216C_schematic

  1. AHT10温湿度传感器原理图

  1. ICM20602六轴传感器原理图

  1. 传感器电源

    sensor_power_hardware

为了保证传感器的正常工作,需要给传感器供电,Sensor_POWER高电平时供电。

主要管脚定义和作用:

名称 管脚 作用
I2C_SDA3 PC1 I2C3的数据引脚
I2C_SCL3 PC0 I2C3的时钟控制引脚
Sensor_POWER PD14 传感器电源

如图所示,三个传感器位于开发板的右下角:

sensor_position_onboard

7.3 软件说明

AP3216C芯片相关驱动在sensors文件夹下的ap3216c.c文件中,通过统一的sensors框架进行封装,用户可以通过sensors框架提供的外层接口直接获得芯片读出的光强和距离感应值。

以AP3216C为例,sensors实现框架的函数结构如图表所示: | 函数名 | 用途 | | -------- | ------------------ | | os_hw_ap3216c_light_init | 初始化传感器光强功能 | | os_hw_ap3216c_proximity_init | 初始化传感器距离感应功能 | | ap3216c_init | 初始化芯片相关信息,总线及芯片地址等 | | ap3216c_proximity_control | 距离感应相关功能控制 | | ap3216c_fetch_proximity_data | 获取距离数据 | | ap3216c_light_control | 光强感应相关功能控制 | | ap3216c_fetch_light_data | 获取光强数据 |

以AP3216C光强传感器为例,用户只需要传入对应的芯片名称,即可正确读写芯片数据。

static int sensor_light_test(int argc, char *argv[])
{
    int  i;
    char sensor_name[24];
    struct os_sensor_data sensor_data;

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

    snprintf(sensor_name, sizeof(sensor_name) - 1, "li_%s", argv[1]);

    os_device_t *sensor = os_device_find(sensor_name);
    OS_ASSERT(sensor != NULL);
    os_device_open(sensor);

    struct os_sensor_info sensor_info;
    os_device_control(sensor, OS_SENSOR_CTRL_GET_INFO, &sensor_info);

    for (i = 0; i < 10; i++)
    {
        os_device_read_nonblock(sensor, 0, &sensor_data, sizeof(struct os_sensor_data));

        if (sensor_info.unit == OS_SENSOR_UNIT_MLUX)
        {
            os_kprintf("sensor light (%d.%03d)\r\n", sensor_data.data.light / 1000, sensor_data.data.light % 1000);
        }
        else if (sensor_info.unit == OS_SENSOR_UNIT_LUX)
        {
            os_kprintf("sensor light (%d)\r\n", sensor_data.data.light);
        }
        else if (sensor_info.unit == OS_SENSOR_UNIT_RAW)
        {
            os_kprintf("sensor light raw(%d) mV\r\n", sensor_data.data.light);
        }
        else
        {
            os_kprintf("invalid unit\r\n");
        }

        os_task_msleep(1000);
    }

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

ATH10芯片相关驱动在sensors文件夹下的aht10.c文件中,通过统一的sensors框架进行封装,用户可以通过sensors框架提供的外层接口直接获得传感器芯片检测到的温度和湿度数据。详细说明可以参考AP3216C芯片。

ICM20602芯片相关驱动在OneOS根目录thirdparty\mpu6xxx文件夹下的sensor_inven_mpu6xxx.c,mpu6xxx.c文件中,通过统一的sensors框架进行封装,用户可以通过sensors框架提供的外层接口直接获得传感器检测到的数据。

7.4 编译运行

7.4.1 STM32CubeMX配置

万耦开发板传感器实验中,传感器均采用软件模拟i2c的方式实现交互,因此,不必在STM32CubeMX中进行i2c的硬件配置。

7.4.2 OnsOS-Cube配置

1、配置模拟I2C的引脚信息,万耦开发板中,传感器设备都使用i2c3接口。

如图,在Drivers → I2C路径下,需要使能i2c设备驱动,勾选使用模拟i2c,设置i2c总线延时(调节软件i2c的频率)并使能i2c3总线。

2、配置模拟i2c管脚。

3、在 Drivers→ Sensors→ Using sensor device drivers → Enable ap3216c路径下,以打开光感传感器配置,配置传感器使用的i2C接口为soft_I2c3,地址是0x1e。

同理,配置AHT10传感器:

ICM20602传感器配置稍微有所区别,其配置方式如下图所示:

使用Q退出,然后选中Y保存配置。

7.4.3 生成MDK工程

完成OnsOS-Cube配置后,使用scons指令:scons --ide=mdk5编译生成mdk5工程。

7.4.4 运行

1、使用keil5打开工程project.uvprojx ,编译下载程序;

2、添加传感器测试代码;

3、编译成功后烧写到设备,连接串口到电脑,打开串口工具;

输入help指令,可看到此时多了传感器的测试指令。

sh>help
OneOS shell commands:
sensor_acce_test - sensor_acce_test
sensor_alti_test - sensor_alti_test
sensor_baro_test - sensor_baro_test
sensor_gyro_test - sensor_gyro_test
sensor_humi_test - sensor_humi_test
sensor_light_test - sensor_light_test
sensor_temp_test - sensor_temp_test
device           - show device information
pinMode          - set hardware pin mode
pinWrite         - write value to hardware pin
pinRead          - read status from hardware pin
event            - show event information
mb               - show mailbox information
memp             - show memory pool information
mem              - show memory usage information
mq               - show message queue information
mutex            - show mutex information
sem              - show semaphore information
task             - show task information
timer            - show timer information
version          - show oneos version
help             - Obtain help of commands
sh>

通过指令查看设备,此时能看到已经配置好的soft_i2c3总线与传感器:

sh>device
device                  type         ref count
--------------- -------------------- ----------
gyro_icm20602   Sensor Device        0
acce_icm20602   Sensor Device        0
pr_ap3216c      Sensor Device        0
li_ap3216c      Sensor Device        0
humi_aht10      Sensor Device        0
temp_aht10      Sensor Device        0
soft_i2c3       I2C Bus              0
iwdg            Miscellaneous Device 0
rtc             RTC                  0
uart3           Character Device     2
uart2           Character Device     0
uart1           Character Device     0
uart4           Character Device     0
pin_0           Miscellaneous Device 0
sh>

4、输入传感器测试指令;

如下所示,用手电照射光强传感器时,随着距离接近,光照更强,读数变大。

sh>sensor_light_test ap3216c
sensor light (182.700)
sensor light (180.600)
sensor light (177.100)
sensor light (179.200)
sensor light (211.750)
sensor light (246.050)
sensor light (300.650)
sensor light (427.350)
sensor light (488.250)
sensor light (564.200)
sh>

如下所示,当将手指放在温湿度传感器上时(或对着温度传感器呼气),温度会有缓慢升高。

sh>sensor_temp_test aht10
sensor temp (24.841)
sensor temp (24.860)
sensor temp (25.620)
sensor temp (26.413)
sensor temp (26.943)
sensor temp (27.363)
sensor temp (27.720)
sensor temp (27.937)
sensor temp (27.755)
sensor temp (27.505)
sh>

传感器测试较多,此处不一一列举。

7.5 注意事项

7.5.1 硬件I2C配置

本章节使用的是软件模拟I2C,如果需要使用硬件I2C,则需要配置STM32CubeMX;

同时,OnsOS-Cube的配置方式也有所不同,如下:

7.5.2 管脚编号

在本章7.4.2小结中,配置了I2C3的SCL与SDA引脚编号,此编号与实际引脚名称的对应关系如下表:

MCU管脚 编号
PA0 0
PA1 1
... ...
PA15 15
PB0 16
PB15 31
PC0 32
PC15 47
PD0 48
PD15 63
PE0 64
PE15 79
PF0 80
... ...

PA0对应编号0 ,PA1对应编号1,后面管脚号以此类推。

7.5.3 传感器供电

默认情况下,在STM32CubeMX中对万耦开发板传感器供电引脚进行了配置,生成了相关的代码,不需要用户额外增加控制代码。

sensor_power_cubemx

注:音频,WIFI模组,4G模组等器件的供电控制方式和传感器采用相同的方式,后续文档不会再单独进行说明。

第八章 红外发送和接收实验

8.1 简介

本实验通过开发板上的红外发送和接收装置实现红外的发送和接收,其原理是通过GPIO外部中断,记录红外信号上、下边沿的时间戳,然后根据高低脉冲宽度,解码出红外信息,实现红外通信功能。

8.2 硬件说明

红外的发送和接收电路图如下:

infrared_schematic1

infrared_schematic2

红外接收和发送引脚连接到了MCU的引脚上。

infrared_schematic3

管脚定义和作用:

名称 管脚 作用
RECEPTION_OUT PB1 红外接收器
EMISSION PB0 红外发送器

红外发送器和接收器在开发板中的位置:

infrared_board

8.3 软件说明

红外设备的测试代码位于demos\driver\infrared_test.c中,其创建了一个红外接收任务处理红外信号的接收与解析。

static void infrared_recv_task(void *parameter)
{
    os_device_t *infrared;
    struct os_infrared_info info;
    int infrared_rx_count = 0;

    infrared = os_device_find("atk_rmt");
    OS_ASSERT(infrared);

    os_device_open(infrared);

    while (1)
    {
#ifdef INF_READ_BLOCK
        os_device_read_block(infrared, 0, &info, sizeof(info));
#else
        if (os_device_read_nonblock(infrared, 0, &info, sizeof(info)) != sizeof(info))
        {
            os_task_msleep(100);
            continue;
        }
#endif
        LOG_I(DBG_TAG,"infrared_rx_done(%d) addr: %02x, data: %02x", ++infrared_rx_count, info.addr, info.data);
    }
}

static int infrared_recv_test(void)
{
    os_task_t *task;

    task = os_task_create("ir_recv", infrared_recv_task, NULL, 2048, 3);
    OS_ASSERT(task);
    os_task_startup(task);

    return 0;
}

static int infrared_send_test(int argc, char **argv)
{
    os_uint8_t addr = 0x5a;
    os_uint8_t data = 0x3c;
    int i, repeat, loops = 1;

    if (argc == 1 || (argc == 2 && !strcmp(argv[1], "help")))
    {
        LOG_I(DBG_TAG,"usage:");
        LOG_I(DBG_TAG,"infrared_send_test [addr] [data] [repeat] [loops]");
        return 0;
    }

    if (argc > 1)
    {
        addr = strtol(argv[1], NULL, 0);
    }

    if (argc > 2)
    {
        data = strtol(argv[2], NULL, 0);
    }

    if (argc > 3)
    {
        repeat = strtol(argv[3], NULL, 0);
    }

    if (argc > 4)
    {
        loops = strtol(argv[4], NULL, 0);
    }

    os_device_t *infrared;
    struct os_infrared_info info;

    infrared = os_device_find("atk_rmt");
    OS_ASSERT(infrared);

    os_device_open(infrared);

    os_task_t *self = os_task_self();
    os_uint8_t task_prio = os_task_get_priority(self);
    os_uint8_t high_prio = 1;    
    os_task_set_priority(self, high_prio);

    for (i = 0; i < loops; i++)
    {
        os_task_msleep(1000);

        info.addr  = addr;
        info.data  = data + i;
        info.times = repeat;

#ifdef INF_WRITE_BLOCK
        os_device_write_block(infrared, 0, &info, sizeof(info));
#else
        while (os_device_write_nonblock(infrared, 0, &info, sizeof(info)) != sizeof(info));
#endif
    }

    os_device_close(infrared);

    os_task_set_priority(self, task_prio);

    return 0;
}

SH_CMD_EXPORT(infrared_recv_test, infrared_recv_test, "infrared_recv_test");
SH_CMD_EXPORT(infrared_send_test, infrared_send_test, "infrared_send_test");

8.4 编译运行

8.4.1 STM32CubeMX配置

因为红外传感器使用到的是GPIO接口较为简单,所以不必单独使用STM32CubeMX进行配置,只需保证相应引脚不被占用即可。

8.4.2 OnsOS-Cube配置

Drivers→ Infrared路径下,配置红外设备的信息;

同时,还需要配置红外接收与发送引脚。

1)配置发送引脚:

2)配置接收引脚:

使用Q退出,然后选中Y保存配置。

8.4.3 scons编译

完成OnsOS-Cube配置后,使用scons指令scons --ide=mdk5编译生成keil工程。

8.4.4 运行

1、使用keil5打开工程project.uvprojx ;

2、添加红外测试代码;

3、编译成功后烧写到设备,连接串口到电脑,打开串口工具;

输入infrared_test运行测试程序,使用红外遥控器对着开发板上的红外接收器按下按钮(或者直接在命令行中输入infrared_send_test 命令),红外接收器接收到信号后打印出相应结果。

sh>infrared_recv_test
[2473] I/infrared: infrared start receive [infrared_recv_init][303]
[66022] I/infrared_test: usage: [infrared_send_test][71]
[66022] I/infrared_test: infrared_send_test [addr] [data] [repeat] [loops] [infrared_send_test][72]
sh>infrared_send_test 0 100 1
sh>[3147] I/infrared_test: infrared_rx_done(1) addr: 00, data: 64 [infrared_recv_task][48]
[3148] I/infrared_test: infrared_rx_done(2) addr: 00, data: 64 [infrared_recv_task][48]
sh>infrared_send_test 0 60 1
sh>[62551] I/infrared_test: infrared_rx_done(3) addr: 00, data: 3c [infrared_recv_task][48]
[62552] I/infrared_test: infrared_rx_done(4) addr: 00, data: 3c [infrared_recv_task][48]

8.5 注意事项

在使用红外接收器时,因为其接收特性,需要将dlog的选项调整一下,否则无法在控制台中看见红外打印信息。

在Debug路径下,需要打开 Debug功能。

在Components→ Dlog下,调整记录等级为Information。

第九章 LCD显示实验

9.1 简介

本实验主要介绍了如何在万耦开发板上使用 LCD。

9.2 硬件说明

万耦开发板板载一块1.3寸的LCD显示屏,分辨率为240*240,显示效果十分细腻。显示屏的驱动芯片是ST7789,通过4-line SPI接口和单片机进行通讯。如图,LCD屏幕通过J8转接口连接到开发板上,因为只需要往LCD写数据而不需要读取,所以可以不接 MISO 引脚。

lcd_hardware

如电路原理图,处理器通过图示管脚来控制LCD,每个管脚作用如下表:

名称 管脚 作用
TFT_SPICLK PA5 SP1时钟信号
TFT_SPIMOSI PA7 SPI1数据信号
TFT_RES PA6 LCD复位信号
TFT_DC PD11 LCD命令/数据选择信号
TFT_BLK PA4 LCD背光控制信号

9.3 软件说明

测试代码位于driver/graphic/graphic.c中,如下:

static os_err_t graphic_test(int argc, char **argv)
{
    if (argc != 2)
    {
        os_kprintf("usage: graphic_test <dev> \r\n");
        os_kprintf("       graphic_test lcd \r\n");
        return -1;
    }

    os_device_graphic_t *graphic;
    graphic = (os_device_graphic_t *)os_device_find(argv[1]);

    if (graphic == NULL || graphic->parent.type != OS_DEVICE_TYPE_GRAPHIC)
    {
        os_kprintf("invalide graphic device [%s].\r\n", argv[1]);
        return OS_EINVAL;
    }

    if (graphic->info.pixel_format == OS_GRAPHIC_PIXEL_FORMAT_ARGB888)
    {
        return graphic_test_888(graphic);
    }

    if (graphic->info.pixel_format == OS_GRAPHIC_PIXEL_FORMAT_RGB565)
    {
        return graphic_test_565(graphic);
    }

    return OS_EINVAL;
}

SH_CMD_EXPORT(graphic_test, graphic_test, "graphic_test");

9.4 编译运行

9.4.1 STM32CubeMX配置

由原理图可知,万耦开发板中LCD显示屏用到了SPI1作为交互的接口,因此在STM32CubeMX只对SPI1进行配置即可。

如下图,可将SPI1的模式设置为Half-Duplex Master模式。

SPI1的基本参数设置。

9.4.2 OnsOS-Cube配置

使用LCD屏幕前需要进行如下配置:

首先,需要在Drivers→ Graphic路径下,选择使用图像设备驱动。

然后,在显示设备中对LCD 驱动芯片st7789进行配置,其路径:Drivers -> Graphic ->Using Graphic devices ->Use st7789。

选中后使用Q退出,然后选中Y保存配置

9.4.3 生成MDK工程

完成OnsOS-Cube配置后,使用scons指令:scons --ide=mdk5编译生成mdk5工程。

9.4.4 运行

1、使用keil5打开工程project.uvprojx ,编译下载程序。

2、输入图形设备的测试指令后,LCD以红,绿,蓝等颜色进行刷屏。

graphic_test
sh />graphic_test
usage: graphic_test <dev>
       graphic_test lcd
sh />graphic_test lcd
red
green
blue
black
white
sh />

9.5 注意事项

1、LCD连接到开发板的SPI片选信号内部拉低(低电平有效),因此没有将SPI片选信号外接出来。

2、屏幕的分辨率是240*240,输入位置参数时要注意小于240,不然会出现无法显示的现象。

3、图像的取模方式为自上而下,自左向右,高位在前,16位色(RGB-565)。

第十章 USB鼠标实验

10.1 简介

本实验使用万耦开发板USB设备接口连接PC机,并将开发板设备作为鼠标进而控制桌面鼠标移动,并可使用按键模拟鼠标的左键和右键。

10.2 硬件说明

本实验主要用到的是USB接口,其硬件设计如下图所示:

usb_hardware

名称 管脚 作用
USB_DM PA11 USB DM引脚
USB_DP PA12 USB DP引脚

USB设备接口在开发板上的位置:

usb_otg_position

10.3 软件说明

USB鼠标测试代码位于demos\driver\usbd_hid_test.c中,运行测试代码后,桌面鼠标光标会按矩形路径自动移动5圈,在此期间按下相应的按键,可起到鼠标按键的效果。

static int usbd_hid_test(int argc, char **argv)
{
    int          i, j;
    os_device_t *device = os_device_find("hidd");
    OS_ASSERT(device != OS_NULL);
    os_device_open(device);

    /* Mouse left button */
    if (key_table_size > 0)
    {
        os_pin_mode(key_table[0].pin, key_table[0].mode);
        os_pin_attach_irq(key_table[0].pin, key_table[0].irq_mode, left_callback, NULL);
        os_pin_irq_enable(key_table[0].pin, PIN_IRQ_ENABLE);
    }

    /* Mouse right button */
    if (key_table_size > 1)
    {
        os_pin_mode(key_table[1].pin, key_table[1].mode);
        os_pin_attach_irq(key_table[1].pin, key_table[1].irq_mode, right_callback, NULL);
        os_pin_irq_enable(key_table[1].pin, PIN_IRQ_ENABLE);
    }

    for (j = 0; j < 5; j++)
    {
        os_kprintf("loop %d/5\r\n", j + 1);

        for (i = 0; i < 20; i++)
        {
            x = 10;
            y = 0;
            update_mouse(device);
            os_task_msleep(100);
        }

        for (i = 0; i < 20; i++)
        {
            x = 0;
            y = 10;
            update_mouse(device);
            os_task_msleep(100);
        }

        for (i = 0; i < 20; i++)
        {
            x = -10;
            y = 0;
            update_mouse(device);
            os_task_msleep(100);
        }

        for (i = 0; i < 20; i++)
        {
            x = 0;
            y = -10;
            update_mouse(device);
            os_task_msleep(100);
        }
    }

    return 0;
}

SH_CMD_EXPORT(usbd_hid_test, usbd_hid_test, "usbd_hid_test");

10.4 编译运行

10.4.1 STM32CubeMX配置

1、使能USB接口并配置USB接口模式,引脚;

2、配置USB接口的基本参数;

3、配置USB接口中断。

10.4.2 OnsOS-Cube配置

在Drivers→ USB路径下配置好USB设备,具体配置如下图所示:

10.4.3 生成MDK工程

完成OnsOS-Cube配置后,使用scons指令:scons --ide=mdk5编译生成mdk5工程。

10.4.4 运行

1、使用keil5打开工程project.uvprojx ;

2、添加USB的测试代码;

3、编译下载,运行代码;

4、打开PC机设备管理器,此时,可看到有两个鼠标设备;

usb_setup

5、执行测试代码,此时鼠标会自动开始在屏幕上沿顺时针方向矩形运动。在循环中按下KEY1相当于按下了鼠标左键,按下KEY2相当于按下了鼠标右键。

sh>usbd_hid_test
loop 1/5
left button click
right button click
loop 2/5
loop 3/5
loop 4/5
loop 5/5

10.5注意事项

若PC电脑未识别到USB设备,可尝试将开发板重新上电。

第十一章 FAL读写FLASH实验

11.1 简介

本实验通过FAL软件包对Flash进行分区管理操作。通过调用FAL接口完成了对指定分区的测试工作,完成了对Flash读、写、擦的测试,同时也通过本实验完成了对Flash驱动的基本测试。

11.2 硬件说明

本开发板在核心板上外拓展了一块W25Q64的flash芯片,大小为8MB,通过QSPI1接口与处理器相连。

QSPI_FLASH_schematic

如电路原理图,各个管脚作用如下表:

名称 管脚 作用
QSPI1_BK1_NCS PE11 QSP1时钟信号
QSPI1_BK1_IO1 PE13 QSPI1数据信号
QSPI1_BK1_IO0 PE12 LCD复位信号
QSPI1_BK1_CLK PE10 LCD命令/数据选择信号
QSPI1_BK1_IO3 PE15 QSPI1数据信号
QSPI1_BK1_IO2 PE14 QSPI1数据信号

11.3 软件说明

本实验包含QSPI接口、fal软件包、sfud库。fal软件包统一管理片内和片外flash,通过sfud使用QSPI接口对接片外flash。用户可以通过fal便捷的管理flash,客户如果基于框架进行自己开发其他flash芯片时需要注意flash芯片是否被sfud支持,详细的实现过程请查看源码中的fal和sfud软件包。

fal测试代码fal_test.c在demos\driver目录下。

static void fal(int argc, char **argv)
{
    if (argc < 3)
    {
help:
        os_kprintf("\r\n");
        os_kprintf("fal [OPTION] [PARAM ...]\r\n");
        os_kprintf("    read       <part> <off> <len>  Read <len> Bytes from <off> of <part>\r\n");
        os_kprintf("    write      <part> <off> <len>  Write <len> Bytes from <off> of <part>\r\n");
        os_kprintf("    erase      <part> <off> <len>  Erase <len> Bytes from <off> of <part>\r\n");
        os_kprintf("    eraseall   <part>              Erase all data on <part>\r\n");
        os_kprintf("    write_read <part> <off> <len>  Write & Read <len> Bytes from <off> of <part>\r\n");
        os_kprintf("    lock       <part>              Lock <part>\r\n");
        os_kprintf("    unlock     <part>              Unlock <part>\r\n");
        os_kprintf("    mount      <part> [dir] [fs]   Mount <part> [/] [fat, jffs2]\r\n");
        return;
    }

    if (!strcmp(argv[1], "read"))
    {
        if (argc < 5)
        {
            os_kprintf("The input parameters are too few!\r\n");
            goto help;
        }
        fal_read(argv[2], strtol(argv[3], NULL, 0), strtol(argv[4], NULL, 0));
    }
    else if (!strcmp(argv[1], "write"))
    {
        if (argc < 5)
        {
            os_kprintf("The input parameters are too few!\r\n");
            goto help;
        }
        fal_write(argv[2], strtol(argv[3], NULL, 0), strtol(argv[4], NULL, 0));
    }
    else if (!strcmp(argv[1], "erase"))
    {
        if (argc < 5)
        {
            os_kprintf("The input parameters are too few!\r\n");
            goto help;
        }
        fal_erase(argv[2], strtol(argv[3], NULL, 0), strtol(argv[4], NULL, 0));
    }
    else if (!strcmp(argv[1], "eraseall"))
    {
        fal_erase_all(argv[2]);
    }
    else if (!strcmp(argv[1], "write_read"))
    {
        if (argc < 5)
        {
            os_kprintf("The input parameters are too few!\r\n");
            goto help;
        }
        fal_write_read(argv[2], strtol(argv[3], NULL, 0), strtol(argv[4], NULL, 0));
    }
    else if (!strcmp(argv[1], "lock"))
    {
        fal_lock(argv[2]);
    }
    else if (!strcmp(argv[1], "unlock"))
    {
        fal_unlock(argv[2]);
    }
    else if (!strcmp(argv[1], "mount"))
    {
        const char *dir = "/";
        const char *fs  = "fat";

        if (argc >= 4)
            dir = argv[3];

        if (argc >= 5)
            fs = argv[4];

        fal_mount(argv[2], dir, fs);
    }
    else
    {
        os_kprintf("Input parameters are not supported!\r\n");
        goto help;
    }
}

SH_CMD_EXPORT(fal, fal, "fal test");

11.4 编译运行

11.4.1 STM32CubeMX配置

配置QSPI接口模式与引脚。

配置QSPI基本参数。

11.4.2 OnsOS-Cube配置

  1. 配置flash相关接口

​ 在Drivers → SPI路径下,使能QSPI模式,以及其他相关信息。

  1. 配置QSPI总线

​ 在Using QSPI mode support路径下配置总线名称。

  1. 配置片外flash信息

​ 在 Extern flash sfud port cfg路径下配置FLASH的信息。

  1. 配置使能FAL工具

  1. 勾选MTD设备

mtd_oscube

最后使用Q退出,然后选中Y保存配置。

11.4.3 生成MDK工程

完成OnsOS-Cube配置后,使用scons指令:scons --ide=mdk5编译生成keil工程。

11.4.4 运行

1、使用keil5打开工程project.uvprojx ,编译下载程序。 2、添加flash测试代码。 3、编译下载,运行代码。

系统启动时,可看见外部flash已经添加到FAL TABLE中。

sh>[0] W/STARTUP: OneOS kernel start, version: Kernel-V2.0.1-20210118 [_k_startup][251]
[SFUD] Warning: The OS tick(100) is less than 1000. So the flash write will take more time.
[SFUD] Find a Winbond flash chip. Size is 8388608 bytes.
[SFUD] W25Q64 flash device is initialize success.
==================== FAL partition table ====================
| name       | flash_dev    |   offset   |    length  |
-------------------------------------------------------------
| bootloader | onchip_flash | 0x00000000 | 0x00010000 |
| cfg        | onchip_flash | 0x00010000 | 0x00010000 |
| app        | onchip_flash | 0x00020000 | 0x00040000 |
| download   | onchip_flash | 0x00060000 | 0x00020000 |
| diff_patch | nor_flash    | 0x00000000 | 0x00100000 |
| backup     | nor_flash    | 0x00100000 | 0x00100000 |
| easyflash  | nor_flash    | 0x00200000 | 0x00080000 |
| wifi_image | nor_flash    | 0x00280000 | 0x00080000 |
| font       | nor_flash    | 0x00300000 | 0x00300000 |
| filesystem | nor_flash    | 0x00600000 | 0x00200000 |
=============================================================

sh>

4、使用fal测试指令对flash进行读写。

测试时,可先使用read读出一段flash的值,再进行write操作(需要确认当前段是否可进行write),然后回读查看write是否成功。最后,对其进行erase后再回读,查看erase是否成功。

sh>fal
fal [OPTION] [PARAM ...]
    read       <part> <off> <len>  Read <len> Bytes from <off> of <part>
    write      <part> <off> <len>  Write <len> Bytes from <off> of <part>
    erase      <part> <off> <len>  Erase <len> Bytes from <off> of <part>
    eraseall   <part>              Erase all data on <part>
    write_read <part> <off> <len>  Write & Read <len> Bytes from <off> of <part>
    lock       <part>              Lock <part>
    unlock     <part>              Unlock <part>
    mount      <part> [dir] [fs]   Mount <part> [/] [fat, jffs2]
sh>
sh />fal read font 0 100
part page size: 0x1000, erase size:0x1000, size:0x300000
read offset:0x0 count=100/100
read success
00000000: ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
00000010: ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
00000020: ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
00000030: ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
00000040: ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
00000050: ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
00000060: ff ff ff ff

sh />fal write font 0 100
part page size: 0x1000, erase size:0x1000, size:0x300000
write offset:0x0 count=100/100
write success

sh />fal read font 0 100
part page size: 0x1000, erase size:0x1000, size:0x300000
read offset:0x0 count=100/100
read success
00000000: 00 01 02 03 04 05 06 07  08 09 0a 0b 0c 0d 0e 0f
00000010: 10 11 12 13 14 15 16 17  18 19 1a 1b 1c 1d 1e 1f
00000020: 20 21 22 23 24 25 26 27  28 29 2a 2b 2c 2d 2e 2f
00000030: 30 31 32 33 34 35 36 37  38 39 3a 3b 3c 3d 3e 3f
00000040: 40 41 42 43 44 45 46 47  48 49 4a 4b 4c 4d 4e 4f
00000050: 50 51 52 53 54 55 56 57  58 59 5a 5b 5c 5d 5e 5f
00000060: 60 61 62 63


sh />fal erase font 0 4096
part page size: 0x1000, erase size:0x1000, size:0x300000
erase success

sh />fal read font 0 100
part page size: 0x1000, erase size:0x1000, size:0x300000
read offset:0x0 count=100/100
read success
00000000: ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
00000010: ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
00000020: ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
00000030: ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
00000040: ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
00000050: ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
00000060: ff ff ff ff

11.5 注意事项

1、擦除flash内容时,注意相关芯片的长度要求,否则会擦除失败。

2、本实验既可对片外flash进行读写、擦除,也可以对片内flash进行操作,只是用户需要注意FAL TABLE分区的边界,以免擦除到了程序内容,导致系统崩溃。

第十二章 TF卡挂载文件系统实验

12.1 简介

本实验将开发板上TF卡槽中的TF卡作为文件系统的存储设备,展示如何在TF卡上创建文件系统(格式化卡),并挂载文件系统到OneOS物联网操作系统中,实现对TF卡的文件管理。

12.2 硬件说明

TF卡使用SPI口与处理器相连,硬件连接如图:

TFcard_schematic

各管脚作用如下表:

名称 管脚 作用
NRF_CS PB12 SPI2片选信号
SPI2_MOSI PB15 SPI2数据信号
SPI2_SCK PB13 SPI2时钟信号
SPI2_MISO PB14 SPI2数据信号
NRF_CE PB11 TF卡使能信号

12.3 软件说明

1、在挂载文件系统之前,需要先创建SD卡块存储设备。

sd0是基于spi2设备而创建的,创建块设备的代码在drivers/spi_tfcard.c文件中。msd_init函数会在spi_tfcard设备上进行探测,并基于该设备创建名为sd0的块设备,用于文件系统的挂载,代码如下所示:

static int os_hw_spi_tfcard(void)
{
    os_hw_spi_device_attach(BSP_SDCARD_SPI_DEV, "spi_tfcard", BSP_SDCARD_SPI_CS_PIN);
    return msd_init("sd0", "spi_tfcard");
}
OS_CMPOENT_INIT(os_hw_spi_tfcard);

2、可通过以下示例代码将块设备sd0中的文件系统以fatfs文件系统格式挂载到根目录”/“上,代码路径demos\driver\sdmmc_test.c。

int sdmmc_test( void )
{     
    /* mount the file system from tf card */
    if (vfs_mount("sd0", "/", "fat", 0, 0) == 0)
    {
        os_kprintf("Filesystem initialized!\n");
    }
    else
    {
        os_kprintf("Failed to initialize filesystem!\n");
    }

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

12.4 编译运行

12.4.1 STM32CubeMX配置

根据硬件设计原理图可知,SPI2需要配置为全双工模式,如下图所示:

SPI2的的参数配置参考SPI1,一般保持默认即可。

12.4.2 OnsOS-Cube配置

1、Drivers→ SPI路径下配置TF卡SPI2接口与相关设置。

2、Drivers→ SPI→ Enable SDCARD (SPI)路径下,配置TF卡的SPI总线名称与片选信号。

3、进入组件配置界面,在虚拟文件系统中使能fat,并进行相关属性配置,如分卷大小为4096。

FAT相关配置:

12.4.3 生成MDK工程

完成OnsOS-Cube配置后,使用scons指令:scons --ide=mdk5编译生成mdk5工程。

12.4.4运行

1、使用keil5打开工程project.uvprojx ;

2、添加测试代码;

3、编译下载,运行程序;

4、输入sdmmc_test测试指令,系统打印文件系统初始化完成,输入ls指令,可查看当前sd卡中的内容。

sh />sdmmc_test
Filesystem initialized!
sh />ls
Directory /:
System Volume Information<DIR>
3.wav               43159596
fei.wav             14018886
lin.wav             52616064
liu.wav             37643974
test.wav            321324
test.wv             0
test1.wav           231468
test2.wav           231468
zhang.wav           38382556
zhou.wav            50883344
MUSIC               <DIR>
RECORDER            <DIR>
1.wav               52616064
2.wav               43159596
sh />

12.5 注意事项

如果是初次使用TF卡,那在挂载文件系统之前需要将 TF 卡被格式化为 Fat 文件系统,否则会挂载失败。

第十三章 音频播放器与录音机实验

13.1简介

万耦 STM32L475 开发板拥有串行音频接口(SAI),支持 I2S、LSB/MSB 对其、PCM/DSP、TDM 等协议,同时开发板集成了一颗高性能的音频编解码器ES8388,支持最高 96KHz 24BIT 的音频播放,并且支持录音。本实验将会就如何在OneOS中配置,使用播放器播放音乐、录音机录音功能进行说明。

13.2硬件说明

查看原理图可知,STM32L475处理器通过SAI1接口连接到音频编解码器ES8388,实现音频数据的交互,同时通过i2c3总线访问ES8388的寄存器,实现解码芯片相关的初始化与控制功能。

audio_hardware

音频编解码芯片的供电。

audio_power_hardware

管脚信息:

名称 管脚 作用
SAI1_MCLK_A PE2 主时钟信号
SAI1_SD_B PE3 录音通道
SAI1_FS_A PE4 采样时钟
SAI1_SCK_A PE5 位时钟
SAI1_SD_A PE6 播放通道
Audio_POWER PD15 音频编解码芯片供电控制

13.3软件说明

音频测试代码分为播放器测试audio_wav_player_test.c与录音机测试audio_wav_recorder_test.c两个部分,用户可根据需求进行添加。

void wavplay_sample_task(void *parameter)
{
    int fd = -1;
    int count, index;
    int length;
    uint8_t *buffer = NULL;
    struct wav_info *info = NULL;
    struct os_audio_caps caps = {0};
    os_device_t *snd_dev;

    fd = open(media_name, O_RDONLY);
    if (fd < 0)
    {
        os_kprintf("open file failed!\r\n");
        goto __exit;
    }

    buffer = os_calloc(1, BUFSZ);
    if (buffer == OS_NULL)
        goto __exit;

    info = (struct wav_info *) os_calloc(1, sizeof * info);
    if (info == OS_NULL)
        goto __exit;

    if (read(fd, &(info->header), sizeof(struct RIFF_HEADER_DEF)) <= 0)    
        goto __exit;
    if (read(fd, &(info->fmt_block),  sizeof(struct FMT_BLOCK_DEF)) <= 0)
        goto __exit;
    if (read(fd, &(info->data_block), sizeof(struct DATA_BLOCK_DEF)) <= 0)
        goto __exit;

    os_kprintf("wav information:\r\n");
    os_kprintf("samplerate %d\r\n", info->fmt_block.wav_format.SamplesPerSec);
    os_kprintf("channel %d\r\n", info->fmt_block.wav_format.Channels);

    snd_dev = os_device_find(SOUND_DEVICE_NAME);
    OS_ASSERT(snd_dev != OS_NULL);

    os_device_open(snd_dev);

    /* parameter settings */
    caps.config_type = AUDIO_PARAM_CMD;
    caps.udata.config.samplerate = info->fmt_block.wav_format.SamplesPerSec;
    caps.udata.config.channels   = info->fmt_block.wav_format.Channels;
    os_device_control(snd_dev, AUDIO_CTL_CONFIGURE, &caps);
    caps.config_type = AUDIO_VOLUME_CMD;
    caps.udata.value = 35;
    os_device_control(snd_dev, AUDIO_CTL_CONFIGURE, &caps);

    while (1)
    {
        length = read(fd, buffer, BUFSZ);

        if (length <= 0)
            break;

        index = 0;

        while (index < length)
        {
#ifndef AUDIO_WRITE_NONBLOCK
            count = os_device_write_block(snd_dev, 0, buffer + index, length - index);
#else
            count = os_device_write_nonblock(snd_dev, 0, buffer + index, length - index);
#endif

            if (count <= 0)
                continue;

            index += count;
        }
    }

    os_device_close(snd_dev);

    os_kprintf("end of audio playing!\r\n");

__exit:

    if (fd >= 0)
        close(fd);

    if (buffer)
        os_free(buffer);

    if (info)
        os_free(info);

    media_name[0] = 0;
}

int wavplay_sample(int argc, char **argv)
{
    os_task_t *task;

    if (argc != 2)
    {
        os_kprintf("Usage:\r\n");
        os_kprintf("wavplay_sample song.wav\r\n");
        return 0;
    }

    if (media_name[0] != 0)
    {
        os_kprintf("player thread running...\r\n");
        return 0;
    }

    snprintf(media_name, sizeof(media_name) - 1, "%s", argv[1]);

    task = os_task_create("media_player", wavplay_sample_task, NULL, 4096, 5);
    OS_ASSERT(task);
    os_task_startup(task);
    return 0;
}


SH_CMD_EXPORT(wav_player, wavplay_sample, "play wav file in task");

由于测试代码行数较多,录音机实验代码不在展示,详见代码。

13.4编译运行

13.4.1 STM32CubeMX配置

  1. 配置SAI的模式与基本参数

​ 通过原理图分析可知,SAI A作为播放通道,SAI B作为录音通道,且STM32L475需要输出时钟给ESP8388,因此,SAI A设置为主模式且输出时钟,SAI B设置为同步,从模式。

aduio_cubemx1

  1. 配置DMA

​ 因为音频处理的特性,两个数据通道均需要使用DMA,且设置为循环模式。

audio_cubemx2

  1. 检查GPIO引脚是否与原理图一致

audio_cubemx3

13.4.2 OnsOS-Cube配置

用户使用音频功能时,需要在Drivers→ Audio→ Using audio device drivers路径下进行配置。

  1. 使用音频相关的驱动

​ 音频相关的驱动可大致分为音频设备层数据缓存配置,数据通道驱动层配置和编解码芯片配置三个层级。

audio_oscube1

  1. 配置音频设备数据缓存

​ 如下,可将音频播放数据缓存配置为2块,每块大小为2048Byte。音频播放设置为2块,每块大小为3528Byte(44.1khz录音20ms数据量)。

audio_oscube2

  1. 配置数据通道驱动

​ 因为万耦STM32L475开发板采用的是SAI方式,所以此处使能SAI驱动。如是I2S接口,则选择I2S驱动。

audio_oscube3

  1. 配置编解码芯片

​ 1)配置编解码芯片的控制总线

​ 由硬件原理图可知,其控制总线是i2c3。

audio_oscube5

​ 2)配置编解码芯片数据通道

audio_oscube6

退出并保存配置。

13.4.3 生成MDK工程

完成OnsOS-Cube配置后,使用scons指令:scons --ide=mdk5编译生成mdk5工程。

13.4.4运行

1、进入工程目录,双击project.uvprojx打开工程 ;

2、添加tf内存卡与音频测试文件;

3、编译下载,运行程序;

4、输入tf卡测试程序,挂载文件系统;

5、输入音频测试指令。

如下,先使用录音机录制了一段名为r513.wav的音频文件,然后使用播放器播放。

sh />wav_recorder
Usage:
wavplay_sample song.wav
sh />
sh />wav_player
Usage:
wavplay_sample song.wav

wav_recorder
sh />wav_recorder r513.wav
sh />
sh />end of audio recording!

wav_player
sh />wav_player r513.wav
wav information:
samplerate 44100
channel 2
sh />end of audio playing!

13.5 注意事项

1、使用音频功能,因为需要读取或者存储大量数据,首先需要将TF卡与文件系统相关的驱动使能。

2、当前音频功能只支持.wav格式的音频文件处理。

3、频播放器目前只支持播放,停止,调节音量大小功能,暂不支持暂停功能。

第十四章 WIFI模组联网实验

14.1 简介

本实验将展示如何使用OneOS的网络组件Molink来实现WIFI模组ESP8266联网的功能。

14.2 硬件说明

WIFI模组主要是通过串口与万耦开发板进行交互。

wifi_hardware

WIFI模组供电:

wifi_power_hardware

各管脚作用如下表:

名称 管脚 作用WIFI
WIFI_POWER PC6 WIFI模组电源控制引脚
WIFI_UART_TX PA10 WIFI模组串口发送引脚
WIFI_UART_RX PA9 WIFI模组串口接收引脚

注:其余管脚暂时未使用。

14.3 软件说明

具体请查看Molink组件相关设计文档。

14.4 编译运行

14.4.1 STM32CubeMX配置

根据硬件设计原理图可知,WIFI模组使用的串口是串口1,因此需要在CubeMX中将串口1配置好,具体配置方式参考前文。

14.4.2 OnsOS-Cube配置

WIFI模组的Molink (Module link kit) - 模组连接套件

在Components→ Network→ Molink路径下配置WIFI模组。

wifi_oscube_1

  1. 配置WIFI模组ESP8266

​ 主要需要配置串口设备名称与波特率,需要连接WIFI的名称(AP SSID)和密码(AP Password)。

wifi_oscube_2

  1. 配置AT模组调试功能

​ Tools下调试功能不打开,就无法使用“ifconfig”与“ping”指令进行简单的网络测试与状态查看。

wifi_oscube_3

退出并保存配置。

14.4.3 生成MDK工程

完成OnsOS-Cube配置后,使用scons指令:scons --ide=mdk5编译生成mdk5工程。

14.4.4 运行

1、使用keil5打开工程project.uvprojx ,编译下载程序;

2、运行程序后,在控制台中,输入ifconfig指令,查看网络连接状态;

sh />ifconfig

LIST AT MODULE INFORMATION
--------------------------------------------------------------------------------
Module   Name    : esp8266
WiFi     Mode    : Station
WiFi     Status  : Connected
STA IPv4 Address : 192.168.43.210
--------------------------------------------------------------------------------
sh />

3、输入ping指令,测试网络连接。

sh />ping
Please input: ping <host address> <times[1,50]> <pkg_size> <timeout(sec)>

sh />ping www.baidu.com 10
[0] 32 bytes from 39.156.66.14 icmp_seq=0 time=71 ms
[1] 32 bytes from 39.156.66.18 icmp_seq=1 time=335 ms
[2] 32 bytes from 39.156.66.14 icmp_seq=2 time=142 ms
[3] 32 bytes from 39.156.66.18 icmp_seq=3 time=111 ms
[4] 32 bytes from 39.156.66.14 icmp_seq=4 time=91 ms
[5] 32 bytes from 39.156.66.18 icmp_seq=5 time=89 ms
[6] 32 bytes from 39.156.66.14 icmp_seq=6 time=126 ms
[7] 32 bytes from 39.156.66.18 icmp_seq=7 time=114 ms
[8] 32 bytes from 39.156.66.14 icmp_seq=8 time=129 ms
[9] 32 bytes from 39.156.66.18 icmp_seq=9 time=120 ms

Ping statistics for 39.156.66.18 :
Packets: Sent = 10, Received = 10, Lost = 0, Mintime = 71 ms, Maxtime = 335 ms, Avgtime = 132 ms
sh />

10次测试,没有丢失。

14.5 注意事项

1、4G模组(AT)与WIFI模组使用方式基本一致,后续不再复述。

2、因部分模组通信时功耗较大,所以在使用模组时请接通5V直流电源。

3、因各种组件内部可能用到了TIMER相关的功能,如果不正确配置TIMER,可能会导致功能不正常。

推荐以下配置:1)使用clocksource;2)使用clockevent;3)使用hrtimer;4)选择systick作为内核时钟

timer_oscube1

在cortex-m hardware timer config路径下配置内核时钟:

timer_oscube2

第十五章 MQTT连接OneNET实验

15.1 简介

MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅模式的“轻量级”通讯协议,该协议构建于TCP/IP协议上,由IBM在1999年发布。MQTT最大优点在于,可以以极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。做为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。MQTT组件为用户实现了客户端连接与断开、主题订阅与退订、消息发布、消息接收及回调、心跳维护等功能。

OneNET-中国移动物联网开放平台是由中国移动打造的PaaS物联网开放平台。平台能够帮助开发者轻松实现设备接入与设备连接,提供综合性的物联网解决方案,实现物联网设备的数据获取,数据存储,数据展现。

本实验将演示如何使用OneNET-MQTT组件实现平台连接和数据上传。

15.2 硬件说明

本实验需要依赖万耦开发板上的 WiFi模组ESP8266 完成网络通信,因此在进行此实验前,请配置好 WiFi模组并确保其可以正常工作。

15.3软件说明

具体介绍,请查阅组件《OneNET-MQTT-Kit》与《Paho MQTT》相关的文档。

15.4编译运行

15.4.1 STM32CubeMX配置

本实验通过WIFI模组联网,因此需要在CubeMX中将串口1配置好,具体配置方式参考前文。

15.4.2 OnsOS-Cube配置

1、配置WIFI模组

参照上一章节内容。

2、在Components→ Cloud→ OneNET→ MQTT kit下配置MQTT

mqtt_oscube

15.4.3 生成MDK工程

完成OnsOS-Cube配置后,使用scons指令:scons --ide=mdk5编译生成mdk5工程。

15.4.4 运行

1、使用keil5打开工程project.uvprojx ;

2、修改代码,以连接用户设备;

按照前文配置,生成工程后,MDK工程中会自带一个demo程序,onenet_device_sample.c。其主要实现了数据的上传功能,用户可参考此代码进行开发。

onenet_demo_code

用户需要将onenet_device_sample.中OneNET设备信息替换为用户自己的设备,否则代码运行时无法在OneNET上观测数据。

onenet_device_info

3、编译下载,运行代码。

1)输入help指令查看相关命令信息。


sh />help
OneOS shell commands:
dlog_glvl_ctrl   - Dlog global level control
dlog_tlvl_ctrl   - Dlog tag level control
dlog_gtag_ctrl   - Dlog global tag control
dlog_gkw_ctrl    - Dlog global keyword control
dlog_flush       - Flush dlog cache
...
...
generate_onenet_publish_data_cycle - publish message cycle to onenet specified topic
stop_onenet_publish_data_cycle - stop publishing message cycle to onenet specified topic
onenet_mqtts_device_start - start onenet mqtts device
onenet_mqtts_device_end - end onenet mqtts device
onenet_mqtts_publish - publish message to onenet specified topic
set_prompt       - Set shell prompt
help             - Obtain help of commands
sh />

2)输入指令onenet_mqtts_device_start,启动设备。

启动设备后,在OneNET上设备会处于在线状态。

onenet_device_online

3)输入指令generate_onenet_publish_data_cycle,开始传输数据。

sh />
sh />generate_onenet_publish_data_cycle
sh />Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":1}
Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":2}
Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":3}
Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":4}
Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":5}
Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":6}
Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":7}
Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":8}
Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":9}
Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":10}
Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":11}
Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":12}
Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":13}
Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":14}
Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":15}
Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":16}
Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":17}
Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":18}
Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":19}
Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":20}
...

此时可在OneNET的数据流展示界面,可查看数据情况。

onenet_data1

显示temperature数据波形:

onenet_data2

显示power数据波形:

onenet_data3

4)输入指令stop_onenet_publish_data_cycle,停止传输数据。

5)输入指令onenet_mqtts_device_end,关闭设备。

设备关闭后,设备会处于离线状态。

15.5注意事项

用户创建One Net的账号,创建设备,请自行查阅在https://open.iot.10086.cn/doc/mqtt/。

onenet_create

第十六章 综合演示

16.1 简介

本实验作为综合性演示,在万耦一代开发板上集成了基于OneOs的传感器驱动、文件系统、WIFI模组配网、连接One-Net云平台等功能,并通过 LCD 显示、LED灯,按键输入实现人机交互功能。

16.2 硬件说明

见万耦一代开发板的原理图。

16.3 软件说明

综合实验主要的功能性代码位于 \templates\stm32l475-cmcc-oneos-Demo目录下,重要文件摘要说明如下表所示:

文件名称 作用简介
cmcc_key_process.c 使用KEY1~KEY4个开关,主要作用是控制LCD显示切换,蜂鸣器鸣叫
cmcc_lcd_process.c 显示软硬件版本信息,欢迎导航界面,传感器,日历时钟等信息
cmcc_sensor_process.c 获取温湿度传感器,光强传感器等传感器数据
cmcc_onenet_process.c 连接one-net云端 ,将传感器数据发送到云端
rtc_setup.c 设置日历时间
main.c 程序入口

16.4 综合实验配置说明

综合实验的配置与前面章节实验的配置流程基本一致,都需要在OnsOS-Cube中先对使用到的资源进行选择。因为前面章节没有对WIFI模组以及云端连接的使用进行说明,所以在此处对相关资源的配置进行简单介绍。

16.5 综合实验使用流程

16.5.1 编译运行

按照前面的配置流程走完后,打开工程编译下载代码。

16.5.2 设置日历时间

因为开发板上并未单独安装电池供电,所以在上电后开发板上日历时间一般不准确,需要用户设置一遍。使用以下指令修改日期和时间:

sh />rtc_setup_date 2020 6 16
Tue Jun 16 00:03:21 2020

sh />rtc_setup_time 9 2 30
Tue Jun 16 09:02:32 2020

sh />

16.5.3 按键切换显示界面

综合实验使用开发板上KEY1~KEY4作为LCD显示屏切换显示内容的触发手段,在按下按键时,LCD切换显示内容,蜂鸣器发出反馈声响。

按键 作用
S2按键 HomePage:欢迎导航界面
S3按键 SensorPage:温湿度,光强传感器数据显示
S4按键 AboutPage:开发板软硬件信息
S5按键 CalendarPage:显示日历时间

16.5.4 启动One Net数据发送

综合实验中,One Net云端连接组件是需要用户手动启动的。在WIFI模组正常联网后,用户可根据需要启动云端连接。

输入ifconfig指令,查看网络连接情况。如能查看到IP地址正常,则表示连网成功。

sh />ifconfig

LIST AT MODULE INFORMATIONS
--------------------------------------------------------------------------------
Module   Name    : esp8266
WiFi     Mode    : Station
WiFi     Status  : Connected
STA IPv4 Address : 192.168.0.104
--------------------------------------------------------------------------------
sh />

使用shell指令,运行mqtt相关功能代码。

sh />onenet_mqtts_device_start

云端连接后,可在云端查看到设备处于在线状态。

one_net_start

在云端网页,点击数据流,进入数据流展示界面,打开实时刷新。启动数据上传,此时控制台会打印每次上传信息,如下所示:

sh />onenet_upload_data_cycle
Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":1}
Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":2}
Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":3}
Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":4}
Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":5}
Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":6}
Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":7}
Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":8}
Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":9}
Recv submessage pubdata accepted, Message arrived on topic $sys/350901/cmcc_test/dp/post/json/accepted: {"id":10}
...

综合实验中,只将开发板所处环境的温度与湿度信息发送到了云端。

one_net_data

results matching ""

    No results matching ""