STM32
直播中

HCPcry

8年用户 1190经验值
擅长:处理器/DSP
私信 关注
[问答]

请问Stm32如何通过串口Ymodem协议接收文件?

请问STM32如何通过串口Ymodem协议接收文件?

回帖(1)

陆欣楠

2021-12-8 09:28:29
我自己做了一个 针对stm32的isp 离线编程器,
  设计时候 采用了 W25Q64 作为要烧录文件的存储,
  直接使用 Ymodem 协议,将文件下载到 flash中,免得再写一个上位机软件,
  在ucos2的加持下,整个代码的逻辑比较简单易懂
  Ymodem 协议 参考 https://www.cnblogs.com/dwj411024/p/7717084.html
  
  

  

   

贴上我的代码


头文件:


#ifndef __Y_MODEM_H__
#define __Y_MODEM_H__
enum{
        eYmSOH=0x01,
        eYmSTX=0x02,
        eYmEOT=0x04,
        eYmACK=0x06,
        eYmNAK=0x15,
        eYmCANCEL=0x18,
        eYmC=0x43,
};

enum{
        eYmFileBegin,
        eYmFileData,
        eYmFileEnd0,
        eYmFileEnd1,
};

typedef  unsigned char (*pYmdCb)(unsigned char *pdata,unsigned char state);
unsigned char RecYModem(pYmdCb cb,unsigned char *recbuf);
#endif

代码:


#include "includes.h"
/*******************************************************************************************
   符号         数值         含义
SOH        0x01         128字节数据帧,协议类型
STX        0x02         1024字节数据帧,协议类型
EOT        0x04         结束传输,发送者发送
ACK        0x06         接收者处理成功回应,发送者发现下一包数据(1024或者128)
NAK        0x15         接收者处理失败回应,发送者需要重发此1024或者128数据,或者接收到第一个EOT的回复包
CA                0x18         传输中止
C                 0x43         接收者准备接收时会发连续的C,发送者接收到C开始发送
**********************************************************************************************************************/

//这两个代码要重写,放到应用端
extern unsigned char RecYModemData(unsigned char *timeout);
extern void SendYModemData(unsigned char data);

/*---- Y _   M O D E M _   C   R   C ----
【功能】:crc校验
【参数】:
****
【返回】:****
【说明】:****
--------------作者:卢杰西   2020年12月1日17:15:24--------------------------------*/
unsigned short int Y_Modem_CRC(unsigned char * buf, unsigned short int len)
{
    unsigned short int chsum;
    unsigned short int stat;
    unsigned short int i;
    unsigned char * in_ptr;
    //指向要计算CRC的缓冲区开头
    in_ptr = buf;
    chsum = 0;
    for (stat = len ; stat > 0; stat--) //len是所要计算的长度
    {
        chsum = chsum^(unsigned short int)(*in_ptr++) << 8;
        for (i=8; i!=0; i--) {
            if (chsum & 0x8000){
                chsum = chsum << 1 ^ 0x1021;
            } else {
                chsum = chsum << 1;
            }
        }
    }
    return chsum;
}

/*---- R E C   Y M   P A C K E T ----
【功能】:接收一个包
【参数】:****
【返回】:****
【说明】:****
--------------作者:卢杰西   2020年12月1日17:15:39--------------------------------*/
signed char RecYmPacket(unsigned char *pdata)
{
        unsigned char err;
        unsigned short int cnt,len,crcrec,crc;
        pdata[0]=RecYModemData(&err);
        if(err==OS_TIMEOUT)                                return -1;
        if(pdata[0]==eYmEOT)                        return 0;
        pdata[1]=RecYModemData(&err);
        if(err==OS_TIMEOUT)                                return -1;
        pdata[2]=RecYModemData(&err);
        if(err==OS_TIMEOUT)                                return -1;
        if((pdata[1]^pdata[2])!=0xff)        return -2;
        if(pdata[0]==eYmSOH)  
                len=128;
        else                                       
                len=1024;
        for (cnt=0;cnt         {
                pdata[3+cnt]=RecYModemData(&err);
                if(err==OS_TIMEOUT)
                {
                        return -1;
                }
        }
        crcrec=RecYModemData(&err)<<8;
        if(err==OS_TIMEOUT)                                return -1;
        crcrec|=RecYModemData(&err);
        if(err==OS_TIMEOUT)                                return -1;
        crc=Y_Modem_CRC(pdata+3,len);
        if(crc!=crcrec)               
        {
                if(pdata[0]!=eYmSOH)                return -3;
                else                                                return -4;
        }
        return 0;
}


/*---- R E C   Y   M O D E M ----
【功能】:Ymodem的协议流程,
【参数】:
****
【返回】:****
【说明】:每接收到一个包 回调 cb  进行接收处理
--------------作者:卢杰西   2020年12月1日17:16:27--------------------------------*/
unsigned char RecYModem(pYmdCb cb,unsigned char *recbuf)
{
        unsigned char cntEot=0,cnt,errcnt=0;
        signed char ret;
        do{
                SendYModemData(eYmC);
                ret=RecYmPacket(recbuf);
                if(ret==0 && recbuf[0]==eYmSOH)
                {
                        cb(recbuf,eYmFileBegin);                                        //文件初始化
                        break;
                }
                else
                {
                        OSTimeDly(OS_TICKS_PER_SEC);        //接收 启动 失败
                }
        }while(++errcnt<100);
        if(errcnt<100)
        {
                SendYModemData(eYmACK);
                SendYModemData(eYmC);
                do{
                        ret=RecYmPacket(recbuf);
                        if(ret==0 || ret==-4)
                        {
                                errcnt=0;
                                if( (recbuf[0]==eYmSOH && cntEot<2) ||recbuf[0]==eYmSTX )
                                {
                                        cntEot=0;
                                        cb(recbuf,eYmFileData);                                        //文件下载中
                                        SendYModemData(eYmACK);
                                }
                                else if(recbuf[0]==eYmSOH && cntEot==2)
                                {
                                        printf("rec ocrn");
                                        //cb(recbuf,eYmFileEnd0);                                        //文件结束
                                        SendYModemData(eYmACK);
                                        break;
                                }
                                else if(recbuf[0]==eYmEOT )
                                {
                                        if(cntEot==0)       
                                        {
                                                SendYModemData(eYmNAK);
                                                printf("rec eot 1rn");
                                                ++cntEot;
                                        }
                                        else
                                        {
                                                cb(recbuf,eYmFileEnd1);                                        //文件结束
                                                printf("rec eot 1rn");
                                                SendYModemData(eYmACK);
                                                SendYModemData(eYmC);
                                                break;
                                        }
                                }
                        }
                        else
                        {
                                SendYModemData(eYmNAK);
                        }
                }while(++errcnt<100);
        }
        if(errcnt>=100)
        {
                //终止传输
                for(cnt=0;cnt<10;cnt++)
                        SendYModemData(eYmCANCEL);
        }
        return (errcnt<100);
}


串口接口的代码:


OS_EVENT *OSQModemRec;
unsigned char RecYModemData(unsigned char *timeout)
{
        unsigned char rec;
        rec=(INT32U)OSQPend(OSQModemRec,OS_TICKS_PER_SEC,timeout);
        return rec;
}

void SendYModemData(unsigned char ch)
{
        USART_SendData(USART2, ch);
        while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET) OSTimeDly(1);
}
举报

更多回帖

发帖
×
20
完善资料,
赚取积分