OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 3499|回复: 1

<新手向>第二期 裸机开发 P42-P44第9讲 串口通讯UART 随堂笔记

[复制链接]

5

主题

17

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
254
金钱
254
注册时间
2020-3-22
在线时间
35 小时
发表于 2020-8-19 23:46:00 | 显示全部楼层 |阅读模式
本帖最后由 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 开发板
/*********************************************************************************************/


11_UART.rar

334.33 KB, 下载次数: 9

串口例程

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

2

主题

712

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2178
金钱
2178
注册时间
2018-8-27
在线时间
258 小时
发表于 2020-8-20 11:29:20 | 显示全部楼层
可以 可以  很用心! 加油
森罗万象
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-25 16:23

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表