8051单片机-模拟串口

发布时间:2024-07-30  

传统的8051系列单片机一般都配备一个串口,而STC89C52RC增强型单片机也不例外,只有一个串口可供使用,这样就出问题了,假如当前单片机系统要求二个串口或多个串口进行同时通信,8051系列单片机只有一个串口可供通信就显得十分尴尬,但是在实际的应用中,有两种方法可以选择。


方法1:使用能够支持多串口通信的单片机,不过通过更换其他单片机来代替8051系列单片机,这样就会直接导致成本的增加,优点就是编程简单,而且通信稳定可靠。


方法2:在IO资源比较充足的情况下,可以通过IO来模拟串口的通信,虽然这样会增加编程的难度,模拟串口的波特率会比真正的串口通信低一个层次,但是唯一优点就是成本上得到控制,而且通过不同的IO组合可以实现更加之多的模拟串口,在实际应用中往往会采用模拟串口的方法来实现多串口通信。


普遍使用串口通信的数据流都是1位起始位、8位数据位、1位停止位的格式的,如表1。

表1

image.png

要注意的是,起始位作为识别是否有数据到来,停止位标志数据已经发送完毕。起始位固定值为0,停止位固定值为1,那么为什么起始位要是0,停止位要是1呢?这个很好理解,假设停止位固定值为1,为了更加易识别数据的到来,电平的跳变最为简单也最容易识别,那么当有数据来的时候,只要在规定的时间内检测到发送过来的第一位的电平是否0值,就可以确定是否有数据到来;另外停止位为1的作用就是当没有收发数据之后引脚置为高电平起到抗干扰的作用

在平时使用红外无线收发数据时,一般都采用模拟串口来实现的,但是有个问题要注意,波特率越高,传输距离越近;波特率越低,传输距离越远。对于这些通过模拟串口进行数据传输,波特率适宜为1200b/s来进行数据传输。


例子:在使用单片机的串口接收数据实验当中,使用串口调试助手发送16字节数据,单片机采用模拟串口的方法将接收到的数据返发到PC机。


模拟串口实验代码:

  1 #include "stc.h"

  2 

  3  #define RXD P3_0              //宏定义:接收数据的引脚

  4  #define TXD P3_1              //宏定义:发送数据的引脚

  5  #define RECEIVE_MAX_BYTES 16//宏定义:最大接收字节数

  6 

  7  #define TIMER_ENABLE()  {TL0=TH0;TR0=1;fTimeouts=0;}//使能T/C

  8  #define TIMER_DISABLE() {TR0=0;fTimeouts=0;}//禁止T/C

  9  #define TIMER_WAIT()    {while(!fTimeouts);fTimeouts=0;}//等待T/C超时

 10 

 11 

 12 unsigned char fTimeouts=0;//T/C超时溢出标志位

 13  unsigned char RecvBuf[16];//接收数据缓冲区

 14  unsigned char RecvCount=0;//接收数据计数器

 15  

 16 

 17  /****************************************

 18 *函数名称:SendByte

 19 *输    入:byte 要发送的字节

 20 *输    出:无

 21 *功    能:串口发送单个字节

 22 ******************************************/

 23  void SendByte(unsigned char b)

 24 {

 25      unsigned char i=8;

 26      

 27      TXD=0;

 28 

 29      TIMER_ENABLE();

 30      TIMER_WAIT();

 31      

 32 

 33      while(i--)

 34      {

 35         if(b&1)TXD=1;

 36         else    TXD=0;

 37 

 38         TIMER_WAIT();

 39         

 40         b>>=1;

 41 

 42      }

 43 

 44      

 45      TXD=1;

 46 

 47      TIMER_WAIT();

 48      TIMER_DISABLE();

 49 }

 50  /****************************************

 51 *函数名称:RecvByte

 52 *输    入:无

 53 *输    出:单个字节

 54 *功    能:串口 接收单个字节

 55 ******************************************/

 56 unsigned char RecvByte(void)

 57 {

 58      unsigned char i;

 59      unsigned char b=0;

 60      

 61      TIMER_ENABLE();

 62      TIMER_WAIT();

 63 

 64      for(i=0;i<8;i++)

 65      {

 66          if(RXD)b|=(1< 67 

 68          TIMER_WAIT();

 69      }

 70 

 71      TIMER_WAIT();  //等待结束位

 72       TIMER_DISABLE();

 73   

 74      return b;

 75 

 76 }

 77  /****************************************

 78 *函数名称:PrintfStr

 79 *输    入:pstr 字符串

 80 *输    出:无

 81 *功    能:串口 打印字符串

 82 ******************************************/

 83  void PrintfStr(char * pstr)

 84 {

 85       while(pstr && *pstr)

 86      {

 87            SendByte(*pstr++);

 88      }

 89 }

 90  /****************************************

 91 *函数名称:TimerInit

 92 *输    入:无

 93 *输    出:无

 94 *功    能:T/C初始化

 95 ******************************************/

 96  void TimerInit(void)

 97 {

 98      TMOD=0x02; 

 99      TR0=0;

100      TF0=0;

101      TH0=(256-99);

102      TL0=TH0;

103      ET0=1;

104      EA=1;

105 }

106  /****************************************

107 *函数名称:StartBitCome

108 *输    入:无

109 *输    出:0/1

110 *功    能:是否有起始位到达

111 ******************************************/

112 unsigned char StartBitCome(void)

113 {

114          return (RXD==0);

115 }

116  /****************************************

117 *函数名称:main

118 *输    入:无

119 *输    出:无

120 *功    能:函数主体

121 ******************************************/

122  void main(void)

123 {

124      unsigned char i;

125 

126      TimerInit();

127 

128      PrintfStr("Hello 8051rn");

129 

130      while(1)

131      {

132         if(StartBitCome())

133         {                     

134            RecvBuf[RecvCount++]=RecvByte();

135            

136            if(RecvCount>=RECEIVE_MAX_BYTES)

137            {

138               RecvCount=0;

139 

140               for(i=0;i141               {

142                   SendByte(RecvBuf[i]);

143               }

144            }       

145         }

146  

147      }

148 }

149  /****************************************

150 *函数名称:TimerIRQ

151 *输    入:无

152 *输    出:无

153 *功    能:T/C0中断服务函数

154 ******************************************/

155  void Timer0IRQ(void) interrupt 1 using 0

156 {

157      fTimeouts=1;

158 } 

159  


代码分析

在模拟串口实验代码中,宏的使用占用了相当的一部分。

#define RXD P3_0          //宏定义:接收数据的引脚

#define TXD P3_1          //宏定义:发送数据的引脚

#define TIMER_ENABLE()  {TL0=TH0;TR0=1;fTimeouts=0;}//使能T/C

#define TIMER_DISABLE() {TR0=0;fTimeouts=0;}//禁止T/C

#define TIMER_WAIT()    {while(!fTimeouts);fTimeouts=0;}//等待T/C超时

   

模拟串口接收引脚为P3.0,发送引脚为P3.1。为了达到精确的定时,减少模拟串口时收发数据的累积误差,有必要通过对T/C进行频繁的使能和禁止等操作。例如宏TIMER_ENABLE为使能T/C,宏TIMER_DISABLE禁止T/C,宏TIMER_WAIT等待T/C超时。

模拟串口的工作波特率为9600b/s,在串口收发的数据流当中,每一位的时间为1/9600≈104us,

若单片机工作在12MHz频率下,使用T/C0工作在方式2,那么为了达到104us的定时时间,TH0、TL0的初值为256-104=152,在实际的模拟串口中,往往出现收发数据不正确的现象。原因就在于TH0、TL0的初值,或许很多人会疑惑,按道理来说,计算T/C0的初值是没有错的。对,是没有错,但是在SendByte和Recv的函数当中,执行每一行代码都要消耗一定的时间,这就是所谓的“累积误差”导致收发数据出现问题,因此我们必须通过实际测试得到TH0、TL0的初值,最佳值256-99=157。那么在T/C初始化TimerInit函数中,TH0、TL0的初值不能够按照常规来计算得到,实际初值在正常初值附近,可以通过实际测试得到。

模拟串口主要复杂在模拟串口发送与接收,具体实现函数在SendByte和RecvByte函数,这两个函数必须要遵循“1位起始位、8位数据位、1位停止位”的数据流。

SendByte函数用于模拟串口发送数据,以起始位“0”作为移位传输的起始标志,然后将要发送的自己从低字节到高字节移位传输,最后以停止位“1”作为移位传输的结束标志。

RecvByte函数用于模拟串口接收数据,一旦检测到起始位“0”,就立刻将接收到的每一位移位存储,最后以判断停止位“1”结束当前数据的接收。

main函数完成T/C的初始化,在while(1)死循环以检测起始位“0”为目的,当接收到的数据达到宏RECEIVE_MAX_BYTES的个数时,将接收到的数据返发到外设。


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>