×
单片机 > 单片机程序设计 > 详情

C语言PIC18 serial bootloader和C#语言bootloader PC端串口通信程序

发布时间:2020-06-06 发布时间:
|

  新PIC18 Bootloader


  PhsBoot_v3.0是我最新用C语言实现的PIC bootloader, 采用串口通信,适用于PIC18, 并为其用C#写了PC端通信程序PhsLoader_v3.0。PhsLoader_v3.0通过串口按照自定义的通信协定发送数据PhsBoot_v3.0, PhsBoot_v3.0接收数据,按照通信协定解读数据,解读出其中Hex数据,并将其烧录到正确的位置。


  通信协定


  PIC18单片机端PhsBoot_v3.0和PC端PhsLoader_v3.0之间的通信数据包采用以下协定


...


  定义如下:


STX - Start of packet indicator

ETX - End of packet indicator

LEN - The length of true data

DATA - General data 16 bytes, only first LEN of datas are true

CMD - Base command

ADDR - Address up to 24 bits  ( ADDRL , ADDRH , ADDRH)


  具体有以下Base command:


RD-VER:  0x00 -- Read Version Information (最终版本删除了此命令)

RD_MEM: 0x01 -- Read Program Memory (最终版本删除了此命令)

ER_MEM: 0x03 -- Erase Program Memory

WR_MEM: 0x02 -- Write Program Memory 

WR_CFG: 0x04 -- Write Configuration Registers


  PhsLoader_v3.0 功能


  定义好了通讯协定, 接着就按照协定去实现PhsLoader_v3.0。 PhsLoader_v3.0的具体功能包括选择COM端口和BAUD RATE, 连接COM, 加载应用程序Hex文件,Parse 应用程序的Hex文件,一行一行解读Hex文件,然后按照通讯协定通过串口发送Hex记录到单片机,接收单片机发送回来的Response,发送完毕后断开COM连接,发送期间出现问题就立马结束发送。


  PhsLoader_v3.0 主要代码段


  PhsLoader_v3.0是用C#实现的,是我在利用空余时间自学C#后写的,上面提到的功能都实现了。




        private void btnDownload_Click(object sender, EventArgs e)

        {

            btnDownload.Enabled = false;

            pBarLoading.Visible = false;


            if (!this.connect())

            {

                btnDownload.Enabled = true;

                return;

            }


            try

            {

                loaderReader = new StreamReader(textBoxFile.Text);


            }

            catch (Exception ex)

            {

                Debug.WriteLine("Error: " + ex.Message);

                textBoxStatus.ForeColor = Color.Red;

                textBoxStatus.AppendText("Read hex file unsuccessfully\r\n");

                textBoxStatus.ForeColor = Color.Black;

                loaderReader.Close();

                loaderSerial.Close();

                btnDownload.Enabled = true;

                return;

            }


            loaderFrame = new SerialFrame();

            if (!erase())

            {

                textBoxStatus.ForeColor = Color.Red;

                textBoxStatus.AppendText("Erase unsuccessfully\r\n");

                textBoxStatus.ForeColor = Color.Black;

                loaderReader.Close();

                loaderSerial.Close();

                btnDownload.Enabled = true;

                return;

            }


            pBarLoading.Refresh();

            pBarLoading.Visible = true;

            pBarLoading.Value = 0;

            pBarLoading.Maximum = loaderLines;

            pBarLoading.Step = 1;


            string recordLine;

            Address_U = 0;

            bool isNextLineUserID = false;

            bool isNextLineConfigBits = false;

            textBoxStatus.AppendText("\r\nDownloading hex file ...\r\n");

            try

            {

                while (loaderReader.Peek() >= 0)

                {

                    pBarLoading.PerformStep();

                    recordLine = loaderReader.ReadLine();

                    //if (recordLine.Contains(USER_ID_TOKEN) == true)

                    //{

                    //    isNextLineUserID = true;

                    //    continue;

                    //}

                    //else if (recordLine.Contains(CONFIG_BITS_TOKEN) == true)

                    //{

                    //    isNextLineConfigBits = true;

                    //    continue;

                    //}

                    if (recordLine.Contains(EXTEND_TOKEN) == true)

                    {

                        if (recordLine.Contains(USER_ID_TOKEN) == true)

                        {

                            isNextLineUserID = true;

                            continue;

                        }

                        else if (recordLine.Contains(CONFIG_BITS_TOKEN) == true)

                        {

                            isNextLineConfigBits = true;

                            continue;

                        }

                        else

                        {

                            const int ADDR_U_START_INDEX = 9;

                            const int ADDR_U_LENGTH = 4;

                            string addrU = recordLine.Substring(ADDR_U_START_INDEX, ADDR_U_LENGTH);

                            Address_U = Convert.ToInt32(addrU, 16) << 16;

                            continue;

                        }

                    }

                    else if (recordLine.Contains(END_OF_HEX_FILE_TOKEN) == true)

                    {

                        break;

                    }

                    if (isNextLineUserID)

                    {

                        isNextLineUserID = false;

                        // do nothing;

                    }

                    else if (isNextLineConfigBits)

                    {

                        if (!DownloadConfigLine(recordLine))

                        {

                            Debug.WriteLine("Error found during configuration bits programming");

                            loaderReader.Close();

                            loaderSerial.Close();

                            btnDownload.Enabled = true;

                            return;

                        }

                        isNextLineConfigBits = false;

                    }

                    else

                    {

                        //if (recordLine.Contains(J_TYPE_CONFIG_BITS_TOKEN) == true && Address_U == 0x10000)

                        //{

                        //    continue;

                        //}

                        /*else*/ 

                        if (!DownloadDataLine(recordLine))

                        {

                            Debug.WriteLine("Error found during data programming");

                            loaderReader.Close();

                            loaderSerial.Close();

                            btnDownload.Enabled = true;

                            return;

                        }

                    }

                }

            }

            catch (Exception ex)

            {

                Debug.WriteLine("Error: " + ex.Message);

                textBoxStatus.ForeColor = Color.Red;

                textBoxStatus.AppendText("Downloading failed\r\n");

                textBoxStatus.ForeColor = Color.Black;

                loaderSerial.Close();

                loaderReader.Close();

                btnDownload.Enabled = true;

                return;

            }

            textBoxStatus.AppendText("Downloading completed\r\n");


            if (!run())

            {

                textBoxStatus.ForeColor = Color.Red;

                textBoxStatus.AppendText("Jump to Application unsuccessfully\r\n");

                textBoxStatus.ForeColor = Color.Black;

                loaderReader.Close();

                loaderSerial.Close();

                btnDownload.Enabled = true;

                return;

            }

            loaderSerial.Close();

            loaderReader.Close();

            btnDownload.Enabled = true;

        }


  PhsLoader_v3.0 用户界面


  


  PhsBoot_v3.0 功能


  在PhsLoader_v3.0完成后,接着就是完成PhsBoot_v3.0。 PhsBoot_v3.0主要功能就是接收PhsLoader_v3.0传送过来的Hex记录。解读Hex记录中的启始位,命名,地址,数据和结束位,将数据烧录到指定的程序存储器的位置上,然后通过串口返回Response消息给PC端PhsLoader_v3.0。


  PhsBoot_v3.0 位置


  PhsBoot_v3.0放置在程序存储器的头部,大小为0x400程序字。


  


  Interrupt Vector Remap


  由于新PIC18 bootloader 位于程序存储器的头部,需要对Interrupt Vector进行remap. 代码如下。


    #asm

        PSECT intcode

        goto APP_START + 0x8

        PSECT intcodelo

        goto APP_START + 0x18

    #endasm

  PhsBoot_v3.0 主要代码段


  PhsBoot_v3.0 是用C语言写的,Microchip 8-bit C Compiler--XC8编译的。



    while (1)

    {

        if (PIR1bits.RCIF == 1)

        {

            RecivedByte = RCREG;

            PIR1bits.RCIF == 0;

            m_buffer[m_buffer_Index++] = RecivedByte; //receive data

            if (m_buffer_Index >= BUFFER_MAX)

            {

                if (m_buffer[0] == STX && RecivedByte == ETX)

                { //get complete cmd

                    switch (m_buffer[CMD_INDEX])

                    {

                    case WR_MEM:

                        EECON1 = PGM_WRITE;

                        WriteMem();

                        break;

                    case WR_CFG:

                        if (block_Start)

                        {

                            WriteStart();

                            resetBuffer();

                            block_Start = 0;

                        }

                        EECON1 = CFG_WRITE;

                        WriteCfg();

                        break;

                    case ER_MEM:

                        EECON1 = PGM_ERASE;

                        EraseMem();

                        break;

                    case RUN_APP:

                        if (block_Start)

                        {

                            WriteStart();

                            resetBuffer();

                            block_Start = 0;

                        }

                        sendResponse();

                        TXSTA = 0x02;           

                        RCSTA = 0x00;

                        asm("goto " ___mkstr(APP_START));

                    default:

                        break;

                    }

                }

                else

                { //Send data error back

                    TXREG = '?';

                    while (TXSTAbits.TRMT == 0); //wait empty

                }

                m_buffer_Index=0;

            }

        }

    }


  如何使用 


  1. 使用XC8编译PhsBoot_v3.0。


  2. 使用pickit3烧录PhsBoot_v3.0的Hex文件到目标板中。


  3. 拔除pickit3烧录器


  4. 连接目标板与PC的串口,打开PhsLoader_v3.0用户界面,选择COM端口,BAUD RATE。


  5. 点击PhsLoader_v3.0用户界面上的“.."按钮加载需要烧录的应用程序Hex文件 (注意:由于新PIC18 bootloader占用了程序存储器头部0x400程序字,所以应用程序编译需要设置Code offset为0x400)。


  6. 重启目标板,接着立刻在PhsLoader_v3.0界面上点击Download按钮。如果超时未点击Download按钮,目标板会自动跳转到上次烧录的应用程序中去。


  7. 烧录完毕,再次重启目标板, 2秒后目标板开始正常运行应用程序。


  之后每次更新应用程序,只需重复步骤 4 ~ 7 就可以了。


  主要特性


  新的PIC18 serial bootloader有以下主要特性


  1. C语言写的,XC8 编译。


  2. 非常容易移植。


  3. 支持FLASH烧写, 快速,占用空间小。


  4. 可支持EEPROM烧写。


  5. 支持CONFIG BITS/IDLOC 烧写。



『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
单片机中高阻态的实质及意义