嘉立创产业服务站群
发作品签到
专业版

基于STM32H743的掌上多功能百宝箱

工程标签

1.8w
0
0
50

简介

基于LVGL开发人机交互界面,配套的2.8寸触摸屏。同时使用OV2640摄像头、ATGM336H定位、SHT40温湿度、BH1750环境光传感器等各个传感器对应的配套功能。

简介:基于LVGL开发人机交互界面,配套的2.8寸触摸屏。同时使用OV2640摄像头、ATGM336H定位、SHT40温湿度、BH1750环境光传感器等各个传感器对应的配套功能。
星火计划2024
复刻成本:120

开源协议

GPL 3.0

(未经作者授权,禁止转载)
创建时间:2024-09-06 07:53:53更新时间:2025-07-28 02:08:43

描述

1、作品名称

基于STM32H743的掌上多功能百宝箱

2、项目介绍

前几天参加了STM32的线下研讨会,领略到STM32在AI应用和GUI加速上的魅力。STM32H743是STM32系列的新款高性能MCU,目前在开源广场上关于H7系列的项目寥寥,且大部分都是开发板。为了能使H743的性能得到充分利用,本项目拟基于LVGL开发人机交互界面,配套的2.8寸触摸屏可以省去按键操作的麻烦,提升用户体验。同时,H743的GPIO接口非常多,可以挂接很多外设,本项目将使用OV2640摄像头、ATGM336H定位模块、SHT40温湿度传感器、BH1750环境光传感器等,做各个传感器对应的配套功能。

由于本项目外设多、基于触摸屏可扩展开发相当多的内容,且其仅为手掌大小(比2.8寸屏幕应该略大一圈),因而得名"掌上多功能百宝箱"。用户可基于本项目开源的软件代码,继续修改新增新的功能。

3、硬件模块介绍

3.1 STM32H743ZGT6 主控芯片

STM32H743ZGT6 是 STM32H7 系列中的高性能 MCU,采用 ARM Cortex-M7 内核,主频高达 480 MHz,内置 2MB 的 FLASH 和 1MB 的 RAM。这使得它在处理复杂任务时具备出色的性能,特别适合需要快速响应的应用场景。其丰富的外设接口使得外设的连接和控制更加灵活。
另外,设计上支持DFU下载,可以用STM32CubeProgrammer实现USB直连电脑下载程序。

3.2 扩展SDRAM

本项目中使用了 256Mbit 的 MT48LC16M16A SDRAM(相当于 32MB),其主要用于存储较大的临时数据和运行时的动态数组。由于 STM32H743 内部 RAM 容量有限,外部 SDRAM 的加入大大扩展了系统的可用内存,在显示较高分辨率的图形界面或处理摄像头图像时,SDRAM 提供了充足的缓存空间,为未来开发更复杂的功能提供了硬件基础。

3.3 扩展FLASH

项目中配备了 256Mbit 的 MT25QL256ABA1EW9-0SIT QSPI FLASH,用于存储系统文件和用户数据。QSPI 接口具有较快的读写速度,能够满足在加载大型资源时的需求。预留的 MT29F2G01ABAGDWB 作为备用 FLASH ,将来可做进一步扩展。

3.4 外置EEPROM

JSM24C02 是一个 2Kbit 的 EEPROM,作为本项目的设置参数存储单元,主要用于保存用户的偏好设置、系统配置和重要的运行参数等。相比于 FLASH,EEPROM 的读写寿命更长,且支持小数据的多次写入操作,因此非常适合用于频繁更新但数据量较小的场景。在断电的情况下,EEPROM 能确保配置数据的持久保存,从而避免因电源故障或重启导致的数据丢失。

3.5 ATGM336H 定位模块

ATGM336H 是一款高精度的 GPS 定位模块,能够快速获取当前位置并提供精确的地理坐标信息。在本项目中,定位模块主要用于实现路径追踪、运动轨迹记录等功能。结合触摸屏界面,用户可以查看实时定位信息。ATGM336H 支持GPS和北斗卫星定位,能在复杂的环境中也能获得稳定的定位信号。

3.6 OV2640 摄像头模块

OV2640 是一款具备 200 万像素的图像传感器,支持多种分辨率下的拍照和视频功能。在本项目中,OV2640 摄像头将用于捕获图像,并与 STM32 官方推出的 AI 库结合,开发手势识别等人工智能应用。

3.7 SHT40 温湿度传感器

SHT40 是一款高精度的温湿度传感器,其具备良好的稳定性和快速响应能力,能够精确检测环境的温度和湿度变化。在本项目中,SHT40 主要用于监测设备周围的环境状况,确保用户能实时掌握温湿度数据,并基于此开发相关的环境监控功能。

3.8 BH1750 环境光传感器

BH1750 是一款数字环境光传感器,用于检测周围环境的光线强度。在本项目中,BH1750 主要用于根据环境光线变化自动调整触摸屏的亮度,从而提升视觉体验,尤其是在不同光线条件下,屏幕亮度的自动调整可以有效减轻眼睛疲劳。

3.9 2.8英寸触摸屏

触摸屏用的是下面这一款,驱动IC为ILI9341,电阻式触摸。
http://e.tb.cn/h.gyKlKdaJeWtXDig?tk=mSZ33MEX7nv
若使用电容触摸屏,需要更改显示屏驱动源码。

4 项目进度

时间具体内容
2024.9.6项目创建构思
9.9原理图绘制完毕
9.11PCB绘制完毕
9.18开始软件、UI开发
9.20定位模块相关功能开发完毕
9.23基于LVGL的主要界面开发完毕
9.25加入DMA、缓冲实现全局60Hz流畅刷新
9.26外壳设计完毕
9.30SDRAM驱动开发完毕
10.1QSPI Flash驱动开发完毕
10.6FatFS移植完毕
10.9LVGL文件浏览器Beta开发完毕
10.10工程V1.0发布
10.17已将源码开源于GitHub
2025.5.20将Gui_Guider源码开源

5 软件部分

目前,本项目仍有在开发的功能,附件中的.hex文件不一定是最新的。强烈建议您通过文末的GitHub仓库,clone代码到本地,然后在Keil中编译、下载!

5.1 LVGL性能报告

得益于H7系列自带的缓存以及超大RAM,可以肆无忌惮地增加缓冲数组的大小以及开启缓冲,以下是LVGL性能测试表:

组合帧数CPU
单缓冲10*320+屏幕驱动自带画点函数43FPS97%CPU
单缓冲10*320+DMA+DCache OFF103FPS89%CPU
单缓冲10*320+DMA+DCache ON214FPS87%CPU
双缓冲20*320+DMA+DCache ON440FPS83%CPU
双缓冲100*320+DMA+DCache ON997FPS57%CPU
双缓冲全屏BUFFER240*320+DMA+DCache ON1152FPS62%CPU

综合上述性能测试的表现,为了保持全程60FPS,又不牺牲太多性能和资源占用,因此,选用了双缓冲 100*320+DMA+DCache ON
下面是LVGL接口文件lv_port_disp关于缓冲这段的代码:

 static lv_disp_draw_buf_t draw_buf_dsc_2;
    static lv_color_t buf_2_1[MY_DISP_HOR_RES * 100];                        /*A buffer for 10 rows*/
    static lv_color_t buf_2_2[MY_DISP_HOR_RES * 100];                        /*An other buffer for 10 rows*/
    lv_disp_draw_buf_init(&draw_buf_dsc_2, buf_2_1, buf_2_2, MY_DISP_HOR_RES * 100);   /*Initialize the display buffer*/

5.2 GPS模块的相关开发

在界面显示上面,专门开发了一个界面用于显示GPS相关信息。

PixPin_2024-10-10_20-03-10.jpg
在串口接收完消息后,调用解码GPS模块传来的GNRMC数据:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  if (huart->Instance == USART1)
  {
    if (0x0D == UART1_temp[0])
      UART1_temp[0] = 0x20; // 防止\r在窗口中导致某行显示不了
    if (0x0A == UART1_temp[0])
    {
      UART1_Rx_flg = 1;
    }

    u1_data[UART1_Rx_cnt++] = UART1_temp[0];

    if (UART1_Rx_cnt >= MAX_REC_LENGTH)
    {
      UART1_Rx_cnt = 0;
      memset(u1_data, '\0', strlen(u1_data));
    }
    HAL_UART_Receive_IT(&huart1, (uint8_t *)UART1_temp, REC_LENGTH);
  }

  if (huart->Instance == UART5) // 专门接收GPS的数据 只要$GNRMC这一行的数据
  {
    if (UART5_temp[0] == '$')
    {
      UART5_Rx_cnt = 0;
    }

    if (0x0D == UART5_temp[0])
    {
      UART5_temp[0] = 0x20;
    }
    U5_Rec_temp[UART5_Rx_cnt++] = UART5_temp[0];

    if (U5_Rec_temp[0] == '$' && U5_Rec_temp[4] == 'M' && U5_Rec_temp[5] == 'C' && UART5_temp[0] == 0x0A)
    {
      // 该行接收结束
      UART5_Rx_flg = 1;

      if (strlen(u5_data) + strlen(U5_Rec_temp) > 1000)
        memset(u5_data, '\0', strlen(u5_data));
      strcpy(u5_data, U5_Rec_temp);
      memset(U5_Rec_temp, '\0', strlen(U5_Rec_temp));
      UART5_Rx_cnt = 0;
      Uart_Rece_Pares();
    }
    HAL_UART_Receive_IT(&huart5, (uint8_t *)UART5_temp, REC_LENGTH);
  }
}
void Uart_Rece_Pares(void)   // 串口接收内容解析函数
{
    // 注意变量类型
    char *point = 0;  
    char *nextPoint = 0;   
    for (uint8_t i = 0; i < 8; i ++)
    {
        if (i == 0)
        {
            if ((point = strstr(u5_data,",")) == NULL)
            {
                return ;
            }
        }
        else
        {
            point ++;   
            if ((nextPoint = strstr(point,",")) != NULL)
            {
                // 存储信息
                switch (i)
                {
                case 1:   // UTC时间
                    memcpy(&gps.UTCTime,point,nextPoint - point);
                    break;

                case 2:   // 数据有效标识
                    memcpy(&gps.UsefulFlag,point,nextPoint - point);
                    break;

                case 3:   // 纬度
                    memcpy(&gps.latitude,point,nextPoint - point);
                    break;

                case 4:   // 纬度方向
                    memcpy(&gps.N_S,point,nextPoint - point);
                    break;

                case 5:   // 经度
                    memcpy(&gps.longitude,point,nextPoint - point);
                    break;

                case 6:   // 经度方向
                    memcpy(&gps.E_W,point,nextPoint - point);
                    break;
				case 7:
					memcpy(&gps.speed,point,nextPoint - point);
					break;
				}
                point = nextPoint; 


            }
        }
    }
	//处理数�??
	float latitude = 0;   // 存储纬度信息
	uint16_t temp1 = 0;   
	float longitude = 0;   // 存储经度信息
	uint16_t temp2 = 0;   
	
	latitude = strtod((const char*)gps.latitude,NULL);   // 字符串转换成浮点数
	longitude = strtod((const char*)gps.longitude,NULL);   // 字符串转换成浮点数
	
	// 纬度信息处理
	// 五位纬度信息
	if ((latitude - 10000.0f) >= 0)
	{
		temp1 = (((uint16_t)latitude / 10000) % 10) * 100 + (((uint16_t)latitude / 1000) % 10) * 10 + ((uint16_t)latitude / 100) % 10;
		latitude = latitude - (float)temp1 * 100;
		latitude = (float)temp1 + latitude / 60;
	}
	else   // 四位纬度信息
	{
		temp1 = (((uint16_t)latitude / 1000) % 10) * 10 + ((uint16_t)latitude / 100) % 10;
		latitude = latitude - (float)temp1 * 100;
		latitude = (float)temp1 + latitude / 60;
	}
	
	// 经度信息处理
	// 五位经度信息
	if ((longitude - 10000.0f) >= 0)
	{
		temp2 = (((uint16_t)longitude / 10000) % 10) * 100 + (((uint16_t)longitude / 1000) % 10) * 10 + ((uint16_t)longitude / 100) % 10;
		longitude = longitude - (float)temp2 * 100;
		longitude = (float)temp2 + longitude / 60;
	}
	else   // 四位经度信息
	{
		temp2 = (((uint16_t)longitude / 1000) % 10) * 10 + ((uint16_t)longitude / 100) % 10;
		longitude = longitude - (float)temp2 * 100;
		longitude = (float)temp2 + longitude / 60;
	}
	gps.UTCTime_int = ((uint32_t)strtod((const char*)gps.UTCTime,NULL) +80000)%240000;
	gps.latitude_d = latitude;
	gps.longitude_d = longitude;
	
}

然后显示于表格中

void update_gps_info(lv_timer_t * timer){
		#if !LV_USE_GUIDER_SIMULATOR
		HAL_UART_Receive_IT(&huart5,(uint8_t *)UART5_temp,REC_LENGTH);
		char t0[20],t1[20],t2[20],t3[20],t4[20];
    	//检查状态码
    	if(UART5_Rx_flg==1) {
		UART5_Rx_flg = 0;
		if(gps.UsefulFlag=='V')
			strcpy(t0,"Wait...");
		else if(gps.UsefulFlag=='A')
			strcpy(t0,"OK");
		lv_table_set_cell_value(guider_ui.app_screen_table_gps,0,1,t0);//状态

		sprintf(t1,"%.5f",gps.latitude_d);
		if(gps.N_S=='N')
			strcat(t1," N");
		else if(gps.N_S=='S')
			strcat(t1," S");
		lv_table_set_cell_value(guider_ui.app_screen_table_gps,1,1,t1);//纬度

		sprintf(t2,"%.5f",gps.longitude_d);
		if(gps.E_W=='E')
			strcat(t2," E");
		else if(gps.E_W=='W')
			strcat(t2," W");
		lv_table_set_cell_value(guider_ui.app_screen_table_gps,2,1,t2);//经度

		sprintf(t3,"%02d:%02d:%02d",gps.UTCTime_int/10000,gps.UTCTime_int/100%100,gps.UTCTime_int%100);
		lv_table_set_cell_value(guider_ui.app_screen_table_gps,3,1,t3);//UTC

		gps.speed_d = strtod((const char*)gps.speed,NULL);
		sprintf(t4,"%.2f",gps.speed_d*1.852);
		strcat(t4," km/h");
		lv_table_set_cell_value(guider_ui.app_screen_table_gps,4,1,t4);//速度 km/h
		}
	#endif
}

5.3 踩坑记录表

以下是开发软件过程中踩坑的汇总表,每次解决小问题时都有记录。如有朋友在调试时出现问题,不妨查看此表:

  1. 进systeminit后立即hardfault。解决:用cube programmer进行full chip erase然后下载程序,可能之前程序有错误。
  2. 屏幕显示白屏:解决:开启cortex m7里面的相关选项,见https://blog.csdn.net/weixin_66689383/article/details/132046062
  3. 在CUBEMX中配置需要RCC的power supply设为PWR_LDO,否则芯片跑不起来!!
  4. DMA开启后屏幕花屏。原因:开启了cortex_m7中的MPU的Cache,导致了数据不一致。解决:关闭DCache(会降低性能)或者在DMA中断开启前后加上SCB_CleanInvalidateDCache();
  5. 下载程序后程序不运行。原因:加入了printf但没有任何重定向,删掉即可
  6. 下载程序时显示no algorithm found for。 解决:https://blog.csdn.net/qq_22433397/article/details/122223508
  7. SDRAM写数据后再读取出错,解决:调整SDRAM时钟周期,目前测试不报错的为 2 8 6 6 2 2 6 另外注意SDRAM配置不要出错 BANK1 9BITS 13BITS 3CLK DISABLE 2CLK ENABLE 0CLK
  8. 移植FATFS遇到在f_mount出现内存管理错误。原因:访问了禁止访问的内存。解决:在CUBEMX中把FATFS的设备从2改成1就行。
  9. FATFS文件系统创建后重新挂载失败。原因:sizeof()运算符的坑,写入时用了sizeof(buff),sizeof(buff)读到是4,但实际上要写4096。在建立MBR时,0x55 0xAA代表MBR的结束,在0x1FE~0x1FF上,自然就不被写入flash,也就找不到引导了。
  10. 在移植FATFS到主分支之后,出现了FATFS打不开文件的情况,在测试分支正常。解决:开启了cortex_m7中的MPU的Cache,导致了数据不一致问题。解决:在MPU设置里专门把0X24000000后面512KB区域设为Cacheable disabled
  11. 加入FATFS之后屏幕刷新变卡了。原因:开启了上面的MPU 0x24000000的区域后,需要Cacheable disabled,关闭之后就变卡了。解决:在底层QSPI Read 和 Write函数开头加入SCB_CleanInvalidateDCache(),用以清理DCache缓存保证数据一致性
  12. FATFS读取文件大小错误。原因:在printf时误把 unsigned int 占位符写成了%llu,实际应为%u
  13. LVGL文件系统在读取文件return时进hardfault。原因:在fs_open return了一个局部变量的地址,应将改变量作为全局变量

6 参考 致谢

项目硬件设计过程中参考如下工程:
https://oshwhub.com/lixidixi/stm32h743iit6-development-board

https://oshwhub.com/upoaktreesup/stm32h735igt6-dev
定位模块参考:
https://oshwhub.com/bai-yy/stm32-hu-atgm336h-zeng-ge-yi-biao_copy_copy
在开发软件过程中,在论坛 https://www.armbbs.cn/ 获益良多,感谢硬汉大佬的H7系列开源代码以及热心帮助!

特别感谢嘉立创的星火计划提供耗材支持!

7 外观

IMG_20241010_191342.jpg

IMG_20241010_193834.jpg

IMG_20241010_193847.jpg

IMG_20241010_193859.jpg

IMG_20241010_193913.jpg

代码开源地址

Keil工程源码:https://github.com/vrxiaojie/STM32H743ZGT6

Gui_Guider源码:
https://github.com/vrxiaojie/STM32H743ZGT6/releases/tag/Gui_Guider_V1.0

设计图

未生成预览图,请在编辑器重新保存一次

BOM

暂无BOM

附件

序号文件名称下载次数
1
H743百宝箱.mp4
128
2
STM32H743ZGT6.hex
158
克隆工程
添加到专辑
0
0
分享
侵权投诉

工程成员

评论

全部评论(1)
按时间排序|按热度排序
粉丝0|获赞0
相关工程
暂无相关工程

底部导航