RT-Thread STM32系列驱动介绍①

RT-Thread STM32系列驱动介绍①

在这里插入图片描述

在 RT-Thread 实时操作系统中,各种各样的设备驱动是通过一套 I/O 设备管理框架来管理的。设备管理框架给上层应用提供了一套标准的设备操作 API,开发者通过调用这些标准设备操作 API,可以高效地完成和底层硬件外设的交互。设备管理框架的结构如下图所示:
在这里插入图片描述

使用 I/O 设备管理框架开发应用程序,有如下优点:

  • 使用同一套标准的 API 开发应用程序,使应用程序具有更好的移植性
  • 底层驱动的升级和修改不会影响到上层代码
  • 驱动和应用程序相互独立,方便多个开发者协同开发

1. 驱动分类介绍

本小节介绍 BSP 提供的不同类别驱动的概念,对一个 BSP 而言,有如下三类驱动:

  • 板载外设驱动:指 MCU 之外,开发板上外设,例如 TF 卡、以太网和 LCD 等
  • 片上外设驱动:指 MCU 芯片上的外设,例如硬件定时器、ADC 和看门狗等
  • 扩展模块驱动:指可以通过扩展接口或者杜邦线连接的开发板的模块,例如 ESP8266 模块

这三种外设的示意图如下所示:
在这里插入图片描述

2. 外设驱动的使用方法

当前 RT-Thread 提供的驱动库已经支持 STM32 多个系列的 BSP。点击下表中的驱动名称,即可跳转到对应驱动框架的介绍文档。开发者可以通过阅读相关资料,了解如何在应用开发中通过设备驱动框架来使用这些外设驱动。

2.1 片上外设

序号驱动简介
1GPIO操作 GPIO 管脚
2UART通过串口收发数据
3soft I2C通过软件 I2C 收发数据
4SPI通过 SPI 收发数据
5ADC测量管脚上的模拟量
6SDIO通过 SDIO 读写数据
7TIMER使用硬件定时器实现测量时间和定时执行回调函数功能
8PWM在特定的管脚输出 PWM 波形
9RTC设置和读取时间
10WDT看门狗驱动
11QSPI通过 SPI(1、2、4线) 收发数据

2.2 板载外设

序号驱动简介
1SD适用于 SPI 接口或 SDIO 接口的 SD(TF) 卡
2ETH PHY以太网
3USB PHYUSB
4LCD显示屏

2.3 扩展模块

序号驱动简介
1ESP8266串口转 WIFI 模块
2ENC28J60SPI 接口的以太网控制器

2.4 驱动示例代码

在 RT-Thread 的 examples\test 目录下,有 RT-Thread 提供的基于不同外设驱动的示例代码。在 env 工具中开启 BSP 中要测试的驱动,并将 examples\test 中对应的驱动框架测试文件加入工程,即可快速测试 BSP 中提供的驱动。

  • …\examples\test\net_test.c
/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 */

/*
 * Net Test Utilities for RT-Thread
 */
#include <rtthread.h>
#include <finsh.h>
#include <lwip/api.h>
#include <lwip/sockets.h>
#include <lwip/init.h>

/*
 * UDP echo server
 */
#define UDP_ECHO_PORT   7
rt_thread_t udpecho_tid = RT_NULL;
void udpecho_entry(void *parameter)
{
    struct netconn *conn;
    struct netbuf *buf;
    struct ip_addr *addr;
    unsigned short port;

    conn = netconn_new(NETCONN_UDP);
    if(conn == NULL)
    {
        rt_kprintf("no memory error\n");
        return;
    }
    netconn_bind(conn, IP_ADDR_ANY, 7);

    while(1)
    {
        /* received data to buffer */
#if LWIP_VERSION_MINOR==3U
        buf = netconn_recv(conn);
#else
        netconn_recv(conn, &buf);
#endif
        if(buf == NULL)
        {
            break;
        }
        addr = netbuf_fromaddr(buf);
        port = netbuf_fromport(buf);

        /* send the data to buffer */
        netconn_connect(conn, addr, port);

        /* reset address, and send to client */
#if LWIP_VERSION_MINOR==3U
        buf->addr = RT_NULL;
#else
        buf->addr = *IP_ADDR_ANY;
#endif

        netconn_send(conn, buf);

        /* release buffer */
        netbuf_delete(buf);
    }

    netconn_delete(conn);
}
/*
 * UDP socket echo server
 */
#define UDP_SOCKET_ECHO_PORT    700
#define UDP_SOCKET_BUFFER_SIZE  4096
rt_thread_t udpecho_socket_tid = RT_NULL;
void udpecho_socket_entry(void *parameter)
{
    int sock;
    int bytes_read;
    char *recv_data;
    rt_uint32_t addr_len;
    struct sockaddr_in server_addr, client_addr;

    /* allocate the data buffer */
    recv_data = rt_malloc(UDP_SOCKET_BUFFER_SIZE);
    if (recv_data == RT_NULL)
    {
        /* no memory yet */
        rt_kprintf("no memory\n");
        return;
    }
    /* create a UDP socket */
    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
    {
        rt_kprintf("create socket error\n");
        goto _exit;
    }

    /* initialize server address */
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(UDP_SOCKET_ECHO_PORT);
    server_addr.sin_addr.s_addr = INADDR_ANY;
    rt_memset(&(server_addr.sin_zero),0, sizeof(server_addr.sin_zero));

    /* bind socket to server address */
    if (bind(sock,(struct sockaddr *)&server_addr,
        sizeof(struct sockaddr)) == -1)
    {
        /* bind failed */
        rt_kprintf("bind error\n");
        goto _exit;
    }

    addr_len = sizeof(struct sockaddr);
    while (1)
    {
        /* try to receive from UDP socket */
        bytes_read = recvfrom(sock, recv_data, UDP_SOCKET_BUFFER_SIZE, 0,
            (struct sockaddr *)&client_addr, &addr_len);

        /* send back */
        sendto(sock, recv_data, bytes_read, 0,
            (struct sockaddr *)&client_addr, addr_len);
    }

_exit:
    rt_free(recv_data);
    return;
}

/*
 * TCP echo server
 */
#define TCP_ECHO_PORT   7
rt_thread_t tcpecho_tid = RT_NULL;
void tcpecho_entry(void *parameter)
{
    struct netconn *conn, *newconn;
    err_t err;

    /* Create a new connection identifier. */
    conn = netconn_new(NETCONN_TCP);
    if(conn == NULL)
    {
        rt_kprintf("no memory error\n");
        return;
    }

    /* Bind connection to well known port number 7. */
    netconn_bind(conn, NULL, TCP_ECHO_PORT);

    /* Tell connection to go into listening mode. */
    netconn_listen(conn);

    while(1)
    {
        /* Grab new connection. */
#if LWIP_VERSION_MINOR==3U
        newconn = netconn_accept(conn);
        if(newconn != NULL)
#else
        err = netconn_accept(conn, &newconn);
        if(err == ERR_OK)
#endif
        /* Process the new connection. */
        {
            struct netbuf *buf;
            void *data;
            u16_t len;
#if LWIP_VERSION_MINOR==3U
            while((buf = netconn_recv(newconn)) != NULL)
#else
            while((err = netconn_recv(newconn, &buf)) == ERR_OK)
#endif
            {
                do
                {
                    netbuf_data(buf, &data, &len);
                    err = netconn_write(newconn, data, len, NETCONN_COPY);
                    if(err != ERR_OK)
                    {
                        break;
                    }
                }while(netbuf_next(buf) >= 0);

                netbuf_delete(buf);
            }
            /* Close connection and discard connection identifier. */
            netconn_delete(newconn);
        }
    }

    netconn_delete(conn);
}

/*
 * TCP socket echo server
 */
#define TCP_SOCKET_ECHO_PORT    700
#define TCP_SOCKET_BUFFER_SIZE  4096
rt_thread_t tcpecho_socket_tid = RT_NULL;
void tcpecho_socket_entry(void *parameter)
{
    char *recv_data;
    rt_uint32_t sin_size;
    int sock = -1, connected, bytes_received;
    struct sockaddr_in server_addr, client_addr;

    recv_data = rt_malloc(TCP_SOCKET_BUFFER_SIZE);
    if (recv_data == RT_NULL)
    {
        rt_kprintf("no memory\n");
        return;
    }

    /* create a TCP socket */
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        rt_kprintf("create socket error\n");
        goto _exit;
    }

    /* initialize server address */
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(TCP_SOCKET_ECHO_PORT);
    server_addr.sin_addr.s_addr = INADDR_ANY;
    rt_memset(&(server_addr.sin_zero),0, sizeof(server_addr.sin_zero));

    /* bind to server address */
    if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
    {
        rt_kprintf("bind address failed\n");
        goto _exit;
    }

    /* listen */
    if (listen(sock, 5) == -1)
    {
        rt_kprintf("listen error\n");
        goto _exit;
    }

    sin_size = sizeof(struct sockaddr_in);
    while(1)
    {
        /* accept client connected */
        connected = accept(sock, (struct sockaddr *)&client_addr, &sin_size);
        if (connected > 0)
        {
            int timeout;

            /* set timeout option */
            timeout = 5000; /* 5second */
            setsockopt(connected, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));

            /* handle this client */
            while (1)
            {
                /* receive data from this connection */
                bytes_received = recv(connected,recv_data, TCP_SOCKET_BUFFER_SIZE, 0);
                if (bytes_received <= 0)
                {
                    rt_kprintf("close client connection, errno: %d\n", rt_get_errno());
                    /* connection closed. */
                    lwip_close(connected);
                    break;
                }

                /* send data to client */
                send(connected, recv_data, bytes_received, 0);
            }
        }
    }

_exit:
    /* close socket */
    if (sock != -1) lwip_close(sock);
    rt_free(recv_data);

    return;
}

/*
 * NetIO TCP server
 */

/* network test utilities entry */
void net_test(void)
{
    /* start UDP echo server */
    if (udpecho_tid == RT_NULL)
    {
        udpecho_tid = rt_thread_create("uecho",
                                       udpecho_entry,
                                       RT_NULL,
                                       512,
                                       RT_THREAD_PRIORITY_MAX/2, 5);
        if (udpecho_tid != RT_NULL)
        {
            rt_thread_startup(udpecho_tid);
        }
    }

    if (udpecho_socket_tid == RT_NULL)
    {
        udpecho_socket_tid = rt_thread_create("uecho_s",
                                              udpecho_socket_entry,
                                              RT_NULL,
                                              512,
                                              RT_THREAD_PRIORITY_MAX/2 + 1, 5);
        if (udpecho_socket_tid != RT_NULL)
        {
            rt_thread_startup(udpecho_socket_tid);
        }
    }

    if (tcpecho_tid == RT_NULL)
    {
        tcpecho_tid = rt_thread_create("techo",
                                       tcpecho_entry,
                                       RT_NULL,
                                       512,
                                       RT_THREAD_PRIORITY_MAX/2 + 2, 5);
        if (tcpecho_tid != RT_NULL)
        {
            rt_thread_startup(tcpecho_tid);
        }
    }

    if (tcpecho_socket_tid == RT_NULL)
    {
        tcpecho_socket_tid = rt_thread_create("techo_s",
                                              tcpecho_socket_entry,
                                              RT_NULL,
                                              512,
                                              RT_THREAD_PRIORITY_MAX/2 + 3, 5);
    }
    if (tcpecho_socket_tid != RT_NULL)
    {
        rt_thread_startup(tcpecho_socket_tid);
    }
}
FINSH_FUNCTION_EXPORT(net_test, network test);


维护人:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

华为奋斗者精神

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值