中级会员
- 积分
- 254
- 金钱
- 254
- 注册时间
- 2020-3-22
- 在线时间
- 35 小时
|
本帖最后由 YOKI 于 2020-8-19 23:54 编辑
/********************************************/
时间 :2020/07/10/
作者 :YOKI
导师 :正点原子 左忠凯
硬件 :正点原子 ALPHA I.MX LINUX 开发板
/*******************************************/
UART基本串口实验:
学习到现在,我们知道在学习一个新外设时首先都是遵循下列流程:
1、硬件原理图
2、寄存器功能学习
3、引脚复用 和功能设置
首先从底板原理图着手,在原理图中我们可以找到USART 部分,根据原理图可以知道,
开发板上通过USB口和CH340 电平转换芯片将USB电平信号转换为TTL逻辑电平信号,
TXD和RXD通过两个模拟开关与UART1_TXD和UART1_RXD(串口1)连接。
再来看寄存器,
UARTx_URXD 寄存器 bit0-bit7 用于存放接收到的数据,
UARTx_UTXD 寄存器 bit0-bit7 用于将要发送的数据。
UARTx_UCR1 串口控制寄存器1
bit0 : UARTEN UART 使能位,写1使能,写0关断。
bit14: ADBR 自动波特率检测位,写 0 关闭,写 1 开启。
bit15:ADEN 自动波特率检测中断使能位,当自动波特率检测完成时产生/不产生中断。
自动波特率检测是通过检测 ASCII "A"/ "a" 来实现的,这个功能与 UARTx_USR2 的bit15 ADET有关。
/**本例程未使用自动波特率检测功能,因此 UARTx_UCR1 bit14:ADBR 写 0 **/
UARTx_UCR2 串口控制寄存器2
bit0 : SRST UART 软件复位 写 0 复位。
//与 UARTx_UTS bit0 SOFTRST 配合使用,当 软件复位激活时 UARTx_UTS bit0 为 1 。
bit1 : RXEN UART接收使能, 写 1 使能。
bit2 : TXEN UART发送使能, 写 1 使能。
bit5 : WS 数据长度设置位, 为0:7位数据,为1:8位数据(不包括起始位、停止位、校验位)
bit6 : STPB 数据停止位长度设置位, 为0:1位停止位,为1:2位停止位。
bit7 : PREN 奇偶校验设置位 为0:偶校验,为1:奇校验。
bit8 : PROE 校验使能位 为0关闭,为1使能。
UARTx_UCR3 串口控制寄存器3
bit2 : RXDMUXSEL UART 复用选择位,由于芯片的 RXD引脚是采用复用方式的,所以这一位必须 写1。
UARTx_USR2 UART状态寄存器2
bit0 : 串口数据 接收完成 标志位,为"1"表示接收到数据,为"0"表示 未接收到数据。
bit3 : 串口数据 发送完成 标志位,为"1"表示数据发送完成,为"0"表示数据发送未完成。
UARTx_UFCR 串口FIFO控制寄存器(FIFO: 队列先进先出 )
bit7-bit9: RFDIV 波特率采样时钟分频器设置位
UARTx_UBIR 波特率(BRM) 设置寄存器 (分子)
UARTx_UBMR 波特率(BRM) 设置寄存器 (分母)
UART时钟:
UART的有2个时钟源
1、来自 PLL3(480Mhz) 经过 6分频 获得,也就是说,UART的时钟频率为 480Mhz/6 = 80 Mhz (参考CCM章节 时钟树)
2、来自外部晶振 OSC 24M
时钟源选择由 CSCDR1寄存器 bit6: UART_CLK_SEL UART时钟选择位控制,通常设置为80Mhz,
bit6: UART_CLK_SEL 为0:PLL3(即为80Mhz), 通常设置为80Mhz
为1:OSC_CLK(晶振频率 24Mhz) 。
在最终输入UART前,可以再一次分频
CSCDR1寄存器 bit0-bit5: UART_CLK_PODF 为 000000 1分频 即80Mhz ,111111 2^6分频 。
UARTx_UFCR 寄存器的 bit7-bit9: RFDIV 就是对输入的 UART 的 80Mhz时钟进行再一次分频 。
UART波特率设置:
根据参考手册,I.MX6ULL 的波特率设置公式如下:
Ref_freq
baud Rate(波特率) = ————————————————————————
{16*(UBMR+1)/(UBIR+1)}
Ref_freq: Module_clock(UART_CLK) 经过 RFDIV 分频器分频后的时钟频率
UBIR: UARTx_UBIR 寄存器 的值 (分子)
UBMR: UARTx_UBMR 寄存器 的值 (分母)
当 UARTx_UFCR寄存器的 bit7-bit9: RFDIV = 101 (设置为1分频) 时:
Ref_freq = UART_CLK = (PLL3)/6 = 480Mhz/6 =80Mhz
对上述公式进行整理:
Ref_freq (UBMR+1)*最大公约数
————————————— = ——————————————
16*baud Rate(波特率) (UBIR+1) *最大公约数
所以知道 UART 的时钟频率,以及设置的目标波特率值可以计算出 UBIR 和 UBMR 寄存器的值
其本质是对分数进行约分 (通过求最大公约(因)数可以计算)
欧几里德算法 : 1、若A(k)>=B(K),余数 R(k)=A(k)%B(k);(K表示循环次数)
(求最大公约数) 2、若R(k)!=0,A(k+1)=B,B(k+1)=R(k),k=k+1; R(k)=A(k)%B(k); (循环次数+1)
3、若R(k)==0,则说明 A(k)=B(k)=最大公约数
使用欧几里德算法(又称辗转相除法)条件:分子>分母 否则余数为0,不能迭代。
欧几里德算法 推导图:
分子/分母~~余数
A/B~~R(1),R(1)!=0;
==> B/(R1)~~R(2),R(2)!=0;
==> R(1)/R(2)~~R(3),R(3)!=0;
...
==> R(n-3)/R(n-2)~~R(n-1),R(n-1)!=0;
==> R(n-2)/R(n-1)~~R(n),R(n)==0;
R(n-2)/R(n-1)的余数为0,说明此时R(n-2)==R(n-1);
R(n-1)就是最大公约数
程序编写:
1、初始化程序编写
1.1、I/O 复用及电气属性设置:
回顾一下I/O复用函数和电气属性设置函数的用法
I/O复用函数
IOMUXC_SetPinMux(IOMUXC_UART1_TX_DATA_UART1_TX,0); /* 复用为UART1_TX */
IOMUXC_SetPinMux(IOMUXC_UART1_RX_DATA_UART1_RX,0); /* 复用为UART1_RX */
IOMUXC_SetPinMux() 函数有6个参数
官方文件fsl_iomuxc.h 头文件中使用宏定义的方式将前5个参数固定了下来
#define IOMUXC_UART1_TX_DATA_UART1_TX 0x020E0084U, 0x0U, 0x00000000U, 0x0U, 0x020E0310U
#define IOMUXC_UART1_RX_DATA_UART1_RX 0x020E0088U, 0x0U, 0x020E0624U, 0x3U, 0x020E0314U
其中
第1参数:寄存器的地址(复用寄存器) 第2参数:第1参数的设置值
第3参数:寄存器的地址(设备选用寄存器) 第4参数:第3参数的设置值
第5参数: 寄存器的地址(参数设定寄存器)
前5个参数与复用的功能有关,可以固定下来
第6参数 第1参数的设置值 由用户指定,一般再复用时将这一参数设置为0,也可设置为电气属性值。
电气属性设置函数:
IOMUXC_SetPinConfig(IOMUXC_UART1_TX_DATA_UART1_TX,0x10B0); //参数设置 参考 IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA 寄存器
IOMUXC_SetPinConfig(IOMUXC_UART1_RX_DATA_UART1_RX,0x10B0); //参数设置 参考 IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA 寄存器
也有6个参数(同上),
这个函数的功能是讲第6参数(用户设定值)赋值给第5参数(电气属性设置寄存器)即完成了电气属性的设定
以 IOMUXC_SetPinConfig(IOMUXC_UART1_TX_DATA_UART1_TX,0x10B0);为例
这里表示将 数值:0x10B0 传递给 地址为 0x020E0310U 的寄存器
也就是 IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA寄存器 赋值为 0x10B0(0001 0000 1011 0000);
*bit 16:0 HYS关闭
*bit [15:14]: 00 默认100K下拉
*bit [13]: 0 keeper功能
*bit [12]: 1 pull/keeper使能
*bit [11]: 0 关闭开路输出
*bit [7:6]: 10 速度100Mhz
*bit [5:3]: 110 驱动能力R0/6
*bit [0]: 0 低转换率
1.2 UART开启/关闭、复位函数
uart_disable(UART1); //UART1 关闭
uart_enable(UART1); //UART1 关闭
通过对 UART1_UCR1 寄存器1 bit0 : UARTEN 使能位的操作实现 UART 使能与关断,写1使能,写0关断。
/* 串口UART 软件复位函数 */
void uart_soft_reset(UART_Type *base)
{
base->UCR2 &= ~(1<<0); /* UCR2的bit0为0,复位UART */
while((base->UTS & 0x1) == 1); /* 等待复位完成读取UTS的bit0 */
}
/* 单个字符发送函数 */
/*配合格式化输入/输出函数使用,也可单独使用*/
void putc(unsigned char c)
{
while(((UART1->USR2 >> 3) &0X01) == 0);/* 等待上一次发送完成 USR2 bit3 TXDC 传输完成标志位*/
UART1->UTXD = c ; /* 发送数据 */
}
/* 单个字符接收函数 */
/*配合格式化输入/输出函数使用,也可单独使用*/
unsigned char getc(void)
{
while((UART1->USR2 & 0x1) == 0);/* 等待接收完成 USR2 bit0 RDR 数据接收准备完成标志*/
return UART1->URXD; /* 返回接收到的数据 */
}
/* 字符串发送函数 */
/* 配合格式化输入/输出函数使用,也可单独使用*/
void puts(char *str)
{
char *p = str;
while(*p)
putc(*p++);
}
自编的波特率自动设置程序
/*********************************
自定义的除法运算(不能直接调用除法时使用)
例如:27÷3 div(分子,分母);
返回值为商
*********************************/
uint32_t div(uint32_t A, uint32_t B)
{
uint32_t quotient=0;
if (B != 0)
{
for (quotient=0;A>=B; quotient++)
{
A = A - B;
}
}
return(quotient);
}
/************************************
自定义的求余运算(不能直接调用除法时使用)
例如:27÷5=5````2 rem(27,5);
返回值为余数
**************************************/
uint32_t rem(uint32_t A, uint32_t B)
{
uint32_t quotient;
if (B != 0)
{
for (quotient = 0; A >= B; quotient++)
{
A = A - B;
}
}return(A);
}
/*************************************
最大公约数求解算法
欧几里得算法(辗转相除法)
不能直接调用除法时(采用自定义求余算法)
*************************************/
uint32_t Euclid_2(uint32_t A, uint32_t B)
{
uint32_t max_num;
uint32_t min_num;
uint32_t re_num = 0xffffffff;
if (A > B)
{
max_num = A,min_num = B;
}
else
{
max_num = B,min_num = A;
}
while (re_num != 0)
{
re_num = rem(max_num,min_num);
max_num = min_num;
min_num = re_num;
}
return(max_num);
}
/******************************************************
使用方法:设置串口 UART1 波特率为 115200, 时钟频率 80Mhz
uart_baudrate_autoset(UART1,115200,80000000)
使用前提是UARTx->UFCR bit7:9 RFDIV设置为1分频
******************************************************/
void uart_baudrate_autoset(UART_Type *base, unsigned int baudrate, unsigned int srcclock_hz)
{
uint32_t numerator = 0u; //分子
uint32_t denominator = 0U; //分母
uint32_t gcd = 0U; //最大公约数
numerator = srcclock_hz;
denominator = (baudrate << 4); //波特率左移4位(*16)
gcd=Euclid_2(numerator, denominator);
numerator = div(numerator,gcd);
denominator = div(denominator,gcd);
base->UFCR &=~(7<<7); //UFCR bit7:9清零
base->UFCR |= (5<<7); //ref freq等于ipg_clk/1=80Mhz
base->UBIR = (denominator-1); //要先写UBIR寄存器,然后在写UBMR寄存器,3592页
base->UBMR = (numerator-1);
}
以上注释和代码都是在学习 《正点原子 linux 第二期 裸机开发视频 P42-P44 第19.1-19.2讲 UART串口通信 》 过程中
跟着 左萌主 学习并加入了一点点自己的思考写成的,作为一个小菜鸡,我大着胆子发出来跟大家一起记录学习
如果有帮助请大家自行参考、下载,如果 转载 请注明出处,并在论坛和我联系。如果有错误请大神指正!左萌主赛高!
作者 :YOKI
导师 :正点原子 左忠凯
硬件 :正点原子 ALPHA I.MX LINUX 开发板
/*********************************************************************************************/
|
|