串口离线升级工具

在这里插入图片描述

实现思路

除了传统的bootloader外,在boot区还要实现将app从串口发送出去的功能

  1. bootloader:将新的APP的bin文件从上位机中下载下来到flash区以及将APP发送到板子上的bootloader。
  2. 离线升级工具:与上位机通讯的bootloader和通过按键选择通信方式的多个bootloader。
  3. 上位机

调试经验

  1. 上位机下载APP至离线升级工具时,所使用的串口配置与工具发送APP至产品时所使用的串口配置,两者应慎重考虑,不能有重复定义的变量。
//串口1
#define USARTy               UART3
#define UART1_TX_Port        GPIOB
#define UART1_TX_Pin		 GPIO_PIN_10
#define UART1_TX_AF			 GPIO_AF10_UART3
#define UART1_RX_Port        GPIOB
#define UART1_RX_Pin         GPIO_PIN_11
#define UART1_RX_AF			 GPIO_AF10_UART3
//串口2
#define USARTy_IRQHandler           USART1_IRQHandler
#ifdef _USART1_USART2_
//#define USARTy                      USART1
#define USARTy_CLK                  RCC_APB2_PERIPH_USART1
#define USARTy_GPIO                 GPIOA
#define USARTy_GPIO_CLK             RCC_AHB_PERIPH_GPIOA
#define USARTy_RxPin                GPIO_PIN_10
#define USARTy_TxPin                GPIO_PIN_9
#define USARTy_Rx_GPIO_AF           GPIO_AF5_USART1
#define USARTy_Tx_GPIO_AF           GPIO_AF5_USART1
  1. 慎重考虑flash空间的大小,离线工具功能加bootloader功能,占用的flash空间远高于传统的bootloader,当flash不超过64k且boot为23k时,APP大小不能够超过40k,否则程序会停止运行。
  2. 重定义及隐式声明告警一定清。
  3. 用定时器实现串口的接收超时中断功能,需要仔细计算定时器的超时时间。
    时钟树
    如果时钟从头开始配置,需要从头开始计算时钟频率;
    如果时钟没有从头开始配置,使用默认值,比如如下代码中SYSCLK默认为128k,由于SYSCLK到AHB的时钟同样没有配置,HCLK默认为128MHz。
    时钟计算:
    BSTIMClockFrequency = Common_BSTIM_RCC_Initialize(TIM6, RCC_HCLK_DIV4):表明将HCLK四分频,经过APB1后的频率变为32MHz,
    Common_TIM_Base_Initialize(TIM6, 32768, 0):表明此时的分频系数为0,根据430规格书,当分频系数为0时自动+1,根据时钟树当Prescaler=1时,分频系数为1,因此所使用的TIM6的时钟频率为32MHz。
    在这里插入图片描述

typedef struct
{
    uint32_t SysclkFreq;    /* returns SYSCLK clock frequency expressed in Hz */
    uint32_t HclkFreq;      /* returns HCLK clock frequency expressed in Hz */
    uint32_t Pclk1Freq;     /* returns PCLK1 clock frequency expressed in Hz */
    uint32_t Pclk2Freq;     /* returns PCLK2 clock frequency expressed in Hz */
    uint32_t AdcPllClkFreq; /* returns ADCPLLCLK clock frequency expressed in Hz */
    uint32_t AdcHclkFreq;   /* returns ADCHCLK clock frequency expressed in Hz */
} RCC_ClocksType;

void Tim_Config(void)
{

    /* System Clocks Configuration */
    BSTIMClockFrequency = Common_BSTIM_RCC_Initialize(TIM6, RCC_HCLK_DIV4);

    /* NVIC Configuration */
    Common_TIM_NVIC_Initialize(TIM6_IRQn, ENABLE);

    /* Time base configuration, period = 65535, prescaler = prescaler */
    Common_TIM_Base_Initialize(TIM6, 32768, 0);

    TIM_Base_Reload_Mode_Set(TIM6, TIM_PSC_RELOAD_MODE_IMMEDIATE);

    TIM_Interrupt_Enable(TIM6, TIM_INT_UPDATE);

    // TIM_On(TIM6);
}

uint32_t SysTick_InitConfig(uint32_t ms)
{ 
		RCC_Clocks_Frequencies_Value_Get(&RCC_Clocks);
}

当TIM6定时器的频率为32MHz时,它所使能的中断计算过程如下:
T = 1/32MHz = 31.25ns
32.25ns × 32768 = 1.024ms
计数5次算溢出:
1.024 × 5 = 5.12ms
当超过5ms没有新数据接收的时候默认数据传输完毕。

void TIM6_IRQHandler(void)
{
    if (TIM_Interrupt_Status_Get(TIM6, TIM_INT_UPDATE) != RESET)
    {
        TIM_Interrupt_Status_Clear(TIM6, TIM_INT_UPDATE);
        if(RxCntCur!=0)
		{
            if(RxCntBk!=RxCntCur)//表示有接收到数据 上次接收到的字节数不等于当前接收到的字节数
            {
                RxCntBk=RxCntCur;
                RecTimeOutCnt=0;
            }
            else //当前无新数据接收 RxCntBk==RxCntCur
            {
                RecTimeOutCnt++; //接收超时计数
                if(RecTimeOutCnt>=5)//接收完成一帧数据
                {
                    /
                    RxCntCur=0;
                    RxCntBk=0;
                    RecTimeOutCnt=0;
                    g_RxOverFlag=1;
                    TIM_Off(TIM6);
                }
            }
        }
        else
		{
            RxCntBk=0;
			RecTimeOutCnt=0;
		}					
    }
}
  1. 对同一按键信号,用中断处理,或者在while循环中实时读取电平状态,慎重考虑两种方式是否可以同时存在。
//可行代码
void EXTI9_5_IRQHandler(void)
{
    if (RESET != EXTI_Interrupt_Status_Get(KEY_INPUT_EXTI_LINE_U))
    {
		g_key_on=1;
        u_update_key_flag = 1;
			
        EXTI_Interrupt_Status_Clear(KEY_INPUT_EXTI_LINE_C | KEY_INPUT_EXTI_LINE_U);
    }

    if (RESET != EXTI_Interrupt_Status_Get(KEY_INPUT_EXTI_LINE_C))
    {
		g_key_on=1;
        c_update_key_flag = 1;
			
        EXTI_Interrupt_Status_Clear(KEY_INPUT_EXTI_LINE_C | KEY_INPUT_EXTI_LINE_U);
    }
}

        if(u_update_key_flag == 1)
        {
            u_update_key_flag = 0;
            UART_Request_Update_Flow(); // 开始UART升级流程
        }

        /*CAN升级*/
        if(c_update_key_flag == 1)
        {
            c_update_key_flag = 0;
            CAN_Request_Update_Flow(); // 开始CAN升级流程 
        }
//不可行代码
void EXTI9_5_IRQHandler(void)
{
    if (RESET != EXTI_Interrupt_Status_Get(KEY_INPUT_EXTI_LINE))
    {
			
		g_key_on=1;
			
        EXTI_Interrupt_Status_Clear(KEY_INPUT_EXTI_LINE);
    }
}
    
if(GPIO_Input_Pin_Data_Get(KEY_INPUT_UART_PORT, KEY_INPUT_UART_PIN) == PIN_SET)
    {
      UART_Request_Update_Flow(); // 开始UART升级流程
    }

    /*CAN升级*/
    if(GPIO_Input_Pin_Data_Get(KEY_INPUT_CAN_PORT, KEY_INPUT_CAN_PIN) == PIN_SET)
    {
      CAN_Request_Update_Flow(); // 开始CAN升级流程 
    }
  1. 串口数据发送不了,有可能是没有配置GPIO的时钟

附加代码段:

main.c
/*****************************************************************************
 * Copyright (c) 2019, Nations Technologies Inc.
 *
 * All rights reserved.
 * ****************************************************************************
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the disclaimer below.
 *
 * Nations' name may not be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY NATIONS "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * DISCLAIMED. IN NO EVENT SHALL NATIONS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * ****************************************************************************/

/**
 *\*\file main.c
 *\*\author Nations
 *\*\version v1.0.0
 *\*\copyright Copyright (c) 2019, Nations Technologies Inc. All rights reserved.
 **/

#include "main.h"
#include <math.h>
#include "uart.h"
#include "can.h"
#include "time.h"
#include "led.h"
#include "key.h"
#include "u_app_data.h"
#include "c_app_data.h"
#include "n32g430.h"
#include "BK_Command.h"
#include "n32g430_it.h"

// typedef  void (*iapfun)(void);				//定义一个函数类型的参数.
// iapfun jump2app;
uint8_t  Uart1_RxBuf[256]={0x00};
uint16_t RxIndex=0;
volatile uint8_t  g_RxOverFlag=0;//串口接收一帧完成标志
uint16_t RxCntCur=0;//当前接收的字节数
uint16_t RxCntBk=0; //上次接收的字节数
uint8_t  RecTimeOutCnt=0;//接收超时计数


USART_InitType USART_InitStructure;

RCC_ClocksType RCC_Clocks;
DMA_InitType DMA_InitStructureTx;
volatile uint32_t *p;
volatile uint16_t *p1;
uint16_t PrescalerValue = 0;
uint8_t  g_RetFailFlagToPC=0;



// /***********************************
// *名称:
// *功能:
// *参数: 
// *日期:
// ************************************/
// void boot_write(void)
// {
//     /* System Clocks Configuration */
//     RCC_Configuration();
//     NVIC_Configuration();
//     GPIO_Configuration();
//     // DMA_Configuration();
//     Uart_Config();//
//     Tim_Config();
//     __enable_irq();
//     //

//     IWDG_Config(IWDG_CONFIG_PRESCALER_DIV128, 61*8);//约17S  
//     while(1)
//     {
//         #ifdef _DEBUG
//         IWDG_ReloadKey();
//         #endif

//         Uart_RcvDataProg();
//     }
// }

/**
 * @brief  Configures the different system clocks.
 */
void RCC_Configuration(void)
{
	   /* DMA clock enable */
//    RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA, ENABLE);
    /* Enable GPIO clock */
    RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOA | RCC_AHB_PERIPH_GPIOB);
    /* Enable USART1 and UART3 Clock */
    RCC_APB2_Peripheral_Clock_Enable(RCC_APB2_PERIPH_USART1 | RCC_APB2_PERIPH_UART3);
}


/**
 * @brief  Configures the nested vectored interrupt controller.
 */
void NVIC_Configuration(void)
{
    NVIC_InitType NVIC_InitStructure;

    /* Enable the USARTy_Tx DMA Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel                      = USART1_IRQn;//uart1 irq
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority    = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd                   = ENABLE;
    NVIC_Initializes(&NVIC_InitStructure);
	
    /* Enable the TIM1 global Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel                        = TIM6_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority      = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd                     = ENABLE;
    NVIC_Initializes(&NVIC_InitStructure);
}


/**
 * @brief  Configures the different GPIO ports.
 */
void GPIO_Configuration(void)
{
    GPIO_InitType GPIO_InitStructure;
    /* Initialize GPIO_InitStructure */
    GPIO_Structure_Initialize(&GPIO_InitStructure);   
    /* Configure USARTy Tx as alternate function push-pull */
    GPIO_InitStructure.Pin            = USARTy_TxPin;    
    GPIO_InitStructure.GPIO_Mode      = GPIO_MODE_AF_PP;
    GPIO_InitStructure.GPIO_Alternate = USARTy_Tx_GPIO_AF;
    GPIO_Peripheral_Initialize(USARTy_GPIO, &GPIO_InitStructure);

    /* Configure USARTx Rx as alternate function push-pull */
    GPIO_InitStructure.Pin            = USARTy_RxPin;
    GPIO_InitStructure.GPIO_Alternate = USARTy_Rx_GPIO_AF;
    GPIO_Peripheral_Initialize(USARTy_GPIO, &GPIO_InitStructure);
   //
   //	
	// GPIO_InitStructure.Pin        = GPIO_PIN_6;
    // GPIO_InitStructure.GPIO_Mode  = GPIO_MODE_OUTPUT_PP;
    // GPIO_InitStructure.GPIO_Current = GPIO_DC_LOW;
    // GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
	//用于测试
}


/***********************************
*名称:
*功能:
*参数: 
*日期:
************************************/
void Uart_Config(void)
{
	/* USARTy and USARTz configuration ------------------------------------------------------*/
    USART_InitStructure.BaudRate            = 9600; //1s能发送19200个比特位
    USART_InitStructure.WordLength          = USART_WL_8B;
    USART_InitStructure.StopBits            = USART_STPB_1;
    USART_InitStructure.Parity              = USART_PE_NO;
    USART_InitStructure.HardwareFlowControl = USART_HFCTRL_NONE;
    USART_InitStructure.Mode                = USART_MODE_RX | USART_MODE_TX;
	
	    /* Configure USART1 */
    USART_Initializes(USART1, &USART_InitStructure);
	 // USART_EnableDMA(USARTy,USART_DMAREQ_TX, ENABLE);
	 // DMA_EnableChannel(USARTy_Tx_DMA_Channel,DISABLE);
    //
    USART_Interrupt_Status_Clear(USART1, USART_FLAG_TXC|USART_FLAG_RXDNE);
    USART_Flag_Clear(USART1, USART_INT_TXC|USART_INT_RXDNE);
    /* Enable USARTy Receive interrupt */
    USART_Interrput_Enable(USART1, USART_INT_RXDNE);//允许接收中断  
	USART_Enable(USART1);
}


/**
*\*\name    Common_BSTIM_RCC_Initialize.
*\*\param   TIMx :
*\*\          - TIM6
*\*\param   hclk_division
*\*\          - RCC_HCLK_DIV1
*\*\          - RCC_HCLK_DIV2
*\*\          - RCC_HCLK_DIV4
*\*\          - RCC_HCLK_DIV8
*\*\          - RCC_HCLK_DIV16
*\*\return  uint32_t
**/
uint32_t Common_BSTIM_RCC_Initialize(TIM_Module *TIMx, uint32_t hclk_division)
{
    uint32_t BSTIM_clock;

    RCC_ClocksType RCC_Clocks;

    RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOA | RCC_AHB_PERIPH_GPIOB| RCC_AHB_PERIPH_GPIOC 
                                        | RCC_AHB_PERIPH_GPIOD);
    
    RCC_APB2_Peripheral_Clock_Enable(RCC_APB2_PERIPH_AFIO);
    
    RCC_Pclk1_Config(hclk_division);

    RCC_APB1_Peripheral_Clock_Enable(RCC_APB1_PERIPH_TIM6);

    RCC_Clocks_Frequencies_Value_Get(&RCC_Clocks);

    if(RCC_Clocks.HclkFreq > RCC_Clocks.Pclk1Freq) 
    {
        BSTIM_clock = RCC_Clocks.Pclk1Freq * 2; 
    }
    else
    {
        BSTIM_clock = RCC_Clocks.Pclk1Freq;
    }
    return BSTIM_clock;
}

/**
*\*\name    Common_TIM_NVIC_Initialize.
*\*\param   IRQ_number :
*\*\          - TIM1_BRK_IRQn
*\*\          - TIM1_UP_IRQn
*\*\          - TIM1_TRG_COM_IRQn
*\*\          - TIM1_CC_IRQn
*\*\          - TIM2_IRQn
*\*\          - TIM3_IRQn
*\*\          - TIM4_IRQn
*\*\          - TIM8_BRK_IRQn
*\*\          - TIM8_UP_IRQn
*\*\          - TIM8_TRG_COM_IRQn
*\*\          - TIM8_CC_IRQn
*\*\          - TIM5_IRQn
*\*\          - TIM6_IRQ
*\*\param   command
*\*\          - ENABLE
*\*\          - DISABLE
*\*\return  none
**/
void Common_TIM_NVIC_Initialize(IRQn_Type IRQ_number, FunctionalState command)
{
    NVIC_InitType NVIC_InitStructure;

    NVIC_InitStructure.NVIC_IRQChannel = IRQ_number;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    
    if(ENABLE == command)
    {
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    }
    else
    {
        NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;
    }
    
    NVIC_Initializes(&NVIC_InitStructure);
}

static TIM_TimeBaseInitType TIM_TimeBaseStructure;

/**
*\*\name    Common_TIM_Base_Initialize.
*\*\param   TIMx :
*\*\          - TIM1
*\*\          - TIM2
*\*\          - TIM3
*\*\          - TIM4
*\*\          - TIM5
*\*\          - TIM6
*\*\param   period
*\*\          - [1, 0xffff]
*\*\param   prescaler
*\*\          - [0, 0xffff]
*\*\return  none
**/
void Common_TIM_Base_Initialize(TIM_Module *TIMx, uint16_t period, uint16_t prescaler)
{
    TIM_Base_Struct_Initialize(&TIM_TimeBaseStructure);
    TIM_TimeBaseStructure.Period    = period;
    TIM_TimeBaseStructure.Prescaler = prescaler;
    TIM_TimeBaseStructure.ClkDiv    = 0;
    TIM_TimeBaseStructure.CntMode   = TIM_CNT_MODE_UP;

    TIM_Base_Initialize(TIMx, &TIM_TimeBaseStructure);   
}


uint32_t BSTIMClockFrequency = 0;
void Tim_Config(void)
{
    /* System Clocks Configuration */
    BSTIMClockFrequency = Common_BSTIM_RCC_Initialize(TIM6, RCC_HCLK_DIV4);

    /* NVIC Configuration */
    Common_TIM_NVIC_Initialize(TIM6_IRQn, ENABLE);

    /* Time base configuration, period = 65535, prescaler = prescaler */
    Common_TIM_Base_Initialize(TIM6, 32768, 0);

    TIM_Base_Reload_Mode_Set(TIM6, TIM_PSC_RELOAD_MODE_IMMEDIATE);

    TIM_Interrupt_Enable(TIM6, TIM_INT_UPDATE);

    // TIM_On(TIM6);
}


void IWDG_ReloadKey(void)
{
    IWDG->KEY = KEY_RELOAD_COUNTER;
}


void IWDG_Config(uint8_t IWDG_prescaler, uint16_t reload_value)
{
    //DBG_ConfigPeriph(DBG_IWDG_STOP, ENABLE);//在调试模式下禁用IWDG
	IWDG_Write_Protection_Disable();//开启对IWDG_PR和IWDG_RLR寄存器的写访问
	IWDG_Prescaler_Division_Set(IWDG_prescaler);//30KHZ 分频系数

    /* Sets IWDG reload value */
	/* Set counter reload value to obtain x second IWDG TimeOut.
    Counter Reload Value Time = x(second)/IWDG counter clock period
                            = x(second) / (LSI/IWDG_prescaler)
    */
	IWDG_Counter_Reload(reload_value);//

    /* Reload counter with IWDG_PREDIV value in IWDG_RELV register to prevent reset */
	 /* Reload IWDG counter */
    IWDG_Key_Reload();

    /* Enable IWDG (the LSI oscillator will be enabled by hardware) */
	IWDG_Enable();
}


/***********************************
*名称:
*功能:
*参数: 
*日期:
************************************/
void Delay_us(uint32_t us)
{
	uint32_t i,j;
	for(i=0;i<us;i++)
	{
        #ifdef _DEBUG
		IWDG_ReloadKey();
        #endif

		for(j=0;j<1000;j++)
		{
			;
		}
	}
}


// SENDING_RESULT g_sengding_result = SENDING_FAIL;
volatile CAN_RECEIVE_RESULT g_rx_flag = UNRECEIVED; // UNRECEIVE
volatile uint8_t g_key_on = 0;
/**
 *\*\name   main
 *\*\fun    Main program.
 *\*\param  none
 *\*\return none
 **/
int main(void)
{

    // config 1ms Systick
    SysTick_InitConfig(1);

    // LedInit(LED_RED_PORT, LED_RED_PIN);
    // LedInit(LED_BLUE_PORT, LED_BLUE_PIN);
    // LedInit(LED_GREEN_PORT, LED_GREEN_PIN);
    // LedInit();

    RCC_Configuration();

    KeyInputExtiInit(KEY_INPUT_UART_PORT, KEY_INPUT_UART_PIN);
    KeyInputExtiInit(KEY_INPUT_CAN_PORT, KEY_INPUT_CAN_PIN);

    /* UART and CAN configure */
    UartInit();
    CAN_CONFIG();
    NVIC_Configuration();
    GPIO_Configuration();

    // APP下载UARTS1
    Uart_Config();//
    Tim_Config();
    __enable_irq();
    //

#ifdef _DEBUG
    IWDG_Config(IWDG_CONFIG_PRESCALER_DIV128, 61*8);//约17S  
#endif

    while (1)
    {
        // RCC_Clocks_Frequencies_Value_Get(&RCC_Clocks);
        // boot_write();
        #ifdef _DEBUG
        IWDG_ReloadKey();
        #endif

        Uart_RcvDataProg();

        if (g_key_on==0) 
        {
            continue;//等待按下按键
        }

//		Get_FlashAPPCodeCrc();

        /*UART升级*/
        if(u_update_key_flag == 1)
        {
            // TIM_Compare2_Set(TIM3,2500);					//蓝 闪
            // TIM_Compare2_Set(TIM2,0);						//红 灭
            // // LedOff(LED_GREEN_PORT, LED_GREEN_PIN);          //绿 灭
            u_update_key_flag = 0;
            UART_Request_Update_Flow(); // 开始UART升级流程
        }

        /*CAN升级*/
        if(c_update_key_flag == 1)
        {
            // TIM_Compare2_Set(TIM3,2500);					//蓝 闪
            // TIM_Compare2_Set(TIM2,0);					    //红 灭
            // // LedOff(LED_GREEN_PORT, LED_GREEN_PIN);          //绿 灭
            c_update_key_flag = 0;
            CAN_Request_Update_Flow(); // 开始CAN升级流程 
        }
        

        g_key_on=0; //正常跑完流程,按键状态清零
        // TIM_Compare2_Set(TIM3,0);							//蓝 灭
    }
}

n32g430_it.c
/*****************************************************************************
 * Copyright (c) 2019, Nations Technologies Inc.
 *
 * All rights reserved.
 * ****************************************************************************
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the disclaimer below.
 *
 * Nations' name may not be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY NATIONS "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * DISCLAIMED. IN NO EVENT SHALL NATIONS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * ****************************************************************************/

/**
*\*\file n32g430_it.c
*\*\author Nations
*\*\version v1.0.0
*\*\copyright Copyright (c) 2019, Nations Technologies Inc. All rights reserved.
**/


#include "n32g430_it.h"
#include "main.h"



// uint8_t RxCounter = 0;
// extern uint8_t RxBuffer2[];
// extern uint8_t NbrOfDataToRead;



/** Cortex-M4 Processor Exceptions Handlers **/

/**
*\*\name    NMI_Handler.
*\*\fun     This function handles NMI exception.
*\*\param   none
*\*\return  none 
**/
void NMI_Handler(void)
{
}

/**
*\*\name    HardFault_Handler.
*\*\fun     This function handles Hard Fault exception.
*\*\param   none
*\*\return  none 
**/
void HardFault_Handler(void)
{
    /* Go to infinite loop when Hard Fault exception occurs */
    while (1)
    {
    }
}

/**
*\*\name    MemManage_Handler.
*\*\fun     This function handles Memory Manage exception.
*\*\param   none
*\*\return  none 
**/
void MemManage_Handler(void)
{
    /* Go to infinite loop when Memory Manage exception occurs */
    while (1)
    {
    }
}

/**
*\*\name    BusFault_Handler.
*\*\fun     This function handles Bus Fault exception.
*\*\param   none
*\*\return  none 
**/
void BusFault_Handler(void)
{
    /* Go to infinite loop when Bus Fault exception occurs */
    while (1)
    {
    }
}

/**
*\*\name    UsageFault_Handler.
*\*\fun     This function handles Usage Fault exception.
*\*\param   none
*\*\return  none 
**/
void UsageFault_Handler(void)
{
    /* Go to infinite loop when Usage Fault exception occurs */
    while (1)
    {
    }
}

/**
*\*\name    SVC_Handler.
*\*\fun     This function handles SVCall exception.
*\*\param   none
*\*\return  none 
**/
void SVC_Handler(void)
{
}



/**
*\*\name    PendSV_Handler.
*\*\fun     This function handles PendSV_Handler exception.
*\*\param   none
*\*\return  none 
**/
void PendSV_Handler(void)
{
}


/**
*\*\name    DebugMon_Handler.
*\*\fun     This function handles Debug Monitor exception.
*\*\param   none
*\*\return  none 
**/
void DebugMon_Handler(void)
{
}

/**
*\*\name    SysTick_Handler.
*\*\fun     This function handles SysTick Handler.
*\*\param   none
*\*\return  none 
**/
void SysTick_Handler(void)
{
}


/* N32G430 Peripherals Interrupt Handlers, interrupt handler's name please refer to the startup file (startup_n32g430.s). */

/**
 *\*\name   CAN_RX0_IRQHandler
 *\*\fun    CAN FIFO0 receive interrupt.
 *\*\param  none
 *\*\return none
 **/
void CAN_RX0_IRQHandler(void)
{

    CAN_Message_Receive(CAN, CAN_FIFO0, &CAN_RxMessage); // 从FIFO读取8个字节数据

    // if(Get_Sending_Result(CAN_RxMessage.Data)==SENGDING_OK)
    // {
    //     g_sengding_result= SENGDING_OK; //发送写入成功
    // }else
    // {
    //     g_sengding_result= SENDING_FAIL;//发送写入失败
    // }

    g_rx_flag = RECEIVED; //表示已经接收到数据
}




/** N32G430 Peripherals Interrupt Handlers, interrupt handler's name please refer to the startup file (startup_n32g430.s) **/

/**
*\*\name    EXTI9_5_IRQHandler.
*\*\fun     External lines 5 to 9 interrupt.
*\*\param   none
*\*\return  none 
**/
uint8_t u_update_key_flag = 0, c_update_key_flag = 0;
void EXTI9_5_IRQHandler(void)
{
    if (RESET != EXTI_Interrupt_Status_Get(KEY_INPUT_EXTI_LINE_U))
    {
		g_key_on=1;
        u_update_key_flag = 1;
			
        EXTI_Interrupt_Status_Clear(KEY_INPUT_EXTI_LINE_C | KEY_INPUT_EXTI_LINE_U);
    }

    if (RESET != EXTI_Interrupt_Status_Get(KEY_INPUT_EXTI_LINE_C))
    {
		g_key_on=1;
        c_update_key_flag = 1;
			
        EXTI_Interrupt_Status_Clear(KEY_INPUT_EXTI_LINE_C | KEY_INPUT_EXTI_LINE_U);
    }
}


/******************************************************************************/
/*  N32G430 Peripherals Interrupt Handlers                     */
/*  Add here the Interrupt Handler for the used peripheral(s) (PPP), for the  */
/*  available peripheral interrupt handler's name please refer to the startup */
/*  file (startup_n32g430.s).                                                 */
/******************************************************************************/

/**
 * @brief  This function handles USARTy_Tx or USARTz_Rx DMA global interrupt request.
 */
extern uint8_t  g_RetFailFlagToPC;

void USARTy_IRQHandler(void)
{
    volatile uint8_t tmp=0;
    if (USART_Flag_Status_Get(USART1, USART_INT_RXDNE) != RESET)
    {
        /* Read one byte from the receive data register */   
		USART_Interrupt_Status_Clear(USART1, USART_INT_RXDNE);

        //如果当前还没有接收到数据,则第一个数据必须是0xF1
		if(0==RxCntCur)
		{
			tmp = USART_Data_Receive(USART1);
			if(0xF1==tmp) //接收到的是帧头标志,同步到帧头
			{
				RxIndex=0;
				Uart1_RxBuf[RxIndex]=tmp;
				RxIndex++;
				RxCntCur++;
				RecTimeOutCnt=0; //超时计数清零
                TIM_On(TIM6);
			}
			else //返回失败信息,此时有效接收字节RxCntCur仍然是0x00
			{
				g_RetFailFlagToPC=1;
			}
		}

        //成功接收到帧头之后,RxCntCur才会递增
		else
		{
			Uart1_RxBuf[RxIndex]=USART_Data_Receive(USART1);
			RxIndex++;
			RxCntCur++;
			RecTimeOutCnt=0; //超时计数清零
			if(RxCntCur>=200) //数组溢出,表明数据有错
			{
				RxCntCur=0;
				RxCntBk=0;
				g_RetFailFlagToPC=1;
				g_RxOverFlag=0;
			}
		} 
    }

    if (USART_Flag_Status_Get(USART1, USART_INT_ERRF) != RESET) {
		USART_Interrupt_Status_Clear(USART1, USART_INT_ERRF);
    }
    if (USART_Flag_Status_Get(USART1, USART_INT_OREF) != RESET) {
		USART_Interrupt_Status_Clear(USART1, USART_INT_OREF);
    }
}

// void TIM1_BRK_IRQHandler(void)
// {
//     TIM1_BRK_UP_TRG_COM_IRQHandler();
// }

// void TIM1_UP_IRQHandler(void)
// {
//     TIM1_BRK_UP_TRG_COM_IRQHandler();
// }

// void TIM1_TRG_COM_IRQHandler(void)
// {
//     TIM1_BRK_UP_TRG_COM_IRQHandler();
// }

void TIM6_IRQHandler(void)
{
    if (TIM_Interrupt_Status_Get(TIM6, TIM_INT_UPDATE) != RESET)
    {
        TIM_Interrupt_Status_Clear(TIM6, TIM_INT_UPDATE);
        if(RxCntCur!=0)
		{
            if(RxCntBk!=RxCntCur)//表示有接收到数据 上次接收到的字节数不等于当前接收到的字节数
            {
                RxCntBk=RxCntCur;
                RecTimeOutCnt=0;
            }
            else //当前无新数据接收 RxCntBk==RxCntCur
            {
                RecTimeOutCnt++; //接收超时计数
                if(RecTimeOutCnt>=5)//接收完成一帧数据
                {
                    /
                    RxCntCur=0;
                    RxCntBk=0;
                    RecTimeOutCnt=0;
                    g_RxOverFlag=1;
                    TIM_Off(TIM6);
                }
            }
        }
        else
		{
            RxCntBk=0;
			RecTimeOutCnt=0;
		}					
    }
}

// void TIM1_BRK_UP_TRG_COM_IRQHandler(void)
// {
//     if (TIM_Interrupt_Status_Get(TIM1, TIM_INT_UPDATE) != RESET)
//     {
//         TIM_Interrupt_Status_Clear(TIM1, TIM_INT_UPDATE);
//         if(RxCntCur!=0)
// 		{
//             if(RxCntBk!=RxCntCur)//表示有接收到数据 上次接收到的字节数不等于当前接收到的字节数
//             {
//                 RxCntBk=RxCntCur;
//                 RecTimeOutCnt=0;
//             }
//             else //当前无新数据接收 RxCntBk==RxCntCur
//             {
//                 RecTimeOutCnt++; //接收超时计数
//                 if(RecTimeOutCnt>=10)//接收完成一帧数据
//                 {
//                     /
//                     RxCntCur=0;
//                     RxCntBk=0;
//                     RecTimeOutCnt=0;
//                     g_RxOverFlag=1;
//                 }
//             }
//         }
//         else
// 		{
//             RxCntBk=0;
// 			RecTimeOutCnt=0;
// 		}					
// 		
//         // GPIO_WriteBit(GPIOA, GPIO_PIN_6, (Bit_OperateType)(1 - GPIO_ReadOutputDataBit(GPIOA, GPIO_PIN_6)));	
//     }
// }
uart.c
/*****************************************************************************
 * Copyright (c) 2019, Nations Technologies Inc.
 *
 * All rights reserved.
 * ****************************************************************************
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the disclaimer below.
 *
 * Nations' name may not be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY NATIONS "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * DISCLAIMED. IN NO EVENT SHALL NATIONS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * ****************************************************************************/

/**
 *\*\file can_config.c
 *\*\author Nations
 *\*\version v1.0.0
 *\*\copyright Copyright (c) 2019, Nations Technologies Inc. All rights reserved.
 **/

#include "uart.h"
#include "main.h"
#include "common.h"
#include <string.h>
// #include <math.h>
// #include <stdlib.h>
// #include <string.h>



USART_InitType UART3_InitStructure;

// uint8_t  UartReadBuf[COMNUM][UARTRESIZE]; 
uint8_t *pUartSendBuf[COMNUM]; 
uint16_t SendLen[COMNUM],SendCount[COMNUM];
uint16_t ReceiveLen[COMNUM];
uint8_t TxMark[COMNUM],RxMark[COMNUM];
uint8_t RxEndDelay[COMNUM];

//uint8_t g_device_id = 0x01; // 升级的设备ID
//uint8_t receive_data[28] = {0};


/**
*\*\name    UartInit.
*\*\fun     Configures the Uart.
*\*\param   none
*\*\return  none
**/
void UartInit(void)						//主函数初始化调用一次
{
	GPIO_InitType GPIO_InitStructure; 
    GPIO_Structure_Initialize(&GPIO_InitStructure);
	
	/* Configure USART Tx as alternate function push-pull */
	GPIO_InitStructure.Pin			  = UART1_TX_Pin;//PB10
	GPIO_InitStructure.GPIO_Mode      = GPIO_MODE_AF_PP;
	GPIO_InitStructure.GPIO_Alternate = UART1_TX_AF;
	GPIO_Peripheral_Initialize(UART1_TX_Port, &GPIO_InitStructure); 
	
	/* Configure USART Rx as alternate function push-pull */
	GPIO_InitStructure.Pin			  = UART1_RX_Pin;//PB11
	GPIO_InitStructure.GPIO_Alternate = UART1_RX_AF;
	GPIO_Peripheral_Initialize(UART1_RX_Port, &GPIO_InitStructure);
	
	RCC_APB2_Peripheral_Clock_Enable(RCC_APB2_PERIPH_UART3);
//	UartOpen(USART1, 115200);
	
	UartOpen(USARTy , 9600);
}



void UartOpen(USART_Module* USARTn, u32 BaudRate)			//uart初始化,使能打开
{
	USART_InitType USART_InitStructure;

	/* USART configuration ------------------------------------------------------*/
	USART_InitStructure.BaudRate			= BaudRate;
	USART_InitStructure.WordLength			= USART_WL_8B;
	USART_InitStructure.StopBits			= USART_STPB_1;
	USART_InitStructure.Parity				= USART_PE_NO;
	USART_InitStructure.HardwareFlowControl = USART_HFCTRL_NONE;
	USART_InitStructure.Mode				= USART_MODE_RX | USART_MODE_TX;

	/* Configure USART */
	USART_Initializes(USARTn, &USART_InitStructure);

// 	/* Enable USART Receive and Transmit interrupts */
//     USART_Interrput_Enable(USARTn, USART_INT_RXDNE);
// //	USART_ConfigInt(USARTn, USART_INT_TXC, ENABLE);

    USART_Interrupt_Status_Clear(USARTn, USART_FLAG_TXC|USART_FLAG_RXDNE);
    USART_Flag_Clear(USARTn, USART_INT_TXC|USART_INT_RXDNE);
	/* Enable the USART */
	USART_Enable(USARTn);
}

//----------------------------------------------------------




/**
 * @brief 发送 开始升级 命令
 *
 * @param uart3_id
 * @param data 2个字节数据
 */
void U_Send_Start_Update_Message(uint8_t uart3_id, uint8_t device_id)
{
    uint8_t func_code = U_UPDATE_TYPE_FUN_CODE_WRITE;               // 功能码:写入 0x90 ,读取0x91
    uint8_t fun_ext_code = U_UPDATE_TYPE_FUN_EXT_CODE_START_UPDATE; // 功能扩展码: 0x00
    uint8_t headerR  = UPDATE_TYPE_HEAdER_REQUEST;                // 帧头请求:0xF1
    uint8_t endR  = UPDATE_TYPE_END_REQUEST;                // 帧尾请求:0xF2

    uint8_t data[2] = {0x90, 0x09};

    U_Send_Frame_Data(headerR, uart3_id, device_id, func_code, fun_ext_code, 2, data, endR);
}

/**
 * @brief 发送 快速升级(预留) 命令:改变波特率
 *
 * @param uart3_id
 * @param data 2个字节数据
 */
void U_Send_Fast_Update_Message(uint8_t uart3_id, uint8_t device_id)
{
    uint8_t func_code = U_UPDATE_TYPE_FUN_CODE_WRITE;              // 功能码:写入 0x90 ,读取0x91
    uint8_t fun_ext_code = U_UPDATE_TYPE_FUN_EXT_CODE_FAST_UPDATE; // 功能扩展码: 0x02
    uint8_t headerR  = UPDATE_TYPE_HEAdER_REQUEST;                // 帧头请求:0xF1
    uint8_t endR  = UPDATE_TYPE_END_REQUEST;                // 帧尾请求:0xF2

    uint8_t data[2] = {0x92, 0x29};

    U_Send_Frame_Data(headerR, uart3_id, device_id, func_code, fun_ext_code, 2, data, endR);
}



/**
 * @brief 发送 准备升级 命令,擦除APP Flash区域,同时将APP信息存FLASH Boot信息区域
 *
 * @param uart3_id
 * @param device_id 设备ID
 * @param crc16 app数据的crc16
 * @param app_data_pack_total_num app数据的总包数
 * @param project_id    项目ID
 */
void U_Send_Ready_Update_Message(uint8_t uart3_id, uint8_t device_id, uint16_t app_data_crc16, uint16_t app_data_pack_total_num, uint32_t project_id)
{
    uint8_t func_code = U_UPDATE_TYPE_FUN_CODE_WRITE;               // 功能码:写入 0x90 ,读取0x91
    uint8_t fun_ext_code = U_UPDATE_TYPE_FUN_EXT_CODE_READY_UPDATE; // 功能扩展码: 0x04
    uint8_t headerR  = UPDATE_TYPE_HEAdER_REQUEST;                // 帧头请求:0xF1
    uint8_t endR  = UPDATE_TYPE_END_REQUEST;                // 帧尾请求:0xF2

    uint8_t data[8] = {0};

    data[0] = app_data_crc16 & 0xFF;                 // crc16 低8位
    data[1] = app_data_crc16 >> 8;                   // crc16高8位
    data[2] = app_data_pack_total_num & 0xFF;        // app_data_pack_total_num 低8位
    data[3] = (app_data_pack_total_num >> 8) & 0xFF; // app_data_pack_total_num 高8位
    data[4] = project_id & 0xFF;                     // project_id bit0-bit7
    data[5] = (project_id >> 8) & 0xFF;              // project_id bit8-bit15
    data[6] = (project_id >> 16) & 0xFF;             // project_id bit16-bit7
    data[7] = (project_id >> 24) & 0xFF;             // project_id bit24-bit32

    U_Send_Frame_Data(headerR, uart3_id, device_id, func_code, fun_ext_code, 8, data, endR);
}



/**
 * @brief 发送 APP数据包
 *
 * @param uart3_id
 * @param device_id 设备ID
 * @param app_data_num APP数据包序号,从0开始,0表示第一包
 * @param data 128个字节APP数据
 */
void U_Send_Update_Data_Message(uint8_t uart3_id, uint8_t device_id, uint16_t app_data_num, uint8_t *data)
{
    uint8_t data_length = 131;                                   //(2字节数据分包序号+128个字节数据+当前包的固件数据的CRC8)
    uint8_t func_code = U_UPDATE_TYPE_FUN_CODE_WRITE;              // 功能码:写入 0x90 ,读取0x91
    uint8_t fun_ext_code = U_UPDATE_TYPE_FUN_EXT_CODE_UPDATE_DATA; // 功能扩展码: 0x0C
    uint8_t headerR  = UPDATE_TYPE_HEAdER_REQUEST;                // 帧头请求:0xF1
    uint8_t endR  = UPDATE_TYPE_END_REQUEST;                // 帧尾请求:0xF2

    uint8_t new_data[131] = {0};  // 声明一个固定大小的数组,用于存储新的数据

    //uint8_t *new_data = (uint8_t *)malloc(data_length);        
    new_data[0] = app_data_num & 0xFF;                         // 数据包序号 app_data_num 低8位
    new_data[1] = (app_data_num >> 8) & 0xFF;                  // 数据包序号 app_data_num 高8位
    memcpy(new_data + 2, data, 128);                           // 将传入的数据(128字节)复制到 new_data 数组的偏移为2的位置。
    new_data[data_length - 1] = crc8_check(new_data + 2, 128); // 128个字节数据的CRC 计算并将数据的CRC8校验结果存储在 new_data 数组的最后一个位置。

    U_Send_Frame_Data(headerR, uart3_id, device_id, func_code, fun_ext_code, data_length, new_data, endR);

    //free(new_data); // 释放内存
}

/**
 * @brief 升级完成,
 *
 * @param can_id
 * @param device_id 设备ID
 * @param data 2个字节数据
 */
void U_Send_Finish_Update_Message(uint8_t uart3_id, uint8_t device_id)
{
    uint8_t func_code = U_UPDATE_TYPE_FUN_CODE_WRITE;                // 功能码:写入 0x90 ,读取0x91
    uint8_t fun_ext_code = U_UPDATE_TYPE_FUN_EXT_CODE_FINISH_UPDATE; // 功能扩展码: 0x8E
    uint8_t headerR  = UPDATE_TYPE_HEAdER_REQUEST;                // 帧头请求:0xF1
    uint8_t endR  = UPDATE_TYPE_END_REQUEST;                // 帧尾请求:0xF2

    uint8_t data[2] = {0x8E, 0xE8};

    U_Send_Frame_Data(headerR, uart3_id, device_id, func_code, fun_ext_code, 2, data, endR);
}

/**
 * @brief CAN发送一帧数据,(即  帧头|识别码|功能码|功能扩展码|数据长度|数据|校验码|帧尾  格式)
 *
 * @param uart3_id UART3 ID
 * @param device_id 设备码
 * @param func_code 功能码
 * @param fun_ext_code 功能扩展码
 * @param data_length data_length 数据长度(最大为0xFF)
 * @param data 数据 (数据长度最长只能是255个,0xFF)
 */

uint8_t pBuf[256] = {0};
void U_Send_Frame_Data(uint8_t headerR, uint16_t uart3_id, uint8_t device_id, uint8_t func_code, uint8_t fun_ext_code, uint8_t data_length, uint8_t *data, uint8_t endR)
{
        // 发送一个UART包
        

        pBuf[0] = headerR;
        pBuf[1] = uart3_id;
        pBuf[2] = device_id;
        pBuf[3] = func_code;
        pBuf[4] = fun_ext_code;
        pBuf[5] = data_length;

        uint16_t i = 0;
        for(i = 0; i < data_length; i++)
        {
            pBuf[6+i] = data[i];
        }

        pBuf[data_length + 6] = crc8_check(&pBuf[1],data_length + 5);
        pBuf[data_length + 7] = endR;


        SysTick_Delay_Ms(1);
        UartSendBuffer(pBuf, data_length + 8);
    
    // 帧数据使用完成,释放内存
    //free(pBuf);
}


/*****************************************************************************
 函 数 名  : UartRxDisable
 功能描述  : 单线通讯时,RX禁止
 输入参数  :   
 返 回 值  : 
*****************************************************************************/
void UartRxDisable(void)
{
	USART_Interrput_Disable(USARTy, USART_INT_RXDNE); //USART_INT_RXDNE有数据可以读取
//	Delay10us(10);
    #ifdef SEND_INT_EN
    USART_Interrput_Enable(USARTy, USART_INT_TXC); //USART_INT_TXC所有数据都已经发送完毕
    #endif
    TE_485();
}

void UartRxEnable(void)
{
//	while (USART_GetFlagStatus(USART2, USART_FLAG_TXC) == RESET);
    USART_Interrput_Enable(USARTy, USART_INT_RXDNE);
    #ifdef SEND_INT_EN
    USART_Interrput_Disable(USARTy, USART_INT_TXC);
    #endif
    RE_485();
} 

/*****************************************************************************
 函 数 名  : UartSendBuffer
 功能描述  : Uart 发送 
 输入参数  :   
 返 回 值  : 
*****************************************************************************/ 

uint8_t UartReadBuf[9] = {0};
void UartSendBuffer(uint8_t *pBuf, uint16_t length)
{
    if(length ==0)
        return;
    pUartSendBuf[0] = pBuf;
    SendCount[0] = 1;
    SendLen[0] = length;
    //TxMark[0] = VALID_MARK;
	UartRxDisable();
	//USART_Data_Send(USARTy, *pBuf);
    USART_Flag_Clear(USARTy, USART_FLAG_RXDNE);	
    USART_Flag_Clear(USARTy, USART_FLAG_TXDE);	
    for (uint16_t i = 0; i < length; i++) 
    {
        while ( 0 == USART_Flag_Status_Get(USARTy, USART_FLAG_TXDE)); //等待发送寄存器为空,立马发送下一个字节。
        USART_Data_Send(USARTy, pBuf[i]);
        // SysTick_Delay_Ms(1);
    }

    //TxMark[0] = VALID_MARK+1; 
    
    UartRxEnable();

    for(uint8_t i = 0; i <= 8; i++ )
    {
        while ( 0 == USART_Flag_Status_Get(USARTy, USART_FLAG_RXDNE)); 等待接收寄存器不为空,立马读取数据,保证循环不会过快只读取到一个数据。
        UartReadBuf[i] = USART_Data_Receive(USARTy);
        // SysTick_Delay_Ms(1);
        if(i == 8)
        {
            RxMark[0] = VALID_MARK;
        }
    }
}


// void USARTy_IRQHandler(void)				//中断函数
// {	
// 	if (USART_Interrupt_Status_Get(USARTy, USART_INT_RXDNE) != RESET)
// 	{
//         if(ReceiveLen[0] >= UARTRESIZE)		//大于最大接收字节数,清零
//         {
//             ReceiveLen[0] = 0;
//         }    
//         UartReadBuf[0][ReceiveLen[0]]=USART_Data_Receive(USARTy); //数据存放位置
//         ReceiveLen[0]++;
//         RxEndDelay[0]= RXENDTIME;			//接收最大时间为10ms	   //接收一个字节数据之后,10ms之内无数据,认为一帧数据结束
// 	}

// 	if (USART_Interrupt_Status_Get(USARTy, USART_INT_TXC) != RESET)
// 	{
//         USART_Flag_Clear(USARTy, USART_FLAG_TXC);
//         if(SendCount[0]!=SendLen[0])
//         {
//             USART_Data_Send(USARTy, *(pUartSendBuf[0]+SendCount[0]));		//发送一个数据,计数器加1
//             SendCount[0] ++;
//         }
//         else 
//         {
//             TxMark[0] = VALID_MARK+1; 			//SendCount==SendLen相等,发送完成,改为接收状态
//             UartRxEnable();
//         }
// 	}
// 	USART_Flag_Clear(USARTy, USART_FLAG_CTSF|USART_FLAG_LINBD|USART_FLAG_TXDE|USART_FLAG_RXDNE|USART_FLAG_IDLEF|USART_FLAG_OREF|USART_FLAG_NEF|USART_FLAG_FEF|USART_FLAG_PEF);
// }



// void UartReTimer(void)				//中断调用
// {
//     if(RxEndDelay[0] !=0)
//     {
//         RxEndDelay[0]--;
//         if(RxEndDelay[0]==1)
//         {
//             RxMark[0] = VALID_MARK;		//接收完成
//         }
//     }
// }


// void UartDataDecode(void)			//主函数调用
// {
//     if(RxMark[0]==VALID_MARK)
//     {
//         RxMark[0] = UNVALID_MARK; //正在处理接收的数据
         
// //        mb_Decode(UartReadBuf[0],ReceiveLen[0]);		//boot升级
//         modbus_Decode(UartReadBuf[0],ReceiveLen[0]);	//收到的数据以及数据长度
//         ReceiveLen[0] = 0; //处理完成后,将ReceiveLen[0]置为0,表示接收的数据已经处理完毕。
//     } 
// }

can.c
在这里插入代码片/*****************************************************************************
 * Copyright (c) 2019, Nations Technologies Inc.
 *
 * All rights reserved.
 * ****************************************************************************
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the disclaimer below.
 *
 * Nations' name may not be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY NATIONS "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * DISCLAIMED. IN NO EVENT SHALL NATIONS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * ****************************************************************************/

/**
 *\*\file can_config.c
 *\*\author Nations
 *\*\version v1.0.0
 *\*\copyright Copyright (c) 2019, Nations Technologies Inc. All rights reserved.
 **/

#include "can.h"
#include "main.h"
#include <math.h>
#include <stdlib.h>
#include "common.h"
#include <string.h>


CanTxMessage CAN_TxMessage;
CanRxMessage CAN_RxMessage;

CAN_InitType CAN_InitStructure;
CAN_FilterInitType CAN_FilterInitStructure;

//uint8_t g_device_id = 0x01; // 升级的设备ID

//uint8_t receive_data[28] = {0};

/**
 *\*\name   CAN_CONFIG
 *\*\fun    CAN configure.
 *\*\param  none
 *\*\return none
 **/
void CAN_CONFIG(void)
{
    RCC_APB1_Peripheral_Clock_Enable(RCC_APB1_PERIPH_CAN);

    /* Initializes CAN*/
    CAN_NVIC_Configuration();
    CAN_GPIO_Configuration();

    CAN_Reset(CAN);
    CAN_Structure_Initializes(&CAN_InitStructure);
    /* CAN cell init */
    CAN_InitStructure.TTCM = DISABLE;
    CAN_InitStructure.ABOM = ENABLE;
    CAN_InitStructure.AWKUM = ENABLE;
    CAN_InitStructure.NART = DISABLE;
    CAN_InitStructure.RFLM = DISABLE;
    CAN_InitStructure.TXFP = ENABLE;
    CAN_InitStructure.OperatingMode = CAN_NORMAL_MODE;
    CAN_InitStructure.RSJW = CAN_RSJW_1TQ;
    CAN_InitStructure.TBS1 = CAN_TBS1_8TQ;
    CAN_InitStructure.TBS2 = CAN_TBS2_7TQ;
    CAN_InitStructure.BaudRatePrescaler = 4;

    /*Initializes the CAN */
    CAN_Initializes(CAN, &CAN_InitStructure);

    /* CAN filter init */
    CAN_FilterInitStructure.Filter_Num = 0;
    CAN_FilterInitStructure.Filter_Mode = CAN_FILTER_IDMASKMODE;
    CAN_FilterInitStructure.Filter_Scale = CAN_FILTER_32BITSCALE;
    CAN_FilterInitStructure.Filter_HighId = 0;
    CAN_FilterInitStructure.Filter_LowId = 0;
    CAN_FilterInitStructure.FilterMask_HighId = 0;
    CAN_FilterInitStructure.FilterMask_LowId = 0;
    CAN_FilterInitStructure.Filter_FIFOAssignment = CAN_FIFO0;
    CAN_FilterInitStructure.Filter_Act = ENABLE;
    CAN_Filter_Initializes(&CAN_FilterInitStructure);
    /* IT Configuration for CAN */
    CAN_Config_Interrupt_Enable(CAN, CAN_INT_FMP0);
}

/**
 *\*\name   CAN_NVIC_Configuration
 *\*\fun    CAN NVIC configure.
 *\*\param  none
 *\*\return none
 **/
void CAN_NVIC_Configuration(void)
{
    NVIC_InitType NVIC_InitStructure;

    /* Initializes the NVIC */
    NVIC_Initializes(&NVIC_InitStructure);

    /* NVIC configure */
    NVIC_InitStructure.NVIC_IRQChannel = CAN_RX0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Initializes(&NVIC_InitStructure);
}

/**
 *\*\name   CAN_GPIO_Configuration
 *\*\fun    CAN GPIO configure.
 *\*\param  none
 *\*\return none
 **/
void CAN_GPIO_Configuration(void)
{
    GPIO_InitType GPIO_InitStructure;

    /* Initializes the GPIO */
    GPIO_Structure_Initialize(&GPIO_InitStructure);

    /* configure CAN pin */
    RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOB);
    RCC_APB2_Peripheral_Clock_Enable(RCC_APB2_PERIPH_AFIO);

    GPIO_InitStructure.Pin = GPIO_PIN_8;
    GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP;
    GPIO_InitStructure.GPIO_Alternate = GPIO_AF6_CAN;
    GPIO_Peripheral_Initialize(GPIOB, &GPIO_InitStructure);

    GPIO_InitStructure.Pin = GPIO_PIN_9;
    GPIO_InitStructure.GPIO_Alternate = GPIO_AF6_CAN;
    GPIO_Peripheral_Initialize(GPIOB, &GPIO_InitStructure);
}

//----------------------------------------------------------

// static const uint8_t crc8_table[256] =
//     {
//         0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d,
//         0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65, 0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d,
//         0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb, 0xf2, 0xf5, 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd,
//         0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, 0xa8, 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd,
//         0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2, 0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea,
//         0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2, 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a,
//         0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, 0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a,
//         0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42, 0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a,
//         0x89, 0x8e, 0x87, 0x80, 0x95, 0x92, 0x9b, 0x9c, 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4,
//         0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec, 0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4,
//         0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c, 0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44,
//         0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c, 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34,
//         0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, 0x76, 0x71, 0x78, 0x7f, 0x6a, 0x6d, 0x64, 0x63,
//         0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b, 0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13,
//         0xae, 0xa9, 0xa0, 0xa7, 0xb2, 0xb5, 0xbc, 0xbb, 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83,
//         0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb, 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3};

// // 数据中包含 1 字节校验 //
// uint8_t crc8_check(uint8_t *data, uint16_t len)
// {
//     uint16_t i = 0;
//     uint8_t fcs = 0x0;

//     // 计算数据校验
//     for (i = 0; i < len; i++)
//     {
//         fcs = crc8_table[(uint8_t)fcs ^ *data];
//         data++;
//     }
//     return fcs;
// }



/**
 * @brief 发送 开始升级 命令
 *
 * @param can_id
 * @param data 2个字节数据
 */
void C_Send_Start_Update_Message(uint8_t can_id, uint8_t device_id)
{
    uint8_t func_code = C_UPDATE_TYPE_FUN_CODE_WRITE;               // 功能码:写入 0x90 ,读取0x91
    uint8_t fun_ext_code = C_UPDATE_TYPE_FUN_EXT_CODE_START_UPDATE; // 功能扩展码: 0x00

    uint8_t data[2] = {0x90, 0x09};

    C_Send_Frame_Data(can_id, device_id, func_code, fun_ext_code, 2, data);
}

/**
 * @brief 发送 快速升级(预留) 命令:改变波特率
 *
 * @param can_id
 * @param data 2个字节数据
 */
void C_Send_Fast_Update_Message(uint8_t can_id, uint8_t device_id)
{
    uint8_t func_code = C_UPDATE_TYPE_FUN_CODE_WRITE;              // 功能码:写入 0x90 ,读取0x91
    uint8_t fun_ext_code = C_UPDATE_TYPE_FUN_EXT_CODE_FAST_UPDATE; // 功能扩展码: 0x02

    uint8_t data[2] = {0x92, 0x29};

    C_Send_Frame_Data(can_id, device_id, func_code, fun_ext_code, 2, data);
}

/**
 * @brief 发送 准备升级 命令,擦除APP Flash区域,同时将APP信息存FLASH Boot信息区域
 *
 * @param can_id
 * @param device_id 设备ID
 * @param crc16 app数据的crc16
 * @param app_data_pack_total_num app数据的总包数
 * @param project_id    项目ID
 */
void C_Send_Ready_Update_Message(uint8_t can_id, uint8_t device_id, uint16_t app_data_crc16, uint16_t app_data_pack_total_num, uint32_t project_id)
{
    uint8_t func_code = C_UPDATE_TYPE_FUN_CODE_WRITE;               // 功能码:写入 0x90 ,读取0x91
    uint8_t fun_ext_code = C_UPDATE_TYPE_FUN_EXT_CODE_READY_UPDATE; // 功能扩展码: 0x04
    uint8_t data[8] = {0};

    data[0] = app_data_crc16 & 0xFF;                 // crc16 低8位
    data[1] = app_data_crc16 >> 8;                   // crc16高8位
    data[2] = app_data_pack_total_num & 0xFF;        // app_data_pack_total_num 低8位
    data[3] = (app_data_pack_total_num >> 8) & 0xFF; // app_data_pack_total_num 高8位
    data[4] = project_id & 0xFF;                     // project_id bit0-bit7
    data[5] = (project_id >> 8) & 0xFF;              // project_id bit8-bit15
    data[6] = (project_id >> 16) & 0xFF;             // project_id bit16-bit7
    data[7] = (project_id >> 24) & 0xFF;             // project_id bit24-bit32

    C_Send_Frame_Data(can_id, device_id, func_code, fun_ext_code, 8, data);
}

/**
 * @brief 发送 APP数据包
 *
 * @param can_id
 * @param device_id 设备ID
 * @param app_data_num APP数据包序号,从0开始,0表示第一包
 * @param data 128个字节APP数据
 */
void C_Send_Update_Data_Message(uint8_t can_id, uint8_t device_id, uint16_t app_data_num, uint8_t *data)
{
    uint8_t data_length = 131;                                   //(2字节数据分包序号+128个字节数据+当前包的固件数据的CRC8)
    uint8_t func_code = C_UPDATE_TYPE_FUN_CODE_WRITE;              // 功能码:写入 0x90 ,读取0x91
    uint8_t fun_ext_code = C_UPDATE_TYPE_FUN_EXT_CODE_UPDATE_DATA; // 功能扩展码: 0x1C

    uint8_t *new_data = (uint8_t *)malloc(data_length);        //
    new_data[0] = app_data_num & 0xFF;                         // 数据包序号 app_data_num 低8位
    new_data[1] = (app_data_num >> 8) & 0xFF;                  // 数据包序号 app_data_num 高8位
    memcpy(new_data + 2, data, 128);                           // 128 字节数据
    new_data[data_length - 1] = crc8_check(new_data + 2, 128); // 128个字节数据的CRC

    C_Send_Frame_Data(can_id, device_id, func_code, fun_ext_code, data_length, new_data);

    free(new_data); // 释放内存
}

/**
 * @brief 升级完成,
 *
 * @param can_id
 * @param device_id 设备ID
 * @param data 2个字节数据
 */
void C_Send_Finish_Update_Message(uint8_t can_id, uint8_t device_id)
{
    uint8_t func_code = C_UPDATE_TYPE_FUN_CODE_WRITE;                // 功能码:写入 0x90 ,读取0x91
    uint8_t fun_ext_code = C_UPDATE_TYPE_FUN_EXT_CODE_FINISH_UPDATE; // 功能扩展码: 0x8E
    uint8_t data[2] = {0x8E, 0xE8};

    C_Send_Frame_Data(can_id, device_id, func_code, fun_ext_code, 2, data);
}

/**
 * @brief CAN发送一帧数据,(即  识别码|功能码|功能扩展码|数据长度|数据|校验码  格式)
 *
 * @param can_id CAN ID
 * @param device_id 设备码
 * @param func_code 功能码
 * @param fun_ext_code 功能扩展码
 * @param data_length data_length 数据长度(最大为0xFF)
 * @param data 数据 (数据长度最长只能是255个,0xFF)
 */
void C_Send_Frame_Data(uint16_t can_id, uint8_t device_id, uint8_t func_code, uint8_t fun_ext_code, uint8_t data_length, uint8_t *data)
{
    // 一共要发送多少个CAN包
    uint16_t number_of_packs = (data_length + 3)%6 ? (data_length + 3)/6+1 : (data_length + 3)/6; // 每包数据都包括了识别ID和功能码,所以传输的有效数据从扩展码开始计算,每包传输有效数据是6个字节;data_length+3:表示n个数据+1字节功能扩展码+1字节长度+1字节校验码

    // uint16_t number_of_packs = ceil((double)(data_length + 3) / 6); // 每包数据都包括了识别ID和功能码,所以传输的有效数据从扩展码开始计算,每包传输有效数据是6个字节;data_length+3:表示n个数据+1字节功能扩展码+1字节长度+1字节校验码

    // 存储整个帧数据
    uint8_t *frame = (uint8_t *)malloc((size_t)(2 + number_of_packs * 6)); // 申请一组数据的空间大小,用于存储数据

    // 设备id只使用bit5-bit0
    device_id = device_id & 0x3F;

    // 填充整个帧数据
    frame[0] = 0;                                                    // 识别id,暂不赋予有效的值
    frame[1] = func_code;                                            // 功能码
    frame[2] = fun_ext_code;                                         // 功能扩展码
    frame[3] = data_length;                                          // 数据长度
    memcpy(frame + 4, data, data_length);                            // 数据
    frame[4 + data_length] = crc8_check(frame + 1, data_length + 3); // 校验内容为从功能码到数据域所有数据的CRC8校验

    // 一帧数据分多个CAN包发送
    for (int i = 0; i < number_of_packs; i++)
    {
        uint8_t check_id = 0; // 识别ID

        // 单包
        if (number_of_packs == 1)
        {
            check_id = PACK_TYPE_SINGLE | device_id;
        }
        else // 多包
        {
            if (i == 0) // 起始包
            {
                check_id = PACK_TYPE_START | device_id;
            }
            else if (i == number_of_packs - 1) // 结束包
            {
                check_id = PACK_TYPE_END | device_id;
            }
            else // 续传包
            {
                check_id = PACK_TYPE_CONTINUE | device_id;
            }
        }

        // 填充一个CAN包的数据
        uint8_t *can_data = frame + i * 6;
        can_data[0] = check_id;
        can_data[1] = func_code;

        // 发送一个CAN包
        Send_CAN_Pack_Message(can_id, can_data);
        SysTick_Delay_Ms(1);
    }

    // 帧数据使用完成,释放申请的动态内存
    free(frame);
}

/**
 * @brief 发送一个CAN包
 *
 * @param can_id CAN-ID
 * @param data 包含数据的8个字节的数组
 */
void Send_CAN_Pack_Message(uint16_t can_id, uint8_t data[8])
{

    /* Transmit assign */
    CAN_TxMessage.StdId = can_id;
    CAN_TxMessage.ExtId = 0x00;
    CAN_TxMessage.IDE = CAN_STANDARD_ID; /* CAN_ID_STD / CAN_ID_EXT */
    CAN_TxMessage.RTR = CAN_RTRQ_DATA;   /* CAN_RTR_DATA / CAN_RTR_REMOTE */
    CAN_TxMessage.DLC = 8;               // 发送长度为8字节

    memcpy(CAN_TxMessage.Data, data, 8);

    CAN_Transmit_Message_initializes(CAN, &CAN_TxMessage);
}

key.c
#include "key.h"
#include "main.h"

void KeyInputExtiInit(GPIO_Module* GPIOx, uint16_t Pin)
{
  GPIO_InitType GPIO_InitStructure;
  EXTI_InitType EXTI_InitStructure;
  NVIC_InitType NVIC_InitStructure;

  /* Enable the GPIO Clock */
  if (GPIOx == GPIOA)
  {
    RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOA);
    RCC_APB2_Peripheral_Clock_Enable(RCC_APB2_PERIPH_AFIO);
  }
  else if (GPIOx == GPIOB)
  {
    RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOB);
    RCC_APB2_Peripheral_Clock_Enable(RCC_APB2_PERIPH_AFIO);
  }
  else if (GPIOx == GPIOC)
  {
    RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOC);
    RCC_APB2_Peripheral_Clock_Enable(RCC_APB2_PERIPH_AFIO);
  }
  else if (GPIOx == GPIOD)
  {
    RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOD);
    RCC_APB2_Peripheral_Clock_Enable(RCC_APB2_PERIPH_AFIO);		
  }
  else
  {
    return;
  }

  if (Pin <= GPIO_PIN_ALL)
  {
    GPIO_Structure_Initialize(&GPIO_InitStructure);
    GPIO_InitStructure.Pin          = Pin;
    GPIO_InitStructure.GPIO_Pull    = GPIO_PULL_UP;
    GPIO_Peripheral_Initialize(GPIOx, &GPIO_InitStructure);
  }

  /* Configure key EXTI Line to key input Pin */
  if(Pin == GPIO_PIN_6)
  {
    GPIO_EXTI_Line_Set(KEY_INPUT_PORT_SOURCE_C, KEY_INPUT_PIN_SOURCE_C);
    EXTI_InitStructure.EXTI_Line    = KEY_INPUT_EXTI_LINE_C;
  }
  if(Pin == GPIO_PIN_5)
  {
    GPIO_EXTI_Line_Set(KEY_INPUT_PORT_SOURCE_U, KEY_INPUT_PIN_SOURCE_U);
    EXTI_InitStructure.EXTI_Line    = KEY_INPUT_EXTI_LINE_U;
  }
  

  /* Configure key EXTI line */
  
  EXTI_InitStructure.EXTI_Mode    = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; 
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Peripheral_Initializes(&EXTI_InitStructure);

  /* Set key input interrupt priority */
  NVIC_InitStructure.NVIC_IRQChannel                   = KEY_INPUT_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority        = NVIC_SUB_PRIORITY_1;
  NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
  NVIC_Initializes(&NVIC_InitStructure);
}

led.c
#include "led.h"
#include "main.h"


void LedInit(void)
{
    //RCC
    RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOA | RCC_AHB_PERIPH_GPIOB | RCC_AHB_PERIPH_GPIOC | RCC_AHB_PERIPH_GPIOD);
    RCC_APB1_Peripheral_Clock_Enable(RCC_APB1_PERIPH_TIM2);
    RCC_APB1_Peripheral_Clock_Enable(RCC_APB1_PERIPH_TIM3);

    //LED_GREEN GPIO
    GPIO_InitType GPIO_InitStructure;
    GPIO_Structure_Initialize(&GPIO_InitStructure);
    GPIO_InitStructure.Pin = LED_GREEN_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_MODE_OUT_PP;
    GPIO_Peripheral_Initialize(LED_GREEN_PORT, &GPIO_InitStructure);


    //配置PWM GPIO引脚
    Led_PWM_GPIO_Initialize(); 
   

    // 配置定时器
		//    uint32_t tim_clk=0;
		//    RCC_ClocksType RCC_Clocks;
		//    RCC_Clocks_Frequencies_Value_Get(&RCC_Clocks);
		//    if(RCC_Clocks.HclkFreq > RCC_Clocks.Pclk2Freq)
		//    {
		//        tim_clk = RCC_Clocks.Pclk2Freq *2;
		//    }
		//    else
		//    {
		//        tim_clk = RCC_Clocks.Pclk2Freq;
		//    }

    Led_PWM_TIM_Base_Initialize(TIM2, 5000, 12800); 
    Led_PWM_TIM_Base_Initialize(TIM3, 5000, 12800);


    // 配置PWM通道
    Led_PWM_Config();   

}


void Led_PWM_GPIO_Initialize(void)
{
    GPIO_InitType GPIO_InitStructure;

    GPIO_Structure_Initialize(&GPIO_InitStructure);

    GPIO_InitStructure.Pin = LED_RED_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP;
    GPIO_InitStructure.GPIO_Current = GPIO_DS_4MA;
    GPIO_InitStructure.GPIO_Alternate = LED_RED_TIM2_CH2_AF;
    GPIO_Peripheral_Initialize(LED_RED_PORT, &GPIO_InitStructure);

    GPIO_InitStructure.Pin = LED_BLUE_PIN;
    GPIO_InitStructure.GPIO_Alternate = LED_BLUE_TIM3_CH2_AF;
    GPIO_Peripheral_Initialize(LED_BLUE_PORT, &GPIO_InitStructure);
}


void Led_PWM_TIM_Base_Initialize(TIM_Module *TIMx,uint16_t period,uint16_t prescaler)
{
    TIM_TimeBaseInitType TIM_TimeBaseStructure;

    TIM_Base_Struct_Initialize(&TIM_TimeBaseStructure);
    TIM_TimeBaseStructure.Period=period;
    TIM_TimeBaseStructure.Prescaler=prescaler;
    TIM_TimeBaseStructure.ClkDiv=0;
    TIM_TimeBaseStructure.CntMode=TIM_CNT_MODE_UP;

    TIM_Base_Initialize(TIMx,&TIM_TimeBaseStructure);
}


void Led_PWM_Config(void)
{
    OCInitType TIM_OCInitStructure;

    TIM_Output_Channel_Struct_Initialize(&TIM_OCInitStructure);

    /* Channel 1, 2 and 3 Configuration in PWM mode */
    TIM_OCInitStructure.OcMode       = TIM_OCMODE_PWM2;
    TIM_OCInitStructure.OutputState  = TIM_OUTPUT_STATE_ENABLE;
    TIM_OCInitStructure.OutputNState = TIM_OUTPUT_NSTATE_DISABLE;
    TIM_OCInitStructure.Pulse        = 0;   //设置占空比
    TIM_OCInitStructure.OcPolarity   = TIM_OC_POLARITY_LOW;
    TIM_OCInitStructure.OcNPolarity  = TIM_OCN_POLARITY_LOW;
    TIM_OCInitStructure.OcIdleState  = TIM_OC_IDLE_STATE_SET;
    TIM_OCInitStructure.OcNIdleState = TIM_OCN_IDLE_STATE_RESET;

    TIM_Output_Channel2_Initialize(TIM2, &TIM_OCInitStructure);
    TIM_Output_Channel2_Initialize(TIM3, &TIM_OCInitStructure);


    TIM_On(TIM2);
    TIM_On(TIM3);
    TIM_PWM_Output_Enable(TIM2);
    TIM_PWM_Output_Enable(TIM3);
}


void LED(LED_STATE led_status)
{
	switch(led_status)
	{
		case LED_UPDATE_START :
			
			TIM_Compare2_Set(TIM3,2500);					//蓝 闪
			TIM_Compare2_Set(TIM2,0);							//红 灭
			// LedOff(LED_GREEN_PORT, LED_GREEN_PIN);//绿 灭
		
			break;
		
		case LED_UPDATE_SUCCEED :			
			   
			LedOn(LED_GREEN_PORT, LED_GREEN_PIN);	//绿 亮
			TIM_Compare2_Set(TIM3,0);							//蓝 灭
			TIM_Compare2_Set(TIM2,0);							//红 灭
			
			break;
		
		case LED_UPDATE_KEY_FINISH :						//手动退出流程,且流程失败,红灯常亮			
			   
			TIM_Compare2_Set(TIM2,5000);					//红 亮
			TIM_Compare2_Set(TIM3,0);							//蓝 灭
			// LedOff(LED_GREEN_PORT, LED_GREEN_PIN);//绿 亮

			
			break;
		
		case LED_UPDATE_FAIL :
			
			TIM_Compare2_Set(TIM2,2500);					//红 闪 
		
			break;
		
		default :
			break;
	}

}



void LedOn(GPIO_Module *GPIOx, uint16_t Pin)
{
    GPIO_Pins_Set(GPIOx, Pin);
}

void LedOff(GPIO_Module *GPIOx, uint16_t Pin)
{
    GPIO_PBC_Pins_Reset(GPIOx, Pin);
}
time.c
#include "time.h"
#include "main.h"



/**
 * @brief  Configure the system tick clock.
 */
uint32_t SysTick_InitConfig(uint32_t ms)
{ 
    uint32_t ticks=0;
    u8 pre=8;//分频
	
		RCC_ClocksType RCC_Clocks={0};
		
		if(ms==0)
		{
				return(1);
		}

    //UartReTimer(); 
		
		RCC_Clocks_Frequencies_Value_Get(&RCC_Clocks);
		
		ticks=RCC_Clocks.SysclkFreq / pre/1000*ms;
	
    if (ticks > SysTick_LOAD_RELOAD_Msk)
        return (1); /* Reload value impossible */

    SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;       /* set reload register */
    SysTick->VAL  = 0;                                           /* Load the SysTick Counter Value */
    SysTick->CTRL &=~SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
    SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk;
    return (0); /* Function successful */
}

/**
 * @brief  Use the system tick clock to delay.
 */
void SysTick_Delay_Ms(uint32_t ms)
{
    uint32_t i=0;
  
		SysTick->VAL  = 0;                                           /* Load the SysTick Counter Value */
    SysTick->CTRL = SysTick_CTRL_ENABLE_Msk ;
	
    for (i = 0; i < ms; i++)
    {
        /* When the value of the counter is reduced to 0, the bit 16 of the CRTL register is set to 1.
           When set to 1, the bit  will cleared to 0 with read
        */
        while (!((SysTick->CTRL) & (1 << 16)))
            ;
    }
    // Disable SysTick timer
     SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
}
common.c
#include "common.h"
#include "main.h"
#include <string.h>

static const uint8_t crc8_table[256] =
    {
        0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d,
        0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65, 0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d,
        0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb, 0xf2, 0xf5, 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd,
        0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, 0xa8, 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd,
        0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2, 0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea,
        0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2, 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a,
        0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, 0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a,
        0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42, 0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a,
        0x89, 0x8e, 0x87, 0x80, 0x95, 0x92, 0x9b, 0x9c, 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4,
        0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec, 0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4,
        0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c, 0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44,
        0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c, 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34,
        0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, 0x76, 0x71, 0x78, 0x7f, 0x6a, 0x6d, 0x64, 0x63,
        0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b, 0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13,
        0xae, 0xa9, 0xa0, 0xa7, 0xb2, 0xb5, 0xbc, 0xbb, 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83,
        0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb, 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3};

// 数据中包含 1 字节校验 //
uint8_t crc8_check(uint8_t *data, uint16_t len)
{
    uint16_t i = 0;
    uint8_t fcs = 0x0;

    // 计算数据校验
    for (i = 0; i < len; i++)
    {
        fcs = crc8_table[(uint8_t)fcs ^ *data];
        data++;
    }
    return fcs;
}
u_app_data.c
#include "u_app_data.h"
#include "main.h"
#include "uart.h"
#include "common.h"
#include <string.h>


extern uint8_t TxMark[COMNUM],RxMark[COMNUM];
extern uint8_t  UartReadBuf[9]; 
extern uint16_t ReceiveLen[COMNUM];
// extern uint8_t  UartReadBuf[COMNUM][UARTRESIZE]; 

U_UPDATE_STATE u_g_update_state = U_UPDATE_START; // 初始状态

uint8_t u_app_data_buffer[128] = {0}; // 存储读到的128个字节的数据

void UART_Request_Update_Flow(void)
{
    uint8_t update_finish = 0; // 标志位:1升级结束,退出流程

    u_g_update_state = U_UPDATE_START; // 初始状态

    uint16_t u_app_pack_num = 0; // APP 数据包序号

    uint16_t time = 0;

    while (1)
    {
        if (update_finish == 1)
            break; // 标志位:1升级结束,退出流程
				
        if (g_key_on == 0)//按键手动退出流程
        {
//           if(update_finish != 1)
//						{
//							 LED(LED_UPDATE_KEY_FINISH); // 退出流程时,未成功则红灯常亮
							
//						} 	
            break; // 在一直错误,升级失败的时候,通过按键退出流程,
        }
            
        switch (u_g_update_state)
        {
        case U_UPDATE_START:

            U_Send_Start_Update_Message(UART3_ID, U_DEVICE_ID); // 开始升级

            while (RxMark[0] == UNVALID_MARK && time < 300)
            {
                SysTick_Delay_Ms(10); // 等待接收完成
                time++;
                ; // 等待接收完成 或 手动退出流程
            }

            if (U_Get_Sending_UpdateStart_Result(UartReadBuf) == SENGDING_OK) // 判断响应信息,响应为OK
            {

                U_Send_Start_Update_Message(UART3_ID, U_DEVICE_ID); // 开始升级

                while (RxMark[0] == UNVALID_MARK && time < 300)
                {
                    SysTick_Delay_Ms(10); // 等待接收完成
                    time++;
                    ; // 等待接收完成 或 手动退出流程
                }

                if (U_Get_Sending_UpdateStart_Result(UartReadBuf) == SENGDING_OK) // 判断响应信息,响应为OK
                {
                    u_g_update_state = U_UPDATE_READY; // 更改更新程序流程状态为 U_UPDATE_READY
                }

                else
                {
                    u_g_update_state = U_UPDATE_FAIL; // 响应信息,响应为FAIL,更改更新程序流程状态为 U_UPDATE_FAIL
                }
            }

            else
            {

                u_g_update_state = U_UPDATE_FAIL; // 响应信息,响应为FAIL,更改更新程序流程状态为 U_UPDATE_FAIL
            }

            break;
        case U_UPDATE_READY:

            U_Send_Ready_Update_Message(UART3_ID, U_DEVICE_ID, U_Get_APPCodeCrc(), U_Get_APPCodeTotalNum(), U_PROJECT_ID); // 准备升级,ceil(Get_APPCodeLen()/128,数据的总包数

            while (RxMark[0] == UNVALID_MARK && time < 300)
            {
                SysTick_Delay_Ms(10); // 等待接收完成
                time++;
                ; // 等待接收完成 或 手动退出流程
            }

            if (U_Get_Sending_UpdateReady_Result(UartReadBuf) == SENGDING_OK) // 判断响应信息,响应为OK
            {

                u_g_update_state = U_UPDATE_DATA; // 更改更新程序流程状态为 U_UPDATE_DATA
            }
            else
            {

                u_g_update_state = U_UPDATE_FAIL; // 响应信息,响应为FAIL,更改更新程序流程状态为 U_UPDATE_FAIL
            }
            // ReceiveLen[0] = 0;

            break;
        case U_UPDATE_DATA:

            U_Read_App_Data(U_APP_CODE_ADDR_SART + u_app_pack_num * 128, u_app_data_buffer); // 读取128个数据到u_app_data_buffer

            U_Send_Update_Data_Message(UART3_ID, U_DEVICE_ID, u_app_pack_num, u_app_data_buffer); // 发送app区数据

            while (RxMark[0] == UNVALID_MARK && time < 300)
            {
                SysTick_Delay_Ms(10); // 等待接收完成
                time++;
                ; // 等待接收完成 或 手动退出流程
            }

            if (U_Get_Sending_UpdateData_Result(UartReadBuf) == SENGDING_OK) // 判断响应信息,响应为OK
            {

                u_g_update_state = U_UPDATE_DATA; // 更改更新程序流程状态为 U_UPDATE_DATA

                if ((u_app_pack_num + 1) >= U_Get_APPCodeTotalNum()) // 若是最后一帧APP数据,更新程序流程状态为 U_UPDATE_FINISH
                {
                    u_g_update_state = U_UPDATE_FINISH; // 更改更新程序流程状态为 U_UPDATE_FINISH
                }

                u_app_pack_num++; // 成功,则发下一帧 APP数据
            }
            else
            {
                u_g_update_state = U_UPDATE_FAIL; // 响应信息,响应为FAIL,更改更新程序流程状态为 U_UPDATE_FAIL
                
            }
            // ReceiveLen[0] = 0;
            break;
        case U_UPDATE_FINISH:

            U_Send_Finish_Update_Message(UART3_ID, U_DEVICE_ID); // 升级结束

            while (RxMark[0] == UNVALID_MARK && time < 300)
            {
                SysTick_Delay_Ms(10); // 等待接收完成
                time++;
                ; // 等待接收完成 或 手动退出流程
            }

            if (U_Get_Sending_UpdateFinish_Result(UartReadBuf) == SENGDING_OK) // 判断响应信息,响应为OK
            {

                u_g_update_state = U_UPDATE_SUCCEED; // 更改更新程序流程状态为 U_UPDATE_SUCCEED
            }
            else
            {

                u_g_update_state = U_UPDATE_FAIL; // 响应信息,响应为FAIL,更改更新程序流程状态为 U_UPDATE_FAIL
            }
            // ReceiveLen[0] = 0;
            break;
			case U_UPDATE_SUCCEED:

				update_finish = 1; 	//标志位:1升级结束,退出流程

                //LED(LED_UPDATE_SUCCEED); // 成功 绿灯
				//LedOn(LED_GREEN_PORT, LED_GREEN_PIN);	//绿 亮
                //TIM_Compare2_Set(TIM3,0);							//蓝 灭
                //TIM_Compare2_Set(TIM2,0);							//红 灭

                break;
						
        case U_UPDATE_FAIL:

            update_finish = 1; // 失败则退出流程,重新按键开始
				
						//u_app_pack_num = 0; // 失败,则重新执行流程,所有数据重新发送

                        //            LED(LED_UPDATE_FAIL); // 失败 红灯闪
			TIM_Compare2_Set(TIM2,2500);					//红 闪 

            break;
        default:
            break;
        }

        RxMark[0] = UNVALID_MARK;           // 重新接收数据
        time = 0;
    }
}

/**
 * @brief 获取 U_UPDATE_START流程的响应结果
 *
 * @param data
 * @return SENDING_RESULT
 */
SENDING_RESULT U_Get_Sending_UpdateStart_Result(uint8_t *data)
{
    return U_Get_Sending_Result(UartReadBuf, U_UPDATE_TYPE_FUN_CODE_WRITE, U_UPDATE_TYPE_FUN_EXT_CODE_START_UPDATE); // 判断响应信息,响应为OK
}

/**
 * @brief 获取 U_UPDATE_READY 流程的响应结果
 *
 * @param data
 * @return SENDING_RESULT
 */
SENDING_RESULT U_Get_Sending_UpdateReady_Result(uint8_t *data)
{
    return U_Get_Sending_Result(UartReadBuf, U_UPDATE_TYPE_FUN_CODE_WRITE, U_UPDATE_TYPE_FUN_EXT_CODE_READY_UPDATE); // 判断响应信息,响应为OK
}

/**
 * @brief 获取 UPDATE_DATA流程的响应结果
 *
 * @param data
 * @return SENDING_RESULT
 */
SENDING_RESULT U_Get_Sending_UpdateData_Result(uint8_t *data)
{
    return U_Get_Sending_Result(UartReadBuf, U_UPDATE_TYPE_FUN_CODE_WRITE, U_UPDATE_TYPE_FUN_EXT_CODE_UPDATE_DATA); // 判断响应信息,响应为OK
}

/**
 * @brief 获取 U_UPDATE_FINISH 流程的响应结果
 *
 * @param data
 * @return SENDING_RESULT
 */
SENDING_RESULT U_Get_Sending_UpdateFinish_Result(uint8_t *data)
{
    return U_Get_Sending_Result(UartReadBuf, U_UPDATE_TYPE_FUN_CODE_WRITE, U_UPDATE_TYPE_FUN_EXT_CODE_FINISH_UPDATE); // 判断响应信息,响应为OK
}

/**
 * @brief 获取发送后的成功或失败的结果
 *
 * @param data 接收到的响应的数据
 * @return uint8_t
 */
SENDING_RESULT U_Get_Sending_Result(uint8_t *data, uint8_t fun_code, uint8_t fun_ext_code)
{
    uint8_t fun_code_ask = UartReadBuf[3];     // 功能码
    uint8_t fun_ext_code_ask = UartReadBuf[4]; // 功能扩展码
    uint8_t data_ask = UartReadBuf[6];         // 数据

    uint8_t crc = crc8_check(UartReadBuf + 1, 6); // 计算响应信息的CRC,CRC8校验内容为从功能码到数据域所有数据的CRC8校验

    if ((crc == UartReadBuf[7]) && (UartReadBuf[0]==0xF2) && (UartReadBuf[8]==0xF1)) // 计算的CRC与响应数据中的CRC结果一致,帧头帧尾一致
    {
        if ((data_ask == 0) && (fun_code_ask == fun_code) && (fun_ext_code_ask == fun_ext_code)) // 回复的数据是0,表示成功;校验响应的数据中的功能码和扩展码
        {
            return SENGDING_OK;
        }
        else
        {
            return SENDING_FAIL;
        }
    }
    else
    {
        return SENDING_FAIL;
    }
}

/**
 * @brief 读取APP数据的CRC值
 *
 * @return uint16_t
 */
uint16_t U_Get_APPCodeCrc(void)
{
    return *(uint16_t *)U_APP_CODE_CRC_ADDR;
}

///**
// * @brief 读取APP数据的CRC值
// *
// * @return uint16_t
// */
//uint16_t Get_FlashAPPCodeCrc(void)
//{
//		uint16_t crc=0;
		num=*(uint16_t *)U_APP_CODE_PACK_TOTAL_NUM_ADDR;
//		crc=CRC16((unsigned char *)U_APP_CODE_ADDR_SART,4096);
//    return crc;
//}

/**
 * @brief 读取APP数据的总包数
 *
 * @return uint16_t
 */
uint16_t U_Get_APPCodeTotalNum(void)
{
	uint16_t num=0;
	num=*(uint16_t *)U_APP_CODE_PACK_TOTAL_NUM_ADDR;
    return num;
}

/**
 * @brief 从Flash地址读取128个字节的APP数据
 *
 * @param flash_address
 * @param data_buffer
 */
void U_Read_App_Data(uint32_t flash_address, uint8_t *data_buffer)
{
    for (uint8_t i = 0; i < 128; i++) // 只读取128字节的数据
    {
        data_buffer[i] = *((uint8_t *)(flash_address + i));
    }
}

void U_Load_App(u32 appxaddr)
{
    __disable_irq(); // 关闭所有中断

    // uint8_t i;
    if (((*(volatile uint32_t *)appxaddr) & 0x2FFE0000) == 0x20000000) // 检查栈顶地址是否合法.0x20000000是sram的起始地址,也是程序的栈顶地址
    {
        // 定义一个函数指针,指向应用程序的起始地址
        void (*JumpToApp)(void) = (void (*)(void))(*((uint32_t *)(appxaddr + 4))); // 用户代码区第二个字为程序开始地址(复位地址)

        __set_MSP(*(volatile uint32_t *)appxaddr);

        JumpToApp(); // 跳转到APP.
    }
}

c_app_data.c
在这里插入代码片#include "c_app_data.h"
#include "main.h"
#include "can.h"
#include "common.h"

C_UPDATE_STATE c_g_update_state = C_UPDATE_START; // 初始状态

uint8_t c_app_data_buffer[128] = {0}; // 存储读到的128个字节的数据

void CAN_Request_Update_Flow(void)
{
    uint8_t update_finish = 0; // 标志位:1升级结束,退出流程

    c_g_update_state = C_UPDATE_START; // 初始状态

    uint16_t c_app_pack_num = 0; // APP 数据包序号


    while (1)
    {
        if (update_finish == 1)
            break; // 标志位:1升级结束,退出流程
				
        if (g_key_on == 0)//按键手动退出流程
        {
//           if(C_UPDATE_FINISH != 1)
//						{
//							 LED(LED_UPDATE_KEY_FINISH); // 退出流程时,未成功则红灯常亮
							
//						} 	
            break; // 在一直错误,升级失败的时候,通过按键退出流程,
        }
            
        switch (c_g_update_state)
        {
        case C_UPDATE_START:

            C_Send_Start_Update_Message(CAN_ID, C_DEVICE_ID); // 开始升级

            while (g_rx_flag == UNRECEIVED && g_key_on == 1)
                ; // 等待接收完成 或 手动退出流程

            if (C_Get_Sending_UpdateStart_Result(CAN_RxMessage.Data) == SENGDING_OK) // 判断响应信息,响应为OK
            {

                c_g_update_state = C_UPDATE_READY; // 更改更新程序流程状态为 C_UPDATE_READY
            }
            else
            {

                c_g_update_state = C_UPDATE_FAIL; // 响应信息,响应为FAIL,更改更新程序流程状态为 C_UPDATE_FAIL
            }

            break;
        case C_UPDATE_READY:

            C_Send_Ready_Update_Message(CAN_ID, C_DEVICE_ID, C_Get_APPCodeCrc(), C_Get_APPCodeTotalNum(), C_PROJECT_ID); // 准备升级,ceil(Get_APPCodeLen()/128,数据的总包数

            while (g_rx_flag == UNRECEIVED && g_key_on == 1)
                ; // 等待接收完成 或 手动退出流程


            if (C_Get_Sending_UpdateReady_Result(CAN_RxMessage.Data) == SENGDING_OK) // 判断响应信息,响应为OK
            {
                c_g_update_state = C_UPDATE_DATA; // 更改更新程序流程状态为 C_UPDATE_DATA
            }
            else
            {
                c_g_update_state = C_UPDATE_FAIL; // 响应信息,响应为FAIL,更改更新程序流程状态为 C_UPDATE_FAIL
            }


            break;
        case C_UPDATE_DATA:

            C_Read_App_Data(C_APP_CODE_ADDR_SART + c_app_pack_num * 128, c_app_data_buffer); // 读取128个数据到c_app_data_buffer

            C_Send_Update_Data_Message(CAN_ID, C_DEVICE_ID, c_app_pack_num, c_app_data_buffer); // 发送app区数据

            while (g_rx_flag == UNRECEIVED && g_key_on == 1)
                ; // 等待接收完成 或 手动退出流程

            if (C_Get_Sending_UpdateData_Result(CAN_RxMessage.Data) == SENGDING_OK) // 判断响应信息,响应为OK
            {

                c_g_update_state = C_UPDATE_DATA; // 更改更新程序流程状态为 C_UPDATE_DATA

                if ((c_app_pack_num + 1) >= C_Get_APPCodeTotalNum()) // 若是最后一帧APP数据,更新程序流程状态为 C_UPDATE_FINISH
                {
                    c_g_update_state = C_UPDATE_FINISH; // 更改更新程序流程状态为 C_UPDATE_DATA
                }

                c_app_pack_num++; // 成功,则发下一帧 APP数据
            }
            else
            {
                c_g_update_state = C_UPDATE_FAIL; // 响应信息,响应为FAIL,更改更新程序流程状态为 C_UPDATE_FAIL
                
            }

            break;
        case C_UPDATE_FINISH:

            C_Send_Finish_Update_Message(CAN_ID, C_DEVICE_ID); // 升级结束

            while(g_rx_flag == UNRECEIVED && g_key_on == 1)
                ; // 等待接收完成 或 手动退出流程

            if (C_Get_Sending_UpdateFinish_Result(CAN_RxMessage.Data) == SENGDING_OK) // 判断响应信息,响应为OK
            {

                c_g_update_state = C_UPDATE_SUCCEED; // 更改更新程序流程状态为 C_UPDATE_SUCCEED
            }
            else
            {

                c_g_update_state = C_UPDATE_FAIL; // 响应信息,响应为FAIL,更改更新程序流程状态为 C_UPDATE_FAIL
            }

            break;
		case C_UPDATE_SUCCEED:

			update_finish = 1; 	//标志位:1升级结束,退出流程

//          LED(LED_C_UPDATE_SUCCEED); // 成功 绿灯
			LedOn(LED_GREEN_PORT, LED_GREEN_PIN);	//绿 亮
//			TIM_Compare2_Set(TIM3,0);							//蓝 灭
//			TIM_Compare2_Set(TIM2,0);							//红 灭

            break;
						
        case C_UPDATE_FAIL:

            c_g_update_state = C_UPDATE_START; // 所有响应失败都不做处理,直接重新开始
				
						c_app_pack_num = 0; // 失败,则重新执行流程,所有数据重新发送

//            LED(LED_C_UPDATE_FAIL); // 失败 红灯闪
			TIM_Compare2_Set(TIM2,2500);					//红 闪 

            break;
        default:
            break;
        }

        g_rx_flag = UNRECEIVED; // g_rx_flag更改为UNRECEIVED
    }
}

/**
 * @brief 获取 C_UPDATE_START流程的响应结果
 *
 * @param data
 * @return SENDING_RESULT
 */
SENDING_RESULT C_Get_Sending_UpdateStart_Result(uint8_t *data)
{
    return C_Get_Sending_Result(data, C_UPDATE_TYPE_FUN_CODE_WRITE, C_UPDATE_TYPE_FUN_EXT_CODE_START_UPDATE); // 判断响应信息,响应为OK
}

/**
 * @brief 获取 C_UPDATE_READY 流程的响应结果
 *
 * @param data
 * @return SENDING_RESULT
 */
SENDING_RESULT C_Get_Sending_UpdateReady_Result(uint8_t *data)
{
    return C_Get_Sending_Result(CAN_RxMessage.Data, C_UPDATE_TYPE_FUN_CODE_WRITE, C_UPDATE_TYPE_FUN_EXT_CODE_READY_UPDATE); // 判断响应信息,响应为OK
}

/**
 * @brief 获取 C_UPDATE_DATA流程的响应结果
 *
 * @param data
 * @return SENDING_RESULT
 */
SENDING_RESULT C_Get_Sending_UpdateData_Result(uint8_t *data)
{
    return C_Get_Sending_Result(CAN_RxMessage.Data, C_UPDATE_TYPE_FUN_CODE_WRITE, C_UPDATE_TYPE_FUN_EXT_CODE_UPDATE_DATA); // 判断响应信息,响应为OK
}

/**
 * @brief 获取 C_UPDATE_FINISH 流程的响应结果
 *
 * @param data
 * @return SENDING_RESULT
 */
SENDING_RESULT C_Get_Sending_UpdateFinish_Result(uint8_t *data)
{
    return C_Get_Sending_Result(CAN_RxMessage.Data, C_UPDATE_TYPE_FUN_CODE_WRITE, C_UPDATE_TYPE_FUN_EXT_CODE_FINISH_UPDATE); // 判断响应信息,响应为OK
}

/**
 * @brief 获取发送后的成功或失败的结果
 *
 * @param data 接收到的响应的数据
 * @return uint8_t
 */
SENDING_RESULT C_Get_Sending_Result(uint8_t *data, uint8_t fun_code, uint8_t fun_ext_code)
{
    uint8_t fun_code_ask = data[1];     // 功能码
    uint8_t fun_ext_code_ask = data[2]; // 功能扩展码
    uint8_t data_ask = data[4];         // 数据

    uint8_t crc = crc8_check(data + 1, 4); // 计算响应信息的CRC,CRC8校验内容为从功能码到数据域所有数据的CRC8校验

    if (crc == data[5]) // 计算的CRC与响应数据中的CRC结果一致
    {
        if ((data_ask == 0) && (fun_code_ask == fun_code) && (fun_ext_code_ask == fun_ext_code)) // 回复的数据是0,表示成功;校验响应的数据中的功能码和扩展码
        {
            return SENGDING_OK;
        }
        else
        {
            return SENDING_FAIL;
        }
    }
    else
    {
        return SENDING_FAIL;
    }
}

/**
 * @brief 读取APP数据的CRC值
 *
 * @return uint16_t
 */
uint16_t C_Get_APPCodeCrc(void)
{
    return *(uint16_t *)C_APP_CODE_CRC_ADDR;
}

///**
// * @brief 读取APP数据的CRC值
// *
// * @return uint16_t
// */
//uint16_t Get_FlashAPPCodeCrc(void)
//{
//		uint16_t crc=0;
		num=*(uint16_t *)C_APP_CODE_PACK_TOTAL_NUM_ADDR;
//		crc=CRC16((unsigned char *)APP_CODE_ADDR_SART,4096);
//    return crc;
//}

/**
 * @brief 读取APP数据的总包数
 *
 * @return uint16_t
 */
uint16_t C_Get_APPCodeTotalNum(void)
{
		uint16_t num=0;
		num=*(uint16_t *)C_APP_CODE_PACK_TOTAL_NUM_ADDR;
    return num;
}

/**
 * @brief 从Flash地址读取128个字节的APP数据
 *
 * @param flash_address
 * @param data_buffer
 */
void C_Read_App_Data(uint32_t flash_address, uint8_t *data_buffer)
{
    for (uint8_t i = 0; i < 128; i++) // 只读取128字节的数据
    {
        data_buffer[i] = *((uint8_t *)(flash_address + i));
    }
}

void C_Load_App(u32 appxaddr)
{
    __disable_irq(); // 关闭所有中断

    // uint8_t i;
    if (((*(volatile uint32_t *)appxaddr) & 0x2FFE0000) == 0x20000000) // 检查栈顶地址是否合法.0x20000000是sram的起始地址,也是程序的栈顶地址
    {
        // 定义一个函数指针,指向应用程序的起始地址
        void (*JumpToApp)(void) = (void (*)(void))(*((uint32_t *)(appxaddr + 4))); // 用户代码区第二个字为程序开始地址(复位地址)

        __set_MSP(*(volatile uint32_t *)appxaddr);

        JumpToApp(); // 跳转到APP.
    }
}

  • 20
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: ESP8266离线安装包是为了满足用户在无网络环境下也能够使用ESP8266板子而开发的。离线安装包一般包括编程所需要的软件和必要的驱动程序。因为ESP8266的开发需要固件的烧录、编译和调试等一系列操作,所有这些都需要特定的软件和工具。对于没有网络或者网络条件不好的用户,无法从网络上获取这些软件和工具。因此,我们需要将这些必要的软件和工具打包成一个离线安装包,方便用户离线安装后进行开发。 ESP8266的离线安装包通常包含了Arduino IDE和ESP8266开发版的驱动,用户只需要下载好该安装包后,解压缩并按照说明进行安装即可。此后,用户就可以在离线状态下在Arduino IDE中进行代码编写、调试和上传等工作。 离线安装包的制作可以通过专业的软件制作,也可以通过手动下载所需的软件和驱动程序进行打包。对于ESP8266的开发人员来说,离线安装包简单易用,且可以满足在没有网络情况下的开发需求,是一个不可或缺的工具。 ### 回答2: ESP8266离线安装包是一种软件包,用于安装ESP8266模块上的固件,并且可以在没有互联网连接或在线更新的情况下进行更新。这种包通常包含一个完整的固件文件和一些辅助工具,例如串口通信工具和烧录软件。 在没有互联网连接的情况下,使用ESP8266离线安装包可以帮助用户快速更新固件,提高生产效率和简化操作流程。此外,这种包还可以有效地保护设备的安全性和稳定性,避免因在线更新失误导致的设备故障或数据丢失。 虽然使用ESP8266离线安装包可以避免与互联网连接,但确保离线包的更新和合法性也是非常关键的。用户应该选择官方发布的离线安装包,并遵循官方的更新和安装指南。此外,用户还应定期检查固件的安全性和稳定性,并及时升级到更高版本的固件。 ### 回答3: ESP8266是一款极为流行的物联网芯片,如果要进行开发和调试,需要安装相应的开发环境和相关软件包,其中就包括ESP8266的离线安装包。 ESP8266离线安装包主要是为了方便没有网络连接或者网络连接较慢的开发者使用。这个安装包中包含了ESP8266的驱动程序、开发环境、相关库文件、示例代码以及文档等。 在进行离线安装时,需要先下载这个包,然后将其解压到本地硬盘中。接着,运行安装程序,按照提示完成安装过程即可。需要注意的是,在安装过程中可能会出现一些问题,比如安装路径设置错误、系统环境配错等,在这种情况下,需要及时修改并重新安装。 ESP8266离线安装包的使用方法和在线安装方法基本相同,可以通过它来编写和调试ESP8266的应用程序,进行网络连接、数据传输、系统控制等操作。需要注意的是,由于离线安装包并不包含最新的库文件和示例代码,因此开发者需要及时更新和升级,以确保开发效率和程序性能。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值