Stm32通过串口 Ymodem 协议接收文件

17 篇文章 0 订阅
8 篇文章 0 订阅

我自己做了一个 针对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<len;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 oc\r\n");
					//cb(recbuf,eYmFileEnd0);					//文件结束
					SendYModemData(eYmACK);
					break;
				}
				else if(recbuf[0]==eYmEOT )
				{
					if(cntEot==0)	
					{
						SendYModemData(eYmNAK);
						printf("rec eot 1\r\n");
						++cntEot;
					}
					else
					{
						cb(recbuf,eYmFileEnd1);					//文件结束
						printf("rec eot 1\r\n");
						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);
}

 

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值