崔瑜然 发表于 2025-6-9 14:29:59

TM4C123G_study

图库挂了

时钟

时钟源

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 clock3.时钟源选择(对应上面表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 KHz4.外接晶体频率
                #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,进入中断服务函数,在服务函数中务必清除中断标志,否则程序将不停地进入中断服务函数
示例代码

#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
页: [1]
查看完整版本: TM4C123G_study