5.STM32之通信接口《精讲》之USART通信---实验串口接收程序

根据上节,我们一已经完成了串口发送程序的代码,并且深入的解析探索了串口的原理,接下来,Whappy小编将带领大家进入串口接收程序的探索与实验,并将结合上一节串口发送一起来完成串口的发送和接收实验。

上来两张图

上图为数据手册推荐的TX和RX的GPIO的配置模式!

代码逐步解释

  1. 设置波特率:

    复制代码

    c

    复制代码

    USART1_InitStructure.USART_BaudRate = 9600;

    • 配置串口的通信速率为 9600 bps,这决定了串口通信的速率。
  2. 硬件流控:

    复制代码

    c

    复制代码

    USART1_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

    • 不使用硬件流控制(如 RTS 和 CTS 信号)。默认只进行基本的 TX/RX 数据传输。
  3. 工作模式:

    复制代码

    c

    复制代码

    USART1_InitStructure.USART_Mode = USART_Mode_Tx;

    • 设置为发送模式(Tx),即该配置目前只支持数据发送,不包括接收。
  4. 校验位设置:

    复制代码

    c

    复制代码

    USART1_InitStructure.USART_Parity = USART_Parity_No;

    • 不使用奇偶校验位。
  5. 停止位:

    复制代码

    c

    复制代码

    USART1_InitStructure.USART_StopBits = USART_StopBits_1;

    • 设置 1 个停止位。
  6. 字长设置:

    复制代码

    c

    复制代码

    USART1_InitStructure.USART_WordLength = USART_WordLength_8b;

    • 设置字长为 8 位(不包括起始位、校验位和停止位)。
  7. 初始化 USART1:

    复制代码

    c

    复制代码

    USART_Init(USART1, &USART1_InitStructure);

    • 调用库函数对 USART1 进行初始化,应用上述配置。
  8. 使能 USART1:

    复制代码

    c

    复制代码

    USART_Cmd(USART1, ENABLE);

    • 启用 USART1 外设。

如何添加接收功能

要使能接收功能,需要将 USART_Mode 设置为接收模式或同时支持发送和接收模式,并适配相应的 GPIO 引脚(如 RX 引脚)。

修改代码:
复制代码

c

复制代码

USART1_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;

添加接收引脚的初始化:

初始化 GPIOA 的 PA10(USART1 RX)为浮空输入或上拉输入模式:

复制代码

c

复制代码

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入 GPIO_Init(GPIOA, &GPIO_InitStructure);

使用 USART 接收功能:

接收数据可以通过轮询方式或中断方式读取数据。

  1. 轮询方式 : 使用 USART_ReceiveData 读取接收到的数据:

    复制代码

    c

    复制代码

    if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET) { uint8_t received_data = USART_ReceiveData(USART1); // 读取数据 }

  2. 中断方式

    • 使能 USART1 的接收中断:

      复制代码

      c

      复制代码

      USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); NVIC_EnableIRQ(USART1_IRQn); // 使能中断

    • 在中断处理函数中读取数据:

      复制代码

      c

      复制代码

      void USART1_IRQHandler(void) { if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { uint8_t received_data = USART_ReceiveData(USART1); // 读取接收到的数据 // 处理接收到的数据 } }

这个可以给大家说一下,目前以及以前学的都是STM32内部集成的外设

在这里Whappy给大家整理一下,也可以看对应的数据手册

以下是 STM32 内部外设整理的表格,适合 A4 大小打印:

分类 外设名称 功能描述 备注
通信外设 USART/UART 串口通信,支持异步传输,部分支持 LIN、IrDA、Modbus。 常用作调试串口和外设通信。
SPI 全双工同步通信,用于连接传感器、存储设备等。 常用于高速短距离数据传输。
I2C 主从同步通信协议,连接低速设备(如 EEPROM、传感器)。 适用于多设备共享通信总线。
CAN 工业控制和汽车通信网络。 适合实时和抗干扰场景。
USB 支持设备/主机/OTG 模式,可实现与 PC 的通信。 部分型号支持 USB 2.0。
Ethernet 网络通信接口,用于数据网络传输。 高性能型号支持。
SDIO 与 SD 卡或 MMC 卡通信。 常用于外部存储扩展。
定时器外设 通用定时器(TIMx) PWM 生成、定时、中断产生、脉冲计数等。 提供灵活的定时功能。
高级定时器 支持复杂 PWM,适合电机控制场景。 例如:TIM1、TIM8。
基础定时器 用于简单的时间基准,如滴答定时器。 例如:TIM6、TIM7。
看门狗定时器 独立看门狗和窗口看门狗,用于提高系统容错性。 防止程序跑飞。
模拟外设 ADC 多通道模数转换,通常为 12 位分辨率。 部分型号支持 16 位高精度 ADC。
DAC 数模转换,将数字信号输出为模拟电压。 用于波形生成。
比较器 模拟信号比较,可实现过零检测。 多用于实时保护电路。
运算放大器 集成模拟放大电路,便于信号处理。 仅部分高端型号支持。
存储外设 闪存(Flash Memory) 存储程序代码,支持在线擦写。 用于固件存储。
SRAM 数据存储,静态随机存储器。 易失性存储器。
EEPROM 保存配置数据,非易失性存储器。 部分型号支持内置。
控制与管理外设 DMA 提高数据传输效率,减少 CPU 干预。 用于大数据量传输场景。
RTC 提供低功耗实时时钟,支持日期和时间功能。 适合低功耗应用。
电源管理模块 支持睡眠、停止、待机模式。 降低能耗。
PVD 电源电压检测器,用于检测异常电压。 提供电源保护。
GPIO GPIO 通用输入输出接口,支持输入/输出/模拟模式。 可复用为外设功能引脚。
安全外设 CRC 提供数据完整性校验。 用于通信或存储校验。
TRNG 真随机数生成器,用于加密。 常见于安全应用。
硬件加密引擎 支持 AES、SHA 等硬件加速算法。 提高加密运算效率。
显示外设 LCD 控制器 驱动 LCD 显示屏,支持多种接口标准。 仅部分型号支持。
FSMC/FMC 支持连接外部存储器或显示屏。 高性能型号提供支持。
特殊外设 触摸感应控制器 支持触摸按键或触摸屏检测。 用于人机交互设计。
硬件 DIV/SQRT 硬件实现除法与开方运算,提高效率。 部分型号支持。

不同 STM32 系列(如 F1、F4、H7 等)外设配置有所差异,实际使用时需查阅对应芯片的参考手册

代码加入部分!

配置接收部分,只需另初始化一下GPIOA的PA10即可,然后在初始化的串口模式配置中或上一个接收部分的模式即可!

接收部分!有查询和中断模式,下面分别演示一下这个模式

在 STM32 或嵌入式开发中,轮询方式中断方式是两种常用的外设数据处理方式。两者的核心区别在于程序对外设事件的响应机制:


1. 轮询方式

工作原理
  • 程序不断检查某个标志位(例如,USART 的接收标志位 USART_FLAG_RXNE),当标志位被设置时,执行相应操作。
  • 轮询方式是同步的,程序在等待某个事件发生时无法执行其他任务。
优点
  • 实现简单,不需要配置中断。
  • 不涉及中断优先级,代码逻辑直观。
缺点
  • 占用 CPU 时间:程序不断地检查标志位,会浪费大量 CPU 时间。

  • 不适合实时性高或需要处理多任务的场景。

    void USART_PollingReceive(void) {
    uint8_t received_data;

      while (1) {
          // 检查 RXNE 标志位,判断是否有数据可读
          if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET) {
              // 读取数据
              received_data = USART_ReceiveData(USART1);
    
              // 处理接收到的数据
              printf("Received: %c\n", received_data);
          }
      }
    

    }

执行流程:

  • 程序进入一个无限循环。
  • 持续检查 USART_FLAG_RXNE 是否置位。
  • 如果有数据,则读取处理。

2. 中断方式

工作原理
  • 程序无需主动检查某个标志位。外设事件发生(例如 USART 接收到数据)时,自动触发中断,CPU 跳转到中断服务程序执行预设操作。
  • 中断方式是异步的,外设与主程序解耦,CPU 能处理其他任务。
优点
  • 高效:CPU 只在外设有事件发生时响应,不浪费时间。
  • 支持实时性要求高的场景。
  • 易于实现多任务系统的并行性。
缺点
  • 实现较复杂,需要配置中断向量表、优先级等。
  • 如果中断处理时间过长,可能影响系统的实时性。
示例代码

以下是基于 USART 的中断接收数据的示例:

void USART_InterruptInit(void) {
    // USART 初始化略(同之前的代码)

    // 启用 USART 接收中断
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

    // 配置 NVIC(中断控制器)
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

void USART1_IRQHandler(void) {
    uint8_t received_data;

    // 检查是否是接收中断
    if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
        // 读取接收到的数据
        received_data = USART_ReceiveData(USART1);

        // 处理接收到的数据
        printf("Interrupt Received: %c\n", received_data);

        // 清除中断标志位(库函数自动完成)
    }
}

执行流程:

  • 当 USART 接收到数据时,硬件自动触发中断。
  • CPU 跳转到 USART1_IRQHandler 中断服务函数执行处理。
  • 处理完成后,CPU 返回主程序继续执行其他任务。

轮询模式:

#include "stm32f10x.h"                  // Device header
#include <stdio.h>
#include <stdarg.h>
#include "Delay.h"


void Serial_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);


    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;          // 选择引脚13
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;    // 推挽输出模式
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   // 设置引脚速度
    GPIO_Init(GPIOA, &GPIO_InitStructure);               // 初始化GPIO
	
	//串口发送初始化
	GPIO_InitTypeDef GPIO_InitStructrue;
	GPIO_InitStructrue.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 串口发送的TX
	GPIO_InitStructrue.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructrue.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructrue);
	
	//串口接收GPIO初始化
	GPIO_InitStructrue.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
	GPIO_InitStructrue.GPIO_Pin = GPIO_Pin_10;
//	GPIO_InitStructrue.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructrue);
	
	//内部外设USART1初始化
	USART_InitTypeDef USART1_InitStructure;
	USART1_InitStructure.USART_BaudRate = 9600;
	USART1_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART1_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
	USART1_InitStructure.USART_Parity = USART_Parity_No ;
	USART1_InitStructure.USART_StopBits = USART_StopBits_1;
	USART1_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_Init(USART1,&USART1_InitStructure);
	USART_Cmd(USART1,ENABLE);
	
	
	
	
}

void Serial_SendByte(uint8_t Byte)
{
	USART_SendData(USART1,Byte);
	while ((USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET));
}



void Serial_SendArray(uint8_t* Array, uint8_t Lenght)
{
	uint16_t i;
	for(i=0; i<Lenght; i++)
	{
		Serial_SendByte(Array[i]);
	}
}


void Serial_SendString(char* String)
{
	uint8_t i;
	for(i=0; String[i] != '\0'; i++)
	{
		Serial_SendByte(String[i]);
	}
}

uint32_t Result(uint32_t X, uint32_t Y)
{
	uint8_t result = 1;
	while(Y--)
	{
		result = result * X;
	}
	
	return result;
}

void Serial_SendNum(uint32_t Num, uint16_t Lenght)
{
	uint16_t i;
	uint32_t ww;
	for(i=Lenght; i>0; i--)
	{
		ww = Result(10,i-1);
		Serial_SendByte((Num/ww )% 10 + '0');
		
	}
	
}

	
int fputc(int ch, FILE* f)
{
	Serial_SendByte(ch);
	return ch;
}


void Serial_Printf(char* format, ...)
{
	char String[100];
	va_list arg;
	va_start(arg,format);
	vsprintf(String, format, arg);
	va_end(arg);
	Serial_SendString(String);
}

重定向C库函数printf()到串口,重定向后可使用printf();
//int fputc(int ch,FILE *f)
//{
//	USART_SendData(USART1,(uint8_t)ch);
//	while(!(USART_GetFlagStatus(USART1,USART_FLAG_TC)));
//	return ch;
//}


void USART_PollingReceive(void) {
    uint8_t received_data;
	Serial_Printf("Please enter the book command: ");
    while (1) {
        // 检查 RXNE 标志位,判断是否有数据可读
        if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET) {
            // 读取数据
            received_data = USART_ReceiveData(USART1);
			

            // 只有在接收到'3'时才处理接收的数据
            if (received_data == '3') {
                // 点亮LED
                GPIO_SetBits(GPIOA, GPIO_Pin_4);   // 点亮LED

                // 处理接收到的数据
                printf("Received: %c\n", received_data);
				

                // 等待一段时间,模拟LED点亮一段时间后熄灭(可选)
                Delay_ms(1000); // 延时1000ms,具体延时函数需要根据你的环境定义

                // 熄灭LED
                GPIO_ResetBits(GPIOA, GPIO_Pin_4); // 熄灭LED
            } else {
                // 如果接收到的不是'3',则继续等待
                printf("Invalid command received: %c\n", received_data);
            }
        }
    }
}

中断模式:

#include "stm32f10x.h"                  // Device header
#include <stdio.h>
#include <stdarg.h>
#include "Delay.h"


void Serial_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);


    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;          // 选择引脚13
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;    // 推挽输出模式
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   // 设置引脚速度
    GPIO_Init(GPIOA, &GPIO_InitStructure);               // 初始化GPIO
	
	//串口发送初始化
	GPIO_InitTypeDef GPIO_InitStructrue;
	GPIO_InitStructrue.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 串口发送的TX
	GPIO_InitStructrue.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructrue.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructrue);
	
	//串口接收GPIO初始化
	GPIO_InitStructrue.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
	GPIO_InitStructrue.GPIO_Pin = GPIO_Pin_10;
//	GPIO_InitStructrue.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructrue);
	
	//内部外设USART1初始化
	USART_InitTypeDef USART1_InitStructure;
	USART1_InitStructure.USART_BaudRate = 9600;
	USART1_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART1_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
	USART1_InitStructure.USART_Parity = USART_Parity_No ;
	USART1_InitStructure.USART_StopBits = USART_StopBits_1;
	USART1_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_Init(USART1,&USART1_InitStructure);
	USART_Cmd(USART1,ENABLE);
	
	
	
	//开启中断
	USART_ITConfig(USART1, USART_IT_RXNE,ENABLE);
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	//NVIC配置
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);
	
	
}

void Serial_SendByte(uint8_t Byte)
{
	USART_SendData(USART1,Byte);
	while ((USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET));
}



void Serial_SendArray(uint8_t* Array, uint8_t Lenght)
{
	uint16_t i;
	for(i=0; i<Lenght; i++)
	{
		Serial_SendByte(Array[i]);
	}
}


void Serial_SendString(char* String)
{
	uint8_t i;
	for(i=0; String[i] != '\0'; i++)
	{
		Serial_SendByte(String[i]);
	}
}

uint32_t Result(uint32_t X, uint32_t Y)
{
	uint8_t result = 1;
	while(Y--)
	{
		result = result * X;
	}
	
	return result;
}

void Serial_SendNum(uint32_t Num, uint16_t Lenght)
{
	uint16_t i;
	uint32_t ww;
	for(i=Lenght; i>0; i--)
	{
		ww = Result(10,i-1);
		Serial_SendByte((Num/ww )% 10 + '0');
		
	}
	
}

	
int fputc(int ch, FILE* f)
{
	Serial_SendByte(ch);
	return ch;
}


void Serial_Printf(char* format, ...)
{
	char String[100];
	va_list arg;
	va_start(arg,format);
	vsprintf(String, format, arg);
	va_end(arg);
	Serial_SendString(String);
}

重定向C库函数printf()到串口,重定向后可使用printf();
//int fputc(int ch,FILE *f)
//{
//	USART_SendData(USART1,(uint8_t)ch);
//	while(!(USART_GetFlagStatus(USART1,USART_FLAG_TC)));
//	return ch;
//}


void USART_PollingReceive(void) {
    uint8_t received_data;
	Serial_Printf("Please enter the book command: ");
    while (1) {
        // 检查 RXNE 标志位,判断是否有数据可读
        if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET) {
            // 读取数据
            received_data = USART_ReceiveData(USART1);
			

            // 只有在接收到'3'时才处理接收的数据
            if (received_data == '3') {
                // 点亮LED
                GPIO_SetBits(GPIOA, GPIO_Pin_4);   // 点亮LED

                // 处理接收到的数据
                printf("Received: %c\n", received_data);
				

                // 等待一段时间,模拟LED点亮一段时间后熄灭(可选)
                Delay_ms(1000); // 延时1000ms,具体延时函数需要根据你的环境定义

                // 熄灭LED
                GPIO_ResetBits(GPIOA, GPIO_Pin_4); // 熄灭LED
            } else {
                // 如果接收到的不是'3',则继续等待
                printf("Invalid command received: %c\n", received_data);
            }
        }
    }
}


//USART中断入口函数


void USART1_IRQHandler(void)
{

	if(USART_GetITStatus(USART1, USART_IT_RXNE))
	{
		uint16_t ReceiveData = USART_ReceiveData(USART1);	
		USART_SendData(USART1,ReceiveData);
		while (USART_GetFlagStatus(USART1,USART_FLAG_RXNE));
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);
	}
}

结尾了我要总结一下:

串口(USART)通信是单片机中一种常用的通信方式,主要用于设备之间的数据交换。它的特点是通过串行数据传输,在硬件资源有限的情况下,能够高效地进行数据传输。

典型应用场景:

  1. 设备间通信

    • 常见场景:多个设备之间通过串口进行数据交换,比如在嵌入式系统中,多个传感器(温湿度传感器、光传感器等)通过串口将数据发送到主控单片机进行处理。
    • 实例:假设你在一个温度监测系统中,温度传感器通过串口向单片机发送温度数据,单片机接收到数据后进行处理,并根据温度值控制风扇的开关。
  2. 与计算机的通信

    • 常见场景:单片机通过串口与计算机进行通信,通常用于调试、数据传输和控制。
    • 实例:在开发过程中,单片机通过串口向计算机发送调试信息(例如温度、湿度数据或状态信息),开发者通过计算机监控这些数据。这种方式在嵌入式系统开发时非常常见。
  3. 调试与诊断

    • 常见场景:在开发嵌入式系统时,串口被广泛应用于调试信息的输出。通过串口输出数据或错误信息,帮助开发者进行调试。
    • 实例:开发过程中,单片机通过串口发送错误代码或状态信息,开发者通过串口终端查看这些信息,帮助调试程序。
  4. 无线通信模块

    • 常见场景:串口可以与无线模块(如蓝牙、Wi-Fi、Zigbee)配合使用,用于实现无线通信。
    • 实例:一个常见的应用是蓝牙模块(如HC-05),它通过串口与单片机连接,单片机通过串口接收来自手机的指令并进行相应操作。例如,用户通过手机上的蓝牙应用向单片机发送指令,控制家电(如开启灯光、调节温度等)。
  5. 外设控制

    • 常见场景:使用串口控制外部设备,如液晶显示屏、步进电机等。
    • 实例:在智能家居中,单片机通过串口控制一个LCD显示屏,显示实时温度、湿度等信息。用户通过串口发送命令,控制显示的内容。

详细示例:温湿度传感器通信

假设一个智能家居系统中有一个温湿度传感器(如DHT11),它通过串口(USART)与主控单片机(例如STM32)进行通信。工作流程如下:

  1. 发送数据:传感器通过串口发送温度和湿度数据。
  2. 接收数据:单片机接收传感器的数据,通过串口的接收缓冲区存储。
  3. 处理数据:单片机将接收到的数据进行解析,并根据预设的阈值执行相应操作,比如调节空调、打开加湿器或关闭风扇。
  4. 反馈:单片机还可以通过串口将处理后的数据(例如当前温度和湿度)发送回控制系统或计算机,便于远程监控。

总结:

串口通信在嵌入式系统中的应用非常广泛,不仅用于设备间的简单数据交换,还能支持各种外设的控制与调试。通过适当的配置和使用,串口通信可以实现有效的数据传输和设备控制。

例如:

场景描述:

在此应用中,我们假设使用一个温度传感器(例如DHT11或DHT22)通过串口(USART)将温度数据发送到单片机。单片机根据接收到的温度值来控制风扇的状态。如果温度高于预设的阈值,则风扇开启;如果温度低于阈值,则风扇关闭。

硬件连接:

  1. 温湿度传感器(DHT11/DHT22)通过串口(例如USART1)与STM32单片机连接。

  2. 风扇 (例如继电器控制的风扇)由STM32单片机的GPIO引脚控制。

    代码实现:

  3. 初始化串口通信:初始化STM32的USART,用于接收温度传感器的数据。

  4. 接收数据:通过串口接收温度数据。

  5. 处理数据:根据接收到的温度值控制风扇的开关。

  6. 风扇控制 :使用GPIO控制风扇。

    #include "stm32f10x.h"
    #include <stdio.h>
    
    #define FAN_PIN GPIO_Pin_0 // 假设风扇连接在GPIOA的Pin 0
    #define TEMP_THRESHOLD 30  // 设定的温度阈值,单位:摄氏度
    
    void USART_Init_Config(void);
    void GPIO_Init_Config(void);
    void USART_PollingReceive(void);
    void Fan_Control(uint8_t state);
    
    int main(void) {
        // 初始化串口和GPIO
        USART_Init_Config();
        GPIO_Init_Config();
    
        // 无限循环,定期检查接收到的数据
        while (1) {
            USART_PollingReceive();  // 等待并接收温度数据
        }
    }
    
    void USART_Init_Config(void) {
        // 初始化USART1
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
        
        GPIO_InitTypeDef GPIO_InitStructure;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;  // USART1_TX
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
        
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;  // USART1_RX
        GPIO_Init(GPIOA, &GPIO_InitStructure);
        
        USART_InitTypeDef USART_InitStructure;
        USART_InitStructure.USART_BaudRate = 9600;  // 波特率9600
        USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
        USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;  // 发送和接收模式
        USART_InitStructure.USART_Parity = USART_Parity_No;
        USART_InitStructure.USART_StopBits = USART_StopBits_1;
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;
        USART_Init(USART1, &USART_InitStructure);
        USART_Cmd(USART1, ENABLE);
    }
    
    void GPIO_Init_Config(void) {
        // 初始化风扇控制GPIO
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
        GPIO_InitTypeDef GPIO_InitStructure;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_InitStructure.GPIO_Pin = FAN_PIN;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
    }
    
    void USART_PollingReceive(void) {
        uint8_t received_data;
    
        // 检查RXNE标志位,判断是否有数据可读
        if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET) {
            // 读取接收到的数据
            received_data = USART_ReceiveData(USART1);
    
            // 打印接收到的数据
            printf("Received temperature: %c\n", received_data);
    
            // 判断温度数据,并控制风扇
            if (received_data >= TEMP_THRESHOLD) {
                Fan_Control(1);  // 温度超过阈值,开启风扇
            } else {
                Fan_Control(0);  // 温度低于阈值,关闭风扇
            }
        }
    }
    
    void Fan_Control(uint8_t state) {
        // 控制风扇的开关
        if (state == 1) {
            GPIO_SetBits(GPIOA, FAN_PIN);  // 开启风扇
        } else {
            GPIO_ResetBits(GPIOA, FAN_PIN);  // 关闭风扇
        }
    }
    

    代码解释:

  7. 串口初始化(USART_Init_Config)

    • 配置串口波特率为9600,启用接收和发送模式,并且没有硬件流控制。
    • 配置USART1的TX引脚(PA9)为推挽输出模式,RX引脚(PA10)为浮空输入模式。
  8. GPIO初始化(GPIO_Init_Config)

    • 配置风扇控制引脚(PA0)为推挽输出模式,用来控制风扇的开关。
  9. 串口接收数据(USART_PollingReceive)

    • 通过轮询方式检查串口接收标志(RXNE)。如果接收到数据,则读取数据并处理。
    • 假设温度传感器将数据以字符的形式发送(例如字符 '30' 表示30°C)。
    • 根据接收到的温度数据判断是否大于设定的阈值。如果温度超过阈值,调用 Fan_Control(1) 开启风扇,否则调用 Fan_Control(0) 关闭风扇。
  10. 风扇控制(Fan_Control)

    • 控制风扇的开关。如果参数 state 为1,开启风扇;如果为0,关闭风扇。

      总结:

      **该系统通过串口接收温度数据并根据数据控制风扇的开关,属于典型的串口通信应用场景。通过串口通信,单片机能够与外部温湿度传感器进行数据交换,根据接收到的实时数据做出响应,从而实现温控系统的自动化。

      下一节我们将进行数据包以及多字节的数据发送与接收**
      其中包括HEX数据包发送和文本格式数据包的发送与接收
      期待!!!!!!

相关推荐
鸿喵小仙女28 分钟前
C# WPF读写STM32/GD32单片机Flash数据
stm32·单片机·c#·wpf
lucy1530275107942 分钟前
MCU 功耗基准测试
科技·单片机·嵌入式硬件·智能家居·信号处理·工控主板
m0_748240911 小时前
OpenMV与STM32通信全面指南
stm32·单片机·嵌入式硬件
Cchengzu4 小时前
阿里巴巴2017实习生笔试题(二)
stm32·单片机·嵌入式硬件
重生之我是数学王子7 小时前
单片机 STM32入门
stm32·单片机·嵌入式硬件
qq_4597300311 小时前
4-3 MCU中ARM存储器的作用
arm开发·单片机·嵌入式硬件
嵌入式科普13 小时前
嵌入式科普(24)从SPI和CAN通信重新理解“全双工”
c语言·stm32·can·spi·全双工·ra6m5
重生之我是数学王子14 小时前
点亮核心板小灯 STM32U575
stm32·单片机·嵌入式硬件
end_SJ14 小时前
初学stm32 --- 定时器中断
stm32·单片机·嵌入式硬件
南城花随雪。14 小时前
单片机:实现数码管动态显示(0~99999999)74hc138驱动(附带源码)
单片机·嵌入式硬件