恃液 发表于 2025-6-4 19:05:59

基于STM32(Freertos)&ESP01S的红外空调网络控制器 -STM32软件部分

1.概述
本文主要介绍控制器软件部分,包含Freertos任务控制逻辑、Freertos系统初始化,STM32红外接收发射任务应用实现,加湿器模块控制实现、串口初始化。
2.主函数控制逻辑
在主函数中创建了4个任务,分别为:

[*]1.主任务管理器任务(Taskmgr)
[*]2.发送信息任务(SentMessage)
[*]3.空调控制任务(IR)
[*]4.加湿器控制任务(Humi)
控制系统流程图如下:

main.c 代码如下:
#include "stm32f10x.h"
#include "system.h"
#include "stdio.h"
/*APP Doc*/
#include "HDC1080.h"
#include "oled.h"
#include "IRLED.h"
#include "Humidifier.h"
#include "Led.h"
/*FreeRtos element*/
#define Start_Task_Prio 5//任务优先级,数值越大优先级越高
#define Start_Stk_Size 100//任务堆栈大小,单位Word,4字节
TaskHandle_t StartTask_Handler;
void Start_Task(void* pvParameters);//函数未定义,先声明

#define Taskmgr_Task_Prio 2//任务优先级,数值越大优先级越高
#define Taskmgr_Stk_Size 100//任务堆栈大小,单位Word,4字节
TaskHandle_t Taskmgr_Handler;
void Taskmgr_Task(void* pvParameters);//函数未定义,先声明

#define SentMessage_Task_Prio 4//任务优先级,数值越大优先级越高
#define SentMessage_Stk_Size 100//任务堆栈大小
TaskHandle_t SentMessageTask_Handler;
void SentMessage_Task(void* p_arg);//函数未定义,先声明

#define IR_Task_Prio 3//任务优先级,数值越大优先级越高
#define IR_Stk_Size 100//任务堆栈大小
TaskHandle_t IR_Task_Handler;
void IR_Task(void* p_arg);//函数未定义,先声明

#define Humi_Task_Prio 3//任务优先级,数值越大优先级越高
#define Humi_Stk_Size 100//任务堆栈大小
TaskHandle_t Humi_Task_Handler;
void Humi_Task(void* p_arg);//函数未定义,先声明

//#define debug_Task_Prio 3//任务优先级,数值越大优先级越高
//#define debug_Stk_Size 100//任务堆栈大小
//TaskHandle_t debug_Task_Handler;
//void debug_Task(void* p_arg);//函数未定义,先声明
//全局变量
extern volatile uint8_t ir_data;//供接收数据存储,未初始化接收时无用

SysData SYS_Glabal_varible={0,0,State_OFF,{0,Auto,26}};

int main(void)
{
SYSCLK_Config();
        delay_Init(ManualSetSYSCLK);
/*
//必须尽早创建任务,不然SCKtick进入中断调用xTaskIncrementTick后会造成野指针,
        //具体内容:https://blog.csdn.net/zhjmyx/article/details/120490993
        //创建任务
//创建开始任务,此任务在执行后被删除
*/       
        xTaskCreate((TaskFunction_t) Start_Task,//任务函数
                                                        (const char*)"Start_task",//任务名称
                                                  (uint16_t) Start_Stk_Size,//任务堆栈大小
                                                        (void*)NULL,          //传递给任务函数的参数
                                                        (UBaseType_t)Start_Task_Prio,//任务优先级
                                                        (TaskHandle_t*) &StartTask_Handler);
//通信初始化       
        USART1_Init(9600);
        USART3_Init(9600);
IIC_Init();
//App 初始化
        Ledflow();
        HDC_Init();
        IR_Init();//默认发射配置
        RH_GPIO_Init();
//        OLED_Init();
//OLED_ColorTurn(0);
//        OLED_DisplayTurn(0);

vTaskStartScheduler();//此函数对调用系统Systick初始化,覆盖掉前序配置
}

void Start_Task(void* pvParameters)
{
        taskENTER_CRITICAL();//进入临界区,在此区域的代码不会被打断
        //创建IIC通信相关任务,将IIC功能放在不同的任务中,会导致相互竞争IIC控制权
                                                       
       
                                                        xTaskCreate((TaskFunction_t) SentMessage_Task,//任务函数
                                                        (const char*)"HDC_task",//任务名称
                                                  (uint16_t) SentMessage_Stk_Size,//任务堆栈大小
                                                        (void*)NULL,          //传递给任务函数的参数
                                                        (UBaseType_t)SentMessage_Task_Prio,//任务优先级
                                                        (TaskHandle_t*) &SentMessageTask_Handler);
               
                                                        xTaskCreate((TaskFunction_t) Humi_Task,//任务函数
                                                        (const char*)"Humi_task",//任务名称
                                                  (uint16_t)Humi_Stk_Size,//任务堆栈大小
                                                        (void*)NULL,          //传递给任务函数的参数
                                                        (UBaseType_t)Humi_Task_Prio,//任务优先级
                                                        (TaskHandle_t*) &Humi_Task_Handler);
                                                       
                                                        xTaskCreate((TaskFunction_t) IR_Task,//任务函数
                                                        (const char*)"IR_task",//任务名称
                                                  (uint16_t)IR_Stk_Size,//任务堆栈大小
                                                        (void*)NULL,          //传递给任务函数的参数
                                                        (UBaseType_t)IR_Task_Prio,//任务优先级
                                                        (TaskHandle_t*) &IR_Task_Handler);
                                                       
                                                        xTaskCreate((TaskFunction_t) Taskmgr_Task,//任务函数
                                                        (const char*)"Taskmgr_Task",//任务名称
                                                  (uint16_t) Taskmgr_Stk_Size,//任务堆栈大小
                                                        (void*)NULL,          //传递给任务函数的参数
                                                        (UBaseType_t)Taskmgr_Task_Prio,//任务优先级
                                                        (TaskHandle_t*) &Taskmgr_Handler);

//                                                        xTaskCreate((TaskFunction_t) debug_Task,//任务函数
//                                                        (const char*)"debug_Task",//任务名称
//                                                  (uint16_t) debug_Stk_Size,//任务堆栈大小
//                                                        (void*)NULL,          //传递给任务函数的参数
//                                                        (UBaseType_t)debug_Task_Prio,//任务优先级
//                                                        (TaskHandle_t*) &debug_Task_Handler);
                                                       
                vTaskDelete(StartTask_Handler);       
taskEXIT_CRITICAL();                                                               
}
void Taskmgr_Task(void* p_arg)
{
u8 lastIR_Temp,lastIR_mode,last_humimode;
        u8 OFF_Sta;
        while(1)
        {
               
                if((lastIR_Temp!=USART3_RX_BUF)||(lastIR_mode!=USART3_RX_BUF))
                {
                        //IR_命令有变,执行命令
                        lastIR_Temp=USART3_RX_BUF;//更新最后一次的IR控制值
                lastIR_mode=USART3_RX_BUF;
                        OFF_Sta=0;//其他途径开机
                        xTaskNotifyGive(IR_Task_Handler);
                }
                if(last_humimode!=USART3_RX_BUF)
                {                       
                last_humimode=USART3_RX_BUF;
                        xTaskNotifyGive(Humi_Task_Handler);
                }
                if(((USART3_RX_BUF&0x0F)==0x0F)&&OFF_Sta==0)//低四位变F时关机
                {
                          USART3_RX_BUF|=0xF0;//低四位清零
                          OFF_Sta=1;
                          Normal_Code(0xB2,0x7B,0xE0);//关机
                }
                else if((USART3_RX_BUF==0x00)&&(OFF_Sta==1))
    {
                        //否则为开机,执行上一次的空调控制参数
                        xTaskNotifyGive(IR_Task_Handler);
                        OFF_Sta=0;
                }
               
        }
}
void SentMessage_Task(void* pvParameters)//温湿度读取任务
{
      float temp,humid;
          u32 NotifyVaule;
                  while(1)
            {
                        NotifyVaule=ulTaskNotifyTake(pdTRUE,portMAX_DELAY);
                                if(NotifyVaule==1)
                                {
                       
                        //获取传感器数据
                        Get_HDC1080_THValue(&temp,&humid);
                        SYS_Glabal_varible.curtemp=temp;
                        SYS_Glabal_varible.curhumid=humid;
                        //0.发送0xB3
            USART_SendData(USART3,0xB3);
                        delay_ms(100);//延时必须,ESP端使用状态机接收,太快了处理不过来
            //1.发送空调温度       
            USART_SendData(USART3,SYS_Glabal_varible.IR_Sent_Data.temp);
                        delay_ms(100);
                  //2.发送空调模式
                  USART_SendData(USART3,SYS_Glabal_varible.IR_Sent_Data.mode);
                        delay_ms(100);
                  //3.发送加湿器模式
                  USART_SendData(USART3,SYS_Glabal_varible.RH_Sta);
                        delay_ms(100);
                     //4-7.发送温度数据
                  send_float_via_uart(USART3,temp);               
                     //8-11.发送湿度数据
                  send_float_via_uart(USART3,humid);
                        delay_ms(100);
                                }
          }               
}
void IR_Task(void* p_arg)
{
        u32 NotifyVaule;
        while(1)
        {
                NotifyVaule=ulTaskNotifyTake(pdTRUE,portMAX_DELAY);
      GPIO_SetBits(GPIOA, GPIO_Pin_5);               
      if(NotifyVaule==1)
                {
                ConducterControl((ConducterMode)USART3_RX_BUF ,USART3_RX_BUF);//第五byte空调温度,第六byte空调模式
                xTaskNotifyGive(SentMessageTask_Handler);
                }
               
        }
}
void Humi_Task(void* p_arg)
{
u32 NotifyVaule;
        while(1)
        {
               NotifyVaule=ulTaskNotifyTake(pdTRUE,portMAX_DELAY);
               if(NotifyVaule==1)
               {                       
               RH_Control((RH_State)USART3_RX_BUF);
               xTaskNotifyGive(SentMessageTask_Handler);
               }
        }
}
void debug_Task(void* p_arg)
{
        while(1)
        {
          delay_ms(1000);
          Decode_IRDta();
          printf(" A=%#X,NA=%#X", ir_data,ir_data);
          printf(" B=%#X,NB=%#X", ir_data,ir_data);
          printf(" C=%#X,NC=%#X", ir_data,ir_data);
        }
}3.Freertos 初始化
3.1Freertos 配置
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H

/*-----------------------------------------------------------
* Application specific definitions.
*
* These definitions should be adjusted for your particular hardware and
* application requirements.
*
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
*
* See http://www.freertos.org/a00110.html
*----------------------------------------------------------*/

#define configUSE_PREEMPTION                1//设置抢占式调度器
#define configUSE_IDLE_HOOK                        0//设置空闲任务钩子
#define configUSE_TIME_SLICING0//设置相同优先级任务被轮转执行
#define configUSE_TICK_HOOK                        0//设置时间片钩子
#define configUSE_TASK_NOTIFICATIONS 1
#define configUSE_MUTEXES 1

#define configPRIO_BITS    4
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY   0x0F //四位,值越小优先级越高

#define configCPU_CLOCK_HZ                        ( ( unsigned long ) 72000000 )        //CPU执行频率
#define configTICK_RATE_HZ                        ( ( TickType_t ) 1000 )//节拍中断频率,每次中断会进行任务调度
#define configMAX_PRIORITIES                ( 5 )//设置优先级范围:0·X-1数字越小优先级越低
#define configMINIMAL_STACK_SIZE        ( ( unsigned short ) 256 )//定义空闲任务使用的堆栈的大小
#define configTOTAL_HEAP_SIZE                ( ( size_t ) ( 10 * 1024 ) )//
#define configMAX_TASK_NAME_LEN                ( 16 )//定义任务名的长度限制
#define configUSE_TRACE_FACILITY        0//启动可视化跟踪调试
#define configUSE_16_BIT_TICKS                0
#define configIDLE_SHOULD_YIELD                1

/* Co-routine definitions. */
#define configUSE_CO_ROUTINES                 0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )

/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */

#define INCLUDE_vTaskPrioritySet                1
#define INCLUDE_uxTaskPriorityGet                1
#define INCLUDE_vTaskDelete                                1
#define INCLUDE_vTaskCleanUpResources        0
#define INCLUDE_vTaskSuspend                        1
#define INCLUDE_vTaskDelayUntil                        1
#define INCLUDE_vTaskDelay                                1

/* This is the raw value as per the Cortex-M3 NVIC.Values can be 255
(lowest) to 0 (1?) (highest). */
//#define configKERNEL_INTERRUPT_PRIORITY                 255 //在port.c 中L37定义
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY         191 /* equivalent to 0xb0, or priority 11. */

#define xPortPendSVHandler   PendSV_Handler
#define xPortSysTickHandlerSysTick_Handler
#define vPortSVCHandler      SVC_Handler



/* This is the value being used as per the ST library which permits 16
priority values, 0 to 15.This must correspond to the
configKERNEL_INTERRUPT_PRIORITY setting.Here 15 corresponds to the lowest
NVIC value of 255. */
//#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY        15                //数字越小优先级越高,这里高于"最低优先级15"都不可管理
//即只可管理最低15优先级,其他都管不了,不合理我要改
#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY          5                //数字越小优先级越高,这里高于5都不可管理,即数字小于5的都管不了
#endif /* FREERTOS_CONFIG_H */3.2 系统初始化
此处是System.h的代码,主要定义全局变量及I2C的引脚宏定义
#ifndef __system_H
#define __system_H
/*System Head doc*/
#include "stm32f10x.h"                  // Device header
#include "delay.h"
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include "usart.h"
#include "iic.h"

/*FreeRtos lib*/
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
typedef enum
{
                State_OFF,
                State_Low,
                State_High,
}RH_State;
typedef enum {Auto,cold,DeHumi,Heat,SentWind}ConducterMode;
//RH_State RH_app_Sta = State_OFF;
typedef struct IR_S
{
        u8 IR_Sent_Data;//依次A B C,A固定0xB2,B的高3位控制风速,低5五位保留1,
          //高3位101为自动风,本程序风速默认自动风
        ConducterMode mode;
        u8 temp;
}IR_Sdate;
typedef struct SystemData
{
           float curtemp;
           float curhumid;
           RH_State RH_Sta;
           IR_Sdate IR_Sent_Data;
}SysData;


extern SysData SYS_Glabal_varible;
extern IR_Sdate IR_SentData;

#define SYSTEM_SUPPPORT_RTOS 1//FRTOS开关标准位

/*IIC_SCL时钟端口、引脚定义 */
#define IIC_SCL_PORT                         GPIOB   
#define IIC_SCL_PIN                         (GPIO_Pin_8)
#define IIC_SCL_PORT_RCC                RCC_APB2Periph_GPIOB

/*IIC_SDA时钟端口、引脚定义 */
#define IIC_SDA_PORT                         GPIOB
#define IIC_SDA_PIN                         (GPIO_Pin_9)
#define IIC_SDA_PORT_RCC                RCC_APB2Periph_GPIOB

#define ManualSetSYSCLK                72

//#define IIC_SCL *((volatile unsigned long*)(0x42000000+((GPIOB_BASE+12)-0x40000000)*32+8*4))//写PB8
//#define IIC_SDA *((volatile unsigned long*)(0x42000000+((GPIOB_BASE+12)-0x40000000)*32+9*4))//写PB9
//#define PB10 *((volatile unsigned long*)(0x42000000+((GPIOB_BASE+12)-0x40000000)*32+10*4))//写PB10
//#define READ_SDA*((volatile unsigned long*)(0x42000000+((GPIOB_BASE+8)-0x40000000)*32+9*4))//读PB9
//unsigned short int returntimeline(void);
void SYSCLK_Config(void);
#endif 系统时钟及中断组选择
/*
功能:系统初始配置
参数:无
说明:系统在执行main之前会执行SystemInit,其中包含时钟的初始化,但确保初始化成功,此处手动进行时钟及中断组选择
*/
void SYSCLK_Config(void)
{
        RCC_DeInit();
        RCC_HSEConfig(RCC_HSE_ON);
        if (RCC_WaitForHSEStartUp() == SUCCESS)
    {
      // 关闭HSI(可选)
      RCC_HSICmd(DISABLE);
      
      // 配置PLL:HSE分频1(不分频)后作为PLL输入,倍频9倍
      // 注意:根据具体型号选择分频系数,此处为STM32F1系列典型配置
      RCC_PLLConfig(RCC_PLLSource_HSE_Div2, RCC_PLLMul_9);
      
      // 启动PLL并等待就绪
      RCC_PLLCmd(ENABLE);
      while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
      
      // 切换系统时钟到PLL输出
      RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
      
      // 验证时钟切换是否成功
      while(RCC_GetSYSCLKSource() != 0x08);
      
      // 配置总线分频(关键修改点)
      RCC_HCLKConfig(RCC_SYSCLK_Div1);    // AHB 72MHz
      RCC_PCLK1Config(RCC_HCLK_Div2);   // APB1 36MHz(不超过官方限制)
      RCC_PCLK2Config(RCC_HCLK_Div1);   // APB2 72MHz
                               
                                vPortRaiseBASEPRI();//开启Freertos的中断管理
                                NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
                               
    }
}3.3 系统delay及滴答定时器初始化
#include "delay.h"
u8 fac_us,fac_ms;

/*******************************************************************************
* 函数名      : delay_Init
* 功能                  : 对系统滴答定时器初始化
* 参数      : SYSCLK,已设置的系统时钟频率如:72,其已在启动文件中设置
* 返回值      : 无
* 描述      : 无
*******************************************************************************/
void delay_Init(u8 SYSCLK)
{
        u32 reload;
        SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);//设置为HCLK不分频,本机在stm32f10x_system.c文件中定义了36MHZ系统时钟频率
        fac_us=SYSCLK;//每微秒需要计的数量,nMHZ执计n次为微秒
        reload=SYSCLK;
        reload=(reload*1000000/configTICK_RATE_HZ);
        //先乘以1000000恢复Mhz,再除以OS工作频率,得到计数次数,
        //按此重装值计数的中断可得到想要的OS工作频率
        fac_ms=1000/configTICK_RATE_HZ;//t=1/f(秒)
        //系统频率下的最小单位时间,乘以1000因为要的是毫秒
        SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;//开启SYSTICK中断
        SysTick->LOAD=reload;//每1/configTICK_RATE_HZ秒中断一次
        SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk;//开启SYSTICK
}
/*******************************************************************************
* 函数名      : delay_us
* 功能                  : 延时nus
* 参数      : nus,要延时的微秒数
* 返回值      : 无
* 描述      : 因为OS的工作频率设定为1000,最小时间单位1ms,
                无法在使用OS框架内延时us级时间
*******************************************************************************/
void delay_us(uint32_t nus)
{
        u32 ticks;
        u32 told ,tnow,tcnt=0;
        u32 reload=SysTick->LOAD;//读取当前重装LOAD值
        ticks=(nus*fac_us);//需要的节拍数
        told=SysTick->VAL;//进入时的计数器值
        while(1)
        {
                tnow=SysTick->VAL;//读取当前值
                if(tnow!=told)//除非单片机卡死了,old值和now值没变化,那就卡死在while里等待恢复
                {
                        if(tnow<told)
                        {
                                tcnt+=told-tnow;//记录两次间隔的计数数量并累加
                        }
                        else//为特殊情况now值到0重装后突变的增加的重装值做修正
                        {
                                tcnt+=(told-(tnow-reload));
                        }
                        told = tnow;//更新Old值
                        if(tcnt>=ticks)
                                break;//时间等于或超过要延时的时间,退出while
                }
        }
}
/*******************************************************************************
* 函数名      : delay_ms
* 功能                  : 延时nms
* 参数      : nms,要延时的毫秒数
* 返回值      : 无
* 描述      : 会引起任务调度
*******************************************************************************/
void delay_ms(uint32_t nms)
{
//        if(1/*xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED*/)
                if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)
        {
                if(nms>=fac_ms)
                {
                        vTaskDelay(nms/fac_ms);//整数倍的毫秒使用任务调度延时
                }
                nms%=fac_ms;               
        }
        delay_us((u32)(nms*1000));//余下部分化成微秒用普通微秒延时
}
/*******************************************************************************
* 函数名      : delay_ms
* 功能                  : 延时nms
* 参数      : nms,要延时的毫秒数
* 返回值      : 无
* 描述      : 不会引起任务调度
*******************************************************************************/
void delay_xms(uint32_t nms)
{
        u32 i;
        for(i=0;i<nms;i++)
        delay_us(1000);
}
void Clock_Test(uint32_t ticks)
{

        u32 told ,tnow,tcnt=0;
        u32 reload=SysTick->LOAD;//读取当前重装LOAD值
//        ticks=(nus*fac_us);//需要的节拍数
        told=SysTick->VAL;//进入时的计数器值
        while(1)
        {
                tnow=SysTick->VAL;//读取当前值
                if(tnow!=told)//除非单片机卡死了,old值和now值没变化,那就卡死在while里等待恢复
                {
                        if(tnow<told)
                        {
                                tcnt+=told-tnow;//记录两次间隔的计数数量并累加
                        }
                        else//为特殊情况now值到0重装后突变的增加的重装值做修正
                        {
                                tcnt+=(told-(tnow-reload));
                        }
                        told=tnow;
                        if(tcnt>=ticks)
                                break;//时间等于或超过要延时的时间,退出while
                }
        }
}4.红外控制
4.1 红外发射接收APP 预设参数
以下代码主要包含红外接收,各信号的时间长度宏定义,发送相关红外协议命令宏定义
#ifndef __IRLED_H
#define __IRLED_H
#include "stm32f10x.h"                  // Device header
#include "delay.h"
#include "system.h"

/* 红外接收相关定义 */
#define IR_TIMER               TIM3
#define IR_TIMER_CHANNEL       TIM_Channel_1
#define IR_GPIO_PORT         GPIOB
#define IR_GPIO_PIN            GPIO_Pin_4
#define IR_CLOCK_FREQ          36000000// 系统时钟72MHz,此处我设置位36MHZ,红外接收的定时计数器每计一个数位为0.5微妙
#define IR_Lead_MAX            18500
#define IR_Lead_MIN            15000
#define IR_DATA_1_MAX          4500
#define IR_DATA_1_MIN          4100
#define IR_DATA_0_MAX          2300
#define IR_DATA_0_MIN          2000
#define SEPARATION_MAX         13000
#define SEPARATION_MIN         10000
//空调相关控制参数,R05D协议
#define IR_A_Data                   0xB2
#define IR_B_Windspeed_Auto         0xBF
#define IR_B_Windspeed_Low          0x9F
#define IR_B_Windspeed_Mid                       0x5F
#define IR_B_Windspeed_High                      0x3F
#define IR_B_OFF                  0x7B
//工作模式只低占3-4位,高4位的温度区域先保留为0
#define IR_C_OperationMode_Auto                        0x08
#define IR_C_OperationMode_cold                        0x00
#define IR_C_OperationMode_DeHumi                0x04
#define IR_C_OperationMode_Heat                  0x0C
#define IR_C_OperationMode_SentWind        0x04 //送风模式没有温度代码
//温度控制参数,低4位都保留为0
#define IR_C_temp_17                                        0x00
#define IR_C_temp_18                                        0x10
#define IR_C_temp_19                                        0x30
#define IR_C_temp_20                                        0x20
#define IR_C_temp_21                                        0x60
#define IR_C_temp_22                                        0x70
#define IR_C_temp_23                                        0x50
#define IR_C_temp_24                                        0x40
#define IR_C_temp_25                                        0xC0
#define IR_C_temp_26                                        0xD0
#define IR_C_temp_27                                        0x90
#define IR_C_temp_28                                        0x80
#define IR_C_temp_29                                        0xA0
#define IR_C_temp_30                                        0xB0
#define IR_C_temp_Nop                                        0xE0
#define IR_C_OFF            0xE0
/* 时间数据buffer */

extern u16 IR_Buffer_Row;
void IR_TIM_Init(void);
u8 decode_A(u16* rowdata);
u8 decode_NA(u16* rowdata);
u8 decode_B(u16* rowdata);
u8 decode_NB(u16* rowdata);
u8 decode_C(u16* rowdata);
u8 decode_NC(u16* rowdata);
u8 Decode_IRDta(void);
u8Lead_cheak(u16* rowdata);
u8 Separation_cheak(u16* rowdata);

       

void IR_Init(void);
void IR_TIM3_PWM_Init(void) ;
void IRLED_GPIO_Init(void);
void Normal_Code(u8 A, u8 B, u8 C);
void TIM3_SETLOW(void);
void TIM3_SETHIG(void);
void Lead_Code(void);
void Stop_Code(void);
void Send_0_Code(void);
void Send_1_Code(void);
void Send_Byte(u8 data);
u8 ConducterControl(ConducterMode mode ,u8 temp);
//   Normal_Code(0xB2, 0x9F, 0x00);//开机 17度
#endif4.2 红外初始化函数
/*
功能:对红外发射接收功能进行初始
参数:无
说明:不可同时启用发射接收初始化,因为他们都使用TIM3定时器
*/
void IR_Init(void)
        {
      IR_TIM3_PWM_Init();//红外发射功能PWM初始化
          //IR_TIM_Init();//红外接收功能初始化
   }4.3 红外发射控制。
通过初始化TIM3以38KHZ输出PWM信号,实现38khz载波,通过改变比较值,控制输出的是38Khz的PWM信号,还是低电平,以此实现发送高或发送低
实现代码如下,部分代码参考了:https://blog.csdn.net/weixin_42204837/article/details/109263771
/*
功能:PWM初始
参数:无
*/
void IR_TIM3_PWM_Init(void)
        {
    // 使能GPIOA和TIM3时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

    // 配置PA6为复用推挽输出(用于Q2栅极)
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 配置TIM3
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_TimeBaseStructure.TIM_Period = 1894; // 38kHz PWM (72MHz / (947 + 1) = 38kHz)
    TIM_TimeBaseStructure.TIM_Prescaler = 0;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

    // 配置TIM3通道1为PWM模式
    TIM_OCInitTypeDef TIM_OCInitStructure;
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 947; // 947 50%占空比
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OC1Init(TIM3, &TIM_OCInitStructure);
    // 启动TIM3
    TIM_Cmd(TIM3, ENABLE);
}
/*
功能:红外不输出,接收器拉高,发送低
参数:无
*/
void         TIM3_SETLOW(void)
{
   TIM3->CCR1 = 0;
//TIM_SetCompare1(TIM3,0);
}
/*
功能:红外输出,接收器拉低,发送高
参数:无
*/
void         TIM3_SETHIG()
{

    TIM3->CCR1 = 947;
//                TIM_SetCompare1(TIM3,947);
}
/*
功能:发送美的红外控制引导码
参数:无
*/
void Lead_Code(void)
{
        TIM3_SETHIG(); //接收器拉低,对发送就是高
        delay_us(4400);
        TIM3_SETLOW(); //接收器拉高,对发送就是低
        delay_us(4400);
}
/*
功能:发送美的红外控制停止码
参数:无
*/
void Stop_Code(void)
{
        TIM3_SETHIG(); //接收器拉低
        delay_us(540);
        TIM3_SETLOW(); //接收器拉高
        delay_us(5220);
}
/*
功能:发送美的红外 bit 0
参数:无
*/
void Send_0_Code(void)
{
        TIM3_SETHIG(); //接收器拉低
        delay_us(540);
        TIM3_SETLOW(); //接收器拉高
        delay_us(540);
}
/*
功能:发送美的红外 bit 1
参数:无
*/
void Send_1_Code(void)
{
        TIM3_SETHIG(); //接收器拉低
        delay_us(540);
        TIM3_SETLOW(); //接收器拉高
        delay_us(1620);
}
/*
功能:发送美的红外8位byte
参数:无
*/
void Send_Byte(u8 data)
{
        int i;
        for(i=7;i>=0;i--)
        {
                if(data & (1<<i))
                {
                        Send_1_Code();
                }
                else
                {
                        Send_0_Code();
                }
        }
}
/*
功能:发送美的红外控制的一条完整信号
参数:无
*/
void Normal_Code(u8 A, u8 B, u8 C)
{
        Lead_Code();
        Send_Byte(A);
        Send_Byte(~A);
        Send_Byte(B);
        Send_Byte(~B);
        Send_Byte(C);
        Send_Byte(~C);
        Stop_Code();
        Lead_Code();
        Send_Byte(A);
        Send_Byte(~A);
        Send_Byte(B);
        Send_Byte(~B);
        Send_Byte(C);
        Send_Byte(~C);
        Stop_Code();
}
/*
功能:控制红外发射完成相应模式温度的信号发送
参数:mode 枚举变量,通过switch对模式进行选择
   temp 通过switch对温度进行选择
*/
u8 ConducterControl(ConducterMode mode ,u8 temp)
{
        u8 C_Data,ModeData,TempData;
        switch(mode)
{
                case Auto   :ModeData=IR_C_OperationMode_Auto;break;
                case cold   :ModeData=IR_C_OperationMode_cold;break;
                case DeHumi   :ModeData=IR_C_OperationMode_DeHumi;break;
                case Heat   :ModeData=IR_C_OperationMode_Heat;break;
                case SentWind :ModeData=IR_C_OperationMode_SentWind;break;
                default: return 0;
        }
        switch(temp)
        {
                case 17 : TempData=IR_C_temp_17;break;
                case 18 : TempData=IR_C_temp_18;break;
                case 19 : TempData=IR_C_temp_19;break;
                case 20 : TempData=IR_C_temp_20;break;
                case 21 : TempData=IR_C_temp_21;break;
                case 22 : TempData=IR_C_temp_22;break;
                case 23 : TempData=IR_C_temp_23;break;
                case 24 : TempData=IR_C_temp_24;break;
                case 25 : TempData=IR_C_temp_25;break;
                case 26 : TempData=IR_C_temp_26;break;
                case 27 : TempData=IR_C_temp_27;break;
                case 28 : TempData=IR_C_temp_28;break;
                case 29 : TempData=IR_C_temp_29;break;
                case 30 : TempData=IR_C_temp_30;break;
                default : TempData=IR_C_temp_Nop;break;
        }
        C_Data=(ModeData&0x0C)|(TempData&0xF0);
        SYS_Glabal_varible.IR_Sent_Data.IR_Sent_Data=0xB2;
        SYS_Glabal_varible.IR_Sent_Data.IR_Sent_Data=IR_B_Windspeed_Auto;
        SYS_Glabal_varible.IR_Sent_Data.IR_Sent_Data=C_Data;
        SYS_Glabal_varible.IR_Sent_Data.temp=temp;
        SYS_Glabal_varible.IR_Sent_Data.mode=mode;
        Normal_Code(0xB2,IR_B_Windspeed_Auto,C_Data);
        return 1;
}5 加湿器模块
加湿器模块通过开关按键实现控制,按一下切换模式,模式有 “关”、“低”、“高” 三种模式
通过延时置位复位IO达到模拟按键的作用。
代码实现如下
/*
功能:接收捕获的定时器配置
参数:无
*/
void IR_TIM_Init(void) {
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_ICInitTypeDef TIM_ICInitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;

    /* 开启时钟 */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
        /* 开启AFIO时钟(关键!)*/
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
        /* 配置PB4复用为TIM3_CH1 */
    GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);// 部分重映射:TIM3_CH1->PB4

    /* 配置GPIO */
    GPIO_InitStructure.GPIO_Pin = IR_GPIO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
    GPIO_Init(IR_GPIO_PORT, &GPIO_InitStructure);

    /* 定时器基础配置 */
        //APB1总线上的定时器时钟确实有一个倍频机制。当APB1的预分频系数设置为1以外的值时(即分频系数为2、4、8或16),定时器的时钟频率会是APB1频率的两倍
    TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
    TIM_TimeBaseStructure.TIM_Prescaler = (IR_CLOCK_FREQ/1000000) - 1; // 0.5us计数
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(IR_TIMER, &TIM_TimeBaseStructure);

    /* 输入捕获配置 */
    TIM_ICInitStructure.TIM_Channel = IR_TIMER_CHANNEL;
    TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling; // 双沿触发
    TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
    TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    TIM_ICInitStructure.TIM_ICFilter = 0x08; // 适当滤波
    TIM_ICInit(IR_TIMER, &TIM_ICInitStructure);

    /* 中断配置 */
    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 4;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    TIM_ClearITPendingBit(IR_TIMER, TIM_IT_CC1 | TIM_IT_Update);
    TIM_ITConfig(IR_TIMER, TIM_IT_CC1 | TIM_IT_Update, ENABLE);
    TIM_Cmd(IR_TIMER, ENABLE);
}
/* 中断服务函数 */
void TIM3_IRQHandler(void)
        {
//                u16 num;
    if(TIM_GetITStatus(IR_TIMER, TIM_IT_Update) != RESET)
    {
      TIM_ClearITPendingBit(IR_TIMER, TIM_IT_Update);
                          TIM_SetCounter(IR_TIMER,0);
    }

   
    if(TIM_GetITStatus(IR_TIMER, TIM_IT_CC1) != RESET)
    {
      if(enter_flag_verify)
      {
      
      if(~GPIO_ReadInputDataBit(IR_GPIO_PORT, IR_GPIO_PIN))
                          {
                                          IR_Buffer_Row=TIM_GetCapture1(IR_TIMER);
                                          Buffer_index++;
                                          if(Buffer_index==99)
                                                        {
                                                                Buffer_index=0;
                                                          enter_flag_verify=0;
                                                        }
      }
                                                        TIM_SetCounter(IR_TIMER,0);
      }
      else
                                {               
            enter_flag_verify=1;
            TIM_SetCounter(IR_TIMER,0);                               
                                }
      TIM_ClearITPendingBit(IR_TIMER, TIM_IT_CC1);
    }
          }
u8Lead_cheak(u16* rowdata)
{
if(rowdata>IR_Lead_MIN&&rowdata<IR_Lead_MAX)
{
    frame_num=1;
    return 1;
}
else
      return 0;
       
}
u8 Separation_cheak(u16* rowdata)
{
if(rowdata>SEPARATION_MIN&&rowdata<SEPARATION_MAX)
{
    frame_num=2;
    return 1;
}
else
    return 0;
       
}

u8 decode_A(u16* rowdata)
{          
    u8 i=0;
          if(frame_num==1)//解码第一帧
                {
       for(i=0;i<8;i++)
      {
//      printf("%d\n",rowdata);
      if(rowdata>IR_DATA_1_MIN&&rowdata<IR_DATA_1_MAX)
          ir_data|=(0x80>>i);
      else if (rowdata<IR_DATA_0_MAX&&rowdata>IR_DATA_0_MIN)
          ir_data&=~(0x80>>i);
      }
                }else if(frame_num==2)//解码第二帧
                {
                       for(i=0;i<8;i++)
      {
//      printf("%d\n",rowdata);
      if(rowdata>IR_DATA_1_MIN&&rowdata<IR_DATA_1_MAX)
          ir_data|=(0x80>>i);
      else if (rowdata<IR_DATA_0_MAX&&rowdata>IR_DATA_0_MIN)
          ir_data&=~(0x80>>i);
      }
                }
    return ir_data;   
}
u8 decode_NA(u16* rowdata)
{
    u8 i=0;
          if(frame_num==1)
                {
    for(i=0;i<8;i++)
    {
                //printf("%d\n",rowdata);
      if(rowdata>IR_DATA_1_MIN&&rowdata<IR_DATA_1_MAX)
          ir_data|=(0x80>>i);
          else if (rowdata<IR_DATA_0_MAX&&rowdata>IR_DATA_0_MIN)
          ir_data&=~(0x80>>i);
    }
          }
                else if(frame_num==2)
                {
                       for(i=0;i<8;i++)
      {
//      printf("%d\n",rowdata);
      if(rowdata>IR_DATA_1_MIN&&rowdata<IR_DATA_1_MAX)
          ir_data|=(0x80>>i);
      else if (rowdata<IR_DATA_0_MAX&&rowdata>IR_DATA_0_MIN)
          ir_data&=~(0x80>>i);
      }
                }
    return ir_data;   
}
u8 decode_B(u16* rowdata)
{
    u8 i=0;
          if(frame_num==1)
                {
    for(i=0;i<8;i++)
    {
                //printf("%d\n",rowdata);
      if(rowdata>IR_DATA_1_MIN&&rowdata<IR_DATA_1_MAX)
          ir_data|=(0x80>>i);
          else if (rowdata<IR_DATA_0_MAX&&rowdata>IR_DATA_0_MIN)
          ir_data&=~(0x80>>i);
    }
          }else if(frame_num==2)
                {
                for(i=0;i<8;i++)
      {
//      printf("%d\n",rowdata);
      if(rowdata>IR_DATA_1_MIN&&rowdata<IR_DATA_1_MAX)
          ir_data|=(0x80>>i);
      else if (rowdata<IR_DATA_0_MAX&&rowdata>IR_DATA_0_MIN)
          ir_data&=~(0x80>>i);
      }
                }
               
    return ir_data;   
}
u8 decode_NB(u16* rowdata)
{
          
    u8 i=0;
        if(frame_num==1)
        {
    for(i=0;i<8;i++)
    {
                //printf("%d\n",rowdata);
      if(rowdata>IR_DATA_1_MIN&&rowdata<IR_DATA_1_MAX)
          ir_data|=(0x80>>i);
          else if (rowdata<IR_DATA_0_MAX&&rowdata>IR_DATA_0_MIN)
          ir_data&=~(0x80>>i);
    }
        }else if(frame_num==2)
        {
                for(i=0;i<8;i++)
      {
//      printf("%d\n",rowdata);
      if(rowdata>IR_DATA_1_MIN&&rowdata<IR_DATA_1_MAX)
          ir_data|=(0x80>>i);
      else if (rowdata<IR_DATA_0_MAX&&rowdata>IR_DATA_0_MIN)
          ir_data&=~(0x80>>i);
      }
        }
    return ir_data;   
}
u8 decode_C(u16* rowdata)
{
          
    u8 i=0;
          if(frame_num==1)
                {
    for(i=0;i<8;i++)
    {
                //printf("%d\n",rowdata);
      if(rowdata>IR_DATA_1_MIN&&rowdata<IR_DATA_1_MAX)
          ir_data|=(0x80>>i);
          else if (rowdata<IR_DATA_0_MAX&&rowdata>IR_DATA_0_MIN)
          ir_data&=~(0x80>>i);
    }
          }else if(frame_num==2)
                {
          for(i=0;i<8;i++)
      {
//      printf("%d\n",rowdata);
      if(rowdata>IR_DATA_1_MIN&&rowdata<IR_DATA_1_MAX)
          ir_data|=(0x80>>i);
      else if (rowdata<IR_DATA_0_MAX&&rowdata>IR_DATA_0_MIN)
          ir_data&=~(0x80>>i);
      }
                }
    return ir_data;   
}
u8 decode_NC(u16* rowdata)
{
    u8 i=0;
        if(frame_num==1)
        {
    for(i=0;i<8;i++)
    {
                //printf("%d\n",rowdata);
      if(rowdata>IR_DATA_1_MIN&&rowdata<IR_DATA_1_MAX)
          ir_data|=(0x80>>i);
          else if (rowdata<IR_DATA_0_MAX&&rowdata>IR_DATA_0_MIN)
          ir_data&=~(0x80>>i);
    }
        }else if(frame_num==2)
        {
                for(i=0;i<8;i++)
      {
//      printf("%d\n",rowdata);
      if(rowdata>IR_DATA_1_MIN&&rowdata<IR_DATA_1_MAX)
          ir_data|=(0x80>>i);
      else if (rowdata<IR_DATA_0_MAX&&rowdata>IR_DATA_0_MIN)
          ir_data&=~(0x80>>i);
      }
        }
    return ir_data;   
}
/*
功能:对接收到的原始数据进行解码
输入:IR_Buffer_Row 原始数据数组首地址
输出:ir_data,x=0->A,x=1->NA,x=2->B,x=3->NB,x=4->C,x=5->NC,
*/
u8 Decode_IRDta(void)
{
        if(Lead_cheak(IR_Buffer_Row))//对第一帧Lead检查
        {

                if((decode_A(IR_Buffer_Row)==(u8)~decode_NA(IR_Buffer_Row))&&
                       (decode_B(IR_Buffer_Row)==(u8)~decode_NB(IR_Buffer_Row))&&
                   (decode_C(IR_Buffer_Row)==(u8)~decode_NC(IR_Buffer_Row)))//对第一帧数据进行解码并反码校验
                {
                          frame_num=0;
                          return 1;
                }
                else{
                          if(Separation_cheak(IR_Buffer_Row))//第一帧检查失败,进行间隔码检查
                      {
                             if((decode_A(IR_Buffer_Row)==(u8)~decode_NA(IR_Buffer_Row))&&
                                (decode_B(IR_Buffer_Row)==(u8)~decode_NB(IR_Buffer_Row))&&
                            (decode_C(IR_Buffer_Row)==(u8)~decode_NC(IR_Buffer_Row)))//间隔码检查通过对第二帧数据进行解码并反码晓校验
                                   //第二帧解码前没有对第二帧的Lead码进行验证,但我觉得没有必要,那我就不验证哒
                                {
                                                                        frame_num=0;
                                    return 2;
                                }else
                                    {//第二帧反码也校验识别,没得玩了
                                                                                frame_num=0;
                                      return 3;
                                    }
                      }
                      else
                          return 4;//间隔码检测失败
                                }
        }
        else
        {
                frame_num=0;
                return 5;
        }
}6.串口初始化
头文件代码,主要完成串口的存储缓冲区定义
#include "Humidifier.h"
#include "stdio.h"
/*
功能:加湿器使用IO初始化
参数:无
*/
void RH_GPIO_Init(void)
{
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
        GPIO_InitTypeDef GPIO_InitStruct;
        GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
        GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;
        GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOB,&GPIO_InitStruct);
        GPIO_ResetBits(GPIOB, GPIO_Pin_5);
}
/*
功能:加湿器按键模拟
参数:num
说明:num表示按几次按键
*/
void PressKey(u8 num)
{
        while(num--)
        {
                GPIO_SetBits(GPIOA, GPIO_Pin_5);
                delay_ms(500);
                GPIO_ResetBits(GPIOB, GPIO_Pin_5);
                delay_ms(500);
        }
}
/*
功能:加湿器模式控制
参数:RH_State sta 模式的枚举变量
说明:通过与最后一次模式的比较,判断需要按几次按键,以完成模式控制
*/
void RH_Control(RH_State sta)
{
        RH_State laststa;
   if(sta!=laststa)
        {
                switch(laststa)
                {
                        case State_Low: //上次是低
                        {
                                if(sta==State_OFF)
                                PressKey(2);
                                else if(sta==State_High)
                                PressKey(1);
                        }
                        case State_OFF:
                        {
                                if(sta==State_Low)
                                PressKey(1);
                                else if(sta==State_High)
                                PressKey(2);
                        }
                        case State_High :
                        {
                                if(sta==State_OFF)
                                PressKey(1);
                                else if(sta==State_Low)
                                PressKey(2);
                        }
                        default: printf("Error!\n");
                }
        }
        laststa=sta;
}使用USART3作为与ESP01S 通信接口,USART1 作为调试使用
#include "usart.h"#include "stdio.h"#include "delay.h"int fputc(int ch,FILE *p)//该函数用于在使用printf时发送字符到串口{        USART_SendData(USART1,(u8)ch);                while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);        return ch;}           u8 USART1_RX_BUF;   //自定义了一个数组,可能用于接收缓冲器//其他位可能用于表示错误状态或额外的控制信息̬//bit15接收完成标志位,当接收到完整的数据包(如以特定的结束符结尾)时,该位被置1//bit14表示是否接收到特定的字符(如回车符\r,即0x0D)//bit13~0存储接收到的数据长度u16 USART1_RX_STA=0;       //存储串口接收的状态信息u8 USART3_RX_BUF;   //自定义了一个数组,可能用于接收缓冲器//其他位可能用于表示错误状态或额外的控制信息̬//bit15接收完成标志位,当接收到完整的数据包(如以特定的结束符结尾)时,该位被置1//bit14表示是否接收到特定的字符(如回车符\r,即0x0D)//bit13~0存储接收到的数据长度u16 USART3_RX_STA=0;       //存储串口接收的状态信息/******************************************************************************** 函数名   : USART1_Init* 功能               : USART1初始化* 参数   : bound:串口波特率* 返回值   : 无*******************************************************************************/ void USART1_Init(u32 bound){   //GPIO的IO口、串口及中断管理结构变量定义        GPIO_InitTypeDef GPIO_InitStructure;        USART_InitTypeDef USART_InitStructure;        NVIC_InitTypeDef NVIC_InitStructure;        //开GPIO和串口时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO | RCC_APB2Periph_USART1, ENABLE);         // 重映射USART1到PB6/PB7GPIO_PinRemapConfig(GPIO_Remap_USART1, ENABLE);                /*GPIO参数设置 */        GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;//TX                           //UART1的TX口设置为PB6        GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;        GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;          //推挽输出        GPIO_Init(GPIOB,&GPIO_InitStructure);/* 应用GPIO的IO参数 */        GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7;//RX                       //UART1的RX口设置为PB7        GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;                  //设置浮空输入        GPIO_Init(GPIOB,&GPIO_InitStructure); /* 初始化UART1的接收GPIO */                //USART1 结构变量参数设置        USART_InitStructure.USART_BaudRate = bound;//串口波特率设置        USART_InitStructure.USART_WordLength = USART_WordLength_8b;//数据帧的位数,此处8位        USART_InitStructure.USART_StopBits = USART_StopBits_1;//停止位数为1位        USART_InitStructure.USART_Parity = USART_Parity_No;//奇偶效验,此处关        USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件流控制选项,既通过再加一条RTS时钟线来防止数据丢失        USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;        //串口模式,输入输出同时使用        USART_Init(USART1, &USART_InitStructure); //串口参数初始化使用                USART_Cmd(USART1, ENABLE);//使能UART1                 USART_ClearFlag(USART1, USART_FLAG_TC);//清除UART标准位,在这里是清除UART1的发送完成标志位                        USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//USART_IT_RXNE接收寄存器非空中断,串口中断配置,在这里使能了这个中断        //Usart1 NVIC 中断管理        NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//选择中断函数        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级,数字越低优先级越高        NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;                //等待优先级,在两个中断具备同等的抢占优先级时,等待优先级数字高的优先级越高        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                        //IRQ中断使能        NVIC_Init(&NVIC_InitStructure);        //初始化优先级}/******************************************************************************** 函数名      : USART1_IRQHandler* 功能                  : USART1接收寄存器满了发生中断* 参数      : 无* 返回值      : 无* 描述      : 接收数据,存在USART1_RX_BUF[]数组中,但是接收到回车会进入判断,若只有回车会复位USART1_RX_BUF[]数组从0开始存储,若是回车+换行则不能再接收数据*******************************************************************************/ void USART1_IRQHandler(void)                        {        u8 r;        if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)//如果串口接收寄存器非空标准位为1,该中断以开,即已经接收到了数据        {                r =USART_ReceiveData(USART1);//(USART1->DR);        //将接收到的数据放入r中                if((USART1_RX_STA&0x8000)==0)//还没检查到了换行?                {                        if(USART1_RX_STA&0x4000)//是否检查到回车                        {                                if(r!=0x0a)USART1_RX_STA=0;//若接收到的数据不为换行,则初始化串口接收状态变量,重新接收,直到接收到,0x0a是换行符                                else USART1_RX_STA|=0x8000;        //置串口接收状态变量最高位为1,表接收完成                         }                        //将USART1_RX_STA|=0x8000;表示此次数据接收任务结束,同时设置此标志位在下次数据输入时使数据进入缓存                        else //未接收到了,回车0X0D                        {                                        if(r==0x0d)USART1_RX_STA|=0x4000;//检查数据是否回车,将第14位置1                                else                                {                                        USART1_RX_BUF=r;//将数据放在缓存中,0X3FFF是将0到13位置1,实际按STA来表示数据长度                                        USART1_RX_STA++;                                        if(USART1_RX_STA>(USART1_REC_LEN-1))USART1_RX_STA=0;//若数据长度超过USART1_REC_LEN,重新开始计数数据长度,覆盖原有数据                                          }                                       }                }                          } }//int fputc(int ch, FILE *f)//{//        USART_TypeDef* USARTx =USART1;//        while((USARTx->SR&(1
页: [1]
查看完整版本: 基于STM32(Freertos)&ESP01S的红外空调网络控制器 -STM32软件部分