马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
1.概述
本文主要介绍控制器软件部分,包含Freertos系统初始化,STM32红外接收发射任务应用实现,加湿器模块控制实现、串口初始化及Freertos任务控制逻辑。
2.Freertos 初始化
2.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_SLICING 0//设置相同优先级任务被轮转执行
- #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 xPortSysTickHandler SysTick_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 */
复制代码 2.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[3];//依次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);
-
- }
- }
复制代码 2.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
- }
- }
- }
复制代码 3.红外控制
3.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[125];
- 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);
- u8 Lead_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度
- #endif
复制代码 3.2 红外初始化函数- /*
- 功能:对红外发射接收功能进行初始
- 参数:无
- 说明:不可同时启用发射接收初始化,因为他们都使用TIM3定时器
- */
- void IR_Init(void)
- {
- IR_TIM3_PWM_Init();//红外发射功能PWM初始化
- //IR_TIM_Init();//红外接收功能初始化
- }
复制代码 3.3 红外发射控制。
实现代码如下,部分代码参考了: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[0]=0xB2;
- SYS_Glabal_varible.IR_Sent_Data.IR_Sent_Data[1]=IR_B_Windspeed_Auto;
- SYS_Glabal_varible.IR_Sent_Data.IR_Sent_Data[2]=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;
- }
复制代码 4 加湿器模块
加湿器模块通过开关按键实现控制,按一下切换模式,模式有 “关”、“低”、“高” 三种模式
通过延时置位复位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[Buffer_index]=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);
- }
- }
- u8 Lead_cheak(u16* rowdata)
- {
- if(rowdata[0]>IR_Lead_MIN&&rowdata[0]<IR_Lead_MAX)
- {
- frame_num=1;
- return 1;
- }
- else
- return 0;
-
- }
- u8 Separation_cheak(u16* rowdata)
- {
- if(rowdata[49]>SEPARATION_MIN&&rowdata[49]<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[i+1]);
- if(rowdata[i+1]>IR_DATA_1_MIN&&rowdata[i+1]<IR_DATA_1_MAX)
- ir_data[0]|=(0x80>>i);
- else if (rowdata[i+1]<IR_DATA_0_MAX&&rowdata[i+1]>IR_DATA_0_MIN)
- ir_data[0]&=~(0x80>>i);
- }
- }else if(frame_num==2)//解码第二帧
- {
- for(i=0;i<8;i++)
- {
- // printf("%d\n",rowdata[i+51]);
- if(rowdata[i+51]>IR_DATA_1_MIN&&rowdata[i+51]<IR_DATA_1_MAX)
- ir_data[0]|=(0x80>>i);
- else if (rowdata[i+51]<IR_DATA_0_MAX&&rowdata[i+51]>IR_DATA_0_MIN)
- ir_data[0]&=~(0x80>>i);
- }
- }
- return ir_data[0];
- }
- u8 decode_NA(u16* rowdata)
- {
- u8 i=0;
- if(frame_num==1)
- {
- for(i=0;i<8;i++)
- {
- //printf("%d\n",rowdata[i+9]);
- if(rowdata[i+9]>IR_DATA_1_MIN&&rowdata[i+9]<IR_DATA_1_MAX)
- ir_data[1]|=(0x80>>i);
- else if (rowdata[i+9]<IR_DATA_0_MAX&&rowdata[i+9]>IR_DATA_0_MIN)
- ir_data[1]&=~(0x80>>i);
- }
- }
- else if(frame_num==2)
- {
- for(i=0;i<8;i++)
- {
- // printf("%d\n",rowdata[i+59]);
- if(rowdata[i+59]>IR_DATA_1_MIN&&rowdata[i+59]<IR_DATA_1_MAX)
- ir_data[1]|=(0x80>>i);
- else if (rowdata[i+59]<IR_DATA_0_MAX&&rowdata[i+59]>IR_DATA_0_MIN)
- ir_data[1]&=~(0x80>>i);
- }
- }
- return ir_data[1];
- }
- u8 decode_B(u16* rowdata)
- {
- u8 i=0;
- if(frame_num==1)
- {
- for(i=0;i<8;i++)
- {
- //printf("%d\n",rowdata[i+17]);
- if(rowdata[i+17]>IR_DATA_1_MIN&&rowdata[i+17]<IR_DATA_1_MAX)
- ir_data[2]|=(0x80>>i);
- else if (rowdata[i+17]<IR_DATA_0_MAX&&rowdata[i+17]>IR_DATA_0_MIN)
- ir_data[2]&=~(0x80>>i);
- }
- }else if(frame_num==2)
- {
- for(i=0;i<8;i++)
- {
- // printf("%d\n",rowdata[i+67]);
- if(rowdata[i+67]>IR_DATA_1_MIN&&rowdata[i+67]<IR_DATA_1_MAX)
- ir_data[2]|=(0x80>>i);
- else if (rowdata[i+67]<IR_DATA_0_MAX&&rowdata[i+67]>IR_DATA_0_MIN)
- ir_data[2]&=~(0x80>>i);
- }
- }
-
- return ir_data[2];
- }
- u8 decode_NB(u16* rowdata)
- {
-
- u8 i=0;
- if(frame_num==1)
- {
- for(i=0;i<8;i++)
- {
- //printf("%d\n",rowdata[i+25]);
- if(rowdata[i+25]>IR_DATA_1_MIN&&rowdata[i+25]<IR_DATA_1_MAX)
- ir_data[3]|=(0x80>>i);
- else if (rowdata[i+25]<IR_DATA_0_MAX&&rowdata[i+25]>IR_DATA_0_MIN)
- ir_data[3]&=~(0x80>>i);
- }
- }else if(frame_num==2)
- {
- for(i=0;i<8;i++)
- {
- // printf("%d\n",rowdata[i+75]);
- if(rowdata[i+75]>IR_DATA_1_MIN&&rowdata[i+75]<IR_DATA_1_MAX)
- ir_data[3]|=(0x80>>i);
- else if (rowdata[i+75]<IR_DATA_0_MAX&&rowdata[i+75]>IR_DATA_0_MIN)
- ir_data[3]&=~(0x80>>i);
- }
- }
- return ir_data[3];
- }
- u8 decode_C(u16* rowdata)
- {
-
- u8 i=0;
- if(frame_num==1)
- {
- for(i=0;i<8;i++)
- {
- //printf("%d\n",rowdata[i+33]);
- if(rowdata[i+33]>IR_DATA_1_MIN&&rowdata[i+33]<IR_DATA_1_MAX)
- ir_data[4]|=(0x80>>i);
- else if (rowdata[i+33]<IR_DATA_0_MAX&&rowdata[i+33]>IR_DATA_0_MIN)
- ir_data[4]&=~(0x80>>i);
- }
- }else if(frame_num==2)
- {
- for(i=0;i<8;i++)
- {
- // printf("%d\n",rowdata[i+83]);
- if(rowdata[i+83]>IR_DATA_1_MIN&&rowdata[i+83]<IR_DATA_1_MAX)
- ir_data[4]|=(0x80>>i);
- else if (rowdata[i+83]<IR_DATA_0_MAX&&rowdata[i+83]>IR_DATA_0_MIN)
- ir_data[4]&=~(0x80>>i);
- }
- }
- return ir_data[4];
- }
- u8 decode_NC(u16* rowdata)
- {
- u8 i=0;
- if(frame_num==1)
- {
- for(i=0;i<8;i++)
- {
- //printf("%d\n",rowdata[i+41]);
- if(rowdata[i+41]>IR_DATA_1_MIN&&rowdata[i+41]<IR_DATA_1_MAX)
- ir_data[5]|=(0x80>>i);
- else if (rowdata[i+41]<IR_DATA_0_MAX&&rowdata[i+41]>IR_DATA_0_MIN)
- ir_data[5]&=~(0x80>>i);
- }
- }else if(frame_num==2)
- {
- for(i=0;i<8;i++)
- {
- // printf("%d\n",rowdata[i+91]);
- if(rowdata[i+91]>IR_DATA_1_MIN&&rowdata[i+91]<IR_DATA_1_MAX)
- ir_data[5]|=(0x80>>i);
- else if (rowdata[i+91]<IR_DATA_0_MAX&&rowdata[i+91]>IR_DATA_0_MIN)
- ir_data[5]&=~(0x80>>i);
- }
- }
- return ir_data[5];
- }
- /*
- 功能:对接收到的原始数据进行解码
- 输入:IR_Buffer_Row 原始数据数组首地址
- 输出:ir_data[x],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;
- }
- }
复制代码 5.串口初始化
头文件代码,主要完成串口的存储缓冲区界说- #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 作为调试使用
[code]#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[USART1_REC_LEN]; //自界说了一个数组,可能用于接收缓冲器//其他位可能用于表示错误状态或额外的控制信息̬//bit15接收完成标记位,当接收到完整的数据包(如以特定的竣事符结尾)时,该位被置1//bit14表示是否接收到特定的字符(如回车符\r,即0x0D)//bit13~0存储接收到的数据长度u16 USART1_RX_STA=0; //存储串口接收的状态信息u8 USART3_RX_BUF[USART3_REC_LEN]; //自界说了一个数组,可能用于接收缓冲器//其他位可能用于表示错误状态或额外的控制信息̬//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/PB7 GPIO_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[USART1_RX_STA&0X3FFF]=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 |