目录
一、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;
}