TM4C123笔记(三、串口/中断/定时器)

写在前面:这几篇主要是作为笔记用,所以写的非常简陋…(或者说,乱orz),现在由于对markdown的语法也不太熟悉,而且TM4也才刚刚接触,非常可能会出现有错的地方…!
如果不嫌弃的话欢迎指教!!(qq:1159806228)

这几篇有望在19年国赛结束后慢慢整理完毕(。

一、串口

需要引用库:

#include <stdbool.h>
#include <stdint.h>
#include “inc/hw_gpio.h”//gpio宏定义
#include “inc/hw_memmap.h”//rom宏定义remap
#include “inc/hw_types.h”//板子类型宏定义(?)
#include “inc/hw_ints.h”//中断宏定义
#include “driverlib/gpio.h”//gpio库
#include “driverlib/pin_map.h”//gpio功能映射
#include “driverlib/rom.h”
#include “driverlib/rom_map.h”//关于rom的一些库函数remap
#include “driverlib/sysctl.h”//时钟相关
#include “driverlib/uart.h”//串口相关
#include “driverlib/interrupt.h”//中断相关
#include “pinout.h”//这个是我用TI的PinMux生成的初始化IO口文件(用法类似于stm32cube)

IO口配置(这些也可以用PinMux生成.c文件自动配置好):

 //使能PORT 
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

  //使能串口0
 SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
  
  //配置IO口功能
   GPIOPinConfigure(GPIO_PA0_U0RX);
  GPIOPinConfigure(GPIO_PA1_U0TX);
  GPIOPinTypeUART(GPIO_PORTA_BASE,GPIO_PIN_0 | GPIO_PIN_1);

    //选择串口时钟:内部精确时钟/系统时钟
    UARTClockSourceSet(UART0_BASE,UART_CLOCK_PIOSC);

//(不推荐!!这个是
看examples里的,但是调用的不是官方库,而且校验停止什么的都没选,感觉不是很好,不如下面那个)
//配置串口:串口编号/波特率/时钟频率
UARTStdioConfig(0, 115200,16000000);

以下这些不包含在PinMux生成的.c文件里,所以下面这些是必须需要的啊!!!!!!!!!)
(顺便PinMux党记得还要添加 SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);语句(使能串口0时钟…不知道为啥它没有自动写这句QAQ))
(↑惨痛的教训)

//配置串口:

//串口号/时钟/波特率/格式

UARTConfigSetExpClk(UART0_BASE,ROM_SysCtlClockGet(),115200, (UART_CONFIG_WLEN_8|UART_CONFIG_STOP_ONE |UART_CONFIG_PAR_NONE));

//开串口中断(使能&发送接收中断)
//注册UART0中断服务函数,第二个是中断函数句柄
UARTIntRegister(UART0_BASE,UART0IntHandler);

// 设置中断优先级,TM4C123G的中断优先级有8个,0最高 
IntPrioritySet(INT_UART0,0);


//使能接收完成中断和接收超时中断 
UARTIntEnable(UART0_BASE,UART_INT_RX | UART_INT_RT);

//使能UART0中断 
IntEnable(INT_UART0);

接收和发送

采用了FIFO模式接收,因为串口速率不及CPU,用了FIFO减少了CPU频繁去操作串口数据的负担。我自己测了测是8个字节才会触发一次UART_INT_RX状态,所以如果需要实时性很高,又要每次只传一个字节的话,那就不要用检测串口状态来接收数据了(不然你就得等8次才能收一次数据),而是通过检测FIFO有无数据来接收数据。

用到了下面这些函数:
·

UARTCharsAvail(UART0_BASE)//检测FIFO有无数据

UARTCharGet(UART0_BASE);//接收一字节数据

UARTCharPut(UART0_BASE,data);//发送一字节数据

//下面是一个自收发例子(这个是参考了别人的代码,用到了FIFO,所以电脑发送8个字节单片机才会接收一次)

void UART0IntHandler(void)

{

	//获取中断标志
	uint32_t flag =UARTIntStatus(UART0_BASE,1);

	//清除中断标志
	UARTIntClear(UART0_BASE,flag);

	if(flag&UART_INT_RX)//接收中断
	//UARTCharsAvail()判断FIFO是否还有数据 

	while(UARTCharsAvail(UART0_BASE))
	{
		//输出得到的数据
		UARTCharPut(UART0_BASE,UARTCharGet(UART0_BASE));
	}

}

我是这么写的(一个字节接收一次,所以没有用flag检测串口状态)

void UART0IntHandler(void)
{ 
	 //获取中断标志 
	  uint32_t flag = UARTIntStatus(UART0_BASE,1);    

	UARTIntClear(UART0_BASE,flag);

	uint8_t data;   
	
	 while(UARTCharsAvail(UART0_BASE))
	{
	  /* 接收数据 */

	data = UARTCharGet(UART0_BASE);
   
	/* 将数据发送出去 */

	UARTCharPut(UART0_BASE, data);

	  }

}

二、中断

中断部分参考了https://blog.csdn.net/qq_43725844/article/details/89093405

大部分GPIO都可以做中断,中断是以一个port为一组的(同一个port下io口共用一个中断函数),在中断函数里检测是哪个io被触发。

(…QAQ虽然和中断没什么关系…但是记得launchPad上按键没有电容记得软件消抖啊(惨痛的教训+1

需要引用库:

#include<stdint.h>
#include<stdbool.h>
#include“ inc/hw_memmap.h”
#include “inc/hw_ints.h”
#include “driverlib/gpio.h”
#include “driverlib/pin_map.h”
#include “driverlib/sysctl.h”
#include “driverlib/interrupt.h”

中断配置过程:(以launchPad上SW1为例)

//IO中断口使能
GPIOIntEnable(GPIO_PORTF_BASE,GPIO_PIN_4);

//IO中断配置
GPIOIntTypeSet(GPIO_PORTF_BASE,GPIO_PIN_4,GPIO_FALLING_EDGE);

// 设置中断优先级,TM4C123G的中断优先级有8个,0最高
IntPrioritySet(INT_GPIOF|INT_GPIOP4, 0);

//中断注册,第二个参数是中断服务函数句柄
GPIOIntRegister(GPIO_PORTF_BASE,IntHandler_GPIOF);

//Port中断使能
IntEnable(INT_GPIOF);

//开启总中断
IntMasterEnable();

中断服务函数:

用到函数:

//获得指定的中断状态并返回;
ui32IntStatus= GPIOIntStatus(GPIO_PORTF_BASE,true);

//清除中断标志
GPIOIntClear(GPIO_PORTF_BASE,GPIO_PIN_4);

举个例子:流程如下:

void  IntHandler_GPIOF(void)//中断服务函数
 {

	  ui32 IntStatus  = GPIOIntStatus(GPIO_PORTF_BASE,  true);//获取状态
      	  GPIOIntClear(GPIO_PORTF_BASE,    GPIO_PIN_4);//清除指定的中断源
   	  if((ui32IntStatus& GPIO_PIN_4) == GPIO_PIN_4)//这里可以判断是哪个io口的中断
	   {

	  //内部逻辑

	   }

}

三、定时器

TM4一共有两种定时器,16位和32位的(TIM和WTIM),每种有6组,每组下又有2个定时器(A、B)。每组两个定时器可以连起来扩展成两倍位宽的定时器,支持上升下降单次循环计数,也可以来产生PWM信号。
这里以TIM0的A定时器为例。

引用diverlib下timer.h文件,以后要用什么外设直接引用对应文件就可以,之后就不专门提了…

定时器流程:

 
/* 设置中断优先级,TM4C123G的中断优先级有8个,0最高 */ 
IntPrioritySet(INT_TIMER0A, 0);
          
  SysCtlClockSet(SYSCTL_SYSDIV_1|SYSCTL_USE_OSC|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);
  //系统时钟设置
 
 SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
//使能定时器模块Timer0。
 
 TimerConfigure(TIMER0_BASE,TIMER_CFG_PERIODIC);
 //配置定时器模块Timer0为Periodic周期性计数模式。

TimerLoadSet(TIMER0_BASE,TIMER_A,SysCtlClockGet()-1);
 //TimerLoadSet(TIMER0_BASE,TIMER_A,SysCtlClockGet()-1); //定时1s
 //设定定时器模块Timer0的Load重装载值为系统时钟频率的一半再减一(为0.5秒)。

TimerIntRegister(TIMER0_BASE,TIMER_A,IntHandle_TIMER0A);
  //注册中断服务函数,最后那个是中断服务函数句柄,其实后面看库函数手册这一步也可以不用啦,那时候中断入口函数名字就是官方默认的(具体是什么忘了...)  
       
  IntEnable(INT_TIMER0A);
 //使能定时器模块Timer0的定时器A的中断。

TimerIntEnable(TIMER0_BASE,TIMER_TIMA_TIMEOUT);
  //使能单独的定时器中断源,第一个TIMER0_BASE为Timer0的基地址,第二个是中断源启用的中断事件的标识码,TIMER_TIMA_TIMEOUT的意思是定时器A(TimerA)溢出(重装载),以此为标志位,当TimerA重装载时就会触发中断。
 
IntMasterEnable();
 //使能处理器中断,使处理器能够响应中断。

 TimerEnable(TIMER0_BASE,TIMER_A);
//使能定时器TimerA。


中断服务函数:



void IntHandle_TIMER0A(void)//和你注册中断句柄时的名称保持一致

{

 TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
       //清除标志位,第二个是中断类型,我这里是定时器A溢出中断
       
		{
		//其他逻辑
		}  

 }
  • 7
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值