目录

一、原理图

①飞控板

②遥控板

二、SI24R1

①状态转换图

②数据包处理协议

(1)ARQ包格式

1、前导码

2、地址

3、包控制字

4、负载数据

5、CRC(循环冗余性校验)

三、STM32CubeMX

四、Keil

五、VSCode

①int_SI24R1.h

②int_SI24R1.c

③App_freertos_task.h

④App_freertos_task.c


一、原理图

①飞控板

②遥控板

二、SI24R1

①状态转换图

②数据包处理协议

(1)ARQ包格式

1、前导码

也叫帧头校验,主要用于接收数据同步,发射时芯片自动附上,接收时芯片自动去掉,对用户不可见,唯一性。

2、地址

地址字段为接收数据方地址,只有当该地址与芯片的地址寄存器中地址相同时才会接收。地址长度可以通过配置寄存器 AW 配置为 3、或 4、或5 字节。
需要注意的是,地址的最高字节不可设为 0xFF、0x00、0xA5、0x5A、0xAA、0x55,否则可能导致接收失败。

3、包控制字

包控制字段长度为 9bit,数据包长度子字段指定数据包的长度,可以为0到32字节例如:000000=0byte(包为空)
100000=32 byte(数据包长度为32字节)
PID 子字段告知接收端这个包是一个新的包还是一个重发的包,可以防止接收端多次接收同一个包。发射方通过SPI写 FIFO,PID 的值自动累加。接收端通过对比 PID和 CRC 来判断接收的此包是新包还是重发包。如果 PID 和上一包的 PID 相同则比对CRC,如果 CRC也相同,则判断为上一数据的重发并将数据丢弃。

4、负载数据

负载数据字段为发射数据内容,可以最长 32 字节。

5、CRC(循环冗余性校验)

CRC 字段为包的 CRC值,CRC支持 8bit和 16bit 两种,CRC 的长度通过 CONFIG寄存器中的 CRCO 位配置。

三、STM32CubeMX

以飞控板为例

①SPI1模式为全双工模式

②prescaler分频器为8

③PA4和PA8均为GPIO_Output

④PA4默认为高电平,用户标签为SPI1_NSS

⑤PA8默认为低电平,用户标签为SI_EN

四、Keil

①在interface下创建int_SI24R1.c/.h文件

②添加.c/.h文件

五、VSCode

①int_SI24R1.h

#ifndef __nRF24L01P__
#define __nRF24L01P__

#include "spi.h"
#include "Com_debug.h"

// (1) STM32开发板使用SI24R1需要先到CUBEMX中配置SPI
// 拉低片选
#define CS_LOW HAL_GPIO_WritePin(SPI1_NSS_GPIO_Port, SPI1_NSS_Pin, GPIO_PIN_RESET);
// 拉高片选
#define CS_HIGH HAL_GPIO_WritePin(SPI1_NSS_GPIO_Port, SPI1_NSS_Pin, GPIO_PIN_SET);

// 拉低使能
#define CE_LOW HAL_GPIO_WritePin(SI_EN_GPIO_Port, SI_EN_Pin, GPIO_PIN_RESET);
// 拉高使能
#define CE_HIGH HAL_GPIO_WritePin(SI_EN_GPIO_Port, SI_EN_Pin, GPIO_PIN_SET);

// 选择使用的射频通道
#define CHANNEL 40
#define TX_ADR_WIDTH 5    // 5字节宽度的发送/接收地址
#define TX_PLOAD_WIDTH 32 // 数据通道有效数据宽度

//********************************************************************************************************************//
// SPI(SI24R1) commands
#define SI24R1_READ_REG 0x00  // Define read command to register
#define SI24R1_WRITE_REG 0x20 // Define write command to register
#define RD_RX_PLOAD 0x61      // Define RX payload register address
#define WR_TX_PLOAD 0xA0      // Define TX payload register address
#define FLUSH_TX 0xE1         // Define flush TX register command
#define FLUSH_RX 0xE2         // Define flush RX register command
#define REUSE_TX_PL 0xE3      // Define reuse TX payload register command
#define NOP 0xFF              // Define No Operation, might be used to read status register

//********************************************************************************************************************//
// SPI(SI24R1) registers(addresses)
#define CONFIG 0x00      // 'Config' register address
#define EN_AA 0x01       // 'Enable Auto Acknowledgment' register address
#define EN_RXADDR 0x02   // 'Enabled RX addresses' register address
#define SETUP_AW 0x03    // 'Setup address width' register address
#define SETUP_RETR 0x04  // 'Setup Auto. Retrans' register address
#define RF_CH 0x05       // 'RF channel' register address
#define RF_SETUP 0x06    // 'RF setup' register address
#define STATUS 0x07      // 'Status' register address
#define OBSERVE_TX 0x08  // 'Observe TX' register address
#define RSSI 0x09        // 'Received Signal Strength Indecator' register address
#define RX_ADDR_P0 0x0A  // 'RX address pipe0' register address
#define RX_ADDR_P1 0x0B  // 'RX address pipe1' register address
#define RX_ADDR_P2 0x0C  // 'RX address pipe2' register address
#define RX_ADDR_P3 0x0D  // 'RX address pipe3' register address
#define RX_ADDR_P4 0x0E  // 'RX address pipe4' register address
#define RX_ADDR_P5 0x0F  // 'RX address pipe5' register address
#define TX_ADDR 0x10     // 'TX address' register address
#define RX_PW_P0 0x11    // 'RX payload width, pipe0' register address
#define RX_PW_P1 0x12    // 'RX payload width, pipe1' register address
#define RX_PW_P2 0x13    // 'RX payload width, pipe2' register address
#define RX_PW_P3 0x14    // 'RX payload width, pipe3' register address
#define RX_PW_P4 0x15    // 'RX payload width, pipe4' register address
#define RX_PW_P5 0x16    // 'RX payload width, pipe5' register address
#define FIFO_STATUS 0x17 // 'FIFO Status Register' register address

//********************************************************************************************************************//
// STATUS Register
#define RX_DR 0x40 /**/
#define TX_DS 0x20
#define MAX_RT 0x10

//********************************************************************************************************************//
//                                        FUNCTION's PROTOTYPES                                                       //
//********************************************************************************************************************//
// SI24R1 API Functions

/********************************************************
函数功能:写寄存器的值(单字节)
入口参数:reg:寄存器映射地址(格式:SI24R1_WRITE_REG|reg)
                    value:寄存器的值
返回  值:状态寄存器的值
*********************************************************/
uint8_t Int_SI24R1_Write_Reg(uint8_t reg, uint8_t value);
/********************************************************
函数功能:写寄存器的值(多字节)
入口参数:reg:寄存器映射地址(格式:SI24R1_WRITE_REG|reg)
                    pBuf:写数据首地址
                    bytes:写数据字节数
返回  值:状态寄存器的值
*********************************************************/
uint8_t Int_SI24R1_Write_Buf(uint8_t reg, const uint8_t *pBuf, uint8_t size);
/********************************************************
函数功能:读取寄存器的值(单字节)
入口参数:reg:寄存器映射地址(格式:SI24R1_READ_REG|reg)
返回  值:寄存器值
*********************************************************/
uint8_t Int_SI24R1_Read_Reg(uint8_t reg);
/********************************************************
函数功能:读取寄存器的值(多字节)
入口参数:reg:寄存器映射地址(SI24R1_READ_REG|reg)
                    pBuf:接收缓冲区的首地址
                    bytes:读取字节数
返回  值:状态寄存器的值
*********************************************************/
uint8_t Int_SI24R1_Read_Buf(uint8_t reg, uint8_t *pBuf, uint8_t size);

/********************************************************
函数功能:SI24R1接收模式初始化
入口参数:无
返回  值:无
*********************************************************/
void Int_SI24R1_RX_Mode(void);
/********************************************************
函数功能:SI24R1发送模式初始化
入口参数:无
返回  值:无
*********************************************************/
void Int_SI24R1_TX_Mode(void);

/********************************************************
函数功能:读取接收数据   硬件直接接收数据保存到 FIFO队列中 => 通过状态标志位判断队列中是否有数据 
入口参数:rxbuf:接收数据存放首地址
返回  值:0:接收到数据
		  1:没有接收到数据
*********************************************************/
uint8_t Int_SI24R1_RxPacket(uint8_t *rxbuf);

/********************************************************
函数功能:发送一个数据包
入口参数:txbuf:要发送的数据
返回  值: 0: 发送成功 1: 发送失败
*********************************************************/
uint8_t Int_SI24R1_TxPacket(uint8_t *txbuf);

/**
 * @brief 硬件接口层SI24R1的初始化
 *
 */
void Int_SI24R1_Init(void); // SI24R1 Pin Init
//********************************************************************************************************************//
#endif

②int_SI24R1.c

#include "Int_SI24R1.h"

// 定义一个静态的发送地址  => 发送地址与接收地址相同
uint8_t TX_ADDRESS[TX_ADR_WIDTH] = {0x0A, 0x01, 0x06, 0x1E, 0x01}; // 定义一个静态发送地址

// SPI读写一个字节 => 写入的字节是传入的参数  读取的字节是返回值
static uint8_t SPI_RW(uint8_t byte)
{
	uint8_t rx_data = 0;
	HAL_SPI_TransmitReceive(&hspi1, &byte, &rx_data, 1, 1000);
	return rx_data;
}

/********************************************************
函数功能:写寄存器的值(单字节)
入口参数:reg:寄存器映射地址(格式:SI24R1_WRITE_REG|reg)
					value:寄存器的值
返回  值:状态寄存器的值
*********************************************************/
uint8_t Int_SI24R1_Write_Reg(uint8_t reg, uint8_t value)
{
	uint8_t status;

	CS_LOW;
	status = SPI_RW(reg);
	SPI_RW(value);
	CS_HIGH;

	return (status);
}

/********************************************************
函数功能:写寄存器的值(多字节)
入口参数:reg:寄存器映射地址(格式:SI24R1_WRITE_REG|reg)
					pBuf:写数据首地址
					bytes:写数据字节数
返回  值:状态寄存器的值
*********************************************************/
uint8_t Int_SI24R1_Write_Buf(uint8_t reg, const uint8_t *pBuf, uint8_t size)
{
	uint8_t status, byte_ctr;

	CS_LOW;
	status = SPI_RW(reg);
	for (byte_ctr = 0; byte_ctr < size; byte_ctr++)
	{
		SPI_RW(*pBuf++);
	}

	CS_HIGH;

	return (status);
}

/********************************************************
函数功能:读取寄存器的值(单字节)
入口参数:reg:寄存器映射地址(格式:SI24R1_READ_REG|reg)
返回  值:寄存器值
*********************************************************/
uint8_t Int_SI24R1_Read_Reg(uint8_t reg)
{
	uint8_t value;

	CS_LOW;
	SPI_RW(reg);
	value = SPI_RW(0);
	CS_HIGH;

	return (value);
}

/********************************************************
函数功能:读取寄存器的值(多字节)
入口参数:reg:寄存器映射地址(SI24R1_READ_REG|reg)
					pBuf:接收缓冲区的首地址
					bytes:读取字节数
返回  值:状态寄存器的值
*********************************************************/
uint8_t Int_SI24R1_Read_Buf(uint8_t reg, uint8_t *pBuf, uint8_t size)
{
	uint8_t status, byte_ctr;

	CS_LOW;
	status = SPI_RW(reg);
	for (byte_ctr = 0; byte_ctr < size; byte_ctr++)
	{
		pBuf[byte_ctr] = SPI_RW(0); // 读取数据,低字节在前
	}
	CS_HIGH;

	return (status);
}

/********************************************************
函数功能:SI24R1接收模式初始化
入口参数:无
返回  值:无
*********************************************************/
void Int_SI24R1_RX_Mode(void)
{
	CE_LOW;
	Int_SI24R1_Write_Buf(SI24R1_WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH); // 接收设备接收通道0使用和发送设备相同的发送地址
	Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + EN_AA, 0x01);						   // 使能接收通道0自动应答
	Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + EN_RXADDR, 0x01);					   // 使能接收通道0
	Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + RF_CH, CHANNEL);					   // 选择射频通道40
	Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + RX_PW_P0, TX_PLOAD_WIDTH);			   // 接收通道0选择和发送通道相同有效数据宽度
	Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + RF_SETUP, 0x06);					   // 数据传输率1Mbps,发射功率4dBm
	Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + CONFIG, 0x0f);						   // CRC使能,16位CRC校验,上电,接收模式
	Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + STATUS, 0xff);						   // 清除所有的中断标志位
	CE_HIGH;																	   // 拉高CE启动接收设备
}

/********************************************************
函数功能:SI24R1发送模式初始化
入口参数:无
返回  值:无
*********************************************************/
void Int_SI24R1_TX_Mode(void)
{
	CE_LOW;
	Int_SI24R1_Write_Buf(SI24R1_WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH);	   // 写入发送地址
	Int_SI24R1_Write_Buf(SI24R1_WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH); // 为了应答接收设备,接收通道0地址和发送地址相同
	Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + EN_AA, 0x01);						   // 使能接收通道0自动应答
	Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + EN_RXADDR, 0x01);					   // 使能接收通道0
	Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + SETUP_RETR, 0x0a);					   // 自动重发延时等待250us+86us,自动重发10次
	Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + RF_CH, CHANNEL);					   // 选择射频通道0x40
	Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + RF_SETUP, 0x06);					   // 数据传输率1Mbps,发射功率4dBm
	Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + CONFIG, 0x0e);						   // CRC使能,16位CRC校验,上电
	CE_HIGH;
}

/********************************************************
函数功能:读取接收数据   硬件直接接收数据保存到 FIFO队列中 => 通过状态标志位判断队列中是否有数据
入口参数:rxbuf:接收数据存放首地址
返回  值:0:接收到数据
		  1:没有接收到数据
*********************************************************/
uint8_t Int_SI24R1_RxPacket(uint8_t *rxbuf)
{
	uint8_t state;
	// 将读取到的值 原封不动再写回状态寄存器  => 因为状态寄存器中的标志位设计为写1清除
	state = Int_SI24R1_Read_Reg(STATUS);					// 读取状态寄存器的值
	Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + STATUS, state); // 清除RX_DS中断标志

	if (state & RX_DR) // 接收到数据
	{
		Int_SI24R1_Read_Buf(RD_RX_PLOAD, rxbuf, TX_PLOAD_WIDTH); // 读取数据
		Int_SI24R1_Write_Reg(FLUSH_RX, 0xff);					 // 清除RX FIFO寄存器
		return 0;
	}
	return 1; // 没收到任何数据
}

/********************************************************
函数功能:发送一个数据包
入口参数:txbuf:要发送的数据
返回  值: 0: 发送成功 1: 发送失败
*********************************************************/
uint8_t Int_SI24R1_TxPacket(uint8_t *txbuf)
{
	uint8_t state;
	CE_LOW;													  // CE拉低,使能SI24R1配置
	Int_SI24R1_Write_Buf(WR_TX_PLOAD, txbuf, TX_PLOAD_WIDTH); // 写数据到TX FIFO,32个字节
	CE_HIGH;												  // CE置高,使能发送

	// 没有使用中断判断是否发送完成  => 使用轮询读取状态标志位
	// while (IRQ == 1)
	// 	;										 // 等待发送完成

	state = Int_SI24R1_Read_Reg(STATUS); // 读取状态寄存器的值
	while (((state & TX_DS) == 0) && ((state & MAX_RT) == 0))
	{
		state = Int_SI24R1_Read_Reg(STATUS);
	}

	Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + STATUS, state); // 清除TX_DS或MAX_RT中断标志
	if (state & MAX_RT)										// 达到最大重发次数
	{
		Int_SI24R1_Write_Reg(FLUSH_TX, 0xff); // 清除TX FIFO寄存器
		return 1;
	}
	if (state & TX_DS) // 发送完成
	{
		return 0;
	}
	return 1; // 发送失败
}

uint8_t si24r1_rx_buff[5] = {0};

/**
 * @brief SI24R1的初始化检测
 *
 * @return uint8_t  0:检测成功  1:检测失败
 */
uint8_t Int_SI24R1_Check(void)
{

	// 1. 测试SPI通信能够正常读写寄存器
	// 1.0 SI24R1芯片需要先读取一次  保证SPI正常之后再写入
	Int_SI24R1_Read_Buf(SI24R1_READ_REG + TX_ADDR, si24r1_rx_buff, TX_ADR_WIDTH);

	// 1.1 写入发送地址
	Int_SI24R1_Write_Buf(SI24R1_WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH);

	// 1.2 读取同样的数据
	Int_SI24R1_Read_Buf(SI24R1_READ_REG + TX_ADDR, si24r1_rx_buff, TX_ADR_WIDTH);

	for (uint8_t i = 0; i < TX_ADR_WIDTH; i++)
	{
		if (si24r1_rx_buff[i] != TX_ADDRESS[i])
		{
			return 1;
		}
	}
	return 0;
}

/**
 * @brief 硬件接口层SI24R1的初始化
 *
 */
void Int_SI24R1_Init(void)
{
	// 上电之后的芯片延迟 >100ms
	HAL_Delay(200);
	// 校验检测
	while (Int_SI24R1_Check() == 1)
	{
		// 每两次检测间隔10ms
		HAL_Delay(10);
	}

	// 设置默认的状态为接收模式  => 每次发送数据的时候  切换到发送状态 
	Int_SI24R1_RX_Mode();
	debug_printf("SI24R1 Init Success!\r\n");
}

③App_freertos_task.h

#ifndef __APP_FREERTOS_TASK__
#define __APP_FREERTOS_TASK__

#include "FreeRTOS.h"
#include "task.h"
#include "Com_debug.h"
#include "Com_config.h"
#include "Int_IP5305T.h"
#include "Int_motor.h"
#include "Int_led.h"
#include "Int_SI24R1.h"
/**
 * @brief 启动freeRTOS操作系统
 * 
 */
void App_freeRTOS_start(void);

#endif // __APP_FREERTOS_TASK__

④App_freertos_task.c

#include "App_freeRTOS_Task.h"

// STM32F103C8T6 => SRAM 20k  => 分配12K给操作系统
// 内存管理 => C语言中的结构体通常保存在堆中  不会自动垃圾回收  => 始终使用同一个结构体 不断循环使用

// 电机结构体
Motor_Struct left_top_motor = {.tim = &htim3, .channel = TIM_CHANNEL_1, .speed = 200};
Motor_Struct left_bottom_motor = {.tim = &htim4, .channel = TIM_CHANNEL_4, .speed = 200};
Motor_Struct right_top_motor = {.tim = &htim2, .channel = TIM_CHANNEL_2, .speed = 200};
Motor_Struct right_bottom_motor = {.tim = &htim1, .channel = TIM_CHANNEL_3, .speed = 200};

// LED结构体
LED_Struct left_top_led = {.port = LED1_GPIO_Port, .pin = LED1_Pin};
LED_Struct right_top_led = {.port = LED2_GPIO_Port, .pin = LED2_Pin};
LED_Struct right_bottom_led = {.port = LED3_GPIO_Port, .pin = LED3_Pin};
LED_Struct left_bottom_led = {.port = LED4_GPIO_Port, .pin = LED4_Pin};

// 表示当前连接状态
Remote_State remote_state = REMOTE_DISCONNECTED;

// 表示当前的飞行状态
Flight_State flight_state = NORMAL;

// 电源管理任务
void power_task(void *args);
// 最小推荐填写128 => 128*4 = 512B
#define POWER_TASK_STACK_SIZE 128
// 任务优先级 => 数值越小 优先级越小  => 最大4  => 不推荐使用最小优先级0
#define POWER_TASK_PRIORITY 4
TaskHandle_t power_task_handle;
// 定义任务的周期
#define POWER_TASK_PERIOD 10000

// 飞行控制任务
void flight_task(void *args);
#define FLIGHT_TASK_STACK_SIZE 128
#define FLIGHT_TASK_PRIORITY 3
TaskHandle_t flight_task_handle;
#define FLIGHT_TASK_PERIOD 6

// LED任务
void led_task(void *args);
#define LED_TASK_STACK_SIZE 128
#define LED_TASK_PRIORITY 1
TaskHandle_t led_task_handle;
#define LED_TASK_PERIOD 100

// 通讯任务
void com_task(void *args);
#define COM_TASK_STACK_SIZE 128
#define COM_TASK_PRIORITY 2
TaskHandle_t com_task_handle;
// 任务周期
#define COM_TASK_PERIOD 6

/**
 * @brief 启动freeRTOS操作系统
 *
 */
void App_freeRTOS_start(void)
{
    // 1. 创建电源管理任务
    xTaskCreate(power_task, "power_task", POWER_TASK_STACK_SIZE, NULL, POWER_TASK_PRIORITY, &power_task_handle);

    // 2. 创建飞行控制任务
    xTaskCreate(flight_task, "flight_task", FLIGHT_TASK_STACK_SIZE, NULL, FLIGHT_TASK_PRIORITY, &flight_task_handle);

    // 3. 创建LED灯任务
    xTaskCreate(led_task, "led_task", LED_TASK_STACK_SIZE, NULL, LED_TASK_PRIORITY, &led_task_handle);

    // 4. 创建通讯任务
    xTaskCreate(com_task, "com_task", COM_TASK_STACK_SIZE, NULL, COM_TASK_PRIORITY, &com_task_handle);

    // 5. 启动调度器
    vTaskStartScheduler();
}

void power_task(void *args)
{
    // 获取当前的基准时间
    TickType_t xLastWakeTime = xTaskGetTickCount();
    while (1)
    {

        // 每10s执行一次  =>  启动电源  避免自动关机
        vTaskDelayUntil(&xLastWakeTime, POWER_TASK_PERIOD);

        // 启动电源
        Int_IP5305T_start();
    }
}

void flight_task(void *args)
{
    // 获取当前的基准时间
    TickType_t xLastWakeTime = xTaskGetTickCount();
    while (1)
    {

        // 1. 设置电机的转速
        left_top_motor.speed = 400;

        // 2. 直接启动电机
        // Int_motor_start(&left_top_motor);
        // Int_motor_start(&right_bottom_motor);

        vTaskDelayUntil(&xLastWakeTime, FLIGHT_TASK_PERIOD);
    }
}

void led_task(void *args)
{

    // 获取当前的基准时间
    TickType_t xLastWakeTime = xTaskGetTickCount();
    uint8_t count = 0;
    while (1)
    {
        count++;
        // 前两个灯表示连接状态
        // 1. 判断当前连接状态
        if (remote_state == REMOTE_CONNECTED)
        {
            // 点亮前两个灯
            Int_led_turn_on(&left_top_led);
            Int_led_turn_on(&right_top_led);
        }
        else if (remote_state == REMOTE_DISCONNECTED)
        {
            // 关掉前两个灯
            Int_led_turn_off(&left_top_led);
            Int_led_turn_off(&right_top_led);
        }

        // 后两个灯表示飞行状态
        // 2. 判断当前飞行状态
        if (flight_state == IDLE)
        {
            // 灯慢闪烁 => 500ms亮 500ms灭
            if (count % 5 == 0)
            {
                // 循环5次  一次是100ms  5次等于500ms
                Int_led_toggle(&left_bottom_led);
                Int_led_toggle(&right_bottom_led);
            }
        }
        else if (flight_state == NORMAL)
        {
            // 灯快闪  =>  200ms亮 200ms灭
            if (count % 2 == 0)
            {
                // 循环2次  一次是100ms  2次等于200ms
                Int_led_toggle(&left_bottom_led);
                Int_led_toggle(&right_bottom_led);
            }
        }
        else if (flight_state == FIX_HEIGHT)
        {
            // 后两个灯常量
            Int_led_turn_on(&left_bottom_led);
            Int_led_turn_on(&right_bottom_led);
        }
        else if (flight_state == FAIL)
        {
            // 后两个灯灭
            Int_led_turn_off(&left_bottom_led);
            Int_led_turn_off(&right_bottom_led);
        }

        // 将count计数重置
        if (count == 10)
        {
            count = 0;
        }

        vTaskDelayUntil(&xLastWakeTime, LED_TASK_PERIOD);
    }
}

uint8_t com_data[TX_PLOAD_WIDTH] = {0};

void com_task(void *args)
{
    // 获取当前的基准时间
    TickType_t xLastWakeTime = xTaskGetTickCount();
    while (1)
    {
        // 1. 接收数据到缓冲区
        uint8_t res = Int_SI24R1_RxPacket(com_data);
        if (res == 0)
        {
            printf("%s\n", com_data);
        }
        
        // 6ms执行一次 接收数据的时间间隔应该等于发送数据的时间间隔
        vTaskDelayUntil(&xLastWakeTime, COM_TASK_PERIOD);
    }
}

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐