Rtthread记录

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:这里可以添加本文要记录的大概内容:

这是记录rtthread 学习之路的汇总


提示:以下是本篇文章正文内容,下面案例可供参考

一、方法论是什么?

一开始的一些内核部分的知识过于理论,可以在平时实际问题中进行学习!先不用深究,可以把rtthread 在keil上仿真的示例源码弄懂即可!!

以及搭配cubemx+rtthread studio 的方式快速开发具体工程,利用组件+软件包对实际开发工程拓展

目前学设备和驱动篇!分析rtthread标准源码

使用rtthread studio 验证具体学习的知识

二、基本步骤

基于RT-Thread studio开发换将创建的工程,时钟默认为内部时钟,如果希望使用外部时钟,如何配置呢?
rtthread studio外部时钟配置
选择相应芯片,使用cubemx 的debug 和 sys 、usart1 。通过配置HSE,使用cubemx生成的systemconfig 替换driver下的drv.clk.c里面的system_config (注意默认生成的例程使用到了usart1,当使用到cubemx生成工程后,需要对usart1进行配置)
生成工程选择Makefile 而不是MDK
主代码

通过输出,可以看到时钟被配置成HSE
生成结果
RtThread 操作系统原子stm32学习

代码参考:led点亮,key中断控制

#include <rtdevice.h>
#define LED_IO GET_PIN(E,5)
#define LED_I1 GET_PIN(B,5)
#define KEY1_IO GET_PIN(E,3)
#define KEY0_IO GET_PIN(E,4)
int flag=0;
//回调函数
void KEY_CallBack_Function(void *args)
{
    flag=!flag;
    rt_pin_write(LED_IO, flag);

}
int main(void)
{
      rt_pin_mode(LED_IO, PIN_MODE_OUTPUT);
      rt_pin_mode(LED_I1, PIN_MODE_OUTPUT);
      rt_pin_mode(KEY1_IO,PIN_MODE_INPUT);
      rt_pin_mode(KEY0_IO,PIN_MODE_INPUT_PULLUP);
      rt_pin_write(LED_IO, 1);//默认关灯

      rt_pin_attach_irq(KEY1_IO, PIN_IRQ_MODE_FALLING , KEY_CallBack_Function, RT_NULL);
      rt_pin_irq_enable(KEY1_IO, PIN_IRQ_ENABLE);

      while(1){
          //rt_kprintf("key:%d\n",rt_pin_read(KEY0_IO));
          rt_pin_mode(LED_I1, PIN_MODE_OUTPUT);
          rt_thread_mdelay(500);
          rt_pin_mode(LED_I1, PIN_MODE_OUTPUT);
          rt_thread_mdelay(500);
      }
    return RT_EOK;
}

连按,不连按
长按(2s)和短按

按键KEY0长按2秒之后,LED1点亮,松开后再长按2秒,LED1熄灭。按键KEY0按下不到2秒松开,LED0点亮,再按一次,LED0熄灭

/* 按键同时支持长按和短按 */
int main(void)
{
    int i = 0, j = 0;
    int key_up = 1;
    rt_uint16_t t = 0;

    /* 把LED引脚设置为输出 */
    rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
    rt_pin_mode(LED1_PIN, PIN_MODE_OUTPUT);

    /* 把KEY引脚设置为输入 */
    rt_pin_mode(KEY0_PIN, PIN_MODE_INPUT);
    rt_pin_mode(KEY1_PIN, PIN_MODE_INPUT);
    rt_pin_mode(KEY2_PIN, PIN_MODE_INPUT);
    rt_pin_mode(KEY_UP_PIN, PIN_MODE_INPUT);

    /* 先把两个灯都关掉 */
    rt_pin_write(LED0_PIN, PIN_HIGH);
    rt_pin_write(LED1_PIN, PIN_HIGH);

    while (1)
    {
        /* 读取KEY0引脚电平 */
        if (rt_pin_read(KEY0_PIN) == PIN_LOW)//按键按下时为低电平
        {
            rt_thread_mdelay(10);//延时消抖
            t++;
            if (t == 200)
            {//长按两秒
                j = ~j;
                if(j)
                {
                    rt_pin_write(LED1_PIN, PIN_LOW);//点亮LED1
                }
                else
                {
                    rt_pin_write(LED1_PIN, PIN_HIGH);//熄灭LED1
                }
            }
        }
        else if(rt_pin_read(KEY0_PIN) != PIN_LOW)//按键松开
        {
            if(t >=3 && t<= 200)
            {//短按
                i = ~i;
                if(i)
                {
                    rt_pin_write(LED0_PIN, PIN_LOW);//点亮LED0
                }
                else
                {
                    rt_pin_write(LED0_PIN, PIN_HIGH);//熄灭LED0
                }    
            }
            t = 0;
        }
    }
}

启用Rthread studio 的Terminal 可以开启串口

使用xterm来进行msh的使用(要求main里面的while(1)需要延时期间会挂起线程不占用cpu资源)

在这里插入图片描述

2.IO设备框架

矜辰所致的博客导航

简单的设备–无需经过设备驱动层,直接注册到IO设备管理层,
复杂的设备 --> 设备驱动层–>IO设备管理层
创建的设备示例先注册到对应的设备驱动框架,再有设备驱动框架往IO设备管理层进行注册

drv.usart.c --> serial.c -->
在RT-Thread中,设备也是一种内核对象,和以前说的线程,IPC机制,定时器等对象一样,有自己的对象控制块

设备对象控制块
在这里插入图片描述
设备类型 —字符、块、其他设备类型
设备注册 flag --属于什么状态的设备,可读、可写、收发等
设备访问 open_flag —设备访问的时候,需要使用这个 open_flag 来判断需要对设备进行什么操作,是读?还是写? 还是发送等。。。

/**  rtdef.h
 * Device structure
 */
struct rt_device
{
    struct rt_object          parent;                   /**< inherit from rt_object */

    enum rt_device_class_type type;                     /**< device type */
    rt_uint16_t               flag;                     /**< device flag */
    rt_uint16_t               open_flag;                /**< device open flag */

    rt_uint8_t                ref_count;                /**< reference count */
    rt_uint8_t                device_id;                /**< 0 - 255 */

    /* device call back */
    rt_err_t (*rx_indicate)(rt_device_t dev, rt_size_t size);
    rt_err_t (*tx_complete)(rt_device_t dev, void *buffer);

#ifdef RT_USING_DEVICE_OPS
    const struct rt_device_ops *ops;
#else
    /* common device interface */
    rt_err_t  (*init)   (rt_device_t dev);
    rt_err_t  (*open)   (rt_device_t dev, rt_uint16_t oflag);
    rt_err_t  (*close)  (rt_device_t dev);
    rt_size_t (*read)   (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
    rt_size_t (*write)  (rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
    rt_err_t  (*control)(rt_device_t dev, int cmd, void *args);
#endif

#if defined(RT_USING_POSIX)
    const struct dfs_file_ops *fops;
    struct rt_wqueue wait_queue;
#endif

    void                     *user_data;                /**< device private data */
};

device.c
设备创建 = 初始化+操作方法 vs 设备销毁
设备注册 (到IO设备管理器,应用程序才可访问) vs 设备注销
注销只是把这个 设备对象结构体 从管理链表中去掉,并不会释放这个对象结构体的空间,要释放空间需要调用销毁设备函数。

查找设备
初始化设备
打开和关闭设备

UART 设备模型 是复习理解 RT-Thread I/O 设备模型的完美设备。

设备驱动层和设备驱动框架层

在 RT-Thread 操作系统中,对UART设备的初始化,可以理解为就是对 stm32_uart 结构体对象 的初始化

int rt_hw_usart_init(void)
{
    rt_size_t obj_num = sizeof(uart_obj) / sizeof(struct stm32_uart);
    struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
    rt_err_t result = 0;

    stm32_uart_get_dma_config();

    for (int i = 0; i < obj_num; i++)
    {
        uart_obj[i].config = &uart_config[i];
        uart_obj[i].serial.ops    = &stm32_uart_ops;
        uart_obj[i].serial.config = config;
        /* register UART device */
        result = rt_hw_serial_register(&uart_obj[i].serial, uart_obj[i].config->name,
                                       RT_DEVICE_FLAG_RDWR
                                       | RT_DEVICE_FLAG_INT_RX
                                       | RT_DEVICE_FLAG_INT_TX
                                       | uart_obj[i].uart_dma_flag
                                       , NULL);
        RT_ASSERT(result == RT_EOK);
    }

    return result;
}

board.c(rt_hw_board_init–>hw_board_init 完成板子的bsp初始化,其内部使用宏来管理pin设备和usat设备等通rtthread setting 组件一致)
rt_hw_usart_init–> (usart初始化)
rt_hw_serial_register(设备驱动框架,其内部调用rt_device_register)
–>rt_device_register(通用注册函数,用于将其注册到IO设备管理器)

在这里插入图片描述
串口RX —我们正常的项目使用中,一般都是 中断接收 或者 DMA 接收,
基本上不会使用 轮询接收的方式
在 RT-Thread 系统中,我们常用信号量或者消息队列 来标志是否接收到串口数据,这样的好处是当没有数据的时候,会将数据处理线程挂机,让出CPU资源

串口TX — 轮询 方式发送。

/轮询方式发送,中断接收orDMA接收/

RT-thread相关教程汇总–env
开发环境搭建!rtthread源码版本下载4.0.3(可通过rtthread studio快速获取)
尽量使用env开发工具来增添移除文件,使用keil来增添时,下一次使用env将会移除

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
UART 设备的设备驱动框架层,是有定义了 UART 设备自己的控制块,其继承了rt_device的内容,同时还增加了 UART 设备特有的一些配置,操作,回调函数之类的内容

pin设备

pin设备的对象结构体在pin.h中有定义,struct rt_device_pin
rt_hw_pin_init()会调用 rt_device_pin_register 函数进行 PIN 设备的初始化

int entry --> rtthread_startup-->bo

在hw_board_ini进行对rt_hw_pin_init()对引脚进行配置,通过宏开启是否对该组件进行配置
在这里插入图片描述
在这里插入图片描述
rt_hw_pin_init()内部使用rt_device_pin_register设备驱动框架层注册,
rt_device_pin_register使用rt_device_register注册到IO设备管理层,在pin.c中,提供了应用层访问硬件的接口

应用层是通过设备驱动框架层的rt_pin_get 、rt_pin_read 、rt_pin_write 来控制硬件

ADC设备

ADC 通道 MCU一般都有 ADC 引脚,将需要检测的模拟量连接至对应的 IO 口,做好配置就能使用

ADC 分辨率
STM32F1xx 系列的芯片来说,他们的 ADC 最大支持12位
一个ADC设置为 12 位的分辨率,2 的12 次方 = 4096,简单来说就是这个 ADC 设备把他的量程分为 4096 份:0 ~ 4095 最大值 4095 就等于他量程的最大值
STM32 ADC的量程为 0~ 3.3V,如果读到 4095 的ADC 值,就表示读到的电压为 3.3V

在这里插入图片描述
ADC设备操作函数

在这里插入图片描述

在这里插入图片描述

实际操作
I/O 设备模型之ADC设备

SPI设备

SPI 通讯有4种模式,由 CPOL (时钟的极性)和 CPHA (时钟的相位)决定:
在这里插入图片描述

在这里插入图片描述

挂载SPI设备,

spi设备操作:读取墨水屏驱动ID,

RT-thread SPI SFUD读写W25Q128
SFUD库源移植: sfud-通用的spi-flash库
基于hal库的使用,printf的重定向支持,

wds_rtthread study

开始篇目:先从设备驱动程序学习!

在这里插入图片描述

  1. 统一设备接口,使用设备驱动框架层()
    在这里插入图片描述

  2. PIN驱动分析
    在这里插入图片描述


  1. I2C设备
    在这里插入图片描述

  2. 块设备驱动程序
    核心要点就是:
    写入数据到pos位置,由此读该pos位置可以得到写入的数据,
    不同于字符设备主要体现在控制功能,如led点亮熄灭操作。块设备传输数据的单位为扇区,具有存储功能
    描述磁盘容量信息:有多少个扇区,扇区大小为多少,可擦除的块有多大

  3. 文件系统

基于RTThread的DFS文件系统组件使用笔记

POSIX 标准定义了操作系统应该为应用程序提供的接口标准,是 IEEE 为要在各种 UNIX 操作系统上运行的软件而定义的一系列 API 标准的总称

DFS虚拟文件系统向用户应用程序提供POSIX接口层,POSIX接口层是给开发者使用的接口 函数层。开发者使用POSIX接口层提供的POSIX API进行文件操作,无需关心文件系统是 如何实现的,也无需关心数据是存放在哪个存储设备中。
在这里插入图片描述

在这里插入图片描述

提炼点:参考文章

5.1.挂载点
windows 下插入一个U盘,盘符信息、文件系统格式信息、块设备驱动程序(读、写、擦除设备操作)

对于rtthread或linux系统来说,没有盘符的概念,而是一个树状结构的文件目录格式,相当与将某一设备挂载在某一个目录下(该目录等价于设备之于操作系统明确的实际位置)

以linux 操作系统举例:
在这里插入图片描述
在这里插入图片描述


5.1.挂载点、文件系统、块设备三者之间的关系

提升篇目: 链表与对象管理器的学习

内核知识学习

stm32基础+cubemx+硬件

硬件开发+嵌软+自制MQTT服务器

STM32程序编写风格:

把所有用到的头文件存放到一个include.h 中,后期所有的.c 文件皆包含该头文件,举例如下:
在这里插入图片描述
用法,效果修饰凡是test.h 声明的函数,其他文件就可以直接去使用
在这里插入图片描述

在test.c中定义一个变量,同时在test.h 中声明,让其他文件调用
在这里插入图片描述
在这里插入图片描述

总结

提示:这里对文章进行总结:

在这里插入图片描述
在这里插入图片描述

env 工具的学习

参考了很多教程,来制作bsp,可以参考官网的bsp教程or这篇,生成对应芯片的mdk 配置,只需要在board文件中修改。可以对比rtthread studio 生成的工程文件rtconfig.h来比对是否正确完成bsp制作

只要注意几点:

  1. cubemx 配置基本的rcc sys usart 选项,并且在生成工程不选择单独生成.c 和.h 选项
  2. 修改适合与当前芯片的flash和ram容量信息
  3. 在修改完成cubemx后,修改Kconfig 选项,换成自己的BSP对应芯片,其他有需要可以按实际情况修改!!! 这个主要是依照自己板载的外设,来具体添加,在使用env 工具,命令menuconfig来使能rtconfig.h 相应的宏来完成外设的初始化
  4. 修改链接脚本适合于MDK工程
  5. 在 env 界面输入命令 menuconfig 对工程进行配置,并生成新的 rtconfig.h 文件
  6. 使用 env 工具输入命令 scons --target=mdk5
  7. 特别要注意在rtconfig.h 文件中需要开启组件自动初始化,对RT_USING_COMPONENTS_INIT进行宏定义!! 只需要明白一点,使用组件必须先声明这个宏,否则比如Finsh组件使用无效(敲回车不能交互)
    其它注意事项:参考官网bsp教程
    cubemx每次生成只需要保留4这个文件就可以
    在这里插入图片描述

目前就是使用env 配置工程时使用不太熟悉,没有在rtconfig.h中包含
#define RT_USING_COMPONENTS_INIT,需要手动添加!!!!!!
在这里插入图片描述
下一步是需要将工程生成位置变得便携,完成env工具的学习
使用命令,scons --dist 生成需要的模版文件,打开project.uvprojx。

结合单独驱动的.c 和.h 完成往rtthread 工程中移植!!目前想到的主要是完成路径的包含,以及注意延时函数的替换上

env 完成e-paper的软件架构–wifi

玩转RT-Thread系列教程(12)–WIFI模组的使用

我选择的是usart2,并且开启了esp8266线程
在这里插入图片描述

menuconfig 其实就是完成对stm32f1xxx_hal_conf.h的宏定义的取消注释
可以在MDK工程全局搜索这个 #define __STM32F1xx_HAL_CONF_H,找到这个文件,通过完成相应宏的定义,来简化定义kconfig的注释!这个主要是为了快速开发!!,但是后续应该就是对Kconfig文件的修改

rtthread 完成任意芯片工程的驱动!!!–最基本的外设驱动能力
开发模式:cubemx + 修改kconfig + env配置 + 简单的.c 和.h移植(SConscript)

kconfig 主要修改成开发板所包含的硬件驱动外设,完成menuconfig的设置
在这里插入图片描述

寻找一个通用的Kconfig 来修改,如F1参考已给的工程例程
在这里插入图片描述
rtthread studio 学习:只需要rtthread setting 和 cubemx setting

学习高级的内核部分知识优化驱动性能,理解rtthread 操作系统元源码!!!!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值