相关作业和资料已上传,请在主页自行查看
UART Universal Asynchronous Receiver Transmitter
通用异步收发器,是一种通用的串行、异步通信总线 该总线有两条数据线,可以实现全双工的发送和接收 在嵌入式系统中常用于主机与辅助设备之间的通信
波特率用于描述UART通信时的通信速度,其单位为 bps(bit per second)即每秒钟传送的bit的数量(不是字节)
规定:空闲状态数据线上状态是高电平
发送前要发送一个信号告诉对方要开始发送了,所以起始位低位
先发高位再发低位
奇偶校验,不能修正错位
串口只能发一个字节,多字节不能连续发送,发完一个需要停止后再发
如何区分发送的是01还是0011
- 通过波特率来区分,双发都要掐表计算(比如发送一个1是1秒)
- 掐表是双方各自掐表,会出现双方掐表的时间不一样(比如一个秒一个0.1秒),解决办法就是要停止掐表,即只能一个一个发
一般情况下处理器中都会集成UART控制器 我们使用UART进行通信时候只需对其内部的相关寄存器进行设置即可
设置引脚功能的实质是让引脚在芯片内部连接到某一个对应的控制器上
接收
(此节只用到部分寄存器)
/*1.将GPA1_0和GPA1_1设置成UART2的接收和发送引脚 GPA1CON[7:0]*/
GPA1.CON = GPA1.CON & (~(0xFF << 0)) | (0x22 << 0);
本次实验数据为8位,停止位1位,不校验,正常(有线)模式
/*2.设置UART2的帧格式 8位数据位 1位停止位 无校验 正常模式 ULCON2[6:0]*/
UART2.ULCON2 = UART2.ULCON2 & (~(0x7F << 0)) | (0x3 << 0);
本次实验只用了部分位
/*3.设置UART2的接收和发送模式为轮询模式 UCON2[3:0]*/
UART2.UCON2 = UART2.UCON2 & (~(0xF << 0)) | (0x5 << 0);
四种工作模式
- 轮寻:cpu不断主动查看FIFO是否有数据来
- 中断:串口控制器去通知CPU
- DMA:直接将接收的数据放到内存中不经过cpu
/*等待发送寄存器为空,即上一个数据已经发送完成 UTRSTAT2[1]*/
while(!(UART2.UTRSTAT2 & (1 << 1)));
//将要发送的数据写入发射寄存器 UTXH2就能发送过去
UART2.UTXH2 = 'A'; //SecureCRT默认只能显示字符不能显示数字
如何设置波特率
/*4.设置UART2的波特率为115200 UBRDIV2/UFRACVAL2*/
UART2.UBRDIV2 = 53;
UART2.UFRACVAL2 = 4;
}
#include "exynos_4412.h"
int main()
{
/*1.将GPA1_0和GPA1_1设置成UART2的接收和发送引脚 GPA1CON[7:0]*/
GPA1.CON = GPA1.CON & (~(0xFF << 0)) | (0x22 << 0);
/*2.设置UART2的帧格式 8位数据位 1位停止位 无校验 正常模式 ULCON2[6:0]*/
UART2.ULCON2 = UART2.ULCON2 & (~(0x7F << 0)) | (0x3 << 0); //7位清零 0111 1111 = ox7f
/*3.设置UART2的接收和发送模式为轮询模式 UCON2[3:0]*/
UART2.UCON2 = UART2.UCON2 &( ~(0xF << 0)) | (0x5 << 0);
/*4.设置UART2的波特率为115200 UBRDIV2/UFRACVAL2*/
UART2.UBRDIV2 = 53; //(100000000 / (115200 x 16))-1 = 53.25
UART2.UFRACVAL2 = 4; // 0.25 X 16 = 4
while(1)
{
//将要发送的数据写入发射寄存器 UTXH2就能发送过去
UART2.UTXH2 = 'A'; //SecureCRT默认只能显示字符不能显示数字
//UART2.UTXH2 = 'B'; //SecureCRT默认只能显示字符不能显示数字
//UART2.UTXH2 = 'C'; //SecureCRT默认只能显示字符不能显示数字
//UART2.UTXH2 = 'D'; //SecureCRT默认只能显示字符不能显示数字
}
return 0;
}
现象:终端循环发送
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0a9bqVUQ-1691459920316)(https://cdn.jsdelivr.net/gh/ybm2002329/mdlmage/202308080953427.png)]
将注释去掉再看现象:没有规律,和发送的数据不一样
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nvFY8aoX-1691459920316)(https://cdn.jsdelivr.net/gh/ybm2002329/mdlmage/202308080953429.png)]
解决办法:通过读取状态寄存器的值来判断是否写入THX中
#include "exynos_4412.h"
void UART_Init(void)
{
/*1.将GPA1_0和GPA1_1设置成UART2的接收和发送引脚 GPA1CON[7:0]*/
GPA1.CON = GPA1.CON & (~(0xFF << 0)) | (0x22 << 0);
/*2.设置UART2的帧格式 8位数据位 1位停止位 无校验 正常模式 ULCON2[6:0]*/
UART2.ULCON2 = UART2.ULCON2 & (~(0x7F << 0)) | (0x3 << 0); //7位清零 0111 1111 = ox7f
/*3.设置UART2的接收和发送模式为轮询模式 UCON2[3:0]*/
UART2.UCON2 = UART2.UCON2 &( ~(0xF << 0)) | (0x5 << 0);
/*4.设置UART2的波特率为115200 UBRDIV2/UFRACVAL2*/
UART2.UBRDIV2 = 53; //(100000000 / (115200 x 16))-1 = 53.25
UART2.UFRACVAL2 = 4; // 0.25 X 16 = 4
}
void UART_Send_Byte(char Dat)
{
/*等待发送寄存器为空,即上一个数据已经发送完 UTRSTAT2[1]*/
while(!(UART2.UTRSTAT2 & (1 << 1))); //这个条件表示这个寄存器第一位的状态
{
//将要发送的数据写入发射寄存器 UTXH2就能发送过去
UART2.UTXH2 = Dat; //SecureCRT默认只能显示字符不能显示数字
}
}
char UART_Rec_Byte(void)
{
char Dat = 0;
/*判断接收寄存器是否接收到了数据 UTRSTAT2[0]*/
if(UART2.UTRSTAT2 & 1) // 0位不需要移动
{
/*从接收寄存器中读取接收到的数据 URXH2*/
Dat = UART2.URXH2;
return Dat;
}
else
return 0;
}
int main()
{
UART_Init();
char RecDat = 0;
while(1)
{
RecDat = UART_Rec_Byte();
if(RecDat == 0)
{
}
else
{
RecDat = RecDat+1;
UART_Send_Byte(RecDat);
}
}
return 0;
}
现象:在键盘输入a会打印b,因为程序写着接收的数据加一
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tOkn5C2b-1691459920317)(https://cdn.jsdelivr.net/gh/ybm2002329/mdlmage/202308080953430.png)]
#include "exynos_4412.h"
void UART_Init(void)
{
/*1.将GPA1_0和GPA1_1设置成UART2的接收和发送引脚 GPA1CON[7:0]*/
GPA1.CON = GPA1.CON & (~(0xFF << 0)) | (0x22 << 0);
/*2.设置UART2的帧格式 8位数据位 1位停止位 无校验 正常模式 ULCON2[6:0]*/
UART2.ULCON2 = UART2.ULCON2 & (~(0x7F << 0)) | (0x3 << 0); //7位清零 0111 1111 = ox7f
/*3.设置UART2的接收和发送模式为轮询模式 UCON2[3:0]*/
UART2.UCON2 = UART2.UCON2 &( ~(0xF << 0)) | (0x5 << 0);
/*4.设置UART2的波特率为115200 UBRDIV2/UFRACVAL2*/
UART2.UBRDIV2 = 53; //(100000000 / (115200 x 16))-1 = 53.25
UART2.UFRACVAL2 = 4; // 0.25 X 16 = 4
}
void UART_Send_Byte(char Dat)
{
/*等待发送寄存器为空,即上一个数据已经发送完 UTRSTAT2[1]*/
while(!(UART2.UTRSTAT2 & (1 << 1))); //这个条件表示这个寄存器第一位的状态
{
//将要发送的数据写入发射寄存器 UTXH2就能发送过去
UART2.UTXH2 = Dat; //SecureCRT默认只能显示字符不能显示数字
}
}
char UART_Rec_Byte(void)
{
char Dat = 0;
/*判断接收寄存器是否接收到了数据 UTRSTAT2[0]*/
if(UART2.UTRSTAT2 & 1) // 0位不需要移动
{
/*从接收寄存器中读取接收到的数据 URXH2*/
Dat = UART2.URXH2;
return Dat;
}
else
return 0;
}
//
//发送字符串
void UART_Send_Str(char * pstr)
{
while(*pstr != '\0')
UART_Send_Byte(*pstr++);
}
int main()
{
UART_Init();
char RecDat = 0;
while(1)
{
UART_Send_Str("Hello World\n");
}c
return 0;
}
printf
函数,已经在资料里面提供不用自己写#include "exynos_4412.h"
void UART_Init(void)
{
/*1.将GPA1_0和GPA1_1设置成UART2的接收和发送引脚 GPA1CON[7:0]*/
GPA1.CON = GPA1.CON & (~(0xFF << 0)) | (0x22 << 0);
/*2.设置UART2的帧格式 8位数据位 1位停止位 无校验 正常模式 ULCON2[6:0]*/
UART2.ULCON2 = UART2.ULCON2 & (~(0x7F << 0)) | (0x3 << 0); //7位清零 0111 1111 = ox7f
/*3.设置UART2的接收和发送模式为轮询模式 UCON2[3:0]*/
UART2.UCON2 = UART2.UCON2 &( ~(0xF << 0)) | (0x5 << 0);
/*4.设置UART2的波特率为115200 UBRDIV2/UFRACVAL2*/
UART2.UBRDIV2 = 53; //(100000000 / (115200 x 16))-1 = 53.25
UART2.UFRACVAL2 = 4; // 0.25 X 16 = 4
}
void UART_Send_Byte(char Dat)
{
/*等待发送寄存器为空,即上一个数据已经发送完 UTRSTAT2[1]*/
while(!(UART2.UTRSTAT2 & (1 << 1))); //这个条件表示这个寄存器第一位的状态
{
//将要发送的数据写入发射寄存器 UTXH2就能发送过去
UART2.UTXH2 = Dat; //SecureCRT默认只能显示字符不能显示数字
}
}
char UART_Rec_Byte(void)
{
char Dat = 0;
/*判断接收寄存器是否接收到了数据 UTRSTAT2[0]*/
if(UART2.UTRSTAT2 & 1) // 0位不需要移动
{
/*从接收寄存器中读取接收到的数据 URXH2*/
Dat = UART2.URXH2;
return Dat;
}
else
return 0;
}
//
//发送字符串
void UART_Send_Str(char * pstr)
{
while(*pstr != '\0')
UART_Send_Byte(*pstr++);
}
int main()
{
UART_Init();
char RecDat = 0;
while(1)
{
printf("你好");
}
return 0;
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EbTEFev3-1691459920318)(https://cdn.jsdelivr.net/gh/ybm2002329/mdlmage/202308080953431.png)]
自己写的printf和c库的输出定向不同
所以有区别的
1.若使用UART协议发送一个字节的数据0x63,画出信号线上的时序图
注:8位数据位、无校验位、一位停止位
2.编程实现电脑远程控制LED状态
注:在终端上输入‘2’,LED2点亮,再次输入‘2’,LED2熄灭… …
#include "exynos_4412.h"
void UART_Init(void)
{
/*1.将GPA1_0和GPA1_1设置成UART2的接收和发送引脚 GPA1CON[7:0]*/
GPA1.CON = GPA1.CON & (~(0xFF << 0)) | (0x22 << 0);
/*2.设置UART2的帧格式 8位数据位 1位停止位 无校验 正常模式 ULCON2[6:0]*/
UART2.ULCON2 = UART2.ULCON2 & (~(0x7F << 0)) | (0x3 << 0); //7位清零 0111 1111 = ox7f
/*3.设置UART2的接收和发送模式为轮询模式 UCON2[3:0]*/
UART2.UCON2 = UART2.UCON2 &( ~(0xF << 0)) | (0x5 << 0);
/*4.设置UART2的波特率为115200 UBRDIV2/UFRACVAL2*/
UART2.UBRDIV2 = 53; //(100000000 / (115200 x 16))-1 = 53.25
UART2.UFRACVAL2 = 4; // 0.25 X 16 = 4
}
void UART_Send_Byte(char Dat)
{
/*等待发送寄存器为空,即上一个数据已经发送完 UTRSTAT2[1]*/
while(!(UART2.UTRSTAT2 & (1 << 1))); //这个条件表示这个寄存器第一位的状态
{
//将要发送的数据写入发射寄存器 UTXH2就能发送过去
UART2.UTXH2 = Dat; //SecureCRT默认只能显示字符不能显示数字
}
}
char UART_Rec_Byte(void)
{
char Dat = 0;
/*判断接收寄存器是否接收到了数据 UTRSTAT2[0]*/
if(UART2.UTRSTAT2 & 1) // 0位不需要移动
{
/*从接收寄存器中读取接收到的数据 URXH2*/
Dat = UART2.URXH2;
return Dat;
}
else
return 0;
}
void LED_Init(void)
{
GPX2.CON = GPX2.CON & (~( 0xF << 28)) | (0X1 << 28);
}
void LED_ON(void)
{
GPX2.DAT = GPX2.DAT | (1 << 7);
}
void LED_OFF(void)
{
GPX2.DAT = GPX2.DAT & (~(1 << 7));
}
//
//发送字符串
void UART_Send_Str(char * pstr)
{
while(*pstr != '\0')
UART_Send_Byte(*pstr++);
}
int main()
{
UART_Init();
LED_Init();
LED_OFF();
char RecDat = 0;
int a = 0;
while(1)
{
RecDat = UART_Rec_Byte();
if(RecDat == '2' && a==0)
{UART_Send_Byte(RecDat);
LED_ON();
a = 1;
}
else if(RecDat == '2' && a ==1 )
{UART_Send_Byte(RecDat);
LED_OFF();
a = 0;
}
else{
UART_Send_Byte(RecDat);
}
}
return 0;
}