基于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]