TM4C123库函数学习(3)---串口中断

简介: TM4C123库函数学习(3)---串口中断

前言

(1)学习本文之前,需要先学习前两篇文章。

(2)学习本文需要准备好TTL转USB模块。

函数介绍

ROM_GPIOPinConfigure()

配置GPIO引脚的复用功能。因为引脚不可能只有一个输出输入作用,还可能能够当作复用引脚。所以这个函数用于当IO需要用于其他功能的时候,调用这个函数。

/****** 函数声明 ******/
//这个存放在ROM
void ROM_GPIOPinConfigure(uint32_t ui32PinConfig);
//这个是存放在flash
void GPIOPinConfigure(uint32_t ui32PinConfig);
/****** 函数介绍 ******/
/* 作用 : 配置GPIO引脚的复用功能。
 * 传入参数 : 参数在 pin_map.h 中选择,例如 GPIOPinConfigure(GPIO_PB0_U1RX);是把 PB0 复用为
U1RX
 * 返回参数 : 无
*/


ROM_GPIOPinTypeUART()

配置UART外设使用的引脚。

/****** 函数声明 ******/
//这个存放在ROM
void ROM_GPIOPinTypeUART(uint32_t ui32Port,uint8_t ui8Pins);
//这个是存放在flash
void GPIOPinTypeUART(uint32_t ui32Port,uint8_t ui8Pins);
/****** 函数介绍 ******/
/* 作用 : 配置UART外设使用的引脚。
 * 传入参数 : 
     * ui32Port : GPIO口的基地地址,GPIO_PORTx_BASE,x可为A,B,C,D,E,F,G,H
     * ui8Pins : GPIO_PIN_X,x可为1,2,3,4,5,6,7
 * 返回参数 : 无
*/


ROM_UARTConfigSetExpClk()

(1)设置UART的配置。

(2)这里需要注意一个点,UARTStdioConfig()函数也可以配置串口,但是我个人不建议使用这个配置。因为这个函数配置了之后,默认为使用 8 位数据,没有奇偶校验位,1 停止位。虽然我们后面也是这样配置。

(3)UARTStdioConfig()这个函数有一个很重要的点,如果是调用这个函数配置的串口,可以使用UARTprintf()函数,却不能使用UARTCharput()函数,用UARTConfigSetExpClk()配置的函数可以使用UARTCharput()函数,却不能使用UARTprintf()函数。

(4)UARTprintf()是一个伪printf()函数,使用方法与printf()函数一致。但是这样做的话会有两个问题:

<1>如果调用UARTprintf()函数,但是单片机有多个串口同时打开了,都需要输出。这样UARTprintf()函数到底是对应的哪一个串口呢?

<2>这个函数使用起来不灵活。比如,数据类型限制:UARTprintf函数只支持有限的数据类型,例如整数和浮点数等。如果需要输出其他数据类型,可能需要自己编写输出函数。格式化限制:UARTprintf函数使用标准的printf格式化字符串语法,但是并不支持所有的printf格式化字符串选项。例如,它不支持长整型(long)和长双精度浮点型(long double)等类型。缓冲区大小限制:UARTprintf函数使用一个内部的静态缓冲区来存储格式化后的字符串,因此输出的字符串长度受到缓冲区大小的限制。如果输出的字符串长度超过了缓冲区大小,可能会导致输出不完整或被截断。


/****** 函数声明 ******/
//这个存放在ROM
void ROM_UARTConfigSetExpClk(uint32_t ui32Base,uint32_t ui32UARTClk,uint32_t ui32Baud,uint32_t ui32Config);
//这个是存放在flash
void UARTConfigSetExpClk(uint32_t ui32Base,uint32_t ui32UARTClk,uint32_t ui32Baud,uint32_t ui32Config);
/****** 函数介绍 ******/
/* 作用 : 设置UART的配置。
 * 传入参数 : 
     * ui32Base : UART端口的基地址
     * ui32UARTClk : 提供给UART模块的时钟速率。
     * ui32Baud : 波特率
     * ui32Config : 可选参数如下:
         * 数据位 : UART_CONFIG_WLEN_8(8数据位),
                    UART_CONFIG_WLEN_7(7数据位),
                    UART_CONFIG_WLEN_6(6数据位),
                    UART_CONFIG_WLEN_5(5数据位)
         * 停止位 : UART_CONFIG_STOP_ONE(1停止位),
                    UART_CONFIG_STOP_TWO (2停止位)
         * 校验位 : UART_CONFIG_PAR_NONE(无校验位) ,
                    UART_CONFIG_PAR_EVEN(偶校验),
                    UART_CONFIG_PAR_ODD (奇校验),
                    UART_CONFIG_PAR_ONE (1校验),
                    UART_CONFIG_PAR_ZERO (0校验)
 * 返回参数 : 无
*/

ROM_UARTFIFODisable()

(1)用于禁用FIFO。

(2)FIFO是一个寄存器,串口通讯的数据可以将FIFO作为中转站,CPU需要发送数据,就将数据一次性发给FIFO,然后FIFO来处理。如果接收数据,也是先将数据接收到FIFO中,然后CPU再去处理。这样做的好处:

<1>这样做允许串口同时处理多个字符,而不需要等待每个字符都被处理完毕。这可以减少串口通信的延迟,提高通信效率。

<2>允许串口同时处理多个字符,而不需要等待每个字符都被处理完毕。这可以减少串口通信的延迟,提高通信效率。

<3>当使能FIFO缓冲区时,串口接收到的数据将被存储在FIFO缓冲区中,而不是直接传输到接收缓冲区。这可以减少中断的数量,从而提高系统响应速度。(注意:这样做的话串口的实时性就会降低很多!!!)

(3)因为我们想要串口接收到数据就马上进行反应,所以我们将FIFO禁用。


/****** 函数声明 ******/
//这个存放在ROM
void ROM_UARTFIFODisable(uint32_t ui32Base);
//这个是存放在flash
void ROM_UARTFIFODisable(uint32_t ui32Base);
/****** 函数介绍 ******/
/* 作用 : 用于禁用FIFO。
 * 传入参数 : 
     * ui32Base :要禁用FIFO的UART端口的基地址
 * 返回参数 : 无
*/

ROM_UARTIntEnable()

启用单独的UART中断源。

/****** 函数声明 ******/
//这个存放在ROM
void ROM_UARTIntEnable(uint32_t ui32Base,uint32_t ui32IntFlags);
//这个是存放在flash
void UARTIntEnable(uint32_t ui32Base,uint32_t ui32IntFlags);
/****** 函数介绍 ******/
/* 作用 : 用于禁用FIFO。
 * 传入参数 : 
     * ui32Base :UART端口的基地址
     * ui32IntFlags : UART_INT_9BIT(9位地址匹配中断),
                       UART_INT_OE(错误中断,接收到的数据中出现了错误的“停止位”),
                       UART_INT_BE(错误中断,数据接收器的缓冲区已满时,继续接收数据而导致之前接收到的数据被覆盖,从而引发中断),
                       UART_INT_PE(奇偶校验错误中断),
                       UART_INT_FE(帧错误中断),
                       UART_INT_RT(接收超时中断),
                       UART_INT_TX(发送中断),
                       UART_INT_RX(接收中断),
                       UART_INT_DSR(DSR中断),
                       UART_INT_DCD(DCD中断),
                       UART_INT_CTS(CTS中断),
                       UART_INT_RI(RI中断)
 * 返回参数 : 无
*/


UARTIntRegister()

(1)UART中断函数注册

(2)这个的ROM函数似乎没有

/****** 函数声明 ******/
//这个是存放在flash
void UARTIntRegister(uint32_t ui32Base, void (*pfnHandler)(void));
/****** 函数介绍 ******/
/* 作用 : UART中断函数注册
 * 传入参数 : 
     * ui32Base :UART端口的基地址
     * void (*pfnHandler)(void) : 串口中断函数名字,此函数无返回值,无传入值
 * 返回参数 : 无
*/

ROM_IntPrioritySet()

设置中断的优先级。

/****** 函数声明 ******/
//这个存放在ROM
void ROM_IntPrioritySet(uint32_t ui32Interrupt,uint8_t ui8Priority);
//这个是存放在flash
void IntPrioritySet(uint32_t ui32Interrupt,uint8_t ui8Priority);
/****** 函数介绍 ******/
/* 作用 : 设置中断的优先级
 * 传入参数 : 
     * ui32Interrupt :指定所涉及的中断。在hw_ints.h中定义
     * ui8Priority : 中断优先级,当同时断言多个中断时,具有最高优先级的中断将在较低优先级的中断之前被处理。xxx0 0000,只看 xxx 前三位。比如0的优先级比0xE0高。
 * 返回参数 : 无
*/


printf重映射

(1)因为很多人喜欢使用printf重映射打印数据。所以这里我也进行简单的讲解。但是printf重映射只能映射一个串口,不过我下面还有一个方案,可以让所有的串口都能够printf重映射。

(2)我们只需要将x改动一下即可。同时需要打开MicroLIB。


//重新映射printf函数到UARTx,x可为1,2,3,4,5,6,7
int fputc(int ch, FILE *f){UARTCharPut(UARTx_BASE,ch);  return (ch);}
int fgetc(FILE *f) {int ch=UARTCharGet(UARTx_BASE); return (ch);}
printf("* 作者     : CSND 风正豪 \r\n");


多个串口同时重映射

直接复制如下的函数,就可以直接将多个串口初始

/* 作用 : 用于多路串口重定义
 * 传入参数 : 
     baseAddress : 要打印的串口地址,UARTx_BASE,x可为0,1,2,3,4,5,6,7
     format : 需要打印的东西
     ... : 如果是打印字符,输入%c。有符号数字,%d。用法与printf一样
 * 返回值 : 无
*/
void UART_printf(uint32_t baseAddress, const char *format,...)
{
    uint32_t length;
    va_list args;
    uint32_t i;
    char TxBuffer[128] = {0};
    va_start(args, format);
    length = vsnprintf((char*)TxBuffer, sizeof(TxBuffer), (char*)format, args);
    va_end(args);
    for(i = 0; i < length; i++)
    {
       while(UARTBusy(baseAddress));
       UARTCharPut(baseAddress,TxBuffer[i]);
    }
}

实操

#include "stdio.h"
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdarg.h>
#include "hw_memmap.h"
#include "hw_types.h"
#include "hw_gpio.h"
#include "hw_ints.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
/*
*********************************************************************************************************
* 函 数 名: PrintfLogo
* 功能说明: 打印例程名称和例程发布日期, 接上串口线后,打开PC机的串口终端软件可以观察结果
* 形    参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void PrintfLogo(void)
{
  printf("*************************************************************\n\r");
  printf("* %s\r\n", "串口0控制RGB例程"); /* 打印例程名称 */
  printf("* 发布日期 : %s\r\n", "2023年4月24日");  /* 打印例程日期 */
  printf("* 使用芯片 : TM4C123GH6PZI7\r\n");
  printf("* 作者     : CSND 风正豪 \r\n");
  printf("*************************************************************\n\r");
}
/* 作用 : 用于多路串口重定义
 * 传入参数 : 
     baseAddress : 要打印的串口地址,UARTx_BASE,x可为0,1,2,3,4,5,6,7
     format : 需要打印的东西
     ... : 如果是打印字符,输入%c。有符号数字,%d。用法与printf一样
 * 返回值 : 无
*/
void UART_printf(uint32_t baseAddress, const char *format,...)
{
    uint32_t length;
    va_list args;
    uint32_t i;
    char TxBuffer[128] = {0};
    va_start(args, format);
    length = vsnprintf((char*)TxBuffer, sizeof(TxBuffer), (char*)format, args);
    va_end(args);
    for(i = 0; i < length; i++)
    {
       while(UARTBusy(baseAddress));
       UARTCharPut(baseAddress,TxBuffer[i]);
    }
}
//串口0的接收中断
static uint8_t ch;
void UART0_IRQHandler(void)
{   
  //获取中断标志 原始中断状态 屏蔽中断标志    
  uint32_t flag = UARTIntStatus(UART0_BASE,1);
  //清除中断标志      
  UARTIntClear(UART0_BASE,flag);
  //判断FIFO是否还有数据
  while(UARTCharsAvail(UART0_BASE))   
  { 
    //接收数据
    ch=UARTCharGet(UART0_BASE);
  } 
}
void ConfigureUART0(void)
{ 
    //使能UART使用的GPIO外设 
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    //使能 UART0
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    //配置UART模式的GPIO引脚
    ROM_GPIOPinConfigure(GPIO_PA0_U0RX);
    ROM_GPIOPinConfigure(GPIO_PA1_U0TX);
    ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    //设置串口0,时钟源速率为系统时钟,波特率为9600,8数据位,1停止位,无校验位
    UARTConfigSetExpClk(UART0_BASE, SysCtlClockGet(), 9600,(UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |UART_CONFIG_PAR_NONE));
    //禁用UART模块的FIFO缓冲区。减少串口接收的延迟,提高响应速度。
    UARTFIFODisable(UART0_BASE);
    //使能UART0接收中断 
    UARTIntEnable(UART0_BASE,UART_INT_RX);
    //UART0中断函数注册 
    UARTIntRegister(UART0_BASE,UART0_IRQHandler);
    //设置中断优先级
    ROM_IntPrioritySet(INT_UART0,0x60);
}
//重新映射printf函数到UART0
int fputc(int ch, FILE *f){UARTCharPut(UART0_BASE,ch);  return (ch);}
int fgetc(FILE *f) {int ch=UARTCharGet(UART0_BASE); return (ch);}
void RGB_Init(void)
{
  ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);  //使能GPIOF外设 
  ROM_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_5);//红色
  ROM_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_6);//绿色
  ROM_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_4);//蓝色
  ROM_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_PIN_4);//置高位熄灭
  ROM_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_5, GPIO_PIN_5);//置高位熄灭
  ROM_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_6, GPIO_PIN_6);//置高位熄灭
}
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
    RGB_Init();
    ConfigureUART0();//初始化串口0
    PrintfLogo();//串口打印版本信息
    while(1)
    {
      if((int8_t)ch == 'a')
      {
        UARTprintf("Turn on the LED1\n"); //无法使用
        UART_printf(UART0_BASE,"%s\n","hello world");
        GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_5, !GPIO_PIN_5);//置低位点亮
        SysCtlDelay(SysCtlClockGet() / 10);    
        GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_5, GPIO_PIN_5);//置高位熄灭
        SysCtlDelay(SysCtlClockGet() / 10);
      }
      if((int8_t)ch == 'b')
      {
        UART_printf(UART0_BASE,"2+2=%d\n",4);
        GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_6, !GPIO_PIN_6);//置低位点亮
        SysCtlDelay(SysCtlClockGet() / 10);    
        GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_6, GPIO_PIN_6);//置高位熄灭
        SysCtlDelay(SysCtlClockGet() / 10);
      }
      if((int8_t)ch == 'c')
      {
        UART_printf(UART0_BASE,"2+2.0=%f\n",4.0);
        GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_4, !GPIO_PIN_4);//置低位点亮
        SysCtlDelay(SysCtlClockGet() / 10);      
        GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_PIN_4);//置高位熄灭
        SysCtlDelay(SysCtlClockGet() / 10);
      }
    }
}
目录
相关文章
|
6天前
|
传感器
STM32标准库外部中断和定时器知识点总结-2
STM32标准库外部中断和定时器知识点总结
|
9月前
|
数据采集
TM4C123库函数学习(4)--- 按键输入
TM4C123库函数学习(4)--- 按键输入
52 0
|
7月前
|
芯片
STM32速成笔记(四)—中断
本文介绍了中断的概念,中断的相关名词,STM32外部中断配置方法以及使用中断的注意事项。给出了外部中断点亮LED程序设计思路和关键代码。
174 0
STM32速成笔记(四)—中断
|
9月前
|
算法 搜索推荐 芯片
TM4C123库函数学习(1)--- 点亮LED+TM4C123的ROM函数简介+keil开发环境搭建
TM4C123库函数学习(1)--- 点亮LED+TM4C123的ROM函数简介+keil开发环境搭建
157 0
|
9月前
|
调度
TM4C123库函数学习(2)--- LED闪烁,滴答定时器精准延时
TM4C123库函数学习(2)--- LED闪烁,滴答定时器精准延时
137 0
|
11月前
|
存储 API Windows
驱动开发:内核中进程与句柄互转
在内核开发中,经常需要进行进程和句柄之间的互相转换。进程通常由一个唯一的进程标识符(PID)来标识,而句柄是指对内核对象的引用。在Windows内核中,`EProcess`结构表示一个进程,而HANDLE是一个句柄。为了实现进程与句柄之间的转换,我们需要使用一些内核函数。对于进程PID和句柄的互相转换,可以使用函数如`OpenProcess`和`GetProcessId`。OpenProcess函数接受一个PID作为参数,并返回一个句柄。GetProcessId函数接受一个句柄作为参数,并返回该进程的PID。
327 0
STM32外中断
STM32外中断
59 0
【STM32】USART串口重映射 & 打印输出printf标识符
【STM32】USART串口重映射 & 打印输出printf标识符
167 0
UART子系统(十二)UART驱动调试方法
UART子系统(十二)UART驱动调试方法
146 0
UART子系统(十二)UART驱动调试方法