【MPC5744P】Bootloader上位机开发(CAN通讯)

上位机源码范例直接下载:https://download.csdn.net/download/u010875635/10882176

此处上位机采用C#编写,界面框架为WPF。

为保证烧录过程不出现错误,上下位机采用一问一答模式,上位机发送一帧数据后,下位机接收处理完毕再回馈给上位机,上位机再决定下一步动作。

核心代码逻辑部分,将命令分成EntryBootloader, Reset, Data, DataEnd, CheckBootloader, Erase, ERR几个部分。

烧录时会先检查是否处于Bootloader,,然后执行擦写操作(擦写地址范围由上位机发送),再发送数据(地址+数据为一帧),最后发送结束命令。

注意,由于CAN长度为8字节,而32位地址已经占用4字节,Flash地址从0x800000开始,所以所有地址减去0x800000,3字节即可,首字节作为数据类型。

示例代码中,无论是进入用户App还是Bootloader都会通过CAN回复当前状态,Bootloader中蓝色LED低频1s闪烁,烧录时红色LED快速闪烁,用户App中彩灯闪烁,Bootloader中4s未接收到命令会进入用户App中,若监测不到用户App存在,会再次复位到Bootloader中。

注意,本实例中使用的是周立功的USBCAN,理论上支持所有致远的CAN设备,实际试验的是USBCAN-E-mini,若是有其它的CAN设备,更换底层的CAN驱动代码即可,程序没有直接调用ZlgCAN,有中转类,方便替换(主要是初始化函数、波特率设置、发送、接收函数等)。

 

 

#region 连接断开

/// 
/// 连接CAN
/// 
bool Connect()
{
    if (m_BOpen)
        return true;

    MotorControl1CmdForDevelop.Scm_DevelopCanConfig scm_DevCanConfig = new MotorControl1CmdForDevelop.Scm_DevelopCanConfig();
    scm_DevCanConfig.canType = (CANDevices.ZlgCAN.ZlgCanType)Enum.Parse(typeof(CANDevices.ZlgCAN.ZlgCanType), cbCanType.SelectedItem.ToString());
    scm_DevCanConfig.devIndex = (uint)cbDeviceIndex.SelectedIndex;
    scm_DevCanConfig.canIndexs = m_CanIndexs;
    scm_DevCanConfig.baudrates = m_Baudrates;
    scm_DevCanConfig.idList = null;
    scm_DevCanConfig.sheildRule = new bool[] { false };
    MotorControl1CmdForDevelop.Ecm_CanInitialErrorTypes result = m_Mtcl1DevelopCmd.Connect(scm_DevCanConfig);//设置参数

    if (result != MotorControl1CmdForDevelop.Ecm_CanInitialErrorTypes.OK)
    {
        return false;
    }

    m_BOpen = true;
    Connect_UIChange(true);
    return true;

}

/// 
/// 断开CAN
/// 
bool DisConnect()
{
    if (!m_BOpen)
        return true;

    if (!m_Mtcl1DevelopCmd.DisConnect())
        return false;

    m_BOpen = false;
    Connect_UIChange(false);
    return true;
}

/// 
/// 连接串口
/// 
private void btnConnectCan_Click(object sender, RoutedEventArgs e)
{
    if (m_BOpen)
    {
        if (!DisConnect())
        {
            Controls.Windows.UserMessageBox userMsg = new Windows.UserMessageBox(m_WinLocation, m_WinSize, "CAN异常", "关闭失败!");
            userMsg.ShowDialog();
        }
    }
    else
    {
        if (!Connect())
        {
            Controls.Windows.UserMessageBox userMsg = new Windows.UserMessageBox(m_WinLocation, m_WinSize, "CAN异常", "打开失败!");
            userMsg.ShowDialog();
        }
    }


}

#endregion

#region 数据收发



#region 发送数据
/// 
/// 开始烧录
/// 
private void btnStartBurn_Click(object sender, RoutedEventArgs e)
{
    BurnHex();
}

Thread m_SendThread;
/// 
/// 开始烧录、停止烧录
/// 
private void BurnHex()
{
    if (m_IsBurnning)
    {
        m_AutoSendTimer.Stop();

        m_IsBurnning = false;
        RunBurn_UIChange(m_IsBurnning);
        if (m_SendThread != null)
            m_SendThread.Abort();
    }
    else
    {
        m_SendThread = new Thread(() =>
        {
            DateTime startTime;

            m_InBootloader = m_McuFlashIsErased = false;

                
            //检查是否处于Bootloader中
            TextBlockAddMsg("检查是否处于Bootloader中", System.Windows.Media.Brushes.Black);
            m_Mtcl1DevelopCmd.SendNormalBytes(0, m_CanDataParse.g_CheckBootloaderCmd);
            startTime = DateTime.Now; //开始计时
            while (!m_InBootloader)
            {
                uint count = 0;
                while (count < 100000)
                    count++;
                if (DateTime.Now.Subtract(startTime).TotalSeconds > 5) //是否超过5s没有接收到
                    break;
            }

            if (!m_InBootloader)
            {
                TextBlockAddMsg("请先进入bootloader模式", System.Windows.Media.Brushes.Red, 1);
                return;
            }
            TextBlockAddMsg("已处于Bootloader中!", System.Windows.Media.Brushes.Blue);

            TextBlockAddMsg("检查是否已擦除Flash", System.Windows.Media.Brushes.Black);
            m_Mtcl1DevelopCmd.SendNormalBytes(0, m_CanDataParse.CanErasePackage(m_AllAddrData.AddrDataCollection[0].RealAddr, m_AllAddrData.AddrDataCollection[m_AllAddrData.AddrDataCollection.Count-1].RealAddr));

            startTime = DateTime.Now; //开始计时
            while (!m_McuFlashIsErased)
            {
                uint count = 0;
                while (count < 100000)
                    count++;
                if (DateTime.Now.Subtract(startTime).TotalSeconds > 10) //是否超过10s没有接收到
                    break;
            }
            if (!m_McuFlashIsErased)
            {
                TextBlockAddMsg("擦除超时", System.Windows.Media.Brushes.Red, 1);
                return;
            }
            string ts = DateTime.Now.Subtract(startTime).TotalSeconds.ToString();
            TextBlockAddMsg("擦除完毕!,总耗时:"+ts+"s", System.Windows.Media.Brushes.Blue);

            TextBlockAddMsg("开始发送数据,总指令数: "+m_AllAddrData.AddrDataCollection.Count.ToString() , System.Windows.Media.Brushes.Black);
                    
                
            SendData(); //发送数据

        });
        m_SendThread.Start();
        //m_AutoSendTimer.Start();

        m_IsBurnning = true;
        RunBurn_UIChange(m_IsBurnning);
    }

            
}

/// 
/// 发送等待接收
/// 
/// 
/// 发送数据
/// 
private void SendData()
{

    m_SendDataCount = 0;
    m_ReceiveDataCount = 0;
    DateTime dataSartTime = DateTime.Now; //开始计时
            
    while (m_SendDataCount < m_AllAddrData.AddrDataCollection.Count)
    {
        //m_SendHasReponse = false;
        byte[] data = m_CanDataParse.CanDataPackage(m_AllAddrData.AddrDataCollection[m_SendDataCount]); //地址会减去0x800000

        //TextBlockAddMsg("SendData:" + BitConverter.ToString(data), System.Windows.Media.Brushes.DarkOrange);
        TextBlockChangeMsg("发送进度", "已发送指令: " + (m_SendDataCount+1).ToString() + " ", System.Windows.Media.Brushes.Gray);

        m_Mtcl1DevelopCmd.SendNormalBytes(0, data); //实际发送
                
        //m_CanDataParse.UserFlash_DataParseAddrData(data, (byte)data.Length); //测试

        m_SendDataCount++;
        double percent = m_SendDataCount * 1.0 / m_AllAddrData.AddrDataCollection.Count * 100;
        ProcessUpdate(percent);
        SendDataCheck_Wait(ref m_SendDataCount, ref m_ReceiveDataCount, 100);

        int tryAgainCount = 0;
        while (m_SendDataCount != m_ReceiveDataCount && tryAgainCount<3) //未发送成功,尝试3次
        {
            m_Mtcl1DevelopCmd.SendNormalBytes(0, data); //再次发送
            SendDataCheck_Wait(ref m_SendDataCount, ref m_ReceiveDataCount, 100);
            tryAgainCount++;
        }

        if (m_SendDataCount != m_ReceiveDataCount) //发送中断
        {
            TextBlockAddMsg("发送中断: ", System.Windows.Media.Brushes.Red);
            return;
        }

    }
    SendDataCheck_Wait(ref m_SendDataCount, ref m_ReceiveDataCount, 300);

    //发送完毕,停止发送

    TimeSpan ts = DateTime.Now.Subtract(dataSartTime);

    TextBlockAddMsg("发送数据结束,耗时: " + ts.TotalSeconds.ToString() + "s", System.Windows.Media.Brushes.Black);
                
    m_Mtcl1DevelopCmd.SendNormalBytes(0, m_CanDataParse.g_DataEndCmd); //数据结束命令
    m_SendDataCount++;
    SendDataCheck_Wait(ref m_SendDataCount, ref m_ReceiveDataCount, 300);
    BurnHex();
    //m_CanDataParse.UserFlash_EndCheck(); //测试
            


}

#endregion

#region 接收数据

/// 
/// 接收数据,回调函数
/// 
private void ReceiveData(uint canIndex, byte[] datas)
{
            
    //判断回馈类型
    ClassBootloaderForCAN.CmdType cmdType = m_CanDataParse.ReceiveDataParse(ref datas);
    //TextBlockAddMsg("ReceiveData:"+BitConverter.ToString(datas), System.Windows.Media.Brushes.DarkOrange);
    switch (cmdType)
    {
        case ClassBootloaderForCAN.CmdType.EntryBootloader:
            m_InBootloader = true;
            BootloaderIndicator(true);
            TextBlockAddMsg("成功进入Bootloader,"+ datas[1].ToString()+"s内无操作进入用户程序!", System.Windows.Media.Brushes.Blue);
            break;
                
        case ClassBootloaderForCAN.CmdType.Reset:
            m_InBootloader = false;
            BootloaderIndicator(false);
            TextBlockAddMsg("进入用户程序!", System.Windows.Media.Brushes.Blue);
            break;
        case ClassBootloaderForCAN.CmdType.Data:
            m_ReceiveDataCount++;
            //m_SendHasReponse = true;
            TextBlockChangeMsg("刷写进度","已刷写指令: "+m_ReceiveDataCount.ToString()+" " , System.Windows.Media.Brushes.Gray);
            break;
        case ClassBootloaderForCAN.CmdType.DataEnd:
            //m_SendHasReponse = true;
            m_ReceiveDataCount++;
            TextBlockAddMsg("用户程序刷新完毕!", System.Windows.Media.Brushes.Blue);
                                       
            break;
        case ClassBootloaderForCAN.CmdType.CheckBootloader:
            m_InBootloader = true;
            break;
        case ClassBootloaderForCAN.CmdType.Earse:
                    
            m_McuFlashIsErased = true;
                    
            break;
        case ClassBootloaderForCAN.CmdType.Other:
            TextBlockAddMsg("Receive Other: " + BitConverter.ToString(datas), System.Windows.Media.Brushes.DarkOrange);
            break;
        default: break;
    }
}

#endregion

 

你可能感兴趣的:(MCU,NXP,MPC574X开发)