【下载链接】
链接:https://pan.baidu.com/s/1gCQ2ayH2OQz0bQBAciNJ4w
提取码:qljc

【使用说明】
(1)用ST-Link或JLink将Bootloader程序烧写到单片机中
(2)拔掉ST-Link或JLink调试器,复位单片机
(3)配置要烧写的程序的起始地址为0x8008000,程序区大小为“原大小-0x8000”,即0x100000-0x8000=0xf8000

(4)勾选“Create HEX file”

(5)打开STM32F4xx_HAL_Driver/system_stm32f4xx.c,取消USER_VECT_TAB_ADDRESS的注释,将VECT_TAB_OFFSET的值修改为0x8000

(6)编译程序,打开蓝牙串口无线烧写软件,选择生成的hex文件,将要烧写的程序烧写到子程序区

请注意:子程序里面必须要定时喂狗(IWDG),否则每隔10秒就会复位一次。

【Bootloader代码】

下载程序使用的串口为UART4,可以自行修改。

// 本程序用内部晶振(HSI)作为系统时钟, 没有用到外部晶振(HSE), 所以不需要指定HSE_VALUE的值
// 本程序已选择-O3优化。若要用ST-Link调试本程序, 请改选-O0优化
#include <stdio.h>
#include <stm32f4xx.h>
#include <string.h>
#include "common.h"
#include "DFU.h"// 若想要直接在Keil中下载并用ST-Link调试子程序, 则需要禁用CRC校验
#define START_ADDR 0x08004000 // 一定要保证这个地址不在DFU程序的地址范围中, 否则擦除Flash会直接Hard Error// 可以在项目属性中设置IROM1的Size, 限制主程序的大小, 防止主程序过大// 若主程序太大, 可以在C/C++选项卡中开启-O3优化减小主程序大小
#define RESERVED_SIZE 0x4000 // 请参考system_stm32xxx.c中描述的VECT_TAB_OFFSET的对齐方式// 里面有这样一句话: Vector Table base offset field. This value must be a multiple of 0xXXX.// 必须保证设置RESERVED_SIZE的值能被0xXXX整除, 并且在START_ADDR所在的Flash页上, RESERVED_SIZE能占满整页#define HARDWARE_CRC 0 // 启用硬件CRC校验
#define PROGRAM_ENABLE 1 // 是否真正烧写Flash (调试用)
#define PRINTF_ENABLE 1 // 是否开启调试输出
#define UART_FIFOCNT 35 // 数据缓冲区个数
#define UART_MTU 512 // 每个缓冲区的大小 (必须为4的倍数)#if UART_MTU % 4 != 0
#error "UART_MTU must be a multiple of 4"
#endifstatic int dfu_process_crc_config(const CRCConfig *config);
static int dfu_process_firmware_download(void);
static int dfu_start_transfer(void);DMA_HandleTypeDef hdma12, hdma14;
IWDG_HandleTypeDef hiwdg;
static const uint16_t flash_sectors[FLASH_SECTOR_TOTAL] = {16, 16, 16, 16, 64, 128, 128, 128, 128, 128, 128, 128}; // Flash各扇区的大小
static const uint32_t crc_disable __attribute((at(START_ADDR + 4))) = 0x54545454; // 默认禁用CRC, 这样ST-Link下载了主程序后能马上下载子程序
static uint8_t uart_data[UART_FIFOCNT][UART_MTU + 1];
static volatile uint8_t uart_front, uart_rear, uart_busy;
static volatile uint32_t uart_frontaddr, uart_rearaddr;
static DeviceResponse device_response;
static FirmwareInfo firmware_info;#if HARDWARE_CRC
// 注意: 不是所有的STM32单片机都能使用自定义CRC校验多项式
CRC_HandleTypeDef hcrc;static uint8_t calc_crc8(const void *data, int len)
{assert_param(HAL_CRC_GetState(&hcrc) == HAL_CRC_STATE_READY);return (uint8_t)HAL_CRC_Calculate(&hcrc, (uint32_t *)data, len);
}static void crc_init(void)
{__HAL_RCC_CRC_CLK_ENABLE();hcrc.Instance = CRC;hcrc.Init.CRCLength = CRC_POLYLENGTH_8B;hcrc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_DISABLE;hcrc.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_DISABLE;hcrc.Init.GeneratingPolynomial = POLYNOMIAL_CRC8 & 0xff;hcrc.Init.InitValue = 0;hcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_NONE;hcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_DISABLE;hcrc.InputDataFormat = CRC_INPUTDATA_FORMAT_BYTES;HAL_CRC_Init(&hcrc);
}
#else
static uint8_t calc_crc8(const void *data, int len)
{const uint8_t *p = data;int i, j;uint16_t temp = 0;if (len != 0)temp = p[0] << 8;for (i = 1; i <= len; i++){if (i != len)temp |= p[i];for (j = 0; j < 8; j++){if (temp & 0x8000)temp ^= POLYNOMIAL_CRC8 << 7;temp <<= 1;}}return temp >> 8;
}#define crc_init()
#endif// 请在这里配置串口收发所用的DMA通道
// 注意文件最后还有DMA中断的函数名也要改
static void dfu_dma_init(void)
{if (hdma12.Instance != NULL)return;__HAL_RCC_DMA1_CLK_ENABLE();hdma12.Instance = DMA1_Stream2;hdma12.Init.Channel = DMA_CHANNEL_4;hdma12.Init.Direction = DMA_PERIPH_TO_MEMORY; // 注意方向不要写反了(1)hdma12.Init.FIFOMode = DMA_FIFOMODE_DISABLE;hdma12.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;hdma12.Init.MemInc = DMA_MINC_ENABLE;hdma12.Init.Mode = DMA_NORMAL;hdma12.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;hdma12.Init.PeriphInc = DMA_PINC_DISABLE;hdma12.Init.Priority = DMA_PRIORITY_HIGH;HAL_DMA_Init(&hdma12);__HAL_LINKDMA(&huart4, hdmarx, hdma12); // 注意方向不要写反了(2)hdma14.Instance = DMA1_Stream4;hdma14.Init.Channel = DMA_CHANNEL_4;hdma14.Init.Direction = DMA_MEMORY_TO_PERIPH;hdma14.Init.FIFOMode = DMA_FIFOMODE_DISABLE;hdma14.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;hdma14.Init.MemInc = DMA_MINC_ENABLE;hdma14.Init.Mode = DMA_NORMAL;hdma14.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;hdma14.Init.PeriphInc = DMA_PINC_DISABLE;hdma14.Init.Priority = DMA_PRIORITY_HIGH;HAL_DMA_Init(&hdma14);__HAL_LINKDMA(&huart4, hdmatx, hdma14);
}static int dfu_process(void)
{int header_valid = 0;int i, j, len;uint8_t sync[16];uint32_t header;CRCConfig crccfg;// 发送成功进入DFU模式的回应memset(sync, 0xcd, sizeof(sync));HAL_UART_Transmit(&huart4, sync, sizeof(sync), HAL_MAX_DELAY);printf("Enter DFU mode!\n");// 接收请求信息i = 0;do{// 跳过冗余的0xab同步信号, 寻找头部字段HAL_IWDG_Refresh(&hiwdg);memset(uart_data[0], 0, UART_MTU);HAL_UART_Receive(&huart4, uart_data[0], UART_MTU, 1000);for (j = 0; j < UART_MTU; j++){if (uart_data[0][j] != 0xab)break;}len = UART_MTU - j;if (len >= 4){memcpy(&header, &uart_data[0][j], 4);switch (header){case HEADER_CRC_CONFIG:// CRC校验配置printf("header=HEADER_CRC_CONFIG\n");if (len >= sizeof(CRCConfig)){memcpy(&crccfg, &uart_data[0][j], sizeof(CRCConfig));if (calc_crc8(&crccfg, sizeof(CRCConfig)) == 0)header_valid = 1;}break;case HEADER_FIRMWARE_INFO:// 固件信息头printf("header=HEADER_FIRMWARE_INFO\n");if (len >= sizeof(FirmwareInfo)){memcpy(&firmware_info, &uart_data[0][j], sizeof(FirmwareInfo));if (calc_crc8(&firmware_info, sizeof(FirmwareInfo)) == 0)header_valid = 1;}break;default:printf("Invalid header: 0x%x\n", header);break;}printf("header_valid=%d\n", header_valid);}if (!header_valid){// 请求重传头部printf("Failed to receive header!\n");i++;if (i == 5)return -1;device_response.addr = 0xffffffff;device_response.size = 0xffffffff;device_response.checksum = calc_crc8(&device_response, sizeof(DeviceResponse) - 1);HAL_UART_Transmit(&huart4, (uint8_t *)&device_response, sizeof(DeviceResponse), HAL_MAX_DELAY);}} while (!header_valid);// 处理请求switch (header){case HEADER_CRC_CONFIG:return dfu_process_crc_config(&crccfg);case HEADER_FIRMWARE_INFO:return dfu_process_firmware_download();default:return -1;}
}/* 处理CRC校验配置请求 */
static int dfu_process_crc_config(const CRCConfig *config)
{int i;uint8_t buffer[8];uint8_t *value = (uint8_t *)START_ADDR + 5;uint32_t addr;
#if PROGRAM_ENABLEuint32_t err;FLASH_EraseInitTypeDef erase;
#endifmemcpy(buffer, (void *)START_ADDR, sizeof(buffer));buffer[5] = (config->crc_enabled) ? 0x00 : 0x54;if (*value != buffer[5]){addr = FLASH_BASE;for (i = 0; i < _countof(flash_sectors); i++){addr += flash_sectors[i] * 1024;if (addr > START_ADDR)break;}#if PROGRAM_ENABLEHAL_FLASH_Unlock();erase.Banks = FLASH_BANK_1;erase.TypeErase = FLASH_TYPEERASE_SECTORS;erase.Sector = i;erase.NbSectors = 1;erase.VoltageRange = FLASH_VOLTAGE_RANGE_3;HAL_FLASHEx_Erase(&erase, &err);HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, START_ADDR, __UNALIGNED_UINT32_READ(buffer));HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, START_ADDR + 4, __UNALIGNED_UINT32_READ(buffer + 4));HAL_FLASH_Lock();
#endif}device_response.addr = (uintptr_t)value;device_response.size = (memcmp((void *)START_ADDR, buffer, sizeof(buffer)) == 0);device_response.checksum = calc_crc8(&device_response, sizeof(DeviceResponse) - 1);HAL_UART_Transmit(&huart4, (uint8_t *)&device_response, sizeof(device_response), HAL_MAX_DELAY);return 0;
}/* 处理固件下载请求 */
static int dfu_process_firmware_download(void)
{int ret;uint32_t err, ticks;uint32_t maxsize, size;HAL_StatusTypeDef status;
#if PROGRAM_ENABLEint i;uint32_t addr[3];FLASH_EraseInitTypeDef erase;
#endifmaxsize = (FLASH_BASE + FLASH_SIZE) - (START_ADDR + RESERVED_SIZE);printf("Available flash: %u\n", maxsize);printf("Size: %u\n", firmware_info.size);printf("Address: 0x%08x - 0x%08x\n", firmware_info.start_addr, firmware_info.end_addr - 1);printf("Entry Point: 0x%08x\n", firmware_info.entry_point);printf("Checksum: 0x%02x\n", firmware_info.firmware_checksum);if (firmware_info.size > maxsize){// Flash容量不够device_response.addr = 0;device_response.size = maxsize;device_response.checksum = calc_crc8(&device_response, sizeof(DeviceResponse) - 1);HAL_UART_Transmit(&huart4, (uint8_t *)&device_response, sizeof(DeviceResponse), HAL_MAX_DELAY);return -1;}else if (firmware_info.start_addr != START_ADDR + RESERVED_SIZE){// 程序的起始地址不正确printf("Invalid firmware address!\n");device_response.addr = START_ADDR + RESERVED_SIZE;device_response.size = 0;device_response.checksum = calc_crc8(&device_response, sizeof(DeviceResponse) - 1);HAL_UART_Transmit(&huart4, (uint8_t *)&device_response, sizeof(DeviceResponse), HAL_MAX_DELAY);return -1;}else if (firmware_info.start_addr + firmware_info.size != firmware_info.end_addr){printf("Incorrect firmware size!\n");return -1;}// 利用中断, 并行接收数据HAL_NVIC_EnableIRQ(DMA1_Stream2_IRQn);HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);HAL_NVIC_EnableIRQ(UART4_IRQn);dfu_dma_init();uart_front = 0;uart_frontaddr = START_ADDR + RESERVED_SIZE;uart_rear = 0;uart_rearaddr = uart_frontaddr;dfu_start_transfer();#if PROGRAM_ENABLE// 擦除需要的Flash页HAL_IWDG_Refresh(&hiwdg);HAL_FLASH_Unlock();addr[0] = FLASH_BASE;addr[2] = firmware_info.end_addr - 1; // 子程序结束地址memset(&erase, 0xff, sizeof(FLASH_EraseInitTypeDef));for (i = 0; i < _countof(flash_sectors); i++){// i为扇区号, addr[0]为扇区i的起始地址, addr[1]为扇区i的结束地址addr[1] = addr[0] + flash_sectors[i] * 1024 - 1;if (START_ADDR >= addr[0] && START_ADDR <= addr[1])erase.Sector = i;if (addr[2] >= addr[0] && addr[2] <= addr[1]){erase.NbSectors = i - erase.Sector + 1;break;}addr[0] = addr[1] + 1;}erase.Banks = FLASH_BANK_1;erase.TypeErase = FLASH_TYPEERASE_SECTORS;erase.VoltageRange = FLASH_VOLTAGE_RANGE_3;printf("Erase sector %d~%d\n", erase.Sector, erase.Sector + erase.NbSectors - 1);HAL_FLASHEx_Erase(&erase, &err);// 将程序大小和CRC校验码保存到RESERVED区域, 并启用CRC校验HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, START_ADDR, firmware_info.size);HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, START_ADDR + 4, firmware_info.firmware_checksum);
#endifwhile (uart_frontaddr != firmware_info.end_addr){// 等待FIFO中有数据err = 0;ticks = HAL_GetTick();HAL_IWDG_Refresh(&hiwdg);while (uart_front == uart_rear){if (HAL_GetTick() - ticks > 3500){// 进入到这里面, 一般是因为传输过程中丢失了某些字节, 无法构成完整的数据包, DMA传输无法完成// (这不同于HAL_UART_RxCpltCallback里面的CRC错误, 只有收到了完整的数据包, 但CRC校验不通过, 才认定为CRC错误)// 也可能是因为用户取消了程序烧写HAL_IWDG_Refresh(&hiwdg);printf("Data timeout!\n");status = HAL_UART_Abort(&huart4); // 以阻塞方式强行中止中断或DMA方式的串口传输if (status == HAL_OK)uart_busy = 0; // 中止成功// 注意HAL_UART_Abort和HAL_UART_Abort_IT的区别// HAL_UART_Abort在函数返回时已经中止成功, 不会触发回调函数// HAL_UART_Abort_IT是以中断方式强行中止中断或DMA方式的串口传输// 函数返回时不一定已经中止完毕, 直到HAL_UART_AbortCpltCallback回调函数触发时, 才算中止完毕// 请求上位机重传数据包err++;if (err == 3)break; // 10秒还没有反应, 强行退出ticks = HAL_GetTick();dfu_start_transfer();}}if (uart_front == uart_rear)break;// 计算数据量maxsize = firmware_info.end_addr - uart_frontaddr;size = UART_MTU;if (size > maxsize)size = maxsize;// 烧写Flash// 注意: 当地址不能被4整除时, 不能用*(uint32_t *)//       应该用*(__packed uint32_t *), 即__UNALIGNED_UINT32_READ, 否则会导致Hard Error
#if PROGRAM_ENABLEHAL_IWDG_Refresh(&hiwdg);for (i = 0; i < size; i += 4)HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, uart_frontaddr + i, __UNALIGNED_UINT32_READ(uart_data[uart_front] + i));
#endif// 释放FIFOuart_front = (uart_front + 1) % UART_FIFOCNT;uart_frontaddr += size;}// 结束请求assert_param(!uart_busy);HAL_IWDG_Refresh(&hiwdg);HAL_NVIC_DisableIRQ(DMA1_Stream2_IRQn);HAL_NVIC_DisableIRQ(DMA1_Stream4_IRQn);HAL_NVIC_DisableIRQ(UART4_IRQn);if (uart_frontaddr == firmware_info.end_addr){device_response.addr = uart_frontaddr;device_response.size = 0;device_response.checksum = calc_crc8(&device_response, sizeof(DeviceResponse) - 1);HAL_UART_Transmit(&huart4, (uint8_t *)&device_response, sizeof(DeviceResponse), HAL_MAX_DELAY);ret = 0;}elseret = -1;#if PROGRAM_ENABLEHAL_FLASH_Lock();
#endifreturn ret;
}/* 请求主机传输固件数据 */
static int dfu_start_transfer(void)
{uint32_t maxsize;if (uart_busy)return -1;if (huart4.gState != HAL_UART_STATE_READY)return -1; // 如果UART Handle被锁, 则暂不启动传输, 稍后在TxCallback里面重试 (STM32H7就有这种问题)if ((uart_rear + 1) % UART_FIFOCNT == uart_front)return -1; // FIFO已满maxsize = firmware_info.end_addr - uart_rearaddr;if (maxsize == 0)return -1; // 固件已传输完毕HAL_IWDG_Refresh(&hiwdg);uart_busy = 1;device_response.addr = uart_rearaddr;device_response.size = UART_MTU;if (device_response.size > maxsize)device_response.size = maxsize;device_response.checksum = calc_crc8(&device_response, sizeof(DeviceResponse) - 1);HAL_UART_Transmit_DMA(&huart4, (uint8_t *)&device_response, sizeof(DeviceResponse));HAL_UART_Receive_DMA(&huart4, uart_data[uart_rear], device_response.size + 1);return 0;
}static int dfu_sync(void)
{int i;uint8_t sync[16];HAL_StatusTypeDef status;status = HAL_UART_Receive(&huart4, sync, sizeof(sync), 100);if (status == HAL_OK){for (i = 0; i < sizeof(sync); i++){if (sync[i] != 0xab)break;}if (i == sizeof(sync))return 0;}return -1;
}static void iwdg_init(void)
{
#ifdef __HAL_RCC_DBGMCU_CLK_ENABLE__HAL_RCC_DBGMCU_CLK_ENABLE();
#endif
#ifdef __HAL_DBGMCU_FREEZE_IWDG__HAL_DBGMCU_FREEZE_IWDG();
#endifhiwdg.Instance = IWDG;hiwdg.Init.Prescaler = IWDG_PRESCALER_128;hiwdg.Init.Reload = 2499; // 超时时间为(2499+1)*4ms=10s//hiwdg.Init.Window = 4095; // 有的STM32的IWDG有Window参数, 必须要设置HAL_IWDG_Init(&hiwdg);
}static int jump_to_application(void)
{static Runnable run;const uint8_t *crc = (const uint8_t *)(START_ADDR + 4);const uint32_t *size = (const uint32_t *)START_ADDR;uint32_t *addr = (uint32_t *)(START_ADDR + RESERVED_SIZE + 4);uint32_t *msp = (uint32_t *)(START_ADDR + RESERVED_SIZE);uint32_t value;if (*(crc + 1) == 0x54){// CRC校验已关闭printf("CRC check has been disabled!\n");}else{// 进行CRC校验if (START_ADDR + RESERVED_SIZE + *size > FLASH_BASE + FLASH_SIZE){printf("Program data error!\n");return -1;}value = calc_crc8((const uint8_t *)START_ADDR + RESERVED_SIZE, *size);if (*crc == value)printf("CRC passed! addr=0x%08x, msp=0x%08x\n", *addr, *msp);else{printf("CRC failed! 0x%02x!=0x%02x\n", *crc, value);return -1;}}if ((*msp & 0xf0000000) != 0x20000000 || (*addr & 0xff000000) != 0x08000000){printf("Program data error!\n");return -1;}printf("Jump to application...\n");run = (Runnable)*addr;HAL_DeInit(); // 关闭所有外设和中断, 防止子程序的运行受到主程序的影响 (很重要)// 一旦修改了栈顶指针, 就不能再使用函数中的局部变量, 否则可能会出现Hard Error错误// 但可以使用static变量, 所以run变量必须声明为static__set_MSP(*msp); // 修改栈顶指针run();return 0;
}int main(void)
{int dfu_cnt = 3; // DFU请求同步次数 (数值越大, 上位机检测到设备的成功率越高, 但开机后程序启动越慢)int ret;HAL_Init();iwdg_init();usart_init(115200);printf_enable(PRINTF_ENABLE);printf("STM32F405RG DFU\n");printf("SystemCoreClock=%u\n", SystemCoreClock);crc_init();while (1){while (dfu_cnt > 0){HAL_IWDG_Refresh(&hiwdg);dfu_cnt--;ret = dfu_sync(); // 接收主机的DFU请求if (ret == 0){// 成功进入DFU模式ret = dfu_process(); // DFU处理// 暂停, 等待上位机下发命令printf("Send any command to continue...\n");while (__HAL_UART_GET_FLAG(&huart4, UART_FLAG_RXNE) == RESET)HAL_IWDG_Refresh(&hiwdg);HAL_UART_Receive(&huart4, uart_data[0], 1, HAL_MAX_DELAY);if (ret == 0){dfu_cnt = 0; // 程序下载成功后, 启动程序HAL_Delay(2000); // 延迟足够的时间, 保证即使是用有线串口, 也能在打开串口调试助手后看到第一行调试信息}elsedfu_cnt = 10; // 程序下载失败时, 不运行程序, 而是重新进入下载模式}}// 启动用户程序 (若启动成功, 则函数不返回)HAL_IWDG_Refresh(&hiwdg);jump_to_application();// 启动用户程序失败, 再次进入DFU模式HAL_Delay(250);dfu_cnt = 1;}
}void DMA1_Stream2_IRQHandler(void)
{HAL_DMA_IRQHandler(&hdma12);
}void DMA1_Stream4_IRQHandler(void)
{HAL_DMA_IRQHandler(&hdma14);
}void UART4_IRQHandler(void)
{HAL_UART_IRQHandler(&huart4);
}void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{if (huart->Instance == USART1)printf("USART1 error: 0x%x!\n", huart->ErrorCode);else if (huart->Instance == UART4)printf("UART4 error: 0x%x!\n", huart->ErrorCode);
}void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{uint8_t crc;// 进行CRC校验crc = calc_crc8(uart_data[uart_rear], device_response.size + 1);if (crc == 0){uart_rear = (uart_rear + 1) % UART_FIFOCNT; // 校验通过, 接收下一个数据包uart_rearaddr += device_response.size;}elseprintf("Data CRC failed!\n");uart_busy = 0;dfu_start_transfer();
}void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{dfu_start_transfer();
}

【蓝牙串口无线烧写程序】适用于STM32F405RG的Bootloader相关推荐

  1. Stm32开发1-蓝牙实现STM32的无线烧写程序 ISP模式 串口1不受影响 无线下载

    最近研究如何实现Stm32的无线烧写程序.从CSDN上看到大部分的无线烧写方法,大都是采用ESP8266+CMSIS-DAP的方式,其能下载也能调试程序,也能通过虚拟串口通信.但是其串口应该是用软件实 ...

  2. STC单片机蓝牙无线下载-烧写程序ISP(STC8 STC15 STC12 STC11 STC89)

    前一阵子用单片机开发一个小东西,其应用在一个非常潮湿的环境,以至于电脑和人员没发接近,但是又需要很长时间来调整参数,才能将设备设定好.另外设备一直在转动,这又导致不能通过电缆下载程序.在此时,我想到了 ...

  3. 瑞萨e2studio(5)----使用UART串口烧写程序到瑞萨芯片

    瑞萨e2studio.5----使用UART串口烧写程序到瑞萨芯片 概述 视频教学 csdn课程 样品申请 硬件准备 软件准备 hex文件准备 UART串口与瑞萨开发板进行接线 烧录 概述 本篇文章主 ...

  4. atmega8a如何烧写程序_快捷又安全!如何利用芯片内部Bootloader烧写程序?

    CC2640 R2是德州仪器推出的面向 Bluetooth Smart 应用的低功耗无线 MCU.该芯片运行TI的BLE协议栈,具有功耗低,外设种类丰富,射频性能好等特点.利用它可以实现许多有趣的应用 ...

  5. 开发板之驱动安装与烧写程序

    硬件接口 开发板接口:板载USB串口.JTAG.usb下载口(dnw) 软件下载 USB串口连接及驱动安装 串口驱动的安装非常简单: 运行串口驱动 PL2303_Prolific_DriverInst ...

  6. 51单片机usb烧录电路_51单片机怎么用usb烧写程序 - 全文

    单片机怎样用usb烧写程序 首先,需要安装keil软件和STC_ISP程序下载软件. 先对你想要实现对单片机的功能用keil编程,然后用STC_ISP下载软件下载到单片机上,最后打开给单片机提供电源就 ...

  7. 给单片机焼写程序需要什么东西_单片机怎么烧写程序

    1.单片机怎么烧写程序 STC系列单片机为例:首先,需要安装keil软件和STC_ISP程序下载软件.先对你想要实现对单片机的功能用keil编程,然后用STC_ISP下载软件下载到单片机上,最后打开给 ...

  8. C语言烧写C51单片机的线,51单片机烧写程序过程以及详细说明【图文】

    Step 1:Keil软件的安装 1.选中文件夹中的C51V900安装程序并打开,如图: 2.在安装对话框里一直选择Next,直到Finish完成Keil的安装. Step 2: 安装USB转串口线的 ...

  9. 32通过rs485烧写程序_28027芯片sci程序烧写问题请教

    需求:希望用TI官方提供的"f28027_flash_kernel"过通sci串口烧录程序 如下所示bootload与pc烧录软件都是TI官方提供的. pc烧录软件: D:tico ...

最新文章

  1. 数据蒋堂 | JOIN延伸 - 维度查询语法
  2. 解决win8.1企业版安装WP8 SDK出现“根据当前系统时钟或签名文件中的时间戳验证时要求的证书不在有效期内”的问题
  3. 牛客题霸 [ 排序] C++题解/答案
  4. 为什么python不需要编译_为什么我用Go写机器学习部署平台,而偏偏不用Python?...
  5. 2 python全局变量如何指定(是在模块内,还是函数内)
  6. springmvc细节篇
  7. 面试官问:Mybatis Plus 是如何实现动态 SQL 语句的?原理你懂吗?
  8. String、StringBuffer和StringBuilder
  9. 处理效应模型stata实例_『Stata』政策处理效应PSM模型基本命令汇总
  10. 腾讯云服务器入门使用流程 新手必看教程
  11. 【git提交报错】git commit 提交的时候报错husky > pre-commit (node v16.15.0) No staged files match any of provided
  12. jQuery全选全删动态表格
  13. 11. Container With Most Wate
  14. 【java毕业设计】基于javaEE+原生Servlet+SqlServer的医院管理住院系统设计与实现(毕业论文+程序源码)——医院管理住院系统
  15. 富士康计算机类笔试题,富士康2021校招技术类笔试题
  16. The Devil Wears Prada-3
  17. 大众点评app数据采集接口
  18. Ubuntu 16.10 禁用 Guest 访客模式
  19. java实现未读消息提醒_JS(jQuery)实现聊天接收到消息语言自动提醒功能详解【提示“您有新的消息请注意查收”】...
  20. wireshark过滤器

热门文章

  1. 金蝶虚拟化客户端连不上服务器,金蝶kis客户端远程连接服务器
  2. python识别屏幕图像后点击操作_Python学习笔记——用GUI自动化控制键盘和鼠标
  3. kodi mysql_Kodi
  4. oracle游标添加数据,Oracle使用游标更新数据
  5. Java线程池与Lambda表达式
  6. 人生就是一个醒悟的过程(深度好文)
  7. 【5G/4G】NAS与AS层 完整性保护与加密算法系列文章
  8. 关于启动 vue 项目出现 98% after emitting CopyPlugin 的解决方法!
  9. 微信 语音转文字 java,微信语音转文字怎么操作?手把手教你,一秒钟搞定!
  10. python爬虫模式_python爬虫的入门试炼