博客專欄

        EEPW首頁 > 博客 > 程序員為女友DIY一款紅外線遙控器,感動哭了

        程序員為女友DIY一款紅外線遙控器,感動哭了

        發布人:智能物聯研習社 時間:2021-01-09 來源:工程師 發布文章

        身為一位資深電子發燒友,他經常自己動手將家中傳統電器改造成智能電器。此次,該同學基于涂鴉 IoT 開發工具,使用涂鴉 WBR1D 云模組、紅外遙控器外殼等器材,借助涂鴉智能紅外遙控開源硬件開發資料,將家中空調改造成智能空調,可通過手機 App 輕松控制。

        以下內容為涂鴉開發者“李勇”創作,經其授權編輯發布:


        參加此次涂鴉智能&立創EDA實戰訓練營,要求做物聯網相關項目,使用涂鴉的云模組。一提到云,我最先想到的是智能家居,自己平時工作之余,也做了不少與物聯網相關的項目,做的大大小小的項目不少,家里電器差不多都自己動手改造成智能的。

        正好最近有做紅外遙控空調的想法。冬天來了,早上起床太早都不敢掀被子(太冷),一直想改造成智能的,用手機控制,支持定時開啟/關閉,智能場景聯動。加上工作原因,有涂鴉智能的云開發需求,所以參加此次訓練營。

        功能設計

        要實現空調控制,就是要發送紅外信號,所以要有紅外發送功能。市面上空調種類繁多,肯定要適用多種品牌和機型,所以要有紅外學習功能。要支持場景聯動,就要有環境感知傳感器。要支持手機控制,就要有云端和模組。

        綜上,設計功能有:

        1、紅外發送(紅外****管);

        2、紅外學習(一體化接收頭);

        3、室內溫度檢測(DHT11);

        4、手機控制(通過涂鴉云模組實現)。

        成品效果

        在實際場景中,空調的安裝位置一般都不固定,所以,紅外控制器不能近距離控制。參考其他大品牌紅外控制器設計,采用壁掛式設計,可以掛在天花板或墻壁上。

        控制板全部用立創EDA繪制,自己手工貼片,涂鴉云模組上面的文字是被清洗劑洗掉了,操作時大意了。


        使用的公模外殼,安裝效果如下。


        硬件設計

        1.電源

        電源部分采用Micro USB接口,直接提供5V電源,經過內部分壓得到3.3V電壓,為MCU、涂鴉云模組和外圍電路供電。降壓采用TI的TLV62569DBVR電源芯片,外圍器件少,功率大,紋波小。


        2.云模組

        采用涂鴉智能提供的WBR1D-IPEX云模組,WBR1D是雙頻雙模模組,支持WI-FI和藍牙,采用MCU接入方案,通過串口與MCU連接。


        3.MCU

        MCU采用ST的STM32F103C8T6,64K的Flash。

        4.紅外****

        紅外****采用紅外管,因為是壁掛式安裝方式,所以對控制范圍有要求,本設計中采用8顆紅外****管并聯,每科管子由一顆大功率三極管驅動,所有三極管由一個控制端驅動。以提高****功率,提高****功率后,紅外控制范圍會明顯擴大。(多顆紅外管最好并聯控制,不要為畫PCB方便或者節省器件而選擇串聯,串聯的管子都不會正常工作,****功率會大幅度下降。)


        5.紅外接收

        紅外接收比較簡單,直接采用一體化接收頭。


        6.附加電路

        按鍵

        按鍵用于配網使用,但是在實際調試時,模組會自動配網,所以按鍵改為清除紅外預存的數據。

        LED

        LED用于指示配網狀態和進入紅外學習模式,以及故障閃爍。

        DHT11

        DHT11用于檢測室內溫濕度,在本設計中,紅外遙控器作為單品使用,DHT11可以向云端上報室內溫度、濕度,可實現智能場景聯動。

        7.PCB設計

        PCB設計時,因為是壁掛式,所以選了一個公模外殼。在設計時器件布局和PCB外形要符合外殼尺寸。

        外殼:


        PCB:初版PCB有幾個錯誤,按鍵位置與LED位置反了,絲印錯誤,已經更新。


        軟件設計

        1.紅外接收實現

        紅外接收比較簡單,如果是易于解析的NEC格式編碼,直接用定時器捕獲外部輸入電平時間長度即可,對于不易解析的編碼(廠家自定義的編碼)采用外部中斷和定時器方式測電平時間長度。對于NEC格式編碼,按照NEC編碼格式的規范,先判斷低電平時間,通過長度區分起始碼、數據碼和結束碼。網上例程比較多,這里就不贅述了,要注意的是:有的廠家空調雖然是NEC編碼,但是他們的編碼中高低電平長度一般都不同,所以在中斷中判斷電平長度時,要注意設置范圍。

        2.紅外****實現

        紅外****是紅外管完成,注意:紅外管不****紅外在接收端輸出1,****紅外在接收端輸出是0,這里要注意區分。

        實現方式用定時器輸出一個38K的方波,控制方波輸出的時間長度即可實現發送不同的數據和編碼。本項目采用兩個定時器來實現發送紅外,TIM1輸出38K載波,TIM3定時,由TIM3計時,控制TIM1輸出/關閉PWM,這樣可以實現任意時間長度發送。但是這樣比較耗費MCU資源,對于STM32來說,影響不大,對于小型MCU就要考慮資源了。

        下面是實現紅外發送的關鍵代碼:

        發送一組完整紅外編碼Inf_RX_NECcoding()

        void Inf_RX_NECcoding(uint8_t *pbuff,uint8_t Length,uint8_t quantity){    uint8_t i;
            TIM_CtrlPWMOutputs(TIM1,ENABLE);  //開輸出
            TIM_Cmd(TIM3,ENABLE);  //開定時器
            TIM_Cmd(TIM1,ENABLE);    
          while(Inf_RX_StartCode()); //起始碼
            
            if(Length>InfraredDataLength)  //數據有效長度限制
                Length = InfraredDataLength;  
            
            for(i=0;i<Length;i++)    //發送數據
              Inf_RX_Data(pbuff[i],Right); 
            
            while(Inf_RX_Stop());  //結束碼
            
            while(Inf_RX_Interval()); //間隔碼
            
            while(Inf_RX_StartCode());  
            
            if(Length>InfraredDataLength)
                Length = InfraredDataLength; 
            
            for(i=0;i<Length;i++)
              Inf_RX_Data(pbuff[i],Right); 
            
            while(Inf_RX_Stop());  
            
            for(i=0;i<quantity;i++)  //重復發送
            while(Inf_SendRepeatedly());
            
            TIM_CtrlPWMOutputs(TIM1,DISABLE);  //關輸出    
            TIM_Cmd(TIM3,DISABLE);  //關定時器
            TIM_Cmd(TIM1,DISABLE);
        }

        數據發送(1個8位)

        uint8_t Inf_RX_StartCode(void)
        {    if(!retemp)
            {
                retemp=1;
                TimerOclk=0;
                TIM_SetCompare1(TIM1,1100); //設置占空比為50%         
            }    if(TimerOclk==441) //低電平時間到
                TIM_SetCompare1(TIM1,0); //設置占空比為0
            if(TimerOclk==881) //高電平時間到
            {
                retemp=0;
                TimerOclk=0; 
            }    return retemp; //狀態返回   }

        3.紅外學習功能

        本項目中只實現NEC編碼紅外學習,當按下手機端空間時,如果沒有指令,會自動進入學習狀態,等待發送紅外指令。紅外指令接收到以后,會自動保存。

        4.云功能實現

        因為使用涂鴉的MCU接入方案,云端只做功能和APP界面的配置,并下載MCU的SDK,將SDK移植到代碼中即可

        云端功能配置:


        APP界面配置:


        5.防跑飛

        在實際測試過程中遇到了,設備掉線和控制無反應問題,起初以為是網絡問題,更換網絡以后,問題依舊存在。

        拆下板子發現整個PCB發燙,測量MCU供電只有接近2V左右,照理說可以正常工作。拔掉電源,重插,MCU供電恢復。

        等待問題再次出現時,測得紅外管驅動三極管控制端一直是低電平,問題發現了:8顆紅外****管的****功率比較大,在關閉輸出時可能是被中斷打斷,導致關斷不成功,紅外管一直處于發送狀態,時間一長,8顆紅外管總電流增大,提供給MCU的電流減小,出現假死現象。

        為了解決這個問題,增加了三道防線,一是每次發送完成后將輸出和定時器一起關閉,這樣可以減少中斷沖突的機率。二是增加STM32內部測溫,一旦檢測到溫度超過允許值,再關定時器和PWM輸出1次,如果超過警報值,直接復位MCU。三是增加看門狗,定時喂狗,防止假死和程序跑飛。

        加上這三道防線后,實測問題不再發生。

        關鍵點分析

        1.MCU_SDK 移植

        涂鴉提供配套的MCU SDK,具體使用方式涂鴉也提供很多的文檔,b站也有很多案例。我們只需要移植到MCU中即可,通過串口通訊,實現MCU接入。注意接涂鴉模組串口的波特率,一般默認是9600,也可以修改為115200,具體在云端控制臺的硬件開發->模組固件中修改。在移植時有以下幾個地方要注意:

        **mcu_api.c**

        1)串口接收函數uart_receive_input(),要用中斷法接收,防止數據丟包

        涂鴉提供串口數據接收緩存和數據處理方法,我們不需要再單獨去做處理,只需要在串口接收中斷里面調用uart_receive_input()函數即可。

        //USART2中斷服務函數void USART2_IRQHandler(void)                {
          uint8_t value ;  if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  //接收中斷
            {   value = USART_ReceiveData(USART2);   //讀取接收數據        
             uart_receive_input(value); //數據存入涂鴉緩沖器
            }       
        }

        2)數據輪詢函數wifi_uart_service(),要輪詢這個函數,不然模組下發的數據MCU接收不到。放在主循環里面就行。

        while (1)
        {       
            wifi_uart_service(); //輪詢涂鴉數據
            /*
              用戶其他函數
            */}

        3)協議初始化函數wifi_protocol_init(),這是為涂鴉串口數據提供一個緩存空間,在初始化中調用,初始化后不需要再調用。

        int main(void){   
            wifi_protocol_init(); //涂鴉模組協議初始化
            /*
              用戶其他初始化函數
            */
            while(1)
            {
               wifi_uart_service(); //輪詢涂鴉數據
            /*
              用戶其他函數
            */          
            }
        }

        **protocl.c**

        1)串口發送函數uart_transmit_output(),用調用法發送,也可以用中斷。

        涂鴉提供串口發送數據處理方法,我們也不需要再單獨去做處理,只需要將串口發送語句放在uart_transmit_output()函數里即可。

        void uart_transmit_output(unsigned char value){ 
          while((USART2->SR &(1<<7))==0);  
            USART2->DR = value;
        }

        2)所有數據上報函數all_data_update()

        我們要在all_data_update函數中實現設備數據的傳入,涂鴉模組或向MCU申請返回設備全部數據,設備數據通過all_data_update函數發送,所以要把設備的數據項傳入到對應的函數中。注意:這個函數根據自己云端定義的功能對應,不能直接添加。

        void all_data_update(void)
        {   
            //此代碼為平臺自動生成,請按照實際數據修改每個可下發可上報函數和只上報函數  
            mcu_dp_bool_update(DPID_SWITCH,AirControlStructure.AirPowerControl); //BOOL型數據上報; //當前開關
            mcu_dp_value_update(DPID_TEMP_SET,AirControlStructure.AirRunTemper); //VALUE型數據上報;  //當前溫度設置    //    mcu_dp_value_update(DPID_TEMP_CURRENT,AirControlStructure.AirRunTemper); //VALUE型數據上報;  //當前當前溫度  
            mcu_dp_enum_update(DPID_MODE,AirControlStructure.AirRunMode); //枚舉型數據上報; //當前工作模式   
            mcu_dp_enum_update(DPID_FAN_SPEED_ENUM,AirControlStructure.AirRunFan); //枚舉型數據上報; //當前風速    //    mcu_dp_enum_update(DPID_STATUS,AirControlStructure.AirRunFlag); //枚舉型數據上報;  //當前狀態    
            mcu_dp_bool_update(DPID_AUTO,AirControlStructure.AirForceful); //BOOL型數據上報; //當前自動模式    
            mcu_dp_bool_update(DPID_HEAT,AirControlStructure.AirHeat); //BOOL型數據上報;  //當前輔熱  }

        3)單個數據下發處理函數,在protocl.c中涂鴉定義了與功能對應的處理函數,我們要在對應函數中實現控制代碼。示例

        static unsigned char dp_download_switch_handle(const unsigned char value[], unsigned short length)    //開關{    //示例:當前DP類型為BOOL
            unsigned char ret;    //0:關/1:開
            unsigned char switch_1;
            
            switch_1 = mcu_get_dp_download_bool(value,length);    if(switch_1 == 0) {
                AirControlStructure.AirPowerControl=OFF;//關
                AirControlStructure.AirHeat = OFF;       //輔熱關
                AirControlStructure.AirForceful = OFF;   //強勁關
            }else {
                AirControlStructure.AirPowerControl=ON; //開         
            }       
            AirControlInfRX(); //發送紅外代碼
          
            //處理完DP數據后應有反饋
            ret = mcu_dp_bool_update(DPID_SWITCH,switch_1);    if(ret == SUCCESS)        return SUCCESS;    else
                return ERROR;
        }

        其實MCU接入方案,就是串口通訊。涂鴉提供有SDK,在云端定義好功能,配置好固件和APP面板,下載SDK包,移植到MCU代碼中就可以用,不要單獨做函數設置配網,上云等繁瑣的工序。這對產品研發者來講,不管是測試,還是研發,都是非常友好的。

        2.空調控制

        以上工作完成后,重點來了,代碼寫得再漂亮,電路設計再完美,控制不了空調都等于0。大家都知道空調是紅外遙控控制,所以本項目就是****空調遙控器****的紅外編碼,代替遙控器控制空調。這里的難點在于如何獲得空調的紅外編碼,目前市面上銷售的空調,紅外編碼都是廠家自定義的。售后或者說明書里面也不會提供具體的編碼協議,所以只能自己去解析。下面簡述解析過程,解析篇幅較多,詳細內容請移步“閱讀原文”

        首先要獲得紅外的編碼,我的方式是用邏輯分析儀和紅外接收頭,按遙控器的一個鍵,查看分析儀捕獲的波形,通過波形解析出數據,這個過程不難,但是很繁瑣。


        以開機為例,按下開機鍵,遙控器發送一組紅外編碼,邏輯分析儀捕獲到波形,如圖


        重復按下開機鍵,每次分析儀捕獲的波形都相同,將波形放大后打印,如圖:


        這就是完整的一組紅外波形,我只要發送與這組波形一樣的編碼即可控制空調開機。但是現在只是知道了電平變換時間,具體變換的時間長度代表什么還不知道。但是通過這組完整的波形可以看出,它是符合NEC編碼格式(不了解NEC紅外編碼格式的,請先查查相關資料),只是電平變換時間長度略有不同而已,所以先嘗試用NEC編碼接收程序試一下。通過NEC編碼紅外接收程序測試,發現能夠接收到數據:


        那么現在直接發送這組紅外數據,就能控制空調開機。但是實測沒有辦法控制,空調無反應。反過來查看邏輯分析儀捕獲的波形,這個波形與標準NEC編碼的****波形除了高低電平變換時間長度不同,總長度也不同。細看這個開機波形,它的前半部分和后半部分是相同,按照NEC格式截取前后半個部分波形,

        前半部分:


        后半部分:


        驚奇發現它們的起始碼、數據碼是相同的,結束碼略有不同,由此可以看出,這個紅外編碼是由兩幀構成,兩幀之間有一個中間碼,是連接以及第一幀和第二幀用的。將第一幀波形、第二幀波形和完整波形,得到中間碼的波形。


        通過邏輯分析儀得出,中間的電平變化時間關系:



        由此,解析出起始碼、數據碼、中間碼和結束碼的電平變化時間間隔,按照解析的接收重新定義紅外發送函數,測試能正常開機。

        3.App功能配置

        App界面除了默認功能外,加了部分功能,因為使用的公版APP界面,所以界面UI和功能自定義的范圍有限,后期會改成面板SDK開發,現階段時間不多,做不了開發。

        以強勁功能為例,本項目設計時,沒有添加強勁功能。現在要添加,首先進入涂鴉IoT開發平臺,找到項目,進入APP面板配置頁面,在頁面點擊“編輯”,


        進入編輯頁面,先選擇按鈕添加的位置,這里添加到更多頁面


        配置好屬性和關聯功能以后,點擊發布,涂鴉會自動打包,打包好了以后,會提供測試二維碼,掃二維碼可以測試這個面板,如果測試通過點正式發布,發布以后,手機端退出“涂鴉智能”APP,重新進入,添加的功能就生效。

        總結

        這次使用涂鴉智能,不管是整體開發流程,還是技術服務,涂鴉做得非常好。

        涂鴉模組提供MCU SDK,用戶只需要移植到MCU OS中,即可完成上云操作,節省研發和調試周期。

        涂鴉提供的穩定MCU接入模組SDK,減少用戶程序邏輯架構不嚴謹造成的錯誤,減輕用戶底層代碼量。

        涂鴉技術支持服務也非常周到,不定期詢問開發者是否有問題需要解決,這點比某科模組做的好。

        如果想自己親自動手DIY的,可以戳:

        https://auth.tuya.com/?_source=7c8653b7bd61bf9239a1a6c12e52124d


        還在等什么!為女友DIY創造一個溫暖舒適的家居生活,低成本改造自家空調可真是真香系列~撒花~建議:涂鴉能開放模組的二次服務,為開發者和物聯網設備廠商提供更多的自定義服務和功能,相信會受到更多開發者和物聯網愛好者的青睞。


        *博客內容為網友個人發布,僅代表博主個人觀點,如有侵權請聯系工作人員刪除。



        關鍵詞: 嵌入式 工程師

        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 东丰县| 怀远县| 色达县| 永安市| 绥芬河市| 唐海县| 临澧县| 黄浦区| 达孜县| 腾冲县| 晋中市| 冷水江市| 思南县| 攀枝花市| 新疆| 郓城县| 瑞昌市| 怀宁县| 漠河县| 庆云县| 闵行区| 通道| 渑池县| 高邑县| 黄石市| 七台河市| 靖远县| 石河子市| 正安县| 专栏| 重庆市| 文成县| 罗城| 宝山区| 余干县| 文昌市| 南川市| 越西县| 城口县| 青神县| 九龙坡区|