MM32F0140 UART学习笔记

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),接收器对接收到的数据进行“串->并”转换。
图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引脚上。
图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寄存器中。
图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) ) { }}  
图4. mm32f0140部分时钟树
图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 crh |= gpio_pinmode_in_floating; /* pa10 floating input. */ gpioa->afrh |= (gpio_af_1 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 fra = (board_debug_uart_freq / board_debug_uart_baudrate) % 16u; /* enable uart1. */ uart1->gcr |= uart_gcr_uarten_mask;}  
图7. mm32f0140 uart_gcr寄存器
图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); }}  
图9. 实验现象
来源:灵动mm32mcu


如何检测交换机性能好坏,方法有哪些
隐私计算密码技术的典型应用场景
网卡固件版本未达到需求版本怎么办
电子元器件一直以来给下游降本,如今却一地鸡毛
水电磁阀的规格型号_水电磁阀的选型依据
MM32F0140 UART学习笔记
张晓论币:2.21主流数字货币行情分析
雷迪埃宇航级开关——专为卫星设计的新型开关
服务器数据恢复—EMC存储raid5故障的数据恢复案例
72小时烧制19道工序打磨 OPPO R15陶瓷黑带来3D四曲面设计
苹果造车要出意外?现代很不服气:不想做第二个富士康
互联网行业将迎来用户减少的拐点
iQOO 3内置“机械键盘”,打字体验再升级
Mesh组网怎么操作?
谈谈协程的那些事儿
喜报 | 全耀传感科技荣获“国家高新技术企业”认定
关于华为AI芯片的性能分析和介绍
曙光政务云平台获得商用密评认证 Silicon Labs宣布和Memfault合作
芯朋微提供高效可靠的电源和驱动类芯片解决方案
热电偶冷端补偿电路图详解