找回密码
 立即注册
首页 业界区 安全 TM4C123G_study

TM4C123G_study

崔瑜然 2025-6-9 14:29:59
图库挂了

时钟

时钟源

TM4C123内部共有4个时钟源,见下表
时钟简介内部高精度振荡器(PIOSC)内部振荡器,其频率为16MHz,精度为1%,可以用来驱动PLL主振荡器 (MOSC)外部高速振荡器,频率可在4-25M间选择,可以驱动PLL(此时频率在5-25M)低频内部振荡器 (LFIOSC)适用于深度睡眠省电模式,它的频率是会改变的,范围在10KHz-90KHz之间,标准值30KHz休眠模块时钟源32.768KHz晶振,用于实时时钟源或睡眠时钟
1.png

时钟树
2.png


  • MOSC和PIOSC可以用来驱动PLL
  • PLL输出锁定在400MHz,它可以在经过二分频和SYSDIV分频(这个可以程序配置)后提供系统时钟。注意TM4C123G的最大主频为80MHz,因此配置时钟的时候,若使用的PLL,最小分频数只能是2.5分频
时钟配置

使用函数 void SysCtlClockSet(uint32_t ui32Config); 进行系统时钟设置
这个函数参数是4个部分做按位与,包括 时钟分频SYSDIV设置,系统时钟来源(直接用振荡器,还是用PLL倍频过的),时钟源选择(对应上面表2.4),外接晶体频率
  1. 1. 时钟分频SYSDIV设置
  2.         #define SYSCTL_SYSDIV_1         0x07800000  // Processor clock is osc/pll /1
  3.                 #define SYSCTL_SYSDIV_2         0x00C00000  // Processor clock is osc/pll /2
  4.                 ...
  5.                 #define SYSCTL_SYSDIV_62        0x9EC00000  // Processor clock is osc/pll /62
  6.                 #define SYSCTL_SYSDIV_63        0x9F400000  // Processor clock is osc/pll /63
  7.                 #define SYSCTL_SYSDIV_64        0x9FC00000  // Processor clock is osc/pll /64
  8.                 #define SYSCTL_SYSDIV_2_5       0xC1000000  // Processor clock is pll / 2.5
  9.                 #define SYSCTL_SYSDIV_3_5       0xC1800000  // Processor clock is pll / 3.5
  10.                 #define SYSCTL_SYSDIV_4_5       0xC2000000  // Processor clock is pll / 4.5
  11.                 ...
  12.                 #define SYSCTL_SYSDIV_61_5      0xDE800000  // Processor clock is pll / 61.5
  13.                 #define SYSCTL_SYSDIV_62_5      0xDF000000  // Processor clock is pll / 62.5
  14.                 #define SYSCTL_SYSDIV_63_5      0xDF800000  // Processor clock is pll / 63.
复制代码
  1. 2.系统时钟来源(直接用振荡器,还是用PLL倍频过的)
  2.             #define SYSCTL_USE_PLL          0x00000000  // System clock is the PLL clock
  3.                 #define SYSCTL_USE_OSC          0x00003800  // System clock is the osc clock
复制代码
  1. 3.时钟源选择(对应上面表2.4)
  2.                 #define SYSCTL_OSC_MAIN         0x00000000  // Osc source is main osc
  3.                 #define SYSCTL_OSC_INT          0x00000010  // Osc source is int. osc
  4.                 #define SYSCTL_OSC_INT4         0x00000020  // Osc source is int. osc /4
  5.                 #define SYSCTL_OSC_INT30        0x00000030  // Osc source is int. 30 KHz
  6.                 #define SYSCTL_OSC_EXT32        0x80000038  // Osc source is ext. 32 KHz
复制代码
  1. 4.外接晶体频率
  2.                 #define SYSCTL_XTAL_1MHZ        0x00000000  // External crystal is 1MHz
  3.                 #define SYSCTL_XTAL_1_84MHZ     0x00000040  // External crystal is 1.8432MHz
  4.                 #define SYSCTL_XTAL_2MHZ        0x00000080  // External crystal is 2MHz
  5.                 #define SYSCTL_XTAL_2_45MHZ     0x000000C0  // External crystal is 2.4576MHz
  6.                 #define SYSCTL_XTAL_3_57MHZ     0x00000100  // External crystal is 3.579545MHz
  7.                 ...
  8.                 #define SYSCTL_XTAL_24MHZ       0x00000640  // External crystal is 24.0 MHz
  9.                 #define SYSCTL_XTAL_25MHZ       0x00000680  // External crystal is 25.0 MHz
复制代码
配置示例
  1. /* MOSC频率16M,SYSDIV5分频,系统时钟源自PLL锁相环倍频,时钟源使用MOSC */
  2. /* 系统时钟频率400M/2/5=40M */
  3. SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_XTAL_16MHZ|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN);       
  4. /* MOSC频率16M,SYSDIV2.5分频,系统时钟源自PLL锁相环倍频,时钟源使用MOSC */
  5. /* 系统时钟频率400M/2/2.5=80M , 注意这是上限了*/
  6. SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
  7. /* MOSC频率16M,SYSDIV不分频,系统时钟来自时钟源,时钟源使用MOSC */
  8. /* 系统时钟频率16M/1=16M */
  9. SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
复制代码
延时函数

TM4C库提供了一个延时函数,它利用汇编,提供了跨越工具链时恒定的延迟。延时3*ui32Count个时钟周期
  1. __asm void SysCtlDelay(uint32_t ui32Count);
复制代码
但若系统时钟频率不同,一个时钟周期的长度也不同,一旦改了系统时钟频率,延时就会变化,需要改进
利用以下函数获取系统时钟频率(单位Hz)
  1. uint32_t SysCtlClockGet(void);
复制代码
假设系统时钟频率为nHz,即(n/1000)KHz,设cnt=(n/1000),每秒有1000cnt个周期,每个cnt长1ms。
SysCtlDelay(Count)可以延时3
Count个周期,令Count=cnt/3,即可延时1个cnt长(即1ms)

    1. //延时n毫秒,不用考虑时钟频率
    2.                 #define delay_ms(n); SysCtlDelay(n*(SysCtlClockGet()/3000));
    复制代码
不管用哪个时钟源,只要工作频率高于40MHz,就会导致实际延时时间大于设置值。原因好像是芯片内部Flash的读取频率最大只能达到40M,
当工作频率大于40MHz时,通过预取两个字的指令来达到80M的运行主频。但是,当遇到SysCtlDelay函数这种短跳转时这个特性并不能很好的工作,每次都需要读取指令,所以时间就延长了
也就是说如果主频大于40M,SysCtlDelay(n*(SysCtlClockGet()/3000))这个方法也不是很准,可以考虑用ROM_SysCtlDelasy()
GPIO

RGB_LED

3.png

4.png

控制LED是一个三极管开关电路,单片机PF1/PF2/PF3连接到LED_R/LED_B/LED_G,GPIO输出高电平即可点亮二极管
相关库函数

1.使能外设时钟
  1. (1)void SysCtlPeripheralEnable(uint32_t ui32Peripheral)
复制代码
功能:使能外设时钟
参数:uint32_t ui32Peripheral 要使能的外设
说明:从写外设使能操作完成到实际上的外设使能间有5个时钟周期的延迟,这期间内访问外设将导致一个总线错误。应注 意确保在这段时间内不访问该外设。
2.引脚配置为输出模式
  1. (2)void GPIOPinTypeGPIOOutput(uint32_t ui32Port, uint8_t ui8Pins)
复制代码
功能:引脚配置为输出模式
参数:
ui32Port GPIO口的基地址
ui8Pins bit-packed格式表示的引脚
说明:要使GPIO引脚做为GPIO输出,必须正确地配置引脚。本函数提供这些引脚的典型配置。引脚使用bit-packed 字节格式表示,每一位表示一个要访问的引脚,位0表示引脚0,位1表示引脚1,以此类推。
底层:
  1. void GPIOPadConfigSet(uint32_t ui32Port, uint8_t ui8Pins,uint32_t ui32Strength, uint32_t ui32PinType);//设置输出类型和强度
  2. void GPIODirModeSet(ui32Port, ui8Pins, GPIO_DIR_MODE_OUT);//设置方向(输入or输出)
复制代码
3.写值到指定引脚
  1. 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.不受频率影响的延时函数
  1. SysCtlDelay(100*(SysCtlClockGet()/3000));
复制代码
示例代码
  1. #include <stdint.h>
  2. #include <stdbool.h>
  3. #include "inc/hw_types.h"                                        //通用类型和宏
  4. #include "inc/hw_memmap.h"                                        //外设和存储器的基地址
  5. #include "driverlib/sysctl.h"                                //API函数中外设、状态等的标志
  6. #include "driverlib/gpio.h"
  7. int main(void)
  8. {
  9.         uint8_t ui8LED = 2;        //2 = 0010
  10.                         //1 = 0001
  11.                         //8 = 0100
  12.    
  13.         //系统时钟分频器系数|选择外部晶振频率|使用PLL锁相环作为系统时钟源
  14. SysCtlClockSet(SYSCTL_SYSDIV_6|SYSCTL_XTAL_16MHZ|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN);
  15.         //使能PF时钟
  16.         SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);       
  17.    //配置引脚为GPIO输出,底层是GPIOPadConfigSet和GPIODirModeSet       
  18.         GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);                                               
  19.        
  20.         while(1)
  21.         {
  22.                 // Turn on the LED :PF1(R),PF2(B),PF3(G)
  23.                 GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, ui8LED);       
  24.                 // Delay for a bit               
  25.                 SysCtlDelay(100*(SysCtlClockGet()/3000));
  26.                
  27.                 // Cycle through Red, Green and Blue LEDs
  28.                 //写入2->4->8(0010->0100->1000)(R->B->G)
  29.                 if (ui8LED == 8)
  30.                         ui8LED = 2;
  31.                 else
  32.                         ui8LED = ui8LED*2;                                                               
  33.         }
  34. }
复制代码
EXTI

相关库函数

1.设置指定引脚的中断触发类型.
  1. void GPIOIntTypeSet(uint32_t ui32Port, uint8_t ui8Pins,uint32_t ui32IntType)
复制代码
功能:设置指定引脚的中断触发类型.
参数:
(1)ui32Port: GPIO口的基地址
(2)ui8Pins: 多个bit-packed格式表示的引脚
(3)ui32IntType: 中断触发类型(有以下类型)
  1. #define GPIO_FALLING_EDGE       0x00000000  // Interrupt on falling edge
  2.                 #define GPIO_RISING_EDGE        0x00000004  // Interrupt on rising edge
  3.                 #define GPIO_BOTH_EDGES         0x00000001  // Interrupt on both edges
  4.                 #define GPIO_LOW_LEVEL          0x00000002  // Interrupt on low level
  5.                 #define GPIO_HIGH_LEVEL         0x00000006  // Interrupt on high level
  6.                 //前5个都可和下面这个或运算一起作为ui32IntType参数,但不是所有引脚都支持离散中断,需要查手册
  7.                 #define GPIO_DISCRETE_INT       0x00010000  // Interrupt for individual pins
复制代码
说明: 为了避免毛刺引发的中断,用户必须确保GPIO口处于稳定状态时执行本函数
2.注册GPIO中断的中断处理程序
  1. void GPIOIntRegister(uint32_t ui32Port, void (*pfnIntHandler)(void))
复制代码
功能:注册GPIO中断的中断处理程序
参数:
(1)ui32Port :GPIO口的基地址
(2)pfnIntHandler: 是GPIO中断服务程序入口地址指针。
说明:
(1)不管是什么外设触发的中断,都要先注册中断服务函数,告诉程序中断发生时去哪里,类似的函数有SysCtlIntRegister、ADCIntRegister等
(2)如果不利用这些中断注册函数,也可以在启动文件中修改中断向量表进行手动注册
(3)GPIOIntRegister只能以GPIO组为单位注册,不能精确到判断哪个引脚发生中断,因此要在中断服务函数中判断触发中断的引脚,以下为一个示例
  1.                 //GPIOF中断服务函数
  2.                 void io_interrupt(void)
  3.                 {       
  4.                         //获取中断状态
  5.                         uint32_t s = GPIOIntStatus(GPIO_PORTF_BASE, true);
  6.                         //如果PF4触发中断
  7.                           if((s&GPIO_PIN_4) == GPIO_PIN_4)
  8.                         {...}
  9.                 }
复制代码
3.使能指定引脚的中断.

void GPIOIntEnable(uint32_t ui32Port, uint32_t ui32IntFlags)
功能:使能指定引脚的中断.
参数:
(1)ui32Port :GPIO口的基地址
(2)ui32IntFlags: 被禁止的中断源中断屏蔽位(指示哪些引脚中断被开启,是以下参数的逻辑或)
  1.         #define GPIO_INT_PIN_0          0x00000001
  2.                 #define GPIO_INT_PIN_1          0x00000002
  3.                 #define GPIO_INT_PIN_2          0x00000004
  4.                 #define GPIO_INT_PIN_3          0x00000008
  5.                 #define GPIO_INT_PIN_4          0x00000010
  6.                 #define GPIO_INT_PIN_5          0x00000020
  7.                 #define GPIO_INT_PIN_6          0x00000040
  8.                 #define GPIO_INT_PIN_7          0x00000080
复制代码
说明:这个函数是中断源级的中断使能控制
4.使能一个中断
  1. void IntEnable(uint32_t ui32Interrupt)
复制代码
功能:使能一个中断
参数:
(1)ui32Interrupt 指定的被允许的中断.
说明:这个函数是中断控制器级的中断使能控制
5.使能处理器中断
  1. bool IntMasterEnable(void)
复制代码
功能:使能处理器中断.
参数:无
说明:
(1)这是处理器级的中断使能控制,它决定处理器要不要处理中断控制器的请求
(2)以上三个函数,从低级到高级对应了中断处理通路的三道“开关”,如下图所示
5.png

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)以上三个函数,从低级到高级对应了中断处理通路的三道“开关”,如下图所示
  1. 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的逻辑或.
6.png

7.清除指定中断源标志
  1. 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
您需要登录后才可以回帖 登录 | 立即注册