UART实验

文章详细介绍了UART通信的基本概念,包括波特率、帧格式、硬件连接和控制器,并以Exynos4412为例展示了UART控制器的设置和寄存器操作。此外,还讨论了UART编程中的问题和解决方案,如输入输出重定向以及如何使用UART控制LED灯。
摘要由CSDN通过智能技术生成

目录

一、UART

1.1简介

1.2并行通信和串行通信

1.3单工和双工 

1.4波特率

1.5UART帧格式

1.6UART硬件连接

1.7UART控制器

二、Exynos4412的UART控制器

三、UART寄存器 

四、UART编程

五、输入输出重定向

六、使用串口控制LED


一、UART

1.1简介

Universal Asynchronous Receiver Transmitter 即通用异步收发器,是一种通用的串行、异步通信总线该总线有两条数据线,可以实现全双工的发送和接收在嵌入式系统中常用于主机与辅助设备之间的通信。

1.2并行通信和串行通信

1.3单工和双工 

1.4波特率

波特率用于描述UART通信时的通信速度,其单位为bps(bit per second)即每秒钟传送的bit的数量

1.5UART帧格式

串口一般为奇偶校验

偶校验(Parity Check)是一种校验代码传输正确性的方法。根据被传输的一组二进制代码的数位中“1”的个数是奇数或偶数来进行校验。采用奇数的称为奇校验,反之,称为偶校验。采用何种校验是事先规定好的。通常专门设置一个奇偶校验位,用它使这组代码中“1”的个数为奇数或偶数。若用奇校验,则当接收端收到这组代码时,校验“1”的个数是否为奇数,从而确定传输代码的正确性。

奇偶校验_百度百科

为了避免累计误差的出现一次最多发一个字节,异步通信的弊端。

1.6UART硬件连接

1.7UART控制器

一般情况下处理器中都会集成UART控制器,我们使用UART进行通信时候只需对其内部的相

关寄存器进行设置即可。

二、Exynos4412的UART控制器

由于串口信号太弱了,所以加上SP3232EEA芯片来放大这个信号

 

设置引脚功能本质上就是让引脚连接对应的控制器

 这个串口输入输出控制器都有个缓冲区,FIFO形式的发送时只需要将发送内容写入缓冲区就会自动发送,接收时也只需要读取缓冲区内容即可。每个串口缓冲区不一样大,本次使用的是ch2,

串口通信最大频率是4M

串口的波特率是可以编程的

支持红外传输,(无线)

1位或者两位停止位

数据位可以是5-8位,还可以有校验位

 波特率发生器、发送器、接收器、控制单元

 

 

 SOC的频率是1000M,UART是100M,数据通过引脚->移位器->FIFO,FIFO->移位器->引脚实现

发送和接收

CLOCK Source是100M

三、UART寄存器 

tar xvf 出来一个新工程

 ULCON2 = 0000011

回环模式将发送接收短接

 UCON2 = 0101

中断模式:有消息通知CPU

轮询模式:CPU一直在等消息

DMA:自动传送给内存,解放CPU

 AFC:自动流控制,这次实验就是普通的收发暂时不需要

只能读,【1】表示发送的队列是空的【0】表示接收的队列有数据

 波特率的计算方法

 如果还有小数直接四舍五入就行,虽然有一丢误差,但是因为他会重新算所以没到一位就不会有问题。

四、UART编程

#include "exynos_4412.h"

int main()
{
	GPA1.CON = GPA1.CON & (~(0xFF)) | (0x22);
	UART2.ULCON2 = UART2.ULCON2 & (~(0x7F)) | (0x3);
	UART2.UCON2 = UART2.UCON2 & (~(0xF)) | (0x5);
	UART2.UBRDIV2 = 53;
	UART2.UFRACVAL2 = 4;
	while(1)
	{
		UART2.UTXH2 = 'A';
	} 
	return 0;
}

 

#include "exynos_4412.h"

int main()
{
	GPA1.CON = GPA1.CON & (~(0xFF)) | (0x22);
	UART2.ULCON2 = UART2.ULCON2 & (~(0x7F)) | (0x3);
	UART2.UCON2 = UART2.UCON2 & (~(0xF)) | (0x5);
	UART2.UBRDIV2 = 53;
	UART2.UFRACVAL2 = 4;
	while(1)
	{
		UART2.UTXH2 = 'A';
		UART2.UTXH2 = 'B';
		UART2.UTXH2 = 'C';
		UART2.UTXH2 = 'D';
	} 
	return 0;
}

 结果和想的不一样,因为CPU的执行速度是1GHz,而串口速度是115200,CPU速度太快了,我们前一个还没发送完CPU已经送进来好几个了。

#include "exynos_4412.h"

int main()
{
	GPA1.CON = GPA1.CON & (~(0xFF)) | (0x22);
	UART2.ULCON2 = UART2.ULCON2 & (~(0x7F)) | (0x3);
	UART2.UCON2 = UART2.UCON2 & (~(0xF)) | (0x5);
	UART2.UBRDIV2 = 53;
	UART2.UFRACVAL2 = 4;
	while(1)
	{
		while(!(UART2.UTRSTAT2 & (1 << 1)));
		UART2.UTXH2 = 'A';
		while(!(UART2.UTRSTAT2 & (1 << 1)));
		UART2.UTXH2 = 'B';
		while(!(UART2.UTRSTAT2 & (1 << 1)));
		UART2.UTXH2 = 'C';
		while(!(UART2.UTRSTAT2 & (1 << 1)));
		UART2.UTXH2 = 'D';
	} 
	return 0;
}

#include "exynos_4412.h"

void UART_Init(void)
{
	GPA1.CON = GPA1.CON & (~(0xFF)) | (0x22);
	UART2.ULCON2 = UART2.ULCON2 & (~(0x7F)) | (0x3);
	UART2.UCON2 = UART2.UCON2 & (~(0xF)) | (0x5);
	UART2.UBRDIV2 = 53;
	UART2.UFRACVAL2 = 4;
}

void uart_send_byte(char Dat)
{	
	while(!(UART2.UTRSTAT2 & (1 << 1)));
	UART2.UTXH2 = Dat;
}

char uart_recv_byte(void)
{
	char Dat = 0;
	if(UART2.UTRSTAT2 & 1)
	{
		Dat = UART2.URXH2;
		return Dat;
	}
	else
    {
		return 0;
    }
}

int main()
{
    char RecDat = 0;
	UART_Init();
	while(1)
	{
        RecDat = uart_recv_byte();
        if(RecDat == 0)
        {
        
        }
        else
        {
            RecDat = RecDat + 1;
            uart_send_byte(RecDat);
        }
	} 
	return 0;
}

 

 输入什么返回什么加一,以ASCII计算

五、输入输出重定向

#include "exynos_4412.h"

void UART_Init(void)
{
	GPA1.CON = GPA1.CON & (~(0xFF)) | (0x22);
	UART2.ULCON2 = UART2.ULCON2 & (~(0x7F)) | (0x3);
	UART2.UCON2 = UART2.UCON2 & (~(0xF)) | (0x5);
	UART2.UBRDIV2 = 53;
	UART2.UFRACVAL2 = 4;
}

void uart_send_byte(char Dat)
{	
	while(!(UART2.UTRSTAT2 & (1 << 1)));
	UART2.UTXH2 = Dat;
}

char uart_recv_byte(void)
{
	char Dat = 0;
	if(UART2.UTRSTAT2 & 1)
	{
		Dat = UART2.URXH2;
		return Dat;
	}
	else
    {
		return 0;
    }
}

void uart_send_str(char * pstr)
{
    while(*pstr != '\0')
        uart_send_byte(*pstr++);
}

int main()
{
    char RecDat = 0;
	UART_Init();
#if 0
    while(1)
	{
        RecDat = uart_recv_byte();
        if(RecDat == 0)
        {
        
        }
        else
        {
            RecDat = RecDat + 1;
            uart_send_byte(RecDat);
        }
	}
#endif
    while(1)
    {
        uart_send_str("Hello World\n");
    }
	return 0;
}

因为Linux和windows换行不一样    windows要写/r/n 

 我们也可以把printf封装一下直接调用,但是这时的输出和以前的不同,以前的是Linux为我们提供的C库,它将输出重定向到显卡,所以我们能在屏幕上看到,而这个printf是我们自己写的,它重定向到了串口,所以我们使用串口软件连接单片机时能打印出来

#include "exynos_4412.h"

void UART_Init(void)
{
	GPA1.CON = GPA1.CON & (~(0xFF)) | (0x22);
	UART2.ULCON2 = UART2.ULCON2 & (~(0x7F)) | (0x3);
	UART2.UCON2 = UART2.UCON2 & (~(0xF)) | (0x5);
	UART2.UBRDIV2 = 53;
	UART2.UFRACVAL2 = 4;
}

void uart_send_byte(char Dat)
{	
	while(!(UART2.UTRSTAT2 & (1 << 1)));
	UART2.UTXH2 = Dat;
}

char uart_recv_byte(void)
{
	char Dat = 0;
	if(UART2.UTRSTAT2 & 1)
	{
		Dat = UART2.URXH2;
		return Dat;
	}
	else
    {
		return 0;
    }
}

void uart_send_str(char * pstr)
{
    while(*pstr != '\0')
        uart_send_byte(*pstr++);
}

int main()
{
    char RecDat = 0;
	UART_Init();
#if 0
    while(1)
	{
        RecDat = uart_recv_byte();
        if(RecDat == 0)
        {
        
        }
        else
        {
            RecDat = RecDat + 1;
            uart_send_byte(RecDat);
        }
	}
#endif
    while(1)
    {
        printf("Hello World\n");
    }
	return 0;
}

六、使用串口控制LED

#include "exynos_4412.h"

void UART_Init(void)
{
	GPA1.CON = GPA1.CON & (~(0xFF)) | (0x22);
	UART2.ULCON2 = UART2.ULCON2 & (~(0x7F)) | (0x3);
	UART2.UCON2 = UART2.UCON2 & (~(0xF)) | (0x5);
	UART2.UBRDIV2 = 53;
	UART2.UFRACVAL2 = 4;
}

void uart_send_byte(char Dat)
{	
	while(!(UART2.UTRSTAT2 & (1 << 1)));
	UART2.UTXH2 = Dat;
}

char uart_recv_byte(void)
{
	char Dat = 0;
	if(UART2.UTRSTAT2 & 1)
	{
		Dat = UART2.URXH2;
		return Dat;
	}
	else
    {
		return 0;
    }
}

void uart_send_str(char * pstr)
{
    while(*pstr != '\0')
        uart_send_byte(*pstr++);
}

void LED_init(void)
{
	GPX2.CON = GPX2.CON & (~(0xF << 28)) | (0x1 << 28);	
}
unsigned int LED(unsigned int flag)
{
	if(flag == 1)
	{
		GPX2.DAT = GPX2.DAT | (1 << 7);
		return 0;
	}else if(flag == 0)
	{
		GPX2.DAT = GPX2.DAT & (~(1 << 7));
		return 1;
	}
}

int main()
{
    char RecDat = 0;
	UART_Init();
	LED_init();
#if 0
    while(1)
	{
        RecDat = uart_recv_byte();
        if(RecDat == 0)
        {
        
        }
        else
        {
            RecDat = RecDat + 1;
            uart_send_byte(RecDat);
        }
	}
#endif
	unsigned int flag = 1;
    while(1)
    {
		RecDat = uart_recv_byte();
        if(RecDat == 0)
        {
        
        }
        else if(RecDat == '2')
		{
			uart_send_byte(RecDat);
			flag = LED(flag);
		}
    }
	return 0;
}

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宇努力学习

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值