串行通信的基本概念
在通信领域内,有两种通信方式:并行通讯和串行通信
串口的数据传输是以串行的方式进行的。串口在数据通讯中,一次只能传输一个比特的数据。串行数据的传输速度用 bps或波特率 来描述
串行通信设计的常用术语
单工、半双工和全双工:
单工:仅能进行一个方向的数据传送。
半双工:数据可以在两个方向进行传送,但是这种传送绝对不能同时进行。
全双工:数据可以在两个方向进行数据传送。
数据传输率:
每秒传输的二进制位数,单位为bps(bit per second)也称为比特率
异步方式和同步方式:
同步通信方式:所用的数据格式没有起始位、停止位,一次传送的字符个数可变。在传送前,先按照一定的格式将各种信息装配成一个包,该包包括供接收方识别用的同步字符一个或者两个,其后紧跟着要传送的n个字符,再后就是校验字符
异步方式:也称为 起止同步式
硬件流控制:
如果打开串口硬件流控制后,串口A只有在nCTS被激活就才能吧数据发送出去。
当串口A可以接收数据时,激活nRTS
UTRT通信接口功能模块示意图:
编程原理:数据由总线传输过来,进入 发送/接收 寄存器之前,需判断对应寄存器缓存区中的数据是否为满或者空(发送判满、接收判空);
这里由三种方式进行判断:1、利用循环,在寄存器内部实现轮询方式,直到对应寄存器满空标志位为空,在进行 写入/读取 数据,以下编程主要采用该种方式。2、采用异常中断的方式来实现。3、使用PWM方式实现。
由查询原理图和芯片手册了解到可能需要编写的寄存器有(需要原理图和芯片手册请私信):
GPA1CON 0x11400020 //用于设置该接口的复用功能UART_2_RXD和UART_2_TXD
ULCON 0x13820000 //用于设置串口协议的数据位、停止位、奇偶校验位
UBRDIV 0x13820028 //用于设置波特率的整数部分
UFRACVAL 0x1382002c //用于设置波特率的小数部分
UCON 0x13820004 //用于设置串口协议读写工作模式:轮询 or 中断
UTXH/URXH 0x13820020/0x13820024 //寄存器读写缓存区内容
编程阶段
该阶段使用汇编和C语言混编模式,主要代码在C代码实现。
功能说明:实现连接开发板的终端的屏显。键盘输入之后,在终端显示出来。
汇编部分:
.text
b main.c
.end
C部分:
#define GPA1CON *(volatile unsigned int *)0x11400020
#define ULCON *(volatile unsigned int *)0x13820000
#define UBRDIV *(volatile unsigned int *)0x13820028
#define UFRACVAL *(volatile unsigned int *)0x1382002c
#define UCON *(volatile unsigned int *)0x13820004
#define UTRSTAT *(volatile unsigned int *)0x13820010
#define UTXH *(volatile unsigned int *)0x13820020
#define URXH *(volatile unsigned int *)0x13820024
void gpio_init()
{
//设置GPA1_0复用 UART_2_RXD功能,GPA1_1复用 UART_2_TXD功能
// GPA1CON = GPA1CON & ( ~(0xff << 0)) | (0x2 << 0) | (0x2 << 4);
GPA1CON = GPA1CON & ( ~(0xff << 0)) | (0x22 << 0);
}
void uart_init()//初始化串口协议
{
//设置串口协议:数据位(8)、停止位(1)、奇偶校验位(无): 0000011
ULCON |= 0x3;
//设置波特率:115200
// DIV_VAL = (PCLK_UART)/ (bps *16) -1
// = 100MHZ / (115200*16)-1
// = 100000000 / 115200/16-1
// = 53.25
// UBRDIV = 53
// UFRACVAL = 0.25*16 = 4
UBRDIV = 53;
UFRACVAL = 4;
//设置发送和接受数据的 工作模式: 中断或轮询 0101
UCON = 0x05;
}
void uart_send(char ch)
{
// while( UTRSTAT & (0x1 << 1) != 0x2 );
while( !(UTRSTAT & (0x1 << 1)) );//采用轮询方式阻塞等待发送缓存区清空
UTXH = ch;
}
char uart_recv()
{
// while( UTRSTAT & (0x1) != 1);
while( !(UTRSTAT & (0x1)));//阻塞等待
return URXH & 0xff;
}
void send(char *p)
{
while(*p){
uart_send(*p++);
}
}
int main()
{
gpio_init();
uart_init();
send("\r\n")// 发送一个换行符
while(1)
{
send(uart_recv());
}
}
效果:
详细原理讲解请参考:↓↓↓ 这个讲得好