ARM实验3 —— UART实验
实验3 UART实验
- 总线相关概念
UART:Universal Asynchronous Receiver and Transmitter (UART) :
通用的异步接收器和发送器/通用的异步串行总线
总线的分类:
按总线的通信方式:
串行总线:数据在总线上发送器一个时钟周期发送一位数据,
接收器一个时钟周期接收一位数据。
并行总线:数据在总线上发送器一个时钟周期发送多位数据,
接收器一个时钟周期接收多位数据。
串行和并行的优缺点
串行:节约资源,传输速度慢 IIC UART SPI CAN 485
并行:浪费资源,传输速度快 LCD屏
数据的的传输方向:
时钟划分:同步总线和异步总线
UART总线的硬件连接:
串口在开发中主要作用:实现开发板和PC端数据的交互, 最大传输距离15米
- UART总线的通信协议
- 分析电路图
SP3232EEN:电平转换芯片,可以将RS232电平转换为TTL电平
或者将TTL电平转换为RS232电平。
SOC引脚默认使用TTL电平:
0V ---》0
3.3V----》1
串口使用RS232电平:
-3 ~ -15V ----》 1
+3 ~ +15 ----》 0
- 分析芯片手册
GPIO章节:设置GPIOD14和GPIOD18引脚位UART功能。
UART章节:中午抽时间自己先翻译一下串口章节。下午继续讲解。
ULCONn:指定串口的数据帧格式。
UCONn:串口控制寄存器:设置串口的发送模式和接收模式,采用轮训模式
UTXHn:发送数据寄存器
URXHn:接收数据寄存器
UBRDIVn:波特率分频值的整数部分
UFRACVAL:波特率分频值的小数部分
本开发板上的UART使用EXT_UCLK作为时钟源,时钟的频率是50MHz。
UBRDIV = 26;
UFRACVAL = 2; 1/2/3都可以。
数据在传输的过程中会造成误差的基类。停止位的作用可以校准时钟。
停止位越多校准的时钟越准确。
UTRSTATn:串口发送和接收状态寄存器
UTRSTAT[1]:判断发送缓冲区是否为空,如果发送缓冲区不为空,
等待发送缓冲区为空之后,在向UTXH中写入数据。
UTRSTAT[0]:判断接收缓冲区是否有有效的数据,如果接收缓冲区没有有效数据,
等待接收缓冲区有效的数据之后,在从URXH中读取数据。
编写代码
main.c
#include "led.h"
#include "pwm.h"
#include "delay.h"
#include "uart0.h"
int main()
{
hal_led_init();
// hal_pwm_init();
hal_uart_init();
Tri_String("UART Test\n");
while(1)
{
Tri_Byte(Recv_Byte()+1);
// printf("pwm test!\n");
// led_flash(500);
// hal_pwm_switch(299, 149, ON);
// delay_ms(1000);
// hal_pwm_switch(299, 149, OFF);
// delay_ms(1000);
}
return 0;
}
uart0.c
#include "uart0.h"
void hal_uart_init(void)
{
// 1. 设置GPIO14引脚和GPIO18引脚位串口功能
GPIOD.ALTFN0 &= (~(0x3 << 28));
GPIOD.ALTFN0 |= (0x1 << 28);
GPIOD.ALTFN1 &= (~(0x3 << 4));
GPIOD.ALTFN1 |= (0x1 << 4);
// 2. 设置串口数据帧的格式:8N1 ULCON
// 正常模式 8位数据位 无校验位,1个停止位
UART0.ULCON &= (~(0x1 << 6));
UART0.ULCON &= (~(0x7 << 3));
UART0.ULCON &= (~(0x1 << 2));
UART0.ULCON |= (0x3 << 0);
// 3. 设置串口的波特率 115200 UBRDIV UFRACVAL
UART0.UBRDIV = 26;
UART0.UFRACVAL = 2;
// 4. 设置串口发送和接收模式:轮询模式 UCON
UART0.UCON &= (~0xF);
UART0.UCON |= 0x5;
}
// 发送一个字节的函数
void Tri_Byte(char ch)
{
// 判断发送缓冲区是否为空,如果发送缓冲区不为空,
//则等待发送缓冲区为空 UTRSTAT[1]
while(!(UART0.UTRSTAT & (1 << 1)));
// 发送数据
UART0.UTXH = ch;
if(ch == '\n')
Tri_Byte('\r');
}
// 接收一个字节的函数
char Recv_Byte(void)
{
char ch;
// 判断接收缓冲区是否有有效数据,如果接收缓冲区没有有效数据,
// 则等待接收缓冲区有有效的数据 UTRSTAT[0]
while(!(UART0.UTRSTAT & (1 << 0)));
//接收数据
ch = UART0.URXH;
return ch;
}
// 发送字符串的函数
void Tri_String(char *str)
{
// 判断是否到字符串的结尾,
while(*str != '\0')
// 如果没有到结尾调用Tri_Byte()函数,一个字节一个字节发送。
Tri_Byte(*str++);
}
uart0.h
#ifndef __UART0_H__
#define __UART0_H__
/*********************** UART ************************/
typedef struct {
unsigned int ULCON;
unsigned int UCON;
unsigned int UFCON;
unsigned int UMCON;
unsigned int UTRSTAT;
unsigned int UERSTAT;
unsigned int UFSTAT;
unsigned int UMSTAT;
unsigned int UTXH;
unsigned int URXH;
unsigned int UBRDIV;
unsigned int UFRACVAL;
unsigned int UINTP;
unsigned int UINTS;
unsigned int UINTM;
}uart;
/*************** UART0 *****************/
#define UART0 ( * (volatile uart *)0xC00A1000 )
/*************** UART1 *****************/
#define UART1 ( * (volatile uart *)0xC00A0000 )
/*************** UART2 *****************/
#define UART2 ( * (volatile uart *)0xC00A2000 )
/*************** UART3 *****************/
#define UART3 ( * (volatile uart *)0xC00A3000 )
/*************** UART4 *****************/
#define UART4 ( * (volatile uart *)0xC00AD000 )
/*************** UART5 *****************/
#define UART5 ( * (volatile uart *)0xC00AF000 )
void hal_uart_init(void);
void Tri_Byte(char ch);
char Recv_Byte(void) ;
void Tri_String(char *str);
#endif
下载调试