电赛延期了,开学就没时间打了,写点博客记录一下调试过的模块,移植过的源码

# 在 CubeMX 上移植 Nano

# 在 CubeMX 上 添加 RealThread 软件包

在新建 CubeMX 工程的基础上,我们需要安装一个 软件包,一个 pdsc 的软件包, https://www.rt-thread.org/download/cube/RealThread.RT-Thread.pdsc
, 点击 help 中的 manage embedded software packs 选择 From URL, 在框中输入 网址,然后点击 check
alt 来源:https://blog.bruceou.cn/2020/11/2-2-transplantation-of-rt-thread-nano-based-on-cubemx/314/
点击 OK 回到 User Defined Packs Manager 界面,
再次点击 OK, CubeMX 自动连接服务器,获取包描述文件.
alt 来源:https://blog.bruceou.cn/2020/11/2-2-transplantation-of-rt-thread-nano-based-on-cubemx/314/

再次进入 anage embedded software packs 界面的时候 就会出现 RealThread 选项卡,

点击之后选择其中一个 (建议 3.1.3 及其以上) 点击 install now, 等待下载

中间会弹出一个使用许可,记得同意

# 在 CubxMX 上 添加 RT-Threard Nano 至 工程

打开,我们新建的基本 CubeMX 的基本工程,不会建立的点这里.

然后点击 Software Packs, 选择 select components, 进入 Software Packs Component Selector

勾上 RealThread, 然后 右边就会出现 RT-Trhead 及其版本号,我这里使用 3.1.5, 可以勾选是否使用 shell, kernel, 和 device (这个我没用过,因该是这两个月出的这里先不做 demo), 点击 OK 结束

PS: 如果没有左半边的的界面点击一下粉红色框起的地方点击

这时候就会在 工程的 最左侧栏最底部多出一个 Software Packs 的 选项 里面有 RealThread RT-Thread 3.1.5 (不同版本号会不同), 点击后 中间会出现 RTOS KernelRTOS shell , 勾选上,底部就会出现参数栏

参数这里按需配置,我打开了小内存管理,其他的一切照常,debug 项会在 RT-Thread Nano 初始胡过程中,打印执行到哪死在哪。看需求进行配置

最后,由于我们使用了 RT-Thread Ta 会占用 systick 所以我们需要修改 系统的定时器,这里我改成 TIM5

到这我们 用 cubemx 移植 RT-Thread 就完成了,生成工程即可,不过需要注释掉 cubeMX 生成的 HardFault_Handler 中断,

# 配置 Shell

kernel 配置 完毕,但是编译的时候 Keil 会报一个 未定义的 error

这里有我写好了的 串口输出代码,相关宏自行修改

void rt_hw_console_output(const char *str)
{
    rt_size_t i = 0, size = 0;
    char a = '\r';
    __HAL_UNLOCK(&UartHandle);
    size = rt_strlen(str);
    for (i = 0; i < size; i++)
    {
        if (*(str + i) == '\n')
        {
            HAL_UART_Transmit(&UartHandle, (uint8_t *)&a, 1, 1);
        }
        HAL_UART_Transmit(&UartHandle, (uint8_t *)(str + i), 1, 1);
    }
}

这是 shell 未定义 输出函数导致的问题,当然当你写好了 输出函数后,他又会报另一个错

因为这个,函数在这里被调用了

之所以 接收函数 没有报错是因为,在 链接的时候 输出函数在 输入函数之前,在检测出函数异常后,直接中断链接过程

接收函数 就比较麻烦。除了接收中断之外 为了保证 接收的数据的稳定性,我们需要加上 一个 环形缓冲区,所以代码量就会上升一些
这里我就不细说了,直接贴个代码

# ringbuffer.h

环形缓冲区头文件

/**
 * @file ringbuffer.h
 * @author BlackSheep (ywz_123xxx@163.com)
 * @brief   环形缓冲区
 * @version 0.1
 * @date 2021-05-16
 * 
 * @copyright Copyright (c) 2021
 * 
 */
#ifndef __RINGBUFFER_H__
#define __RINGBUFFER_H__
#include "stdint.h"
#define ALIGN_SIZE 4 // 字节对齐
// * 返回对齐数
#define ALIGN_DOWN(size, align) ((size) & ~((align)-1))
#define ringbuffer_space_len(rb) ((rb)->buffer_size - ringbuffer_data_len(rb))
struct ringbuffer
{
    uint8_t *buffer_ptr;
    uint16_t read_mirror : 1;
    uint16_t read_index : 15;
    uint16_t write_mirror : 1;
    uint16_t write_index : 15;
    int16_t buffer_size;
};
enum ringbuffer_state
{
    RINGBUFFER_EMPTY,
    RINGBUFFER_FULL,
    /* half full is neither full nor empty */
    RINGBUFFER_HALFFULL,
};
void ringbuffer_init(struct ringbuffer *rb, uint8_t *pool, int16_t size);
uint32_t ringbuffer_data_len(struct ringbuffer *rb);
enum ringbuffer_state ringbuffer_status(struct ringbuffer *rb);
uint32_t ringbuffer_getchar(struct ringbuffer *rb, uint8_t *ch);
uint32_t ringbuffer_putchar(struct ringbuffer *rb, const uint8_t ch);
#endif

# ringbuffer.c

环形缓冲区 .c 文件

/**
 * @brief           获取 ringbuffer 状态
 * 
 * @param rb        缓冲区对象
 * 
 * @retval           ringbuffer 枚举
 *                      空  :   RINGBUFFER_EMPTY
 *                      满  :   RINGBUFFER_FULL
 *                      半满:   RINGBUFFER_HALFFULL
 * @date 2021-05-16
 */
inline enum ringbuffer_state ringbuffer_status(struct ringbuffer *rb)
{
    if (rb->read_index == rb->write_index)
    {
        if (rb->read_mirror == rb->write_mirror)
        {
            return RINGBUFFER_EMPTY;
        }
        else
        {
            return RINGBUFFER_FULL;
        }
    }
    return RINGBUFFER_HALFFULL;
}
/**
 * @brief           获取缓冲区中数据大小
 * 
 * @param rb        缓冲区对象
 * 
 * @retval          缓冲区中现有数据
 * 
 * @date 2021-05-16
 */
uint32_t ringbuffer_data_len(struct ringbuffer *rb)
{
    switch (ringbuffer_status(rb))
    {
    case RINGBUFFER_EMPTY:
        return 0;
    case RINGBUFFER_FULL:
        return rb->buffer_size;
    case RINGBUFFER_HALFFULL:
    default:
        if (rb->write_index > rb->read_index)
        {
            return rb->write_index - rb->read_index;
        }
        else
        {
            return rb->buffer_size - (rb->read_index - rb->write_index);
        }
    };
}
/**
 * @brief           初始化 ringbuffer 实例
 * 
 * @param rb        缓冲区对象
 * @param pool      缓冲区数组首地址
 * @param size      缓冲区数组大小
 * 
 * 
 * @date 2021-05-16
 */
void ringbuffer_init(struct ringbuffer *rb,
                     uint8_t *pool,
                     int16_t size)
{
    /* 初始化读写索引 */
    rb->read_mirror = rb->read_index = 0;
    rb->write_mirror = rb->write_index = 0;
    /* 配置缓冲区首地址 和 大小 */
    rb->buffer_ptr = pool;
    rb->buffer_size = ALIGN_DOWN(size, ALIGN_SIZE);
}
/**
 * @brief           缓冲区存入 1 字节
 * 
 * @param rb        缓冲区对象
 * @param ch        存入缓冲区的数据
 * 
 * @retval          执行结果
 *                      0:  error
 *                      1:  succee
 * @date 2021-05-16
 */
uint32_t ringbuffer_putchar(struct ringbuffer *rb, const uint8_t ch)
{
    /* 缓冲区满 */
    if (!ringbuffer_space_len(rb))
        return 0;
    rb->buffer_ptr[rb->write_index] = ch;
    /* 翻转检测 */
    if (rb->write_index == rb->buffer_size - 1)
    {
        rb->write_mirror = ~rb->write_mirror;
        rb->write_index = 0;
    }
    else
    {
        rb->write_index++;
    }
    return 1;
}
/**
 * @brief           从缓冲区中读取 1 字节
 * 
 * @param rb        缓冲区实体
 * @param ch        读取的字节
 * 
 * @retval          执行结果:
 *                      0:  error
 *                      1:  succee
 * 
 * @date 2021-05-16
 */
uint32_t ringbuffer_getchar(struct ringbuffer *rb, uint8_t *ch)
{
    /* 缓存区为 NULL */
    if (!ringbuffer_data_len(rb))
        return 0;
    /* 存入字节 */
    *ch = rb->buffer_ptr[rb->read_index];
    if (rb->read_index == rb->buffer_size - 1)
    {
        rb->read_mirror = ~rb->read_mirror;
        rb->read_index = 0;
    }
    else
    {
        rb->read_index++;
    }
    return 1;
}

# FinSHDriver.h

FinSH 串口驱动头文件

#include <rtthread.h>
#include "ringbuffer.h"
// tShell
#define SHELL_USING_UART1 1
#define SHELL_USING_UART2 0
#define SHELL_USING_UART3 0
#define SHELL_USING_UART4 0
#define SHELL_USING_UART5 0
#define SHELL_USING_UART6 0
#define SHELL_USING_UART7 0
#define SHELL_USING_UART8 0
#define UART_RX_BUF_LEN 16
#if SHELL_USING_UART1
#define FIN_SHELL_UART USART1              // * tShell 串口
#define FIN_SHELL_IRQn USART1_IRQn          // * tShell 中断号
#define TSHELL_IRQHandler USART1_IRQHandler // * tShell 中断服务函数
#endif
#if SHELL_USING_UART2
#define FIN_SHELL_UART USART2              // * tShell 串口
#define FIN_SHELL_IRQn USART2_IRQn          // * tShell 中断号
#define TSHELL_IRQHandler USART2_IRQHandler // * tShell 中断服务函数
#define TSHELL_AF   GPIO_AF7_USART2
#endif
#define FIN_SHELL_BAUDRATE 115200 // * tShell 波特率

# FinSHDriver.c

FinSH 源文件

/**
 * @brief       移植控制台,实现控制台输出,
 *              对接 rt_hw_console_output
 * 
 * @param str   需要输出的 字符
 * 
 * 
 * @date 2021-07-30
 */
void rt_hw_console_output(const char *str)
{
    rt_size_t i = 0, size = 0;
    char a = '\r';
    __HAL_UNLOCK(&UartHandle);
    size = rt_strlen(str);
    for (i = 0; i < size; i++)
    {
        if (*(str + i) == '\n')
        {
            HAL_UART_Transmit(&UartHandle, (uint8_t *)&a, 1, 1);
        }
        HAL_UART_Transmit(&UartHandle, (uint8_t *)(str + i), 1, 1);
    }
}
/**
 * @brief       移植 FinSH, 实现命令行交互 中断方式
 *              然后再对接 rt_hw_console_getchar
 * 
 * @retval 
 * 
 * @date 2021-07-30
 */
char rt_hw_console_getchar(void)
{
   char ch = 0;
   /* 从 ringbuffer 中拿出数据 */
   while (ringbuffer_getchar(&uart_rxcb, (rt_uint8_t *)&ch) != 1)
   {
       rt_sem_take(&shell_rx_sem, RT_WAITING_FOREVER);
   }
   return ch;
}
/**
 * @brief       tshell 接收 
 * 
 * 
 * @date 2021-07-30
 */
void TSHELL_IRQHandler(void)
{
    int ch = -1;
    rt_base_t level;
    /* enter interrupt */
    rt_interrupt_enter(); // 在中断中一定要调用这对函数,进入中断
    if ((__HAL_UART_GET_FLAG(&(UartHandle), UART_FLAG_RXNE) != RESET) &&
        (__HAL_UART_GET_IT_SOURCE(&(UartHandle), UART_IT_RXNE) != RESET))
    {
        while (1)
        {
            ch = -1;
            if (__HAL_UART_GET_FLAG(&(UartHandle), UART_FLAG_RXNE) != RESET)
            {
                ch = UartHandle.Instance->DR & 0xff;
            }
            if (ch == -1)
            {
                break;
            }
            /* 读取到数据,将数据存入 ringbuffer */
            ringbuffer_putchar(&uart_rxcb, ch);
        }
        rt_sem_release(&shell_rx_sem);
    }
    /* leave interrupt */
    rt_interrupt_leave(); // 在中断中一定要调用这对函数,离开中断
}

到这里,才算是移植结束,Nano 可带命令行 操作


大道五十,天衍四十九,人遁其一!

更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

黑羊 支付宝

支付宝