基于STM32的红外万能遥控器完整教程 您所在的位置:网站首页 万能电灯遥控器使用说明 基于STM32的红外万能遥控器完整教程

基于STM32的红外万能遥控器完整教程

2023-10-28 18:10| 来源: 网络整理| 查看: 265

连载目录: 01、基于STM32的红外万能遥控器完整教程 视情况更新。。。

基于STM32的红外万能遥控器完整教程 一、概述实现的功能参考文档 二、项目的逻辑三、硬件主控模块接线方式 四、代码结构Main函数红外接收器驱动(remote)红外数据存储(remote_save)红外发射器驱动(irsend) 五、Github地址

一、概述

一直想自己实现一个类似于万能遥控的功能,最近借着嵌入式课设的机会终于完成了这个项目,目前已经完成了验收,将工程源码全部开源Github,希望能对大家有所帮助。

实现的功能

学习、存储和发射标准NEC格式的红外信息,如机顶盒,少数电视

学习、存储和发射非标准格式的红外信息,如风扇,空调

展示NEC格式解码后的数据(二进制和十进制展示)

展示非标准格式的波形数据(包括高低电平及其持续时间)

参考文档 详解红外遥控器编码解码原理!Github Infrared Universal Control基于STM32的红外遥控重点解析格力空调遥控器红外编码透析(长码) 二、项目的逻辑

使用单片机遥控器控制demo,OLED屏幕显示提示信息和数据,使用单片机遥控机进行功能选择,学习完成后,也是要单片机遥控器控制demo发射学习到的信息实现控制其他设备的功能,所以就能够实现使用一个单片机遥控器控制所有红外家电的目标。

因为单片机遥控器按键数量有限,为了能够控制更多设备,这个项目实现了分区的功能,在进入首页后,可以按1选择不同的区,每个区对应flash里面不同的起始地址,在学习存储和发射红外信息时相同的按键值对应的存储空间就会不同,从而实现按键的复用。

简单来说:使用单片机遥控器来控制设备发出可以控制其它家电的红外信号。

三、硬件 主控

STM32F103xx(flash最好大于等于256k,方便存储数据,该项目使用的是STM32F103RCT6最小系统板)

模块

0.96寸OLED屏12864液晶显示屏(IIC接口) 在这里插入图片描述 红外接收模块或者通用红外接收头 在这里插入图片描述 红外发射器(见下图) 在这里插入图片描述 单片机遥控器 在这里插入图片描述

接线方式

OLED

电源3.3vSCL -> PB6SDA -> PB7

红外接收器

电源3.3vDAT -> PB9

红外发射器

VCC -> 3V3GND -> PC2(使用PC2引脚输出高低电平实现对发射器的开关控制)DAT -> PA0 四、代码 结构

Template(工程目录) |- USER    |- main.c (主函数文件) |- SYSTEM    |- delay.c (延时函数,来自于STM32F4的库,F1的延时函数时间不准!!!) |- HARDWARE    |- oled.c (OLED驱动)    |- remote.c (红外接收器驱动)    |- pwm.c (波形产生驱动,用于产生38KHz 方波)    |- irsend.c (红外发射器驱动)    |- stmflash.c (flash存储驱动)    |- remote_save.c (在stmflash.c的基础上编写的便于存储红外数据的存储驱动)

其他文件和目录均来自于正点原子库函数模版

驱动函数 xx.c 和 xx.h 一 一对应,接口写在xx.h中,具体实现在xx.c中实现,本文主要介绍逻辑,以h文件为主,详细代码请看Github。

Main函数 #include "oled.h" #include "remote.h" #include "pwm.h" #include "irsend.h" #include "usart.h" #include "delay.h" #include "remote_save.h" #include "guet.h" //主要的函数模块 void showData(u32 data); //显示数据信息 void data_Init(void); //红外数据数组初始化 void ShowSquareWave_Init(void); //初始化波形数组 void SetPart(void); //设置区号1-9 主要是为了扩大设备可用性,用不同区号相同按键实现不同的功能(按键的复用) int GetPart(void); //得到区号,在首页显示,便于用户区分 void SendLearn(void); //学习/发送函数 void Delete(void); //删除数据函数 void ShowData(void); //展示输入信号信息函数 int key; //用于记录用户按下的按键或者数据信息 u16 data[350]; //红外数据数组,存储波形时间数据 u16 addr = 0; //偏移量 unsigned char show[128 * 2] = {0}; //波形显示存储数组 int main() { //初始化部分 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 uart_init(115200); delay_init(72); OLED_IIC_Init(); //初始化OLED IIC Initial_M096128x64_ssd1306(); //OLED初始化 OLED_Fill_picture(0x00); //清屏 Remote_Init(); TIM2_PWM_Init(1895,0); IR_SendPort_Init(); ShowSquareWave_Init(); //显示欢迎页 OLED_Picture_Part(guet, 0, 64, 0, 8); OLED_ShowStr(10, 1, "GUET"); OLED_ShowStr(8, 3, "Welcome"); Remote_Num(); //暂停 //显示首页功能提示信息 while (1) { OLED_Fill_picture(0x00); //清屏 OLED_ShowStr(0, 0, "1.SetPart( )"); OLED_ShowNum(10, 0, GetPart(), 1); OLED_ShowStr(0, 1, "2.Send/Learn"); OLED_ShowStr(0, 2, "3.Delete"); OLED_ShowStr(0, 3, "4.ShowData"); switch (Remote_Num()) //输入数字进入相应的功能模块 { case 1: SetPart(); break; case 2: SendLearn(); break; case 3: Delete(); break; case 4: ShowData(); break; } } }

mian函数展示了项目的基础控制逻辑:上电后显示欢迎页(校徽),单片机遥控器按下任意按键进入主菜单,菜单样式:   | 1.SetPart(1) -> 设置分区 | 2.Send/Learn -> 进入发射、学习模式 | 3.Delete -> 进入删除模式(删除存储的红外数据) | 4.ShowData -> 进入展示模式(显示NEC的解码数据或非标准数据的波形)   按下对应数字进入相应功能。

子模式函数:

/** * OLED显示32位数据的信息(左边二进制,右边十进制) * * @param data 32位数据 */ void showData(u32 data) { OLED_Fill_picture(0x00); //清屏 OLED_ShowBite(0, 0, data >> 24); OLED_ShowNum(10, 0, data >> 24, 3); OLED_ShowBite(0, 1, data >> 16); OLED_ShowNum(10, 1, (data >> 16) % 256, 3); OLED_ShowBite(0, 2, data >> 8); OLED_ShowNum(10, 2, (data >> 8) % 256, 3); OLED_ShowBite(0, 3, data); OLED_ShowNum(10, 3, data % 256, 3); } /** * 红外数据数组初始化 */ void data_Init(void) { int i; for(i = 0; i OLED_Fill_picture(0x00); //清屏 OLED_ShowStr(0, 0, "SetPart:0-9"); while (1) { key = Remote_Num(); if (key == POWER) break; else if (key >= 1 && key return addr / 20 + 1; } /** * 数字学习模式 */ void DigitalLearn(void) { while (1) { u32 get; OLED_Fill_picture(0x00); //清屏 OLED_ShowStr(0, 0, "Select key!"); key = Remote_Num(); if (key == POWER) break; OLED_ShowStr(0, 1, "Getting..."); get = Remote_GetData(); showData(get); data[0] = (u16)get; data[1] = (u16)(get >> 16); SaveData(addr + key, 0, data, 2); delay_ms(100); } } /** * 模拟学习模式 */ void AnalogLearn(void) { while (1) { int a; OLED_Fill_picture(0x00); //清屏 OLED_ShowStr(0, 0, "Select key!"); key = Remote_Num(); if (key == POWER) break; OLED_ShowStr(0, 1, "Input after 2s!"); delay_ms(1000); OLED_ShowStr(0, 1, "Input after 1s!"); delay_ms(1000); OLED_Clean(1); Re_Record_ON(); OLED_ShowStr(5, 1, "Input!"); delay_ms(1500); OLED_ShowStr(5, 2, "OK!"); a = Re_Record_OFF(); OLED_ShowNum(9, 2, a, 4); SaveData(addr + key, 1, Re_Record_Get(), a); delay_ms(400); } } /** * 学习/发送函数 */ void SendLearn(void) { int dot = 0; //用了记录上次执行了哪个操作,确定是否需要清空屏幕 while (1) { if (dot == 0) OLED_Fill_picture(0x00); //清屏 else if (dot == 1) OLED_Clean(3); else if (dot == 2) OLED_Clean(0); OLED_ShowStr(0, 0, "Mode:learn"); OLED_ShowStr(0, 1, "POWER:exit"); OLED_ShowStr(0, 2, "Other:send"); dot = 0; key = Remote_Num(); if (key == POWER) break; if (key == MODE) { // 学习模式 while (1) {// 选择学习模式 OLED_Fill_picture(0x00); //清屏 OLED_ShowStr(0, 0, "Learn Mode:"); OLED_ShowStr(0, 1, "1.Digital"); OLED_ShowStr(0, 2, "2.Analog"); key = Remote_Num(); if (key == POWER) break; else if (key == 1) {// 数字模式 DigitalLearn(); } else if (key == 2) {// 模拟模式 AnalogLearn(); } } } else { // 发送模式 int sta; data_Init(); sta = GetData(addr + key, data); if (sta != -1) { OLED_ShowStr(2, 3, "SEND!"); delay_ms(100); Remote_OFF(); TR_SendTimeData(data, sta); Remote_ON(); delay_ms(200); dot = 1; } else //未读取到数据 { OLED_Fill_picture(0x00); //清屏 OLED_ShowStr(0, 0, "Don't have data!"); delay_ms(300); dot = 2; } } } } /** * 删除数据函数 */ void Delete(void) //删除数据函数 { OLED_Fill_picture(0x00); //清屏 while (1) { OLED_Clean(3); OLED_ShowStr(0, 0, "Mode:del all"); OLED_ShowStr(0, 1, "POWER:exit"); OLED_ShowStr(0, 2, "Other:del one"); key = Remote_Num(); if (key == POWER) break; if (key == MODE) { DelPartData(addr); OLED_ShowStr(0, 3, "del all success!"); delay_ms(300); } else { DelData(addr + key); OLED_ShowStr(0, 3, "del one success!"); delay_ms(300); } } } /** * 初始化波形数组 */ void ShowSquareWave_Init(void) { int i, j; show[0] = 0xfe; show[1] = 0xfe; show[128 + 0] = 0x7f; show[128 + 1] = 0x7f; j = 128 + 2; for (i = 0; i show[j + i] = 0x06; } show[64 + 0] = 0xfe; show[64 + 1] = 0xfe; show[128 + 64 + 0] = 0x7f; show[128 + 64 + 1] = 0x7f; j = 128 + 64 + 2; for (i = 0; i show[j + i] = 0x06; } } /** * OLED展示波形函数(仅波形) */ void ShowSquareWave(void) { OLED_Picture_Part(show, 0, 128, 4, 2); } /** * 展示波形信息 * @param pBuffer 时长数组指针 * @param lenth 数组长度 */ void ShowDataAnalog(u16 * pBuffer, u16 lenth) { int page = 1; OLED_Fill_picture(0x00); //清屏 OLED_ShowStr(0, 0, "Mode:show lenth"); OLED_ShowStr(0, 1, "Left:left page"); OLED_ShowStr(0, 2, "right:right page"); OLED_ShowStr(0, 3, "POWER:exit"); while (1) { key = Remote_Num(); if (key == POWER) break; if (key == MODE) { //展示长度信息 OLED_Fill_picture(0x00); //清屏 OLED_ShowStr(0, 0, "Lenth: "); OLED_ShowNum(6, 0, lenth, 4); } else if (key == LEFT || key == RIGHT || key == 1 || key == 9) { if (key == LEFT) { page -= 1; if (page page = 1; } else if (key == 9) { page = (lenth + 3) / 4; } OLED_Fill_picture(0x00); //清屏 OLED_ShowStr(0, 0, "P: Start: "); OLED_ShowNum(2, 0, page, 2); OLED_ShowNum(11, 0, (page - 1) * 4 + 1, 4); ShowSquareWave(); OLED_ShowNum(0, 3, pBuffer[(page - 1) * 4 + 0 + 1], 4); OLED_ShowNum(4, 1, pBuffer[(page - 1) * 4 + 1 + 1], 4); OLED_ShowNum(8, 3, pBuffer[(page - 1) * 4 + 2 + 1], 4); OLED_ShowNum(12, 1, pBuffer[(page - 1) * 4 + 3 + 1], 4); } } } /** * 展示输入信号信息函数 */ void ShowData(void) { while (1) { OLED_Fill_picture(0x00); //清屏 OLED_ShowStr(0, 0, "Select From:"); OLED_ShowStr(0, 1, "1.input"); OLED_ShowStr(0, 2, "2.flash"); OLED_ShowStr(0, 3, "POWER:exit"); key = Remote_Num(); if (key == POWER) break; if (key == 1) {//输入信息展示 while (1) { OLED_Fill_picture(0x00); //清屏 OLED_ShowStr(0, 0, "Select Mode:"); OLED_ShowStr(0, 1, "1.Digital"); OLED_ShowStr(0, 2, "2.Analog"); OLED_ShowStr(0, 3, "POWER:exit"); key = Remote_Num(); if (key == POWER) break; else if (key == 1) {// 数字模式 while (1) { OLED_Fill_picture(0x00); //清屏 OLED_ShowStr(0, 0, "Getting..."); key = Remote_GetData(); showData(key); key = Remote_Num(); //POWER退出,其它按键继续 if (key == POWER) break; } } else if (key == 2) {// 模拟模式 OLED_Fill_picture(0x00); //清屏 OLED_ShowStr(0, 0, "Input after 2s!"); delay_ms(1000); OLED_ShowStr(0, 0, "Input after 1s!"); delay_ms(1000); OLED_Clean(0); Re_Record_ON(); OLED_ShowStr(5, 0, "Input!"); delay_ms(1500); OLED_ShowStr(5, 1, "OK!"); ShowDataAnalog(Re_Record_Get(), Re_Record_OFF()); } } } else if (key == 2) {//存储信息展示 OLED_Fill_picture(0x00); //清屏 OLED_ShowStr(0, 0, "Select key!"); while (1) { key = Remote_Num(); if (key == POWER) break; else { int sta; data_Init(); sta = GetData(addr + key, data); if (sta != -1) { if (((sta >> 12) & 0x7) == 1) //模拟模式 ShowDataAnalog(data, sta & 0x03FF); else if (((sta >> 12) & 0x7) == 0) //标准模式 { key = (data[1] /* 初始化结构体定义 */ GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; TIM_OCInitTypeDef TIM_OCInitStructure; /* 使能相应端口的时钟 */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //使能定时器2时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIO外设时钟 /* GPIOA.0初始化 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // TIM2 CH1 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // PA.0 复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_SetBits(GPIOA,GPIO_Pin_0); /* TIM2 初始化*/ TIM_TimeBaseInitStructure.TIM_Period = arr; //下一个更新事件装入活动的自动重装载寄存器周期的值 TIM_TimeBaseInitStructure.TIM_Prescaler = psc; //作为TIMx时钟频率除数的预分频值 TIM_TimeBaseInitStructure.TIM_ClockDivision = 0; //时钟分割:TDTS = Tck_tim TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); /* 定时器TIM2 Ch1 PWM模式初始化 */ TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM PWM1 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能 //TIM_OCInitStructure.TIM_Pulse = (arr+1)/2; //占空比 50% TIM_OCInitStructure.TIM_Pulse = (arr+1)/3; //占空比1:3 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高 TIM_OC1Init(TIM2, &TIM_OCInitStructure); /* 使能TIM2在CCR1上的预装载寄存器 */ TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable); /* 使能定时器 */ TIM_Cmd(TIM2, ENABLE); } 五、Github地址

该项目:基于STM32F103的红外学习遥控项目 个人主页:Wing



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有