图库挂了
时钟
时钟源
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 | 1. 时钟分频SYSDIV设置 |
1 | 2.系统时钟来源(直接用振荡器,还是用PLL倍频过的) |
1 | 3.时钟源选择(对应上面表2.4) |
1 | 4.外接晶体频率 |
配置示例
1 | /* MOSC频率16M,SYSDIV5分频,系统时钟源自PLL锁相环倍频,时钟源使用MOSC */ |
延时函数
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)可以延时3Count个周期,令Count=cnt/3,即可延时1个cnt长(即1ms)
//延时n毫秒,不用考虑时钟频率 #define delay_ms(n); SysCtlDelay(n*(SysCtlClockGet()/3000));1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
不管用哪个时钟源,只要工作频率高于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.使能外设时钟
```c
(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);//设置输出类型和强度 |
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 |
|
EXTI
相关库函数
1.设置指定引脚的中断触发类型.
1 | void GPIOIntTypeSet(uint32_t ui32Port, uint8_t ui8Pins,uint32_t ui32IntType) |
功能:设置指定引脚的中断触发类型.
参数:
(1)ui32Port: GPIO口的基地址
(2)ui8Pins: 多个bit-packed格式表示的引脚
(3)ui32IntType: 中断触发类型(有以下类型)
1 |
|
说明: 为了避免毛刺引发的中断,用户必须确保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中断服务函数 |
3.使能指定引脚的中断.
void GPIOIntEnable(uint32_t ui32Port, uint32_t ui32IntFlags)
功能:使能指定引脚的中断.
参数:
(1)ui32Port :GPIO口的基地址
(2)ui32IntFlags: 被禁止的中断源中断屏蔽位(指示哪些引脚中断被开启,是以下参数的逻辑或)
1 |
说明:这个函数是中断源级的中断使能控制
4.使能一个中断
1 | void IntEnable(uint32_t ui32Interrupt) |
功能:使能一个中断
参数:
(1)ui32Interrupt 指定的被允许的中断.
说明:这个函数是中断控制器级的中断使能控制
5.使能处理器中断
1 | 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)以上三个函数,从低级到高级对应了中断处理通路的三道“开关”,如下图所示
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的逻辑或.
7.清除指定中断源标志
1 | void GPIOIntClear(uint32_t ui32Port, uint32_t ui32IntFlags) |
功能:清除指定中断源标志
参数:
(1)ui32Port :GPIO口的基地址
(2)ui32IntFlags :被清除的中断源中断屏蔽位
发生中断后,对应的中断标志位置1,进入中断服务函数,在服务函数中务必清除中断标志,否则程序将不停地进入中断服务函数
示例代码
1 |
|
UART
1.Tiva控制器的UART特征
2.UART结构图
UART和引脚的复用映射表
这个表非常重要,编程时要根据这个参考
(TM4C123GXL板子:串口0的接收端不能用,串口1正常,串口2也不正常,涉及到芯片部分IO解锁的东西)
3.FIFO操作
看来许多人还没有真正理解FIFO的作用和优点,仍然停留在每收发一个字符就要中断处理一次的老思路上。UART收发FIFO主要是为了解决收发中断过于频繁而导致的CPU效率不高的问题。
FIFO的必要性。在进行UART通信时,中断方式比轮询方式要简便且效率高。但是,如果没有收发FIFO,则每传输一个数据(5~8位)都要中断处理一次,效率仍然不高。如果有了收发FIFO,则可以在连续收发若干个数据(可多至14个)后才产生一次中断,然后一起处理。这就大大提高了收发效率。
接收超时问题。如果没有接收超时功能,则在对方已经发送完毕而接收FIFO未填满时并不会触发中断(FIFO满才会触发中断),结果造成最后接收的有效数据得不到处理的问题。有了接收超时功能后,如果接收FIFO未填满而对方发送已经停,则在不超过3个数据的接收时间内就会触发超时中断,因此数据会照常得到处理。
总之,FIFO的设计是优秀而合理的,它已经帮你想到了收发过程中存在的任何问题,只要初始化配置UART后,就可以放心收发了,FIFO和中断例程会自动搞定一切!
完全不必要担心FIFO大大减少了中断产生的次数而“可能”造成数据丢失的问题!
发送时,只要发送FIFO不满,数据只管往里连续放,放完后就直接退出发送子程序。随后,FIFO真正发送完成后会自动产生中断,通知主程序说:我已经完成真正的发送。
接收时,如果对方是连续不间断发送,则填满FIFO后会以中断的方式通知主程序说:现在有一批数据来了,请处理。
如果对方是间断性发送,也不要紧,当间隔时间过长时(2~3个字符传输时间),也会产生中断,这次是超时中断,通知主程序说:对方可能已经发送完毕,但FIFO未满,也请处理。
每个UART有两个16x8的缓冲区,一个用来发送,一个用来接收
FIFO状态通过UART标志寄存器UARTFR和UART接收状态寄存器(UARTRSR)显示。硬件监视空、满和溢出情况。
FIFO产生中断的触发条件由 UART中断FIFO深度选择(UARTIFLS)控制。两个FIFO可以单独配置为不同的电平情况下触发中断。可以选择如下配置:1/8、1/4、1/2、3/4、7/8。(例如:1/4代表连续FIFO装入16*1/4=4个字节产生一个接受中断)
复位后FIFO都是禁用的并作为1字节的保留寄存器,FIFO中断默认为两个都是1/2选项。通过UARTLCRH的FEN位启用FIFO。
注意:关于复位后FIFO是默认使能还是禁用,似乎TI手册之间有矛盾,总之不要用默认设置,自己手动设置一下吧
以下内容来自ti的getting start手册
相关库函数
\1. UARTConfigSet()
配置UART,例如:
// 配置UART2:波特率9600,数据位8,停止位1,无校验
UARTConfigSet(UART2_BASE, 9600, UART_CONFIG_WLEN_8 |
UART_CONFIG_STOP_ONE |
UART_CONFIG_PAR_NONE);
\2. UARTFIFOLevelSet()
设置UART收发FIFO的深度,可以设置的深度有2、4、8、12、14
\3. UARTSpaceAvail()
确认在发送FIFO里是否有可利用的空间。
\4. UARTCharsAvail()
确认在接收FIFO里是否存在字符。
\5. UARTCharPutNonBlocking()
该函数要与UARTSpaceAvail()配合使用,如果已确认发送FIFO里有可用空间,则将字符直接放入发送FIFO,不等待。
\6. UARTCharGetNonBlocking()
该函数要与UARTCharsAvail()配合使用,如果已确认接收FIFO里有字符,则直接从接收FIFO里读取字符,不等待。
\7. UARTCharPut()
将字符放到发送FIFO里,如果没有可用空间则一直等待。
\8. UARTCharGet()
从接收FIFO里读取字符,如果没有字符则一直等待。
\9. UARTIntEnable()
使能一个或多个UART中断,例如:
// 同时使能接收中断(接收FIFO溢出)和接收超时中断
UARTIntEnable(UART2_BASE, UART_INT_RX | UART_INT_RT);
4.中断
如下介绍,建议结合相关的寄存器看,包括UARTCTL寄存器和UARTIFLS寄存器
- 接收超时中断:当FIFO不是空的,并且在32位期间没有接收到进一步的数据时触发
- 接收中断:如果开启FIFO,当收数据>=FIFO深度时触发;否则每次接收到数据都触发
- 发送中断:如果开启FIFO,当FIFO中数据<=FIFO深度时触发;否则在FIFO中没有数据时触发
5.示例代码
1 | /*官方例程1*/ |
1 | static void Uart1_Init(void){ |
PWM
TM4C123GH6PM控制器包含两个pwm模块,每个模块由4个pwm发生器和一个控制模块组成,每个发生器可以产生2个pwm信号,一共可以输出16个pwm信号(同一发生器产生的两个信号的周期是一致的,但占空比可以设为不同的)
PWM发生器特点
PWM结构图
其中一个发生器的细节
PWM引脚映射情况
它记录了在硬件层面上,哪些pwm信号输出连接到哪些引脚,编程时需要对照查看
PWM模块时钟来源
查看原理图,可见pwm模块时钟来源于经过USEPWMDIV分频的系统时钟,所有pwm信号的时钟频率都是这个。
PWM信号产生过程
(1)类似stm32,TM4C的pwm利用定时器实现(不过TM4C的pwm模块中有自带的定时器,不需要想stm32那样使用timer外设),可以选择三种计数模式
向上计数(pwm信号右对齐)
向下计数(pwm信号左对齐)
上下计数(pwm信号中间对齐)
(2)每个pwm信号发生器,可以配置两个pwm比较器(类似stm32中的ccrx),比较器根据设定的比较值和当前计数值输出高电平脉冲
(3)所有计数器、比较器的信息会被pwm信号发生器检测,并生成对应的pwm波
PWM配置过程及示例代码
配置一个PWM发生器,频率25KHz,信号0(MnPWM0)占空比25%,信号1(MnPWM1)占空比75%,假定系统时钟频率为20M
使能PWM时钟 SysCtlPeripheralEnable()
使能被复用引脚的时钟 SysCtlPeripheralEnable()
使能引脚复用PWM功能 GPIOPinTypePWM()
将PWM信号分配到合适的引脚上 GPIOPinConfigure()
使能PWM时钟,设置PWM分频器为2分频(PWM时钟源为10M) SysCtlPWMClockSet();
配置为向下计数,参数立即更新模式 PWMGenConfigure()
设置周期时间(定时器计数范围),目标频率25K,PWM频率10M,则每一个信号周期有400个PWM周期,故装载值设为400-1(0到399共400个值) PWMGenPeriodSet()
设置信号0占空比25%,信号1占空比75% PWMPulseWidthSet()
启动PWM发生器的定时器 PWMGenEnable()
使能PWM输出 PWMOutputState()
1 |
|
PWM_Init
1 | void PWM_Init(void) |
1 | SysCtlPWMClockSet(SYSCTL_PWMDIV_8); |
PWM_Set
1 | void PWM_Set(uint16_t motor1,uint16_t motor2) |
1 | PWMPulseWidthSet(PWM1_BASE,PWM_OUT_6,motor1); |
输入捕获
输入捕获引脚映射关系
边沿计数模式
在该模式中,TimerA或TimerB被配置为能够捕获外部输入脉冲边沿事件的递增/减计数器。共有3种边沿事件类型:正边沿、负边沿、双边沿
工作过程是:
(1)减计数:设置装载值Preload,并预设一个匹配值Match(应当小于装载值);计数使能后,在特定的CCP管脚每输入1个脉冲(正边沿、负边沿或双边沿有效),计数值就减1;当计数值与匹配值Match相等时停止运行(若使能中断,这时会被触发)。定时器自动重装载Preload值,但如果需要再次捕获外部脉冲,则要重新进行配置。
(2)加计数:设置匹配值Match;计数使能后,在特定的CCP管脚每输入1个脉冲(正边沿、负边沿或双边沿有效),计数值就加1;当计数值与匹配值Match相等时停止运行(若使能中断,这时会被触发)。定时器自动清0并自动开始捕获外部脉冲计数,不需要重新进行配置
注意:
配置为边沿计数模式时,定时器必须配置为拆分模式,64-bit未拆分模式下不可以用Capture
此模式下,8bit的定时器预分频寄存器(Prescaler)不再作为分频器使用,定时器频率和系统时钟频率相同, 预分频寄存器的8bit空间作为计数范围的扩展,增加到定时器计数器的高位。也就是说32/64位定时器的输入捕获计数范围为24/48bit
配置过程:
GPIO设置:
1.GPIOPinConfigure 进行引脚到TnCCPm的信号映射
2.GPIOPinTypeTimer 配置引脚到定时器模式
3.GPIOPadConfigSet 配置其他引脚参数
配置定时器模块为捕捉-边沿计数模式:
- TimerConfigure 配置定时器模式。注意第二个参数一定是TIMER_CFG_SPLIT_PAIR和一下之一相或
(1)TIMER_CFG_A_CAP_COUNT 模块A捕捉-边沿减计数模式
(2)TIMER_CFG_A_CAP_COUNT_UP 模块A捕捉-边沿加计数模式
(3)TIMER_CFG_B_CAP_COUNT 模块B捕捉-边沿减计数模式
(4)TIMER_CFG_B_CAP_COUNT_UP 模块B捕捉-边沿加计数模式
设置要捕捉的边沿:
- TimerControlEvent
设置计数范围:
- TimerMatchSet设置加/减计数结束值
- TimerLoadSet设置减计数起始值
中断设置:
- TimerIntRegister 注册中断服务函数
- TimerIntEnable 源级中断使能,这里注意配置中断类型
(1)TIMER_CAPA_MATCH – 模块A计数到达预设值
(2)TIMER_CAPB_MATCH – 模块B计数到达预设值 - IntEnable 中断控制器级中断使能
- IntMasterEnable处理器级中断使能
启动定时器模块:
- TimerEnable
边沿计时模式
简介:在该模式中,TimerA/B被配置为自由运行的16位递减计数器,允许在输入信号的上升沿或下降沿捕获事件。
工作过程是:设置装载值(默认为0xFFFF)、捕获边沿类型;计数器被使能后开始自由运行,从装载值开始递减计数(或从0开始递增计数),计数到0(或装载值)时重装(或清零),继续计数;如果从CCP管脚上出现有效的输入脉冲边沿事件,则当前计数值被自动复制到一个特定的寄存器里,该值会一直保存不变,直至遇到下一个有效输入边沿时被刷新。为了能够及时读取捕获到的计数值,应当使能边沿事件捕获中断,并在中断服务函数里读取。
注意:
配置为边沿计时模式时,定时器必须配置为拆分模式,64-bit未拆分模式下不可以用Capture
此模式下,8bit的定时器预分频寄存器(Prescaler)不再作为分频器使用,定时器频率和系统时钟频率相同, 预分频寄存器的8bit空间作为计数范围的扩展,增加到定时器计时器的高位。也就是说32/64位定时器的输入捕获计时范围为24/48bit
配置过程:和计数模式基本一样,仅有以下区别
需要配置定时器模块为捕捉-边沿计时模式
TimerConfigure第二个参数是TIMER_CFG_SPLIT_PAIR和一下之一相或
(1)TIMER_CFG_A_CAP_TIME 模块A捕捉-边沿减计时模式
(2)TIMER_CFG_A_CAP_TIME UP 模块A捕捉-边沿加计时模式
(3)TIMER_CFG_B_CAP TIME 模块B捕捉-边沿减计时模式
(4)TIMER_CFG_B_CAP_ TIME _UP 模块B捕捉-边沿加计时模式
设置计时范围
- TimerLoadSet无论加计时还是减计时,都用这个函数设置Preload值
中断设置
- TimerIntEnable的中断类型参数变为以下二者之一
(1) TIMER_CAPA_EVENT 模块A发生捕获事件
(2) TIMER_CAPB_EVENT 模块B发生捕获事件
示例代码
1 | //timer0A输入捕获,脉冲从PB6输入(PF0作T0CCP0) |
Timer
单次运行模式和连续运行模式
定时器的基本功能为计数(包括加计数和减计数两种),Stellaris LM4F中以系统时钟为计数节拍(当计数器被拆分使用时可以使用预分频功能,为了简单起见这里不作讨论)。当加计数时,计数器由零开始,逐步加一,直到到达用户预设值;减计数则由某一用户预设值开始,逐步减一,直到计数为零。每当计数完成,则会置相应的状态位(包括中断),提示计时完成。
单次运行与连续运行工作时没有区别,不同的是单次运行在完成一次计时后会自动停止,连续模式下定时器会自动从计数起点开始(根据计数方向为零或用户设定值)继续计时。
定时器程序设置
1.启用时钟模块
使用SysCtlPeripheralEnable函数启用相应的定时器模块。
程序示例:
SysCtlPeripheralEnable(SYSCTL_PERIPH_WTIMER0);
在StellarisWare中,32/16-bit定时器模块为TIMER,64/32-bit定时器模块为WTIMER (Wide Timer)。除了名字不同、计数范围不同外没有其它区别。
2.设置时钟模块工作模式
使用TimerConfigure函数对定时器模块的工作模式进行设置,将其设置为定时器功能。
程序示例:
TimerConfigure(TIMER0_BASE,TIMER_CFG_ONE_SHOT);
TimerConfigure(WTIMER2_BASE,TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_ONE_SHOT |TIMER_CFG_B_PERIODIC);
在不拆分的情况下,可以用下面参数中的一个将模块设置成所需的定时器模式:
TIMER_CFG_ONE_SHOT – 单次减计数模式
TIMER_CFG_ONE_SHOT_UP – 单次加计数模式
TIMER_CFG_PERIODIC – 连续减计数模式
TIMER_CFG_PERIODIC_UP – 连续加计数模式
TIMER_CFG_RTC – 实时时钟模式
如果需要将计时器拆分,则需使用参数TIMER_CFG_SPLIT_PAIR然后用“|”号连接被拆分定时器A、B的设置。如果只使用了一个可以只设置用到的那个。拆分出来的定时器A和B的设置方法是一样的,只是函数名中各自用A和B:
TIMER_CFG_A_ONE_SHOT – 定时器A单次减计数
TIMER_CFG_A_ONE_SHOT_UP –定时器A单次加计数
TIMER_CFG_A_PERIODIC – 定时器A连续减计数
TIMER_CFG_A_PERIODIC_UP – 定时器A连续加计数
TIMER_CFG_B_ONE_SHOT – 定时器B单次减计数
TIMER_CFG_B_ONE_SHOT_UP –定时器B单次加计数
TIMER_CFG_B_PERIODIC – 定时器B连续减计数
TIMER_CFG_B_PERIODIC_UP – 定时器B连续加计数
3.设置时钟的计数范围
使用TimerLoadSet、TimerLoadSet64函数可以为计数设置范围。设置未拆分使用的64/32-bit定时器模块,需要使用TimerLoadSet64函数,对其它模块、其它状况的设置使用TimerLoadSet函数。计数范围为设置值到零(加计数: 0预设值,减计数: 预设值0)。
程序示例:
TimerLoadSet64(TIMER3_BASE, 80000);
TimerLoadSet(WTIMER0_BASE, TIMER_B, 10000);
4.启动时钟
使用TimerEnable函数启动定时器。可以用的参数有TIMER_A、TIMER_B和TIMER_BOTH。可以分别或同时启动A、B定时器。如果定时器没有拆分,直接使用TIMER_A即可。
程序示例:
TimerEnable(WTIMER0_BASE, TIMER_B);
定时器读取及中断设置
1.计数值读取
可以使用TimerValueGet函数和TimerValueGet64函数获得定时器当前的计数值。需要注意的是TimerValueGet64返回的是64位结果。
程序示例:
long val = TimerValueGet(TIMER1_BASE, TIMER_A);
long long timer_val = TimerValueGet64(WTIMER3_BASE);
2.中断设置
一般定时器多用中断响应以满足时间要求。可以用TimerIntRegister向系统注册中断处理函数,用TimerIntEnable来允许某个定时器的中断请求。需要注意的是,在M4中还应该用IntEnable在系统层使能定时器的中断。当然,系统总中断开关也必须用IntMasterEnable使能。
TimerIntEnable在该模式下可以支持:
TIMER_TIMA_TIMEOUT
TIMER_TIMB_TIMEOUT
程序示例:
TimerIntRegister(WTIMER0_BASE, TIMER_B, WTimer0BIntHandler);
IntMasterEnable();
TimerIntEnable(WTIMER0_BASE, TIMER_TIMB_TIMEOUT);
IntEnable(INT_WTIMER0B);
在Timer中断中,需要手工清除中断标志位,可以使用如下代码:
unsignedlong ulstatus = TimerIntStatus(TIMER4_BASE, TIMER_TIMA_TIMEOUT |TIMER_TIMB_TIMEOUT);
TimerIntClear(TIMER4_BASE,ulstatus);
示例代码
1 | // Stellaris硬件定义及StellarisWare驱动定义头文件 |
1 | static void Timer_Init(void){ |
I2C
一、I2C接口的介绍:
内部集成电路(I2C)总线通过一个两线设计(串行数据线 SDA 和串行时钟线 SCL)来提供双向数据传输,并且与外部 I2C 器件诸如串行存储器(RAM 和 ROM),网络设备,LCD,音频发生器等联系。I2C 总线也可用于产品开发和制造的系统测试和诊断的目的。TM4C123GH6PM 微控制器提供与其他 I2C 总线上的设备交互(发送和接收)的能力。TM4C123GH6PM 控制器的 I2C 模块具有以下特点:
I2C 总线上的设备可被配置为主机或从机
— 支持一个主机或从机发送和接收数据
— 同时支持主机和从机操作
四个 I2C 模式:
— 主机发送模式
— 主机接收模式
— 从机发送模式
— 从机接收模式
四个发送速率:
— 标准模式(100 Kbps)
— 快速模式(400 Kbps)
— 超快速模式(1Mbps)
— 高速模式(3.33Mbps)
时钟低超时中断的
双从地址能力
抗干扰
主机和从机中断的产生
— 当主机发送或接收操作完成时(或因错误终止时),产生中断
— 当从机发送数据或主机需要数据或检测到起始或停止条件时,产生中断
主机由仲裁和时钟同步,支持多主机,以及 7 位寻址模式

二、结构图:
三、 初始化与配置
以下例子给出如何配置 I2C 模块用于主机传输一个字节。这里假定系统时钟为 20 MHz 。
- 在系统控制模块使用 RCGCI2C 寄存器使能 I2C 时钟。
- 通过在系统控制模块的 RCGCGPIO 寄存器为相应的 GPIO 模块使能时钟。要了解使能哪些GPIO 端口。
- 在 GPIO 模块,通过 GPIOAFSEL 寄存器位它们的复用功能使能相应的引脚。请参看表 23-4,以确定配置那个 GPOI。
- 使能 I2CSDA 引脚来配置开漏操作。
- 在 GPIOPCTL 寄存器配置 PMCn 位组为相应的引脚配置 I2C 信号。
- 向 I2CMCR 寄存器写入 0x00000010 值来初始化 I2C 主机。
- 通过写入 I2CMTPR 寄存器正确的值来设置所需的 100 Kbps 的 SCL 时钟速度。写入I2CMTPR 寄存器的值代表在一个 SCL 时钟周期中系统时钟周期数。TPR 值由以下等式确定:
TPR = (System Clock/(2*(SCL_LP + SCL_HP)SCL_CLK))-1;
TPR = (20MHz/(2(6+4)*100000))-1;
TPR = 9向 I2CMTPR 寄存器写入 0x00000009. - 规定主机的从机地址,下一个操作是一个发送,该发送通过向 I2CMSA 寄存器值写入0x00000076 实现。这设置了从机地址为 0x3B。
- 通过向 I2CMDR 寄存器写入所需数据将数据(位)传输到数据寄存器。
- 启动从主机到从机的数据单字节的传输是通过向 I2CMCS 寄存器写入 0x00000007 (STOP,START, RUN)实现。
- 等待直到传输完成,通过轮询 I2CMCS 寄存器的 BUSBSTY 位,直到该位被清除。
- 检测 I2CMCS 寄存器的 ERROR 位以确保传输被应答。
四、环路操作实验
可以通过设置 I2C 主机配置(I2CMCR)寄存器的 LPBK 位将 I2C 模块放入一个内部环路模式用于诊断或调试工作。在环回模式下,来自主机的 SDA 和 SCL 信号和从机模块的 SDA 和SCL 信号绑定在一起,并允许内部的设备测试,而不必去通过 I / O实验的验证就是通过主机发送数据-从机接收,从机发数据-主机接收
1 | /******************************************************** |