UART(Universal Asynchronous Receiver/Transmitter,通用异步收发器)是一种常用的串行通信协议,广泛应用于单片机或各种嵌入式设备之间的通信。本文将详细介绍UART通信的基本原理、工作模式、波特率计算以及常见使用方式,帮助有一定单片机开发能力的人群更好地理解和应用UART通信。
UART通信是一种异步串行通信方式,其基本原理是通过数据线上传输二进制数据位。UART通信系统主要由发送端和接收端两部分组成,它们之间通过数据线进行数据传输。发送端将待发送的数据转换为并行信号,然后通过驱动电路将并行信号转换为串行信号,并通过发送电路将串行信号发送到数据线上。接收端则通过接收电路将数据线上的信号还原为并行信号,再通过解码电路将并行信号转换为原始数据位。
UART通信采用异步通信方式,即发送端和接收端之间通过数据线进行数据传输。在异步通信中,发送端和接收端不需要同时处于激活状态,而是通过起始位和停止位来标识数据帧的开始和结束。具体来说,当发送端产生起始位后,发送一个数据位;然后等待接收端的起始位,如果接收到起始位,则继续发送下一个数据位;如果没有接收到起始位,则认为数据帧传输失败。同样,当接收端产生停止位后,发送一个校验位;然后等待发送端的停止位,如果接收到停止位,则认为数据帧传输成功。
波特率表示单位时间内通过线路传输的二进制数据的位数,通常用bps(bits per second)表示。例如,如果波特率为9600bps,则每秒钟可以传输9600个比特位的数据。
串口传输数据的波特率是单片机的时钟系统来产生的,因此它和单片机的系统时钟存在算式关系。
波特率= (16 * 时钟频率) / (32 * 采样时间) + (1 * 时钟频率) / (32 * 采样时间) - (1 * 时钟频率) / (64 * 采样时间)
其中,采样时间指从上一次起始位到本次起始位之间的时间间隔。例如,如果采样时间为10ns,则波特率为9600bps。
常见的波特率有2400、4800、9600、19200、38400、57600、115200……它们都可是2400的整数倍,因此不同的波特率可以通过分频器来产生。现在的单片机虽然都有着不同的频率,常见的有32MHz、48MHz和144MHz,通常它们都会有一个外部系统时钟为单片机的外围设备提供基础时钟频率(如1MHz),UART产生波特率也是从该时钟产生时钟信号。
需要注意的是,在实际使用中,时钟频率可能会受到一些因素的影响,如晶振漂移、电源噪声等。因此,为了保证数据传输的正确性和可靠性,建议在设计UART通信系统时使用外部晶振或时钟发生器,并对其进行校准和补偿。
在UART异步通信中,停止位用于表示数据帧的结束。停止位可以是1个或2个比特位。当停止位为1个比特位时,每个数据字节的后面都添加一个额外的时间间隔,以补偿时钟抖动和其他因素引起的误差。例如,如果波特率为9600bps,则每个字节的时间间隔为4ms,因此每个停止位的时间间隔为4ms / 8 = 0.5ms。
当停止位为2个比特位时,每个数据字节的后面都添加两个额外的时间间隔,即每个字节的时间间隔为4ms / (8 + 4) = 0.3125ms。这种模式适用于需要更高精度的数据传输场景。
奇偶校验是一种常用的错误检测方法,可以检测数据传输过程中的错误和丢失。在UART通信中,可以通过设置奇偶校验位来提高数据传输的正确性和可靠性。
需要注意的是,奇偶校验位只能检测数据传输过程中的错误和丢失,而不能保证数据的完整性和正确性。因此,在使用UART通信时,还需要采取其他措施来确保数据传输的正确性和可靠性。
前面我们讲过,UART通信就是把一个字节的数据拆分成若干bit位,然后一个bit一个bit的发送。当一个字节的数据被送进UART发送器后,这个字节被转换成bit位,UART发送这个字节后还要产生停止位,此时UART发送器已经空闲,可以继续发送下一个字节。通常UART发送器发送完一个字节后会产生一个空闲状态,轮询式发送就是等待这个空闲状态并发送下一个字节。UART接收也是如此,UART接收器收完一个字节并收到停止位信号时,就会向单片机的UART数据寄存器保存刚收到的数据,并产生一个收到标志位,轮询该标志位就可以接收到该字节数据。
但是在单片机系统中经常不止UART收发应用,这时就要用到中断收发。通常单片机的UART收发都有RX收到中断和TX完毕中断。中断发送时,UART发送器是空闲状态,此时往发送器里面写入第一个字节,该字节传输完毕后产生TX完毕中断,在TX完毕中断的服务函数中再填入后续字节并产生下一个中断,最后直到把需要传输的字节都传完为止。中断接收时,UART接收器收到字节后会产生RX收到中断,在RX收到中断服务函数中读取收到的字节,每次中断时都读取收到的字节。
在很多单片机系统中,都会提供UART Read和UART Write这样的接口函数。一些高级的单片机甚至还有UART Read Callback和UART Write Callback这样的回调函数来收发数据。通常很多单片机的数据处理能力相对UART通信来说要快得多,因此像采用上述接口函数的单片机系统都使用了数据缓存来辅助UART收发。常见的UART收发方式有这几种:
数据队列(Queue)收发:
这种方式适合大多数单片机,只要有中断就行。使用UART Write发送数据时,数据并不是直接写入到UART发送器,而是放进了一个环形缓冲区中。然后在UART TX发送完毕中断服务函数中读取环形缓冲区并把读到的字节送入UART发送器,然后等待TX发送完毕中断服务函数再次执行时送入下一个字节,直到把环形缓冲区的数据送完为止。环形缓冲区通常有一个标记头和尾的变量,只要头和尾的变量值不相等就说明缓冲区有数据。使用UART Read接收数据时,也不是直接从UART接收器中获取数据,而是从环形缓冲区中获取数据。UART RX收到中断服务函数中把UART接收器收到的字节送进环形缓冲区,单片机执行UART Read时获取到的数据是环形缓冲区的数据,这样可以保证单片机程序不用一直等待UART接收器。这种设计的优点是可以有效地处理实时数据,避免了数据的丢失。但是,如果Queue的大小设置不当,可能会导致数据的溢出。因此,我们需要根据实际的应用场景来合理地设置Queue的大小。
带硬件FIFO的UART收发
很多先进的单片机的UART收发用上了硬件FIFO。没有硬件FIFO的单片机在收发数据时每收发一个字节就要执行一次中断函数,在高波特率通信时单片机会频繁进入中断,从而影响单片机主任务的处理。而硬件FIFO则可以缓解这种矛盾。例如单片机的UART FIFO是16字节,单片机在发送数据时一次最多可以传输16字节数据,等16字节数据发送完毕后才产生UART TX发送完毕中断。接收数据时通常是“半满”中断和“超时”中断,即接收FIFO中的字节数超过8字节,或者接收FIFO不为空但是超过1字节的时间内没有收到新的字节数据,产生一次UART RX接收中断。通常带硬件FIFO的UART会和数据队列的方式相结合使用,在高波特率通信下传输效率更高。
带DMA的UART收发
DMA(Direct Memory Access)是一种可以将计算机的某个存储区域直接映射到内存地址空间的技术,从而实现对内存和其他外设的统一访问。当UART接收到数据时,数据会被直接写入到DMA控制的内存区域中,然后触发中断。在中断服务程序中,我们可以从DMA控制的内存区域中取出数据,进行必要的处理,然后再通过UART发送出去。
使用DMA进行UART传输对连续多条数据的传输帮助特别大,例如前面提到的UART Read Callback和UART Write Callback回调函数的方式。连续发送多条数据流时,可以把数据流放在单片机的多个不同的缓冲区,然后DMA直接指向缓冲区地址,待DMA传输完毕后产生UART Write Callback,然后在UART Write Callback中把DMA指向下一个缓冲区地址。接收数据时也可以预约一个接收缓冲区,DMA传输的数据传输到该缓冲区,传输满了后产生UART Read Callback再指向下一个接收缓冲区,同时可以让单片机主程序处理已收满数据的缓冲区的内容。
本文详细介绍了UART通信的基本原理、波特率计算、工作模式以及常见的使用方式,帮助有一定单片机开发能力的人群更好地理解和应用UART通信。掌握UART通信技术,可以为单片机控制系统的设计和应用带来很大的便利。