[TM4]TM4C123G使用笔记(一)
TI的板子真让人头大?甚至重装了两遍KEIL5
如何用keil5新建工程可以参考如下博客:
https://blog.csdn.net/D_XingGuang/article/details/89390211?spm=1001.2014.3001.5506
记得在榔头里的C/C++勾选C99 Mode和GNU extensions,不然一大堆报错
下面主要是常用外设的使用
GPIO
常用函数
void SysCtlPeripheralEnable(uint32_t ui32Peripheral)
- 功能:使能外设时钟
- 参数:uint32_t ui32Peripheral:需要使能的外设,在本文中需要使能的外设为GPIO(例如SYSCTL_PERIPH_GPIOF)
- 说明:从使能操作开始到完成需要经过五个时钟周期,在此期间不可访问外设,否则会出现总线错误。
void GPIOPinTypeGPIOOutput(uint32_t ui32Port, uint8_t ui8Pins)
-
功能:配置引脚为输出模式
-
参数:参见下面例程
void GPIODirModeSet(uint32_t ui32Port, uint8_t ui8Pins,uint32_t ui32PinIO)
-
功能:设置引脚模式
-
参数:
#define GPIO_DIR_MODE_IN 0x00000000 // Pin is a GPIO input #define GPIO_DIR_MODE_OUT 0x00000001 // Pin is a GPIO output #define GPIO_DIR_MODE_HW 0x00000002 // Pin is a peripheral function
void GPIOPadConfigSet(uint32_t ui32Port, uint8_t ui8Pins,uint32_t ui32Strength, uint32_t ui32PadType)
-
功能:设置引脚PAD
-
参数:ui32Strength:输出驱动强度,正常设为2MA;ui32PadType:设置上下拉推挽开漏等
//输出驱动强度 GPIO_STRENGTH_2MA GPIO_STRENGTH_4MA GPIO_STRENGTH_8MA GPIO_STRENGTH_8MA_SC GPIO_STRENGTH_6MA GPIO_STRENGTH_10MA GPIO_STRENGTH_12MA //模式 GPIO_PIN_TYPE_STD // 推挽 GPIO_PIN_TYPE_STD_WPU // 弱上拉 GPIO_PIN_TYPE_STD_WPD // 弱下拉 GPIO_PIN_TYPE_OD // 开漏 GPIO_PIN_TYPE_ANALOG // 模拟 GPIO_PIN_TYPE_WAKE_HIGH GPIO_PIN_TYPE_WAKE_LOW -
注:该函数一般与上面的void GPIODirModeSet(uint32_t ui32Port, uint8_t ui8Pins,uint32_t ui32PinIO)函数连用
void GPIOPinWrite(uint32_t ui32Port, uint8_t ui8Pins, uint8_t ui8Val)
-
功能:写入高低电平
-
参数:ui8Val:低电平为0,高电平为引脚名(这个很特别,在读取电平也是一样的道理)
-
说明:例如GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2, GPIO_PIN_1|GPIO_PIN_2);表示Pin1和Pin2输出高电平。若引脚被设置为输入,则向该引脚输出是无效的。
int32_t GPIOPinRead(uint32_t ui32Port, uint8_t ui8Pins)
- 功能:读取电平
- 返回值:低电平为0,高电平为引脚名
例程:
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_gpio.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "inc/hw_memmap.h"
#include "driverlib/sysctl.h"
int main()
{
// 使能外设时钟
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
// 设置输出引脚
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1);
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_2);
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_3);
// 设置输入引脚
GPIODirModeSet(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_DIR_MODE_IN); // 设置为输入
GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU); // 上拉输入
while(1)
{
if(GPIOPinRead(GPIO_PORTF_BASE, GPIO_PIN_4) == GPIO_PIN_4) // 读取高电平,即按键没有被按下
{
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);
}
else // 按键按下
{
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2);
}
}
}
外部中断
常用函数
void GPIOIntTypeSet(uint32_t ui32Port, uint8_t ui8Pins, uint32_t ui32IntType)
- 功能:设置引脚中断的触发条件
- 参数:
GPIO_FALLING_EDGE // sets detection to edge and trigger to falling
GPIO_RISING_EDGE // sets detection to edge and trigger to rising
GPIO_BOTH_EDGES // sets detection to both edges
GPIO_LOW_LEVEL // sets detection to low level
GPIO_HIGH_LEVEL // sets detection to high level
void GPIOIntRegister(uint32_t ui32Port, void (*pfnIntHandler)(void))
- 功能:注册中断回调函数
- 参数:自定义的中断回调函数名称
void GPIOIntEnable(uint32_t ui32Port, uint32_t ui32IntFlags)
- 功能:使能GPIO端口中断
- 参数:ui32IntFlags:
GPIO_INT_PIN_x
GPIO_INT_DMA
void IntEnable(uint32_t ui32Interrupt)
- 功能:使能中断外设
- 参数:如 INT_GPIOx 等
void IntMasterEnable(void)
- 功能:使能处理器中断
uint32_t GPIOIntStatus(uint32_t ui32Port, bool bMasked)
- 功能:读取中断状态
- 参数:bMasked:指定返回被屏蔽的中断状态(true)还是原始的中断状态(false)
- 说明:被屏蔽的中断状态:就是只返回在GPIOIntEnable函数里被使能的ui32IntFlags的中断状态,其他的被屏蔽。
void GPIOIntClear(uint32_t ui32Port, uint32_t ui32IntFlags)
- 功能:清除指定中断源标志
- 说明:发生中断后,对应的中断标志位置1,进入中断服务函数,在服务函数中务必清除中断标志,否则程序将不停地进入中断服务函数
例程
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_gpio.h"
#include "inc/hw_ints.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "inc/hw_memmap.h"
#include "driverlib/sysctl.h"
#include "driverlib/interrupt.h"
void GPIOFIntHandler(void);
void GPIO_Init()
{
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
// 设置LED的IO引脚
GPIODirModeSet(GPIO_PORTF_BASE, GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1, GPIO_DIR_MODE_OUT);
GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
// 初始化LED
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1, 0);
}
void GPIO_Init_IT()
{
//使能外设
SysCtlPeripheralEnable( SYSCTL_PERIPH_GPIOF);
//配置GPIOF_PIN_4为输入
GPIODirModeSet(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_DIR_MODE_IN);
//设置GPIOF_PIN_4为推挽上拉输出,驱动强度小点就可以
GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);
//设置为下降沿触发
GPIOIntTypeSet( GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_FALLING_EDGE);
//注册中断回调函数
GPIOIntRegister( GPIO_PORTF_BASE,GPIOFIntHandler);
//三个函数用来开启中断
GPIOIntEnable( GPIO_PORTF_BASE, GPIO_INT_PIN_4);
IntEnable(INT_GPIOF);
IntMasterEnable();
}
int main()
{
// 时钟设置
SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN);
GPIO_Init();
GPIO_Init_IT();
while(1)
{
}
}
void GPIOFIntHandler(void)
{
// 读取中断状态
uint32_t GPIOF_IT_FLAG = GPIOIntStatus(GPIO_PORTF_BASE, true);
static int keyFlag;
// 清除标志位
GPIOIntClear(GPIO_PORTF_BASE, GPIO_INT_PIN_4);
// 如果是PIN4触发中断
if((GPIOF_IT_FLAG & GPIO_PIN_4) == GPIO_PIN_4)
{
keyFlag++;
}
// 改变灯的颜色
switch(keyFlag % 3)
{
case 0:
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, GPIO_PIN_1);
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, 0);
break;
case 1:
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 0);
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2);
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, 0);
break;
case 2:
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 0);
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, GPIO_PIN_3);
break;
}
}
Pulse Width Modulator(PWM)
与STM32相似,TM4C的PWM利用定时器实现,但TM4C的PWM模块中有自带的定时器,不需要像STM32那样使用定时器外设。
类比STM32,TM4C的分频系数相当于PSC,Period相当于ARR,Width相当于CCRx,PWM频率的计算公式为:
占空比的计算公式为:
观察PWM结构框图能知道,TM4C的PWM外设包含两个PWM模块,每个模块有4个PWM Generator,每个PWM Generator控制两个PWM信号的产生。同一个PWM Generator产生的两个PWM信号的Period是相同的,但Width可以不同。

下面的表格十分重要,编程时需要一一对照查表。

TM4C中PWM的配置过程
1、使能PWM时钟 SysCtlPeripheralEnable()
2、使能被复用引脚的时钟 SysCtlPeripheralEnable()
3、使能引脚复用PWM功能 GPIOPinTypePWM()
4、将PWM信号分配到合适的引脚上 GPIOPinConfigure()
5、使能PWM时钟,设置PWM分频器为4分频(PWM时钟源为10M) SysCtlPWMClockSet();
6、配置为向下计数,参数立即更新模式 PWMGenConfigure()
7、设置周期时间(定时器计数范围) PWMGenPeriodSet()
8、设置信号0占空比25%,信号1占空比75% PWMPulseWidthSet()
9、启动PWM发生器的定时器 PWMGenEnable()
10、使能PWM输出 PWMOutputState()
常用函数
void SysCtlPWMClockSet(uint32_t ui32Config)
- 功能:设置分频系数
- 参数:
//*****************************************************************************
//
// The following are values that can be passed to the SysCtlPWMClockSet() API
// as the ui32Config parameter, and can be returned by the SysCtlPWMClockGet()
// API.
//
//*****************************************************************************
#define SYSCTL_PWMDIV_1 0x00000000 // PWM clock is processor clock /1
#define SYSCTL_PWMDIV_2 0x00100000 // PWM clock is processor clock /2
#define SYSCTL_PWMDIV_4 0x00120000 // PWM clock is processor clock /4
#define SYSCTL_PWMDIV_8 0x00140000 // PWM clock is processor clock /8
#define SYSCTL_PWMDIV_16 0x00160000 // PWM clock is processor clock /16
#define SYSCTL_PWMDIV_32 0x00180000 // PWM clock is processor clock /32
#define SYSCTL_PWMDIV_64 0x001A0000 // PWM clock is processor clock /64
void GPIOPinTypePWM(uint32_t ui32Port, uint8_t ui8Pins)
- 功能:为引脚分配PWM信号
void GPIOPinConfigure(uint32_t ui32PinConfig)
- 功能:使能GPIO引脚复用
- 参数:GPIO_Pxx_xxxx(xx引脚的xxxx功能)
void PWMGenConfigure(uint32_t ui32Base, uint32_t ui32Gen,uint32_t ui32Config)
- 功能:配置PWM Generator
- 参数:ui32Config:PWM寄存器的计数方式
void PWMGenPeriodSet(uint32_t ui32Base, uint32_t ui32Gen,uint32_t ui32Period)
- 功能:设置PWM Generator的Period
void PWMPulseWidthSet(uint32_t ui32Base, uint32_t ui32PWMOut,uint32_t ui32Width)
- 功能:设置PWM Output的Width
void PWMOutputState(uint32_t ui32Base, uint32_t ui32PWMOutBits,bool bEnable)
- 功能:使能PWM Output
void PWMGenEnable(uint32_t ui32Base, uint32_t ui32Gen)
- 功能:使能PWM Generator
例程
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_gpio.h"
#include "inc/hw_ints.h"
#include "driverlib/gpio.h"
#include "driverlib/pwm.h"
#include "driverlib/pin_map.h"
#include "inc/hw_memmap.h"
#include "driverlib/sysctl.h"
#include "driverlib/interrupt.h"
#define Delay_ms(n); SysCtlDelay(n*(SysCtlClockGet()/3000));
void PWM_Init()
{
// 因为设置了时钟总线是40MHz,所以在这里分一下频设置为4分频,那么PWM时钟就是10MHz
SysCtlPWMClockSet(SYSCTL_PWMDIV_4);
// 使能时钟
SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM1); //使能PWM模块1时钟
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); //使能GPIOF时钟
// 分配pwm信号
GPIOPinTypePWM(GPIO_PORTF_BASE,GPIO_PIN_2);
GPIOPinTypePWM(GPIO_PORTF_BASE,GPIO_PIN_3);
// 使能引脚复用
GPIOPinConfigure(GPIO_PF2_M1PWM6); //PF2->PWM模块1信号6
GPIOPinConfigure(GPIO_PF3_M1PWM7); //PF3->PWM模块1信号7
// 配置PWM发生器
// 模块1->发生器3->上下计数,不同步
PWMGenConfigure(PWM1_BASE,PWM_GEN_3,PWM_GEN_MODE_UP_DOWN|PWM_GEN_MODE_NO_SYNC);
//配置PWM周期,此时PWM输出频率为10M/2k = 50000Hz。计数器为16位,故第三个参数不能超过65535
PWMGenPeriodSet(PWM1_BASE,PWM_GEN_3,2000);
//配置PWM占空比为1%
PWMPulseWidthSet(PWM1_BASE,PWM_OUT_6,PWMGenPeriodGet(PWM1_BASE, PWM_GEN_3)*0.01 - 1);
PWMPulseWidthSet(PWM1_BASE,PWM_OUT_7,PWMGenPeriodGet(PWM1_BASE, PWM_GEN_3)*0.01 - 1);
//使能PWM模块1输出
PWMOutputState(PWM1_BASE,PWM_OUT_6_BIT,true);
PWMOutputState(PWM1_BASE,PWM_OUT_7_BIT,true);
//使能PWM发生器
PWMGenEnable(PWM1_BASE,PWM_GEN_3);
}
void PWM_Set_Duty(uint32_t ui32Base,uint32_t ui32PWMOut,float duty)
{
uint32_t ui32Gen;
uint32_t ui32OutBits;
switch(ui32PWMOut)
{
case PWM_OUT_0: ui32Gen=PWM_GEN_0,ui32OutBits=PWM_OUT_0_BIT; break;
case PWM_OUT_1: ui32Gen=PWM_GEN_0,ui32OutBits=PWM_OUT_1_BIT; break;
case PWM_OUT_2: ui32Gen=PWM_GEN_1,ui32OutBits=PWM_OUT_2_BIT; break;
case PWM_OUT_3: ui32Gen=PWM_GEN_1,ui32OutBits=PWM_OUT_3_BIT; break;
case PWM_OUT_4: ui32Gen=PWM_GEN_2,ui32OutBits=PWM_OUT_4_BIT; break;
case PWM_OUT_5: ui32Gen=PWM_GEN_2,ui32OutBits=PWM_OUT_5_BIT; break;
case PWM_OUT_6: ui32Gen=PWM_GEN_3,ui32OutBits=PWM_OUT_6_BIT; break;
case PWM_OUT_7: ui32Gen=PWM_GEN_3,ui32OutBits=PWM_OUT_7_BIT; break;
}
//配置占空比
PWMPulseWidthSet(ui32Base, ui32PWMOut, PWMGenPeriodGet(ui32Base, ui32Gen)*duty - 1);
PWMOutputState(ui32Base, ui32OutBits, true);
//使能发生器模块
PWMGenEnable(ui32Base, ui32Gen);
}
int main()
{
float duty1=0.1,duty2=0.9;
float d=0.01; // 步长
// 设置时钟总线频率为40MHz
SysCtlClockSet( SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);
PWM_Init();
while(1)
{
PWM_Set_Duty(PWM1_BASE,PWM_OUT_6,duty1);
PWM_Set_Duty(PWM1_BASE,PWM_OUT_7,duty2);
Delay_ms(10);
duty1+=d;
duty2-=d;
if(duty1>=0.95 && duty2<=0.05) d=-0.01;
else if(duty2>=0.95 && duty1<=0.05) d=0.01;
}
}