欢迎光临
我们一直在努力

串口通信方式、串口发送字符和字符串、printf重定向、串口中断接收、串口发送接收控制LED灯

文章目录

  • 串口USART
  • 1. 常见的通信方式
    • 1.1 串行通信和并行通信
    • 1.2 全双工,半双工和单工通信
    • 1.3 同步通信和异步通信
    • 1.4 通信速率
    • 1.5 常见的通信协议
  • 2. 串口基础知识
    • 2.1 电平特性
    • 2.2 串口传输协议
    • 2.3 STM32F103的USART资源
    • 2.4 STM32F103的UART框图
      • 2.4.1 端口引脚
      • 2.4.2 数据寄存器单元
      • 2.4.3 发送接收控制单元
      • 2.4.4 波特率发生器
      • 2.4.5 UART框图配置步骤
  • 3. 实现串口发送
    • 3.1 发送字符和字符串
    • 3.2 TXE 和 TC
  • 4. printf重定向
  • 5. 实现串口中断接收
  • 6. 串口发送接收控制LED灯

串口USART

1. 常见的通信方式

1.1 串行通信和并行通信

串行通信:速度较并行慢,但是占用的硬件资源少,通常只需要时钟线,一两根数据线还有片选线即可。 在这里插入图片描述

并行通信:速度快,但是需要很多根数据线、地址线等。 在这里插入图片描述

1.2 全双工,半双工和单工通信

全双工:同一时刻双方可以互相发送数据、接收数据 在这里插入图片描述

半双工:同一时刻只能有一方可以给另外一方发送数据,即此发彼收,此收彼发 在这里插入图片描述

单工:只能由发送方数据发送给接收方 在这里插入图片描述

1.3 同步通信和异步通信

  • 同步通信和异步通信都是针对串行通信而言
  • 异步通信
    • 1.数据是以字符为单位组成字符帧传输的。
    • 2.字符帧由发送端一帧一帧的发送,每帧数据均是低位在前,高位在后,通过传输线被接收端一帧一帧的接收。
    • 3.发送端和接收端可以有各自独立的时钟来控制数据的发送和接收,这两个时钟各自独立,互不同步。
    • 4.接收端依靠字符帧格式来判断发送端是何时开始和结束发送的。
    • 5.字符帧也叫做数据帧,由起始位,数据位,奇偶校验位,停止位等部分组成,是异步通信的一个重要指标。
    • 6.同步通信的另一个重要指标是波特率 (表示每秒钟传输的符号数量,单位是 波特)。
  • 同步通信
    • 1.同步是指在约定的通信速率下,发送端和接收端的时钟信号始终保持一致,保证通信双方在发送和接收数据时具有完全一致的定时关系。
    • 2.同步通信把许多字符组成一个信息帧,每帧的开始用同步字符来表示。
    • 3.在绝大多数场合下,发送端和接收端,采用的都是同一个时钟,所以在传送数据的同时还要发送时钟信号,以便接收端可以使用时钟信号来确定每一个信息位。
    • 4.同步通信一次通信只能传送一帧信息。

1.4 通信速率

对于同步通信,通信速率由时钟信号决定,时钟信号越快,传输速度越快。 对于异步通信来说,需要收发双方提前统一通信速率,这也就是我们串口调试时,波特率不对显示乱码的原因。

1、比特率:系统在单位时间内传输的比特率个数 (二进制0或1) ,通常用Rb表示,单位是比特 (bit/s),缩写为bps。 2、波特率:系统在单位时间内传输的码元个数,通常用RB来表示,单位是波特 (Bd) 3、码元有N个状态时,比特率与波特率的关系式:Rb = RB × log2 N (比特率 = 波特率 × 每符号比特数)

1.5 常见的通信协议

在嵌入式中,有众多的通信协议,往往从性能,成本,稳定性,易用性等角度考虑选择合适的协议。 在这里插入图片描述

2. 串口基础知识

2.1 电平特性

在这里插入图片描述 在这里插入图片描述

2.2 串口传输协议

在这里插入图片描述 参数概念:

  • 波特率:一般选波特率都会有9600,19200,115200等选项,其实意思就是每秒传输的码元数。
  • 起始位:先发出一个逻辑 0 的信号,表示传输数据的开始。
  • 数据位:可以是5~8位逻辑 “0” 或“1”,先传输Bit0,再传输bit1,以此类推。
  • 校验位:数据位加上这一位之后,使得 1 的位数应为偶数(偶校验)或者奇数(奇校验),以此来校验数据传送的正确性,校验位是可选的,可以不传输。
  • 停止位:它是一个字符数据的结束标志,数据线变回逻辑“1”。

2.3 STM32F103的USART资源

  • STM32103有三个通用同步异步收发器USART,两个通用异步收发器UART,USART也可以当作UART使用。
  • 通常使用的是UART功能,USART在某些场合会使用到,选择通信方式使用场合决定。
  • 可以通过电平转化芯片变为RS232/RS485电平。 在这里插入图片描述
  • 2.4 STM32F103的UART框图

    在这里插入图片描述

    2.4.1 端口引脚

    在这里插入图片描述 在这里插入图片描述

  • TX:数据发送端口
  • RX:数据接收端口
  • SW_RX:在单线和智能卡模式下接收数据,属于内部端口,没有实际的外部引脚
  • RTS:在硬件流控制下用于指示设备准备好可以接收数据了,低电平表示可以接收数据
  • CTS:在硬件流控制下用于指示设备 接收方准备好接收数据,允许发送方开始发送,如果是高电平那么在本次数据发送完成后会阻塞下一次的传输,只有在低电平的时候才允许下一次传输。
  • CK:同步时钟端口,在同步通信模式下使用,用于输出同步时钟信号。
  • 2.4.2 数据寄存器单元

    在这里插入图片描述

  • TDR:发送数据寄存器
  • RDR:接收数据寄存器
  • 在UART外设中只有一个寄存器USART_DR,是一个双向寄存器,取决于CPU是读这个寄存器还是写这个寄存器;如果是读就是RDR,如果是写就是TDR。
  • 2.4.3 发送接收控制单元

    在这里插入图片描述

  • CR1/CR2/CR3:控制寄存器,控制各种使能,比如UART使能、收发中断使能、DMA使能等等。
  • SR 状态寄存器:用来表明UART的收发状态和错误状态等等。
  • GTPR:Smartcard和IrDA模式下专用的寄存器
  • 2.4.4 波特率发生器

    在这里插入图片描述

  • fPCLK:外设总线时钟,USART1在APB1,最高可取72MHZ,剩下四个在APB2,最高可取36MHZ
  • USARTDIV:USART/UART时钟分频器
  • DIV_Mantissa:BBR寄存器的高12bit,用于存放波特率设置的整数部分
  • DIV_Fraction:BRR寄存器的低4bit,用于存放波特率设置值的小数部分,每一位对应的精度是1/2的四次方 = 0.0625
  • 波特率计算公式:baudrate = fPCLK / USARTDIV * 16
  • 1、假设fPCLK = 72MHZ,baudrate = 115200, 那么USARTDIV=72MHZ/16/115200 =39.0625, 则DIV_Mantissa = 39<<4 = 0x270,DIV_Fraction=0.0625/0.0625=1, 因此BRR= 0X271

    2、假设fPCLK = 72MHZ, baudrate = 9600, 那么USARTDIV=72MHZ/9600 = 468.75, 则DIV_Mantissa = 468<<4=0x1D40, DIV_Fraction=0.75/0.0625=12=0xC, 因而BRR=0X1D4C

    2.4.5 UART框图配置步骤

    • 选择需要使用的USART/UART (根据地址映射表得到地址)
    • 根据需要的波特率设置BRR寄存器
    • 根据需求配置控制寄存器中的停止位和校验位
    • 根据需求配置同步时钟使能位
    • 使能USART的发送和接收位
    • 根据需求使能发送和接收的中断位
    • 使能RCC中的选中的USART/UART的时钟
    • 使能USART/UART
    • 写USART_DR寄存器发送数据,读USART_DR寄存器接收数据

    3. 实现串口发送

    3.1 发送字符和字符串

    软件流程设计

    • 初始化系统
      • 初始化GPIO、串口外设时钟
      • 初始化串口引脚 (A9 数据发送, A10 数据接收)
      • 初始化串口外设
    • 串口发送

    // USART.h 头文件
    #ifndef USART_H
    #define USART_H
    void My_Usart_Init(void);
    void My_Usart_Send_Byte(USART_TypeDef* USARTx, uint16_t Data);
    void My_Usart_Send_String(USART_TypeDef* USARTx, char *str);
    #endif

    // USART.c 源文件
    #include "stm32f10x.h"
    #include "USART.h"

    // 定义 USART 串口函数
    void My_Usart_Init(void){
    GPIO_InitTypeDef GPIO_InitStruct;
    USART_InitTypeDef USART_InitStruct;// 定义 USART 结构体

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);
    USART_Cmd(USART1, ENABLE);// 串口时钟使能

    // GPIOA9 TX 输出数据发送
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStruct);

    // GPIOA10 RX 输入 数据接收
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOA, &GPIO_InitStruct);

    // 串口 USART1 初始化
    USART_InitStruct.USART_BaudRate = 115200;// 波特率
    USART_InitStruct.USART_WordLength = USART_WordLength_8b; // 串口数据的字节长度
    USART_InitStruct.USART_StopBits = USART_StopBits_1;// 停止位
    USART_InitStruct.USART_Parity = USART_Parity_No;// 奇偶校验位
    USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; // 发送 接收模式
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 硬件流控制
    USART_Init(USART1, &USART_InitStruct);// 初始化 USART1 结构体
    }

    // USART 串口发送一个字节函数
    void My_Usart_Send_Byte(USART_TypeDef* USARTx, uint16_t Data){
    USART_SendData(USARTx, Data);

    // 等待传输完成(TC标志置位), 发送移位寄存器为空(影子寄存器)
    while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET);
    }

    // USART串口发送字符串函数
    void My_Usart_Send_String(USART_TypeDef* USARTx, char *str){
    uint16_t i = 0;

    while(*(str+i) != '\\0'){
    My_Usart_Send_Byte(USARTx, *(str+i));
    i++;
    };
    // 所有字节已在 My_Usart_Send_Byte 中等待 TC, 此处无需再等

    }

    // main.c
    #include "stm32f10x.h"
    #include "main.h"
    #include "USART.h"

    void delay(uint16_t time)
    {
    uint16_t i=0;
    while(time)
    {
    i = 12000;
    while(i);
    }
    }

    int main()
    {
    My_Usart_Init();

    My_Usart_Send_Byte(USART1, 'A');
    My_Usart_Send_Byte(USART1, 'B');
    My_Usart_Send_Byte(USART1, 'C');
    My_Usart_Send_String(USART1, "ZhangSan \\r\\n");
    while(1)
    {

    }
    }

    库函数实现串口发送

    串口USART结构体:
    typedef struct {
    uint32_tUSART_BaudRate;// 设置 USART 的波特率
    uint16_tUSART_WordLength;// 设置数据帧中的数据位长度
    uint16_tUSART_StopBits;// 设置停止位的数量
    uint16_tUSART_Parity;// 设置奇偶校验方式
    uint16_tUSART_Mode;// 设置 USART 的工作模式 (发送/接收使能)
    uint16_tUSART_HardwareFlowControl;// 设置硬件流控制 (RTS/CTS 信号)
    } USART_InitTypeDef;

    串口USART相关库函数:
    voidUSART_DeInit(USART_TypeDef*USARTx);
    voidUSART_Init(USART_TypeDef*USARTx, USART_InitTypeDef*
    USART_InitStruct);
    voidUSART_StructInit(USART_InitTypeDef*USART_InitStruct);
    voidUSART_ClockInit(USART_TypeDef*USARTx, USART_ClockInitTypeDef*
    USART_ClockInitStruct);
    voidUSART_ClockStructInit(USART_ClockInitTypeDef*
    USART_ClockInitStruct);
    voidUSART_Cmd(USART_TypeDef*USARTx, FunctionalStateNewState);
    voidUSART_ITConfig(USART_TypeDef*USARTx, uint16_tUSART_IT,
    FunctionalStateNewState);
    voidUSART_DMACmd(USART_TypeDef*USARTx, uint16_tUSART_DMAReq,
    FunctionalStateNewState);
    voidUSART_SetAddress(USART_TypeDef*USARTx, uint8_tUSART_Address);
    voidUSART_WakeUpConfig(USART_TypeDef*USARTx, uint16_tUSART_WakeUp);voidUSART_ReceiverWakeUpCmd(USART_TypeDef*USARTx, FunctionalState
    NewState);
    voidUSART_LINBreakDetectLengthConfig(USART_TypeDef*USARTx, uint16_t
    USART_LINBreakDetectLength);
    voidUSART_LINCmd(USART_TypeDef*USARTx, FunctionalStateNewState);
    voidUSART_SendData(USART_TypeDef*USARTx, uint16_tData);
    uint16_tUSART_ReceiveData(USART_TypeDef*USARTx);
    voidUSART_SendBreak(USART_TypeDef*USARTx);
    voidUSART_SetGuardTime(USART_TypeDef*USARTx, uint8_t
    USART_GuardTime);
    voidUSART_SetPrescaler(USART_TypeDef*USARTx, uint8_t
    USART_Prescaler);
    voidUSART_SmartCardCmd(USART_TypeDef*USARTx, FunctionalState
    NewState);
    voidUSART_SmartCardNACKCmd(USART_TypeDef*USARTx, FunctionalState
    NewState);
    voidUSART_HalfDuplexCmd(USART_TypeDef*USARTx, FunctionalState
    NewState);
    voidUSART_OverSampling8Cmd(USART_TypeDef*USARTx, FunctionalState
    NewState);
    voidUSART_OneBitMethodCmd(USART_TypeDef*USARTx, FunctionalState
    NewState);
    voidUSART_IrDAConfig(USART_TypeDef*USARTx, uint16_tUSART_IrDAMode);voidUSART_IrDACmd(USART_TypeDef*USARTx, FunctionalStateNewState);
    FlagStatusUSART_GetFlagStatus(USART_TypeDef*USARTx, uint16_t
    USART_FLAG);
    voidUSART_ClearFlag(USART_TypeDef*USARTx, uint16_tUSART_FLAG);
    ITStatusUSART_GetITStatus(USART_TypeDef*USARTx, uint16_tUSART_IT);
    voidUSART_ClearITPendingBit(USART_TypeDef*USARTx, uint16_t
    USART_IT);

    3.2 TXE 和 TC

    标志位含义何时置位
    USART_FLAG_TXE 发送数据寄存器为空 数据从 DR 移入移位寄存器后立即置位(数据尚未完全发出!)
    USART_FLAG_TC 传输完成 整个帧(包括停止位)真正发送完毕
    场景使用 TXE使用 TC
    发送速度 更快(可提前写入下一字节) 稍慢(需等完整帧)
    数据可靠性 ❌ 可能丢尾字节 ✅ 保证物理层发送完成
    适用场合 高速连续发送(如 DMA 或中断缓冲) 单字节/调试输出/可靠传输

    4. printf重定向

    C语言里面的printf函数默认输出设备是显示器,如果要实现printf函数输出在串口或LCD显示屏上,必须要重定义标准库函数里面调用的I/O输出设备相关的函数,比如printf输出串口,需要将 fputc 里面的输出指向串口。

    1、配置勾选 在这里插入图片描述

    2、printf 重定向

    // USATR.c 源文件
    #include "stm32f10x.h"
    #include "USART.h"
    #include "stdio.h"

    // 定义 USART 串口函数
    void My_Usart_Init(void){
    GPIO_InitTypeDef GPIO_InitStruct;
    USART_InitTypeDef USART_InitStruct;// 定义 USART 结构体

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);
    USART_Cmd(USART1, ENABLE);// 串口时钟使能

    // GPIOA9 TX 输出数据发送
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStruct);

    // GPIOA10 RX 输入 数据接收
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOA, &GPIO_InitStruct);

    // 串口 USART1 初始化
    USART_InitStruct.USART_BaudRate = 115200;// 波特率
    USART_InitStruct.USART_WordLength = USART_WordLength_8b; // 串口数据的字节长度
    USART_InitStruct.USART_StopBits = USART_StopBits_1;// 停止位
    USART_InitStruct.USART_Parity = USART_Parity_No;// 奇偶校验位
    USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; // 发送 接收模式
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 硬件流控制
    USART_Init(USART1, &USART_InitStruct);// 初始化 USART1 结构体
    }

    // printf 重定向
    int fputc(int ch, FILE *p){
    USART_SendData(USART1, (u8)ch);
    // 等待整个帧发送完成 (包括停止位)
    while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);

    return ch;
    }

    // main.c
    #include "stm32f10x.h"
    #include "main.h"
    #include "USART.h"
    #include "stdio.h"

    int main()
    {
    My_Usart_Init();

    while(1)
    {
    printf("Hello World \\r\\n");
    }
    }

    5. 实现串口中断接收

    软件流程设计

    • 初始化系统
      • 初始化GPIO、串口时钟
      • 初始化GPIO、串口引脚
      • 初始化串口中断接收外设、NVIC嵌套中断控制器
    • 编写串口中断函数

    // USATR.c 源文件
    #include "stm32f10x.h"
    #include "USART.h"
    #include "stdio.h"

    // 定义 USART 串口函数
    void My_Usart_Init(void){
    GPIO_InitTypeDef GPIO_InitStruct;// 定义 GPIO 结构体
    USART_InitTypeDef USART_InitStruct;// 定义 USART 结构体
    NVIC_InitTypeDef NVIC_InitStruct;// 定义 NVIC 结构体

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);
    USART_Cmd(USART1, ENABLE);// 串口时钟使能

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 优先级分组配置

    // GPIOA9 TX 输出数据发送
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStruct);

    // GPIOA10 RX 输入 数据接收
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOA, &GPIO_InitStruct);

    // 串口 USART1 初始化
    USART_InitStruct.USART_BaudRate = 115200;// 波特率
    USART_InitStruct.USART_WordLength = USART_WordLength_8b; // 串口数据的字节长度
    USART_InitStruct.USART_StopBits = USART_StopBits_1;// 停止位
    USART_InitStruct.USART_Parity = USART_Parity_No;// 奇偶校验位
    USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; // 发送 接收模式
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 硬件流控制
    USART_Init(USART1, &USART_InitStruct);// 初始化 USART1 结构体
    // 串行通信中断配置
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);// 接收数据寄存器不为空发生中断

    // NVIC 初始化
    NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;// 初始化串口中断线1
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);
    }

    // printf 重定向
    int fputc(int ch, FILE *p){
    USART_SendData(USART1, (u8)ch);
    // 等待整个帧发送完成 (包括停止位)
    while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);

    return ch;
    }

    // 串口中断函数, 只要满足完整中断条件, 自动执行函数
    // "中断配置条件" 必须同时包含 USART配置 + NVIC使能
    void USART1_IRQHandler(void){
    char str;

    // 如果检查到串口中断线(USART1)发生了中断请求
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET){
    str = USART_ReceiveData(USART1);// 串口数据接收
    printf("receive date: %c \\r\\n", str);

    // 清除串口中断线(USART1)的中断挂起标志位, 方便下次还能运行函数
    USART_ClearITPendingBit(USART1, USART_IT_RXNE);
    }
    }

    // main.c
    #include "stm32f10x.h"
    #include "main.h"
    #include "USART.h"

    int main()
    {
    My_Usart_Init();

    while(1)
    {

    }
    }

    6. 串口发送接收控制LED灯

    // USATR.c 源文件
    #include "stm32f10x.h"
    #include "USART.h"
    #include "stdio.h"

    // 定义 USART 串口函数
    void My_Usart_Init(void){
    GPIO_InitTypeDef GPIO_InitStruct;// 定义 GPIO 结构体
    USART_InitTypeDef USART_InitStruct;// 定义 USART 结构体
    NVIC_InitTypeDef NVIC_InitStruct;// 定义 NVIC 结构体

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);
    USART_Cmd(USART1, ENABLE);// 串口时钟使能

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 优先级分组配置

    // GPIOA9 TX 输出数据发送
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStruct);

    // GPIOA10 RX 输入 数据接收
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOA, &GPIO_InitStruct);

    // 串口 USART1 初始化
    USART_InitStruct.USART_BaudRate = 115200;// 波特率
    USART_InitStruct.USART_WordLength = USART_WordLength_8b; // 串口数据的字节长度
    USART_InitStruct.USART_StopBits = USART_StopBits_1;// 停止位
    USART_InitStruct.USART_Parity = USART_Parity_No;// 奇偶校验位
    USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; // 发送 接收模式
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 硬件流控制
    USART_Init(USART1, &USART_InitStruct);// 初始化 USART1 结构体
    // 串行通信中断配置
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);// 接收数据寄存器不为空发生中断

    // NVIC 初始化
    NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;// 初始化串口中断线1
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);
    }

    // printf 重定向
    int fputc(int ch, FILE *p){
    USART_SendData(USART1, (u8)ch);
    // 等待整个帧发送完成 (包括停止位)
    while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);

    return ch;
    }

    // 串口中断函数, 只要满足完整中断条件, 自动执行函数
    // "中断配置条件" 必须同时包含 USART配置 + NVIC使能
    void USART1_IRQHandler(void){
    char str;

    // 如果检查到串口中断线(USART1)发生了中断请求
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET){
    str = USART_ReceiveData(USART1);// 串口数据接收
    printf("receive date: %c \\r\\n", str);

    // 清除串口中断线(USART1)的中断挂起标志位, 方便下次还能运行函数
    USART_ClearITPendingBit(USART1, USART_IT_RXNE);
    }
    }

    // 串口中断函数, 只要满足完整中断条件, 自动执行函数
    void USART1_IRQHandler(void){
    char str = 0;

    // 判断是否发生中断
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET){
    str = USART_ReceiveData(USART1);// 串口数据接收
    printf("receive date: %c \\r\\n", str);

    // 串口接收到字符 0 开灯
    if(str == '0'){
    GPIO_ResetBits(GPIOA, GPIO_Pin_1);
    printf("LED IS ON \\r\\n");
    }

    // 串口接收到字符 1 关灯
    if(str == '1'){
    GPIO_SetBits(GPIOA, GPIO_Pin_1);
    printf("LED IS OFF \\r\\n");
    }

    // 清除串口中断线的挂起标志位, 方便函数下次运行
    USART_ClearITPendingBit(USART1, USART_IT_RXNE);
    }
    }

    // main.c
    #include "stm32f10x.h"
    #include "main.h"
    #include "USART.h"
    #include "LED.h"

    int main()
    {
    My_Usart_Init();
    LED_Init();

    while(1)
    {

    }
    }

    赞(0)
    未经允许不得转载:171主机测评 » 串口通信方式、串口发送字符和字符串、printf重定向、串口中断接收、串口发送接收控制LED灯
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址