[TM4]TM4C123G使用笔记

TI的板子真让人头大甚至重装了两遍KEIL5

如何用keil5新建工程可以参考如下博客:

https://blog.csdn.net/D_XingGuang/article/details/89390211?spm=1001.2014.3001.5506

记得在榔头里的C/C++勾选C99 Mode和GNU extensions,不然一大堆报错

下面主要是常用外设的使用

GPIO

常用函数

void SysCtlPeripheralEnable(uint32_t ui32Peripheral)

  • 功能:使能外设时钟
  • 参数:uint32_t ui32Peripheral:需要使能的外设,在本文中需要使能的外设为GPIO(例如SYSCTL_PERIPH_GPIOF)
  • 说明:从使能操作开始到完成需要经过五个时钟周期,在此期间不可访问外设,否则会出现总线错误。

void GPIOPinTypeGPIOOutput(uint32_t ui32Port, uint8_t ui8Pins)

  • 功能:配置引脚为输出模式

  • 参数:参见下面例程

void GPIODirModeSet(uint32_t ui32Port, uint8_t ui8Pins,uint32_t ui32PinIO)

  • 功能:设置引脚模式

  • 参数:

    1. #define GPIO_DIR_MODE_IN 0x00000000 // Pin is a GPIO input
    2. #define GPIO_DIR_MODE_OUT 0x00000001 // Pin is a GPIO output
    3. #define GPIO_DIR_MODE_HW 0x00000002 // Pin is a peripheral function

void GPIOPadConfigSet(uint32_t ui32Port, uint8_t ui8Pins,uint32_t ui32Strength, uint32_t ui32PadType)

  • 功能:设置引脚PAD

  • 参数:ui32Strength:输出驱动强度,正常设为2MA;ui32PadType:设置上下拉推挽开漏等

    1. //输出驱动强度
    2. GPIO_STRENGTH_2MA
    3. GPIO_STRENGTH_4MA
    4. GPIO_STRENGTH_8MA
    5. GPIO_STRENGTH_8MA_SC
    6. GPIO_STRENGTH_6MA
    7. GPIO_STRENGTH_10MA
    8. GPIO_STRENGTH_12MA
    9. //模式
    10. GPIO_PIN_TYPE_STD // 推挽
    11. GPIO_PIN_TYPE_STD_WPU // 弱上拉
    12. GPIO_PIN_TYPE_STD_WPD // 弱下拉
    13. GPIO_PIN_TYPE_OD // 开漏
    14. GPIO_PIN_TYPE_ANALOG // 模拟
    15. GPIO_PIN_TYPE_WAKE_HIGH
    16. GPIO_PIN_TYPE_WAKE_LOW
  • 注:该函数一般与上面的void GPIODirModeSet(uint32_t ui32Port, uint8_t ui8Pins,uint32_t ui32PinIO)函数连用

void GPIOPinWrite(uint32_t ui32Port, uint8_t ui8Pins, uint8_t ui8Val)

  • 功能:写入高低电平

  • 参数:ui8Val:低电平为0,高电平为引脚名(这个很特别,在读取电平也是一样的道理)

  • 说明:例如GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2, GPIO_PIN_1|GPIO_PIN_2);表示Pin1和Pin2输出高电平。若引脚被设置为输入,则向该引脚输出是无效的。

int32_t GPIOPinRead(uint32_t ui32Port, uint8_t ui8Pins)

  • 功能:读取电平
  • 返回值:低电平为0,高电平为引脚名

例程:

  1. #include <stdint.h>
  2. #include <stdbool.h>
  3. #include "inc/hw_gpio.h"
  4. #include "driverlib/gpio.h"
  5. #include "driverlib/pin_map.h"
  6. #include "inc/hw_memmap.h"
  7. #include "driverlib/sysctl.h"
  8. int main()
  9. {
  10. // 使能外设时钟
  11. SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
  12. // 设置输出引脚
  13. GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1);
  14. GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_2);
  15. GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_3);
  16. // 设置输入引脚
  17. GPIODirModeSet(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_DIR_MODE_IN); // 设置为输入
  18. GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU); // 上拉输入
  19. while(1)
  20. {
  21. if(GPIOPinRead(GPIO_PORTF_BASE, GPIO_PIN_4) == GPIO_PIN_4) // 读取高电平,即按键没有被按下
  22. {
  23. GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);
  24. }
  25. else // 按键按下
  26. {
  27. GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2);
  28. }
  29. }
  30. }

外部中断

常用函数

void GPIOIntTypeSet(uint32_t ui32Port, uint8_t ui8Pins, uint32_t ui32IntType)

  • 功能:设置引脚中断的触发条件
  • 参数:
  1. GPIO_FALLING_EDGE // sets detection to edge and trigger to falling
  2. GPIO_RISING_EDGE // sets detection to edge and trigger to rising
  3. GPIO_BOTH_EDGES // sets detection to both edges
  4. GPIO_LOW_LEVEL // sets detection to low level
  5. GPIO_HIGH_LEVEL // sets detection to high level

void GPIOIntRegister(uint32_t ui32Port, void (*pfnIntHandler)(void))

  • 功能:注册中断回调函数
  • 参数:自定义的中断回调函数名称

void GPIOIntEnable(uint32_t ui32Port, uint32_t ui32IntFlags)

  • 功能:使能GPIO端口中断
  • 参数:ui32IntFlags:
  1. GPIO_INT_PIN_x
  2. GPIO_INT_DMA

void IntEnable(uint32_t ui32Interrupt)

  • 功能:使能中断外设
  • 参数:如 INT_GPIOx 等

void IntMasterEnable(void)

  • 功能:使能处理器中断

uint32_t GPIOIntStatus(uint32_t ui32Port, bool bMasked)

  • 功能:读取中断状态
  • 参数:bMasked:指定返回被屏蔽的中断状态(true)还是原始的中断状态(false)
  • 说明:被屏蔽的中断状态:就是只返回在GPIOIntEnable函数里被使能的ui32IntFlags的中断状态,其他的被屏蔽。

void GPIOIntClear(uint32_t ui32Port, uint32_t ui32IntFlags)

  • 功能:清除指定中断源标志
  • 说明:发生中断后,对应的中断标志位置1,进入中断服务函数,在服务函数中务必清除中断标志,否则程序将不停地进入中断服务函数

例程

  1. #include <stdint.h>
  2. #include <stdbool.h>
  3. #include "inc/hw_gpio.h"
  4. #include "inc/hw_ints.h"
  5. #include "driverlib/gpio.h"
  6. #include "driverlib/pin_map.h"
  7. #include "inc/hw_memmap.h"
  8. #include "driverlib/sysctl.h"
  9. #include "driverlib/interrupt.h"
  10. void GPIOFIntHandler(void);
  11. void GPIO_Init()
  12. {
  13. SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
  14. // 设置LED的IO引脚
  15. GPIODirModeSet(GPIO_PORTF_BASE, GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1, GPIO_DIR_MODE_OUT);
  16. GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
  17. // 初始化LED
  18. GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1, 0);
  19. }
  20. void GPIO_Init_IT()
  21. {
  22. //使能外设
  23. SysCtlPeripheralEnable( SYSCTL_PERIPH_GPIOF);
  24. //配置GPIOF_PIN_4为输入
  25. GPIODirModeSet(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_DIR_MODE_IN);
  26. //设置GPIOF_PIN_4为推挽上拉输出,驱动强度小点就可以
  27. GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);
  28. //设置为下降沿触发
  29. GPIOIntTypeSet( GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_FALLING_EDGE);
  30. //注册中断回调函数
  31. GPIOIntRegister( GPIO_PORTF_BASE,GPIOFIntHandler);
  32. //三个函数用来开启中断
  33. GPIOIntEnable( GPIO_PORTF_BASE, GPIO_INT_PIN_4);
  34. IntEnable(INT_GPIOF);
  35. IntMasterEnable();
  36. }
  37. int main()
  38. {
  39. // 时钟设置
  40. SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN);
  41. GPIO_Init();
  42. GPIO_Init_IT();
  43. while(1)
  44. {
  45. }
  46. }
  47. void GPIOFIntHandler(void)
  48. {
  49. // 读取中断状态
  50. uint32_t GPIOF_IT_FLAG = GPIOIntStatus(GPIO_PORTF_BASE, true);
  51. static int keyFlag;
  52. // 清除标志位
  53. GPIOIntClear(GPIO_PORTF_BASE, GPIO_INT_PIN_4);
  54. // 如果是PIN4触发中断
  55. if((GPIOF_IT_FLAG & GPIO_PIN_4) == GPIO_PIN_4)
  56. {
  57. keyFlag++;
  58. }
  59. // 改变灯的颜色
  60. switch(keyFlag % 3)
  61. {
  62. case 0:
  63. GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, GPIO_PIN_1);
  64. GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);
  65. GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, 0);
  66. break;
  67. case 1:
  68. GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 0);
  69. GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2);
  70. GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, 0);
  71. break;
  72. case 2:
  73. GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 0);
  74. GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);
  75. GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, GPIO_PIN_3);
  76. break;
  77. }
  78. }

Pulse Width Modulator(PWM)

与STM32相似,TM4C的PWM利用定时器实现,但TM4C的PWM模块中有自带的定时器,不需要像STM32那样使用定时器外设。

类比STM32,TM4C的分频系数相当于PSC,Period相当于ARR,Width相当于CCRx,PWM频率的计算公式为:

\[Frequency = \frac {时钟总线频率(这里是40MHz)}{分频系数*Period}
\]

占空比的计算公式为:

\[Duty=\frac{Width + 1}{Period}
\]

观察PWM结构框图能知道,TM4C的PWM外设包含两个PWM模块,每个模块有4个PWM Generator,每个PWM Generator控制两个PWM信号的产生。同一个PWM Generator产生的两个PWM信号的Period是相同的,但Width可以不同。

下面的表格十分重要,编程时需要一一对照查表。

TM4C中PWM的配置过程

1、使能PWM时钟 SysCtlPeripheralEnable()

2、使能被复用引脚的时钟 SysCtlPeripheralEnable()

3、使能引脚复用PWM功能 GPIOPinTypePWM()

4、将PWM信号分配到合适的引脚上 GPIOPinConfigure()

5、使能PWM时钟,设置PWM分频器为4分频(PWM时钟源为10M) SysCtlPWMClockSet();

6、配置为向下计数,参数立即更新模式 PWMGenConfigure()

7、设置周期时间(定时器计数范围) PWMGenPeriodSet()

8、设置信号0占空比25%,信号1占空比75% PWMPulseWidthSet()

9、启动PWM发生器的定时器 PWMGenEnable()

10、使能PWM输出 PWMOutputState()

常用函数

void SysCtlPWMClockSet(uint32_t ui32Config)

  • 功能:设置分频系数
  • 参数:
  1. //*****************************************************************************
  2. //
  3. // The following are values that can be passed to the SysCtlPWMClockSet() API
  4. // as the ui32Config parameter, and can be returned by the SysCtlPWMClockGet()
  5. // API.
  6. //
  7. //*****************************************************************************
  8. #define SYSCTL_PWMDIV_1 0x00000000 // PWM clock is processor clock /1
  9. #define SYSCTL_PWMDIV_2 0x00100000 // PWM clock is processor clock /2
  10. #define SYSCTL_PWMDIV_4 0x00120000 // PWM clock is processor clock /4
  11. #define SYSCTL_PWMDIV_8 0x00140000 // PWM clock is processor clock /8
  12. #define SYSCTL_PWMDIV_16 0x00160000 // PWM clock is processor clock /16
  13. #define SYSCTL_PWMDIV_32 0x00180000 // PWM clock is processor clock /32
  14. #define SYSCTL_PWMDIV_64 0x001A0000 // PWM clock is processor clock /64

void GPIOPinTypePWM(uint32_t ui32Port, uint8_t ui8Pins)

  • 功能:为引脚分配PWM信号

void GPIOPinConfigure(uint32_t ui32PinConfig)

  • 功能:使能GPIO引脚复用
  • 参数:GPIO_Pxx_xxxx(xx引脚的xxxx功能)

void PWMGenConfigure(uint32_t ui32Base, uint32_t ui32Gen,uint32_t ui32Config)

  • 功能:配置PWM Generator
  • 参数:ui32Config:PWM寄存器的计数方式

void PWMGenPeriodSet(uint32_t ui32Base, uint32_t ui32Gen,uint32_t ui32Period)

  • 功能:设置PWM Generator的Period

void PWMPulseWidthSet(uint32_t ui32Base, uint32_t ui32PWMOut,uint32_t ui32Width)

  • 功能:设置PWM Output的Width

void PWMOutputState(uint32_t ui32Base, uint32_t ui32PWMOutBits,bool bEnable)

  • 功能:使能PWM Output

void PWMGenEnable(uint32_t ui32Base, uint32_t ui32Gen)

  • 功能:使能PWM Generator

例程

  1. #include <stdint.h>
  2. #include <stdbool.h>
  3. #include "inc/hw_gpio.h"
  4. #include "inc/hw_ints.h"
  5. #include "driverlib/gpio.h"
  6. #include "driverlib/pwm.h"
  7. #include "driverlib/pin_map.h"
  8. #include "inc/hw_memmap.h"
  9. #include "driverlib/sysctl.h"
  10. #include "driverlib/interrupt.h"
  11. #define Delay_ms(n); SysCtlDelay(n*(SysCtlClockGet()/3000));
  12. void PWM_Init()
  13. {
  14. // 因为设置了时钟总线是40MHz,所以在这里分一下频设置为4分频,那么PWM时钟就是10MHz
  15. SysCtlPWMClockSet(SYSCTL_PWMDIV_4);
  16. // 使能时钟
  17. SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM1); //使能PWM模块1时钟
  18. SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); //使能GPIOF时钟
  19. // 分配pwm信号
  20. GPIOPinTypePWM(GPIO_PORTF_BASE,GPIO_PIN_2);
  21. GPIOPinTypePWM(GPIO_PORTF_BASE,GPIO_PIN_3);
  22. // 使能引脚复用
  23. GPIOPinConfigure(GPIO_PF2_M1PWM6); //PF2->PWM模块1信号6
  24. GPIOPinConfigure(GPIO_PF3_M1PWM7); //PF3->PWM模块1信号7
  25. // 配置PWM发生器
  26. // 模块1->发生器3->上下计数,不同步
  27. PWMGenConfigure(PWM1_BASE,PWM_GEN_3,PWM_GEN_MODE_UP_DOWN|PWM_GEN_MODE_NO_SYNC);
  28. //配置PWM周期,此时PWM输出频率为10M/2k = 50000Hz。计数器为16位,故第三个参数不能超过65535
  29. PWMGenPeriodSet(PWM1_BASE,PWM_GEN_3,2000);
  30. //配置PWM占空比为1%
  31. PWMPulseWidthSet(PWM1_BASE,PWM_OUT_6,PWMGenPeriodGet(PWM1_BASE, PWM_GEN_3)*0.01 - 1);
  32. PWMPulseWidthSet(PWM1_BASE,PWM_OUT_7,PWMGenPeriodGet(PWM1_BASE, PWM_GEN_3)*0.01 - 1);
  33. //使能PWM模块1输出
  34. PWMOutputState(PWM1_BASE,PWM_OUT_6_BIT,true);
  35. PWMOutputState(PWM1_BASE,PWM_OUT_7_BIT,true);
  36. //使能PWM发生器
  37. PWMGenEnable(PWM1_BASE,PWM_GEN_3);
  38. }
  39. void PWM_Set_Duty(uint32_t ui32Base,uint32_t ui32PWMOut,float duty)
  40. {
  41. uint32_t ui32Gen;
  42. uint32_t ui32OutBits;
  43. switch(ui32PWMOut)
  44. {
  45. case PWM_OUT_0: ui32Gen=PWM_GEN_0,ui32OutBits=PWM_OUT_0_BIT; break;
  46. case PWM_OUT_1: ui32Gen=PWM_GEN_0,ui32OutBits=PWM_OUT_1_BIT; break;
  47. case PWM_OUT_2: ui32Gen=PWM_GEN_1,ui32OutBits=PWM_OUT_2_BIT; break;
  48. case PWM_OUT_3: ui32Gen=PWM_GEN_1,ui32OutBits=PWM_OUT_3_BIT; break;
  49. case PWM_OUT_4: ui32Gen=PWM_GEN_2,ui32OutBits=PWM_OUT_4_BIT; break;
  50. case PWM_OUT_5: ui32Gen=PWM_GEN_2,ui32OutBits=PWM_OUT_5_BIT; break;
  51. case PWM_OUT_6: ui32Gen=PWM_GEN_3,ui32OutBits=PWM_OUT_6_BIT; break;
  52. case PWM_OUT_7: ui32Gen=PWM_GEN_3,ui32OutBits=PWM_OUT_7_BIT; break;
  53. }
  54. //配置占空比
  55. PWMPulseWidthSet(ui32Base, ui32PWMOut, PWMGenPeriodGet(ui32Base, ui32Gen)*duty - 1);
  56. PWMOutputState(ui32Base, ui32OutBits, true);
  57. //使能发生器模块
  58. PWMGenEnable(ui32Base, ui32Gen);
  59. }
  60. int main()
  61. {
  62. float duty1=0.1,duty2=0.9;
  63. float d=0.01; // 步长
  64. // 设置时钟总线频率为40MHz
  65. SysCtlClockSet( SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);
  66. PWM_Init();
  67. while(1)
  68. {
  69. PWM_Set_Duty(PWM1_BASE,PWM_OUT_6,duty1);
  70. PWM_Set_Duty(PWM1_BASE,PWM_OUT_7,duty2);
  71. Delay_ms(10);
  72. duty1+=d;
  73. duty2-=d;
  74. if(duty1>=0.95 && duty2<=0.05) d=-0.01;
  75. else if(duty2>=0.95 && duty1<=0.05) d=0.01;
  76. }
  77. }

Universal Asynchronous Receivers/Transmitters (UARTs)

和STM32F4的大差不差,但是比F4多一个硬件FIFO。

先对FIFO做一个简要的说明吧,全称为First In First Out,就是先进先出。想象一个水管,用手堵住一个口,然后往另一个口装水,装满了就把手拿掉,先进入的水就会先出来,其中水管的作用就相当于FIFO。所以FIFO实际上起到了一个缓存区的作用。FIFO的大小也有规定,比如一个16x8的FIFO,表示其容量为16个8位数据,就是说他最多可以装16个字节,超过16个字节就满了,同时还要触发中断。

TM4C的FIFO深度可以编程控制,支持1/8,1/4,1/2,3/4,7/8的深度,比如说我给FIFO设置为1/2深度,则FIFO中数据字节数超过16x1/2=8时就会产生一个中断。

通过下面TM4C的UART模块结构图,我们可以发现FIFO最大深度为16个字节,TX、RX各有一个FIFO

参考下图DataSheet的说明,TM4C的FIFO在上电后应该不会自动启动,需要代码里手动配置。如果不配置FIFO的话其相当于一个字节深度,跟STM32的DR寄存器差不多,装一个字节产生一个中断。



具体的UART操作逻辑和STM32差不太多,就不细说了。

常用函数

void GPIOPinTypeUART(uint32_t ui32Port, uint8_t ui8Pins)

  • 功能:给引脚分配UART信号

void UARTClockSourceSet(uint32_t ui32Base, uint32_t ui32Source)

  • 功能:为UART设置波特率时钟源
  • 参数:ui32Base为串口基地址,ui32Source为串口的波特时钟源一般为UART_CLOCK_PIOSC是16MHz

void UARTStdioConfig(uint32_t ui32PortNum, uint32_t ui32Baud, uint32_t ui32SrcClock)

  • 功能:配置串口参数
  • 参数:PortNum:0~7,代表UARTx;Baud:波特率,比如115200;SrcClock:如果你上面波特率时钟源设置的是UART_CLOCK_PIOSC,那么SrcClock就是16000000

void UARTprintf(const char *pcString, ...)

  • 功能:printf

void UARTConfigSetExpClk(uint32_t ui32Base, uint32_t ui32UARTClk,uint32_t ui32Baud, uint32_t ui32Config)

  • 功能:配置串口参数
  • 参数:ui32UARTClk为提供给UART的时钟频率,通过SysCtlClockGet()函数可以得到,通过ui32Config来配置串口的字长,校验位,停止位

void UARTCharPut(uint32_t ui32Base, unsigned char ucData)

  • 功能:输出
  • 说明:等待FIFO中有数据再发送,即阻塞式输出

int32_t UARTCharGet(uint32_t ui32Base)

  • 说明:同上,阻塞式读取

bool UARTCharPutNonBlocking(uint32_t ui32Base, unsigned char ucData)

  • 返回值:若TX的FIFO已满,直接返回false而不在那循环等待
  • 说明:非阻塞式输出

int32_t UARTCharGetNonBlocking(uint32_t ui32Base)

  • 说明:同上,非阻塞式读取,若RX的FIFO为空,直接返回False

void UARTFIFOEnable(uint32_t ui32Base)

  • 功能:使能FIFO

void UARTFIFOLevelSet(uint32_t ui32Base, uint32_t ui32TxLevel,uint32_t ui32RxLevel)

  • 功能:设置FIFO深度

void UARTIntEnable(uint32_t ui32Base, uint32_t ui32IntFlags)

  • 功能:使能串口中断
  • 参数:ui32IntFlags:UART_INT_RX/TX

void UARTIntRegister(uint32_t ui32Base, void (*pfnHandler)(void))

  • 功能:注册串口中断回调函数

void IntPrioritySet(uint32_t ui32Interrupt, uint8_t ui8Priority)

  • 功能:设置中断优先级
  • 参数:ui32Interrupt为中断外设,如INT_UARTx,ui8Priority为中断优先级从0x0到0xE0,0x0优先级最高

uint32_t UARTIntStatus(uint32_t ui32Base, bool bMasked)

  • 功能:读取UART中断状态
  • 参考GPIOIntStatus

void UARTIntClear(uint32_t ui32Base, uint32_t ui32IntFlags)

  • 功能:清除上个函数读取到的标志位

bool UARTCharsAvail(uint32_t ui32Base)

  • 功能:判断FIFO是否有数据存在
  • 返回值:有为true,无为false

void UARTEnable(uint32_t ui32Base)

  • 功能:使能串口

例程

注:

  • 该例程需要导入utils文件夹中的uartstdio.c,并设置包含utils文件夹。
  • 需要将uartstdio.c中126行的static uint32_t g_ui32Base改成自己的串口
  1. #include <stdint.h>
  2. #include <stdbool.h>
  3. #include <string.h>
  4. #include "inc/tm4c123gh6pm.h" //Register Definitions
  5. #include "inc/hw_memmap.h"
  6. #include "inc/hw_types.h"
  7. #include "driverlib/sysctl.h"
  8. #include "driverlib/interrupt.h"
  9. #include "driverlib/gpio.h"
  10. #include "driverlib/uart.h"
  11. #include "uartstdio.h"
  12. #include "driverlib/systick.h"
  13. #include "driverlib/pin_map.h"
  14. #define delay_ms(n); SysCtlDelay(n*(SysCtlClockGet()/3000));
  15. char rxBuffer[256];
  16. void UARTIntHandler(void)
  17. {
  18. uint32_t ui32Status;
  19. ui32Status = UARTIntStatus(UART1_BASE, true); //get interrupt status
  20. static int32_t cnt;
  21. UARTIntClear(UART1_BASE, ui32Status); //clear the asserted interrupts
  22. while(UARTCharsAvail(UART1_BASE)) //loop while there are chars
  23. {
  24. rxBuffer[cnt++] = UARTCharGetNonBlocking(UART1_BASE);
  25. GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2); //blink LED
  26. delay_ms(0.1);
  27. GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0); //turn off LED
  28. }
  29. cnt = 0;
  30. UARTprintf("%s\r\n", rxBuffer);
  31. memset(rxBuffer, 0x00, sizeof(rxBuffer));
  32. }
  33. void UART1_Init()
  34. {
  35. //使能外设
  36. SysCtlPeripheralEnable(SYSCTL_PERIPH_UART1);
  37. //配置复用功能
  38. GPIOPinConfigure(GPIO_PB0_U1RX);
  39. GPIOPinConfigure(GPIO_PB1_U1TX);
  40. //分配UART信号
  41. GPIOPinTypeUART(GPIO_PORTB_BASE,GPIO_PIN_0|GPIO_PIN_1);
  42. //串口参数设置
  43. UARTClockSourceSet(UART1_BASE, UART_CLOCK_PIOSC); //使用16MHz内部高精度振荡器(PIOSC)作为UART模块时钟
  44. UARTStdioConfig(1,115200, 16000000); //UART编号、波特率、UART时钟频率(频率要和上一行设的一致)
  45. //FIFO配置,
  46. UARTFIFOLevelSet(UART1_BASE,UART_FIFO_TX4_8,UART_FIFO_RX2_8); //FIFO填入4Byte时触发中断
  47. UARTFIFOEnable(UART1_BASE);
  48. //中断使能
  49. IntMasterEnable(); //enable processor interrupts
  50. IntEnable(INT_UART1); //enable the UART interrupt
  51. UARTIntEnable(UART1_BASE, UART_INT_RX);
  52. //注册中断服务函数
  53. UARTIntRegister(UART1_BASE,UARTIntHandler);
  54. UARTEnable(UART1_BASE);
  55. }
  56. int main(void)
  57. {
  58. SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
  59. SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
  60. //LED配置
  61. SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); //enable GPIO port for LED
  62. GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_2); //enable pin for LED PF2
  63. UART1_Init();
  64. UARTprintf("Enter Text: \n");
  65. while (1) //let interrupt handler do the UART echo function
  66. {
  67. ;
  68. }
  69. }

后面再准备详细研究一下TM4C的UART

General-Purpose Timers

TM4C有两种定时器,一种是16/32bit,另一种是32/64bit,两种定时器各有六个;对于一个16/32bit定时器来说,其可以拆分成两个16位定时器A和B工作,也可以组装成一个32位定时器工作。

常用函数

void SysCtlPeripheralEnable(uint32_t ui32Peripheral)

  • 功能:使能外设
  • 参数:ui32Peripheral如果为16/32bit的定时器就是TIMER,如果是32/64bit的定时器就是WTIMER。

void TimerConfigure(uint32_t ui32Base, uint32_t ui32Config)

  • 功能:设置定时器模式

  • 说明:

  • 如果在定时器不拆分的情况下,可以将ui32Config设置为以下模式之一:

    1. TIMER_CFG_ONE_SHOT 单次减计数模式
    2. TIMER_CFG_ONE_SHOT_UP 单次加计数模式
    3. TIMER_CFG_PERIODIC 连续减计数模式
    4. TIMER_CFG_PERIODIC_UP 连续加计数模式
    5. TIMER_CFG_RTC 实时时钟模式

    如果将定时器拆分的话则将ui32Config设置为TIMER_CFG_SPLIT_PAIR(分裂为一对)然后与以下模式进行或运算:

    1. TIMER_CFG_A_ONE_SHOT 定时器A单次减计数
    2. TIMER_CFG_A_ONE_SHOT_UP –定时器A单次加计数
    3. TIMER_CFG_A_PERIODIC 定时器A连续减计数
    4. TIMER_CFG_A_PERIODIC_UP 定时器A连续加计数
    5. TIMER_CFG_B_ONE_SHOT 定时器B单次减计数
    6. TIMER_CFG_B_ONE_SHOT_UP –定时器B单次加计数
    7. TIMER_CFG_B_PERIODIC 定时器B连续减计数
    8. TIMER_CFG_B_PERIODIC_UP 定时器B连续加计数

void TimerLoadSet(uint32_t ui32Base, uint32_t ui32Timer, uint32_t ui32Value)

  • 功能:配置定时器频率

  • 参数:ui32Base为定时器基地址,ui32Timer有TIMER_A,TIMER_B和TIMER_BOTH(单独A,单独B,AB都用)三种选择,在定时器拆分的情况下用哪个就设置哪个,在不拆分的情况下就设置为TIMER_A(对于其他函数也是,如果在级联的情况下还需要选择,那默认为选择TIMER_A),ui32Value为定时器加载值,一般来说定时器频率为N,那么定时器加载值=SysCtlClockGet()/N-1,即根据自己的定时器频率即可得定时器加载值。

    此函数适用于16bit,32bit的定时器,即适用于16/32bit的定时器拆分与级联,32/64bit定时器的拆分三种情况,对于64bit的定时器,即32/64bit定时器的级联使用TimerLoadSet64

void TimerIntRegister(uint32_t ui32Base, uint32_t ui32Timer,void (*pfnHandler)(void))

  • 功能:为定时器中断注册中断回调函数

void TimerIntEnable(uint32_t ui32Base, uint32_t ui32IntFlags)

  • 功能:使能定时器中断
  • 参数:ui32Base为定时器基地址,ui32IntFlags为中断模式,在定时器状态下一般设置为TIMER_TIMB_TIMEOUT或TIMER_TIMA_TIMEOUT

void TimerEnable(uint32_t ui32Base, uint32_t ui32Timer)

  • 功能:使能定时器
  • 参数:ui32Base为定时器基地址,ui32Timer也是有TIMER_A,TIMER_B和TIMER_BOTH三种

例程

  1. #include <stdint.h>
  2. #include <stdbool.h>
  3. #include <string.h>
  4. #include "inc/tm4c123gh6pm.h"
  5. #include "inc/hw_memmap.h"
  6. #include "inc/hw_types.h"
  7. #include "driverlib/sysctl.h"
  8. #include "driverlib/interrupt.h"
  9. #include "driverlib/gpio.h"
  10. #include "driverlib/uart.h"
  11. #include "driverlib/timer.h"
  12. #include "uartstdio.h"
  13. #include "driverlib/systick.h"
  14. #include "driverlib/pin_map.h"
  15. #define delay_ms(n); SysCtlDelay(n*(SysCtlClockGet()/3000));
  16. void TIM_IRQHandler(void);
  17. void wTIM_IRQHandler(void);
  18. void TIM_Init()
  19. {
  20. uint32_t freq = 1000;
  21. // 使能定时器TIMER0,16/32bit
  22. SysCtlPeripheralEnable( SYSCTL_PERIPH_TIMER0);
  23. // 配置定时器,将定时器拆分,并配置拆分后的定时器A为周期性计数
  24. TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODIC_UP);
  25. // 设置定时器A装载值,因为要1ms进一次中断,所以1ms=1/1000,所以重装载值为SysCtlClockGet()/1000-1
  26. TimerLoadSet(TIMER0_BASE, TIMER_A,SysCtlClockGet()/freq - 1);
  27. // 为定时器A注册中断函数
  28. TimerIntRegister(TIMER0_BASE, TIMER_A, TIM_IRQHandler);
  29. // 使能Timer0的定时器A为超时中断
  30. TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
  31. // 设置中断优先级
  32. IntPrioritySet(INT_TIMER0A, 0);
  33. // 使能中断
  34. IntEnable(INT_TIMER0A);
  35. IntMasterEnable();
  36. // 使能定时器
  37. TimerEnable( TIMER0_BASE, TIMER_A);
  38. }
  39. // 32/64bit定时器级联
  40. void wTIM_Init()
  41. {
  42. uint64_t freq = 1000;
  43. SysCtlPeripheralEnable(SYSCTL_PERIPH_WTIMER0);
  44. // 设置不拆分并且周期计数
  45. TimerConfigure(WTIMER0_BASE, TIMER_CFG_PERIODIC_UP);
  46. TimerLoadSet64(WTIMER0_BASE, SysCtlClockGet() / freq - 1);
  47. // 级联的情况下默认都是设置定时器A
  48. TimerIntEnable(WTIMER0_BASE, TIMER_TIMA_TIMEOUT);
  49. TimerIntRegister(WTIMER0_BASE, TIMER_A, wTIM_IRQHandler);
  50. IntPrioritySet(INT_WTIMER0A, 1);
  51. // 中断使能
  52. IntEnable(INT_WTIMER0A);
  53. IntMasterEnable();
  54. TimerEnable(WTIMER0_BASE, TIMER_A);
  55. }
  56. void GPIO_Init()
  57. {
  58. SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
  59. GPIODirModeSet(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_DIR_MODE_OUT);
  60. GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
  61. // GPIODirModeSet(GPIO_PORTF_BASE, GPIO_PIN_3, GPIO_DIR_MODE_OUT);
  62. // GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_3, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
  63. }
  64. int main(void)
  65. {
  66. SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
  67. GPIO_Init();
  68. // TIM_Init();
  69. wTIM_Init();
  70. while (1) // Let interrupt handler do the UART echo function
  71. {
  72. ;
  73. }
  74. }
  75. void TIM_IRQHandler()
  76. {
  77. static uint32_t time_count;
  78. static int flag;
  79. // 读取定时器中断状态
  80. uint32_t status = TimerIntStatus(TIMER0_BASE, true);
  81. // 清除中断标志位
  82. TimerIntClear(TIMER0_BASE, status);
  83. // 1ms进一次中断
  84. time_count++;
  85. // 1s进入一次
  86. if(time_count==1000)
  87. {
  88. time_count=0;
  89. flag++;
  90. if(flag % 2 == 1)
  91. {
  92. GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2);
  93. }
  94. else
  95. {
  96. GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);
  97. }
  98. }
  99. }
  100. void wTIM_IRQHandler()
  101. {
  102. static uint32_t time_count;
  103. static int flag;
  104. uint32_t status = TimerIntStatus( WTIMER0_BASE, true);
  105. TimerIntClear(WTIMER0_BASE, status);
  106. time_count++;
  107. if(time_count == 1000)
  108. {
  109. time_count = 0;
  110. flag++;
  111. if(flag % 2 == 1)
  112. {
  113. GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2);
  114. }
  115. else
  116. {
  117. GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);
  118. }
  119. }
  120. }

Quadrature Encoder Interface (QEI)

简单的说,就是TM4自带的编码器外设,能读取电机编码器并且测速以及读取位置(好用捏)

以下是DataSheet里的解释:(懒得翻译了,凑合着看吧)

可以发现,QEI有四个中断来源(有几个看不太懂什么意思,就不细说了)

芝士结构框图:

API函数就自己翻手册吧,没啥好说的

例子

QEI初始化函数:

  1. void QEI_Init(void)
  2. {
  3. const uint32_t MaxPos = 4000;
  4. // 使能外设
  5. SysCtlPeripheralEnable(SYSCTL_PERIPH_QEI0);
  6. while(!SysCtlPeripheralReady(SYSCTL_PERIPH_QEI0)){}
  7. SysCtlPeripheralEnable(SYSCTL_PERIPH_QEI1);
  8. while(!SysCtlPeripheralReady(SYSCTL_PERIPH_QEI1));
  9. SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
  10. SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
  11. SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
  12. // Unlock PD7
  13. HWREG(GPIO_PORTD_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
  14. HWREG(GPIO_PORTD_BASE + GPIO_O_CR) |= 0x80;
  15. HWREG(GPIO_PORTD_BASE + GPIO_O_LOCK) = 0x00;
  16. // QEI1: PC5, PC6
  17. GPIOPinConfigure(GPIO_PC5_PHA1);
  18. GPIOPinTypeQEI(GPIO_PORTC_BASE , GPIO_PIN_5);
  19. GPIOPinConfigure(GPIO_PC6_PHB1);
  20. GPIOPinTypeQEI(GPIO_PORTC_BASE , GPIO_PIN_6);
  21. QEIConfigure(QEI1_BASE, (QEI_CONFIG_CAPTURE_A_B | QEI_CONFIG_RESET_IDX |QEI_CONFIG_QUADRATURE | QEI_CONFIG_NO_SWAP), MaxPos - 1);
  22. QEIVelocityConfigure(QEI1_BASE, QEI_VELDIV_1, SysCtlClockGet()/100);
  23. QEIVelocityEnable(QEI1_BASE);
  24. QEIEnable(QEI1_BASE);
  25. // QEI2: PD6, PD7
  26. GPIOPinConfigure(GPIO_PD6_PHA0);
  27. GPIOPinTypeQEI(GPIO_PORTD_BASE , GPIO_PIN_6);
  28. GPIOPinConfigure(GPIO_PD7_PHB0);
  29. GPIOPinTypeQEI(GPIO_PORTD_BASE , GPIO_PIN_7);
  30. QEIConfigure(QEI0_BASE, (QEI_CONFIG_CAPTURE_A_B | QEI_CONFIG_RESET_IDX |QEI_CONFIG_QUADRATURE | QEI_CONFIG_NO_SWAP), MaxPos - 1);
  31. QEIVelocityConfigure(QEI0_BASE, QEI_VELDIV_1, SysCtlClockGet()/100);
  32. QEIVelocityEnable(QEI0_BASE);
  33. QEIEnable(QEI0_BASE);
  34. }

读取速度:

  1. polarR = -1 * QEIDirectionGet(QEI1_BASE);
  2. velocityR = polarR * QEIVelocityGet(QEI1_BASE);
  3. polarL = 1 * QEIDirectionGet(QEI0_BASE);
  4. velocityL = polarL * QEIVelocityGet(QEI0_BASE);
  5. UARTprintf("R:%d, L:%d\n", velocityR, velocityL);

读取位置:

  1. posL = QEIPositionGet(QEI0_BASE);
  2. UARTprintf("PosL:%d\n", posL);

[TM4]TM4C123G使用笔记的更多相关文章

  1. git-简单流程(学习笔记)

    这是阅读廖雪峰的官方网站的笔记,用于自己以后回看 1.进入项目文件夹 初始化一个Git仓库,使用git init命令. 添加文件到Git仓库,分两步: 第一步,使用命令git add <file ...

  2. js学习笔记:webpack基础入门(一)

    之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...

  3. SQL Server技术内幕笔记合集

    SQL Server技术内幕笔记合集 发这一篇文章主要是方便大家找到我的笔记入口,方便大家o(∩_∩)o Microsoft SQL Server 6.5 技术内幕 笔记http://www.cnbl ...

  4. PHP-自定义模板-学习笔记

    1.  开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2.  整体架构图 ...

  5. PHP-会员登录与注册例子解析-学习笔记

    1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...

  6. NET Core-学习笔记(三)

    这里将要和大家分享的是学习总结第三篇:首先感慨一下这周跟随netcore官网学习是遇到的一些问题: a.官网的英文版教程使用的部分nuget包和我当时安装的最新包版本不一致,所以没法按照教材上给出的列 ...

  7. springMVC学习笔记--知识点总结1

    以下是学习springmvc框架时的笔记整理: 结果跳转方式 1.设置ModelAndView,根据view的名称,和视图渲染器跳转到指定的页面. 比如jsp的视图渲染器是如下配置的: <!-- ...

  8. 读书笔记汇总 - SQL必知必会(第4版)

    本系列记录并分享学习SQL的过程,主要内容为SQL的基础概念及练习过程. 书目信息 中文名:<SQL必知必会(第4版)> 英文名:<Sams Teach Yourself SQL i ...

  9. 2014年暑假c#学习笔记目录

    2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...

  10. JAVA GUI编程学习笔记目录

    2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...

随机推荐

  1. .NET Core开发实战(第22课:异常处理中间件:区分真异常与逻辑异常)--学习笔记(下)

    接下来介绍使用代理方法的方式,也就是说把 ErrorController 整段逻辑直接定义在注册的地方,使用一个匿名委托来处理,这里的逻辑与之前的逻辑是相同的 app.UseExceptionHand ...

  2. .NET Core开发实战(第14课:自定义配置数据源:低成本实现定制化配置方案)--学习笔记

    14 | 自定义配置数据源:低成本实现定制化配置方案 这一节讲解如何定义自己的数据源,来扩展配置框架 扩展步骤 1.实现 IConfigurationSource 2.实现 IConfiguratio ...

  3. [Java][Spring]spring profile与maven profile多环境管理

    spring profile 与 maven profile 多环境管理 spring profile Spring profile是Spring提供的多环境管理方案. 如下图: 每种环境都对应一个y ...

  4. C++ map自定义比较函数遵守严格弱序

    C++ map自定义比较函数遵守严格弱序 问题背景及定位 背景:这个问题是在将tablesaw(一个Java的数据处理项目)迁移到C++时出现的. 问题位置:SplitOn()函数,在数据流水线中的a ...

  5. CF1834

    A 给出一个由 \(1,-1\) 组成的序列.一次操作可以让一个数变相反. 要多少次操作,才能让整个序列和非负且积等于 \(1\). 大 氵题. B 定义两个数 \(A,B\) 有一个价值:每一位上的 ...

  6. 2024年,我又开始用Linux桌面作为主力系统了~

    前言 19年的时候我买了一个 matebook14 笔记本,配置是8代i5和8G内存,在当时看来作为轻薄本是够用的,但是现在已经2024年了,这内存让我想起来去年苹果的新款 mac mini ,丐版三 ...

  7. 如何用低代码实现批量导出PDF?

    前言 事情是这样的,熟悉我们的朋友都知道,我司有一个为广大开发者朋友们提供学习帮助的地方,叫做新手训练营,具体的内容就是会针对初次接触葡萄城产品和技术的用户,通过 2-3 天的集中学习,采用直播授课的 ...

  8. 【Android】使用AIDL实现进程间传递对象案例

    1 前言 ​ 在 Android--使用AIDL实现进程间通讯简单案例 中介绍了使用 AIDL 在进程间传递字符串,对于8种基本数据类型( byte.short.int.long.float.doub ...

  9. Java并发编程实例--10.使用线程组

    并发API提供的一个有趣功能是可以将多个线程组成一个组. 这样我们就能将这一组线程看做一个单元并且提供改组内线程对象的读取操作.例如 你有一些线程在执行同样的任务并且你想控制他们,不考虑有多少个线程仍 ...

  10. 用Taro写一个微信小程序——版本升级

    一.升级 1.升级Taro CLI至最新版本 taro update self npm i -g @tarojs/cli 2.更新项目中 Taro 相关的依赖 taro update project ...