因为想申请 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
#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)
#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);
GPIOPinTypeUART(GPIO_PORTB_BASE,GPIO_PIN_0|GPIO_PIN_1);
UARTClockSourceSet(UART1_BASE, UART_CLOCK_PIOSC);
UARTStdioConfig(1,115200, 16000000);
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"
#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"
#define delay_ms(n); SysCtlDelay(n*(SysCtlClockGet()/3000));
void UARTIntHandler(void)
{
uint32_t ui32Status;
ui32Status = UARTIntStatus(UART1_BASE, true);
UARTIntClear(UART1_BASE, ui32Status);
while(UARTCharsAvail(UART1_BASE))
{
UARTCharPutNonBlocking(UART1_BASE, UARTCharGetNonBlocking(UART1_BASE));
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2);
delay_ms(1);
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);
}
}
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);
GPIOPinTypeUART(GPIO_PORTB_BASE,GPIO_PIN_0|GPIO_PIN_1);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_2);
UARTClockSourceSet(UART1_BASE, UART_CLOCK_PIOSC);
UARTStdioConfig(1,115200, 16000000);
IntMasterEnable();
IntEnable(INT_UART1);
UARTIntEnable(UART1_BASE, UART_INT_RX | UART_INT_RT);
UARTIntRegister(UART1_BASE,UARTIntHandler);
UARTprintf("Enter Text: \n");
while (1)
{
;
}
}
(4)FIFO测试
修改上述代码,测试FIFO的功能。
配置接收中断,当接收FIFO半满(8byte)时触发。利用串口调试助手一个char一个char发送。
观察到发送8个char后进入中断,FIFO测试成功
#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"
#define delay_ms(n); SysCtlDelay(n*(SysCtlClockGet()/3000));
void UARTIntHandler(void)
{
uint32_t ui32Status;
ui32Status = UARTIntStatus(UART1_BASE, true);
UARTIntClear(UART1_BASE, ui32Status);
while(UARTCharsAvail(UART1_BASE))
{
UARTCharPutNonBlocking(UART1_BASE, UARTCharGetNonBlocking(UART1_BASE));
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2);
delay_ms(1);
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);
}
}
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);
GPIOPinTypeUART(GPIO_PORTB_BASE,GPIO_PIN_0|GPIO_PIN_1);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_2);
UARTClockSourceSet(UART1_BASE, UART_CLOCK_PIOSC);
UARTStdioConfig(1,115200, 16000000);
UARTFIFOLevelSet(UART1_BASE,UART_FIFO_TX4_8,UART_FIFO_RX4_8);
UARTFIFOEnable(UART1_BASE);
IntMasterEnable();
IntEnable(INT_UART1);
UARTIntEnable(UART1_BASE, UART_INT_RX);
UARTIntRegister(UART1_BASE,UARTIntHandler);
UARTprintf("Enter Text: \n");
while (1)
{
;
}
}
进一步进行其他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功能
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)