嵌入式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.mzph.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; 试题…