基于RT-Thread系统的机智云数字仪表教程(一)——移植RT-Thread的BSP模板

目录:

1.基于RT-Thread系统的机智云数字仪表教程(一)——RT-Thread的BSP模板移植
2.基于RT-Thread系统的机智云数字仪表教程(二)——机智云云端开发
3.基于RT-Thread系统的机智云数字仪表教程(三)——STM32G0代码移植
4.基于RT-Thread系统的机智云数字仪表教程(四)——机智云APP代码移植
5.基于RT-Thread系统的机智云数字仪表教程(五)——机智云web代码移植
6.基于RT-Thread系统的机智云数字仪表教程(六)——STM32F7下位机toughGFX界面制作

实验内容:

  • 功能需求:
    • 在MCU设备端,美观漂亮的温度和湿度数据的UI展示
    • 在机智云云端,实现MCU设备端连接机智云,及数据采集并展示
    • 在Android⼿手机端,实现通过机智云读取MCU设备端温度和湿度数据并展示
  • 系统结构:
    • STM32F767+STM32G071双MCU设计,易易于扩展
    • STM32G071读取传感器器数据和机智云的连接
    • STM32F767负责UI界⾯面的展示
  • 可⽀支持二次开发(推荐):
    • 数字示波器器 激光测距仪 设备⼿手持操作器器等
    • 信号发⽣生器器 空⽓气质量量分析仪 ⽔水质检测仪等
      在这里插入图片描述

实验平台:

硬件: ST的STM32G071RBT6公版
在这里插入图片描述
软件: 最新版本的STM32CubeF4固件库, STM32CubeMX v5.2.1,开发环境MDK v5.26,
RT-Thread系统源码

实验前准备工作:

1.如果手头没有STM32G071RBT6公版,可以准备一个其他的STM32开发板,准备一个ESP8266
2.下载 RT-Thread系统源码
3.下载 STM32CubeMX
4.下载 MDK v5.26

代码:

代码持续更新中
github代码下载地址:https://github.com/Aladdin-Wang/stm32g071-st-gizwits

联系作者:

有问题欢迎添加微信交流,加项目备注:
在这里插入图片描述

移植RT-Thread的BSP模板:

1.学习RT-Thread系统(学过的可以跳过此步骤)
2.移植BSP
  • 参考官方使用 Env 创建 RT-Thread 项目工程的教程
    • 选择 BSP
      获取 RT-Thread 源代码后需要根据自己手上的开发板型号找到对应的 BSP,我手里有一个ST的STM32G071RBT6开发板,所以选择对应于STM32G071的BSP包,首先找到如下目录:…\rt-thread-v4.0.1\rt-thread\bsp\stm32\stm32g071-st-nucleo。
    • 搭建项目框架
      打开 Env 工具进入 stm32g071-st-nucleo 目录,运行scons --dist 命令。使用此命令会在 stm32g071-st-nucleo 目录下生成 dist 目录,这便是开发项目的目录结构,RT-Thread 源码位于项目文件夹内,仅包含 stm32g071-st-nucleo 的 BSP,可以随意拷贝此 BSP 到任何目录下使用。
      在这里插入图片描述
      进入dist目录下,把工程里面的 stm32g071-st-nucleo压缩包拷贝到你的项目目录下待使用。
    • 修改BSP
      参考这个官方教程

STM32G0管脚功能定义

GPIOMODE说明
PC-15WIFI_ENESP8266使能 低电平关机,保持高电平 STM32采用pull_up 输出模式
PC-12WIFI_RSTESP8266复位 低电平复位,保持高电平 STM32采用pull_up 输出模式,初始化输出高电平
PB-9WIFI_CONFESP8266模式 低电平使能下载,保持高电平模块正常工作 STM32采用pull_up 输出模式
PB-15SHT30_RSTSHT复位引脚 此引脚需要上拉输出 STM32采用pull_up 输出模式,初始化高电平
PB-14SHT30_ALTSHT报警引脚 此引脚不能上拉或者下拉 STM32采用no_pull_up and no_pull_down 输入模式
PC-13SOFTAP_KEY按键,上拉输入模式,SOFTAP
PC-14AIRLINK_KEY按键,上拉输入模式,AIRLINK
PD-2LED0低电平有效,开机初始化保持高电平
PB-4LED1高电平有效,开机初始化为低电平,高速推挽输出
PA-9I2C1_SCLSHT30数据通讯I2C口
PA-10I2C1_SDASHT30数据通讯I2C口
PC-10USART3-TX ESP8266-RXWIFI协议通讯串口波特率9600
PC-11USART3-RX ESP8266-TXWIFI协议通讯串口波特率9600
PA-0USART4-TX备用波特率9600
PA-1USART4-RX备用波特率9600
PA-2USART2-TX备用波特率9600
PA-3USART2-RX备用波特率9600
PC-4USART1-TX备用波特率9600
PC-5USART1-RX备用波特率9600
PC-1LPUART1-TX日志打印串口波特率115200
PC-0LPUART1-RX日志打印串口波特率115200

在路径…\stm32g071-st-nucleo\board\CubeMX_Config下,打开 CubeMX 工程,CubeMX_Config只需要配置串口的管脚即可生成工程,其他GPIO在系统里配置
在这里插入图片描述

生成工程后只需要保留如下文件即可
在这里插入图片描述

  • 配置和裁剪 RT-Thread
    打开 Env 工具使用 menuconfig 命令打开配置界面
    在这里插入图片描述
    打开LPUART1、UART1、UART2、UART3、UART4、软件IIC和硬件定时器2,保存,退出。
    原本BSP没有UART3、UART4。参考这个教程添加UART3、UART4
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述

  • 生成工程
    使用scons --target=mdk5 命令或者 scons --target=iar 命令生成 MDK 或者 IAR 工程
    在这里插入图片描述
  • 修改工程USART驱动
    由于STM32G071RBT6的 LPUART1、UART3、UART4共用一个中断号,所以当这三个中断发生中断时会进入同一个中断函数,为了加以区分是哪个串口,需要修改USART的驱动代码,具体修改如下:
void LPUART1_IRQHandler(void)
{
  uint32_t isrflags   = READ_REG(uart_obj[LPUART1_INDEX].handle.Instance->ISR);
  uint32_t cr1its     = READ_REG(uart_obj[LPUART1_INDEX].handle.Instance->CR1);
  uint32_t cr3its     = READ_REG(uart_obj[LPUART1_INDEX].handle.Instance->CR3);
  uint32_t errorflags;
  /* If no error occurs */
  errorflags = (isrflags & (uint32_t)(USART_ISR_PE | USART_ISR_FE | USART_ISR_ORE | USART_ISR_NE));
  if (errorflags == 0U)
  {
  	if (((isrflags & USART_ISR_RXNE_RXFNE) != 0U)
  		&& (((cr1its & USART_CR1_RXNEIE_RXFNEIE) != 0U)
  		|| ((cr3its & USART_CR3_RXFTIE) != 0U)))
  	{
  		/* enter interrupt */
  		rt_interrupt_enter();

  		uart_isr(&(uart_obj[LPUART1_INDEX].serial));

  		/* leave interrupt */
  		rt_interrupt_leave();
  	}
  	else
  	{
  		UART4_IRQHandler();
  	}
  }
}
void UART4_IRQHandler(void)
{
   uint32_t isrflags   = READ_REG(uart_obj[UART4_INDEX].handle.Instance->ISR);
   uint32_t cr1its     = READ_REG(uart_obj[UART4_INDEX].handle.Instance->CR1);
   uint32_t cr3its     = READ_REG(uart_obj[UART4_INDEX].handle.Instance->CR3);
   uint32_t errorflags;
   if (errorflags == 0U)
   {
   	if (((isrflags & USART_ISR_RXNE_RXFNE) != 0U)
   		&& (((cr1its & USART_CR1_RXNEIE_RXFNEIE) != 0U)
   		|| ((cr3its & USART_CR3_RXFTIE) != 0U)))
   	{
   		/* enter interrupt */
   		rt_interrupt_enter();

   		uart_isr(&(uart_obj[UART4_INDEX].serial));
   		
   		/* leave interrupt */
   		rt_interrupt_leave();
   	}
   	else
   	{
   		USART3_IRQHandler();
   	}
   		
   }
}
void USART3_IRQHandler(void)
{
   uint32_t isrflags   = READ_REG(uart_obj[UART3_INDEX].handle.Instance->ISR);
   uint32_t cr1its     = READ_REG(uart_obj[UART3_INDEX].handle.Instance->CR1);
   uint32_t cr3its     = READ_REG(uart_obj[UART3_INDEX].handle.Instance->CR3);
   uint32_t errorflags;
   if (errorflags == 0U)
   {
   	if (((isrflags & USART_ISR_RXNE_RXFNE) != 0U)
   		&& (((cr1its & USART_CR1_RXNEIE_RXFNEIE) != 0U)
   		|| ((cr3its & USART_CR3_RXFTIE) != 0U)))
   	{
   		/* enter interrupt */
   		rt_interrupt_enter();

   		uart_isr(&(uart_obj[UART3_INDEX].serial));
   		
   		/* leave interrupt */
   		rt_interrupt_leave();
   	}
   	else
   	{
   		
   	}
   }
}

在main函数添加线程,验证功能,具体内容请看注释

/*
 * Copyright (c) 2006-2018, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2018-11-06     SummerGift   change to new framework
 */

#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
/*
*************************************************************************
*                               变量
*************************************************************************
*/
static rt_thread_t led1_thread = RT_NULL;/* 定义线程控制块 */
static struct rt_semaphore rx_sem;/* 用于接收消息的信号量 */
static rt_thread_t receivedata_thread;/* 用于接收消息的线程 */
static rt_device_t hwtime2_dev; /* 定时器设备句柄*/
static rt_hwtimer_mode_t mode; /* 定时器模式*/
static rt_hwtimerval_t timeout_s; /* 定时器超时值*/
static rt_device_t uart1_serial;/* 串口设备句柄*/
static rt_device_t uart2_serial;/* 串口设备句柄*/
static rt_device_t uart3_serial;/* 串口设备句柄*/
static rt_device_t uart4_serial;/* 串口设备句柄*/
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; /* 配置参数 */
/************************* 全局变量声明 ****************************/
/*
 * 当我们在写应用程序的时候,可能需要用到一些全局变量。
 */
#define LED0_PIN     GET_PIN(D, 2)
#define HWTIMER_DEV_NAME "timer2" /* 定时器名称*/
#define SAMPLE_UART1_NAME "uart1" /* 串口设备名称*/
#define SAMPLE_UART2_NAME "uart2" /* 串口设备名称*/
#define SAMPLE_UART3_NAME "uart3" /* 串口设备名称*/
#define SAMPLE_UART4_NAME "uart4" /* 串口设备名称*/
/*
*************************************************************************
*                             函数声明
*************************************************************************
*/
static void led1_thread_entry(void* parameter);
static void serial_thread_entry(void *parameter);
/*
*************************************************************************
*                             函数回调
*************************************************************************
*/
/* 定时器超时回调函数*/
static rt_err_t timeout_cb(rt_device_t dev, rt_size_t size)
{
	if(hwtime2_dev == dev)
	{

	}
	return 0;
}
/* 接收数据回调函数*/
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
	if(dev == uart1_serial)
	{
		/* 串口接收到数据后产生中断,调用此回调函数,然后发送接收信号量 */
		rt_sem_release(&rx_sem);
	}
	if(dev == uart2_serial)
	{
		/* 串口接收到数据后产生中断,调用此回调函数,然后发送接收信号量 */

	}	
	if(dev == uart3_serial)
	{
		/* 串口接收到数据后产生中断,调用此回调函数,然后发送接收信号量 */
		rt_sem_release(&rx_sem);
	}
	if(dev == uart4_serial)
	{
		/* 串口接收到数据后产生中断,调用此回调函数,然后发送接收信号量 */

	}	
    return RT_EOK;
}

/*
*************************************************************************
*                             main 函数
*************************************************************************
*/
/**
  * @brief  主函数
  * @param  无
  * @retval 无
  */
int main(void)
{
	/*************************** 局部变量 ****************************/
	
    /************************* 初始化信号量 *************************/
    rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
	/******************定时器********************/
	hwtime2_dev = rt_device_find(HWTIMER_DEV_NAME);
	/* 以读写方式打开设备*/
	rt_device_open(hwtime2_dev, RT_DEVICE_OFLAG_RDWR);
	/* 设置超时回调函数*/
	rt_device_set_rx_indicate(hwtime2_dev, timeout_cb);
	/* 设置模式为周期性定时器*/
	mode = HWTIMER_MODE_PERIOD;
	rt_device_control(hwtime2_dev, HWTIMER_CTRL_MODE_SET , &mode);
	/* 设置定时器超时值为5s 并启动定时器*/
	timeout_s.sec = 0; /* 秒*/
	timeout_s.usec = 1000; /* 微秒*/
	rt_device_write(hwtime2_dev, 0, &timeout_s, sizeof(timeout_s));
	
	
    /****************************串口******************************/
	/* 查找串口设备*/
	uart1_serial = rt_device_find(SAMPLE_UART1_NAME);
	/* 以中断接收及轮询发送方式打开串口设备*/
	rt_device_open(uart1_serial, RT_DEVICE_FLAG_INT_RX);
	config.baud_rate = BAUD_RATE_9600;
	config.data_bits = DATA_BITS_8;
	config.stop_bits = STOP_BITS_2;
	config.parity = PARITY_NONE;
	/* 打开设备后才可修改串口配置参数 */
	rt_device_control(uart1_serial, RT_DEVICE_CTRL_CONFIG, &config);
	/* 设置接收回调函数*/
	rt_device_set_rx_indicate(uart1_serial, uart_input);
	
		/* 查找串口设备*/
	uart2_serial = rt_device_find(SAMPLE_UART2_NAME);
	/* 以中断接收及轮询发送方式打开串口设备*/
	rt_device_open(uart2_serial, RT_DEVICE_FLAG_INT_RX);
	config.baud_rate = BAUD_RATE_9600;
	config.data_bits = DATA_BITS_8;
	config.stop_bits = STOP_BITS_2;
	config.parity = PARITY_NONE;
	/* 打开设备后才可修改串口配置参数 */
	rt_device_control(uart2_serial, RT_DEVICE_CTRL_CONFIG, &config);
	/* 设置接收回调函数*/
	rt_device_set_rx_indicate(uart2_serial, uart_input);
	
	/* 查找串口设备*/
	uart4_serial = rt_device_find(SAMPLE_UART4_NAME);
	/* 以中断接收及轮询发送方式打开串口设备*/
	rt_device_open(uart4_serial, RT_DEVICE_FLAG_INT_RX);
	config.baud_rate = BAUD_RATE_9600;
	config.data_bits = DATA_BITS_8;
	config.stop_bits = STOP_BITS_2;
	config.parity = PARITY_NONE;
	/* 打开设备后才可修改串口配置参数 */
	rt_device_control(uart4_serial, RT_DEVICE_CTRL_CONFIG, &config);
	/* 设置接收回调函数*/
	rt_device_set_rx_indicate(uart4_serial, uart_input);	
	
	/* 查找串口设备*/
	uart3_serial = rt_device_find(SAMPLE_UART3_NAME);
	/* 以中断接收及轮询发送方式打开串口设备*/
	rt_device_open(uart3_serial, RT_DEVICE_FLAG_INT_RX);
	config.baud_rate = BAUD_RATE_9600;
	config.data_bits = DATA_BITS_8;
	config.stop_bits = STOP_BITS_2;
	config.parity = PARITY_NONE;
	/* 打开设备后才可修改串口配置参数 */
	rt_device_control(uart3_serial, RT_DEVICE_CTRL_CONFIG, &config);
	/* 设置接收回调函数*/
	rt_device_set_rx_indicate(uart3_serial, uart_input);
	
	
	/****************************线程******************************/
	/* 创建 serial 线程 */
    receivedata_thread =                   /* 线程控制块指针 */
	rt_thread_create( "recdata",       	   /* 线程名字 */
					  serial_thread_entry, /* 线程入口函数 */
					  RT_NULL,             /* 线程入口函数参数 */
					  512,                 /* 线程栈大小 */
					  5,                   /* 线程的优先级 */
					  10);                 /* 线程时间片 */
    /* 创建成功则启动线程 */
    if (receivedata_thread != RT_NULL)
        rt_thread_startup(receivedata_thread);
    else
        return -1;
	led1_thread =                          /* 线程控制块指针 */
    rt_thread_create( "led1",              /* 线程名字 */
                      led1_thread_entry,   /* 线程入口函数 */
                      RT_NULL,             /* 线程入口函数参数 */
                      512,                 /* 线程栈大小 */
                      10,                  /* 线程的优先级 */
                      20);                 /* 线程时间片 */
                   
    /* 启动线程,开启调度 */
   if (led1_thread != RT_NULL)
        rt_thread_startup(led1_thread);
   else
        return -1;

    return RT_EOK;
}
/*
*************************************************************************
*                             线程定义
*************************************************************************
*/
static void led1_thread_entry(void* parameter)
{	
	 /* set LED0 pin mode to output */
    rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
    while (1)
    {
		rt_pin_write(LED0_PIN, PIN_HIGH);
        rt_thread_mdelay(500);
        rt_pin_write(LED0_PIN, PIN_LOW);
        rt_thread_mdelay(500);	 		
    }
}
static void serial_thread_entry(void *parameter)
{
    char ch;
    while (1)
    {
        /* 从串口读取一个字节的数据,没有读取到则等待接收信号量 */
        while (rt_device_read(uart3_serial, -1, &ch, 1) != 1)
        {
            /* 阻塞等待接收信号量,等到信号量后再次读取数据 */
            rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
        }
        /* 读取到的数据通过串口错位输出 */
        //rt_device_write(serial, 0, &ch, 1);
		//rt_kprintf("%c", ch);
    }
}


  • 验证工程
    LED0 500ms闪烁一次
    串口FinSH运行良好
    在这里插入图片描述
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
对于MSP432微控制器的RT-Thread操作系统移植,您可以按照以下步骤进行操作: 1. 准备工作: - 下载RT-Thread源代码:从RT-Thread官方网站下载最新版本的源代码。 - 安装MSP432开发环境:确保您已经安装了MSP432的开发环境,包括MSP432 LaunchPad开发板和相关软件。 2. 创建MSP432的板级支持包(BSP): - 在RT-Threadbsp文件夹下创建一个新的目录,命名为msp432。 - 在msp432目录下创建一个board.c文件,实现与MSP432开发板相关的初始化函数,如时钟配置、中断配置等。 - 根据MSP432的数据手册和参考手册,编写板级支持包的代码,以适配MSP432的硬件。 3. 配置RT-Thread内核: - 在RT-Thread的env目录下创建一个新的目录,命名为msp432。 - 在msp432目录下创建一个rtconfig.h文件,配置RT-Thread内核的相关选项,如内存大小、线程数量等。 - 根据MSP432的特性和需求,进行相应的内核配置。 4. 编译和烧录: - 进入RT-Thread的根目录,执行menuconfig命令进行配置,选择MSP432平台和相应的BSP。 - 执行scons命令,编译RT-Thread操作系统。 - 使用MSP432开发环境将生成的可执行文件烧录到MSP432开发板上。 5. 应用程序开发: - 在RT-Thread的applications目录下编写应用程序代码,实现您的功能。 - 在bsp/msp432目录下添加驱动代码或配置文件,以支持您的应用程序。 - 编译和烧录应用程序到MSP432开发板上。 这些是大致的步骤,具体的移植过程可能会因各种因素而有所不同。您可以参考RT-Thread官方文档和MSP432的相关资料,以获取更详细的移植指南。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

WALI-KANG

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

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

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

打赏作者

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

抵扣说明:

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

余额充值