图库挂了
时钟
时钟源
TM4C123内部共有4个时钟源,见下表
时钟简介内部高精度振荡器(PIOSC)内部振荡器,其频率为16MHz,精度为1%,可以用来驱动PLL主振荡器 (MOSC)外部高速振荡器,频率可在4-25M间选择,可以驱动PLL(此时频率在5-25M)低频内部振荡器 (LFIOSC)适用于深度睡眠省电模式,它的频率是会改变的,范围在10KHz-90KHz之间,标准值30KHz休眠模块时钟源32.768KHz晶振,用于实时时钟源或睡眠时钟
时钟树
- MOSC和PIOSC可以用来驱动PLL
- PLL输出锁定在400MHz,它可以在经过二分频和SYSDIV分频(这个可以程序配置)后提供系统时钟。注意TM4C123G的最大主频为80MHz,因此配置时钟的时候,若使用的PLL,最小分频数只能是2.5分频。
时钟配置
使用函数 void SysCtlClockSet(uint32_t ui32Config); 进行系统时钟设置
这个函数参数是4个部分做按位与,包括 时钟分频SYSDIV设置,系统时钟来源(直接用振荡器,还是用PLL倍频过的),时钟源选择(对应上面表2.4),外接晶体频率- 1. 时钟分频SYSDIV设置
- #define SYSCTL_SYSDIV_1 0x07800000 // Processor clock is osc/pll /1
- #define SYSCTL_SYSDIV_2 0x00C00000 // Processor clock is osc/pll /2
- ...
- #define SYSCTL_SYSDIV_62 0x9EC00000 // Processor clock is osc/pll /62
- #define SYSCTL_SYSDIV_63 0x9F400000 // Processor clock is osc/pll /63
- #define SYSCTL_SYSDIV_64 0x9FC00000 // Processor clock is osc/pll /64
- #define SYSCTL_SYSDIV_2_5 0xC1000000 // Processor clock is pll / 2.5
- #define SYSCTL_SYSDIV_3_5 0xC1800000 // Processor clock is pll / 3.5
- #define SYSCTL_SYSDIV_4_5 0xC2000000 // Processor clock is pll / 4.5
- ...
- #define SYSCTL_SYSDIV_61_5 0xDE800000 // Processor clock is pll / 61.5
- #define SYSCTL_SYSDIV_62_5 0xDF000000 // Processor clock is pll / 62.5
- #define SYSCTL_SYSDIV_63_5 0xDF800000 // Processor clock is pll / 63.
复制代码- 2.系统时钟来源(直接用振荡器,还是用PLL倍频过的)
- #define SYSCTL_USE_PLL 0x00000000 // System clock is the PLL clock
- #define SYSCTL_USE_OSC 0x00003800 // System clock is the osc clock
复制代码- 3.时钟源选择(对应上面表2.4)
- #define SYSCTL_OSC_MAIN 0x00000000 // Osc source is main osc
- #define SYSCTL_OSC_INT 0x00000010 // Osc source is int. osc
- #define SYSCTL_OSC_INT4 0x00000020 // Osc source is int. osc /4
- #define SYSCTL_OSC_INT30 0x00000030 // Osc source is int. 30 KHz
- #define SYSCTL_OSC_EXT32 0x80000038 // Osc source is ext. 32 KHz
复制代码- 4.外接晶体频率
- #define SYSCTL_XTAL_1MHZ 0x00000000 // External crystal is 1MHz
- #define SYSCTL_XTAL_1_84MHZ 0x00000040 // External crystal is 1.8432MHz
- #define SYSCTL_XTAL_2MHZ 0x00000080 // External crystal is 2MHz
- #define SYSCTL_XTAL_2_45MHZ 0x000000C0 // External crystal is 2.4576MHz
- #define SYSCTL_XTAL_3_57MHZ 0x00000100 // External crystal is 3.579545MHz
- ...
- #define SYSCTL_XTAL_24MHZ 0x00000640 // External crystal is 24.0 MHz
- #define SYSCTL_XTAL_25MHZ 0x00000680 // External crystal is 25.0 MHz
复制代码 配置示例- /* MOSC频率16M,SYSDIV5分频,系统时钟源自PLL锁相环倍频,时钟源使用MOSC */
- /* 系统时钟频率400M/2/5=40M */
- SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_XTAL_16MHZ|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN);
- /* MOSC频率16M,SYSDIV2.5分频,系统时钟源自PLL锁相环倍频,时钟源使用MOSC */
- /* 系统时钟频率400M/2/2.5=80M , 注意这是上限了*/
- SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
- /* MOSC频率16M,SYSDIV不分频,系统时钟来自时钟源,时钟源使用MOSC */
- /* 系统时钟频率16M/1=16M */
- SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
复制代码 延时函数
TM4C库提供了一个延时函数,它利用汇编,提供了跨越工具链时恒定的延迟。延时3*ui32Count个时钟周期- __asm void SysCtlDelay(uint32_t ui32Count);
复制代码 但若系统时钟频率不同,一个时钟周期的长度也不同,一旦改了系统时钟频率,延时就会变化,需要改进
利用以下函数获取系统时钟频率(单位Hz)- uint32_t SysCtlClockGet(void);
复制代码 假设系统时钟频率为nHz,即(n/1000)KHz,设cnt=(n/1000),每秒有1000cnt个周期,每个cnt长1ms。
SysCtlDelay(Count)可以延时3Count个周期,令Count=cnt/3,即可延时1个cnt长(即1ms)
- //延时n毫秒,不用考虑时钟频率
- #define delay_ms(n); SysCtlDelay(n*(SysCtlClockGet()/3000));
复制代码 不管用哪个时钟源,只要工作频率高于40MHz,就会导致实际延时时间大于设置值。原因好像是芯片内部Flash的读取频率最大只能达到40M,
当工作频率大于40MHz时,通过预取两个字的指令来达到80M的运行主频。但是,当遇到SysCtlDelay函数这种短跳转时这个特性并不能很好的工作,每次都需要读取指令,所以时间就延长了
也就是说如果主频大于40M,SysCtlDelay(n*(SysCtlClockGet()/3000))这个方法也不是很准,可以考虑用ROM_SysCtlDelasy()
GPIO
RGB_LED
控制LED是一个三极管开关电路,单片机PF1/PF2/PF3连接到LED_R/LED_B/LED_G,GPIO输出高电平即可点亮二极管
相关库函数
1.使能外设时钟
- (1)void SysCtlPeripheralEnable(uint32_t ui32Peripheral)
复制代码 功能:使能外设时钟
参数:uint32_t ui32Peripheral 要使能的外设
说明:从写外设使能操作完成到实际上的外设使能间有5个时钟周期的延迟,这期间内访问外设将导致一个总线错误。应注 意确保在这段时间内不访问该外设。
2.引脚配置为输出模式
- (2)void GPIOPinTypeGPIOOutput(uint32_t ui32Port, uint8_t ui8Pins)
复制代码 功能:引脚配置为输出模式
参数:
ui32Port GPIO口的基地址
ui8Pins bit-packed格式表示的引脚
说明:要使GPIO引脚做为GPIO输出,必须正确地配置引脚。本函数提供这些引脚的典型配置。引脚使用bit-packed 字节格式表示,每一位表示一个要访问的引脚,位0表示引脚0,位1表示引脚1,以此类推。
底层:- void GPIOPadConfigSet(uint32_t ui32Port, uint8_t ui8Pins,uint32_t ui32Strength, uint32_t ui32PinType);//设置输出类型和强度
- void GPIODirModeSet(ui32Port, ui8Pins, GPIO_DIR_MODE_OUT);//设置方向(输入or输出)
复制代码 3.写值到指定引脚
- void GPIOPinWrite(uint32_t ui32Port, uint8_t ui8Pins, uint8_t ui8Val);
复制代码 功能:写值到指定引脚.
参数:
ui32Port GPIO口的基地制作.
ui8Pins bit-packed 格式表示的引脚
ui8Val 将要写入引脚的值.
说明:写相应位的数值到ui8Pins参数指定的引脚,写数值时不影响配置为输入的引脚状态。引脚用 bit-packed 字节格式表示, 每一个位代表一个引脚,位0表示GPIO口的引脚0,位1表示GPIO口的引脚1,以此类推。
4.不受频率影响的延时函数
- SysCtlDelay(100*(SysCtlClockGet()/3000));
复制代码 示例代码
- #include <stdint.h>
- #include <stdbool.h>
- #include "inc/hw_types.h" //通用类型和宏
- #include "inc/hw_memmap.h" //外设和存储器的基地址
- #include "driverlib/sysctl.h" //API函数中外设、状态等的标志
- #include "driverlib/gpio.h"
- int main(void)
- {
- uint8_t ui8LED = 2; //2 = 0010
- //1 = 0001
- //8 = 0100
-
- //系统时钟分频器系数|选择外部晶振频率|使用PLL锁相环作为系统时钟源
- SysCtlClockSet(SYSCTL_SYSDIV_6|SYSCTL_XTAL_16MHZ|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN);
- //使能PF时钟
- SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
- //配置引脚为GPIO输出,底层是GPIOPadConfigSet和GPIODirModeSet
- GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
-
- while(1)
- {
- // Turn on the LED :PF1(R),PF2(B),PF3(G)
- GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, ui8LED);
- // Delay for a bit
- SysCtlDelay(100*(SysCtlClockGet()/3000));
-
- // Cycle through Red, Green and Blue LEDs
- //写入2->4->8(0010->0100->1000)(R->B->G)
- if (ui8LED == 8)
- ui8LED = 2;
- else
- ui8LED = ui8LED*2;
- }
- }
复制代码 EXTI
相关库函数
1.设置指定引脚的中断触发类型.
- void GPIOIntTypeSet(uint32_t ui32Port, uint8_t ui8Pins,uint32_t ui32IntType)
复制代码 功能:设置指定引脚的中断触发类型.
参数:
(1)ui32Port: GPIO口的基地址
(2)ui8Pins: 多个bit-packed格式表示的引脚
(3)ui32IntType: 中断触发类型(有以下类型)- #define GPIO_FALLING_EDGE 0x00000000 // Interrupt on falling edge
- #define GPIO_RISING_EDGE 0x00000004 // Interrupt on rising edge
- #define GPIO_BOTH_EDGES 0x00000001 // Interrupt on both edges
- #define GPIO_LOW_LEVEL 0x00000002 // Interrupt on low level
- #define GPIO_HIGH_LEVEL 0x00000006 // Interrupt on high level
- //前5个都可和下面这个或运算一起作为ui32IntType参数,但不是所有引脚都支持离散中断,需要查手册
- #define GPIO_DISCRETE_INT 0x00010000 // Interrupt for individual pins
复制代码 说明: 为了避免毛刺引发的中断,用户必须确保GPIO口处于稳定状态时执行本函数
2.注册GPIO中断的中断处理程序
- void GPIOIntRegister(uint32_t ui32Port, void (*pfnIntHandler)(void))
复制代码 功能:注册GPIO中断的中断处理程序
参数:
(1)ui32Port :GPIO口的基地址
(2)pfnIntHandler: 是GPIO中断服务程序入口地址指针。
说明:
(1)不管是什么外设触发的中断,都要先注册中断服务函数,告诉程序中断发生时去哪里,类似的函数有SysCtlIntRegister、ADCIntRegister等
(2)如果不利用这些中断注册函数,也可以在启动文件中修改中断向量表进行手动注册
(3)GPIOIntRegister只能以GPIO组为单位注册,不能精确到判断哪个引脚发生中断,因此要在中断服务函数中判断触发中断的引脚,以下为一个示例- //GPIOF中断服务函数
- void io_interrupt(void)
- {
- //获取中断状态
- uint32_t s = GPIOIntStatus(GPIO_PORTF_BASE, true);
- //如果PF4触发中断
- if((s&GPIO_PIN_4) == GPIO_PIN_4)
- {...}
- }
复制代码 3.使能指定引脚的中断.
void GPIOIntEnable(uint32_t ui32Port, uint32_t ui32IntFlags)
功能:使能指定引脚的中断.
参数:
(1)ui32Port :GPIO口的基地址
(2)ui32IntFlags: 被禁止的中断源中断屏蔽位(指示哪些引脚中断被开启,是以下参数的逻辑或)- #define GPIO_INT_PIN_0 0x00000001
- #define GPIO_INT_PIN_1 0x00000002
- #define GPIO_INT_PIN_2 0x00000004
- #define GPIO_INT_PIN_3 0x00000008
- #define GPIO_INT_PIN_4 0x00000010
- #define GPIO_INT_PIN_5 0x00000020
- #define GPIO_INT_PIN_6 0x00000040
- #define GPIO_INT_PIN_7 0x00000080
复制代码 说明:这个函数是中断源级的中断使能控制
4.使能一个中断
- void IntEnable(uint32_t ui32Interrupt)
复制代码 功能:使能一个中断
参数:
(1)ui32Interrupt 指定的被允许的中断.
说明:这个函数是中断控制器级的中断使能控制
5.使能处理器中断
- bool IntMasterEnable(void)
复制代码 功能:使能处理器中断.
参数:无
说明:
(1)这是处理器级的中断使能控制,它决定处理器要不要处理中断控制器的请求
(2)以上三个函数,从低级到高级对应了中断处理通路的三道“开关”,如下图所示
6.读取指定GPIO口的中断状态
说明:这个函数是中断源级的中断使能控制
(4)void IntEnable(uint32_t ui32Interrupt)
功能:使能一个中断
参数:
(1)ui32Interrupt 指定的被允许的中断.
说明:这个函数是中断控制器级的中断使能控制
(5)bool IntMasterEnable(void)
功能:使能处理器中断.
参数:无
说明:
(1)这是处理器级的中断使能控制,它决定处理器要不要处理中断控制器的请求
(2)以上三个函数,从低级到高级对应了中断处理通路的三道“开关”,如下图所示
(3)void GPIOIntEnable(uint32_t ui32Port, uint32_t ui32IntFlags)
功能:使能指定引脚的中断.
参数:
(1)ui32Port :GPIO口的基地址
(2)ui32IntFlags: 被禁止的中断源中断屏蔽位(指示哪些引脚中断被开启,是以下参数的逻辑或)
#define GPIO_INT_PIN_0 0x00000001
#define GPIO_INT_PIN_1 0x00000002
#define GPIO_INT_PIN_2 0x00000004
#define GPIO_INT_PIN_3 0x00000008
#define GPIO_INT_PIN_4 0x00000010
#define GPIO_INT_PIN_5 0x00000020
#define GPIO_INT_PIN_6 0x00000040
#define GPIO_INT_PIN_7 0x00000080
1
2
3
4
5
6
7
8
说明:这个函数是中断源级的中断使能控制
(4)void IntEnable(uint32_t ui32Interrupt)
功能:使能一个中断
参数:
(1)ui32Interrupt 指定的被允许的中断.
说明:这个函数是中断控制器级的中断使能控制
(5)bool IntMasterEnable(void)
功能:使能处理器中断.
参数:无
说明:
(1)这是处理器级的中断使能控制,它决定处理器要不要处理中断控制器的请求
(2)以上三个函数,从低级到高级对应了中断处理通路的三道“开关”,如下图所示- uint32_t GPIOIntStatus(uint32_t ui32Port, bool bMasked)
复制代码 功能:读取指定GPIO口的中断状态
参数:
(1)ui32Port: GPIO口的基地址.
(2)bMasked: 指定返回屏蔽的中断状态还是原始的中断状态
说明: 如果bMasked被设置为真,则函数返回被屏蔽的中断状态,否则返回原始的中断状态。解释一下所谓“被屏蔽的中断状态”。在GPIOIntEnable这个函数中,没有写在第二个参数ui32IntFlags中的引脚是被屏蔽的(即不处理它们的中断事件)。当bMasked为真时,返回GPIOMIS寄存器值,所有被屏蔽的位都是0,否则返回GPIORIS寄存器值,被屏蔽的位也可能是1(因为虽然不处理这些引脚的中断事件,但它们的输入也可能符合中断特征)
返回值:返回指定GPIO口当前的中断状态,返回值是当前有效的GPIO_INT_∗values的逻辑或.
7.清除指定中断源标志
- void GPIOIntClear(uint32_t ui32Port, uint32_t ui32IntFlags)
复制代码 功能:清除指定中断源标志
参数:
(1)ui32Port :GPIO口的基地址
(2)ui32IntFlags :被清除的中断源中断屏蔽位
发生中断后,对应的中断标志位置1,进入中断服务函数,在服务函数中务必清除中断标志,否则程序将不停地进入中断服务函数
示例代码
[code]#include #include #include "inc/tm4c123gh6pm.h" //Register Definitions#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 ButtonsInit(void);void io_interrupt(void);int main(){ //使能时钟 SysCtlClockSet(SYSCTL_SYSDIV_4|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); //配置PF1/PF3为输出,点亮绿灯(PF3) GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE,GPIO_PIN_3|GPIO_PIN_1); GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_3|GPIO_PIN_1,1 |