- 下载官方IAP:STSW-STM32008 - 使用USART进行STM32F10xxx应用内编程(AN2557) - 意法半导体STMicroelectronics
- 打开工程
- 官方例程是通过控制按键进入IAP控制程序,将按键控制修改为时间控制,复位后5S内未接收到值‘U’(0x5050)就进入主程序。
选择STM32F10E-EVAL进行编译,添加定时器驱动程序,再在stm3210e_eval.c中添加定时器初始化程序以及串口判断程序,并在stm32f10e_eval.h加入函数声明
/****************************DTJ_ADD_START**************************************/
#include "stm32f10x_tim.h"
#include "common.h"
uint16_t timer_count=0;
void TIMER_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
//定时器TIM3初始化
TIM_TimeBaseStructure.TIM_Period = arr-1; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc-1; //设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
//中断优先级NVIC设置
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器
TIM_SetCounter(TIM3, 0);
TIM_Cmd(TIM3, ENABLE);
}
volatile uint16_t temp2;
//判断是否有命令,如超时未接收到命令,返回0
uint16_t IsGetKey(void)
{
uint8_t key = 0;
uint8_t flag = 0;
/* Waiting for user input */
while (timer_count < 50)
{
if (SerialKeyPressed((uint8_t*)&key))
{
if(key == 0x55)
{
flag=1;
break;
}
}
}
TIM_Cmd(TIM3, DISABLE);
TIM_SetCounter(TIM3, 0);
TIM_ITConfig(TIM3, TIM_IT_Update, DISABLE);
NVIC_DisableIRQ(TIM3_IRQn);
return flag;
}
void TIM3_IRQHandler(void) //TIM3中断
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查TIM3更新中断发生与否
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx更新中断标志
timer_count++;
}
}
/****************************DTJ_ADD_EDD****************************************/
- 修改主函数
int main(void)
{
/* Flash unlock */
FLASH_Unlock();
IAP_Init(); //初始化串口,默认USART1
SerialPutString("Enter the command 'U' or enter the main program in five seconds\r\n");
//初始化定时器,设为100ms产生一次中断
TIMER_Init(7200,1000);
/* Test if Key push-button on STM3210X-EVAL Board is pressed */
if(IsGetKey())
{
/* If Key is pressed */
/* Execute the IAP driver in order to re-program the Flash */
SerialPutString("\r\n======================================================================");
SerialPutString("\r\n= (C) COPYRIGHT 2010 STMicroelectronics =");
SerialPutString("\r\n= =");
SerialPutString("\r\n= In-Application Programming Application (Version 3.3.0) =");
SerialPutString("\r\n= =");
SerialPutString("\r\n= By MCD Application Team =");
SerialPutString("\r\n======================================================================");
SerialPutString("\r\n\r\n");
Main_Menu ();
}
/* Keep the user application running */
else
{
/* Test if user code is programmed starting from address "ApplicationAddress" */
if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)
{
/* Jump to user application */
JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
Jump_To_Application = (pFunction) JumpAddress;
/* Initialize user application's Stack Pointer */
__set_MSP(*(__IO uint32_t*) ApplicationAddress);
Jump_To_Application();
}
}
while (1)
{}
}
修改程序烧录位置
至此IAP程序修改完成,用Jlink/STlink烧录IAP程序。
- 新建一个APP程序
选择对应的MCU,设置外部晶振,设置时钟树
- 初始化串口+LED
- 在main函数起始位置设置中断向量表偏移,在while函数中点灯,同时设置收到指令可以复位
#include "stdio.h"
uint8_t rxdata,rxflag;
int main(void)
{
/* USER CODE BEGIN 1 */
SCB->VTOR = FLASH_BASE | 0x3000; // 0x1C00 即 BootLoader 大小(偏移量)
/* 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();
/* USER CODE BEGIN 2 */
HAL_UART_Receive_IT(&huart1,&rxdata,1);
printf("here is APP\r\n");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_GPIO_TogglePin(LED_RED_GPIO_Port,LED_RED_Pin);
HAL_Delay(1000);
if(rxflag==1)
{
rxflag=0;
HAL_UART_Receive_IT(&huart1,&rxdata,1);
if(rxdata == 0x31)
{
NVIC_SystemReset();
}
}
}
/* USER CODE END 3 */
}
/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart == &huart1)
{
rxflag=1;
}
}
/* USER CODE END 4 */
- 在usart.c中重定义printf
#include "stdio.h"
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
/**
* 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
return ch;
}
- 修改烧录地址
$K\ARM\ARMCC\bin\fromelf.exe --bin --output=@L.bin !L
至此APP程序编写完成;
- 用正点原子串口工具连接串口
SecureCRT有个问题,如果连接的时候复位的话,程序会复位失败(暂时不知道原因);先用正点原子的串口工具连接串口,按下复位键,再输入U,再输入1,此时需要传输程序,断开正点原子串口工具,连接SECURECRT工具
- 通过SECURECRT下载APP程序
下载成功之后,按下按键3进入APP程序。进入APP程序之后,按下1会进行软复位,此时可重新开始烧录。