⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 io_com.c

📁 这是一个只要带定时器的单片机都能用普通的I/O口模拟出一个串口的程序
💻 C
字号:
/*****************************************************/
/* 虚拟串口通讯程序                 */
/* MCU 型号: Winbond STC89C516RD+        */
/* 开发环境: Keil C51 V8.05             */
/* 开发日期: 2007.11.24              */
/* 程序编写: liu90091               */
/* 时钟频率: 22.1184 MHz            */
/*****************************************************/
#include <reg52.h>
#include <stdio.h>
#include <stdarg.h>
#include "define.h"
#include "interface.h"

//#ifdef SYSCLK221184   // 系统时钟 22.1184 MHz
//=
//=65536-22118400 /12/9600 = 0xff40
//9600
#define SU_TH2      0xFF        // 重装值 (2^16-0xff40)*12/22.1184*10^(-6)
#define SU_TL2      0x40        // = 104.167us(1/9600) (22.1184MHz)
#define DELAY_TH2   0xff
#define DELAY_TL2    0xc0
//4800
//#define SU_TH2      0xFe        // 重装值 (2^16-0xfe80)*12/22.1184*10^(-6)
//#define SU_TL2      0x80        // = 2* 104.167us(1/4800) (22.1184MHz)
//#define DELAY_TH2   0xff
//#define DELAY_TL2    0x80

uchar RxCnt;                   // 模拟接收计数器及标志(0~3:计数器; 4:允许接收; 5:接收完成)
uchar TxCnt;                   // 模拟发送计数器及标志(0~3:计数器; 4:允许发送; 5:发送完成; 6:起始位未发送)
/* NEWCA */
uchar RXBUF;                   // 模拟串行接收缓冲
uchar TXBUF;                   // 模拟串行发送缓冲
//uchar uParity;                    // 校验计算字节

#define BUSYMSK     0x10        // 模拟串口忙标志掩蔽位
#define OVERMSK     0x20        // 模拟串口完成标志掩蔽位

#define OUTBUFFERSIZE   256             // 发送缓冲区大小
uchar xdata OutBuffer[OUTBUFFERSIZE];       // 发送缓冲区
uchar tin;                            // 发送缓冲区入指针
uchar tout;                           // 发送缓冲区出指针

#define INBUFFERSIZE    256            // 接收缓冲区大小
uchar xdata InBuffer[INBUFFERSIZE];         // 接收缓冲区
uchar rin;                            // 接收缓冲区入指针
uchar rout;                           // 接收缓冲区出指针
uchar RxCmdBuf[32];
uchar TxCmdBuf[32];
uchar rcount = 0;
uchar tcount = 0;
uchar TxIndex = 0;

bit  TxCommand    = 0;
bit  RxCommand = 0;                //收到命令包的个数
bit  Synflag = 0;
bit  sendfull=0;                           // 发送缓冲区满标志
bit  sendactive=0;                         // 正在发送标志
bit  bIsPacket=0;
code uchar TOASC[16]=
{'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};


//***************************************************************************/
//       su_init: initialize simulator uart interface                       */
//***************************************************************************/
void SU_Init(void)
{
    FEEDDOG();
    tin     = 0;
    tout    = 0;
    rin     = 0;
    rout    = 0;
    RxCnt   = 0;
    TxCnt   = 0;
    //9600,n,8,1

    //接收时钟设置
    T2CON   = 0x00;                 // 16 Bit Auto-Reload Mode
    RCAP2H  = SU_TH2;               // 9600bps定时 (22.1184MHz)
    RCAP2L  = SU_TL2;
    ET2     = 1;                    // 定时器 2 中断允许

    //接收中断设置
    IE0 = 0;                //清中断标志
    //IP &= 0xfd;            //T0 低优先级
    PT0 = 0;
    IP |= 0x20;
    //PT2 = 1;
    IPH = 0x21;
    TCON |= 0x01;             // 外部中断 0 为边沿触发
方式
    EX0 = 1;                 // 外部中断 0 允许
    EN485 = 0;
    EA = 1;
}

//***************************************************************************/
//       su_rcv_int: receive start bit interrupt 0                          */
//***************************************************************************/
void su_rcv_int1() interrupt 0
{
    //uchar data i;
    if(!(RxCnt & BUSYMSK))              // 如允许接收
    {   // 起始位
        FEEDDOG();
        //i=DELAY_TIMES;
        //while(i--);               // 延时 (23*4+4)*12/22.1184 = 52.083 us (22.1184MHz)
        //if(!RXD1)                       // 检测起始位
        {
            EX0 = 0;                    // 外部中断 0 不允许
            RxCnt = 0x00 | BUSYMSK;
            TH2 = DELAY_TH2;         
            TL2 = DELAY_TL2;
            TR2 = 1;                // 定时器 2 启动
        }
    }
}

//*****************************************************************************
/
//       su_timer: timer2 interrupt                                           
*/
//*****************************************************************************
/
void Recieve_timer() interrupt 5    using 3
{
    TF2 = 0;                            // 中断标志清除( Timer2 必须软件清除!)
    FEEDDOG();
    if(RxCnt & BUSYMSK)                 // 接收
    {
        if((RxCnt & 0x0f) == 0x00)    //起始位
        {
            if(RXD1)
            {
                RxCnt = 0x00; 
                EX0 = 1;                // 外部中断 
0 允许
                TR2 = 0;
            }
            else
            {
                RXBUF = 0x00;
                RxCnt++;
            }
        }
        else if((RxCnt & 0x0f) < 0x09)
        {
            RXBUF >>= 1;
            if(RXD1)RXBUF |= 0x80;
            RxCnt++;
        }
        else  // 收到1个字符
        {
        //  if(RXD1)//停止位有效
            GLED = ~GLED;
//            InBuffer[rin++ & (INBUFFERSIZE-1)] = RXBUF; // 数据存入缓冲区
            //if(rcount > 3){RxCommand = 1;}
            if(RXBUF == '@') 
            {
                bIsPacket = 1;
                rcount = 0;
                //InBuffer[rin++ & (INBUFFERSIZE-1)] = RXBUF; // 数据存入缓冲区
                RxCmdBuf[rcount++] = RXBUF;
            }
            else if(RXBUF == '#')
            {
                //InBuffer[rin++ & (INBUFFERSIZE-1)] = RXBUF; // 数据存入缓冲区
                RxCmdBuf[rcount++] = RXBUF;
                RxCommand = 1; GLED = ~GLED;
                bIsPacket = 0;
            }
            else if(bIsPacket)
            {
                //InBuffer[rin++ & (INBUFFERSIZE-1)] = RXBUF; // 数据存入缓冲区
                //rcount++;
                RxCmdBuf[rcount++] = RXBUF;
            }
            //接受数据处理
            
            RxCnt = 0x00;             // 收到1个字符
            EX0 = 1;                // 外部中断 0 允许
            TR2 = 0;
            //EN485 = 1;
            //TxCnt = BUSYMSK;
            //TXBUF = RXBUF;     // 写SBUF
        }        
    }
    else if(TxCnt & BUSYMSK)                 // 发送
    {
        uchar tmp;
        tmp = TxCnt & 0x0f;
        if(tmp == 0x00)     // 若还未发送起始位
        {
            TXD1 = 0;               // 发送起始位
            TxCnt++;
        }
        else if(tmp < 0x09)
        {
            TXD1 = (bit)(TXBUF & 0x01);
            TXBUF = TXBUF >> 1;
            TxCnt++;
        }
        else if(tmp == 0x09)
        {
            TXD1 = 1;               // 发送停止位
            TxCnt++;
        }
        else
        {
            TXD1=1;
            sendfull = 0;         // 清除发送缓冲区满标志
            //TxIndex++;
            //if(tcount > TxIndex)
            if(tin != tout)
            {                                   // 若缓冲区有字符
                TXBUF = OutBuffer[tout++ & (OUTBUFFERSIZE-1)];
				//TxCmdBuf[TxIndex];    // 发送1个字符
                TxCnt = BUSYMSK;                
            }
            else
            {
                sendactive = 0;                // 若发送完, 清除正在发送标志
                TxCnt = 0x00;
                TR2=0;     //停止发送
                EX0 = 1;
                EN485 = 0;
                GLED = ~GLED;
                TxCommand = 1;
            }
        }
    }
//    if(RxCnt || TxCnt == 0x00)TR2 = 0;   
}

//发送一个字节
void putbuf(uchar c)
{
    FEEDDOG();
    if(!sendfull)
    {   // 发送缓冲区未满才发送
        if(!sendactive)
        {   // 若当前未发送
            sendactive  = 1;
            TxCnt = BUSYMSK;
            TXBUF = c;     // 写SBUF
            EX0 = 0;
            TXD1 = 1;
            EN485 = 1;
            TH2  = SU_TH2;              
            TL2  = SU_TL2;
            TR2 = 1;                    // 定时器 2 启动
        }
        else
        {                                   // 若正在发送
            OutBuffer[tin++ & (OUTBUFFERSIZE-1)] = c; // 将字符放入发送缓冲区
            if(((tin ^ tout) & (OUTBUFFERSIZE-1)) == 0)
            {
                sendfull = 1;               // 置发送缓冲区满标志
            }
        }
    }
} 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -