TM4C123G学习记录(6)--UART

2023-05-16

因为想申请 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标志寄存器UARTFRUART接收状态寄存器(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选项。通过UARTLCRHFEN位启用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.huartstdio.c文件,即可使用类似printf()等C函数

  • UART时钟、波特率配置函数需要从UARTConfigSetExpClk变为UARTStdioConfig
  • UARTprintf();的使用方法和C中printf()完全类似,支持%d等标准输入输出格式符

在这里插入图片描述

  • 特别注意一下,同一时间,只有一个串口可以用UARTprintfuartstdio.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来指示数据接收和发送的情况

  1. 增加头文件inc/hw_ints.hdriverlib/interrupt.h(具体路径根据你的工程来)
  2. 进行中断配置,开启接受中断和超时中断`
  3. 配置指示用的LED
  4. 编写中断服务函数:这里首先要读中断状态寄存器,分析发生中断的种类;然后用读取的来清除中断标志(TM4C库函数中,中断标志返回值和清除中断标志函数的参数都是bit-packed格式,可以直接用,挺巧妙的);接下来读取并发送收到的数据;最后让led闪烁一下
  5. 别忘了注册中断服务函数,可以用函数注册,也可以手动修改中断像量表
#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 status
	UARTIntClear(UART1_BASE, ui32Status); 			//clear the asserted interrupts
	while(UARTCharsAvail(UART1_BASE)) 				//loop while there are chars
	{
		UARTCharPutNonBlocking(UART1_BASE, UARTCharGetNonBlocking(UART1_BASE)); //echo character
		GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2); 	//blink LED
		delay_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 LED
	GPIOPinTypeGPIOOutput(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 interrupts
	IntEnable(INT_UART1); 										//enable the UART interrupt
	UARTIntEnable(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 status
	UARTIntClear(UART1_BASE, ui32Status); 				//clear the asserted interrupts
	while(UARTCharsAvail(UART1_BASE)) 						//loop while there are chars
	{
		UARTCharPutNonBlocking(UART1_BASE, UARTCharGetNonBlocking(UART1_BASE)); //echo character
		GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2); //blink LED
		delay_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 LED
	GPIOPinTypeGPIOOutput(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 interrupts
	IntEnable(INT_UART1); 																	//enable the UART interrupt
	UARTIntEnable(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, …)

  1. 包含uartstdio.cuartstdio.h后可用
  2. 类似C语言printf()

(2)void UARTCharPut(uint32_t ui32Base, unsigned char ucData)

  1. 串口输出一个char型
  2. 等待FIFO中有数据再发送

(3)int32_t UARTCharGet(uint32_t ui32Base)

  1. 串口接收一个uint32_t型数据
  2. 等待FIFO中有数据再接收

(4)bool UARTCharPutNonBlocking(uint32_t ui32Base, unsigned char ucData)

  1. 串口输出一个char型
  2. 若发送时FIFO已满时,直接返回false而不在那循环等待

(5)int32_t UARTCharGetNonBlocking(uint32_t ui32Base)

  1. 串口接收一个uint32_t型数据
  2. 如果遇到接收时FIFO为空,直接返回false而不在那循环等待

(6)void UARTFIFOLevelSet(uint32_t ui32Base, uint32_t ui32TxLevel,uint32_t ui32RxLevel)

  1. 配置输入输出FIFO的深度

(7)void UARTFIFOEnable(uint32_t ui32Base)

  1. 开启某UART的FIFO功能
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

TM4C123G学习记录(6)--UART 的相关文章

随机推荐