前言
(1) 首先,我们需要知道TM4C123是M4的内核。对于绝大多数人而言,入门都是学习STM32F103,这款芯片是采用的M3的内核。所以想必各位对M3内核还是有一定的了解。M4内核就是M3内核的升级版本,他继承了M3的的所有功能,同时还增加和增强了如下功能:
<1> 增加了高精度 MAC,使得在 做算法计算时的性能更高;
<2>增加了浮点单元 FPU;
<3>增加了具有 SIMD 功能的 DSP 指令;
(2)这几个新增加的功能让M4内核的芯片有很强大的浮点运算功能,让M4的芯片多用于需要复杂的数字运算功能的场景。
开发环境搭建
keil工程环境搭建
(1)首先搜索引擎搜索keil,进入keil官网,搜索pack,然后按Ctrl+F搜索TEXAS(因为TI的英文名前缀是这个)。
(2)将pack文件导入到keil中。打开keil(注意,任意工程都行,就算没有工程是空白的也行)。点击左上角的PACK Installer
(3)进入PACK Installer之后,关闭弹窗——>点击左上角的File——>点击Import
(4)找到存放PACK的路径,然后打开他即可。之后你需要等待一段时间,右下角会有一个进度条,因为安装包是在国外网站,所以需要等待比较长的时间。
注意:TM4C123的pack名字不是如下图,因为我懒得重新演示,所以复制的我RA2E1 开发板教程截图。
(5)之后keil工程里面会弹出一个弹框,点击确定即可。
(6)之后按照下图确认是否pack已经安装
程序下载
(1)连接好下载器,设置下载器
(2)设置ROM的运算单元的起始位置和大小。以及设置编程算法
(3)编译,下载
TM4C123前缀带ROM的函数
函数介绍
ROM_FPUEnable();
因为在M4的内核中,可以有专门的浮点运算单元。所以当我们需要在程序中使用浮点运算的时候,需要调用ROM_FPUEnable()函数。
/****** 函数声明 ******/ //这个存放在ROM void ROM_FPUEnable(void); //这个是存放在flash void FPUEnable(void);
ROM_FPULazyStackingEnable();
当处理中断时,这个函数允许浮点寄存器s0-s15的延迟堆叠。当lazy stacking被启用时,堆栈上为浮点上下文保留空间,但不保存浮点状态。如果在中断上下文中执行一个浮点指令,那么该浮点上下文中首先被保存到堆栈预留的空间中。在中断处理程序完成时,只有保存了(作为执行浮点指令的结果)的浮点上下文才会被恢复。
(1)这提供了快速中断响应(因为在中断入口时不会保存浮点状态)和(2)在中断处理程序中使用浮点的能力(因为如果使用浮点指令,会保存浮点状态)之间的折衷。
/****** 函数声明 ******/ //这个存放在ROM void ROM_FPULazyStackingEnable(void); //这个是存放在flash void FPULazyStackingEnable(void);
ROM_SysCtlClockSet();
(1)这个函数用于设置设备时钟。一般采用ROM_SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ |SYSCTL_OSC_MAIN);设置系统时钟为80MHZ。
(2)如下为 TM4C123 的时钟树。很多人对于时钟树就头痛,起始没有必要害怕,我们现在只需要看系统时钟。因为它最重要,其他的时钟信号,要用到的时候再去看。
<1>咱们一个一个的看ROM_SysCtlClockSet()中传入的参数。SYSCTL_USE_PLL | SYSCTL_OSC_MAIN这一段话表示让PLL作为系统时钟的时钟源。
<2>SYSCTL_XTAL_16MHZ表示主振荡器为16MHZ,这个需要更具你的外部晶振频率来设定。因为本人的开发板外部晶振是16MHZ,所以选择SYSCTL_XTAL_16MHZ。
<3>SYSCTL_SYSDIV_2_5进行再次分频的。因为PLL输出400MHZ频率,返回进行了一次2分频之后是200MHZ。因为TM4C123最大频率为80MHZ,所以再次分频数必须大于2.5。我们这里选择分频2.5,让TM4C123以最大频率运转。
/****** 系统时钟设置为80MHZ ******/ ROM_SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ |SYSCTL_OSC_MAIN);//配置系统时钟,系统时钟频率400M/2/2.5=80M /****** 函数声明 ******/ //这个存放在ROM void ROM_SysCtlClockSet(uint32_t ui32Config); //这个存放在flash void SysCtlClockSet(uint32_t ui32Config);
ROM_SysCtlPeripheralEnable()
(1)经过上面的初始之后,我们现在可以正常进入LED程序编写了。系统上电的时候,IO口时钟是默认关闭的,作用是降低功耗。所以首先我们需要打开IO口时钟,因为我的开发板,LED是在PF4。所以我需要打开PF这一组IO的时钟。
/****** 函数声明 ******/ //这个存放在ROM void ROM_SysCtlPeripheralEnable(uint32_t ui32Peripheral); //这个存放在flash void SysCtlPeripheralEnable(uint32_t ui32Peripheral); /****** 函数介绍 ******/ /* 作用 : 使能IO * 传入参数 : * ui32Peripheral : 参数必须仅为下列值之一: SYSCTL_PERIPH_ADC0, SYSCTL_PERIPH_ADC1, SYSCTL_PERIPH_CAN0, SYSCTL_PERIPH_CAN1, SYSCTL_PERIPH_CCM0, SYSCTL_PERIPH_COMP0, SYSCTL_PERIPH_EEPROM0, SYSCTL_PERIPH_EMAC, SYSCTL_PERIPH_EPHY, SYSCTL_PERIPH_EPI0, SYSCTL_PERIPH_GPIOA, SYSCTL_PERIPH_GPIOB, SYSCTL_PERIPH_GPIOC, SYSCTL_PERIPH_GPIOD, SYSCTL_PERIPH_GPIOE, SYSCTL_PERIPH_GPIOF, SYSCTL_PERIPH_GPIOG, SYSCTL_PERIPH_GPIOH, SYSCTL_PERIPH_GPIOJ, SYSCTL_PERIPH_GPIOK, SYSCTL_PERIPH_GPIOL, SYSCTL_PERIPH_GPIOM, SYSCTL_PERIPH_GPION, SYSCTL_PERIPH_GPIOP, SYSCTL_PERIPH_GPIOQ, SYSCTL_PERIPH_GPIOR, SYSCTL_PERIPH_GPIOS, SYSCTL_PERIPH_GPIOT, SYSCTL_PERIPH_HIBERNATE, SYSCTL_PERIPH_I2C0, SYSCTL_PERIPH_I2C1, SYSCTL_PERIPH_I2C2, SYSCTL_PERIPH_I2C3, SYSCTL_PERIPH_I2C4, SYSCTL_PERIPH_I2C5, SYSCTL_PERIPH_I2C6, SYSCTL_PERIPH_I2C7, SYSCTL_PERIPH_I2C8, SYSCTL_PERIPH_I2C9, SYSCTL_PERIPH_LCD0, SYSCTL_PERIPH_ONEWIRE0, SYSCTL_PERIPH_PWM0, SYSCTL_PERIPH_PWM1, SYSCTL_PERIPH_QEI0, SYSCTL_PERIPH_QEI1, SYSCTL_PERIPH_SSI0, SYSCTL_PERIPH_SSI1, SYSCTL_PERIPH_SSI2, SYSCTL_PERIPH_SSI3, SYSCTL_PERIPH_TIMER0, SYSCTL_PERIPH_TIMER1, SYSCTL_PERIPH_TIMER2, SYSCTL_PERIPH_TIMER3, SYSCTL_PERIPH_TIMER4, SYSCTL_PERIPH_TIMER5, SYSCTL_PERIPH_TIMER6, SYSCTL_PERIPH_TIMER7, SYSCTL_PERIPH_UART0, SYSCTL_PERIPH_UART1, SYSCTL_PERIPH_UART2, SYSCTL_PERIPH_UART3, SYSCTL_PERIPH_UART4, SYSCTL_PERIPH_UART5, SYSCTL_PERIPH_UART6, SYSCTL_PERIPH_UART7, SYSCTL_PERIPH_UDMA, SYSCTL_PERIPH_USB0, SYSCTL_PERIPH_WDOG0, SYSCTL_PERIPH_WDOG1, SYSCTL_PERIPH_WTIMER0, SYSCTL_PERIPH_WTIMER1, SYSCTL_PERIPH_WTIMER2, SYSCTL_PERIPH_WTIMER3, SYSCTL_PERIPH_WTIMER4, or SYSCTL_PERIPH_WTIMER5 * 返回参数 : 无 */
ROM_GPIOPinTypeGPIOOutput()
因为我们想要点亮LED,那么就需要将IO口设置为输出引脚。使用这个函数可以将IO口设置为输出。
/****** 函数声明 ******/ //这个存放在ROM void ROM_GPIOPinTypeGPIOOutput(uint32_t ui32Port, uint8_t ui8Pins); //这个存放在flash void GPIOPinTypeGPIOOutput(uint32_t ui32Port, uint8_t ui8Pins); /****** 函数介绍 ******/ /* 作用 : 将IO口设置为输出 * 传入参数 : * ui32Port : GPIO_PORTx_BASE,x可为A,B,C,D,E,F,G,H,J,K * ui8Pins : GPIO_PIN_x,x可为1,2,3,4,5,6,7 *返回值 : 无 */
ROM_GPIOPinWrite()
我们配置完IO之后,需要需要设置它的输出引脚电平。因为我的LED是共阳,所以输出低电平才是点亮LED。
/****** 函数声明 ******/ //这个存放在ROM void ROM_GPIOPinWrite(uint32_t ui32Port, uint8_t ui8Pins, uint8_t ui8Val); //这个存放在flash void GPIOPinWrite(uint32_t ui32Port, uint8_t ui8Pins, uint8_t ui8Val); /****** 函数介绍 ******/ /* 作用 : 设置IO口电平 * 传入参数 : * ui32Port : GPIO_PORTx_BASE,x可为A,B,C,D,E,F,G,H,J,K * ui8Pins : GPIO_PIN_x,x可为1,2,3,4,5,6,7 * ui8Val : GPIO_PIN_x表示设置为高电平,!GPIO_PIN_x表示设置为低电平 *返回值 : 无 */
代码实操
#include "stdio.h" #include <stdint.h> #include <stdbool.h> #include "hw_memmap.h" #include "hw_types.h" #include "hw_gpio.h" #include "debug.h" #include "fpu.h" #include "gpio.h" #include "pin_map.h" #include "rom.h" #include "sysctl.h" #include "uart.h" #include "uartstdio.h" #ifdef DEBUG void __error__(char *pcFilename, uint32_t ui32Line) { } #endif int main(void) { ROM_FPUEnable();//使能浮点单元。这个函数必须在执行任何硬件浮点运算之前被调用;如果不这样做,将导致NOCP使用错误。 ROM_FPULazyStackingEnable();//浮点延迟堆栈,减少中断响应延迟 ROM_SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ |SYSCTL_OSC_MAIN);//配置系统时钟,系统时钟频率400M/2/2.5=80M ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); //使能GPIOF外设 ROM_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_4);// LED ROM_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_PIN_4);//置高位熄灭 while(1) { GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_5, !GPIO_PIN_5);//置低位点亮 SysCtlDelay(SysCtlClockGet() / 10); //延时0.1s,为什么先不用管,后面会讲解 GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_5, GPIO_PIN_5);//置高位熄灭 SysCtlDelay(SysCtlClockGet() / 10);//延时0.1s,为什么先不用管,后面会讲解 }