目录
一:UART
1:概念
2:工作模式
3:逻辑电平
4:串口结构图
5:时间的计算
二:寄存器
1:简单的UART传输数据
A:GPHCON--配置引脚
B:GPHUP----使能内部上拉编辑
C: UCON0---设置频率115200
D: ULCON0----数据格式8n1
E:发送数据
A:UTRSTAT0
B:UTXHO--发送数据输缓冲寄存器
F:接收数据
A:UTRSTAT0
B:URXH0 ---接收缓冲区寄存器
三:代码
1:UART的简单实现
S3C2440A通用异步收发器(UART)提供三个独立的异步串行I/O (SIO)端口,每个端口都可以在基于中断或基于dma的模式下工作。换句话说,UART可以生成中断或DMA请求来在CPU和UART之间传输数据。使用系统时钟,UART可以支持高达921.6Kbps的波特率。如果外部设备为UART提供UEXTCLK,则UART可以以更高的速度运行。每个UART信道包含两个64字节的fifo,分别用于接收和发送。
S3C2440A UART包括可编程波特率,红外(IR)发送/接收,一个或两个停止位插入,5位,6位,7位或8位数据宽度和奇偶校验。
每个UART包括波特率发生器、发送器、接收器和控制单元。波特率发生器可以通过PCLK, FCLK/n或UEXTCLK(外部输入时钟)进行时钟。
发射器和接收器包含64字节的fifo和数据移位器。数据被写入FIFO,然后在传输之前复制到传输移位器。然后通过传输数据引脚(TxDn)将数据移出。同时,接收数据从接收数据引脚(RxDn)转移,然后从移位器复制到FIFO。
1:波特率 : 双方约定每一位占用的时间
2:格式 : 数据位, 停止位, 校验位, 流量控制
校验分为奇校验和偶校验, 以前的电解技术没有那么稳定, 使用采用了; 不过现在使用比较少;
数据位+校验位为 " 1"的个数
eg: 数据位为8位--0001 0001 --采用奇校验 使用校验位为1; 3个1所以是奇校验
如果采用偶校验, 校验位为0----2个1就是偶校验
作用 : 串口不仅可以为我们打印调式信息, 还可以连接需要外设模块, 实现之间的通信 (GPS, 蓝牙, mpu6050......)
这个和STM32发送的基本一样详情可以参考我的 : 09:STM32-------USART串口通信+串口数据包
假设2440现在需要向外面的pc端口发送一个数据, 他的工作模式如下
发送 "A" 0x41 0b0100 0001
2440向pc段发送数据
A : 首先逻辑电平是高电平
B : ARM被拉低(开始位)---告诉pc段我要开始发送数据了; 在这里会停留1bit的时间, 也就是我们双方约定的波特率.
C:通过拉低逻辑电平电平的方式传输数据. 每一位停留一个波特率的时间. 一般数据为采用8位
D:在一个数据位发送介绍拉高电平告诉, pc段我们发送完了
pc段读取数据:
在数据位中间的位置开始读取数据
TTL电平传输方式-----我们2440采用的就是这种的传输方式; 当电平高在某一个范围的时候他就会被判定位高电平, 同理在电平低于某一个范围的时候被判定为低电平.
RS232电平传输----我们pc段采用这种方式的传输
2种不同的电平协议是不能相互传输数据的, 我们的2440添加了电平转化芯片或者USB串口芯片.
可以看到我们引脚需要我们的配置, 来把他变为发送和接收引脚. 而不是普通的GPIO口
简单理解:
2440向pc段发送数据:
A:FIFO会向内存中取到需要发送的数据
B:在这个UART单元中FIFO把数据发送到移位器里面去, 移位器通过逐步发送,把数据发送到了pc段.
pc段向2440发送数据:
A:pc段把数据发送给我移位器, 移位器逐步接收.
B:移位器再把数据发送给我FIFO, FIFO, 程序从FIFO把数据取出来写入内存.
可以使用中断或者不断查看标志位的方式来查看数据是否发送完毕.
注意我们使用的发送和接收的是0号, 在下面选择寄存器是也应该选择0号.
可以看到了我们需要把GPH2 和GPH3配置使他为发送和接收引脚, 而不是普通的GPIO口
GPHCON &= ~((3 << 4) | (3 << 6));
GPHCON |= ((2 << 4) | (2 << 6));
GPHUP &= ~((1 << 2) | (1 << 3)); /* 使能内部上拉 */
把GPH2和GPH3的接收引脚上拉
UART块中有三个UART控制寄存器,包括UCONO、UCON1和UCON2。
时钟我们选择默认的PCLK时钟----在上一节中我们调节PCLK的频率为50MHZ
UBRDIVn = (int)(selected clock / (baudrate x 16) ) –1
我们使用我们的FCLK作为我们的时钟源--在汇编中是50MHZ
UBRDIVn=(5000 0000 /(115200*16))-1=26
UBRDIV0 = 26;
我们只需要最简单的实现---所以只有打开发送和接收模式
UCON0 = 0x00000005;
全部代码----实现了频率为11520, 打开接收和发送模式
UCON0 = 0x00000005;
UBRDIV0 = 26;
/*数据格式*/
ULCON0 = 0x00000003; //不能写为这个ULCON0 |= (3 << 1)因为还要关注其他位;/*数据位=8,停止位=1,无奇偶校验 8n1*/
发射机空; 当传输缓冲寄存器没有有效数据要传输且传输移位寄存器为空时,自动设置为1。
0 =不空 1=发射机(传输缓冲区和移位寄存器)空
while ((UTRSTAT0 & (1 << 2)) == 0); //while (!(UTRSTAT0 & (1 << 2)));
在UART块中有三个UART传输缓冲寄存器,包括UTXHO、UTXH1和UTXH2。UTXHn有一个8位的数据用于传输数据。
return URXH0;
全部代码
while ((UTRSTAT0 & (1 << 2)) == 0); //while (!(UTRSTAT0 & (1 << 2)));
UTXH0 = (unsigned char)c;
while ((UTRSTAT0 & (1 << 0)) == 0); //while (!(UTRSTAT0 & (1 << 0)));
在UART块中有三个UART接收缓冲区寄存器,包括URXHO, URXH1和URXH2。URXHn对接收的数据有一个8位的数据。
return URXH0
全部代码
while ((UTRSTAT0 & (1 << 0)) == 0); //while (!(UTRSTAT0 & (1 << 0)));
return URXH0;
全部的代码见---三:代码 1:UART的简单实现
#include "sc2440_so.h"
/*在UART块中有三个UART线路控制寄存器,包括ULCONO、ULCON1和ULCON2。
我们使用的是--ULCONO
*/
//115200 8n1
void UART_init()
{
/*引脚设置*/
GPHCON &= ~((3 << 4) | (3 << 6));
GPHCON |= ((2 << 4) | (2 << 6));
GPHUP &= ~((1 << 2) | (1 << 3)); /* 使能内部上拉 */
/*设置波特率---设置波特率位115200*/
/*
UBRDIVn = (int)(selected clock / (baudrate x 16) ) –1
我们使用我们的FCLK作为我们的时钟源--在汇编中是50MHZ
UBRDIVn=(5000 0000 /(115200*16))-1=26
*/
UCON0 = 0x00000005;
UBRDIV0 = 26;
/*数据格式*/
ULCON0 = 0x00000003; //不能写为这个ULCON0 |= (3 << 1)因为还要关注其他位;/*数据位=8,停止位=1,无奇偶校验 8n1*/
}
int putchar(int c)
{
/*发送数据*/
while ((UTRSTAT0 & (1 << 2)) == 0); //while (!(UTRSTAT0 & (1 << 2)));
UTXH0 = (unsigned char)c;
}
int getchar(void)
{
/*接收数据*/
while ((UTRSTAT0 & (1 << 0)) == 0); //while (!(UTRSTAT0 & (1 << 0)));
return URXH0;
}
int puts(const char* s)
{
while (*s)
{
putchar(*s);
s++;
}
}
#ifndef __UART_H
#define __UART_H
void UART_init();
int putchar(int c);
int getchar(void);
int puts(const char* s);
#endif
#ifndef __SC2440_SO_H
#define __SC2440_SO_H
#define ULCON0 (*((volatile unsigned int*)0x50000000))
#define UCON0 (*((volatile unsigned int*)0x50000004))
#define UBRDIV0 (*((volatile unsigned int*)0x50000028))
#define GPHCON (*((volatile unsigned int*)0x56000070))
#define GPHUP (*((volatile unsigned int*)0x56000078))
#define UFCON0 (*((volatile unsigned int*)0x50000008))
#define UTRSTAT0 (*((volatile unsigned int*)0x50000010))
#define UTXH0 (*((volatile unsigned char*)0x50000020))
#define URXH0 (*((volatile unsigned char*)0x50000024))
#endif
#include "uart.h"
#include "sc2440_so.h"
int main(void)
{
unsigned char c;
UART_init();
puts("Hello, world!\n\r");
while (1)
{
c = getchar();
if (c == '\r')
{
putchar('\n');
}
if (c == '\n')
{
putchar('\r');
}
putchar(c);
}
return 0;
}
分析makefile文件
我们要使用makefile文件交叉编译来生成bin文件
all:
arm-linux-gcc -c -o uart.o uart.c
arm-linux-gcc -c -o main.o main.c
arm-linux-gcc -c -o start.o start.S
arm-linux-ld -Ttext 0 start.o uart.o main.o -o uart.elf
arm-linux-objcopy -O binary -S uart.elf uart.bin
arm-linux-objdump -D uart.elf > uart.dis
clean:
rm *.bin *.o *.elf *.dis
A: 先把所以的c语言和汇编语言全部, 编译为.o文件
B:链接: 这是一个链接命令,用于将三个目标文件(start.o、uart.o、main.o)链接成一个可执行文件(uart.elf)。其中-Ttext 0指定了链接地址的起始地址为0,start.o是程序的入口地址。这个命令会将三个目标文件中的符号解析出来,并将它们放到正确的位置上,生成可执行文件
C:这个命令的作用是将uart.elf文件转换为uart.bin文件。其中,-O binary表示输出格式为二进制文件,-S表示去掉所有的符号信息。这个命令通常用于将可执行文件转换为裸机程序,以便在嵌入式系统中运行。(把连接生成的elf文件转换为单板使用的bin文件)
D:对连接生成的elf文件进行反汇编,调试错误时用。生成.dis文件
1:UART每发送完一个数据发送停止位, 还是发送完想要发送的数据在发送停止位?
根据引用中的定义,UART协议的数据传输包括起始位、数据位和终止位。其中,起始位是低电平,终止位是高电平。在UART发送一段数据时,每个数据字节后面都会跟随一个停止位。停止位的数量取决于UART协议的设置,通常为1个或2个。因此,UART发送一段数据,一共发送的停止位数量为1个或2个,具体取决于UART协议的设置
2:UART发送数据是发送完毕,接收端在读取, 还是一边发送, 接收端一边读取
根据提供的引用内容,UART是一种通用异步接收器/发送器,其主要目的是发送和接收串行数据。在UART发送数据时,数据包以串行方式从发送UART送至接收UART,接收UART以预配置的波特率对数据线进行采样。因此,在UART发送数据时,接收端需要一边接收一边读取数据,否则数据将会丢失