STM32标准库移植RT-Thread Nano添加FinSH与控制台[通俗易懂]

STM32标准库移植RT-Thread Nano添加FinSH与控制台[通俗易懂]添加过shell后首先要在rtconfig.h中定义#defineRT_USING_FINSH为了方便,串口相关函数添加在board.c中使用串口中断实现命令的接收/**Copyright(c)2006-2019,RT-ThreadDevelopmentTeam**SPDX-License-Identifier:Apache-2.0**ChangeLogs:*DateAuthorNotes*2017-0

大家好,又见面了,我是你们的朋友全栈君。

获取更多资源,请关注微信公众号:嵌入式基地
在这里插入图片描述

添加过shell后
在这里插入图片描述
首先要在 rtconfig.h中定义

#define RT_USING_FINSH

为了方便,串口相关函数添加在board.c中
使用串口中断实现命令的接收

/* * Copyright (c) 2006-2019, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2017-07-24 Tanek the first version * 2018-11-12 Ernest Chen modify copyright */
 
#include <stdint.h>
#include <rthw.h>
#include <rtthread.h>

#include "stm32f10x.h"
#include <rtthread.h>
#include <string.h>

#define _SCB_BASE (0xE000E010UL)
#define _SYSTICK_CTRL (*(rt_uint32_t *)(_SCB_BASE + 0x0))
#define _SYSTICK_LOAD (*(rt_uint32_t *)(_SCB_BASE + 0x4))
#define _SYSTICK_VAL (*(rt_uint32_t *)(_SCB_BASE + 0x8))
#define _SYSTICK_CALIB (*(rt_uint32_t *)(_SCB_BASE + 0xC))
#define _SYSTICK_PRI (*(rt_uint8_t *)(0xE000ED23UL))

// Updates the variable SystemCoreClock and must be called 
// whenever the core clock is changed during program execution.
extern void SystemCoreClockUpdate(void);

// Holds the system core clock, which is the system clock 
// frequency supplied to the SysTick timer and the processor 
// core clock.
extern uint32_t SystemCoreClock;

static uint32_t _SysTick_Config(rt_uint32_t ticks)
{ 
   
    if ((ticks - 1) > 0xFFFFFF)
    { 
   
        return 1;
    }
    
    _SYSTICK_LOAD = ticks - 1; 
    _SYSTICK_PRI = 0xFF;
    _SYSTICK_VAL  = 0;
    _SYSTICK_CTRL = 0x07;  
    
    return 0;
}

#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
#define RT_HEAP_SIZE 1024
static uint32_t rt_heap[RT_HEAP_SIZE];     // heap default size: 4K(1024 * 4)
RT_WEAK void *rt_heap_begin_get(void)
{ 
   
    return rt_heap;
}

RT_WEAK void *rt_heap_end_get(void)
{ 
   
    return rt_heap + RT_HEAP_SIZE;
}
#endif

//使用串口中断实现 FinSH

//*************************************** 
//第一部分:ringbuffer 实现部分
//***************************************
#define rt_ringbuffer_space_len(rb) ((rb)->buffer_size - rt_ringbuffer_data_len(rb))

struct rt_ringbuffer
{ 
   
    rt_uint8_t *buffer_ptr;

    rt_uint16_t read_mirror : 1;
    rt_uint16_t read_index : 15;
    rt_uint16_t write_mirror : 1;
    rt_uint16_t write_index : 15;

    rt_int16_t buffer_size;
};

enum rt_ringbuffer_state
{ 
   
    RT_RINGBUFFER_EMPTY,
    RT_RINGBUFFER_FULL,
    /* half full is neither full nor empty */
    RT_RINGBUFFER_HALFFULL,
};

rt_inline enum rt_ringbuffer_state rt_ringbuffer_status(struct rt_ringbuffer *rb)
{ 
   
    if (rb->read_index == rb->write_index)
    { 
   
        if (rb->read_mirror == rb->write_mirror)
            return RT_RINGBUFFER_EMPTY;
        else
            return RT_RINGBUFFER_FULL;
    }
    return RT_RINGBUFFER_HALFFULL;
}

/** * get the size of data in rb */
rt_size_t rt_ringbuffer_data_len(struct rt_ringbuffer *rb)
{ 
   
    switch (rt_ringbuffer_status(rb))
    { 
   
    case RT_RINGBUFFER_EMPTY:
        return 0;
    case RT_RINGBUFFER_FULL:
        return rb->buffer_size;
    case RT_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);
    };
}

void rt_ringbuffer_init(struct rt_ringbuffer *rb,
                        rt_uint8_t           *pool,
                        rt_int16_t            size)
{ 
   
    RT_ASSERT(rb != RT_NULL);
    RT_ASSERT(size > 0);

    /* initialize read and write index */
    rb->read_mirror = rb->read_index = 0;
    rb->write_mirror = rb->write_index = 0;

    /* set buffer pool and size */
    rb->buffer_ptr = pool;
    rb->buffer_size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
}

/** * put a character into ring buffer */
rt_size_t rt_ringbuffer_putchar(struct rt_ringbuffer *rb, const rt_uint8_t ch)
{ 
   
    RT_ASSERT(rb != RT_NULL);

    /* whether has enough space */
    if (!rt_ringbuffer_space_len(rb))
        return 0;

    rb->buffer_ptr[rb->write_index] = ch;

    /* flip mirror */
    if (rb->write_index == rb->buffer_size-1)
    { 
   
        rb->write_mirror = ~rb->write_mirror;
        rb->write_index = 0;
    }
    else
    { 
   
        rb->write_index++;
    }

    return 1;
}

/** * get a character from a ringbuffer */
rt_size_t rt_ringbuffer_getchar(struct rt_ringbuffer *rb, rt_uint8_t *ch)
{ 
   
    RT_ASSERT(rb != RT_NULL);

    /* ringbuffer is empty */
    if (!rt_ringbuffer_data_len(rb))
        return 0;

    /* put character */
    *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;
}

/* 第二部分:finsh 移植对接部分 */
#define UART_RX_BUF_LEN 16
rt_uint8_t uart_rx_buf[UART_RX_BUF_LEN] = { 
   0};
struct rt_ringbuffer  uart_rxcb;         /* 定义一个 ringbuffer cb */
static struct rt_semaphore shell_rx_sem; /* 定义一个静态信号量 */
static USART_InitTypeDef UartHandle;

static int uart_init(void)
{ 
   
	//GPIO端口设置
  	GPIO_InitTypeDef GPIO_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	/* 初始化串口接收 ringbuffer */
    rt_ringbuffer_init(&uart_rxcb, uart_rx_buf, UART_RX_BUF_LEN);
	/* 初始化串口接收数据的信号量 */
    rt_sem_init(&(shell_rx_sem), "shell_rx", 0, 0);
	 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);	//使能USART1,GPIOA时钟
  
	//USART1_TX GPIOA.9
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
    GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
   
    //USART1_RX GPIOA.10初始化
  	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
  	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10 

  	//Usart1 NVIC 配置
  	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
  
   //USART 初始化设置

	UartHandle.USART_BaudRate = 115200;//串口波特率
	UartHandle.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
	UartHandle.USART_StopBits = USART_StopBits_1;//一个停止位
	UartHandle.USART_Parity = USART_Parity_No;//无奇偶校验位
	UartHandle.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
	UartHandle.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式

  	USART_Init(USART1, &UartHandle); //初始化串口1
  	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
  	USART_Cmd(USART1, ENABLE);                    //使能串口1 
}

/************************************************ rt_hw_console_output的两种实现方法都可以 ************************************************/
//方法一
void uart_send_byte(u8 data)
{ 
   
	while((USART1->SR & 0X40) == 0);
	USART1->DR = data;
}

void rt_hw_console_output(const char *str)
{ 
   
	rt_size_t i = 0, size = 0;
	char  a = '\r';
	
	size = rt_strlen(str);
	for(i = 0; i < size; i++)
	{ 
   
		if(*(str + i) == '\n')
		{ 
   
			uart_send_byte(a);									//发送数据
		}
		uart_send_byte(*(str+i));									//发送数据
	}
	
}
//方法二
//void rt_hw_console_output(const char *str)
//{ 
   
// rt_size_t i = 0, size = 0;
// char a = '\r';
// 
// size = rt_strlen(str);
// for(i = 0; i < size; i++)
// { 
   
// if(*(str + i) == '\n')
// { 
   
// USART_SendData(USART1, a); //发送数据
// while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); //等待发送完成
// }
// USART_SendData(USART1, *(str+i)); //发送数据
// while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); //等待发送完成
// }
// 
//}

/************************************************ rt_hw_console_getchar 方法一与方法二是功能相同 在串口接收命令时候只能一个字符一个字符的接收 因此使用方法三: 使用串口中断 把串口接收的命令保存在数组中 ************************************************/
//方法一
//char rt_hw_console_getchar()
//{ 
   
// int ch = -1;
// if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
// { 
   
// ch = USART_ReceiveData(USART1) & 0xff;
// }
// else 
// { 
   
// if(USART_GetITStatus(USART1, USART_IT_ORE) != RESET) //
// { 
   
// USART_ClearFlag(USART1, USART_FLAG_RXNE);
// }
// rt_thread_mdelay(10);
// }
// return ch;
//}

//方法二
///* 移植 FinSH,实现命令行交互, 需要添加 FinSH 源码,然后再对接 rt_hw_console_getchar */
///* 查询方式 */
//char rt_hw_console_getchar(void)
//{ 
   
// int ch = -1;
// 
// if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) != RESET)
// { 
   
// //USART_ClearITPendingBit(USART_DEBUG, USART_FLAG_RXNE);
// ch = USART_ReceiveData(USART1) & 0xFF;
// }
// else
// { 
   
// if(USART_GetFlagStatus(USART1, USART_FLAG_ORE) != RESET)
// { 
   
// USART_ClearITPendingBit(USART1, USART_FLAG_ORE);
// }
// rt_thread_mdelay(10);
// }
// 
// return ch;
//}

//方法三
/* 移植 FinSH,实现命令行交互, 需要添加 FinSH 源码,然后再对接 rt_hw_console_getchar */
/* 中断方式 */
char rt_hw_console_getchar(void)
{ 
   
    char ch = 0;

    /* 从 ringbuffer 中拿出数据 */
    while (rt_ringbuffer_getchar(&uart_rxcb, (rt_uint8_t *)&ch) != 1)
    { 
   
        rt_sem_take(&shell_rx_sem, RT_WAITING_FOREVER);
    } 
    return ch;   
}

void USART1_IRQHandler(void)                	//串口1中断服务程序
{ 
   
    int ch = -1;
// rt_base_t level;
    /* enter interrupt */
    rt_interrupt_enter();          //在中断中一定要调用这对函数,进入中断

    if ((USART_GetFlagStatus(USART1, USART_FLAG_RXNE) != RESET) &&
        (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET))
    { 
   
        while (1)
        { 
   
            ch = -1;
            if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) != RESET)
            { 
   
                ch =  USART1->DR & 0xff;
            }
            if (ch == -1)
            { 
   
                break;
            }  
            /* 读取到数据,将数据存入 ringbuffer */
            rt_ringbuffer_putchar(&uart_rxcb, ch);
        }        
        rt_sem_release(&shell_rx_sem);
    }

    /* leave interrupt */
    rt_interrupt_leave();    //在中断中一定要调用这对函数,离开中断
}


/** * This function will initial your board. */
void rt_hw_board_init()
{ 
   
    /* System Clock Update */
    SystemCoreClockUpdate();
    
    /* System Tick Configuration */
    _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);

    /* Call components board initial (use INIT_BOARD_EXPORT()) */
#ifdef RT_USING_COMPONENTS_INIT
    rt_components_board_init();
#endif

#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
    rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());
#endif
	uart_init();
}

void SysTick_Handler(void)
{ 
   
    /* enter interrupt */
    rt_interrupt_enter();

    rt_tick_increase();

    /* leave interrupt */
    rt_interrupt_leave();
}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/143606.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • Cordova App 打包全揭秘

    本文作者:大师兄(高武军)现就职于某公司移动端架构师兼产品开发。主要开发产品:mdn(适配app和微信的移动端解决方案),pageui(移动端ui组件库),formBuilder(可以让前端建表和操作表的表单设计器)。课程介绍点击查看原文Cordova是一个开源的移动开发框架。允许你用标准的Web技术——HTML5,CSS3和JavaScript做跨平台开发。应用在每个平台的

  • 达梦数据库备份实操「建议收藏」

    达梦数据库备份实操「建议收藏」达梦数据库备份方式:物理备份,逻辑备份物理备份 冷备:(dmap服务打开的状态下,数据库是关闭的) 热备:(dmap服务一定是打开的,数据库是打开的,数据库要开归档) 逻辑备份 导入导出:dexpdimp 集群:数据守护(dw),DSC(RAC) 达梦支持第三方的备份工具:如第三方备份一体机备份首先要开归档 SQL>alterdatabasemount;#mo…

  • 股票模拟交易_复杂状态机

    股票模拟交易_复杂状态机给定一个长度为 N 的数组,数组中的第 i 个数字表示一个给定股票在第 i 天的价格。设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。输入格式第一行包含整数 N,表示数组长度。第二行包含 N 个不超过 10000 的正整数,表示完整的数组。输出格式输出一个整数,表示最大利润。数据范围1≤N≤105输入样例:51

  • navicat15 永久激活码-激活码分享2022.02.27「建议收藏」

    (navicat15 永久激活码)JetBrains旗下有多款编译器工具(如:IntelliJ、WebStorm、PyCharm等)在各编程领域几乎都占据了垄断地位。建立在开源IntelliJ平台之上,过去15年以来,JetBrains一直在不断发展和完善这个平台。这个平台可以针对您的开发工作流进行微调并且能够提供…

  • 龙芯CPU架构_龙芯mips架构

    龙芯CPU架构_龙芯mips架构龙芯架构龙芯指令集:CPU访存指令24个全部来自MIPSCPU算数指令(ALU)10个全部来自MIPSCPU算数指令14个全部来自MIPSCPU乘除指令12个来自MIPS12个来自龙芯(其中8个重复MIPS指令功能)CPU跳转分支指令20个全部来自MIPSCPU位移指令15个全部来自MIPSCPU特殊指令2个全部来自MIPSCPU异常指令12个全…

  • c++ 字符串流 sstream(常用于格式转换)

    c++ 字符串流 sstream(常用于格式转换)点我进入原文c++字符串流sstream(常用于格式转换)  使用stringstream对象简化类型转换C++标准库中的提供了比ANSIC的更高级的一些功能,即单纯性、类型安全和可扩展性。在本文中,我将展示怎样使用这些库来实现安全和自动的类型转换。为什么要学习如果你已习惯了风格的转换,也许你首先会问:为什么要花

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号