一个非常不错的串口程序

//PC读MCU指令结构:(中断方式,ASCII码表示) 
//帧:   帧头标志|帧类型|器件地址|启始地址|长度n|效验和|帧尾标志 
//值:    ’n’ ’y’| ’r’  |  0x01  |   x    |  x  |   x  |0x13 0x10 
//字节数:   2   |  1   |    1   |   1    |  1  |   1  |   2 
//求和: 



//公司名称:*** 
//模 块 名:protocol.c 
//创 建 者:牛毅 
//修 改 者: 
//功能描述:中断方式:本程序为mcu的串口通讯提供(贞结构)函数接口,包括具体协议部分 
//其他说明:只提供对AT89c51具体硬件的可靠访问接口 
//版    本:1.0 
//信    息:QQ 75011221        C51BBS匿名:niuyi 



#include <reg51.h> 
#include <config.h> 
//预定义 
//帧 
#define F_ST1 0x6e            //帧头标志            n 
#define F_ST2 0x79            //帧头标志            y 
#define F_R 0x72            //帧类型 读         
    r 
#define F_W 0x77            //帧类型 写         
    w 
#define F_D 0x64            //帧类型 数据帧        d 
#define F_B 0x62            //帧类型 写回应帧    b 
#define F_C 0x63            //帧类型 重发命令帧    c 
#define F_Q 0x71            //帧类型 放弃帧        q 
#define F_ADDR 0x31            //器件地址            0-9 
#define F_END 0x7a            //帧尾标志            z 
#define F_SPACE 0x30        //空标志            0 
#define F_ERR1 0x31            //错误标志1,flagerr    1 
#define F_ERR2 0x32            //错误标志2         
    2 
//常数 
#define S_MAXBUF 16            //接收/发送数据的最大缓存量 
#define FIELD_MAXBUF 48     //最小场缓存,可以大于48字节,因为协议是以20字节为单 
位传输的 
#define communicationing P1_7//正在通讯(1)标志 
#define ERRFRAME_MAX 5        //连续NOFRAME_CNT次帧不正确    
#define ERR_NOCNTMAX_RESEND    if(++errframe_cnt<=ERRFRAME_MAX)resend_frame();  
else errframe_cnt=communicationing=0; 
                            //若超过  
ERRFRAME_MAX 次则令通讯停止ERR_NOCNTMAX_RESEND 

//public 变量 
unsigned char databuf[FIELD_MAXBUF],errframe_cnt; 
//函数 


//函 数 名:send() 
//功能描述:向串口发送一个字符 
//函数说明: 
//调用函数: 
//全局变量: 
//输    入:ch-要发送的ASCII字符 
//返    回:无 
//设 计 者:牛毅 
//修 改 者: 
//版    本: 

void send(unsigned char ch) 
{SBUF=ch;while(TI==0);TI=0;} 


//函 数 名:receive() 
//功能描述:从串口接收一个字符 
//函数说明: 
//调用函数: 
//全局变量: 
//输    入:无 
//返    回:一个ASCII字符 
//设 计 者:牛毅 
//修 改 者: 
//版    本: 

unsigned char receive(void) 
{while(RI==0);RI=0;return SBUF;} 


//函 数 名:CharToHex() 
//功能描述:把ASCII字符转换为16进制 
//函数说明: 
//调用函数: 
//全局变量: 
//输    入:ASCII字符 
//返    回:16进制 
//设 计 者:牛毅 
//修 改 者: 
//版    本: 

unsigned char CharToHex(unsigned char bChar){ 
    if((bChar>=0x30)&&(bChar<=0x39)) 
        bChar -= 0x30; 
    else if((bChar>=0x41)&&(bChar<=0x46))//大写字母 
        bChar -= 0x37; 
    else if((bChar>=0x61)&&(bChar<=0x66))//小写字母 
        bChar -= 0x57; 
    else bChar = 0xff; 
    return bChar; 



//函 数 名:HexToChar() 
//功能描述:把16进制转换为ASCII字符 
//函数说明: 
//调用函数: 
//全局变量: 
//输    入:16进制 
//返    回:ASCII字符 
//设 计 者:牛毅 
//修 改 者: 
//版    本: 

unsigned char HexToChar(unsigned char bHex){ 
    if((bHex>=0)&&(bHex<=9)) 
        bHex += 0x30; 
    else if((bHex>=10)&&(bHex<=15))//大写字母 
        bHex += 0x37; 
    else bHex = 0xff; 
    return bHex; 



//函 数 名:com_int() 
//功能描述:初始化串口 
//函数说明:默认其他参数为[baud_rate],n,8,1 
//调用函数: 
//全局变量: 
//输    入:baud_rate 波特率 
//返    回:无 
//设 计 者:牛毅 
//修 改 者: 
//版    本: 

void com_init(unsigned int baud_rate){ 
    EA=1;ES=1;//ET1=1;   
    SCON = 0x50;    /* 0x52;//SCON */ 
    TMOD = 0x20;    /*0x20;// TMOD */ 
    TCON = 0x60;    /*0x60;// TCON */ 
    PCON=PCON&0x7f; 
    switch(baud_rate){    //波特率设置 
        case 1200: 
            TL1=0xe8;TH1=0Xe8;break;//1200 
        case 2400: 
            TL1=0xf4;TH1=0Xf4;break;//2400 
        case 4800: 
            TL1=0xfa;TH1=0Xfa;break;//4800 
        case 9600: 
            TL1=0xfd;TH1=0Xfd;break;//9600 
        case 19200: 
            PCON=PCON|0x80;TL1=0xfd;TH1=0Xfd;break;//19200 
        case 38400: 
            PCON=PCON|0x80;TL1=0xfe;TH1=0Xfe;break;//38400 
        default: 
             TL1=0xfd;TH1=0Xfd;break;//9600 
    } 


//函 数 名:resend_frame() 
//功能描述:发送重发帧 
//函数说明:通知PC重发 
//调用函数: 
//全局变量: 
//输    入:无 
//返    回:无 
//设 计 者:牛毅 
//修 改 者: 
//版    本: 

void resend_frame(void){ 
    send(F_ST1);send(F_ST2);send(F_C);send(F_SPACE);send(F_SPACE);//发送效 
验和 
    send(F_END); 



//函 数 名:quit_frame() 
//功能描述:发送放弃帧 
//函数说明:通知PC放弃通讯 
//调用函数: 
//全局变量: 
//输    入:无 
//返    回:无 
//设 计 者:牛毅 
//修 改 者: 
//版    本: 

void quit_frame(void){ 
    send(F_ST1);send(F_ST2);send(F_Q);send(F_ERR1);send(F_ERR1);//发送效验 
和 
    send(F_END); 



//函 数 名:com_int() 
//功能描述:串口中断 
//函数说明: 
//调用函数: 
//全局变量: 
//输    入:无 
//返    回:无 
//设 计 者:牛毅 
//修 改 者: 
//版    本: 

void com_int()interrupt 4{ 
unsigned char i,csaddr,clen,csum,tempbuf[S_MAXBUF]; 
csum=0; 
if(receive()==F_ST1){//是侦 
    if(receive()==F_ST2){//头判断完 
        communicationing=1;//设置通讯状态为正常    即启动通讯 
        switch(receive()){ 
            case F_R://是读指令帧r 
                if(receive()==F_ADDR){P1_2=!P1_2;//地址 
正确         
                         csaddr=CharToHex(receive())<<4;csaddr+=CharToHex 
(receive()); 
                    clen=CharToHex(receive()) 
<<4;clen+=CharToHex(receive()); 
                    csum=csaddr+clen; 
                    i=CharToHex(receive()) 
<<4;i+=CharToHex(receive()); 
                    if(i==csum){//效验和正确 
                        if(receive() 
==F_END){//结束标志正确    //开始发送数据帧 
                         
    csum=0;send(F_ST1);send(F_ST2);send(F_D); 
                            send 
(HexToChar((clen&0xf0)>>4));send(HexToChar(clen&0x0f));csum+=clen; 
                            for 
(i=0;i<clen;i++){ 
                             
    send(HexToChar((databuf[i+csaddr]&0xf0)>>4));send(HexToChar(databuf 
[i+csaddr]&0x0f)); 
                             
    csum+=databuf[i+csaddr]; 
                            } 
                            //if 
(csum>127)csum-=128; 
                            send 
(HexToChar((csum&0xf0)>>4));send(HexToChar(csum&0x0f));send(F_END); 
                             
    //发送数据帧完毕 
                            P1_0=! 
P1_0; 
                        }else  
{ERR_NOCNTMAX_RESEND break;}//结束标志错误 
                    }else {ERR_NOCNTMAX_RESEND  
break;}//效验和错误 
                }//地址不正确 
                break; 
            case F_W://是PC写指令帧w 
                if(receive()==F_ADDR){//地址正确 
                    csaddr=CharToHex(receive()) 
<<4;csaddr+=CharToHex(receive()); 
                    clen=CharToHex(receive()) 
<<4;clen+=CharToHex(receive()); 
                    csum=csaddr+clen; 
                    for(i=0;i<clen;i++){ 
                        tempbuf[i+csaddr] 
=CharToHex(receive())<<4;tempbuf[i+csaddr]+=CharToHex(receive()); 
                        csum+=tempbuf 
[i+csaddr]; 
                        } 
                    i=CharToHex(receive()) 
<<4;i+=CharToHex(receive()); 
                    if(csum!=i) 
{ERR_NOCNTMAX_RESEND break;}//效验和错误 
                    if(F_END!=receive()) 
{ERR_NOCNTMAX_RESEND break;}//结束标志错误 
                    for 
(i=csaddr;i<clen+csaddr;i++)databuf[i-csaddr]=tempbuf[i-csaddr];//正确则保存数据 
                }//从PC获得数据写完毕//开始发送写回应帧 
                send(F_ST1);send(F_ST2);send(F_B);send 
(F_SPACE);send(F_SPACE);//发送效验和 
                send(F_END);//写回应帧发送完毕 
                P1_1=!P1_1; 
                break; 
            case F_Q://检测接收放弃帧 
                csaddr=receive();csum+=csaddr;//csaddr 
兼做放弃帧码标志 
                if(csaddr!=F_ERR1 && csaddr!=F_ERR2) 
{ERR_NOCNTMAX_RESEND break;} 
                if(csum!=receive()) 
{ERR_NOCNTMAX_RESEND break;} 
                if(F_END!=receive()) 
{ERR_NOCNTMAX_RESEND break;} 
                communicationing=0;//出错退出通讯 
                break; 
            default: 
                resend_frame();//要求从发 
        } 
    }//忽略     
}//忽略 
if(!communicationing)quit_frame();//调用放弃帧,通知PC 放弃通讯 



//主函数 


void main(void){ 
unsigned char i; 
for (i=0;i<FIELD_MAXBUF;i++)databuf[i]=i+0x30; 
com_init(38400); 
while(1){ 
/*可以处理非串口任务*/ 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值