TM4C123G学习记录(6)--UART
因为想申请 CSDN 博客认证需要一定的粉丝量,而我写了五年博客才 700 多粉丝,本文开启关注才可阅读全文,很抱歉影响您的阅读体验
- 为了准备电赛临时学一下TM4C123G,简单记录学习内容
- 大家可以在这里下载我收集的资源,非常全面,花了很大功夫收集来的,还有书籍、例程代码等
- 还可以在TI官网下载相关文档TI官网
文章目录
- 一、实验简介
- 二、TM4C的UART资源
- (1)Tiva控制器的UART特征
- (2)UART结构图
- (3)UART和引脚的复用映射表
- (4)FIFO操作
- (5)中断、
- 三、编程实践
- (1)UART配置和使用的基本流程
- (2)使用类似C语言中stdio.h的方法
- (3)UART中断
- (4)FIFO测试
- 四、部分库函数小结
- (1)void UARTprintf(const char *pcString, ...)
- (2)void UARTCharPut(uint32_t ui32Base, unsigned char ucData)
- (3)int32_t UARTCharGet(uint32_t ui32Base)
- (4)bool UARTCharPutNonBlocking(uint32_t ui32Base, unsigned char ucData)
- (5)int32_t UARTCharGetNonBlocking(uint32_t ui32Base)
- (6)void UARTFIFOLevelSet(uint32_t ui32Base, uint32_t ui32TxLevel,uint32_t ui32RxLevel)
- (7)void UARTFIFOEnable(uint32_t ui32Base)
一、实验简介
通过TM4C123G的板载UART串口和电脑通信,观察各种中断发生情况
二、TM4C的UART资源
简单介绍TM4C123G的UART资源,关于波特率发生原理、数据传输流程、ISR、调制解调器握手、9位UART模式、环回模式、DMA等内容省略
(1)Tiva控制器的UART特征
(2)UART结构图
(3)UART和引脚的复用映射表
这个表非常重要,编程时要根据这个参考
(4)FIFO操作
关于FIFO的作用可以看看这篇文章,讲的很明白:uart FIFO
每个UART有两个16x8的缓冲区,一个用来发送,一个用来接收
FIFO状态通过
UART标志寄存器UARTFR
和UART接收状态寄存器(UARTRSR)
显示。硬件监视空、满和溢出情况。FIFO产生中断的触发条件由
UART中断FIFO深度选择(UARTIFLS)
控制。两个FIFO可以单独配置为不同的电平情况下触发中断。可以选择如下配置:1/8、1/4、1/2、3/4、7/8。(例如:1/4代表连续FIFO装入16*1/4=4个字节产生一个接受中断)复位后FIFO都是禁用的并作为1字节的保留寄存器,FIFO中断默认为两个都是1/2选项。通过
UARTLCRH
的FEN
位启用FIFO。
注意:关于复位后FIFO是默认使能还是禁用,似乎TI手册之间有矛盾,总之不要用默认设置,自己手动设置一下吧
以下内容来自ti的getting start手册
(5)中断、
如下介绍,建议结合相关的寄存器看,包括UARTCTL寄存器
和UARTIFLS寄存器
- 接收超时中断:当FIFO不是空的,并且在32位期间没有接收到进一步的数据时触发
- 接收中断:如果开启FIFO,当收数据>=FIFO深度时触发;否则每次接收到数据都触发
- 发送中断:如果开启FIFO,当FIFO中数据<=FIFO深度时触发;否则在FIFO中没有数据时触发
三、编程实践
下面就按TIgetting start
手册的顺序进行UART实验吧
(1)UART配置和使用的基本流程
下面看一个官方例程,UART0实现echo
/*官方例程1*/
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
int main(void)
{SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);GPIOPinConfigure(GPIO_PA0_U0RX);GPIOPinConfigure(GPIO_PA1_U0TX);GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);UARTConfigSetExpClk(UART0_BASE, SysCtlClockGet(), 115200, (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));UARTCharPut(UART0_BASE, 'E');UARTCharPut(UART0_BASE, 'n');UARTCharPut(UART0_BASE, 't');UARTCharPut(UART0_BASE, 'e');UARTCharPut(UART0_BASE, 'r');UARTCharPut(UART0_BASE, ' ');UARTCharPut(UART0_BASE, 'T');UARTCharPut(UART0_BASE, 'e');UARTCharPut(UART0_BASE, 'x');UARTCharPut(UART0_BASE, 't');UARTCharPut(UART0_BASE, ':');UARTCharPut(UART0_BASE, ' ');while (1){if (UARTCharsAvail(UART0_BASE)) UARTCharPut(UART0_BASE, UARTCharGet(UART0_BASE));}
}
官方对于程序的讲解如下
(2)使用类似C语言中stdio.h的方法
包含TivaWare提供的uartstdio.h
和uartstdio.c
文件,即可使用类似printf()
等C函数
- UART时钟、波特率配置函数需要从
UARTConfigSetExpClk
变为UARTStdioConfig
UARTprintf();
的使用方法和C中printf()
完全类似,支持%d
等标准输入输出格式符
- 特别注意一下,同一时间,只有一个串口可以用
UARTprintf
,uartstdio.c
中对printf重定向,默认是定向到UART0
,我这里修改成UART1
,如下
利用uartstdio改写上面的官方例程实现一样的功能,大家可以对比一下(我用的UART1,官方是UART0)
/*官方例程1改写,使用uartstdio*/
#include <stdint.h>
#include <stdbool.h>
#include "inc/tm4c123gh6pm.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/sysctl.h"
#include "driverlib/interrupt.h"
#include "driverlib/gpio.h"
#include "driverlib/uart.h"
#include "uartstdio.h"
#include "driverlib/systick.h"
#include "driverlib/pin_map.h"int main(void)
{SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);//使能外设SysCtlPeripheralEnable(SYSCTL_PERIPH_UART1);SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);//配置复用功能GPIOPinConfigure(GPIO_PB0_U1RX);GPIOPinConfigure(GPIO_PB1_U1TX);//分配UART信号GPIOPinTypeUART(GPIO_PORTB_BASE,GPIO_PIN_0|GPIO_PIN_1);//配置UART参数(这样配置可以用UARTprintf)UARTClockSourceSet(UART1_BASE, UART_CLOCK_PIOSC); //使用16MHz内部高精度振荡器(PIOSC)作为UART模块时钟UARTStdioConfig(1,115200, 16000000); //UART编号、波特率、UART时钟频率(频率要和上一行设的一致)UARTprintf("Enter Text: \n");uint8_t getChar;while (1){getChar=UARTCharGet(UART1_BASE);UARTCharPut(UART1_BASE,getChar);}
}
(3)UART中断
进一步改进刚才的例程,使用接收中断代替主函数中的轮询检测,同时我们增加一个LED来指示数据接收和发送的情况
- 增加头文件
inc/hw_ints.h
和driverlib/interrupt.h
(具体路径根据你的工程来) - 进行中断配置,开启接受中断和超时中断`
- 配置指示用的LED
- 编写中断服务函数:这里首先要读中断状态寄存器,分析发生中断的种类;然后用读取的来清除中断标志(TM4C库函数中,中断标志返回值和清除中断标志函数的参数都是bit-packed格式,可以直接用,挺巧妙的);接下来读取并发送收到的数据;最后让led闪烁一下
- 别忘了注册中断服务函数,可以用函数注册,也可以手动修改中断像量表
#include <stdint.h>
#include <stdbool.h>
#include "inc/tm4c123gh6pm.h" //Register Definitions
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/sysctl.h"
//#include "inc/hw_ints.h"
#include "driverlib/interrupt.h"
#include "driverlib/gpio.h"
#include "driverlib/uart.h"
#include "uartstdio.h"
#include "driverlib/systick.h"
#include "driverlib/pin_map.h"#define delay_ms(n); SysCtlDelay(n*(SysCtlClockGet()/3000));void UARTIntHandler(void)
{uint32_t ui32Status;ui32Status = UARTIntStatus(UART1_BASE, true); //get interrupt statusUARTIntClear(UART1_BASE, ui32Status); //clear the asserted interruptswhile(UARTCharsAvail(UART1_BASE)) //loop while there are chars{UARTCharPutNonBlocking(UART1_BASE, UARTCharGetNonBlocking(UART1_BASE)); //echo characterGPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2); //blink LEDdelay_ms(1);GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0); //turn off LED}
}int main(void)
{ SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);//使能外设SysCtlPeripheralEnable(SYSCTL_PERIPH_UART1);SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);//配置复用功能GPIOPinConfigure(GPIO_PB0_U1RX);GPIOPinConfigure(GPIO_PB1_U1TX);//分配UART信号GPIOPinTypeUART(GPIO_PORTB_BASE,GPIO_PIN_0|GPIO_PIN_1);//LED配置SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); //enable GPIO port for LEDGPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_2); //enable pin for LED PF2//串口参数设置UARTClockSourceSet(UART1_BASE, UART_CLOCK_PIOSC); //使用16MHz内部高精度振荡器(PIOSC)作为UART模块时钟UARTStdioConfig(1,115200, 16000000); //UART编号、波特率、UART时钟频率(频率要和上一行设的一致)//中断使能IntMasterEnable(); //enable processor interruptsIntEnable(INT_UART1); //enable the UART interruptUARTIntEnable(UART1_BASE, UART_INT_RX | UART_INT_RT); //only enable RX and TX interrupts//注册中断服务函数UARTIntRegister(UART1_BASE,UARTIntHandler);UARTprintf("Enter Text: \n");while (1) //let interrupt handler do the UART echo function{ ;}
}
(4)FIFO测试
修改上述代码,测试FIFO的功能。
配置接收中断,当接收FIFO半满(8byte)时触发。利用串口调试助手一个char一个char发送。
观察到发送8个char后进入中断,FIFO测试成功
#include <stdint.h>
#include <stdbool.h>
#include "inc/tm4c123gh6pm.h" //Register Definitions
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/sysctl.h"
//#include "inc/hw_ints.h"
#include "driverlib/interrupt.h"
#include "driverlib/gpio.h"
#include "driverlib/uart.h"
#include "uartstdio.h"
#include "driverlib/systick.h"
#include "driverlib/pin_map.h"#define delay_ms(n); SysCtlDelay(n*(SysCtlClockGet()/3000));void UARTIntHandler(void)
{uint32_t ui32Status;ui32Status = UARTIntStatus(UART1_BASE, true); //get interrupt statusUARTIntClear(UART1_BASE, ui32Status); //clear the asserted interruptswhile(UARTCharsAvail(UART1_BASE)) //loop while there are chars{UARTCharPutNonBlocking(UART1_BASE, UARTCharGetNonBlocking(UART1_BASE)); //echo characterGPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2); //blink LEDdelay_ms(1);GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0); //turn off LED}
}int main(void)
{ SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);//使能外设SysCtlPeripheralEnable(SYSCTL_PERIPH_UART1);SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);//配置复用功能GPIOPinConfigure(GPIO_PB0_U1RX);GPIOPinConfigure(GPIO_PB1_U1TX);//分配UART信号GPIOPinTypeUART(GPIO_PORTB_BASE,GPIO_PIN_0|GPIO_PIN_1);//LED配置SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); //enable GPIO port for LEDGPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_2); //enable pin for LED PF2//串口参数设置UARTClockSourceSet(UART1_BASE, UART_CLOCK_PIOSC); //使用16MHz内部高精度振荡器(PIOSC)作为UART模块时钟UARTStdioConfig(1,115200, 16000000); //UART编号、波特率、UART时钟频率(频率要和上一行设的一致)//FIFO配置,UARTFIFOLevelSet(UART1_BASE,UART_FIFO_TX4_8,UART_FIFO_RX4_8); //FIFO填入半满(8byte)时触发中断UARTFIFOEnable(UART1_BASE);//中断使能IntMasterEnable(); //enable processor interruptsIntEnable(INT_UART1); //enable the UART interruptUARTIntEnable(UART1_BASE, UART_INT_RX); //注册中断服务函数UARTIntRegister(UART1_BASE,UARTIntHandler);UARTprintf("Enter Text: \n");while (1) //let interrupt handler do the UART echo function{ ;}
}
进一步进行其他FIFO中断测试,如下:
- 打开FIFO的情况下,打开
UART_INT_OE
(FIFO溢出中断),此时FIFO深度无作用,FIFO接收17个(FIFO溢出)后进入中断,第17个byte丢失,会输出FIFO中存储的所有16个字符,特别注意FIFO溢出是一个错误引发的中断,在中断服务函数中,除了用UARTIntClear
清除标志,还要写一句HWREG(UART1_BASE+UART_O_ECR)=0;
清除错误标志,否则中断只能进一次。 - 关闭FIFO的情况下(相当于FIFO深度为1),打开
UART_INT_OE
(FIFO溢出中断),连续收到两个byte溢出,在中断中打印第一个byte;打开UART_INT_RX
(FIFO溢出中断),每收到一个byte都会进中断打印
四、部分库函数小结
(1)void UARTprintf(const char *pcString, …)
- 包含
uartstdio.c
和uartstdio.h
后可用 - 类似C语言printf()
(2)void UARTCharPut(uint32_t ui32Base, unsigned char ucData)
- 串口输出一个char型
- 等待FIFO中有数据再发送
(3)int32_t UARTCharGet(uint32_t ui32Base)
- 串口接收一个uint32_t型数据
- 等待FIFO中有数据再接收
(4)bool UARTCharPutNonBlocking(uint32_t ui32Base, unsigned char ucData)
- 串口输出一个char型
- 若发送时FIFO已满时,直接返回false而不在那循环等待
(5)int32_t UARTCharGetNonBlocking(uint32_t ui32Base)
- 串口接收一个uint32_t型数据
- 如果遇到接收时FIFO为空,直接返回false而不在那循环等待
(6)void UARTFIFOLevelSet(uint32_t ui32Base, uint32_t ui32TxLevel,uint32_t ui32RxLevel)
- 配置输入输出FIFO的深度
(7)void UARTFIFOEnable(uint32_t ui32Base)
- 开启某UART的FIFO功能
TM4C123G学习记录(6)--UART相关推荐
- TM4C123G学习记录(2)--GPIO
为了准备电赛临时学一下TM4C123G,简单记录学习内容 大家可以在这里下载我收集的资源,非常全面,花了很大功夫收集来的,还有书籍.例程代码等 还可以在TI官网下载相关文档TI官网 一.实验简介 简单 ...
- TM4C123G学习记录(5)--PWM输出
因为想申请 CSDN 博客认证需要一定的粉丝量,而我写了五年博客才 700 多粉丝,本文开启关注才可阅读全文,很抱歉影响您的阅读体验 为了准备电赛临时学一下TM4C123G,简单记录学习内容 大家可以 ...
- K210学习记录(2)——UART(串口)
0.引言 本系列博客仅作为本人学习K210单片机的学习记录,主要学习其内部资源使用,作为初学者难免有错误之处,如有发现还望指出. 硬件:Sipeed Maix Dock开发板(推荐官方KD233开发板 ...
- 【转】BLE 学习记录
原文网址:http://m.blog.csdn.net/blog/chiooo/43985401 BLE 学习记录 ANROID BLE 开发,基于 bluetoothlegatt 分析 mBluet ...
- 基于全志A33开发板linux系统移植学习记录(Boot0)
基于全志A33开发板linux系统移植学习记录 第一章 Boot0基于ARMGCC的编译与修改 文章目录 基于全志A33开发板linux系统移植学习记录 前言 一.全志A33简介以及上电引导流程 二. ...
- 主线剧情01-ARM-IMX6ULL基础学习记录
ARM & i.MX6ULL 基础学习记录 编辑整理 by Staok 本文大部分内容摘自"100ask imx6ull"开发板的配套资料(如<IMX6ULL裸机开发 ...
- 学习记录--蓝牙模块HC05(串口收发)
主要实现:PC上位机与蓝牙之间的通信(收发) 一,HC05模式等一系列设置 参考博客: (11条消息) stm32之蓝牙模块HC-05使用_一剃解千愁的博客-CSDN博客_stm32蓝牙模块的使用 ( ...
- MSP432单片机学习记录(二)
文章目录 1.复位视图 2.代码提示 3.新建自己的硬件库(hardware) 4.中断的使用 前面的文章提到了ccs工程的创建,下面继续介绍msp432的使用,上一篇文章链接如下所示:MSP432单 ...
- Pytorch学习记录-torchtext和Pytorch的实例( 使用神经网络训练Seq2Seq代码)
Pytorch学习记录-torchtext和Pytorch的实例1 0. PyTorch Seq2Seq项目介绍 1. 使用神经网络训练Seq2Seq 1.1 简介,对论文中公式的解读 1.2 数据预 ...
最新文章
- 表白这件事,比解 bug 要难多少?
- CodeSmith 学习资料收集
- 一款全屏图片滑动js 插件 超快捷
- PHP过滤器 filter_has_var() 函数
- Vishay将MCW 0406 AT系列精密宽端子薄膜片式电阻欧姆值降至业内最低
- 网络推广离不开关键词的精准挖掘
- 怎样将employee 加到Territory里
- 查询已有链表的hashmap_原创 | 面试不再慌,看完这篇保证让你写HashMap跟玩一样...
- 0.1uf与47uf并联_UF是什么形式?
- 判断一个字符串的字符是不是唯一
- 黑苹果 电脑关机是因为发生了问题_【电脑常识】常见的电脑误区,你中了几点?...
- 封装制作ghost xp,含加入域帐号配置迁移脚本。
- 【转载】深入浅出讲解FOC算法与SVPWM技术——自制FOC驱动器
- php给发qq消息,PHP 模拟QQ登录及发送消息实现方法
- java中设置5秒后跳转_javaweb 3秒后自动跳转的几种方式
- “大学教育的目的”-- 芝加哥大学Andrew Abbott教授的演讲
- 数据视化Echarts+百度地图API实现市县区级下钻
- 机器学习基础 维基翻译 保序回归 随机森林 Pipeline处理 及简单的sklearn例子
- 用C++写出求矩形和圆形面积的程序
- 管理经济学第一遍总结