找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 7890|回复: 4
收起左侧

51单片机xmodem协议程序—接收部分的代码及rs232.h头文件

[复制链接]
ID:75263 发表于 2015-3-25 00:12 | 显示全部楼层 |阅读模式
本帖最后由 niuniu 于 2015-3-25 00:13 编辑

#include "..\include\AT89X52.H"
#include "..\include\rs232.h"

uchar RS232_Rec;
static bit RS232_Rec_flag=0;
static bit RS232_Trn_flag=1;
//----------------------------------------------------------
// 函数名称 RS232_Init()
// 函数功能 串口初始化,设置默认通信速率为9600bps
//          单片机主振频率11.0592MHz,主频为其它值时
//          通信速率按比例变化。
// 入口参数:无
// 函数返回:无
// 函数引用:无
// 变量引用:无
// 变量修改:TMOD:设置T1为串口波特率发生器
//          TH1,TL1:设置波特率为9600bps(以11.0592MHz晶体为基准)
//          TR1,RI,TI:启动T2,清除TI、RI标志
//          REN,SM0,SM1:使能串口接收,1位起始8位数据1位停止模式
//          ES,EA:使能串口中断,使能总中断
//          RS232_Trn_flag:设置发送完成标志
// 函数作者:周大苟
// 创建时间:10/01/2009
// 修改历程:10/01/2009:创建本函数
//          10/29/2009:格式规范
//----------------------------------------------------------
void RS232_Init(void)
{
    uchar i;
    RS232_Trn_flag = 1;
    TMOD &= 0x0f;
    TMOD |= 0x20;
    TH1   = 0xfd;
    TL1   = 0xfd;
    TR1   = 1;
    REN   = 1;
    SM0   = 0;
    SM1   = 1;
    RI    = 0;
    TI    = 0;
    EA    = 1;
    ES    = 1;
}
//----------------------------------------------------------
// 函数名称:RS232_ISR()
// 函数功能:串口中断服务函数
// 入口参数:无
// 函数返回:无
// 函数引用:无
// 变量引用:RI:串口接收标志
//          SBUF:串口接收缓冲寄存器
// 变量修改:RI,TI:清除TI、RI标志
//          RS232_Rec:接收串口收到的字节
//          RS232_Rec_flag:设置成功接收标志
//          RS232_Trn_flag:设置发送完成标志
// 函数作者:周大苟
// 创建时间:10/01/2009
// 修改历程:10/01/2009:创建本函数
//          10/29/2009:格式规范
//----------------------------------------------------------
void RS232_ISR(void) interrupt 4
{
    if(RI)
    {
        RS232_Rec  = SBUF;
        RS232_Rec_flag = 1;
    }
    else RS232_Trn_flag = 1;
    RI = 0;
    TI = 0;
}
//----------------------------------------------------------
// 函数名称:RS232_Tran_Chr(...)
// 函数功能:串口单个字符发送函数
// 入口参数:chr:待发送的字符
// 函数返回:无
// 函数引用:无
// 变量引用:RS232_Trn_flag,自定义串口发送成功标志
// 变量修改:
//          SBUF:赋值串口发送缓冲寄存器
//          RS232_Trn_flag:清除自定义串口发送成功标志
// 函数作者:周大苟
// 创建时间:10/01/2009
// 修改历程:10/01/2009:创建本函数
//          10/29/2009:格式规范,解决发送偶尔死循环不返回问题
//----------------------------------------------------------
void RS232_Tran_Chr(uchar chr)
{
    uint tryit = 5000;
    while((!RS232_Trn_flag) && (tryit--)) ;
    RS232_Trn_flag = 0;
    SBUF = chr;
}
//----------------------------------------------------------
// 函数名称:RS232_Rec_Xmodem()
// 函数功能:Xmodem协议接收部分,128字节缓冲区
// 入口参数:无
// 函数返回:无
// 函数引用:RS232_Tran_Chr(...)
// 变量引用:RS232_Rec_flag:串口收到字符的标志
//          RS232_Rec:串口收到的字符
//          Xmodem_Buffer[]:Xmodem接收缓冲区
//          Xmodem_Buffer_Ptr:Xmodem缓冲区指针
// 变量修改:RS232_Rec_flag:串口收到字符的标志
//          Xmodem_Buffer_Ptr:Xmodem缓冲区指针
//          Xmodem_Buffer[]:环形缓冲区
// 函数作者:周大苟
// 创建时间:10/01/2009
// 修改历程:10/01/2009:创建本函数
//          10/29/2009:格式规范

//          11/09/2009:修改原因:在包头部分发现错误,不应该立即发NAK,而是应该等这个包收完了再发NAK
//                               即将修改:接收过程中应做延时检查,防止断线进入死循环。
//----------------------------------------------------------
// #define SOH             0x01
// #define STX             0x02
// #define EOT             0x04
// #define ACK             0x06
// #define NAK             0x15
// #define CAN             0x18
// #define CTRLZ           0x1A
//enum TXmoden_STate {IDLE, WSTART, START, SEQ, CSEQ, DATA, DEND};
enum TXmoden_STate Xmoden_STate = IDLE;
xdata uchar Xmodem_Buffer[128];
uchar Xmodem_Buffer_Ptr=0;
uchar ChkSum=0;
uchar PSer=1, PT=0;
uchar xerror;
void RS232_Rec_Xmodem(void)
{
    if(Xmoden_STate == IDLE) return;
    if(RS232_Rec_flag)
    {
        switch(Xmoden_STate)
        {
            case WSTART:      //当前正等待接收主机发送起始符号SOH
                if(RS232_Rec == SOH)      //收到主机发送的SOH符号
                {
                    Xmoden_STate = START; //进入"SOH已经收到"状态
                    xerror=0;
                }
                else
                if(RS232_Rec == EOT)      //收到主机发送的EOT符号
                {
                    RS232_Tran_Chr(ACK);
                    Xmoden_STate = IDLE;         //进入"空闲"状态
                }
                break;
            case START://SOH已经收到,当前正等待接收期望的包序列号
                Xmoden_STate = SEQ;    //进入"序列号已经收到"状态
                if(RS232_Rec != PSer)        //不是期望的包序列号
                    xerror=1;                      //设置出错标志
                break;
            case SEQ:       //包号已经收到,当前正等待接收包号补码
                Xmoden_STate = CSEQ;     //进入"包号补码已收"状态
                if(RS232_Rec != (0xff-PSer)) //不是期望的包号补码
                    xerror=1;                      //设置出错标志
                break;
            case CSEQ:      //包号补码已经收到,当前正等待接收数据
                Xmodem_Buffer[0] = RS232_Rec;
                ChkSum = RS232_Rec;
                Xmodem_Buffer_Ptr = 1;
                Xmoden_STate = DATA;
                break;
            case DATA:                       //当前正等待接收数据
                if(Xmodem_Buffer_Ptr<128)
                {
                    Xmodem_Buffer[Xmodem_Buffer_Ptr++] = RS232_Rec;
                    ChkSum += RS232_Rec;
                    if(Xmodem_Buffer_Ptr==128)
                    Xmoden_STate = DEND;
                }
                break;
            case DEND:      //数据包接收结束,当前正等待接收校验和
                if((ChkSum == RS232_Rec)&&(xerror==0))
                {
                    KS108_Disp_uint_Dec(0,0,PSer,0);
                    Flash_Write(((ulong)(PSer-1+(PT<<8))<<7), Xmodem_Buffer, 128);
                    PSer++;
                    if(PSer==0) PT++;
                    RS232_Tran_Chr(ACK);         //给主机正确应答
                    Xmoden_STate = WSTART;
                }
                else
                {
                    RS232_Tran_Chr(NAK);    //要求主机重发SOH符号
                    Xmoden_STate = WSTART;//回到"等待接收SOH"状态
                }
                break;
            default:break;
        }
        RS232_Rec_flag = 0;
    }
}
//本函数的调用方式如下:
//  Xmoden_STate = WSTART;
//  RS232_Tran_Chr(NAK);
//  while(Xmoden_STate != IDLE) RS232_Rec_Xmodem();

//需要进一步完善/优化。已经成功用于PC--->51单片机管理下的2M字节串行Flash芯片AT45DB161D下载16点阵汉字库。
//每个包都人为设置多个错误,测试通过

回复

使用道具 举报

ID:75263 发表于 2015-3-25 00:13 | 显示全部楼层
下面是头文件rs232.h的内容:
  1. #ifndef __RS232_H__
  2. #define __RS232_H__

  3. #define uchar unsigned char
  4. #define uint  unsigned int
  5. #define ulong unsigned long

  6. #define SOH             0x01
  7. #define STX             0x02
  8. #define EOT             0x04
  9. #define ACK             0x06
  10. #define NAK             0x15
  11. #define CAN             0x18
  12. #define CTRLZ           0x1A
  13. enum TXmoden_STate {IDLE, WSTART, START, SEQ, CSEQ, DATA, DEND};

  14. extern uchar RS232_Rec;
  15. extern idata uchar RS232_Rec_Buf[];
  16. extern uchar RS232_Rec_Buf_Index;
  17. extern enum TXmoden_STate Xmoden_STate;

  18. void RS232_Init(void);
  19. void RS232_ISR(void);
  20. void RS232_Tran_Chr(uchar chr);
  21. // void RS232_Tran_Str(const uchar* str);
  22. //uchar* RS232_Rec_Str(void);
  23. void RS232_Rec_Xmodem(void);
  24. #endif
复制代码
回复

使用道具 举报

ID:128605 发表于 2016-6-29 20:34 | 显示全部楼层
感谢 正好要用到
回复

使用道具 举报

ID:17809 发表于 2020-8-15 08:07 | 显示全部楼层
谢谢, 程序写得很好
回复

使用道具 举报

ID:137736 发表于 2020-11-9 19:49 | 显示全部楼层
编译通不过,请上传文件
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表