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

📄 单片机串口通信.txt

📁 串口控制程序一般分为查询和中断两者方式。查询方式适用于简单的应用
💻 TXT
字号:
单片机串口通信
                                                                                                      串口控制程序一般分为查询和中断两者方式。查询方式适用于简单的应用,简单可靠,但是缺点是需要占用处理器资源,在发送或者接收数据的时候不能做其它的事情,处理器利用率低。中断方式下,在发送或者接受数据的时候处理器还可以做其它的工作,效率较高。
        对于稍微复杂的系统来说,中断方式管理串口程序将会更加有效。中断处理方式也可分为几种,其中采用循环缓冲区的方式比较高效。循环缓冲区为定义的一定长度的RAM区间,对于接受数据来说,中断中收到的数据将存入RAM中,然后等待主程序来读取。其中会涉及到数据见的协调问题,写数据的时候不能把还没有读取的数据覆盖掉,读数据的时候应该读取的是缓冲区中最老的数据。当缓冲区已满的时候,写入的新数据应该覆盖掉最老的数据。这些问题的处理可以使用两个指针来实现。

  

        初始化时两个指针均指向RAM区间的底部,如图1所示。当中断中接收到一个数据的时候,将这个数据写入写指针WPTR指向的存储单元,然后调整写指针指向下一个空余的RAM区间,程序上处理就是把写指针加一,如图2所示。同理,写入N个数据后写指针同步更新,如图3所示。

  

        当读数据的时候,首先判断缓冲区中是否有数据,方法是判断读指针和写指针是否相等,如果相等表明没有数据,如图5所示。如果读指针和写指针不等,那么读取缓冲区中的数据,然后调整读指针,当写指针和读指针相等的时候,表明缓冲区中的有效数据已经读取完,此时读指针和写指针相等。

  

        当有数据再次写入的时候,继续紧接着上次写入的地址后写入新的数据,如果数据长度超过缓冲区的长度,写指针重新返回缓冲区的底部重新开始(这是循环缓冲的由来),如图6所示。此时如果有数据读出,读指针做同样的更新。如果没有数据读出,一直有数据写入,可能会出现缓冲区写满的情况,如图7所示。此时如果仍然没有数据读取,继续有数据写入的时候,为了保留新的数据,必须丢弃老的数据,即写指针可能超过读指针,此时,读指针必须和谐指针同步更新,这样才能保证读取的是没有被覆盖的最老的数据,如图8所示。

  

        需要注意的是,读指针在中断过程中也可能被更改,因此,读数据的子程序需要对读指针的更改进行保护,方法是在读数据的时候关闭串行口中断。下面是循环缓冲区接收数据的程序实例。
        FT, 尽然连文本都不能上传,代码只好贴出来吧。
/*
 * FileName:    uart.h
 * Description: header file for SerialPort
 * Author:      SangWei, HUST-CEEE-2004
 * Contact:     swkyer@163.com, swkyer@hotmail.com
 * Date:        2005-09-22
 *
 * Platform:    P89C6102(Philips), KeilC51(ver: 7.20)
 * 
 * (C)All Rights Reserved.
*/    
#ifndef __UART_H__
#define __UART_H__

#define UARTBUFFLEN    64     /* 串口缓冲区64个字节 */

void UartInit(void);
void SendChar(unsigned char ch);
unsigned char IsUartReceived(void);
unsigned char ReadChar(unsigned char idata *buf);

#endif /* __UART_H__ */


/*
 * FileName:    uart.c
 * Description: Implementation of SerialPort
 * Author:      SangWei, HUST-CEEE-2004
 * Contact:     swkyer@163.com, swkyer@hotmail.com
 * Date:        2005-09-22
 * 
 * Platform:    P89C6102(Philips), KeilC51(ver: 7.20)
 * 
 * (C)All Rights Reserved.
*/
#i nclude <intrins.h>
#i nclude "hardware.h"
#i nclude "uart.h"

unsigned char data ramuse;
static unsigned char idata uartbuf;
static unsigned char idata bufwptr, bufrptr;
extern unsigned char xdata uartbuff[UARTBUFFLEN];

/*
 * 初始化串口, 波特率9600
 */
void UartInit(void)
{
 CLR_DOG;
 status = 0;
 bufwptr = 0;     // 写指针
 bufrptr = 0;     // 读指针
 MAX485CTL = 0;     // 接收数据
 PCON = 0x00;     // 设置串口波特率, 时钟频率30MHZ
 T2CON = 0x30;     // 定时器2作为波特率发生器
 SCON = 0x50;     // 模式1
         // n = 65536 - [fosc/baud*32]
         // n = 65536 - 30000000/(19200*32) = 65536 - 49 = 65490 = 0xffd2
         // n = 65536 - 22118400/(19200*32) = 65536 - 36 = 65500 = 0xffdc
#ifdef _DEBUG_AT_HOME
 RCAP2H = 0xff;     
 RCAP2L = 0xb8;     // baud rate 9600
 TH2 = 0xff;
 TL2 = 0xb8;
#else
 RCAP2H = 0xff;     
 RCAP2L = 0x9e;     // baud rate 9600   
 TH2 = 0xff;
 TL2 = 0x9e;
#endif

 IP = 0x10;      // 串口中断优先级高
 REN = 1;
 TI = 0;
 RI = 0;
 TR2 = 1;      // 启动定时器2
 ES0 = 1;      // 使能串口中断

 CLR_DOG;
}

/*
 *  发送一个字节数据
 */
void SendChar(unsigned char ch)
{
 SBUF = ch;
 while(TI == 0);
 TI = 0;
}

/*
 * 判断是否接收到数据,如果没有返回0,如果有,返回数据长度
 */
unsigned char IsUartReceived(void)
{
 unsigned char num;
 
 CLR_DOG;
 EA = 0;       // 关中断
 if(bufwptr == bufrptr)
  num = 0;
 else if(bufwptr > bufrptr)
  num = (bufwptr-bufrptr);
 else // if(bufwptr < bufrptr)
  num = (UARTBUFFLEN-bufwptr+bufrptr);
 EA = 1;
 return num;
}

/*
 * 从缓冲区中读一个字节数据
 * 返回剩下的字节数
 */
unsigned char ReadChar(unsigned char idata *buf)
{
 unsigned char ch, num;

 CLR_DOG;
 USE_ERAM;
 EA = 0;
 if(bufwptr == bufrptr)
 {
  *buf = 0;
  num = 0;
 }
 else if(bufwptr > bufrptr)
 {
  ch = uartbuff[bufrptr];
  *buf = ch;
  bufrptr++;
  num = (bufwptr-bufrptr);
 }
 else // if(bufwptr < bufrptr)
 {
  ch = uartbuff[bufrptr];
  *buf = ch;
  bufrptr++;
  if(bufrptr == UARTBUFFLEN)
   bufrptr = 0;
  num = (UARTBUFFLEN-bufrptr+bufwptr);
 }

 EA = 1;
 return num;
}

/*
 * 串口中断接受
 */
void UartInt(void) interrupt 4 using 1
{          // use eram
 if(RI)
 {
  ES0 = 0;
  ramuse = AUXR;     // 保存进入中断时的ram区间状态
  ramuse &= 0x03;
  AUXR = 0x00;
  uartbuf = SBUF;
  RI = 0;        // 清中断标志
  
  CLR_DOG;
  uartbuff[bufwptr] = uartbuf; // 数据写入缓冲区
  if(bufwptr >= UARTBUFFLEN-1) // 循环缓冲指针
   bufwptr = 0;
  else
   bufwptr++;
  if(bufwptr == bufrptr)   // 未读数据被覆盖,读指针更新到写指针的上一个单元
   bufrptr = bufwptr + 1;

  AUXR = ramuse;
  ES0 = 1;
 }
}

⌨️ 快捷键说明

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