两轮平衡车_9_无线升级

用烧录器下载程序,每次插拔下载接口都非常的费劲。就想着能够实现无线烧录程序就好;查了相关资料,需要先写一个Bootloader,然后下载到F28035主控板,然后通过上位机通过无线串口对主控板实现升级;对DSP内部存储器的调用得用官方提供的API库;安装C2000ware之后,在下面路径可以搜索到API_lib;而且有例程可以参考;

参考例程学会如何调用API函数后,就可以开始写Bootloader,之前有发过帖子分享了F103的串口Bootloader,直接引用之前的程序,再加上OLED显示Bootloader的状态;代码如下:

//============================================================================
// * Function    :  BootloaderAPP()
// * Purpose     :  This function initializes the BootloaderAPP.
// * Parameters  :  Null
// * Return      :  Null
//============================================================================
#pragma CODE_SECTION(BootloaderAPP,"ramfuncs");
 void BootloaderAPP(void)
 {
    Uint16 Status;
    Uint32 u32OffsetAddress = 0;
    Uint16 u16ProgramCount  = 0;
    Uint16 u16VerityCount   = 0;
    Uint32 u32TimerCount    = 0;

    u8Program_Cnt=0;
    memset(&tSCICom, 0, sizeof(tSCICom));
    memset(&tSCICom.u8SCIRXBuffer, 0, (PacketSize+8));

    while(1)
    {

        tUpdateFlash.u8UpdateDataFlag = 1;
        while(tUpdateFlash.u8UpdateDataFlag == 1)
        {
            u32TimerCount++;
            if(u32TimerCount > 15000000)
            {
                u32TimerCount = 0;

                Status = Flash_Verify((Uint16 *)VerifyAddr,(Uint16 *)UpdataFlag16,8,&FlashStatus);
                if(Status == STATUS_SUCCESS)
                {
                   return;
                }
            }
        }
        if(tUpdateFlash.u8UpdateDataStatus == 0)
        {
            switch(tSCICom.u8SCIRXBuffer[Data_Commad])
            {
            case Update_Keep:
                tUpdateFlash.u8UpdateDataStatus = M_ACK;
                //============================OLED显示==============================//
                   OLED_Clear();
                   OLED_ShowString(20,10,"<-BootAPP->");
                   OLED_ShowString(0,30,"Link_Success");
                   OLED_Refresh_Gram();
               //================================================================//
                break;

            case Update_EraseAll:
                DINT;
                Status = Flash_Erase((SECTORD|SECTORE|SECTORF|SECTORG|SECTORH),&FlashStatus);
                EINT;
                if(Status == STATUS_SUCCESS)
                {
                    tUpdateFlash.u8UpdateDataStatus = EraseAll_Success;
                //============================OLED显示==============================//
                    OLED_Clear();
                    OLED_ShowString(20,10,"<-BootAPP->");
                    OLED_ShowString(0,30,"Erase_Success");
                    OLED_Refresh_Gram();
                //================================================================//
                }
                else
                {
                  tUpdateFlash.u8UpdateDataStatus = Com_Fail;
                }
                break;

            case Update_ProgramCommand:
                u32OffsetAddress = ((long)tSCICom.u8SCIRXBuffer[4]<<8)+((long)tSCICom.u8SCIRXBuffer[5]);
                if(u32OffsetAddress <= 0xFFFF)
                {
                    for(u16ProgramCount = 0; u16ProgramCount < (tSCICom.u16UpdateDataLength/2); u16ProgramCount++)
                    {
                        tSCICom.Update_Buffer[u16ProgramCount]=(tSCICom.u8SCIRXBuffer[2*u16ProgramCount+6] << 8)+(tSCICom.u8SCIRXBuffer[2*u16ProgramCount+7]);
                    }

                    for(u16VerityCount = 0; u16VerityCount < (tSCICom.u16UpdateDataLength/4); u16VerityCount++)
                    {
                        tSCICom.Verify_Buffer[u16VerityCount]=((Uint32)tSCICom.u8SCIRXBuffer[2*u16VerityCount+1] << 16)+((Uint32)tSCICom.u8SCIRXBuffer[2*u16VerityCount]);
                    }


                    Status = Flash_Program((Uint16 *)(u32OffsetAddress + Flash_ProjectStart),(Uint16 *)tSCICom.Update_Buffer,tSCICom.u16UpdateDataLength/2,&FlashStatus);

                    if(Status == STATUS_SUCCESS)
                    {
                        tUpdateFlash.u8UpdateDataStatus = ProgramCommand_Success;
                    //============================OLED显示==============================//
                        u8Program_Cnt++;
                        OLED_ShowString(20,10,"<-BootAPP->");
                        OLED_ShowString(0,30,"Programming  ");
                        OLED_ShowNumber(96,30,u8Program_Cnt,3,12);
                        OLED_Refresh_Gram();
                    //================================================================//
                    }
                    else
                   {
                     tUpdateFlash.u8UpdateDataStatus = Com_Fail;
                   }
                }
                else
                {
                    tUpdateFlash.u8UpdateDataStatus = Com_Fail;
                }
                break;

            case Update_End:
                 tUpdateFlash.u8UpdateDataStatus = M_NACK;
                 break;
            }
        }
        UpdateReplyData();
        tSCICom.u16BuffCountNum = 0;
        u32TimerCount = 0;
        if(tUpdateFlash.u8UpdateDataStatus == M_NACK)
        {
            WriteVerfyData();
        //============================OLED显示==============================//
            u8Program_Cnt=0;
            OLED_Clear();
            OLED_ShowString(20,10,"<-BootAPP->");
            OLED_ShowString(0,30,"Upgrade_Success");
            OLED_Refresh_Gram();
        //================================================================//
            memset(&tSCICom , 0 , sizeof(tSCICom));
            memset(tSCICom.u8SCIRXBuffer , 0xFF , (PacketSize+8));
            break;
        }
   }
}

Bootloader写好之后就是上位机的编写,之前就有过C#的学习经历,还有点基础,其他不懂的就问DeekSeek ;上位机主要难点有三个,1、是如何对烧录下载文件的解析;2、是如何对下载到DSP的每一帧数据处理;3、是跟DSP之间的通信协议;

对烧录文件的解析如下:

 private UInt16 File_Parsing(object sender)
 {
     byte DataLen = 0;
     byte FileCom;
     UInt16 count = 0;
     while (count < PacketSize)
     {
         if ((LineDataCount == 0) && (SupdataFlag == 0))
         {
             File_String = reader.ReadLine();
             SendBox.AppendText(File_String);
             SendBox.AppendText(Environment.NewLine);
             LineNumCount++;
         }
         if (File_String.IndexOf(':') == 0)
         {
             DataLen = Convert.ToByte(File_String.Substring(1, 2), 16);
             AddressOffset = Convert.ToUInt32((Convert.ToByte(File_String.Substring(3, 2), 16) << 8) + (Convert.ToByte(File_String.Substring(5, 2), 16)));
             if (DataLen != 0)
             {
                if (UpgradeObject.Text == "DSP")
                {
                     if (LineNumCount == 2)
                     {
                         AddressRecord = AddressOffset + AddressBase;
                     }
                     AddressReal = AddressBase + AddressOffset;
                     AddressTemp = Convert.ToUInt32(AddressReal - AddressRecord);
                     AddressTemp = Convert.ToUInt32(AddressOffset * 2);
                }
                else if (UpgradeObject.Text == "MCU")
                 {
                     AddressReal = AddressBase + AddressOffset;
                     AddressTemp = Convert.ToUInt32(AddressReal);
                 }
             }
                
             FileCom = Convert.ToByte(File_String.Substring(7, 2), 16);
             switch (FileCom) 
             {
                 case 0x00:
                     while (((AddressTemp - PreviousAddress) != PreviousDataLen) && (FristFlag == 1) && (count < PacketSize))
                     {
                         Data[count + 6] = 0xFF;
                         count++;
                         PreviousAddress++;
                         if (count == PacketSize)
                         {
                             SupdataFlag = 1;
                             return count;
                         }
                     }
                     for (; (LineDataCount < DataLen) && (count < PacketSize); LineDataCount++)
                     {
                         Data[count + 6] = Convert.ToByte(File_String.Substring(LineDataCount * 2 + 9, 2), 16);
                         count++;
                     }
                     if (LineDataCount == DataLen)
                     {
                         PreviousDataLen = DataLen;
                         PreviousAddress = AddressTemp;
                         LineDataCount = 0;
                         SupdataFlag = 0;
                     }
                     FristFlag = 1;
                     break;

                 case 0x01:
                     reader.Close();
                     UpdataFlag = 1;
                     return count;

                 case 0x04:
                     AddressBase = Convert.ToUInt32((Convert.ToByte(File_String.Substring(3, 2), 16) << 8) +
                                                    (Convert.ToByte(File_String.Substring(5, 2), 16)) +
                                                    (Convert.ToByte(File_String.Substring(9, 2), 16) << 24) +
                                                    (Convert.ToByte(File_String.Substring(11, 2), 16) << 16));
                     break;
             }
         }
     }
     return count;
 }

发送数据处理代码如下:

 private void Updata_Packaging(object sender)
 {
     UInt16 crc = 0;
     UInt16 i;
     UInt16 strlen;

     //起始字节
     Data[0] = 0xDD;
     //数据长度 + 数据获取
     strlen = File_Parsing(sender);
     if (strlen != PacketSize)
     {
         for (i = strlen; i < PacketSize; i++ )
         {
             Data[i + 6] = 0xFF;
         }
         strlen = PacketSize;
     }

     Data[1] = Convert.ToByte(strlen >> 8);
     Data[2] = Convert.ToByte(strlen & 0xFF);
     //命令
     Data[3] = 0x0E;
     //地址
     Data[4] = Convert.ToByte(Download_Addr >> 8);
     Data[5] = Convert.ToByte(Download_Addr & 0xFF);
     Download_Addr += PacketSize/2;
     //crc校验
     strlen = Convert.ToUInt16(strlen + 6);
     crc = CalculateCrc16(Data, strlen);

     
     Data[strlen] = Convert.ToByte(crc >> 8);
     Data[strlen + 1] = Convert.ToByte(crc & 0xFF);

     //将待发送数据拷贝到DataBuffer,等待发送
     DataLength = strlen + 2;
     Array.Copy(Data, DataBuffer, DataLength);
 }

与DSP通讯交互代码如下:

        private void StartUpdata_Click(object sender, EventArgs e)
        {
            int num;
            ushort crc = 0;

            Calculagraph.Reset();
            Calculagraph.Start();
            //1.引导进入Boot
            num = 1;
            while (num <= AgainCount)
            {
                Data[0] = 0xDD;
                Data[1] = 0x00;
                Data[2] = 0x1A;
                Data[3] = 0x2A;
                Data[4] = 0x3A;
                crc = CalculateCrc16(Data, 5);
                Data[5] = Convert.ToByte(crc >> 8);
                Data[6] = Convert.ToByte(crc & 0xFF);
                serialPort.Write(Data, 0, 7);

                Delay(200);
                num++;
            }
            //2.状态检测
            num = 1;
            while (num <= AgainCount)
            {
                Data[0] = 0xDD;
                Data[1] = 0x00;
                Data[2] = 0x00;
                Data[3] = 0x0A;
                Data[4] = 0x00;
                Data[5] = 0x00;
                crc = CalculateCrc16(Data, 6);
                Data[6] = Convert.ToByte(crc >> 8);
                Data[7] = Convert.ToByte(crc & 0xFF);
                serialPort.Write(Data, 0, 8);

                Delay(200);
                num++;
                if (Cmdata[2] == 0xAA)
                {
                    Cmdata[2] = 0x00;
                    RecState.Text = "连接成功";
                    StartUpdata.Enabled = false;
                    break;
                }
                if (num == AgainCount)
                {
                    MessageBox.Show(" 升级等待超时1 ");
                    return;
                }
            }

            //3.擦除Flash
            num = 1;
            while (num <= AgainCount)
            {
                Data[0] = 0xDD;
                Data[1] = 0x00;
                Data[2] = 0x00;
                Data[3] = 0x0C;
                Data[4] = 0x00;
                Data[5] = 0x00;
                crc = CalculateCrc16(Data, 6);
                Data[6] = Convert.ToByte(crc >> 8);
                Data[7] = Convert.ToByte(crc & 0xFF);
                serialPort.Write(Data, 0, 8);

                Delay(3000);
                num++;
                if (Cmdata[2] == 0xC1)
                {
                    Cmdata[2] = 0x00;
                    RecState.Text = "擦除全部成功";
                    break;
                }
                if (num == AgainCount)
                {
                    MessageBox.Show(" 升级等待超时2 ");
                    return;
                }
            }

            //4.烧录数据
            UpdataFlag = 0;
            while (UpdataFlag == 0)
            {
                Updata_Packaging(sender);
                num = 1;
                while (num <= AgainCount)
                {
                    serialPort.Write(DataBuffer, 0, DataLength);
                    Delay(100);
                    num++;
                    if (Cmdata[2] == 0xE1)
                    {
                        Cmdata[2] = 0x00;
                        RecState.Text = "正在升级";
                        break;
                    }
                    if (num == AgainCount)
                    {
                        MessageBox.Show(" 升级等待超时3 ");
                        return;
                    }
                }
            }

            //5.升级完成
            if (UpdataFlag == 1)
            {
                num = 1;
                while (num <= AgainCount)
                {
                    Delay(100);
                    Data[0] = 0xDD;
                    Data[1] = 0x00;
                    Data[2] = 0x00;
                    Data[3] = 0x0B;
                    Data[4] = 0x00;
                    Data[5] = 0x00;
                    crc = CalculateCrc16(Data, 6);
                    Data[6] = Convert.ToByte(crc >> 8);
                    Data[7] = Convert.ToByte(crc & 0xFF);
                    serialPort.Write(Data, 0, 8);

                    Delay(100);
                    num++;
                    if (Cmdata[2] == 0xBB)
                    {
                        Cmdata[2] = 0x00;
                        Calculagraph.Stop();
                        RecState.Text = "升级成功";
                        break;
                    }
                    if (num == AgainCount)
                    {
                        MessageBox.Show(" 升级等待超时4 ");
                        return;
                    }
                }
            }

        }

下面视频介绍上位机如何生成一个单独应用程序

 

声明:本内容为作者独立观点,不代表电子星球立场。未经允许不得转载。授权事宜与稿件投诉,请联系:editor@netbroad.com
本篇所含全部资料,点击此处留下邮箱我会发给你
资料明细:上位机安装包
觉得内容不错的朋友,别忘了一键三连哦!
赞 3
收藏 4
关注 120
成为作者 赚取收益
全部留言
0/200
  • zhoucwyh 2025-09-29 19:50
    老师,能不能发我一下资料,谢谢! zh****@****.com
    回复 1条回复