TIVA TM4C123G LaunchPad学习过程
第一章开发工具
CCS开发环境是必不可少的,相关的资料比较多,这里不再介绍。在进行TIVA系列芯片学习的时候TIVA开发工具包是一定要安装的,里面集成几乎在开发过程中用到的所有函数库,相关下载安装的说明资料比较多,请自行查阅。好像现在最新的版本是2.1(在官网上有最新的下载)。不过现在很多的代码例程以1.0版本居多(也可能是我用的太少)。正常2.1版本兼容1.0,不过我就遇到过不兼容的案例,现在也没有找到原因(可能是经验不足)。
安装好开发环境CCS、开发工具包、及相应的驱动,再找一开发套件就可以学习了。
第二章开发工具包的应用
要想使用函数库,必须把包含这些函数库的相应开发工具包添加到工程文件中。添加方法:右键工程文件名→Properties→Build→ARMCompiler→IncludeOptions,在Adddirto#includesearchpath中添加你安装开发工具包,添加后相应的路径会出现在下方。例如:"C:\ti\TivaWare_C_Series-1.0",这个是1.0版本的工具包。
个人觉得这样就应该可以使用这个工具包中的函数库中的函数了,但是在实际应用中,出现了一些错误,需要再添加一个路径:右键工程文件名→Properties→ARMLinker→FileSearchPath,在Includelibraryfileorcommandfileasinput中添加链接"C:\ti\TivaWare_C_Series-1.0\driverlib\ccs\Debug\driverlib.lib"这个应该编译后的一类函数库。
不知是什么原因,请那位大虾有空科普下。
另外,还有一个问题:在添加这个链接后,如把源文件添加到工程中,对一些函数或变量会提示重复定义的错误。
(这方面的问题在后面有实例再说吧)
第三章时钟设置
在进行开发时,第一步要做的应该就是时钟设置了。关于时钟设置在相应芯片手册中有详细说明,我看一段时间,参数说明之后就是各种寄存器的配置,一个字“晕”,感觉这个东西作为查询手册用可能效果更好。
其实,关于时钟配置用一个API函数就可以配置了:SysCtlClockSet()。
这个函数在TIVA开发工具包中,路径:……\driverlib\sysctl.c,打开后可以看到源代码。关于这个函数的说明,查看路径:…..\docs\SW-DRL-UG-1.0.pdf,(安装版本不同,文件名会有区别)。
这里举例说明这个函数的使用方法:
在使用这个函数之前要添加头文件:#include"driverlib/sysctl.h"
之后就可以直接调用这个函数了,调用方法如下:
SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ)
这里对其中的变量时行说明:
SYSCTL_SYSDIV_5:分频系统,这里表示5分频;
SYSCTL_USE_PLL:锁相环至400MHz;
SYSCTL_OSC_MAIN:外部主晶振输入;
SYSCTL_XTAL_16MHZ:外部晶振是16MHz(这个要与硬件电路匹配)。
这个函数定义结果,外部输入16MHz,经PLL至400MHz,再2分频(芯片自带)至200MHz,再5分频至40MHz。因此这个设置的结果为主频40MHz。
如想更改主频设置,只须修改相应的变量即可,关于各变量的写法与定义,可以查阅文件:SW-DRL-UG-1.0.pdf,里面有详细说明。以后有空再加几个例程吧,这样对理解会更有帮助,欢迎大家自主补充。
第四章GPIO设置
这里先说下GPIO设置的步骤:
1) 配置系统时钟(这个在第三章已经介绍);
2) 打开与此GPIO端口对应的端口时钟。
3) 将端口配置为数字输入输出的GPIO功能,而不是端口的其它复用功能
4) 配置GPIO端口驱动电流大小和上下拉电阻的模式
5) 设置管脚的输入输出方向。
6) 设置管脚输出是高电平还是低电平。
同样TIVA函数库为我们提供了相应的API函数,下面举例进行介绍。
在配置之前别忘记加头文件:
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
1) 首先配置系统时钟:
//Setupthesystemclocktorunat50MhzfromPLLwithcrystalreference
SysCtlClockSet(SYSCTL_SYSDIV_4|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);
2) 使能PORTF端口
//EnableandconfiguretheGPIOportfortheLEDoperation.
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
SysCtlPeripheralEnable这个函数在……\driverlib\sysctl.c中,相关函数说明在…..\docs\SW-DRL-UG-1.0.pdf中。
变量SYSCTL_PERIPH_GPIOF定义在driverlib/sysctl.h中。
3)使PORTF为输出
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE,RED_LED|BLUE_LED|GREEN_LED);
GPIOPinTypeGPIOOutput这个函数在……\driverlib\gpio.c中,相关函数说明在…..\docs\SW-DRL-UG-1.0.pdf中。
4)下面是LED控制循环程序
//LoopForever
while(1)
{
// Turn on the Red LED
GPIOPinWrite(GPIO_PORTF_BASE,
RED_LED|BLUE_LED|GREEN_LED, RED_LED);
// Delay for a bit
SysCtlDelay(200000);
// Turn on the Blue LED
GPIOPinWrite(GPIO_PORTF_BASE,
RED_LED|BLUE_LED|GREEN_LED, BLUE_LED);
// Delay for a bit
SysCtlDelay(200000);
// Turn on the Green LED
GPIOPinWrite(GPIO_PORTF_BASE,
RED_LED|BLUE_LED|GREEN_LED, GREEN_LED);
// Delay for a bit
SysCtlDelay(200000);
}
GPIOPinWrite这个函数在……\driverlib\gpio.c中,相关函数说明在…..\docs\SW-DRL-UG-1.0.pdf中。另外,关于这个函数,网站的视频课件说的也非常详细可以看一下,视频做得非常好,只是在线看网络不绘图,下载无数次,成功次数没有突破0.
SysCtlDelay这个函数在……\driverlib\sysctl.c中,相关函数说明在…..\docs\SW-DRL-UG-1.0.pdf中。
这就是一个完整的GPIO配置,控制LED的程序。
注意事项:
1) 本程序用到了几个函数库,所以在起始时一定要添加这些函数库的头文件。
2) 要按第二章介绍,配置工程,即添加引用函路径和链接函数库,实例如下:
右键工程文件名→Properties→Build→ARMCompiler→IncludeOptions,在Adddirto#includesearchpath中添加你安装开发工具包,添加后相应的路径会出现在下方。例如:"C:\ti\TivaWare_C_Series-1.0",这个是1.0版本的工具包。
右键工程文件名→Properties→ARMLinker→FileSearchPath,在Includelibraryfileorcommandfileasinput中添加链接"C:\ti\TivaWare_C_Series-1.0\driverlib\ccs\Debug\driverlib.lib"。
***下面说下第二章提到的问题:
1)在第四章是利用已经编译好的库函数,直接调用,可以正确的运行程序。但是如想查看相应API函数源代码,你必须先知道这个函数在那个库,然后自主去打开(上面已经介绍相对应位置)。
如想直接查看,需要把相应的函数库添加到工程中,添加方法:
右键工程—–add files—–选择相应的源码文件
然后选择函数,按F3即可查看源代码。但是这样就出现了一个问题,在运行时会提示一堆错误,主要是重复定义错误。相应提示如下:(只是节选一部分,应该有代表性)
Description Resource Path Location Type
#10056 symbol "SysCtlADCSpeedGet" redefined: first defined in "./sysctl.obj"; redefined in "C:\ti\TivaWare_C_Series-1.0\driverlib\ccs\Debug\driverlib.lib<sysctl.obj>" gpiostudy C/C++ Problem
#10056 symbol "SysCtlADCSpeedSet" redefined: first defined in "./sysctl.obj"; redefined in "C:\ti\TivaWare_C_Series-1.0\driverlib\ccs\Debug\driverlib.lib<sysctl.obj>" gpiostudy C/C++ Problem
#10056 symbol "SysCtlClockSet" redefined: first defined in "./sysctl.obj"; redefined in "C:\ti\TivaWare_C_Series-1.0\driverlib\ccs\Debug\driverlib.lib<sysctl.obj>" gpiostudy C/C++ Problem
#10056 symbol "bNewPLL" redefined: first defined in "./sysctl.obj"; redefined in "C:\ti\TivaWare_C_Series-1.0\driverlib\ccs\Debug\driverlib.lib<sysctl.obj>" gpiostudy C/C++ Problem
#10056 symbol "SysCtlClockGet" redefined: first defined in "./sysctl.obj"; redefined in "C:\ti\TivaWare_C_Series-1.0\driverlib\ccs\Debug\driverlib.lib<sysctl.obj>" gpiostudy C/C++ Problem
关于这个问题,困惑了我很长时间,现在还没能准确理解个中原因,解决办法就是把添加到工程中的函数文件删除。但是这样想查看源文件代码就比较麻烦,不知这个问题能不能解决。
2)对于上面的问题,我尝试一种解决方法,但是不可行,还在研究中,下面说下方法过程。
根据上面错误提示,应该是重复定义冲突(个人理解),如果把函数库链接取消,即把
右键工程文件名→Properties→ARMLinker→FileSearchPath,在Includelibraryfileorcommandfileasinput中添加链接"C:\ti\TivaWare_C_Series-1.0\driverlib\ccs\Debug\driverlib.lib"。
这一步取消,不链接这个已经编译好的函数库。同时把这个工程引用的文件添加到工程中,主要是引用的头文件如下:
#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
同时把相应的.C文件也添加进来,添加方法如下:
右键工程—–add files—–选择相应的源码文件。
正常这样应该能解决问题了,但是只解决了一半。可以通过选择函数名,按F3,查看源代码,但是在编译的时候出现如下错误提示:
Description Resource Path Location Type
unresolved symbol IntDisable, first referenced in ./sysctl.obj gpiostudy C/C++ Problem
unresolved symbol CPUwfi, first referenced in ./sysctl.obj gpiostudy C/C++ Problem
unresolved symbol IntRegister, first referenced in ./sysctl.obj gpiostudy C/C++ Problem
unresolved symbol IntEnable, first referenced in ./sysctl.obj gpiostudy C/C++ Problem
<a href="file:/C:/ti/ccsv5/tools/compiler/dmed/HTML/10234.html">#10234-D</a> unresolved symbols remain gpiostudy C/C++ Problem
unresolved symbol IntUnregister, first referenced in ./sysctl.obj gpiostudy C/C++ Problem
#10010 errors encountered during linking; "gpiostudy.out" not built gpiostudy C/C++ Problem
请那位大虾科普下,这是什么原因,谢谢。
第五章:中断的使用
第六章:ADC
第七章:DAC
第八章:UART
第九章:I2C
第十章:USB
user4007620:
第五章:中断的使用
中断各类比较多,这一章里将分别进行学习。
5.1 外部中断
TM4C123G 所有的外设接口都可以设置成外部中断源。下面以一个例子来说明。
下面这个例程PD6和PD7作为中断源,分别接按钮;PF1和PF3分别驱动一个LED灯;当按下其中一个按钮时,可以驱动一个LED灯点亮。
首先设置时钟,使用LED驱动端全能输出:
// 设置系统主频
SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN
| SYSCTL_XTAL_16MHZ);
// Enable and configure the GPIO port for the LED operation.
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
(似乎用的外设,都必须先使能,这个印象中看到过说明,这些外设默认是不能用,要想用到这些外设,必须先使能)
下面这个代码是使相应LED驱动端为输出。
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE,RED_LED|BLUE_LED|GREEN_LED);
下面介绍如何设置外部中断:
void Init_Int_Key() {
// Make PD6/7 an output.
使能外部中断源外设:
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
按钮接入端设置为输入:
GPIODirModeSet(GPIO_PORTD_BASE, GPIO_PIN_6 | GPIO_PIN_7, GPIO_DIR_MODE_IN);
端口设置功率和弱上拉:
GPIOPadConfigSet(GPIO_PORTD_BASE, GPIO_PIN_6 | GPIO_PIN_7, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);
中断设置为低电平触发:
GPIOIntTypeSet(GPIO_PORTD_BASE, GPIO_PIN_6 | GPIO_PIN_7, GPIO_LOW_LEVEL);
使能相应端口中断
GPIOIntEnable(GPIO_PORTD_BASE, GPIO_PIN_6 | GPIO_PIN_7);
使能中断:
IntEnable(INT_GPIOD);
这个应该是使能全局中断:
IntMasterEnable();
(不理解为什么要设置这么多中断)
下面是清除相应端口中断标志:
GPIOIntClear(GPIO_PORTD_BASE, GPIO_PIN_6 | GPIO_PIN_7);
}
下面这一段是中断响应程序,比较易理解,这里只是贴出。
void Int_GPIO_D_Handler(void)
{
unsigned long ulStatus;
// 读取中断状态
ulStatus = GPIOIntStatus(GPIO_PORTD_BASE, true);
// 清除中断状态
GPIOIntClear(GPIO_PORTD_BASE, ulStatus);
// 如果KEY的中断状态有效
if (ulStatus & GPIO_PIN_7)
{
// 延时约10ms,消除按键抖动
SysCtlDelay(10 * (SysCtlClockGet() / 3000));
// 等待KEY抬起
while (GPIOPinRead(GPIO_PORTD_BASE, GPIO_PIN_7) == 0x00);
// 延时约10ms,消除松键抖动
SysCtlDelay(10 * (SysCtlClockGet() / 3000));
//TODO 逻辑处理
// if(cur_Col < (NUM_CHAR – 1))
// cur_Col++;
GPIOPinWrite(GPIO_PORTF_BASE,
RED_LED|BLUE_LED|GREEN_LED, RED_LED);
// Delay for a bit
SysCtlDelay(200000);
}
if (ulStatus & GPIO_PIN_6)// 如果KEY的中断状态有效
{
// 延时约10ms,消除按键抖动
SysCtlDelay(10 * (SysCtlClockGet() / 3000));
// 等待KEY抬起
while (GPIOPinRead(GPIO_PORTD_BASE, GPIO_PIN_6) == 0x00);
// 延时约10ms,消除松键抖动
SysCtlDelay(10 * (SysCtlClockGet() / 3000));
//TODO 逻辑处理
// if(cur_Col > 0)
// cur_Col–;
// Turn on the Green LED
GPIOPinWrite(GPIO_PORTF_BASE,
RED_LED|BLUE_LED|GREEN_LED, GREEN_LED);
// Delay for a bit
SysCtlDelay(200000);
}
}
下面是主程序代码:
int main(void) {
// 设置系统主频
SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN
| SYSCTL_XTAL_16MHZ);
// Enable and configure the GPIO port for the LED operation.
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE,RED_LED|BLUE_LED|GREEN_LED);
Init_Int_Key();
while(1)
{
}
}
注意:
1) 包含头文件路径必须要添加,这个在前面已经说明;
2) 必须在工程中添加文件:startup_ccs.c(目前还没有完全理解这个文件工作过程,这里只是提示一下,不做解释);
3) 必须添加一个宏定义:右键工程文件名→Properties→Build→ARMCompiler→Advance Options→Predefined Symbols,在Pre-definge NAME中添加变量:PART_TM4C123GH6PM和TARGET_IS_BLIZZARD_RA1,具体原因我现在还没有完全理解。
user4007620:
回复 user4007620:
5.2 看门狗
首先要使能看门狗(这个很重要),这个芯片的基础:
SysCtlPeripheralEnable(SYSCTL_PERIPH_WDOG0);
判断看门狗是否补锁,如锁则解:
// Check to see if the registers are locked, and if so, unlock them.
if(WatchdogLockState(WATCHDOG0_BASE) == true)
{
WatchdogUnlock(WATCHDOG0_BASE);
}
给看门狗设定初值,看门狗从此数值开始减小,直到0,给控制器一个中断,再重新计时,到第二次达到0时,才复位,具体过程现在还没有完全理解。
// Initialize the watchdog timer.
WatchdogReloadSet(WATCHDOG0_BASE, SysCtlClockGet());
使能复位功能
// Enable the reset.
WatchdogResetEnable(WATCHDOG0_BASE);
使能看门狗,应该是从此时开始计时
// Enable the watchdog timer.
WatchdogEnable(WATCHDOG0_BASE);
喂狗程序:
WatchdogReloadSet(WATCHDOG0_BASE, SysCtlClockGet());
注意:
利用这个代码狗赋值:WatchdogReloadSet(WATCHDOG0_BASE, SysCtlClockGet());
即初值是系统时钟,这样看门狗理论上是应该1秒产生中断,如果考虑到上面提到的需要两次减计数到0,应该是2秒才产生复位。所以应该是2秒内喂狗即(没有测试过,只是分析)。
jiabao mo:
回复 user4007620:
有串口的实例吗?
Michael Sun:
回复 jiabao mo:
安装TivaWare,然后到这个路径下寻找:
C:\ti\TivaWare_C_Series-2.1.0.12573\examples\boards\ek-tm4c123gxl\uart_echo
jiabao mo:
回复 Michael Sun:
不好使呀,你们试过吗?
xyz549040622:
回复 jiabao mo:
你的问题是还没建立起一个工程,简单的说,就是你实际的器件和例程中选择的器件不同,你在pin_map.h中增加你的芯片型号的预定义就可以么
jiabao mo:
回复 xyz549040622:
谢谢,明白了
XiaoLong Liu:
回复 user4007620:
tm4c的看门狗是第一次count down的时候会给系统一个提示,然后reload设置的值,当第二次count down后仍然没有喂狗的话就产生看门狗复位或者中断,这个是可以通过函数设置的。
XiaoLong Liu:
回复 user4007620:
在Pre-definge NAME中添加变量:PART_TM4C123GH6PM和TARGET_IS_BLIZZARD_RA1,这个添加的原因是tm4c是一个系列的片子,Tivaware 是库函数,里边的函数包括了所有片子的功能函数,但是不同的片子引脚和寄存器会有一些不同,通过预先宏定义的方式让编译器区分不同的片子和相对应的函数。
xyz549040622:
回复 XiaoLong Liu:
这一步是最重要的,好多人提示外设没有定义,就是没有进行这一步。