怎样用UART与PC通信

电子说

1.3w人已加入

描述

示意图

ATmega168

微控制器通信 - 什么是UART?

微控制器经常发现自己处于具有特定功能的专用电路中,例如测量,监控和控制。但是,有些情况下将微控制器连接到计算机可能非常有益甚至是必要的(例如,设备配置)。有几种方法可以实现PC-Microcontroller通信

通过Wi-Fi(如ESP8266模块)

以太网

USB

虽然这些形式的通信可能允许高数据传输速率,但它们很难使用,大多数微控制器都有另外一种类型的通信,称为UART,它代表通用异步接收器/发送器。

这是一个简单的串行连接,可以是用于以低速发送少量数据,并且使用和实现极其简单。使UART更加便捷的是,有USB转串口转换器可用于允许微控制器通过USB使用虚拟COM端口与PC通信。

串行概述

使用微控制器和计算机的串行通信可包括许多不同的设置,包括奇偶校验和停止位。但是,在本教程中,我们将介绍最简单的串行通信形式,这也是最常见的形式之一。所以我们首先要看的是如何发送串行数据。首先,我们来看看硬件!

微控制器上最简单形式的串行外设是一个美化的移位寄存器,它使用两个独立的I/O引脚来发送数据(TxDn)和接收数据(RxDn)

当需要从设备发送数据时,它会将数据发送到其发送移位寄存器中,然后逐位计时数据,直到所有数据都已发送完毕。当需要读取数据时,接收器首先需要检测是否正在接收某些数据。

一旦满足此条件,接收器就会将数据移入移位寄存器。完成后,可以从接收移位寄存器中读取器件,并以其认为合适的任何方式处理数据。

ATmega168

UART模块的简单框图

UART模块中使用的协议本身(有时称为RS-232)包含有助于数据传输/接收的选项和附加功能。下图显示了典型的UART传输,包括起始位,数据本身,奇偶校验位和停止位。

ATmega168

从ATmega168数据表中获取的图像

IDLE - 如果没有发生传输,则传输线必须保留逻辑1(5V,3.3V等)

起始位 - UART线上的下降沿表示传输即将开始

数据位 - 这些是我们的实际数据位发送,并且位首先发送到最低位(位0,位1 。..位7)

奇偶校验位 - 此可选位可用作错误检查的基本形式具有等于所有位组合的异或(XOR)的值

停止位 - 这是停止传输所必需的并且是逻辑1.有时,可以使用两个停止位,但通常只使用一个

ATmega上的UART

ATmega168上的UART模块非常复杂,因为它允许不同的操作模式(包括同步传输),但我们将配置UART以使用适用于99%基于UART的项目的最常见设置。

时钟源

我们需要配置的第一件事是UART模块的时钟源(这也配置了UART运行的模式) 。由于我们将使用异步传输(时钟不传输,只有数据),我们将使用“正常异步”。为此,我们在UCSRnC寄存器中将UMSEL位设置为0.

ATmega168

ATmega168

奇偶校验位和停止位

由于大多数传输不需要奇偶校验,我们将禁用该位。为此,我们需要将两个UPM位都设置为0,这可以在UCSR寄存器中找到。

ATmega168

对于停止位,我们只会使用一个停止位,通过清除UCSRnB寄存器中的USBS位来完成。

ATmega168

数据大小

UART模块能够以不同的位宽发送数据,但对于大多数项目,我们将使用8位数据大小,因为我们的微控制器是一个8位器件。为此,我们将寄存器UCSRnB和UCSRnC中的UCSZ位的值设置为011。

ATmega168

波特率

在谈到串行通信时,波特率通常是指每秒传输的数据位数,可以认为是连接速度。串行通信的典型波特率包括9600,115200和10417.

对于我们的串行设置,我们将使用9600的波特率(非常常见的波特率)。波特率可以使用下面的公式计算,但是,使用第163-165页上的表格更容易。

ATmega168

由于我们的ATmega168连接到8MHz振荡器,我们可以查看下表,看看我们将UBRR寄存器设置为什么值。

对于9600波特,我们将使用值51.请注意,您的CLKDIV8位可能已设置,如果是这种情况,那么您的波特率可能比您预期的慢8倍。如果是这种情况,请尝试使用UBRR值12而将U2X0设置为开,或使用更高的时钟速度。

ATmega168

启用接收/传输

我们需要设置几个启用位,其他启用位是可选的。我们需要使能的前两位是RXEN和TXEN,它们使能接收器和发送器。

我们可以设置两个中断使能位,这意味着当我们的UART模块完成发送或接收数据时,中断将触发(对实时应用程序有用)。

ATmega168

读/写UART

有趣的是,AVR UART外设对接收和发送寄存器使用相同的I/O地址。当写入UART数据寄存器(UDRn)时,数据被发送到UART发送器移位寄存器,当从UART数据寄存器读取时,返回来自UART接收器的数据。

ATmega168

一些有用的控制信号

一个寄存器UCSR0A可以帮助确定UART的状态模块,因为它有几个状态位。

RXC0,第7位,如果接收缓冲区中有需要读取的数据,则为1

TXC0,第6位,一旦传输将为1已完成

如果发送缓冲区为空,UDRE0,位5将为1

FE0,位4,发出帧错误警告

DOR0,第3位,发出数据溢出警告(当收到的数据太多且接收缓冲区已满时)

当奇偶校验时,UPE0,位2将为1在接收到的字节上检测到错误

ATmega168

一个简单的UART示例

此示例将介绍如何创建一个echo设备,该设备将等待连接的PC向UART线路发送一个字节。一旦检测到,AVR将立即发回相同的字节以回显消息。

/*

* AVR UART.c

*

* Created: 09/01/2018

* Author : RobinLaptop

*/

// These are really useful macros that help to get rid of unreadable bit masking code

#define setBit(reg, bit) (reg = reg | (1 《《 bit))

#define clearBit(reg, bit) (reg = reg & ~(1 《《 bit))

#define toggleBit(reg, bit) (reg = reg ^ (1 《《 bit))

#define clearFlag(reg, bit) (reg = reg | (1 《《 bit))

#include

int main(void)

{

// Initialize Registers

// Configure register UCSRA

setBit(UCSR0A, U2X0); // Double the BRG speed (since I am using a 8MHz crystal which is divided by 8)

clearBit(UCSR0A, MPCM0); // Normal UART communication

// Configure register UCSRB

clearBit(UCSR0B, RXCIE0); // We will not enable the receiver interrupt

clearBit(UCSR0B, TXCIE0); // We will not enable the transmitter interrupt

clearBit(UCSR0B, UDRIE0); // We will not enable the data register empty interrupt

setBit(UCSR0B, RXEN0); // Enable reception

setBit(UCSR0B, TXEN0); // Enable transmission

clearBit(UCSR0B, UCSZ02); // 8 bit character size

// Configure register UCSRC

clearBit(UCSR0C, UMSEL00); // Normal Asynchronous Mode

clearBit(UCSR0C, UMSEL01);

clearBit(UCSR0C, UPM00); // No Parity Bits

clearBit(UCSR0C, UPM01); // No Parity Bits

clearBit(UCSR0C, USBS0); // Use 1 stop bit

setBit(UCSR0C, UCSZ01); // 8 bit character size

setBit(UCSR0C, UCSZ00);

// Configure the baud rate register (this is a combination of both UBRR0L and UBRR0H)

// Despite using an 8MHz crystal my Fosc is 1MHz since the CLK8DIV fuse bit is dividing the clock

// by 8. When I try to change this fuse the AVR locks me out!

UBRR0 = 12;

while (1)

{

// Wait until data has been received

while(!(UCSR0A & (1 《《 RXC0)));

// Now send the same byte back

UDR0 = UDR0;

// Wait until the Data Transmit Register is empty

while(!(UCSR0A & (1 《《 TXC0)));

}

}

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分