STM32F407——基于RT-Thread实现触摸屏按键点灯案例

开发要求

a. LCD上实现按键点灯,按键和灯均为LCD虚拟出来的

开发过程

1.配置环境

1.1安装Cubemx ,如果有就跳过这一步

下载Cube MX 5.0 ,下载地址https://www.st.com/en/developmenttools/stm32cubemx.html

下载步骤略

2.配置工程

2.1打开Cubemx,配置RT-Thread内核

从菜单栏 help 进入 Manage embedded software packages 界面,点击 From Url 按钮,进入 User Defined Packs Manager 界面,其次点击 new,填入上述网址,然后点击 check,如下图所示:

check 通过后,点击 OK 回到 User Defined Packs Manager 界面,再次点击 OK,CubeMX 自动连接服务器,获取包描述文件。回到 Manage embedded software packages 界面,就会发现 RT-Thread Nano 3.1.3软件包,选择该软件包,点击 Install Now,如下图所示:

点击安装之后,弹出 Licensing Agreement ,同意协议,点击 Finish,

等待安装完成,成功安装后,版本前面的小蓝色框变成填充的黄绿色

在 CubeMX 主界面的菜单栏中 File 选择 New Project,如下图所示

新建工程之后,在弹出界面芯片型号中输入某一芯片型号,方便锁定查找需要的芯片,双击被选中的芯片

选中芯片型号之后,点击 Softwares Packages->Select Components,进入组件配置界面,选择 RealThread, 然后根据需求选择 RT-Thread 组件,然后点击 OK 按钮,如下图所示(和图片不一样的是要选3.1.3版本的,选3.1.5的无法配置nano):

选择组件之后,对组件参数进行配置。在工程界面 Pinout & Configuration 中,进入所选组件参数配置区,按照下图进行配置

2.2Cubemx配置引脚

按截图的顺序去操作配置触摸要用的引脚及其模式等

之后配置FSMC,用于LCD 的显示等

下面的是与fsmc时序有关的配置,配完需要仔细检查有没有配错

配置一个串口,设为异步,用于调试

配置时钟

配置系统时钟,要挂载在定时器六下面,不然会与RT-Thread 的时钟冲突

【补充:关于NVIC的配置,注意:RT-Thread 操作系统重定义 HardFault_Handler、PendSV_Handler、SysTick_Handler 中断函数,为了避免重复定义的问题,在生成工程之前,需要在中断配置中,代码生成的选项中,取消选择三个中断函数(对应注释选项是 Hard fault interrupt, Pendable request, Time base :System tick timer)】

配置时钟树

之后生成代码

3.修改并完善工程

3.1用keil打开工程,编译运行发现有错误,此时需要修改:

  • 修改文件类型 避免keil识别不出

  • 注释掉shell文件里第182行处

   extern char rt_hw_console_getchar(void);

   return rt_hw_console_getchar();

之后再编译应该就不会出现报错了

3.2修改代码

由于要用到邮箱 我们要把下面红线处的给取消注释

3.3 移植要用到的触摸屏代码,涉及到LCD/TOUCH/SPI等文件的移植

复制网盘链接下载文件到工程(按理不会报错,已把移植后发生的报错解决好了)

通过百度网盘分享的文件:hw 2024-…

链接:https://pan.baidu.com/s/1QQZ2QgOGyeWK-eEwYS8AJw?pwd=3qqo 

提取码:3qqo

复制这段内容打开「百度网盘APP 即可获取」

工程里新建一个light.h文件,复制以下代码到里面

#ifndef __LIGHT_H

#define __LIGHT_H

#include "sys.h"  

#include "stdlib.h"

#include "lcd.h"  

uint16_t gImage_light[xxx] = {};

#endif  

由于uint16_t gImage_light[xxx] = {};里面包含的数据过长,此处建议用图片取模工具完成,图片取模工具的百度网盘链接:

百度网盘 请输入提取码

密码是mg7k

去网上找一张灯的图片 导入取模工具里,设置成类似这样

完成设置,点击保存按钮,在弹出的对话框,输入想要保存的文件名,最好设为.h输出,之后复制到刚刚新建的light.h里

【参考csdn的这篇博客:https://blog.csdn.net/py8105/article/details/128184645?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522170738143716800182116447%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=170738143716800182116447&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-2-128184645-null-null.142^v99^pc_search_result_base6&utm_term=img2lcd&spm=1018.2226.3001.4187】

3.4 main.c文件里修改代码

由于我们是基于邮箱去传递信息,所以打开rtthread官网复制关于邮箱的相关例程到main.c文件里main函数之前

https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/ipc2/ipc2?id=%e9%82%ae%e7%ae%b1

例程如下:

#include <rtthread.h>

#define THREAD_PRIORITY      10

#define THREAD_TIMESLICE     5

/* 邮箱控制块 */

static struct rt_mailbox mb;

/* 用于放邮件的内存池 */

static char mb_pool[128];

static char mb_str1[] = "I'm a mail!";

static char mb_str2[] = "this is another mail!";

static char mb_str3[] = "over";

ALIGN(RT_ALIGN_SIZE)

static char thread1_stack[1024];

static struct rt_thread thread1;

/* 线程 1 入口 */

static void thread1_entry(void *parameter)

{

    char *str;

    while (1)

    {

        rt_kprintf("thread1: try to recv a mail\n");

        /* 从邮箱中收取邮件 */

        if (rt_mb_recv(&mb, (rt_uint32_t *)&str, RT_WAITING_FOREVER) == RT_EOK)

        {

            rt_kprintf("thread1: get a mail from mailbox, the content:%s\n", str);

            if (str == mb_str3)

                break;

            /* 延时 100ms */

            rt_thread_mdelay(100);

        }

    }

    /* 执行邮箱对象脱离 */

    rt_mb_detach(&mb);

}

ALIGN(RT_ALIGN_SIZE)

static char thread2_stack[1024];

static struct rt_thread thread2;

/* 线程 2 入口 */

static void thread2_entry(void *parameter)

{

    rt_uint8_t count;

    count = 0;

    while (count < 10)

    {

        count ++;

        if (count & 0x1)

        {

            /* 发送 mb_str1 地址到邮箱中 */

            rt_mb_send(&mb, (rt_uint32_t)&mb_str1);

        }

        else

        {

            /* 发送 mb_str2 地址到邮箱中 */

            rt_mb_send(&mb, (rt_uint32_t)&mb_str2);

        }

        /* 延时 200ms */

        rt_thread_mdelay(200);

    }

    /* 发送邮件告诉线程 1,线程 2 已经运行结束 */

    rt_mb_send(&mb, (rt_uint32_t)&mb_str3);

}

int mailbox_sample(void)

{

    rt_err_t result;

    /* 初始化一个 mailbox */

    result = rt_mb_init(&mb,

                     "mbt",                      /* 名称是 mbt */

                    &mb_pool[0],                /* 邮箱用到的内存池是 mb_pool */

                   sizeof(mb_pool) / 4,        /* 邮箱中的邮件数目*/

                    RT_IPC_FLAG_FIFO);          /* 采用 FIFO 方式进行线程等待 */

    if (result != RT_EOK)

    {

        rt_kprintf("init mailbox failed.\n");

        return -1;

    }

    rt_thread_init(&thread1,

                   "thread1",

                   thread1_entry,

                   RT_NULL,

                   &thread1_stack[0],

                   sizeof(thread1_stack),

                   THREAD_PRIORITY, THREAD_TIMESLICE);

    rt_thread_startup(&thread1);

    rt_thread_init(&thread2,

                   "thread2",

                   thread2_entry,

                   RT_NULL,

                   &thread2_stack[0],

                   sizeof(thread2_stack),

                   THREAD_PRIORITY, THREAD_TIMESLICE);

    rt_thread_startup(&thread2);

    return 0;

}

/* 导出到 msh 命令列表中 */

MSH_CMD_EXPORT(mailbox_sample, mailbox sample);

大体代码是差不多的,但需要更改一些细节

我们的思路是线程1用于接收线程2发送的邮件,触发线程2发邮件的事件是触摸屏被按下且按下的触摸屏的位置是我们设置的“开关”处(开关的实现是用LCD_Fill函数去控制一块地方呈现颜色)

①所以我们可以修改设置邮件内容为

rt_uint32_t mb_str1 = 1;//开灯

rt_uint32_t mb_str3 = 3;//结束

  • 修改线程1,2的入口函数,其他的不用修改

ALIGN(RT_ALIGN_SIZE)

static char thread1_stack[1024];

static struct rt_thread thread1;

static void thread1_entry(void *parameter)

{

    rt_uint32_t str;

    rt_uint8_t i;

  i = 0;

    while (1)

    {

        /* 从邮箱中收取邮件 */

        if (rt_mb_recv(&mb, (rt_uint32_t *)&str, RT_WAITING_FOREVER) == RT_EOK)

        {  

if (str == mb_str3){

    continue;

}

i ++;

          LCD_Fill(200,270,230,310,GREEN);

if(i%2==1)

{

show_picture1(0,0,150,168,gImage_light);

rt_thread_mdelay(120);

}

if((i%2==0)){

LCD_Fill(0,0,150,168,WHITE);

rt_thread_mdelay(150);

}

            rt_thread_mdelay(10);

        }

    }

    /* 执行邮箱对象脱离 */

    rt_mb_detach(&mb);

}

ALIGN(RT_ALIGN_SIZE)

static char thread2_stack[1024];

static struct rt_thread thread2;

/* 线程 2 入口 */

static void thread2_entry(void *parameter)

{

LCD_Fill(200,270,230,310,RED);

    while (1)

    {

        if (tp_dev.scan(0))

        { if(tp_dev.x[0]>200&&tp_dev.y[0]>270&&tp_dev.x[0]<230&&tp_dev.y[0]<310){

            /* 发送 mb_str1 地址到邮箱中 */

            rt_mb_send(&mb, (rt_uint32_t)mb_str1);

}

        }

        else

        {

 /* 发送 mb_str2 地址到邮箱中 */

            rt_mb_send(&mb, (rt_uint32_t)mb_str3);

        }

        rt_thread_mdelay(300);

    }

   /* 发送邮件告诉线程 1,线程 2 已经运行结束 */

    //rt_mb_send(&mb, (rt_uint32_t)mb_str3);

}

一般而言不会报错,报错的原因多由于头文件没有加入

之后把main函数改成这样

int main(void)

{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */

  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */

  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */

  MX_GPIO_Init();

  MX_USART1_UART_Init();

  MX_FSMC_Init();

  /* USER CODE BEGIN 2 */

//HAL_DeInit();

LCD_Init(); //LCD初始化  

rt_thread_mdelay(1000); // delay 50 ms

W25QXX_Init();

POINT_COLOR=RED;

rt_thread_mdelay(100);

tp_dev.init();

rt_thread_mdelay(700);

TP_Adjust();  

rt_thread_mdelay(700);

LCD_Clear(WHITE);//清除屏幕

mailbox_sample();

  /* USER CODE END 2 */

  /* Infinite loop */

  /* USER CODE BEGIN WHILE */

  while (1)

  {

rt_thread_mdelay(1300);

  }

  /* USER CODE END 3 */

}

  • 10
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值