在通信领域,有两种数据通信方式:并行通信,和串行通信
1、串行传输
优点:使用的数据线少,在远距离通信中可以节约通信成本。
缺点:因为每次只能传输一位数据,所以传输速度比较低。
2、并行传输
优点:因为可以多位数据一起传输,所以传输速度很快。
缺点:数据有多少位,就要用多少数据线,所以需要大量的数据线,成本很高。使用场合
串口的数据传输是以串行方式进行的。串口在数据通信中,一次只传输一个比特数据,串行数据的传输速度用bps或者波特率来描述。
** 1)所有的数据没有其实位和停止位,一次传送的字符个数可变。在传送前,按照一定的格式将各种信息装配成一包,该包包括供接收识别用的同步字符一个或两个,其后紧跟着要传送的n个字符,再后就是校验字符。
2)在约定的通信速率下,发送端和接收端的时钟频率信号和相位始终保持一致(同步),这样保证了通信双方在放松和接受数据时完全一致的定时关系;
3)同步通信把许多字符组成一个信息组(帧),每帧的开始用同步字符来指示,一次通信只能传送一帧信息,在传输数据的同时还需要传输时钟信号,以便接收方可以同时钟信号来确定每个信息位。
4)同步通信的优点时传送信息的位数几乎不受限制,一次通信传输的数据有几十到几千字节,通信效率较高。同步通信的缺点时要求通信中始终保持精确的同步时钟,即发送时钟和接收时钟要严格的同步,常用的做法时两个设备使用同一时钟源。**
1)异步通信,以字符为单位进行传输的,字符之间没有固定的时间间隔要求,而每个字符中的各位以固定的时间传送。
2)在异步通信中,收发双方取得同步是通过在字符格式中设置 起始位和停止位得方法来实现得;具体来说就是在字符正式发送之前,发送器先发送一个起始位,然后发送有效字符位,在字符结束时再发送一个停止位,起始位至停止位构成一帧。停止位和空闲位都是高电平(逻辑值为1),这样保证了起始位开始处一定会有一个下降沿,由此可以标志一个字符传输的起始。而根据起始位和停止位也就很容易的实现字符的界定和同步。
3)显然,采用异步通信时,发送端和接收端可以由各自的时钟来控制数据的收发,这两个时钟源彼此独立,可以互不干扰。
TCP/IP详解1里面对帧有描述,它是一个链路层的PDU,PDU的意思是协议数据单元;简单来讲就是具有特定数据格式的数据包,这个数据包不单单包含数据。也可能包含一些非数据的内容,而这部分内容由不同的协议各自约定;在TCP/IP的网络层中PDU被叫做分组,而传输层中PDU叫段;
简单来讲,帧就是包含数据和特定格式的数据包;

(1)起始位:起始位必须是持续一个比特时间的逻辑0电平,标志传输一个字符的开始,接收方可用起始位使自己的接收时钟与发送方的数据同步。
(2)数据位:数据位紧跟在起始位之后,是通信中的真正有效信息。数据位的位数可以由通信双方共同约定,一般可以是5位、7位或8位,标准的ASCII码是0127(7位),扩展的ASCII码是0255(8位)。传输数据时先传送字符的低位,后传送字符的高位。
(3)奇偶校验位:奇偶校验位仅占一位,用于进行奇校验或偶校验,奇偶检验位不是必须有的。如果是奇校验,需要保证传输的数据总共有奇数个逻辑高位;如果是偶校验,需要保证传输的数据总共有偶数个逻辑高位。
举例来说,假设传输的数据位为01001100,如果是奇校验,则奇校验位为0(要确保总共有奇数个1),如果是偶校验,则偶校验位为1(要确保总共有偶数个1)。
由此可见,奇偶校验位仅是对数据进行简单的置逻辑高位或逻辑低位,不会对数据进行实质的判断,这样做的好处是接收设备能够知道一个位的状态,有可能判断是否有噪声干扰了通信以及传输的数据是否同步。
(4)停止位:停止位可以是是1位、1.5位或2位,可以由软件设定。它一定是逻辑1电平,标志着传输一个字符的结束。
(5)空闲位:空闲位是指从一个字符的停止位结束到下一个字符的起始位开始,表示线路处于空闲状态,必须由高电平来填充。
数据发送过程
清楚了异步通信的数据格式之后,就可以按照指定的数据格式发送数据了,发送数据的具体步骤如下:
(1)初始化后或者没有数据需要发送时,发送端输出逻辑1,可以有任意数量的空闲位。
(2)当需要发送数据时,发送端首先输出逻辑0,作为起始位。
(3)接着就可以开始输出数据位了,发送端首先输出数据的最低位D0,然后是D1,最后是数据的最高位。
(4)如果设有奇偶检验位,发送端输出检验位。
(5)最后,发送端输出停止位(逻辑1)。
(6)如果没有信息需要发送,发送端输出逻辑1(空闲位),如果有信息需要发送,则转入步骤(2)。
数据接收过程
在异步通信中,接收端以接收时钟和波特率因子决定每一位的时间长度。下面以波特率因子等于16(接收时钟每16个时钟周期使接收移位寄存器移位一次)为例来说明。
(1)开始通信,信号线为空闲(逻辑1),当检测到由1到0的跳变时,开始对接收时钟计数。
(2)当计到8个时钟的时候,对输入信号进行检测,若仍然为低电平,则确认这是起始位,而不是干扰信号。
(3)接收端检测到起始位后,隔16个接收时钟对输入信号检测一次,把对应的值作为D0位数据。
(4)再隔16个接收时钟,对输入信号检测一次,把对应的值作为D1位数据,直到全部数据位都输入。
(5)检验奇偶检验位。
(6)接收到规定的数据位个数和校验位之后,通信接口电路希望收到停止位(逻辑1),若此时未收到逻辑1,说明出现了错误,在状态寄存器中置“帧错误”标志;若没有错误,对全部数据位进行奇偶校验,无校验错时,把数据位从移位寄存器中取出送至数据输入寄存器,若校验错,在状态寄存器中置“奇偶错”标志。
(7)本帧信息全部接收完,把线路上出现的高电平作为空闲位。
(8)当信号再次变为低时,开始进入下一帧的检测。
以上就是异步通信中数据发送和接收的全过程了。
总结:简单来说,起止式同步:
(1)应该有起止位和停止位,及数据位,可以有校验位可以没有;
(2)起始位电平为低电平(触发条件为检测到下降沿,且在接收移位寄存器约定的移位时钟周期的一半仍然是低电平);
(3)接收移位寄存器约定的移位时钟周期取决于波特率因子两者相等;
(4)空闲位或停止位电平为高电平;
(5)传输时从每个字符的低位到高位传输,串口通信传输的是字符;
(6)帧的大小在传输开始之前已经约定好;
(7)当一帧传输完成后,如果置为高电平说明后面没有紧跟着要继续传输的下一帧这个时候是空闲状态;若是置为0,那么后面可能紧继续传输的下一帧,但是也可能是
(8)起始位可以使得自己的接收时钟和发送方的时钟数据同步;过程大致就是,当发送方检测出现起始位的时候,将时钟清零,重新开始时钟计数,而此时接收方检测到起始位同样将时钟清零,然后重新开始时钟计数从而实现时钟同步;
(9)停止位标志着一帧数据的结束,同时位起始位提供一个出现下降沿的机会
(1)引脚复用控制寄存器;因为一个引脚通常具有多种功能,当我们要使用某个引脚功能的时候使能相应位即可;引脚复用控制寄存器一般名为GPxxCON;
(2)UART线路控制寄存器;这个寄存器用来设置串口的通信协议,如模式是正常模式还是红外模式,其中红外模式的描述是检测到为低电平需要检测3/16的脉冲周期,校验位是无校验还是奇偶校验,停止位长度,数据为长度;一般设置为正常模式,无校验,停止位长度1位,数据为长度8位;UART线路控制寄存器一般名为;ULCONn
(3)波特分频寄存器;一般名为UBRDIVn和UFRACVALn寄存器,前者和整数部分有关,后者跟小数部分有关;
参照数据手册:UART典型的工作频率在时钟管理单元一般会有描述,假为设100MHZ,SCL_UART即为100;,假设波特率我们规定为115200;
DIV_VAL = (SCLK_UART/(bps x 16)) - 1;
DIV_VAL=(100/(115200X16))-1
DIV_VAL=53.25
UBRDIVn = int(DIV_VAL) = 53
UFRACVALn/16=0.25
UFRACVALn = 0.25*16 = 4
(4)UART模式控制寄存器;这个寄存器可以设置传输模式和发送模式,还有超时使能,中断类型等等;一般设置只设置传输模式和发送模式,设置为 Interrupt request or polling mode;UART模式控制寄存器一般名为UCON
(5)硬件流控制寄存器,,一般明为UMCONn,和UMSTATn;这两个寄存器分别控制的是nRTS,和nCTS;其中UMCONn默认是自动控制nRTS;
nRTS:用于指示本设备可以接收数据,nRTS低电平有效,说明本设备可以接收数据;
nCTS:用于判断是否可以向对方发送数据,nCTS低电平有效,低电平可以向对方发送数据
具体情况参照芯片手册;
(6)FIFO控制寄存器:选择开启或关闭FIFO模式;及其设置FIFO的触发条件;FIFO控制寄存器一般名为:UFCONn
(7)串口传输状态寄存器: UTRSTATn,作用是检查缓冲区的状态
(8)发送寄存器UTXH,接收寄存器URXH:作用是发送数据和接收数据
下面部分的代码可能有问题,没有实验过;
(1)引脚复用寄存器:GPA1CON


(2)串口线路控制寄存器:ULCON2

(3)设置波特率的寄存器:UBRDIV2和UFRACVAL2


(4)串口控制寄存器:UCON2


(5)串口传输状态寄存器: UTRSTAT2


(6)发送寄存器UTXH,接收寄存器URXH

其他寄存器值没修改,直接用默认值即可
/*
* 串口uart编程:
* 1、在目标板上找到 串口(CON7)
* 2、在原理图中,找到cpu上的引脚 (GPA1_0 和 GPA1_1)
* 3、分析原理图, GPA1_0 复用 UART_RXD接收端, GPA1_1复用 UART_TXD发送端
* 4、查看芯片手册:
* 1、配置引脚复用的功能(GPA1CON)
* 2、设置串口协议: 波特率,数据位,停止位,校验位,(数据流控位未设置)
* 3、查看串口数据发送和接受的原理图
* 4、数据发送
* 5、数据接受
* */
#include
#define GPA1CON *(volatile unsigned int *)0x11400020 //volatile声明这个变量是容易改变的,每次需要从内存中存取
#define ULCON2 *(volatile unsigned int *)0x13820000
#define UCON2 *(volatile unsigned int *)0x13820004
#define UBRDIV2 *(volatile unsigned int *)0x13820028
#define UFRACVAL2 *(volatile unsigned int *)0x1382002c
#define UTRSTAT2 *(volatile unsigned int *)0x13820010
#define UTxH2 *(volatile unsigned int *)0x13820020
void uart_init()
{
//1、设置引脚复用串口的接受和发送功能: GPA1_0 复用UART_2_RXD,GPA1_1复用UART_2_TXD
GPA1CON2 = GPA1CON2 & ( ~(0xff << 0)) | (0x22 << 0);
//2、设置串口的通信协议:数据位8bit、停止位1个、无校验。
ULCON2 = ULCON2 &(~(0x7f << 0)) | (0x3 << 0);
//3、设置串口通信协议:波特率 115200
// DIV_VAL = (SCLK_UART)/ (bps * 16) -1
// = 100*10^6 / (115200 * 16) - 1
// = 53.25
// UBRDIV2 = int(DIV_VAL) = 53
// UFRACVAL2 = 0.25*16 = 4
UBRDIV2 = 53;
UFRACVAL2 = 4;
//4、设置串口接受数据或者发送数据的工作方式
UCON2 = UCON2 & (~(0xFFFFFF << 0)) | (0x5 << 0);
}
void uart_sendCh(char ch)
{
//循环的方式判断,发送缓冲区是否有数据,如果有数据,就意味着上条数据没发完,因此必须循环等待
while( (UTRSTAT2 & (0x1 << 1) ) == 0 );
//当发送缓冲区为空时,将新的代发数据写入 发送缓冲区寄存器
UTxH2 = ch;
}
void delay()
{
int i, j;
for (i = 0; i < 1000; i++){
for(j = 0; j < 10000; j++);
}
}
int main(int argc, char *argv[])
{
uart_init();
while(1){
uart_sendCh('a');
delay();
}
}

In FIFO mode, all bytes of Buffer Register are used as FIFO register.
In non-FIFO mode, only 1 byte of Buffer Register is used as Holding register.
这句话很关键
(1)GPA1CON:引脚复用
(3)ULCONn:协议设置
(4)UCONn:设置传输模式
(5)UFCONn:设置FIFO模式



(6)UBRDIVn和UFRACVALn:设置波特率
(7)UFSTATn:返回FIFO的状态

(9)发送寄存器UTXH,接收寄存器URXH
/*
* 串口uart编程:
* 1、在目标板上找到 串口(CON7)
* 2、在原理图中,找到cpu上的引脚 (GPA1_0 和 GPA1_1)
* 3、分析原理图, GPA1_0 复用 UART_RXD接收端, GPA1_1复用 UART_TXD发送端
* 4、查看芯片手册:
* 1、配置引脚复用的功能(GPA1CON)
* 2、设置串口协议: 波特率,数据位,停止位,校验位,(数据流控位未设置)
* 3、查看串口数据发送和接受的原理图
* 4、数据发送
* 5、数据接受
* */
#include
#define GPA1CON *(volatile unsigned int *)0x11400020 //volatile声明这个变量是容易改变的,每次需要从内存中存取
#define ULCON2 *(volatile unsigned int *)0x13820000
#define UCON2 *(volatile unsigned int *)0x13820004
#define UFCON2 *(volatile unsigned int *)0x13820008
#define UBRDIV2 *(volatile unsigned int *)0x13820028
#define UFRACVAL2 *(volatile unsigned int *)0x1382002c
#define UFSTAT2 *(volatile unsigned int *)0x13820018
#define UTxH2 *(volatile unsigned int *)0x13820020
void uart_init()
{
//1、设置引脚复用串口的接受和发送功能: GPA1_0 复用UART_2_RXD,GPA1_1复用UART_2_TXD
GPA1CON2 = GPA1CON2 & ( ~(0xff << 0)) | (0x22 << 0);
//2、设置串口的通信协议:数据位8bit、停止位1个、无校验。
ULCON2 = ULCON2 &(~(0x7f << 0)) | (0x3 << 0);
//3、设置串口通信协议:波特率 115200
// DIV_VAL = (SCLK_UART)/ (bps * 16) -1
// = 100*10^6 / (115200 * 16) - 1
// = 53.25
// UBRDIV2 = int(DIV_VAL) = 53
// UFRACVAL2 = 0.25*16 = 4
UBRDIV2 = 53;
UFRACVAL2 = 4;
//4.设置串口接受数据或者发送数据的工作方式
UCON2 = UCON2 & (~(0xFFFFFF << 0)) | (0x85 << 0);
UFCON2=UFCON&(~(0X7FF<<0))|(0x771<<0);
}
void uart_sendCh(char ch)
{
//当FIFO没满就装数据进FIFO
if(UFSTAT2&(0x1<<24)==0)
UTxH2 = ch;
}
void delay()
{
int i, j;
for (i = 0; i < 1000; i++){
for(j = 0; j < 10000; j++);
}
}
int main(int argc, char *argv[])
{
uart_init();
while(1){
uart_sendCh('a');
delay();
}
}