0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看威廉希尔官方网站 视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

MM32F0140 UART学习笔记

jf_pJlTbmA9 来源:灵动MM32MCU 作者:灵动MM32MCU 2023-09-26 16:45 次阅读

UART简介

UART是通用异步收发器,全称为Universal Asynchronous Receiver and Transmitter,属于异步串口通信协议的一种,能够灵活进行全双工数据交换。

MM32F0140的UART支持全双工数据交换、同步单向通信、半双工单线通信、多处理器之间的通信以及调制解调器(CTS/RTS)操作。

串行通信

串行通信是指使用一条数据线,将数据一位一位地依次传输,每一位数据占据一个固定的时间长度,只需要少数几条线就可以在系统间交换信息

串行通信按照数据传输方向分为:

● 单工通信

数据只能在一个方向上传输,通常采用两线进行通信,分别是:GND、TX(发送数据输出引脚)或RX(接收数据输入引脚),发送设备与接收设备共地将参考电压调节一致,MCU做发送或接收。

● 半双工通信

相当于可切换方向的单工通信,在具体时刻,只允许数据在一个方向上传输,不能同时在两个方向上传输。

● 全双工通信

允许数据同时在两个方向上传输,通常采用三线,分别是:GND、TX、RX,接收设备与发送设备均为双向通信设备,若通信双方有一方需为另一方提供电源,则两设备的VDD相连。

异步通信

异步通信过程中,接收器和发送器使用各自的时钟,以一个字符为传输单位,通信中两个字符间的时间间隔不固定,但在同一个字符中的两个相邻位间的时间间隔固定,每一个字符要用起始位和停止位作为字符开始和结束的标志。

UART功能

如图1所示,Device1做发送器,Device2做接收器进行通信,发送器对发送数据执行“并->串”转换,然后,数据从发送器的发送数据输出引脚(TX)输出,在传输线路上一位一位的传输到接收器的接收数据输入引脚(RX),接收器对接收到的数据进行“串->并”转换。

wKgZomUD7mCAN4ULAABr3RY7zHI594.png 图1. UART通信

数据传输

UART的数据传输如图2所示,包含起始位、数据帧、奇偶校验位、停止位、空闲帧与断开帧。

● 起始位

在发送器被使能,且无数据发送时,TX引脚处于高电平,若要进行数据传输,发送器会在发送起始位拉低TX引脚,即将传输线从高电平拉到低电平并保持1个时钟周期。

● 数据帧

数据帧包含需要传输的数据,数据长度由UART通用控制寄存器(UART_CCR)的CHAR位配置,通常可以设置为5 ~ 8位,若不使用奇偶校验位,数据帧长度可为9位。

发送数据需要将UART全局控制寄存器(UART_GCR)的TXEN位置1,数据从UART发送数据寄存器(UART_TDR)写入,经过一字节缓冲器缓冲,最后通过发送移位寄存器,以最低字节到最高字节的顺序,串行在TX引脚上输出。

接收数据需要将UART全局控制寄存器(UART_GCR)的RXEN位置1,读UART接收数据寄存器(UART_RDR)可获取接收到的数据并清零中断状态寄存器(UART_ISR)的RX_INTF(接收有效数据中断标志)。

● 奇偶校验位

检验数据中1的总个数为奇或偶,判断传输器件数据是否发生改变。奇偶校验可以通过UART通用控制寄存器(UART_CCR)的PEN位置1使能发送接收校验,UART_CCR寄存器的PSEL位为1则数据偶校验,PSEL位为0则数据奇校验。

奇校验:若数据位中1的数目是偶数,则校验位为1,如果1的数目是奇数,校验位为0。

偶校验:若数据位中1的数目是偶数,则校验位为0,如果1的数目是奇数,校验位为1。

● 停止位

停止位用1表示一帧的结束,可通过配置UART通用控制寄存器(UART_CCR)的SPB0位设置停止位位数,位数可设置为0.5、1、1.5、2个停止位。

● 空闲帧

包括停止位在内,一个完全由1组成的完整数据帧,定义为一个空闲符号,下一个数据帧的起始位跟在空闲符之后。

● 断开帧

包括停止位在内,一个完全由0组成的完整数据帧,定义为一个断开符号,在断开帧结束时,发送器再发送一个停止位1,使得下一帧的起始位能够被识别到(产生下降沿被检测到)。断开符号通过设置UART_CCR寄存器的BRK位进行发送,若BKP位置1,在当前数据发送完成后,将会发送一个断开符号到TX引脚上。

wKgaomUD7mGAQ1tZAABe0hfRNvU263.png 图2. UART数据传输

波特率

波特率表示数据传输速率,波特率发生器产生时钟,经过发送器和接收器的使能位置位控制后,供给发送或接收使用。对于大多数串行通信,需要将发送和接收设备的波特率设置为相同的值,若波特率不同,则发送与接收数据的时序可能受到影响。波特率的计算公式如图3所示,UART波特率寄存器(UART_BRR)存放UART分配器除法因子(UARTDIV)的整数部分,UART分数波特率寄存器(UART_FRA)存放UARTDIV的小数部分。例如,若系统时钟为48M,配置波特率为9600(每秒传输9600bit的数据),则(48000000 /9600) / 16的结果赋值到UART_BRR寄存器中,(48000000 / 9600) % 16的取余结果赋值到UART_FRA寄存器中。

wKgZomUD7mOATvEsAABHO-8YbcA724.png 图3. UART的波特率公式

实验

本实验配置UART的基本发送与接收功能,配置时钟速率为48MHz,波特率为9600,数据长度为8位,不使用校验及自动流控制,设置PA9为TX引脚,PA10为RX引脚。通过串口调试工具观察数据的传输,发送数据与接收数据相同。

配置系统时钟 clock_init()

如图4所示,高速外部时钟(HSE)的频率范围为4 ~ 24MHz,实验所使用的晶振为12M,要使系统时钟为48MHz,则配置PLL输出48MHz做系统时钟,操作时钟控制寄存器(RCC_CR)的HSEON位使能HSE,等待HSERDY位拉高(即HSE时钟被释放),设置PLL配置寄存器(RCC_PLLCFGR)中的PLLSRC位为1,并根据公式配置对应参数,PLL配置公式如图5所示。配置闪存访问控制寄存器(FLASH_ACR)启用闪存预取,配置时钟配置寄存器(RCC_CFGR)设置分频并配置PLL输出做系统时钟。

void clock_init()
{
    /* Enable HSE. */
    RCC->CR |= RCC_CR_HSEON_MASK;
    while ( RCC_CR_HSERDY_MASK != (RCC->CR   RCC_CR_HSERDY_MASK ) ) /* Waiting HSE ready. */
    {
    }
    /* F_clko = F_refin * N/(M * P), F_refin = 12M, 12*8/(1*2) = 48. */
    RCC->PLLCFGR = RCC_PLLCFGR_PLLSRC(1)  /* HSE clock is used as PLL input clock. */
                 | RCC_PLLCFGR_PLLDN(7)   /* N = DN + 1 = 7 + 1 = 8. */
                 | RCC_PLLCFGR_PLLDM(1)   /* M = DM + 1 = 1 + 1 = 2. */
                 | RCC_PLLCFGR_PLLDP(0)   /* P = DP + 1 = 0 + 1 = 1. */
                 | RCC_PLLCFGR_PLLLDS(1)  /* PLL lock detector accuracy select. */
                 | RCC_PLLCFGR_PLLICTRL(3)  /* 10uA. */
                 ;
    /* Enable PLL. */
    RCC->CR |= RCC_CR_PLLON_MASK;
    while( 0u == ( RCC->CR   RCC_CR_PLLRDY_MASK ) ) /* Waiting PLL ready. */
    {
    }
    /* Enable the FLASH prefetch. */
    RCC->AHB1ENR |= RCC_AHB1ENR_FLITFEN_MASK; /* Enable the access to FLASH. */
    FLASH->ACR = FLASH_ACR_LATENCY(1u)        /* Setup divider: 1 for 48Mhz. */
               | FLASH_ACR_PRFTBE_MASK        /* Enable flash prefetch. */
               ;
    /* Setup the dividers for each bus. */
    RCC->CFGR = RCC_CFGR_HPRE(0)     /* Div=1 for AHB freq. */
              | RCC_CFGR_PPRE1(0x0)  /* Div=1 for APB1 freq. */
              | RCC_CFGR_PPRE2(0x0)  /* Div=1 for APB2 freq. */
              | RCC_CFGR_MCO(7)      /* Use PLL/2 as output. */
              ;
    /* Switch the system clock source to PLL. */
    RCC->CFGR = ( (RCC->CFGR   ~RCC_CFGR_SW_MASK ) | RCC_CFGR_SW(2) ); /* Use PLL as SYSCLK. */
    /* Wait till PLL is used as system clock source. */
    while ( (RCC->CFGR    RCC_CFGR_SWS_MASK ) != RCC_CFGR_SWS(2) )
    {
    }
}

wKgaomUD7mSAVouFAABUECiS1Do309.png 图4. MM32F0140部分时钟树
wKgZomUD7maAVyWyAABdsLxCS7U107.png 图5. PLL配置公式

启用UART外设时钟 enable_clock()

UART1的UART1_TX与UART1_RX复用引脚为PA9与PA10,因此初始化GPIOA与UART1的外设时钟,UART1在APB2上,GPIOA在AHB上。

void enable_clock()
{
    /* Enable UART1 clock. */
    RCC->APB2ENR |= RCC_APB2_PERIPH_UART1;
    /* Enable GPIOA clock. */
    RCC->AHB1ENR |= RCC_AHB1_PERIPH_GPIOA;
}

配置引脚 pin_init()

由于UART的TX与RX引脚配置为复用功能配置,如图6所示,PA9, PA10的UART1_TX与UART1_RX均使用AF1,对端口复用功能高位寄存器(GPIO_AFRH)的端口9、端口10对应位赋值。

void pin_init()
{
    /* Setup PA9, PA10. */
    GPIOA->CRH  = ~GPIO_CRH_MODE9_MASK;
    GPIOA->CRH |= GPIO_PinMode_AF_PushPull;     /* PA9 multiplexed push-pull output. */
    GPIOA->AFRH  = ~GPIO_AFRH_AFR_MASK;
    GPIOA->AFRH |= (GPIO_AF_1 << GPIO_CRH_MODE9_SHIFT);   /* Use AF1. */

    GPIOA->CRH  = ~GPIO_CRH_MODE10_MASK;
    GPIOA->CRH |= GPIO_PinMode_In_Floating;     /* PA10 floating input. */
    GPIOA->AFRH |= (GPIO_AF_1 << GPIO_CRH_MODE10_SHIFT);    /* Use AF1. */
}

wKgZomUD7meAD4a3AAEkrgICFmQ839.png 图6. 部分引脚复用表格

UART初始化 uart_init()

初始化UART需要配置:时钟频率、波特率、数据长度、停止位、传输模式及是否使用校验。

如图7所示,UART全局控制寄存器(UART_GCR)的TXEN位与RXEN位控制传输模式,两位均置1表示传输模式为TX与RX,AUTOFLOWEN位控制是否使用自动流控制,UARTEN位控制UART的使能。

如图8所示,UART通用控制寄存器(UART_CCR)的SPB1、SPB0位控制停止位位数,CHAR位控制数据宽度,PSEL位选择采用奇校验还是偶校验,PEN位控制校验使能;UART波特率寄存器(UART_BRR)与UART分数波特率寄存器(UART_FRA)分别存储UART分频器除法因子的整数与小数。

void uart_init()
{
    /* Clear the corresponding bit to be used. */
    UART1->CCR  = ~( UART_CCR_PEN_MASK | UART_CCR_PSEL_MASK | UART_CCR_SPB0_MASK | UART_CCR_SPB1_MASK | UART_CCR_CHAR_MASK );
    UART1->GCR  = ~( UART_GCR_AUTOFLOWEN_MASK | UART_GCR_RXEN_MASK | UART_GCR_TXEN_MASK );
    /* WordLength. */
    UART1->CCR |= UART_CCR_CHAR_MASK;
    /* XferMode. */
    UART1->GCR |= (UART_XferMode_RxTx << UART_GCR_RXEN_SHIFT);
    /* Setup baudrate, BOARD_DEBUG_UART_FREQ = 48000000u, BOARD_DEBUG_UART_BAUDRATE = 9600u. */
    UART1->BRR = (BOARD_DEBUG_UART_FREQ / BOARD_DEBUG_UART_BAUDRATE) / 16u;
    UART1->FRA = (BOARD_DEBUG_UART_FREQ / BOARD_DEBUG_UART_BAUDRATE) % 16u;
    /* Enable UART1. */
    UART1->GCR |= UART_GCR_UARTEN_MASK;
}

wKgaomUD7mmAMUfIAAC-8dJ1nho116.png 图7. MM32F0140 UART_GCR寄存器
wKgaomUD7muAIC8-AAHSFZ4nuZM280.png 图8. MM32F0140 UART_CCR寄存器部分位

UART发送数据 uart_putchar()

通过读取UART当前状态寄存器(UART_CSR)获取当前状态,当发送缓冲区为空时,可进行数据发送,将发送数据传入UART发送数据寄存器(UART_TDR),定义发送数据函数uart_putchar(),变量“c”为需要发送的数据。

void uart_putchar(uint8_t c)
{
    while ( 0u == ( UART_STATUS_TX_EMPTY   (UART1->CSR) ) )  /* Waiting tx buffer empty. */
    {}
    UART1->TDR = (uint8_t)c;
}

UART接收数据 uart_getchar()

通过读取UART当前状态寄存器(UART_CSR)获取当前状态,当接收缓冲接收了一个完整字节的数据时,可读取UART接收数据寄存器(UART_RDR)获取接收数据,定义接收数据函数uart_getchar(),该函数返回接收的数据。

uint8_t uart_getchar(void)
{
    while ( 0u == ( UART_STATUS_RX_DONE   (UART1->CSR) ) )  /* Waiting rx buffer receives a complete byte of data. */
    {}
    return (uint8_t)(UART1->RDR   0xff);
}

UART输出字符串 uart_putbuffer()

使用UART发送函数编写发送字符串函数。

void uart_putbuffer(uint8_t *str)
{
    while ((*str) != '�')
    {
        uart_putchar(*str);
        str++;
    }
}

main()函数

main()函数结合上述操作,不断循环接收数据函数uart_getchar()与发送数据函数uart_putchar(),将接收到的数据发送出去,实验现象如图9所示,程序运行后串口输出"uart_basic example.",通过串口调试工具输入"mindmotion",UART输出"mindmotion",输入数据与输出数据相同。

int main(void)
{
    uint8_t c;

    clock_init();
    enable_clock();
    pin_init();
    uart_init();

    uart_putbuffer((uint8_t *)"rnuart_basic example.rn");
    while (1)
    {
        c = uart_getchar();
        uart_putchar(c);
    }
}

wKgZomUD7m2AbgAMAADDOwfwwAw414.png 图9. 实验现象

来源:灵动MM32MCU

审核编辑:汤梓红
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 收发器
    +关注

    关注

    10

    文章

    3424

    浏览量

    105967
  • uart
    +关注

    关注

    22

    文章

    1235

    浏览量

    101359
  • 串行通信
    +关注

    关注

    4

    文章

    571

    浏览量

    35396
  • GND
    GND
    +关注

    关注

    2

    文章

    539

    浏览量

    38699
收藏 人收藏

    评论

    相关推荐

    灵动微课堂 (第203讲) | MM32F0140 UART 学习笔记

    MM32F0140UART支持全双工数据交换、同步单向通信、半双工单线通信、多处理器之间的通信以及调制解调器(CTS/RTS)操作。串行通信串行通信是指使用一条数据线,将数据一位一位地依次传输,每一位
    发表于 03-17 18:54

    AN0052从MM32F0130移植到MM32F0140(英文版)

    AN0052 从MM32F0130移植到MM32F0140(英文版)
    发表于 02-22 18:43 0次下载
    AN0052从<b class='flag-5'>MM32F</b>0130移植到<b class='flag-5'>MM32F0140</b>(英文版)

    MM32F0140 产品手册(中文版)

    MM32F0140 产品手册(中文版)
    发表于 02-22 18:45 0次下载
    <b class='flag-5'>MM32F0140</b> 产品手册(中文版)

    MM32F0140 产品手册(英文版)

    MM32F0140 产品手册(英文版)
    发表于 02-22 18:45 0次下载
    <b class='flag-5'>MM32F0140</b> 产品手册(英文版)

    MM32F0140 用户手册(中文版)

    MM32F0140 用户手册(中文版)
    发表于 02-22 18:46 0次下载
    <b class='flag-5'>MM32F0140</b> 用户手册(中文版)

    MM32F0140 用户手册(英文版)

    MM32F0140 用户手册(英文版)
    发表于 02-22 18:46 0次下载
    <b class='flag-5'>MM32F0140</b> 用户手册(英文版)

    MM32F0140 勘误表(中文版)

    MM32F0140 勘误表(中文版)
    发表于 02-22 18:47 0次下载
    <b class='flag-5'>MM32F0140</b> 勘误表(中文版)

    MM32F0140 勘误表(英文版)

    MM32F0140 勘误表(英文版)
    发表于 02-22 18:48 0次下载
    <b class='flag-5'>MM32F0140</b> 勘误表(英文版)

    基于MM32F0140的UDS Bootloader学习笔记

    基于MM32F0140的UDS Bootloader学习笔记
    的头像 发表于 10-30 17:11 769次阅读
    基于<b class='flag-5'>MM32F0140</b>的UDS Bootloader<b class='flag-5'>学习</b><b class='flag-5'>笔记</b>

    MM32F0140学习笔记——CRC

    MM32F0140学习笔记——CRC
    的头像 发表于 11-10 18:27 610次阅读
    <b class='flag-5'>MM32F0140</b><b class='flag-5'>学习</b><b class='flag-5'>笔记</b>——CRC

    MM32F0140学习笔记——窗口看门狗(WWDG)

    MM32F0140学习笔记——窗口看门狗(WWDG)
    的头像 发表于 10-27 09:45 624次阅读
    <b class='flag-5'>MM32F0140</b><b class='flag-5'>学习</b><b class='flag-5'>笔记</b>——窗口看门狗(WWDG)

    MM32F0140学习笔记——FlexCAN 控制器局域网

    MM32F0140学习笔记——FlexCAN 控制器局域网
    的头像 发表于 10-27 09:25 1464次阅读
    <b class='flag-5'>MM32F0140</b><b class='flag-5'>学习</b><b class='flag-5'>笔记</b>——FlexCAN 控制器局域网

    MM32F0140 SPI学习笔记

    MM32F0140 SPI学习笔记
    的头像 发表于 09-26 16:51 592次阅读
    <b class='flag-5'>MM32F0140</b> SPI<b class='flag-5'>学习</b><b class='flag-5'>笔记</b>

    MM32F0140 DMA学习笔记

    MM32F0140 DMA 学习笔记
    的头像 发表于 09-18 16:57 703次阅读
    <b class='flag-5'>MM32F0140</b> DMA<b class='flag-5'>学习</b><b class='flag-5'>笔记</b>

    MM32F0140 GPIO学习笔记

    MM32F0140 GPIO学习笔记
    的头像 发表于 09-26 16:42 553次阅读
    <b class='flag-5'>MM32F0140</b> GPIO<b class='flag-5'>学习</b><b class='flag-5'>笔记</b>