嵌入式MCU常用模塊

日后填坑。

無線通信模塊

2.4G

基本介紹

以NRF24L01為例。

NRF24L01是一款2.4GHz的無線收發模塊,支持SPI通信協議,具有低功耗、高數據速率(250kbps-2Mbps)和多設備通信能力。

它可以同時與最多6個其他模塊通信,適合用于小型網絡和遠程控制應用

使用方法

  1. 初始化:配置SPI通信和GPIO引腳,設置工作模式(發送或接收)、地址、頻率等參數。
  2. 檢測模塊:通過SPI寫入已知數據,再讀取并驗證數據是否一致,判斷模塊是否存在。
  3. 發送數據:進入發送模式,寫入數據到緩沖區,啟動發送,等待發送完成并檢查狀態。
  4. 接收數據:進入接收模式,等待接收完成,讀取數據并檢查狀態。
  5. 模式切換:通過CE引腳控制模塊在發送和接收模式之間切換。

日后填坑。

注意:

數據通道0 是唯一的一個可以配置為40 位自身地址的數據通道。1~5 數據通道都為8 位自身地址和32 位公用地址。

示例代碼

基于STM32 HAL庫

.c文件

extern SPI_HandleTypeDef g_spi2_handler;             /* SPI2句柄 */
//const uint8_t TX_ADDRESS[TX_ADR_WIDTH] = {0x34, 0x43, 0x10, 0x10, 0x01};    /* 發送地址 */
//const uint8_t RX_ADDRESS[RX_ADR_WIDTH] = {0x34, 0x43, 0x10, 0x10, 0x01};    /* 接收地址 *///這里設置是通道0 因此地址可以自己定義
const uint8_t TX_ADDRESS[TX_ADR_WIDTH] = {0x11, 0x11, 0x66, 0x66, 0x00};    /* 發送地址 */
const uint8_t RX_ADDRESS[RX_ADR_WIDTH] = {0x11, 0x11, 0x66, 0x66, 0x00};    /* 接收地址 *//*** @brief       針對NRF24L01修改SPI2驅動* @param       無* @retval      無*/
void nrf24l01_spi_init(void)
{__HAL_SPI_DISABLE(&g_spi2_handler);                 /* 先關閉SPI2 */g_spi2_handler.Init.CLKPolarity = SPI_POLARITY_LOW; /* 串行同步時鐘的空閑狀態為低電平 */g_spi2_handler.Init.CLKPhase = SPI_PHASE_1EDGE;     /* 串行同步時鐘的第1個跳變沿(上升或下降)數據被采樣 */HAL_SPI_Init(&g_spi2_handler);__HAL_SPI_ENABLE(&g_spi2_handler);                  /* 使能SPI2 */
}/*** @brief       初始化24L01的IO口*   @note      將SPI2模式改成SCK空閑低電平,及SPI 模式0* @param       無* @retval      無*/
void nrf24l01_init(void)
{GPIO_InitTypeDef gpio_init_struct;NRF24L01_CE_GPIO_CLK_ENABLE();  /* CE腳時鐘使能 */NRF24L01_CSN_GPIO_CLK_ENABLE(); /* CSN腳時鐘使能 */NRF24L01_IRQ_GPIO_CLK_ENABLE(); /* IRQ腳時鐘使能 */gpio_init_struct.Pin = NRF24L01_CE_GPIO_PIN;gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;             /* 推挽輸出 */gpio_init_struct.Pull = GPIO_PULLUP;                     /* 上拉 */gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;           /* 高速 */HAL_GPIO_Init(NRF24L01_CE_GPIO_PORT, &gpio_init_struct); /* 初始化CE引腳 */gpio_init_struct.Pin = NRF24L01_CSN_GPIO_PIN;HAL_GPIO_Init(NRF24L01_CSN_GPIO_PORT, &gpio_init_struct);/* 初始化CSN引腳 */gpio_init_struct.Pin = NRF24L01_IRQ_GPIO_PIN;gpio_init_struct.Mode = GPIO_MODE_INPUT;                 /* 輸入 */gpio_init_struct.Pull = GPIO_PULLUP;                     /* 上拉 */gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;           /* 高速 */HAL_GPIO_Init(NRF24L01_IRQ_GPIO_PORT, &gpio_init_struct);/* 初始化CE引腳 */spi2_init();                /* 初始化SPI2 */nrf24l01_spi_init();        /* 針對NRF的特點修改SPI的設置 */NRF24L01_CE(0);             /* 使能24L01 */NRF24L01_CSN(1);            /* SPI片選取消 */
}/*** @brief       檢測24L01是否存在* @param       無* @retval      0, 成功; 1, 失敗;*/
uint8_t nrf24l01_check(void)
{uint8_t buf[5] = {0XA5, 0XA5, 0XA5, 0XA5, 0XA5};uint8_t i;spi2_set_speed(SPI_SPEED_32);                         /* spi速度為7.5Mhz(24L01的最大SPI時鐘為10Mhz) */nrf24l01_write_buf(NRF_WRITE_REG + TX_ADDR, buf, 5);  /* 寫入5個字節的地址. */nrf24l01_read_buf(TX_ADDR, buf, 5);                   /* 讀出寫入的地址 */for (i = 0; i < 5; i++){if (buf[i] != 0XA5) break;}if (i != 5) return 1;   /* 檢測24L01錯誤 */return 0;               /* 檢測到24L01 */
}/*** @brief       NRF24L01寫寄存器* @param       reg   : 寄存器地址* @param       value : 寫入寄存器的值* @retval      狀態寄存器值*/
static uint8_t nrf24l01_write_reg(uint8_t reg, uint8_t value)
{uint8_t status;NRF24L01_CSN(0);                    /* 使能SPI傳輸 */status = spi2_read_write_byte(reg); /* 發送寄存器號 */spi2_read_write_byte(value);        /* 寫入寄存器的值 */NRF24L01_CSN(1);                    /* 禁止SPI傳輸 */return status;                      /* 返回狀態值 */
}/*** @brief       NRF24L01讀寄存器* @param       reg   : 寄存器地址* @retval      讀取到的寄存器值;*/
static uint8_t nrf24l01_read_reg(uint8_t reg)
{uint8_t reg_val;NRF24L01_CSN(0);            /* 使能SPI傳輸 */spi2_read_write_byte(reg);  /* 發送寄存器號 */reg_val = spi2_read_write_byte(0XFF);   /* 讀取寄存器內容 */NRF24L01_CSN(1);            /* 禁止SPI傳輸 */return reg_val;             /* 返回狀態值 */
}/*** @brief       在指定位置讀出指定長度的數據* @param       reg   : 寄存器地址* @param       pbuf  : 數據指針* @param       len   : 數據長度* @retval      狀態寄存器值*/
static uint8_t nrf24l01_read_buf(uint8_t reg, uint8_t *pbuf, uint8_t len)
{uint8_t status, i;NRF24L01_CSN(0);    /* 使能SPI傳輸 */status = spi2_read_write_byte(reg);         /* 發送寄存器值(位置),并讀取狀態值 */for (i = 0; i < len; i++){pbuf[i] = spi2_read_write_byte(0XFF);   /* 讀出數據 */}NRF24L01_CSN(1);    /* 關閉SPI傳輸 */return status;      /* 返回讀到的狀態值 */
}/*** @brief       在指定位置寫指定長度的數據* @param       reg   : 寄存器地址* @param       pbuf  : 數據指針* @param       len   : 數據長度* @retval      狀態寄存器值*/
static uint8_t nrf24l01_write_buf(uint8_t reg, uint8_t *pbuf, uint8_t len)
{uint8_t status, i;NRF24L01_CSN(0);    /* 使能SPI傳輸 */status = spi2_read_write_byte(reg);/* 發送寄存器值(位置),并讀取狀態值 */for (i = 0; i < len; i++){spi2_read_write_byte(*pbuf++); /* 寫入數據 */}NRF24L01_CSN(1);    /* 關閉SPI傳輸 */return status;      /* 返回讀到的狀態值 */
}/*** @brief       啟動NRF24L01發送一次數據(數據長度 = TX_PLOAD_WIDTH)* @param       ptxbuf : 待發送數據首地址* @retval      發送完成狀態*   @arg       0    : 發送成功*   @arg       1    : 達到最大發送次數,失敗*   @arg       0XFF : 其他錯誤*/
uint8_t nrf24l01_tx_packet(uint8_t *ptxbuf)
{uint8_t sta;uint8_t rval = 0XFF;NRF24L01_CE(0);nrf24l01_write_buf(WR_TX_PLOAD, ptxbuf, TX_PLOAD_WIDTH);    /* 寫數據到TX BUF  TX_PLOAD_WIDTH個字節 */NRF24L01_CE(1); /* 啟動發送 */while (NRF24L01_IRQ != 0);          /* 等待發送完成 */sta = nrf24l01_read_reg(STATUS);    /* 讀取狀態寄存器的值 */nrf24l01_write_reg(NRF_WRITE_REG + STATUS, sta);    /* 清除TX_DS或MAX_RT中斷標志 */if (sta & MAX_TX)   /* 達到最大重發次數 */{nrf24l01_write_reg(FLUSH_TX, 0xff); /* 清除TX FIFO寄存器 */rval = 1;}if (sta & TX_OK)/* 發送完成 */{rval = 0;   /* 標記發送成功 */}return rval;    /* 返回結果 */
}/*** @brief       啟動NRF24L01接收一次數據(數據長度 = RX_PLOAD_WIDTH)* @param       prxbuf : 接收數據緩沖區首地址* @retval      接收完成狀態*   @arg       0 : 接收成功*   @arg       1 : 失敗*/
uint8_t nrf24l01_rx_packet(uint8_t *prxbuf)
{uint8_t sta;uint8_t rval = 1;sta = nrf24l01_read_reg(STATUS); /* 讀取狀態寄存器的值 */nrf24l01_write_reg(NRF_WRITE_REG + STATUS, sta); /* 清除RX_OK中斷標志 */if (sta & RX_OK)    /* 接收到數據 */{nrf24l01_read_buf(RD_RX_PLOAD, prxbuf, RX_PLOAD_WIDTH); /* 讀取數據 */nrf24l01_write_reg(FLUSH_RX, 0xff); /* 清除RX FIFO寄存器 */rval = 0;       /* 標記接收完成 */}return rval;    /* 返回結果 */
}/*** @brief       NRF24L01進入接收模式*   @note      設置RX地址,寫RX數據寬度,選擇RF頻道,波特率*              當CE變高后,即進入RX模式,并可以接收數據了* @param       無* @retval      無*/
void nrf24l01_rx_mode(void)
{NRF24L01_CE(0);nrf24l01_write_buf(NRF_WRITE_REG + RX_ADDR_P0, (uint8_t *)RX_ADDRESS, RX_ADR_WIDTH);    /* 寫RX節點地址 */nrf24l01_write_reg(NRF_WRITE_REG + EN_AA, 0x01);        /* 使能通道0的自動應答 */nrf24l01_write_reg(NRF_WRITE_REG + EN_RXADDR, 0x01);    /* 使能通道0的接收地址 */nrf24l01_write_reg(NRF_WRITE_REG + RF_CH, 40);          /* 設置RF通信頻率 */nrf24l01_write_reg(NRF_WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH);   /* 選擇通道0的有效數據寬度 */nrf24l01_write_reg(NRF_WRITE_REG + RF_SETUP, 0x0f);     /* 設置TX發射參數,0db增益,2Mbps */nrf24l01_write_reg(NRF_WRITE_REG + CONFIG, 0x0f);       /* 配置基本工作模式的參數;PWR_UP,EN_CRC,16BIT_CRC,接收模式 */NRF24L01_CE(1); /* CE為高,進入接收模式 */
}/*** @brief       NRF24L01進入發送模式*   @note      設置TX地址,寫TX數據寬度,設置RX自動應答的地址,填充TX發送數據,選擇RF頻道,波特率和*              PWR_UP,CRC使能*              當CE變高后,即進入TX模式,并可以發送數據了, CE為高大于10us,則啟動發送.* @param       無* @retval      無*/
void nrf24l01_tx_mode(void)
{NRF24L01_CE(0);nrf24l01_write_buf(NRF_WRITE_REG + TX_ADDR, (uint8_t *)TX_ADDRESS, TX_ADR_WIDTH);       /* 寫TX節點地址 */nrf24l01_write_buf(NRF_WRITE_REG + RX_ADDR_P0, (uint8_t *)RX_ADDRESS, RX_ADR_WIDTH);    /* 設置RX節點地址,主要為了使能ACK */nrf24l01_write_reg(NRF_WRITE_REG + EN_AA, 0x01);        /* 使能通道0的自動應答 */nrf24l01_write_reg(NRF_WRITE_REG + EN_RXADDR, 0x01);    /* 使能通道0的接收地址 */nrf24l01_write_reg(NRF_WRITE_REG + SETUP_RETR, 0x1a);   /* 設置自動重發間隔時間:500us + 86us;最大自動重發次數:10次 */nrf24l01_write_reg(NRF_WRITE_REG + RF_CH, 40);          /* 設置RF通道為40 */nrf24l01_write_reg(NRF_WRITE_REG + RF_SETUP, 0x0f);     /* 設置TX發射參數,0db增益,2Mbps */nrf24l01_write_reg(NRF_WRITE_REG + CONFIG, 0x0e);       /* 配置基本工作模式的參數;PWR_UP,EN_CRC,16BIT_CRC,接收模式,開啟所有中斷 */NRF24L01_CE(1); /* CE為高,10us后啟動發送 */
}

.h文件

#ifndef __24L01_H
#define __24L01_H#include "./SYSTEM/sys/sys.h"/******************************************************************************************/
/* NRF24L01 操作引腳 定義(不包含SPI_SCK/MISO/MISO等三根線) */#define NRF24L01_CE_GPIO_PORT              GPIOG
#define NRF24L01_CE_GPIO_PIN               GPIO_PIN_8
#define NRF24L01_CE_GPIO_CLK_ENABLE()      do{ __HAL_RCC_GPIOG_CLK_ENABLE(); }while(0)   /* PG口時鐘使能 */#define NRF24L01_CSN_GPIO_PORT             GPIOG
#define NRF24L01_CSN_GPIO_PIN              GPIO_PIN_7
#define NRF24L01_CSN_GPIO_CLK_ENABLE()     do{ __HAL_RCC_GPIOG_CLK_ENABLE(); }while(0)   /* PE口時鐘使能 */#define NRF24L01_IRQ_GPIO_PORT             GPIOG
#define NRF24L01_IRQ_GPIO_PIN              GPIO_PIN_6
#define NRF24L01_IRQ_GPIO_CLK_ENABLE()     do{ __HAL_RCC_GPIOG_CLK_ENABLE(); }while(0)   /* PG口時鐘使能 *//******************************************************************************************//* 24L01操作線 */
#define NRF24L01_CE(x)    do{ x ? \HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT, NRF24L01_CE_GPIO_PIN, GPIO_PIN_SET) : \HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT, NRF24L01_CE_GPIO_PIN, GPIO_PIN_RESET); \}while(0)       /* 24L01模式選擇信號 */#define NRF24L01_CSN(x)   do{ x ? \HAL_GPIO_WritePin(NRF24L01_CSN_GPIO_PORT, NRF24L01_CSN_GPIO_PIN, GPIO_PIN_SET) : \HAL_GPIO_WritePin(NRF24L01_CSN_GPIO_PORT, NRF24L01_CSN_GPIO_PIN, GPIO_PIN_RESET); \}while(0)       /* 24L01片選信號 */#define NRF24L01_IRQ      HAL_GPIO_ReadPin(NRF24L01_IRQ_GPIO_PORT, NRF24L01_IRQ_GPIO_PIN) /* IRQ主機數據輸入 *//* 24L01發送接收數據寬度定義 * 用戶必須根據實際情況設置正確的數據寬度和數據長度* 發送端&接收端必須保持一致, 否則將導致通信失敗!!!!*/
#define TX_ADR_WIDTH    5       /* 5字節的地址寬度 */
#define RX_ADR_WIDTH    5       /* 5字節的地址寬度 */
#define TX_PLOAD_WIDTH  32      /* 32字節的用戶數據寬度 */
#define RX_PLOAD_WIDTH  32      /* 32字節的用戶數據寬度 *//******************************************************************************************/
/* NRF24L01寄存器操作命令 */
#define NRF_READ_REG    0x00    /* 讀配置寄存器,低5位為寄存器地址 */
#define NRF_WRITE_REG   0x20    /* 寫配置寄存器,低5位為寄存器地址 */
#define RD_RX_PLOAD     0x61    /* 讀RX有效數據,1~32字節 */
#define WR_TX_PLOAD     0xA0    /* 寫TX有效數據,1~32字節 */
#define FLUSH_TX        0xE1    /* 清除TX FIFO寄存器.發射模式下用 */
#define FLUSH_RX        0xE2    /* 清除RX FIFO寄存器.接收模式下用 */
#define REUSE_TX_PL     0xE3    /* 重新使用上一包數據,CE為高,數據包被不斷發送. */
#define NOP             0xFF    /* 空操作,可以用來讀狀態寄存器 *//* SPI(NRF24L01)寄存器地址 */
#define CONFIG          0x00    /* 配置寄存器地址;bit0:1接收模式,0發射模式;bit1:電選擇;bit2:CRC模式;bit3:CRC使能; *//* bit4:中斷MAX_RT(達到最大重發次數中斷)使能;bit5:中斷TX_DS使能;bit6:中斷RX_DR使能 */
#define EN_AA           0x01    /* 使能自動應答功能  bit0~5,對應通道0~5 */
#define EN_RXADDR       0x02    /* 接收地址允許,bit0~5,對應通道0~5 */
#define SETUP_AW        0x03    /* 設置地址寬度(所有數據通道):bit1,0:00,3字節;01,4字節;02,5字節; */
#define SETUP_RETR      0x04    /* 建立自動重發;bit3:0,自動重發計數器;bit7:4,自動重發延時 250*x+86us */
#define RF_CH           0x05    /* RF通道,bit6:0,工作通道頻率; */
#define RF_SETUP        0x06    /* RF寄存器;bit3:傳輸速率(0:1Mbps,1:2Mbps);bit2:1,發射功率;bit0:低噪聲放大器增益 */
#define STATUS          0x07    /* 狀態寄存器;bit0:TX FIFO滿標志;bit3:1,接收數據通道號(最大:6);bit4,達到最多次重發 *//* bit5:數據發送完成中斷;bit6:接收數據中斷; */
#define MAX_TX          0x10    /* 達到最大發送次數中斷 */
#define TX_OK           0x20    /* TX發送完成中斷 */
#define RX_OK           0x40    /* 接收到數據中斷 */#define OBSERVE_TX      0x08    /* 發送檢測寄存器,bit7:4,數據包丟失計數器;bit3:0,重發計數器 */
#define CD              0x09    /* 載波檢測寄存器,bit0,載波檢測; */
#define RX_ADDR_P0      0x0A    /* 數據通道0接收地址,最大長度5個字節,低字節在前 */
#define RX_ADDR_P1      0x0B    /* 數據通道1接收地址,最大長度5個字節,低字節在前 */
#define RX_ADDR_P2      0x0C    /* 數據通道2接收地址,最低字節可設置,高字節,必須同RX_ADDR_P1[39:8]相等; */
#define RX_ADDR_P3      0x0D    /* 數據通道3接收地址,最低字節可設置,高字節,必須同RX_ADDR_P1[39:8]相等; */
#define RX_ADDR_P4      0x0E    /* 數據通道4接收地址,最低字節可設置,高字節,必須同RX_ADDR_P1[39:8]相等; */
#define RX_ADDR_P5      0x0F    /* 數據通道5接收地址,最低字節可設置,高字節,必須同RX_ADDR_P1[39:8]相等; */
#define TX_ADDR         0x10    /* 發送地址(低字節在前),ShockBurstTM模式下,RX_ADDR_P0與此地址相等 */
#define RX_PW_P0        0x11    /* 接收數據通道0有效數據寬度(1~32字節),設置為0則非法 */
#define RX_PW_P1        0x12    /* 接收數據通道1有效數據寬度(1~32字節),設置為0則非法 */
#define RX_PW_P2        0x13    /* 接收數據通道2有效數據寬度(1~32字節),設置為0則非法 */
#define RX_PW_P3        0x14    /* 接收數據通道3有效數據寬度(1~32字節),設置為0則非法 */
#define RX_PW_P4        0x15    /* 接收數據通道4有效數據寬度(1~32字節),設置為0則非法 */
#define RX_PW_P5        0x16    /* 接收數據通道5有效數據寬度(1~32字節),設置為0則非法 */
#define NRF_FIFO_STATUS 0x17    /* FIFO狀態寄存器;bit0,RX FIFO寄存器空標志;bit1,RX FIFO滿標志;bit2,3,保留 *//* bit4,TX FIFO空標志;bit5,TX FIFO滿標志;bit6,1,循環發送上一數據包.0,不循環; */
/******************************************************************************************//* 函數申明 */
static uint8_t nrf24l01_write_buf(uint8_t reg, uint8_t *pbuf, uint8_t uint8_ts);   /* 寫數據區 */
static uint8_t nrf24l01_read_buf(uint8_t reg, uint8_t *pbuf, uint8_t uint8_ts);    /* 讀數據區 */void nrf24l01_spi_init(void);   /* 針對NRF24L01修改SPI2驅動 */
void nrf24l01_init(void);       /* 初始化 */
void nrf24l01_rx_mode(void);    /* 配置為接收模式 */
void nrf24l01_tx_mode(void);    /* 配置為發送模式 */
uint8_t nrf24l01_check(void);   /* 檢查24L01是否存在 */
uint8_t nrf24l01_tx_packet(uint8_t *ptxbuf);     /* 發送一個包的數據 */
uint8_t nrf24l01_rx_packet(uint8_t *prxbuf);     /* 接收一個包的數據 */#endif


藍牙模塊

基本介紹

使用方法

示例代碼


WIFI模塊

基本介紹

以ESP8266為例。

使用方法

示例代碼


紅外遙控模塊

基本介紹

紅外遙控的基本概念

紅外遙控是一種通過紅外線進行無線通信的技術,廣泛應用于遙控器、智能家居設備等。紅外遙控器通過發射紅外信號來控制設備,而接收端(如STM32)通過紅外接收模塊解碼這些信號。

紅外遙控的工作原理

  • 發射端:遙控器將按鍵信息編碼為特定的紅外信號(通常是調制的載波信號,如38kHz)。

  • 接收端:紅外接收模塊(如TSOP系列)接收紅外信號,并將其轉換為電信號。

  • 解碼:STM32通過定時器捕獲信號的上升沿和下降沿,計算時間差來解析信號。

簡單理解:通過判斷IO的高電平的時間來確定是邏輯0還是邏輯1。

使用方法

接收順序:引導碼、地址碼、地址反碼、控制碼、控制反碼

  1. 初始化定時器4,設置輸入捕獲參數,包括捕獲極性、輸入通道選擇、輸入分頻和濾波器設置。
  2. 在定時器中斷回調函數中,更新接收狀態,檢查是否完成按鍵信息采集,并根據計數器的值更新狀態。
  3. 在輸入捕獲中斷回調函數中,捕獲上升沿和下降沿的時間差,判斷信號類型(引導碼、0、1或按鍵重復信息),更新接收數據和狀態。
  4. 在按鍵掃描函數中,驗證接收到的數據,包括地址碼和數據碼的正確性,返回按鍵值。

示例代碼

TIM_HandleTypeDef g_tim4_handle;      /* 定時器4句柄 *//*** @brief       紅外遙控初始化*   @note      設置IO以及定時器的輸入捕獲* @param       無* @retval      無*/
void remote_init(void)
{TIM_IC_InitTypeDef tim_ic_init_handle;g_tim4_handle.Instance = REMOTE_IN_TIMX;                    /* 通用定時器4 */g_tim4_handle.Init.Prescaler = (72-1);                      /* 預分頻器,1M的計數頻率,1us加1 */g_tim4_handle.Init.CounterMode = TIM_COUNTERMODE_UP;        /* 向上計數器 */g_tim4_handle.Init.Period = 10000;                          /* 自動裝載值 */g_tim4_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;HAL_TIM_IC_Init(&g_tim4_handle);/* 初始化TIM4輸入捕獲參數 */tim_ic_init_handle.ICPolarity = TIM_ICPOLARITY_RISING;      /* 上升沿捕獲 */tim_ic_init_handle.ICSelection = TIM_ICSELECTION_DIRECTTI;  /* 映射到TI4上 */tim_ic_init_handle.ICPrescaler = TIM_ICPSC_DIV1;            /* 配置輸入分頻,不分頻 */tim_ic_init_handle.ICFilter = 0x03;                         /* IC1F=0003 8個定時器時鐘周期濾波 */HAL_TIM_IC_ConfigChannel(&g_tim4_handle, &tim_ic_init_handle, REMOTE_IN_TIMX_CHY);/* 配置TIM4通道4 */HAL_TIM_IC_Start_IT(&g_tim4_handle, REMOTE_IN_TIMX_CHY);    /* 開始捕獲TIM的通道值 */__HAL_TIM_ENABLE_IT(&g_tim4_handle, TIM_IT_UPDATE);         /* 使能更新中斷 */
}/*** @brief       定時器4底層驅動,時鐘使能,引腳配置* @param       htim:定時器句柄* @note        此函數會被HAL_TIM_IC_Init()調用* @retval      無*/
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{if(htim->Instance == REMOTE_IN_TIMX){GPIO_InitTypeDef gpio_init_struct;REMOTE_IN_GPIO_CLK_ENABLE();            /* 紅外接入引腳GPIO時鐘使能 */REMOTE_IN_TIMX_CHY_CLK_ENABLE();        /* 定時器時鐘使能 */__HAL_AFIO_REMAP_TIM4_DISABLE();        /* 這里用的是PB9/TIM4_CH4,參考AFIO_MAPR寄存器的設置 */gpio_init_struct.Pin = REMOTE_IN_GPIO_PIN;gpio_init_struct.Mode = GPIO_MODE_AF_INPUT;             /* 復用輸入 */gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉 */gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;          /* 高速 */HAL_GPIO_Init(REMOTE_IN_GPIO_PORT, &gpio_init_struct);  /* 初始化定時器通道引腳 */HAL_NVIC_SetPriority(REMOTE_IN_TIMX_IRQn, 1, 3);        /* 設置中斷優先級,搶占優先級1,子優先級3 */HAL_NVIC_EnableIRQ(REMOTE_IN_TIMX_IRQn);                /* 開啟ITM4中斷 */}}/* 遙控器接收狀態* [7]  : 收到了引導碼標志* [6]  : 得到了一個按鍵的所有信息* [5]  : 保留* [4]  : 標記上升沿是否已經被捕獲* [3:0]: 溢出計時器*/
uint8_t g_remote_sta = 0;
uint32_t g_remote_data = 0; /* 紅外接收到的數據 */
uint8_t  g_remote_cnt = 0;  /* 按鍵按下的次數 *//*** @brief       定時器中斷服務函數* @param       無* @retval      無*/
void REMOTE_IN_TIMX_IRQHandler(void)
{HAL_TIM_IRQHandler(&g_tim4_handle); /* 定時器共用處理函數 */
}/*** @brief       定時器更新中斷回調函數* @param       htim:定時器句柄* @retval      無*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if (htim->Instance == REMOTE_IN_TIMX){if (g_remote_sta & 0x80)      /* 上次有數據被接收到了 */{g_remote_sta &= ~0X10;    /* 取消上升沿已經被捕獲標記 */if ((g_remote_sta & 0X0F) == 0X00){g_remote_sta |= 1 << 6; /* 標記已經完成一次按鍵的鍵值信息采集 */}if ((g_remote_sta & 0X0F) < 14){g_remote_sta++;}else{g_remote_sta &= ~(1 << 7);    /* 清空引導標識 */g_remote_sta &= 0XF0;         /* 清空計數器 */}}}
}/*** @brief       定時器輸入捕獲中斷回調函數* @param       htim:定時器句柄* @retval      無*/
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{if (htim->Instance == REMOTE_IN_TIMX){uint16_t dval;  /* 下降沿時計數器的值 */if (RDATA)      /* 上升沿捕獲 */{__HAL_TIM_SET_CAPTUREPOLARITY(&g_tim4_handle,REMOTE_IN_TIMX_CHY,TIM_INPUTCHANNELPOLARITY_FALLING);//CC4P=1 設置為下降沿捕獲__HAL_TIM_SET_COUNTER(&g_tim4_handle, 0);  /* 清空定時器值 */g_remote_sta |= 0X10;                      /* 標記上升沿已經被捕獲 */}else           /* 下降沿捕獲 */{dval=HAL_TIM_ReadCapturedValue(&g_tim4_handle, REMOTE_IN_TIMX_CHY);                /* 讀取CCR4也可以清CC4IF標志位 */__HAL_TIM_SET_CAPTUREPOLARITY(&g_tim4_handle, REMOTE_IN_TIMX_CHY, TIM_INPUTCHANNELPOLARITY_RISING);/* 配置TIM4通道4上升沿捕獲 */if (g_remote_sta & 0X10)        /* 完成一次高電平捕獲 */{if (g_remote_sta & 0X80)    /* 接收到了引導碼 */{if (dval > 300 && dval < 800)           /* 560為標準值,560us */{g_remote_data >>= 1;                /* 右移一位 */g_remote_data &= ~(0x80000000);     /* 接收到0 */}else if (dval > 1400 && dval < 1800)    /* 1680為標準值,1680us */{g_remote_data >>= 1;                /* 右移一位 */g_remote_data |= 0x80000000;        /* 接收到1 */}else if (dval > 2000 && dval < 3000)    /* 得到按鍵鍵值增加的信息 2500為標準值2.5ms */{//這里可理解為長按狀態,遙控器持續發送一個特定波形g_remote_cnt++;         /* 按鍵次數增加1次 */g_remote_sta &= 0XF0;   /* 清空計時器 */}}else if (dval > 4200 && dval < 4700)    /* 4500為標準值4.5ms */{g_remote_sta |= 1 << 7; /* 標記成功接收到了引導碼 */g_remote_cnt = 0;       /* 清除按鍵次數計數器 */}}g_remote_sta&=~(1<<4);}}
}/*** @brief       處理紅外按鍵(類似按鍵掃描)* @param       無* @retval      0   , 沒有任何按鍵按下*              其他, 按下的按鍵鍵值*/
uint8_t remote_scan(void)
{uint8_t sta = 0;uint8_t t1, t2;if (g_remote_sta & (1 << 6))    /* 得到一個按鍵的所有信息了 */{t1 = g_remote_data;                 /* 得到地址碼 */t2 = (g_remote_data >> 8) & 0xff;   /* 得到地址反碼 */if ((t1 == (uint8_t)~t2) && t1 == REMOTE_ID)    /* 檢驗遙控識別碼(ID)及地址 */{t1 = (g_remote_data >> 16) & 0xff;//提取 g_remote_data 的第 16 到第 23 位(即第 3 個字節)。t2 = (g_remote_data >> 24) & 0xff;//提取 g_remote_data 的第 24 到第 31 位(即第 4 個字節)。if (t1 == (uint8_t)~t2){sta = t1;           /* 鍵值正確 */}}if ((sta == 0) || ((g_remote_sta & 0X80) == 0)) /* 按鍵數據錯誤/遙控已經沒有按下了 */{g_remote_sta &= ~(1 << 6);  /* 清除接收到有效按鍵標識 */g_remote_cnt = 0;           /* 清除按鍵次數計數器 */}}return sta;
}


有線通信模塊

can模塊

基本介紹

使用方法

示例代碼


傳感器模塊

DHT11模塊

基本介紹

使用方法

示例代碼



本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/79165.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/79165.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/79165.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

記一次InternVL3- 2B 8B的部署測驗日志

測試效果&#xff1a; 問題和耗時如圖 5、資源占用 不釋放資源會一直漲顯存。總體還算滿意&#xff0c;我試了好多個圖理解大模型&#xff0c;就屬它牛一點 附圖一張 補充&#xff0c;測試InternVL3-2B的結果 1、模型下載魔搭社區 2、運行環境&#xff1a; 1、硬件 RTX 30…

Java版本對應關系表

Java版本對應關系表 以下Java主要版本&#xff08;Major Version&#xff09;與公開大版本號的對應關系 公開大版本名稱Major 版本號內部版本號格式示例&#xff08;java -version輸出&#xff09;Java 8 (1.8)52 (0x34)1.8.0_XXX1.8.0_301Java 953 (0x35)9.0.X9.0.4Java 105…

2025最新版flink2.0.0安裝教程(保姆級)

Flink支持多種安裝模式。 local&#xff08;本地&#xff09;——本地模式 standalone——獨立模式&#xff0c;Flink自帶集群&#xff0c;開發測試環境使用 standaloneHA—獨立集群高可用模式&#xff0c;Flink自帶集群&#xff0c;開發測試環境使用 yarn——計算資源統一…

android11 配置默認電池優化白名單

目錄 1.介紹 2.讀取配置文件 3.默認配置一個白名單列表 1.介紹 在 Android 11 中,DeviceIdleController 是負責控制設備進入 Doze 模式(閑置模式) 的核心系統服務,其內部方法 readConfigFileLocked() 負責從配置文件中讀取 Doze 模式的行為參數,包括 idle 階段的時間間…

java中的Future的設計模式 手寫一個簡易的Future

案例 例如&#xff1a;今天是小妹的生日&#xff0c;需要一個蛋糕有點儀式感&#xff0c;于是去蛋糕店預定&#xff0c;預定完之后&#xff0c;店老板說蛋糕做好了&#xff0c;到時電話通知你&#xff0c;不可能在這傻傻的等著吧&#xff0c;還有其他事情要做啊&#xff0c;于…

【Redis】Redis C++使用

一、Redis的自定義網絡協議 1.1 為什么可以編寫出一個自定義的Redis客戶端 為什么我們可以編寫出一個自定義的Redis客戶端&#xff1f;因為Redis公開了自己的自定義協議。而對于一些其他軟件的客戶端&#xff0c;我們無法編寫出一個自定義的Redis客戶端&#xff0c;因為他們沒…

【軟考系統架構設計師】軟件工程知識點

1、 軟件開發生命周期 軟件定義時期&#xff1a;包括可行性研究和詳細需求分析過程&#xff0c;任務是確定軟件開發工程必須完成的總目標&#xff0c;具體分為問題定義、可行性研究、需求分析等 軟件開發時期&#xff1a;軟件的設計與實現&#xff0c;分為概要設計、詳細設計、…

DeepSeek 與開源:肥沃土壤孕育 AI 碩果

當國產 AI DeepSeek 以其低成本推理和多模態能力在全球范圍內引起轟動時&#xff0c;人們驚嘆于中國技術的迅猛發展&#xff0c;卻很少有人深究這一成就背后的根基。答案其實早已寫在中國開源生態二十多年的發展歷程中。 從倪光南院士提出“以開源打破技術壟斷”的理念&#x…

職坐標:智慧城市未來發展的核心驅動力

內容概要 智慧城市的演進正以顛覆性創新重構人類生存空間&#xff0c;其發展脈絡由物聯網、人工智能與云計算三大技術支柱交織而成。這些技術不僅推動城市治理從經驗決策轉向數據驅動模式&#xff0c;更通過實時感知與智能分析&#xff0c;實現交通、能源等領域的精準調控。以…

vue復習46~90

1.小兔鮮 所有都折疊 ctrl k,ctrl0 所有都展開 ctrl k,ctrlj當前結構渲染5次 <BaseBrandItem v-for"item in 5" :key"item"><BaseBrandItem>2.scoped樣式沖突 結構&#xff1a;只能有一個根元素樣式&#xff1a;全局樣式(默認)&#xff1…

PHP 用 workman 即時通訊,做個簡版QQ

1. workman是什么 &#xff0c;一般應用在那些地方 workerman是一個高性能的PHP socket 服務器框架&#xff0c;workerman基于PHP多進程以及libevent事件輪詢庫&#xff0c;PHP開發者只要實現一兩個接口&#xff0c;便可以開發出自己的網絡應用&#xff0c;例如Rpc服務、聊天室…

【WORD】批量將doc轉為docx

具體步驟進行&#xff1a; 打開Word文檔&#xff0c;按下AltF11快捷鍵&#xff0c;打開VBA編輯器。在VBA編輯器中&#xff0c;左側的“項目資源管理器”窗口會顯示當前打開的Word文檔相關項目。找到您要添加代碼的文檔項目&#xff08;通常以文檔名稱命名&#xff09;&#xf…

【免費】【實測有用】5KPlayer Windows 電腦作為 MacBook 無線擴展屏

總結&#xff1a;使用 5KPlayer 將 Windows 電腦作為 MacBook 無線擴展屏 準備工作 設備要求&#xff1a; MacBook 和 Windows 電腦需連接到同一 Wi-Fi 網絡。【這里有雷&#xff1a;eduroam不會成功&#xff0c;家里的WIFI成功了&#xff0c;需要確認校園網是否可行。】確保…

華為華三模擬器解決兼容問題Win11 24H2 現在使用ENSP的問題解決了

一、Win11 24H2 現在使用ENSP的問題解決了 這個Win11 的 24H2不能使用ENSP的問題已經困擾我們很久了,在之前的文章中,我們也有說明這個問題 之前ENSP肯定啟動會報錯40 當時還建議大家先不要更新到win11的24H2版本,現在終于迎來了更新,不用再擔心了,包括早就升級了24H2版…

嵌入式WebRTC輕量化SDK壓縮至500K-800K ,為嵌入式設備節省Flash資源

一、SDK輕量化的核心技術實現 1、WebRTC庫裁剪與模塊化設計 EasyRTC針對嵌入式設備的資源限制&#xff0c;對原生WebRTC庫進行深度裁剪&#xff0c;僅保留核心通信功能&#xff08;如信令管理、編解碼、網絡傳輸等&#xff09;&#xff0c;移除冗余組件&#xff08;如部分調試…

Maya云渲染工作流,提升渲染速度

在三維動畫與影視特效領域&#xff0c;Autodesk Maya作為行業標桿工具&#xff0c;承載著從角色建模到復雜特效渲染的全流程創作。然而&#xff0c;本地硬件性能不足、渲染周期漫長、跨團隊協作效率低等痛點始終困擾著創作者。渲染101云渲染以彈性算力資源、智能化工作流與全方…

git怎么使遠程分支回退到指定的節點處

git使遠程分支回退到指定的節點 引言場景描述步驟 引言 最近提交代碼的時候&#xff0c;總將分支合并錯&#xff0c;原本要合到A分支&#xff0c;結果合并到了B分支&#xff0c;這樣就導致b分支需要回退到我沒有合并之前的節點處。 本文記錄下怎么將遠程分支回退到指定的節點。…

全網通emotn ui桌面免費嗎?如何開機自啟動

在智能設備的使用中&#xff0c;一款優秀的桌面系統能帶來截然不同的體驗。全網通Emotn UI桌面便是其中的佼佼者&#xff0c;它以完全免費的特性與卓越性能&#xff0c;成為眾多用戶的心頭好。 其簡潔美觀的界面設計如同為設備換上"清新外衣"&#xff0c;常用功能一…

通過微信APPID獲取小程序名稱

進入微信公眾平臺&#xff0c;登錄自己的小程序后臺管理端&#xff0c;在“賬號設置”中找到“第三方設置” 在“第三方設置”頁面中&#xff0c;將頁面拉到最下面&#xff0c;即可通過appid獲取到這個小程序的名稱信息

2025年第十六屆藍橋杯省賽JavaB組真題回顧

第16屆藍橋杯省賽已經結束了&#xff0c;第一次參加也是坐牢了4個小時&#xff0c;現在還是來總結一下吧&#xff08;先聲明以下的解法&#xff0c;大家可以當作一種思路來看&#xff0c;解法不一定是正解&#xff0c;只是給大家提供一種能夠正常想到的思路吧&#xff09; 試題…