chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

軟硬件開(kāi)源項(xiàng)目-紅外遙控網(wǎng)關(guān):IRext 紅外碼庫(kù)+遠(yuǎn)程實(shí)現(xiàn)紅外開(kāi)關(guān)空調(diào)+紅外學(xué)習(xí)

asd ? 來(lái)源:jf_66821157 ? 作者:jf_66821157 ? 2025-08-12 09:41 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

軟硬件開(kāi)源項(xiàng)目-紅外遙控網(wǎng)關(guān):IRext 紅外碼庫(kù)+遠(yuǎn)程實(shí)現(xiàn)紅外開(kāi)關(guān)空調(diào)+紅外學(xué)習(xí)

【下載地址】:紅外遙控網(wǎng)關(guān)源碼

本倉(cāng)庫(kù)提供了一個(gè)完整的紅外遙控網(wǎng)關(guān)源碼,旨在幫助開(kāi)發(fā)者了解紅外控制和紅外學(xué)習(xí)的實(shí)現(xiàn)過(guò)程。項(xiàng)目包含了紅外控制和紅外學(xué)習(xí)的完整代碼。

項(xiàng)目地址:https://gitee.com/daadadada/infrared 小程序源碼地址:https://pan.baidu.com/s/17PZ9PxKzOpBtRuvA9ePOTw?pwd=4hgn


1.前言

當(dāng)智能家居從概念走向現(xiàn)實(shí),傳統(tǒng)紅外設(shè)備的“智能改造”卻成了多數(shù)家庭的痛點(diǎn):不同品牌空調(diào)的紅外協(xié)議千差萬(wàn)別,遙控器堆成小山仍難實(shí)現(xiàn)統(tǒng)一控制。盡管市面上有很多智能控制 APP,但是這需要設(shè)備端支持網(wǎng)絡(luò),一些生產(chǎn)較早的空調(diào)等設(shè)備大多都不支持網(wǎng)絡(luò)這一功能。如果有一個(gè)類似遙控器的產(chǎn)品能遠(yuǎn)程控制市面上大部分的空調(diào)品牌,并且支持紅外學(xué)習(xí)實(shí)現(xiàn)控制,那么問(wèn)題就迎刃而解了。由于 WiFi 信號(hào)容易受影響并且做通信功耗相對(duì)較高,因此我使用以太網(wǎng)做通訊。之前做項(xiàng)目用過(guò) WIZnet 的芯片實(shí)現(xiàn)以太網(wǎng)功能,近期他們出了個(gè)帶 MCU以太網(wǎng)芯片 W55MH32,找他們銷售申請(qǐng)了一套開(kāi)發(fā)板。計(jì)劃是小程序做控制端,開(kāi)發(fā)板做設(shè)備端,通過(guò)以太網(wǎng)進(jìn)行通訊。紅外學(xué)習(xí)到的紅外碼在設(shè)備端使用 w25q64 本地存儲(chǔ)。

目前開(kāi)發(fā)板用著可以,這款芯片集成了全硬件 TCP/IP 協(xié)議棧、MAC 及 PHY,開(kāi)發(fā)板也已經(jīng)集成了網(wǎng)絡(luò)變壓器和網(wǎng)口。Flash 和 SRAM 也足夠大。一些不是很懂的網(wǎng)絡(luò)協(xié)議也可以去他們[官網(wǎng)例程]去了解,里面也有一些講如何配置 Keil 和燒錄,資料很充足。

目前的功能已經(jīng)實(shí)現(xiàn)了遠(yuǎn)程控制空調(diào),但是紅外學(xué)習(xí)機(jī)制是通過(guò)外界發(fā)射紅外信號(hào)來(lái)觸發(fā),并在串口打印,紅外學(xué)習(xí)的功能并沒(méi)有完全實(shí)現(xiàn)。后續(xù)會(huì)通過(guò)小程序按鍵來(lái)觸發(fā)紅外學(xué)習(xí),并且能下發(fā)命令實(shí)現(xiàn)控制。未被收錄的紅外碼通過(guò) w25q64 和 FatFs 文件系統(tǒng),實(shí)現(xiàn)本地存儲(chǔ)!另外,后面也會(huì)自己畫原理圖和 pcb 板,將所有的硬件集成到板子上,也會(huì)把代碼、原理圖以及 pcb 都開(kāi)源出來(lái)。

2.紅外

紅外遙控碼是一種基于 38000Hz 或者 56000Hz 載波頻率的控制編碼,接收方通過(guò)識(shí)別帶有或不帶有載波的時(shí)間間隔片進(jìn)行編碼識(shí)別。

在控制層通常使用高低物理電平對(duì)的序列來(lái)表示一個(gè)獨(dú)立的控制信號(hào),例如以下的 NEC 碼:
ir_nec_sample.png

它使用 9000us 載波+4500us 無(wú)載波時(shí)間序列表示引導(dǎo)碼,并且使用 500us 載波+500us 無(wú)載波時(shí)間序列表示邏輯 0,使用 500us 載波+1500us 無(wú)載波時(shí)間序列表示邏輯 1,采用 2 字節(jié)地址碼和 2 字節(jié)命令碼構(gòu)成,全碼時(shí)間序列長(zhǎng)度為 67.5ms。

IRext 紅外庫(kù)移植

IRext 是一個(gè)開(kāi)源萬(wàn)能紅外遙控碼庫(kù)、編解碼壓縮算法以及免費(fèi)周邊服務(wù)。它向智能家居開(kāi)發(fā)者提供:

  • 支持 16 類 1000 多品牌,上萬(wàn)個(gè)型號(hào)的家用電器遙控。
  • 在線以及離線的萬(wàn)能紅外碼庫(kù),包括按照品牌分類的索引以及遙控編碼。
  • 靈活的服務(wù)部署方式,利用開(kāi)源的服務(wù)端以及控制臺(tái)代碼在容器環(huán)境內(nèi) 5 分鐘快速搭建自己的碼庫(kù)服務(wù)。
  • 碼庫(kù)和解碼算法經(jīng)過(guò)了極限壓縮,能存儲(chǔ)和運(yùn)行在配置低至 51 MCU 的嚴(yán)苛硬件環(huán)境中。
  • 豐富的平臺(tái)適配支持和示例代碼。
  • 詳盡的文檔資源,覆蓋萬(wàn)能遙控開(kāi)發(fā)的每一個(gè)環(huán)節(jié)。
  • 開(kāi)發(fā)者可使用碼庫(kù)擴(kuò)展工具自行擴(kuò)展碼庫(kù),可基于開(kāi)源代碼自由修改方案功能細(xì)節(jié)。

前往[IRext 官網(wǎng)]下載離線碼庫(kù)和 IRext 解碼庫(kù),將 IRext 解碼庫(kù)放進(jìn)單片機(jī)工程目錄里并修改頭文件目錄,讓其包含解碼庫(kù)中的頭文件。根據(jù) IRext 提供的品牌索引庫(kù)從離線碼庫(kù)下載所需要的品牌紅外碼庫(kù)??纱娣诺絾纹瑱C(jī) FLASH 或放到服務(wù)器上。IRext 解碼庫(kù)支持從文件系統(tǒng)解碼或從內(nèi)存解碼。

從文件系統(tǒng)解碼

ir_file_open(category, sub_category, "my_ir_code_file.bin");
ir_decode(key_code, user_data, ac_status, change_wind_dir);
ir_close();

加載到內(nèi)存解碼

ir_binary_open(category, sub_category, buffer, buffer_length);
ir_decode(key_code, user_data, &ac_status, change_wind_dir);
ir_close();

解碼之后在 decoded_data 中獲得可供輸出的 IR 時(shí)間序列,將此序列遞交給 IR 設(shè)備驅(qū)動(dòng)即可實(shí)現(xiàn)紅外發(fā)送。不過(guò),目前 IRext 庫(kù)只支持開(kāi)關(guān),風(fēng)速,溫度控制和掃風(fēng)這些功能。

3.程序功能實(shí)現(xiàn)

小程序與設(shè)備通信功能

使用小程序可以做到遠(yuǎn)程開(kāi)啟空調(diào)而無(wú)需在設(shè)備旁邊,并且小程序無(wú)需下載安裝,通過(guò)微信等平臺(tái)就能直接訪問(wèn),因此我選擇微信小程序來(lái)作為控制端。如圖為小程序界面圖:
微信圖片_2025-08-08_104058_610.jpg

小程序與設(shè)備通信的方式為,小程序調(diào)用 OneNET 平臺(tái)提供的 HTTP 接口實(shí)現(xiàn)設(shè)備屬性下發(fā),云平臺(tái)通過(guò) mqtt 協(xié)議將數(shù)據(jù)發(fā)送給設(shè)備。小程序與云平臺(tái)以及設(shè)備交互的數(shù)據(jù)格式如下,Command 用于下發(fā)控制或紅外學(xué)習(xí)命令。
微信圖片_2025-08-08_090606_876.png

其中 AC_Status 是一個(gè)結(jié)構(gòu)體,存儲(chǔ)空調(diào)的狀態(tài),具體內(nèi)容如下,其中的結(jié)構(gòu)體成員分別是空調(diào)的品牌、型號(hào)、電源、模式、溫度、風(fēng)速和操作,其中操作是因?yàn)?IRext 庫(kù)需要在解碼的時(shí)候作為形參傳入,所以必須定義,這個(gè)操作對(duì)應(yīng)著小程序端按下的按鍵,比如,開(kāi)關(guān)機(jī),升溫等。
微信圖片_2025-08-08_091042_324.png

在設(shè)備端我用到 OneNET 平臺(tái)的通信主題有$sys/{pid}/{device-name}/thing/property/set這個(gè)用于訂閱,接收下發(fā)的控制命令;$sys/{pid}/{device-name}/thing/property/set_reply 用于應(yīng)答下發(fā)的控制命令。一些其他的通信主題沒(méi)有用到,感興趣的小伙伴可以訪問(wèn)OneNET mqtt 通信主題了解。

小程序端使用的是 OneNET 平臺(tái)提供的 http 接口,具體用到的接口為 https://iot-api.heclouds.com/thingmodel/set-device-property ,用于下發(fā)設(shè)備屬性設(shè)置命令到設(shè)備,設(shè)備會(huì)返回設(shè)置結(jié)果。其他的 http 接口可以訪問(wèn)OneNET http 接口。

另外在發(fā)起 https 請(qǐng)求前,還需要在 Headers 中攜帶統(tǒng)一的安全鑒權(quán)信息 authorization 才能成功請(qǐng)求接口。具體方法需前往安全鑒權(quán)查看詳細(xì)內(nèi)容。

我們?cè)?W55MH32 提供的開(kāi)發(fā)套件下寫代碼,一些依賴的頭文件和 pack 包都在里面。

將開(kāi)發(fā)套件下的 do_mqtt.c 和 do_mqtt.h 文件復(fù)制到項(xiàng)目里,并修改 mqtt_params 里的參數(shù)為自己要連接的 mqtt 地址等參數(shù)。

do_mqtt()函數(shù)是一個(gè)基于狀態(tài)機(jī)的 MQTT 客戶端處理函數(shù),負(fù)責(zé)管理 MQTT 連接、訂閱、?;詈拖⒔邮盏炔僮?。當(dāng)函數(shù)第一次運(yùn)行時(shí),會(huì)來(lái)到 conn,開(kāi)始和 MQTT 服務(wù)器建立連接,之后再根據(jù)狀態(tài)進(jìn)行判斷狀態(tài),進(jìn)入到 SUB 訂閱主題或者 KEEPALIVE 保活等。在狀態(tài)為 ERR 時(shí),代表著 mqtt 連接之間出現(xiàn)了錯(cuò)誤,在 ERR 狀態(tài)中,可以重新連接或者自定義一些處理。由于在 mqtt 的狀態(tài)機(jī)中我不需要發(fā)布消息,所以我把發(fā)布消息這一節(jié)點(diǎn)刪除了,代碼如下:

void do_mqtt(void)
{
    uint8_t ret;
    switch (run_status)
    {
    case CONN:
    {
        ret = MQTTConnect(&c, &data); /* 連接到MQTT服務(wù)器 */
        printf("Connect to the MQTT server: %d.%d.%d.%d:%drn", mqtt_params.server_ip[0], mqtt_params.server_ip[1], mqtt_params.server_ip[2], mqtt_params.server_ip[3], mqtt_params.port);
        printf("Connected:%srnrn", ret == SUCCESSS ? "success" : "failed");
        if (ret != SUCCESSS)
        {
            run_status = ERR;
        }
        else
        {
            run_status = SUB;
        }
        break;
    }
    case SUB:
    {
        ret = MQTTSubscribe(&c, mqtt_params.subtopic, mqtt_params.subQoS, message_Arrived); /* 訂閱主題 */
        printf("Subscribing to %srn", mqtt_params.subtopic);
        printf("Subscribed:%srnrn", ret == SUCCESSS ? "success" : "failed");
        if (ret != SUCCESSS)
        {
            run_status = ERR;
        }
        else
        {
            run_status = KEEPALIVE;
        }

        break;
    }
    case KEEPALIVE:
    {
        if (MQTTYield(&c, 30) != SUCCESSS) /* ?;?MQTT */
        {
            run_status = ERR;
        }
        delay_ms(100);
    }
    case RECV:
    {
        if (mqtt_recv_flag)
        {
            mqtt_recv_flag = 0;
            json_decode(mqtt_recv_msg);
        }
        delay_ms(100);
        break;
    }
    case ERR: /* 錯(cuò)誤處理 */
        printf("system ERROR!");
        delay_ms(1000);
        break;

    default:
        break;
    }
}

messageArrived 函數(shù)是當(dāng)我們訂閱的主題發(fā)來(lái)消息時(shí)的回調(diào)函數(shù),當(dāng)有消息到達(dá)時(shí),會(huì)觸發(fā)此函數(shù),并把消息內(nèi)容作為參數(shù)傳遞給此函數(shù)。這里會(huì)打印一些參數(shù),如主題、消息內(nèi)容、QOS 等級(jí)等。代碼如下:

void message_Arrived(MessageData *md)
{
    char topicname[64] = {0};
    char msg[512] = {0};
    sprintf(topicname, "%.*s", (int)md- >topicName- >lenstring.len, md- >topicName- >lenstring.data);
    sprintf(msg, "%.*s", (int)md- >message- >payloadlen, (char *)md- >message- >payload);
    printf("recv data from %s", topicname);
    if (strcmp(topicname, mqtt_params.subtopic) == 0)
    {
        mqtt_recv_flag = 1;
        memset(mqtt_recv_msg, 0, sizeof(mqtt_recv_msg));
        memcpy(mqtt_recv_msg, msg, strlen(msg));
    }
}

json_decode 函數(shù)用于解析 JSON 數(shù)據(jù),這里可以根據(jù)我們?cè)谠破脚_(tái)定義的數(shù)據(jù)來(lái)解析數(shù)據(jù)。解析完成后,會(huì)做一個(gè)回復(fù),表示接收到數(shù)據(jù),做應(yīng)答。代碼如下:

void json_decode(char *msg)
{
    int ret;
    char replymsg[128] = {0};
    cJSON *jsondata = NULL;
    cJSON *id = NULL;
    cJSON *params = NULL;
    cJSON *AC = NULL;
    cJSON *data = NULL;

    jsondata = cJSON_Parse(msg);
    if (jsondata == NULL)
    {
        printf("json parse fail.rn");
        return;
    }

    id = cJSON_GetObjectItem(jsondata, "id");
    params = cJSON_GetObjectItem(jsondata, "params");

    data = cJSON_GetObjectItem(params, "Command");

    // 如果不是控制命令則返回
    if (strcmp(data- >valuestring, "Control"))
    {
        return;
    }

    // 解析json并獲取空調(diào)狀態(tài)
    AC = cJSON_GetObjectItem(params, "AC");
    data = cJSON_GetObjectItem(AC, "ACBrand");
    brand = (unsigned char)data- >valueint;
    data = cJSON_GetObjectItem(AC, "ACType");
    type = (unsigned char)data- >valueint;
    data = cJSON_GetObjectItem(AC, "openFlag");
    ac_status.ac_power = (t_ac_power)data- >valueint;
    data = cJSON_GetObjectItem(AC, "modeGear");
    ac_status.ac_mode = (t_ac_mode)data- >valueint;
    data = cJSON_GetObjectItem(AC, "tempature");
    ac_status.ac_temp = (t_ac_temperature)(data- >valueint - 16);
    data = cJSON_GetObjectItem(AC, "fengsuGear");
    ac_status.ac_wind_speed = (t_ac_wind_speed)data- >valueint;
    data = cJSON_GetObjectItem(AC, "opertion");
    operation = (unsigned char)data- >valueint;

    // 回復(fù)
    pubmessage.qos = QOS0;
    sprintf(replymsg, "{"id":"%s","code":200,"msg":"success"}", id- >valuestring);
    printf("reply:%srn", replymsg);
    pubmessage.payload = replymsg;
    pubmessage.payloadlen = strlen(replymsg);
    ret = MQTTPublish(&c, mqtt_params.subtopic_reply, &pubmessage);
    if (ret != SUCCESSS)
    {
        run_status = ERR;
    }
    else
    {
        printf("publish:%s,%srnrn", mqtt_params.subtopic_reply, (char *)pubmessage.payload);
    }
    cJSON_Delete(jsondata);

    irSendFlag = 1;
}

紅外發(fā)射功能

由于紅外發(fā)射是一種基于 38000Hz 載波頻率的控制編碼,因此我們需要使用到 PWM 功能和 GPIO 口,創(chuàng)建 GPIOConfiguration 和 TIMConfiguration 函數(shù),分別初始化 GPIO 口和 PWM。GPIO 口,即 PWM 輸出口設(shè)為 PA3。定時(shí)器 2 采用的是 PCLK1 時(shí)鐘,頻率盡量最大,這樣輸出的紅外誤碼率低。我選擇頻率為 216MHz,因此不需要分頻。計(jì)數(shù)值設(shè)置為 5736,216MHz/5736≈38KHz。紅外發(fā)射的占空比一般設(shè)為 1/3,因此將占空比,即 TIM_Pulse 設(shè)為 1912。PWM 代碼如下:

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

TIM_TimeBaseStructure.TIM_Period = 5736 - 1;  // 216Mhz/5736≈38Khz
TIM_TimeBaseStructure.TIM_Prescaler = 1 - 1; // 216Mhz/3=216Mhz
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

// 配置PWM模式
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 1912; // 占空比計(jì)算
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC4Init(TIM2, &TIM_OCInitStructure);

TIM_Cmd(TIM2, ENABLE);
TIM_SetCompare4(TIM2, 0);

在 IRControl.c 文件中創(chuàng)建 getIrCode 函數(shù),通過(guò) mqtt 解析的 json 數(shù)據(jù),即可知道要控制哪個(gè)品牌以及類型的空調(diào),目前僅支持三個(gè)品牌。接著調(diào)用 IRext 提供的 API 解碼,并將解碼后的數(shù)據(jù)存放到先前定義的 user_data 變量里,代碼如下:

unsigned char *number_point = NULL;
unsigned short *length_point = NULL;

switch (brand)
{
case 0:
    {
        number_point = Gree[type];
        length_point = Gree_Length;
        break;
    }

    case 1:
    {
        number_point = Midea[type];
        length_point = Midea_Length;
        break;
    }

    case 2:
    {
        number_point = Haier[type];
        length_point = Haier_Length;
        break;
    }

    default:
        break;
}

unsigned char ret = ir_binary_open(1, 1, number_point, length_point[type]);
length = ir_decode(operation_list[operation], user_data, &ac_status, 1);

if (length == 0)
    printf("Decode error");

ir_close();

在 IRControl.c 中創(chuàng)建 runIr 函數(shù),用于驅(qū)動(dòng)紅外發(fā)射模塊,根據(jù)解碼后的時(shí)間序列,驅(qū)動(dòng) PWM 輸出占空比為 33%或 0%的 PWM 波即可控制空調(diào),代碼如下。在最后輸出一個(gè) 40ms 的占空比為 0%的無(wú)載波時(shí)間片,來(lái)終止紅外。

for (unsigned short i = 0; i < length; i++)
{
    if (!(i % 2))
        TIM_SetCompare4(TIM2, 1912);
    else
        TIM_SetCompare4(TIM2, 0);

    delay_us(user_data[i]);
}

TIM_SetCompare4(TIM2, 0);

delay_us(40000);

最后創(chuàng)建 ir_control 函數(shù)并調(diào)用 getIrCode 和 runIr 函數(shù)即可。

紅外學(xué)習(xí)功能

在初始化階段會(huì)配置 GPIO 口中斷用于監(jiān)聽(tīng)紅外信號(hào),定時(shí)器中斷用于計(jì)時(shí)。由于定時(shí)器的重裝值為 16 位,最大只能到 65535us,而紅外信號(hào)會(huì)有重復(fù)碼,很容易就超過(guò)了定時(shí)器的最大值,因此需要使用定時(shí)器溢出中斷來(lái)轉(zhuǎn)換成 32 位計(jì)數(shù)值。在每次觸發(fā) TIM4 更新中斷時(shí),就將溢出計(jì)數(shù)加 1,在需要獲取時(shí)間時(shí)就可以將溢出計(jì)數(shù)左移 16 位并與上當(dāng)前定時(shí)器 的計(jì)數(shù)值就是 32 位計(jì)數(shù)值。例如:

return (timer_overflow_count << 16) | TIM_GetCounter(TIM4);

紅外接收有 2 個(gè)狀態(tài)分別是 IR_IDLE(空閑)、IR_RECEIVING(接收完成)。當(dāng)紅外信號(hào)到來(lái)時(shí),會(huì)進(jìn)入到 EXTI0_IRQHandler 中斷處理函數(shù)中,并將空閑狀態(tài)改變?yōu)榻邮諣顟B(tài),之后開(kāi)始接收數(shù)據(jù),完整代碼如下:

void EXTI0_IRQHandler(void)
{
    uint32_t current_time = 0;
    uint32_t time_interval = 0;

    // 檢查是否是該EXTI線產(chǎn)生的中斷
    if (EXTI_GetITStatus(IR_EXTI_LINE) != RESET)
    {
        // 獲取當(dāng)前時(shí)間
        current_time = Get_32bit_Timer_Value();

        // 計(jì)算時(shí)間間隔
        time_interval = current_time - ir_last_time;

        // 如果是第一個(gè)數(shù)據(jù)點(diǎn)或者是接收狀態(tài),則記錄時(shí)間
        if (ir_state == IR_IDLE)
        {
            // 第一個(gè)邊沿,開(kāi)始接收數(shù)據(jù)
            ir_state = IR_RECEIVING;
            ir_data_count = 0;
            ir_data_ready = 0;
        }

        // 存儲(chǔ)時(shí)間數(shù)據(jù)(如果緩沖區(qū)未滿)
        if (ir_data_count < IR_DATA_BUFFER_SIZE)
        {
            ir_time_data[ir_data_count] = time_interval;
            ir_data_count++;
        }

        // 更新時(shí)間
        ir_last_time = current_time;

        // 清除中斷標(biāo)志位
        EXTI_ClearITPendingBit(IR_EXTI_LINE);
    }
}

我們還需要一個(gè)判斷接收完畢的函數(shù),函數(shù)內(nèi)會(huì)聲明兩個(gè)全局靜態(tài)變量,分別是用于記錄上次進(jìn)入函數(shù)的時(shí)間 last_activity_time 和上次記錄的紅外數(shù)據(jù)計(jì)數(shù)值 previous_count。首先,我們需要判斷當(dāng)前紅外狀態(tài)是否是接收狀態(tài),其次,我們需要判斷紅外數(shù)據(jù)計(jì)數(shù)值不為 0。當(dāng)都滿足時(shí),開(kāi)始計(jì)算時(shí)間間隔,如果當(dāng)前的紅外數(shù)據(jù)計(jì)數(shù)值和上次的不一樣就重置 last_activity_time 并更新 previous_count,返回 0,否則判斷當(dāng)時(shí)間間隔超過(guò) 10ms 時(shí)就認(rèn)為紅外接收完成并返回 1,并重置一些參數(shù)。完整代碼如下:

uint8_t IR_Is_Ready(void)
{
    // 如果正在接收數(shù)據(jù)且有數(shù)據(jù)
    if (ir_state == IR_RECEIVING && ir_data_count > 0)
    {
        // 使用全局靜態(tài)變量來(lái)跟蹤超時(shí)
        static uint32_t last_activity_time = 0;
        static uint16_t previous_count = 0;
        uint32_t current_time = Get_32bit_Timer_Value();

        // 如果數(shù)據(jù)計(jì)數(shù)發(fā)生變化,說(shuō)明有新的數(shù)據(jù)到來(lái)
        if (previous_count != ir_data_count)
        {
            previous_count = ir_data_count;
            last_activity_time = current_time;
        }
        else
        {
            // 數(shù)據(jù)計(jì)數(shù)沒(méi)有變化,檢查是否超時(shí)
            uint32_t time_since_last_activity = current_time - last_activity_time;

            // 如果超過(guò)10ms沒(méi)有新數(shù)據(jù),認(rèn)為接收完成
            if (time_since_last_activity > 10000) // 10ms = 10000us
            {
                // 設(shè)置數(shù)據(jù)就緒標(biāo)志
                ir_data_ready = 1;
                ir_state = IR_IDLE;
                // 重置跟蹤變量
                previous_count = 0;
                return 1;
            }
        }
        return 0;
    }

    return 0;
}

在主循環(huán)里輪詢 IR_Is_Ready,如果返回為 1,則說(shuō)明數(shù)據(jù)就緒,開(kāi)始紅外學(xué)習(xí),調(diào)用函數(shù) ir_learn,ir_learn 函數(shù)用于重復(fù)獲取紅外信號(hào),用于后續(xù)濾波。在函數(shù)內(nèi)也會(huì)計(jì)時(shí),當(dāng)超過(guò) 30s 后,認(rèn)為紅外學(xué)習(xí)失敗,若在 30s 內(nèi)完成 3 次紅外接收,則認(rèn)為紅外學(xué)習(xí)成功,并開(kāi)始均值濾波。均值濾波即將數(shù)組相同下標(biāo)的值相加并除以數(shù)組的個(gè)數(shù)。濾波后通過(guò)串口打印紅外時(shí)間序列。完整代碼如下:

/**
 * @brief  對(duì)二維數(shù)組進(jìn)行均值濾波處理
 * @param  dataCount: 每個(gè)一維數(shù)組中有效數(shù)據(jù)的個(gè)數(shù)
 */
void IR_Mean_Filter(uint8_t dataCount)
{
    uint16_t i;
    uint32_t sum;
    uint16_t mean_value;

    // 對(duì)每個(gè)數(shù)據(jù)位置進(jìn)行均值濾波
    for (i = 0; i < dataCount && i < IR_DATA_BUFFER_SIZE; i++)
    {
        sum = 0;

        // 累加所有數(shù)組在同一位置的值
        for (unsigned char j = 0; j < 3; j++)
        {
            sum += receive_data[j][i];
        }

        // 計(jì)算均值
        mean_value = (uint16_t)(sum / 3);

        // 存儲(chǔ)到濾波后的數(shù)據(jù)數(shù)組中
        filtering_data[i] = mean_value;
    }
}

void ir_learn()
{
    // 計(jì)數(shù)
    unsigned char count = 0;
    unsigned char successFlag = 0;
    unsigned int dataCount = 0;

    IR_Get_Time_Data(receive_data[count], IR_Get_Data_Count());
    // 獲取紅外數(shù)據(jù)數(shù)量
    dataCount = IR_Get_Data_Count();
    IR_Clear_Data();
    count++;

    // 啟動(dòng)30s計(jì)時(shí)
    RTC_30Sec_Start();

    while (!RTC_30Sec_IsTimeout())
    {
        if (IR_Is_Ready())
        {
            IR_Get_Time_Data(receive_data[count], IR_Get_Data_Count());
            IR_Clear_Data();
            count++;

            if (count == 3)
            {
                successFlag = 1;
                break;
            }
        }
    }

    RTC_30Sec_Stop();

    if (!successFlag)
    {
        // 超時(shí),停止紅外學(xué)習(xí),并返回
        printf("timeout return rn");
        return;
    }

    // 均值濾波
    IR_Mean_Filter(dataCount);

    printf("IR learn success rn");
    printf("length:%d,紅外時(shí)間序列:rn", dataCount);
    for (unsigned int i = 1; i < dataCount; i++)
    {
        printf("%drn", filtering_data[i]);
    }
    printf("rn");
}

主函數(shù)代碼

主函數(shù)完整代碼如下:

#include "bsp_rcc.h"
#include "bsp_tim.h"
#include "bsp_uart.h"
#include "delay.h"
#include "do_mqtt.h"
#include "socket.h"
#include "stdlib.h"
#include "wiz_interface.h"
#include "wizchip_conf.h"
#include < stdio.h >
#include < stdlib.h >
#include < string.h >

#include "IR_Control.h"
#include "IR_Receive.h"
#include "RTC.h"
#include "ir_ac_control.h"

#define SOCKET_ID 0
#define ETHERNET_BUF_MAX_SIZE (1024 * 2)

/* 網(wǎng)絡(luò)配置信息 */
wiz_NetInfo default_net_info = {
    .mac = {0x00, 0x08, 0xdc, 0x12, 0x22, 0x05},
    .ip = {192, 168, 2, 40},
    .gw = {192, 168, 2, 1},
    .sn = {255, 255, 255, 0},
    .dns = {8, 8, 8, 8},
    .dhcp = NETINFO_DHCP};

uint8_t        ethernet_buf[ETHERNET_BUF_MAX_SIZE]           = {0};
static uint8_t mqtt_send_ethernet_buf[ETHERNET_BUF_MAX_SIZE] = {0};
static uint8_t mqtt_recv_ethernet_buf[ETHERNET_BUF_MAX_SIZE] = {0};

// 第三方庫(kù)IRext定義的結(jié)構(gòu)體,用于存儲(chǔ)空調(diào)狀態(tài)
t_remote_ac_status ac_status;
// 品牌
unsigned char brand = 0;
// 型號(hào)
unsigned char type = 0;
// 操作類型
unsigned char operation = 0;

int main(void)
{

    // 時(shí)鐘初始化,使能外部高速晶振時(shí)鐘,主頻倍頻至為216MHz,PCLK1、PCLK2都設(shè)為216MHz
    rcc_clk_config();

    delay_init();

    console_usart_init(115200);

    tim3_init();

    printf("Infrared Remote Control Gatewayrn");

    wiz_toe_init();

    wiz_phy_link_check();

    network_init(ethernet_buf, &default_net_info);

    // 紅外初始化
    ir_Config();
    IR_Receive_Init();

    // rtc 時(shí)鐘初始化
    RTC_Init();

    mqtt_init(SOCKET_ID, mqtt_send_ethernet_buf, mqtt_recv_ethernet_buf);

    while (1)
    {
        do_mqtt();

        // 檢查是否收到紅外發(fā)送命令
        if (IR_is_send())
        {
            printf("start IR controlrn");

            // 紅外控制
            ir_Control(brand, type, operation, &ac_status);

            Reset_IR_Send();

            // 清除紅外接收到的數(shù)據(jù),避免觸發(fā)紅外學(xué)習(xí)
            IR_Clear_Data();
        }

        // 檢查是否收到紅外學(xué)習(xí)命令
        if (IR_is_learn())
        {
            printf("start IR learnrn");

            ir_Learn(getFileName());

            Reset_IR_learn();
        }
    }
}

4.功能驗(yàn)證

經(jīng)過(guò)驗(yàn)證,目前的功能能夠穩(wěn)定運(yùn)行。

5.結(jié)語(yǔ)

基于 W55MH32Q-EVB 構(gòu)建的紅外遙控?關(guān),以其獨(dú)特的技術(shù)優(yōu)勢(shì)為智能家居領(lǐng)域的紅外設(shè)備控制提供了全新解決?案。W55MH32Q 芯?的?性能內(nèi)核與全硬件?絡(luò)協(xié)議棧,確保了數(shù)據(jù)處理與通信的?效穩(wěn)定,讓微信?程序與?關(guān)的交互響應(yīng)迅速。

IRext 紅外庫(kù)的靈活移植,突破了品牌壁壘,實(shí)現(xiàn)了多品牌空調(diào)的統(tǒng)?控制;JSON 數(shù)據(jù)解析則讓指令傳遞更精準(zhǔn)?效。從硬件設(shè)計(jì)到軟件實(shí)現(xiàn),整個(gè)系統(tǒng)?縫銜接,既解決了傳統(tǒng)遙控器混亂的痛點(diǎn),?降低了智能家居改造的門檻。

未來(lái),隨著功能的進(jìn)?步拓展,該?關(guān)有望兼容更多類型的紅外設(shè)備,為?戶帶來(lái)更便捷、智能的?活體驗(yàn),也為紅外設(shè)備的智能化升級(jí)提供了可借鑒的技術(shù)范式。

感謝?家的耐?閱讀,想了解紅外學(xué)習(xí)、irext 紅外庫(kù),F(xiàn)atFs 文件系統(tǒng)的請(qǐng)關(guān)注我。后續(xù)會(huì)更新文章。另外,如果你在閱讀過(guò)程中有任何疑問(wèn),歡迎隨時(shí)通過(guò)私信留?。我會(huì)盡快回復(fù)消息。

審核編輯 黃宇

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 單片機(jī)
    +關(guān)注

    關(guān)注

    6076

    文章

    45479

    瀏覽量

    669622
  • 網(wǎng)關(guān)
    +關(guān)注

    關(guān)注

    9

    文章

    6731

    瀏覽量

    56166
  • 智能家居
    +關(guān)注

    關(guān)注

    1943

    文章

    9989

    瀏覽量

    197314
  • 紅外控制
    +關(guān)注

    關(guān)注

    0

    文章

    26

    瀏覽量

    11857
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    智能紅外遙控開(kāi)關(guān)控制器

    遙控器都是針對(duì)各自產(chǎn)品所設(shè)計(jì)的。當(dāng)你在用遙控器對(duì)兩個(gè)或兩個(gè)以上的LED調(diào)光時(shí)你會(huì)發(fā)現(xiàn),有的接收到了,有的沒(méi)有接收到;當(dāng)你遙控器丟掉了的時(shí)候,你需要重新去買一個(gè)新的遙控器。等等一系列的問(wèn)
    發(fā)表于 10-30 22:59

    云智能紅外轉(zhuǎn)WIFI網(wǎng)關(guān)

    )和智能WIFI模塊,恒眾鑫智能技術(shù)開(kāi)發(fā)了云智能紅外轉(zhuǎn)WIFI網(wǎng)關(guān)和App。從恒眾鑫云智能紅外控制器App功能上面看,解決了用戶通過(guò)手機(jī)遠(yuǎn)程家庭紅外
    發(fā)表于 05-05 14:03

    紅外學(xué)習(xí)與接收

    各位大神,請(qǐng)教一下,這個(gè)電路,四個(gè)LED是紅外發(fā)射燈,J1是一個(gè)紅外延長(zhǎng)線的插孔 請(qǐng)問(wèn)這個(gè)電路可以用來(lái)紅外學(xué)習(xí)嗎?如果紅外延長(zhǎng)線的插孔接入紅外
    發(fā)表于 12-10 09:46

    基于紅外學(xué)習(xí)的離線語(yǔ)音控制低成本方案

    匹配方法都需要用戶進(jìn)行一系列復(fù)雜操作,并且一般需要嘗試多次才能夠正確匹配,無(wú)疑增加了用戶的使用難度。 針對(duì)碼庫(kù)匹配問(wèn)題,啟英泰倫研發(fā)了空調(diào)庫(kù)以及匹配方法,可以通過(guò)分析原始遙控器所發(fā)射
    發(fā)表于 11-10 17:16

    基于紅外遙控的智能語(yǔ)音芯片在空調(diào)中的應(yīng)用

    紅外應(yīng)用方案覆蓋多家空調(diào)庫(kù),可支持市面95%以上的空調(diào)型號(hào),3秒一鍵極速匹配,在安靜環(huán)境下可實(shí)現(xiàn)最遠(yuǎn)10米遠(yuǎn)場(chǎng)識(shí)別。該
    發(fā)表于 11-11 11:12

    紅外遙控的相關(guān)資料下載

    目前很多遙控器還是采用的紅外,如電視機(jī)、空調(diào)等,有時(shí)項(xiàng)目需要把遙控嵌入式自己的設(shè)備中,進(jìn)行智能控制,此時(shí)就需要智能
    發(fā)表于 01-25 06:42

    用ESP8266實(shí)現(xiàn)紅外學(xué)習(xí)遙控器介紹

    一、介紹這是一個(gè)用ESP8266實(shí)現(xiàn)紅外學(xué)習(xí)遙控器,代碼可以直接Arduino刷上哈~其它的稍后再說(shuō);二、接線&使用方法如果懶得改代碼想先試試,可以直接把紅外發(fā)射接在D2上;
    發(fā)表于 01-27 07:10

    紅外遙控開(kāi)關(guān)

    紅外遙控開(kāi)關(guān) 如圖所示為紅外遙控開(kāi)關(guān),由紅外
    發(fā)表于 07-27 11:29 ?2547次閱讀

    紅外遙控AB開(kāi)關(guān)

    紅外遙控AB開(kāi)關(guān) 紅外
    發(fā)表于 09-18 14:27 ?1750次閱讀
    <b class='flag-5'>紅外</b><b class='flag-5'>遙控</b>AB<b class='flag-5'>開(kāi)關(guān)</b>

    基于NiosⅡ的紅外學(xué)習(xí)遙控器設(shè)計(jì)

      本文設(shè)計(jì)了一種基于NiosⅡ的紅外學(xué)習(xí)遙控器,把載波頻率測(cè)量、紅外信號(hào)解調(diào)、脈寬測(cè)量、調(diào)制發(fā)送IP核集中到FPG
    發(fā)表于 12-15 10:39 ?3056次閱讀

    基于51系列單片機(jī)的紅外遙控設(shè)計(jì)

    紅外遙控是目前使用最廣泛的一種通信和遙控手段,,本文介紹了單片機(jī)系統(tǒng)中紅外通信的軟硬件設(shè)計(jì)方法,并給出了具體的電路,本方法
    發(fā)表于 07-10 11:05 ?954次下載
    基于51系列單片機(jī)的<b class='flag-5'>紅外</b><b class='flag-5'>遙控</b>設(shè)計(jì)

    通用的紅外遙控開(kāi)關(guān)設(shè)計(jì)與實(shí)現(xiàn)

    通用的紅外遙控開(kāi)關(guān)設(shè)計(jì)與實(shí)現(xiàn)
    發(fā)表于 06-27 10:04 ?43次下載

    ESP8266紅外學(xué)習(xí)遙控

    一、介紹這是一個(gè)用ESP8266實(shí)現(xiàn)紅外學(xué)習(xí)遙控器,代碼可以直接Arduino刷上哈~其它的稍后再說(shuō);二、接線&使用方法如果懶得改代碼想先試試,可以直接把紅外發(fā)射接在D2上;
    發(fā)表于 12-03 17:51 ?24次下載
    ESP8266<b class='flag-5'>紅外學(xué)習(xí)</b><b class='flag-5'>遙控</b>器

    智能學(xué)習(xí)紅外空調(diào)遙控器的設(shè)計(jì)與實(shí)現(xiàn)

    本文設(shè)計(jì)的是一款基于單片機(jī)的紅外智能空調(diào)遙控器,這種遙控器能采用測(cè)量脈沖寬度的方法學(xué)習(xí)紅外信號(hào),
    發(fā)表于 02-11 14:11 ?28次下載
    智能<b class='flag-5'>學(xué)習(xí)</b>型<b class='flag-5'>紅外</b><b class='flag-5'>空調(diào)</b><b class='flag-5'>遙控</b>器的設(shè)計(jì)與<b class='flag-5'>實(shí)現(xiàn)</b>

    紅外學(xué)習(xí)遙控器方案說(shuō)明

    紅外學(xué)習(xí)遙控器可通過(guò)學(xué)習(xí)操作學(xué)習(xí)其它遙控器上的部分按鍵,實(shí)現(xiàn)同一
    的頭像 發(fā)表于 10-18 11:31 ?6160次閱讀