找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3169|回复: 11
收起左侧

关于51单片机串口的问题

[复制链接]
ID:188372 发表于 2017-4-12 10:58 | 显示全部楼层 |阅读模式
最近在做一个小制作。碰到了个问题:51单片机只有一个硬串口,我现在有两个外设需要用到串口,要怎么解决?希望各位牛人能够指点一下,最好给些解决该问题的程序。
回复

使用道具 举报

ID:136679 发表于 2017-4-12 11:53 | 显示全部楼层
  1. #include <reg52.h>

  2. sbit PIN_RXD = P3^4;  //接收引脚定义
  3. sbit PIN_TXD = P3^5;  //发送引脚定义

  4. bit RxdOrTxd = 0;  //指示当前状态为接收还是发送
  5. bit RxdEnd = 0;    //接收结束标志
  6. bit TxdEnd = 0;    //发送结束标志
  7. unsigned char RxdBuf = 0;  //接收缓冲器
  8. unsigned char TxdBuf = 0;  //发送缓冲器

  9. void ConfigUART(unsigned int baud);
  10. void StartTXD(unsigned char dat);
  11. void StartRXD();

  12. void main()
  13. {
  14.     EA = 1;   //开总中断
  15.     ConfigUART(9600);  //配置波特率为9600
  16.    
  17.     while (1)
  18.     {
  19.         while (PIN_RXD);    //等待接收引脚出现低电平,即起始位
  20.         StartRXD();         //启动接收
  21.         while (!RxdEnd);    //等待接收完成
  22.         StartTXD(RxdBuf+1); //接收到的数据+1后,发送回去
  23.         while (!TxdEnd);    //等待发送完成
  24.     }
  25. }
  26. /* 串口配置函数,baud-通信波特率 */
  27. void ConfigUART(unsigned int baud)
  28. {
  29.     TMOD &= 0xF0;   //清零T0的控制位
  30.     TMOD |= 0x02;   //配置T0为模式2
  31.     TH0 = 256 - (11059200/12)/baud;  //计算T0重载值
  32. }
  33. /* 启动串行接收 */
  34. void StartRXD()
  35. {
  36.     TL0 = 256 - ((256-TH0)>>1);  //接收启动时的T0定时为半个波特率周期
  37.     ET0 = 1;        //使能T0中断
  38.     TR0 = 1;        //启动T0
  39.     RxdEnd = 0;     //清零接收结束标志
  40.     RxdOrTxd = 0;   //设置当前状态为接收
  41. }
  42. /* 启动串行发送,dat-待发送字节数据 */
  43. void StartTXD(unsigned char dat)
  44. {
  45.     TxdBuf = dat;   //待发送数据保存到发送缓冲器
  46.     TL0 = TH0;      //T0计数初值为重载值
  47.     ET0 = 1;        //使能T0中断
  48.     TR0 = 1;        //启动T0
  49.     PIN_TXD = 0;    //发送起始位
  50.     TxdEnd = 0;     //清零发送结束标志
  51.     RxdOrTxd = 1;   //设置当前状态为发送
  52. }
  53. /* T0中断服务函数,处理串行发送和接收 */
  54. void InterruptTimer0() interrupt 1
  55. {
  56.     static unsigned char cnt = 0; //位接收或发送计数

  57.     if (RxdOrTxd)  //串行发送处理
  58.     {
  59.         cnt++;
  60.         if (cnt <= 8)  //低位在先依次发送8bit数据位
  61.         {
  62.             PIN_TXD = TxdBuf & 0x01;
  63.             TxdBuf >>= 1;
  64.         }
  65.         else if (cnt == 9)  //发送停止位
  66.         {
  67.             PIN_TXD = 1;
  68.         }
  69.         else  //发送结束
  70.         {
  71.             cnt = 0;    //复位bit计数器
  72.             TR0 = 0;    //关闭T0
  73.             TxdEnd = 1; //置发送结束标志
  74.         }
  75.     }
  76.     else  //串行接收处理
  77.     {
  78.         if (cnt == 0)     //处理起始位
  79.         {
  80.             if (!PIN_RXD) //起始位为0时,清零接收缓冲器,准备接收数据位
  81.             {
  82.                 RxdBuf = 0;
  83.                 cnt++;
  84.             }
  85.             else          //起始位不为0时,中止接收
  86.             {
  87.                 TR0 = 0;  //关闭T0
  88.             }
  89.         }
  90.         else if (cnt <= 8)   //处理8位数据位
  91.         {
  92.             RxdBuf >>= 1;    //低位在先,所以将之前接收的位向右移
  93.             if (PIN_RXD)     //接收脚为1时,缓冲器最高位置1,
  94.             {                //而为0时不处理即仍保持移位后的0
  95.                 RxdBuf |= 0x80;
  96.             }
  97.             cnt++;
  98.         }
  99.         else  //停止位处理
  100.         {
  101.             cnt = 0;         //复位bit计数器
  102.             TR0 = 0;         //关闭T0
  103.             if (PIN_RXD)     //停止位为1时,方能认为数据有效
  104.             {
  105.                 RxdEnd = 1;  //置接收结束标志
  106.             }
  107.         }
  108.     }
  109. }
复制代码
回复

使用道具 举报

ID:136679 发表于 2017-4-12 11:55 | 显示全部楼层
#include <reg52.h>

sbit PIN_RXD = P3^4;  //接收引脚定义
sbit PIN_TXD = P3^5;  //发送引脚定义

bit RxdOrTxd = 0;  //指示当前状态为接收还是发送
bit RxdEnd = 0;    //接收结束标志
bit TxdEnd = 0;    //发送结束标志
unsigned char RxdBuf = 0;  //接收缓冲器
unsigned char TxdBuf = 0;  //发送缓冲器

void ConfigUART(unsigned int baud);
void StartTXD(unsigned char dat);
void StartRXD();

void main()
{
    EA = 1;   //开总中断
    ConfigUART(9600);  //配置波特率为9600
   
    while (1)
    {
        while (PIN_RXD);    //等待接收引脚出现低电平,即起始位
        StartRXD();         //启动接收
        while (!RxdEnd);    //等待接收完成
        StartTXD(RxdBuf+1); //接收到的数据+1后,发送回去
        while (!TxdEnd);    //等待发送完成
    }
}
/* 串口配置函数,baud-通信波特率 */
void ConfigUART(unsigned int baud)
{
    TMOD &= 0xF0;   //清零T0的控制位
    TMOD |= 0x02;   //配置T0为模式2
    TH0 = 256 - (11059200/12)/baud;  //计算T0重载值
}
/* 启动串行接收 */
void StartRXD()
{
    TL0 = 256 - ((256-TH0)>>1);  //接收启动时的T0定时为半个波特率周期
    ET0 = 1;        //使能T0中断
    TR0 = 1;        //启动T0
    RxdEnd = 0;     //清零接收结束标志
    RxdOrTxd = 0;   //设置当前状态为接收
}
/* 启动串行发送,dat-待发送字节数据 */
void StartTXD(unsigned char dat)
{
    TxdBuf = dat;   //待发送数据保存到发送缓冲器
    TL0 = TH0;      //T0计数初值为重载值
    ET0 = 1;        //使能T0中断
    TR0 = 1;        //启动T0
    PIN_TXD = 0;    //发送起始位
    TxdEnd = 0;     //清零发送结束标志
    RxdOrTxd = 1;   //设置当前状态为发送
}
/* T0中断服务函数,处理串行发送和接收 */
void InterruptTimer0() interrupt 1
{
    static unsigned char cnt = 0; //位接收或发送计数

    if (RxdOrTxd)  //串行发送处理
    {
        cnt++;
        if (cnt <= 8)  //低位在先依次发送8bit数据位
        {
            PIN_TXD = TxdBuf & 0x01;
            TxdBuf >>= 1;
        }
        else if (cnt == 9)  //发送停止位
        {
            PIN_TXD = 1;
        }
        else  //发送结束
        {
            cnt = 0;    //复位bit计数器
            TR0 = 0;    //关闭T0
            TxdEnd = 1; //置发送结束标志
        }
    }
    else  //串行接收处理
    {
        if (cnt == 0)     //处理起始位
        {
            if (!PIN_RXD) //起始位为0时,清零接收缓冲器,准备接收数据位
            {
                RxdBuf = 0;
                cnt++;
            }
            else          //起始位不为0时,中止接收
            {
                TR0 = 0;  //关闭T0
            }
        }
        else if (cnt <= 8)   //处理8位数据位
        {
            RxdBuf >>= 1;    //低位在先,所以将之前接收的位向右移
            if (PIN_RXD)     //接收脚为1时,缓冲器最高位置1,
            {                //而为0时不处理即仍保持移位后的0
                RxdBuf |= 0x80;
            }
            cnt++;
        }
        else  //停止位处理
        {
            cnt = 0;         //复位bit计数器
            TR0 = 0;         //关闭T0
            if (PIN_RXD)     //停止位为1时,方能认为数据有效
            {
                RxdEnd = 1;  //置接收结束标志
            }
        }
    }
}
回复

使用道具 举报

ID:151348 发表于 2017-4-12 12:49 | 显示全部楼层
可以自定义通信协议
回复

使用道具 举报

ID:47286 发表于 2017-4-12 13:07 | 显示全部楼层
1. STC11F系列可以虚拟出两个串口
2. STC12C5AxxS2自带两个硬件串口
3. STC15系列有4个硬件串口的
回复

使用道具 举报

ID:47286 发表于 2017-4-12 13:08 | 显示全部楼层
至于程序 STC的相关单片机pdf里有范例 你看一下就明白了 挺简单的 12C5AXXS2的双串口程序百度搜一下 很多 我开始也是百度搜了学的
回复

使用道具 举报

ID:188372 发表于 2017-4-12 15:28 | 显示全部楼层
回复

使用道具 举报

ID:188372 发表于 2017-4-12 15:29 | 显示全部楼层
li1557554 发表于 2017-4-12 11:55
#include

sbit PIN_RXD = P3^4;  //接收引脚定义

谢谢!!!
回复

使用道具 举报

ID:7485 发表于 2017-4-12 16:12 | 显示全部楼层
有任意两根I/O可以模拟一个串口。
回复

使用道具 举报

ID:185329 发表于 2017-4-12 23:17 | 显示全部楼层
IO模拟串口
回复

使用道具 举报

ID:111634 发表于 2017-4-13 14:55 | 显示全部楼层
除了硬串口,还可虚拟串口,而且现在流行虚拟串口。
回复

使用道具 举报

ID:189198 发表于 2017-4-13 15:49 | 显示全部楼层
现在流行虚拟的串口,可以参考一下一下这个

#include <reg52.h>

sbit PIN_RXD = P3^4;  //接收引脚定义
sbit PIN_TXD = P3^5;  //发送引脚定义

bit RxdOrTxd = 0;  //指示当前状态为接收还是发送
bit RxdEnd = 0;    //接收结束标志
bit TxdEnd = 0;    //发送结束标志
unsigned char RxdBuf = 0;  //接收缓冲器
unsigned char TxdBuf = 0;  //发送缓冲器

void ConfigUART(unsigned int baud);
void StartTXD(unsigned char dat);
void StartRXD();

void main()
{
    EA = 1;   //开总中断
    ConfigUART(9600);  //配置波特率为9600
   
    while (1)
    {
        while (PIN_RXD);    //等待接收引脚出现低电平,即起始位
        StartRXD();         //启动接收
        while (!RxdEnd);    //等待接收完成
        StartTXD(RxdBuf+1); //接收到的数据+1后,发送回去
        while (!TxdEnd);    //等待发送完成
    }
}
/* 串口配置函数,baud-通信波特率 */
void ConfigUART(unsigned int baud)
{
    TMOD &= 0xF0;   //清零T0的控制位
    TMOD |= 0x02;   //配置T0为模式2
    TH0 = 256 - (11059200/12)/baud;  //计算T0重载值
}
/* 启动串行接收 */
void StartRXD()
{
    TL0 = 256 - ((256-TH0)>>1);  //接收启动时的T0定时为半个波特率周期
    ET0 = 1;        //使能T0中断
    TR0 = 1;        //启动T0
    RxdEnd = 0;     //清零接收结束标志
    RxdOrTxd = 0;   //设置当前状态为接收
}
/* 启动串行发送,dat-待发送字节数据 */
void StartTXD(unsigned char dat)
{
    TxdBuf = dat;   //待发送数据保存到发送缓冲器
    TL0 = TH0;      //T0计数初值为重载值
    ET0 = 1;        //使能T0中断
    TR0 = 1;        //启动T0
    PIN_TXD = 0;    //发送起始位
    TxdEnd = 0;     //清零发送结束标志
    RxdOrTxd = 1;   //设置当前状态为发送
}
/* T0中断服务函数,处理串行发送和接收 */
void InterruptTimer0() interrupt 1
{
    static unsigned char cnt = 0; //位接收或发送计数

    if (RxdOrTxd)  //串行发送处理
    {
        cnt++;
        if (cnt <= 8)  //低位在先依次发送8bit数据位
        {
            PIN_TXD = TxdBuf & 0x01;
            TxdBuf >>= 1;
        }
        else if (cnt == 9)  //发送停止位
        {
            PIN_TXD = 1;
        }
        else  //发送结束
        {
            cnt = 0;    //复位bit计数器
            TR0 = 0;    //关闭T0
            TxdEnd = 1; //置发送结束标志
        }
    }
    else  //串行接收处理
    {
        if (cnt == 0)     //处理起始位
        {
            if (!PIN_RXD) //起始位为0时,清零接收缓冲器,准备接收数据位
            {
                RxdBuf = 0;
                cnt++;
            }
            else          //起始位不为0时,中止接收
            {
                TR0 = 0;  //关闭T0
            }
        }
        else if (cnt <= 8)   //处理8位数据位
        {
            RxdBuf >>= 1;    //低位在先,所以将之前接收的位向右移
            if (PIN_RXD)     //接收脚为1时,缓冲器最高位置1,
            {                //而为0时不处理即仍保持移位后的0
                RxdBuf |= 0x80;
            }
            cnt++;
        }
        else  //停止位处理
        {
            cnt = 0;         //复位bit计数器
            TR0 = 0;         //关闭T0
            if (PIN_RXD)     //停止位为1时,方能认为数据有效
            {
                RxdEnd = 1;  //置接收结束标志
            }
        }
    }
}
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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