加入星计划,您可以享受以下权益:

  • 创作内容快速变现
  • 行业影响力扩散
  • 作品版权保护
  • 300W+ 专业用户
  • 1.5W+ 优质创作者
  • 5000+ 长期合作伙伴
立即加入

嵌入式工具库-脱机离线下载器(STM32F103C8T6)

03/20 16:33
5475
服务支持:
技术交流群

完成交易后在“购买成功”页面扫码入群,即可与技术大咖们分享疑惑和经验、收获成长和认同、领取优惠和红包等。

虚拟商品不可退

当前内容为数字版权作品,购买后不支持退换且无法转移使用。

加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论
放大
原理图
电路板图(3)
相关方案
  • 方案介绍
    • 前言
    • 原理图:
    • 脱机下载器资料获取
    • PCB
    • 3D效果
    • 实物图
    • 主要代码展示
    • 演示视频
    • 若需要帮助,请咨询博主
  • 相关文件
  • 推荐器件
  • 相关推荐
  • 电子产业图谱
申请入驻 产业图谱

前言

在Gitee上发现了一个脱机下载器项目,我决定实践复刻它。首先,我阅读了项目的代码,了解其实现原理和功能。接着,我自己进行一个电路图的绘画,并通过STM32系列的芯片进行了配置和连接。然后,按照原理图对代码进行了适当的修改和调整,以适配我的硬件环境。最后,我进行了编译、烧录和调试的工作,测试了脱机下载器的功能,确保其正常工作。

最后进行了整机的调试,完成了这个复刻,后续将添加在线下载功能 ~~~~~

原理图:

主要运用到的元器件

STM32F103C8T6,W25Q128,无源晶振(8M),3.3稳压模块,RGB灯(0805)

使用立创经行的换图与连线,咱就图个免费 ~~

完成功能

1.离线下载

2.设置下载地址

3.添加提示音以及状态灯

脱机下载器资料获取

关注微信公众号 -- 星之援工作室 发送关键字(脱机下载器

➡️➡️

欢迎关注微信公众号星之援工作室,公众号不定时开源设计项目

支持单片机,Android系统设计成品定制,项目代做

请联系微信:13648103287

PCB

绘制了两板图,一版是直接焊屏幕,一版就是直接买屏幕,个人偏向买屏幕,毕竟少焊点东西啦,节约时间以及提高容错率

3D效果

正面

反面

实物图

主要代码展示

main.c

/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * @file           : main.c
 * @brief          : Main program body
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2022 STMicroelectronics.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usb_device.h"
#include "key.h"
#include "led.h"
#include "oled.h"
#include "ff.h"
#include "flash_blob.h"
#include "offline.h"
#include "hex2bin.h"
#include "stmflash.h"

FRESULT Res;
FIL fnew;				  /* file objects */
FATFS fs;				  /* FatFs文件系统对象 */
DIR DirInfo;			  /* 目录信息 */
FILINFO FileInfo;		  /* 文件信息 */
int8_t name_cnt = 0;	  /* 文件个数 */
BYTE work[FF_MAX_SS];	  /* FatFs文件工作区域 */
char Name_Buffer[20][20]; /* 文件名 */
int8_t Select_file = 0;	  /* 选中下载文件 */
uint32_t flash_addr = 0x8000000;
uint8_t mode = 0;

int main(void)
{
	uint8_t RES_FS = 0;
	uint8_t addr[4];
	HAL_Init();
	SystemClock_Config();
	OLED_Init();
	MX_USB_DEVICE_Init();
	MX_KEY_Init();
	MX_LED_Init();

	// 赋值falsh
	//  STMFLASH_Read(FLASH_SAVE_ADDR, (uint16_t *)addr, 4);
	//  flash_addr = ((addr[0] << 8 | addr[1]) << 8 | addr[2]) << 8 | addr[3];

	// FATFS文件系统挂载
	algo_init();				  // 下载算法初始化
	RES_FS = f_mount(&fs, "", 1); // 挂载文件系统
	if (RES_FS == FR_OK)
		;
	else if (RES_FS == FR_NO_FILESYSTEM) // 如果是新芯片还没有文件系统
	{
		OLED_ShowString(0, 2, "Fatfs Format..", 12);
		f_mkfs("", 0, work, sizeof(work));
		OLED_ShowString(0, 2, "Format Finished", 12);
	}
	else
		OLED_ShowString(0, 2, "Fatfs Failed..", 12);

	// f_unlink("write.bin");
	//  读取文件名到文件列表
	if (f_opendir(&DirInfo, (const TCHAR *)"0:") == FR_OK) // 读取根目录下文件信息
	{
		f_readdir(&DirInfo, &FileInfo);
		while (f_readdir(&DirInfo, &FileInfo) == FR_OK) // 读文件信息到文件状态结构体中
		{
			if (!FileInfo.fname[0])
				break;
			strcpy(Name_Buffer[name_cnt], FileInfo.fname);
			if (strstr(Name_Buffer[name_cnt], ".BIN"))
			{
				name_cnt++;
				if (name_cnt >= 20) // 最多保存20个文件名
					break;
			}
			if (strstr(Name_Buffer[name_cnt], ".HEX"))
			{
				name_cnt++;
				if (name_cnt >= 20) // 最多保存20个文件名
					break;
			}
		}
	}
	while (1)
	{
		menu();
	}
	/* USER CODE END 3 */
}

void menu(void)
{
	static uint8_t mode_status = 0;
	switch (mode)
	{
	case 0: // 功能选择
		select_function();
		break;
	case 1: // 离线下载模式
		Downloader();
		break;
	case 2: // flash下载地址
		FlashAddr_Set();
		break;
	}
	if (mode != mode_status)
	{
		mode_status = mode;
		OLED_Clear();
	}
}

void OLED_ShowMenu(uint8_t num)
{
	switch (num)
	{
	case 0: // 离线下载
		OLED_ShowCH(24, 0, 0);
		OLED_ShowCH(36, 0, 1);
		OLED_ShowCH(48, 0, 2);
		OLED_ShowCH(60, 0, 3);
		// 地址设置
		OLED_ShowCH(24, 2, 4);
		OLED_ShowCH(36, 2, 5);
		OLED_ShowCH(48, 2, 6);
		OLED_ShowCH(60, 2, 7);
		break;

	case 1: // 文件选择
		OLED_ShowCH(0, 0, 8);
		OLED_ShowCH(12, 0, 9);
		OLED_ShowCH(24, 0, 10);
		OLED_ShowCH(36, 0, 11);
		break;

	case 2: // 地址
		OLED_ShowString(0, 0, "FLASH", 12);
		OLED_ShowCH(40, 0, 12);
		OLED_ShowCH(52, 0, 13);
		OLED_ShowCH(64, 0, 4);
		OLED_ShowCH(76, 0, 5);
		break;
	}
}

void select_function(void)
{
	static uint8_t t = 1;
	uint8_t key;
	key = KEY_Scan();
	if (key == KEY0_PRES)
	{
		t++;
		if (t > 2)
			t = 1;
	}
	else if (key == KEY1_PRES) // 返回主页面
	{
		mode = 0;
		t = 1;
	}
	else if (key == KEY2_PRES) // 确认
	{
		mode = t;
		t = 1;
	}
	switch (t)
	{
	case 1:
		OLED_ShowString(0, 2, "  ", 12);
		OLED_ShowString(0, 0, "->", 12);
		break;

	case 2:
		OLED_ShowString(0, 0, "  ", 12);
		OLED_ShowString(0, 2, "->", 12);
		break;
	}
	OLED_ShowMenu(0);
}

void Downloader(void)
{
	uint8_t key = 0;
	key = KEY_Scan();
	if (key == KEY0_PRES)
	{
		Select_file++;
		OLED_ShowString(0, 2, "                ", 12);
	}
	else if (key == KEY1_PRES) // 返回主页面
		mode = 0;
	else if (key == KEY2_PRES)
		Auto_Fash();
	if (name_cnt == 0)
		Select_file = 0;
	else
	{
		if (Select_file >= name_cnt)
			Select_file = 0;
		else if (Select_file < 0)
			Select_file = name_cnt - 1;
	}
	OLED_ShowMenu(1);
	OLED_ShowString(0, 2, (uint8_t *)Name_Buffer[Select_file], 12);
	if (name_cnt == 0)
		OLED_ShowNum(90, 0, Select_file, 2, 12);
	else
		OLED_ShowNum(90, 0, Select_file + 1, 2, 12);
	OLED_ShowString(102, 0, "/", 12);
	OLED_ShowNum(114, 0, name_cnt, 2, 12);
}

void FlashAddr_Set(void)
{
	static uint8_t k = 0, k1 = 0;
	static uint8_t setmode = 0;
	static uint8_t ad[4];
	static uint8_t addr[8];
	uint8_t key = 0, i;
	addr[7] = (flash_addr / 0x01) % 16;
	addr[6] = (flash_addr / 0x10) % 16;
	addr[5] = (flash_addr / 0x100) % 16;
	addr[4] = (flash_addr / 0x1000) % 16;
	addr[3] = (flash_addr / 0x10000) % 16;
	addr[2] = (flash_addr / 0x100000) % 16;
	addr[1] = (flash_addr / 0x1000000) % 16;
	addr[0] = (flash_addr / 0x10000000) % 16;
	OLED_ShowMenu(2);
	OLED_ShowString(0, 2, "0x", 12);

	while (1)
	{
		for (i = 0; i < 8; i++)
		{
			if (addr[i] < 10)
				OLED_ShowChar(18 + 6 * i, 2, addr[i] + 48, 12);
			else
				OLED_ShowChar(18 + 6 * i, 2, addr[i] + 65 - 10, 12);
		}

		key = KEY_Scan();
		if (key == KEY0_PRES)
		{
			if (setmode == 0)
			{
				OLED_ShowString(18 + 6 * k, 3, "|", 12);
				setmode = 1;
			}
			else if (setmode == 1)
			{
				addr[k]++;
				if (addr[k] > 15)
					addr[k] = 0;
			}
		}
		else if (key == KEY1_PRES)
		{
			if (setmode == 0)
			{
				mode = 0;
				break;
			}
			else if (setmode == 1)
			{
				k++;
				if (k >= 8)
					k = 0;
			}
		}
		else if (key == KEY2_PRES)
		{
			if (setmode == 0)
			{
				// flash_addr = 0;

				ad[0] = addr[0] << 4 | addr[1];
				ad[1] = addr[2] << 4 | addr[3];
				ad[2] = addr[4] << 4 | addr[5];
				ad[3] = addr[6] << 4 | addr[7];

				flash_addr = ((ad[0] << 8 | ad[1]) << 8 | ad[2]) << 8 | ad[3];
				STMFLASH_Write(FLASH_SAVE_ADDR, (uint16_t *)ad, 4);
				HAL_Delay(1000);
				mode = 0;
				k = 0;
				break;
			}
			else if (setmode == 1)
			{
				setmode = 0;
				OLED_ShowString(18 + 6 * k1, 3, " ", 12);
			}
		}

		if (k1 != k)
		{
			OLED_ShowString(18 + 6 * k1, 3, " ", 12);
			OLED_ShowString(18 + 6 * k, 3, "|", 12);
			k1 = k;
		}
	}
}

/**
 * @brief System Clock Configuration
 * @retval None
 */
void SystemClock_Config(void)
{
	RCC_OscInitTypeDef RCC_OscInitStruct = {0};
	RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
	RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

	/** Initializes the RCC Oscillators according to the specified parameters
	 * in the RCC_OscInitTypeDef structure.
	 */
	RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
	RCC_OscInitStruct.HSEState = RCC_HSE_ON;
	RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
	RCC_OscInitStruct.HSIState = RCC_HSI_ON;
	RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
	RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
	RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
	if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
	{
		Error_Handler();
	}
	/** Initializes the CPU, AHB and APB buses clocks
	 */
	RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
	RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
	RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
	RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
	RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

	if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
	{
		Error_Handler();
	}
	PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB;
	PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_PLL_DIV1_5;
	if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
	{
		Error_Handler();
	}
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
 * @brief  This function is executed in case of error occurrence.
 * @retval None
 */
void Error_Handler(void)
{
	/* USER CODE BEGIN Error_Handler_Debug */
	/* User can add his own implementation to report the HAL error return state */
	__disable_irq();
	while (1)
	{
	}
	/* USER CODE END Error_Handler_Debug */
}

#ifdef USE_FULL_ASSERT
/**
 * @brief  Reports the name of the source file and the source line number
 *         where the assert_param error has occurred.
 * @param  file: pointer to the source file name
 * @param  line: assert_param error line source number
 * @retval None
 */
void assert_failed(uint8_t *file, uint32_t line)
{
	/* USER CODE BEGIN 6 */
	/* User can add his own implementation to report the file name and line number,
	   ex: printf("Wrong parameters value: file %s on line %drn", file, line) */
	/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

演示视频

USB文件(自己使用自己的HEX文件即可)

百度网盘

链接:https://pan.baidu.com/s/1sz5dzR5yzwIxZ_9EqGQ5Yw?pwd=xzy0
提取码:xzy0 

若需要帮助,请咨询博主


⚠️⚠️END⚠️⚠️


联系方式 微信号:13648103287

  • 联系方式.docx

推荐器件

更多器件
器件型号 数量 器件厂商 器件描述 数据手册 ECAD模型 风险等级 参考价格 更多信息
HCPL2631SD 1 onsemi 8-Pin DIP Dual-Channel High Speed 10 MBit/s Logic Gate Output Optocoupler (Not recommend for new design. The new equivalent part number is HCPL26xxM), 1000-REEL
$1.73 查看
DS2431P+T&R 1 Maxim Integrated Products EEPROM, 1KX1, Serial, CMOS, PDSO6, ROHS COMPLIANT, TSOC-6
$3.87 查看
LTC2875IS8#PBF 1 Analog Devices Inc ±60V Fault Protected 3.3V or 5V 25kV ESD High Speed CAN FD Transceiver

ECAD模型

下载ECAD模型
$3.09 查看

相关推荐

电子产业图谱

方案定制,程序设计方案、单片机程序设计与讲解、APP定制开发。本公众号致力于向读者传递关于程序设计和开发的相关知识,并分享一些关于软件开发的最佳实践。如果您有什么问题或建议,请随时联系我们。我们将竭诚为您服务