[STM32H5]【STM32 Nucleo-64测评】+测试I3C的动态连接机制

作为替代I2C的新总线方式,I3C依旧使用2个总线。但相对比I2C,I3C总线的特点如下:

1、支持总线上多个主设备
2、支持目标电压是3.3V、1.8V、1.2V,甚至更低。
3、支持软中断
4、支持热拔插
5、支持动态地址
6、支持4种通信模式(SDR、HDR-DDR、HDR-TSL、HDR-TSP)


 

其中。支持动态地址这一点,就很好。以往使用的I2C设备,基本上都是地址固定的。比如常见的0.96英寸的OLED屏,就是固定使用0x3C地址的。动态分配地址,意味着,在同一个总线了,可以同时接入相同的I3C设备,而不用担心地址冲突导致的通讯失败。作为体验,这次我使用STM32H533中的两个I3C外设,实现动态连接、收发数据。其实,只能使用自身的外设测试I3C,也是因为我手里没有其它可用的I3C设备。




 

因为是向下兼容的,虽然依旧是使用2根线完成的通讯,I3C使用了更为复杂的通讯协议,由于协议内容很多,我也是在学习中,这里就不废话了。直接上测试程序测试。

本次测试使用CubeIDE作为开发工具,根据STM32H533开发板的电路图及它本身的特点,使用PB6、PB7作为第一组I3C设备,PC6、PC7作为第二组I3C设备。

在主程序中,不断检查开发板上的用户按钮(占用PC13),以及检查I3C纵向上是否设备要求连接。当按钮按下的时候,程序控制从I3C设备发出连接请求。当主I3C设备在收到连接请求后,会开始分配动态地址(这个地址是你自己乐意随意设置的),并建立热连接。

实测结果很不错,很容易就建立起动态连接了。测试程序没有使用串口输出调试信息,而是使用的OLED输出调试结果。

没有按下用户按钮时的状态:
 


按下用户后的状态:


 





 

可以看到,在动态完成连接后,主设备I3C1给I3C2分配了一个地址50,就是0x32。这个地址使我们预先设置好,让I3C1分配给其他设备的地址之一。

    // 设备1
    TargetDesc_TypeDef TargetDesc1 = { "TARGET_ID1", DEVICE_ID1, 0x0000000000000000, 0x00, TARGET1_DYN_ADDR, };


    // 设备2
    TargetDesc_TypeDef TargetDesc2 = { "TARGET_ID2", DEVICE_ID2, 0x0000000000000000, 0x00, TARGET2_DYN_ADDR, };


    // 目标描述符数组
    TargetDesc_TypeDef *aTargetDesc[2] = {
    &TargetDesc1, /* DEVICE_ID1 */
    &TargetDesc2 /* DEVICE_ID2 */
};


// 从机请求地址分配的回调函数
void HAL_I3C_TgtReqDynamicAddrCallback(I3C_HandleTypeDef *hi3c, uint64_t targetPayload) {
    printf("从机请求地址分配。");
    GUI_ShowString(0, 16, (uint8_t*) "ReqAddr", 8, 1);


    /* Update Payload on aTargetDesc */
    aTargetDesc[uwTargetCount]->TARGET_BCR_DCR_PID = targetPayload;


    /* Send associated dynamic address */
    HAL_I3C_Ctrl_SetDynAddr(hi3c, aTargetDesc[uwTargetCount++]->DYNAMIC_ADDR);
}


主程序代码如下:

复制
/* USER CODE BEGIN Header */

/**

 ******************************************************************************

 * [url=home.php?mod=space&uid=288409]@file[/url]           : main.c

 * [url=home.php?mod=space&uid=247401]@brief[/url]          : Main program body

 ******************************************************************************

 * @attention

 *

 * Copyright (c) 2024 STMicroelectronics.

 * All rights reserved.

 *

 * This software is licensed under terms that can be found in the LICENSE file

 * in the root directory of this software component.

 * If no LICENSE file comes with this software, it is provided AS-IS.

 *

 ******************************************************************************

 */

/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/

#include "main.h"

#include "gui.h"

#include "oled.h"



#define I3C_IDX_FRAME_1         0U  /* Index of Frame 1 */

#define I3C_IDX_FRAME_2         1U  /* Index of Frame 2 */



I3C_HandleTypeDef hi3c1;

I3C_HandleTypeDef hi3c2;

TIM_HandleTypeDef htim2;



// 与帧上下文相关的上下文缓冲区包含通信的不同缓冲值

I3C_XferTypeDef aContextBuffers[2];



// DAA过程中检测到的目标数量

__IO uint32_t uwTargetCount = 0;



// I3C发送用的缓冲区

uint8_t aTxBuffer[0x0F];



// I3C接收用的缓冲区

uint8_t aRxBuffer[RXBUFFERSIZE];



// HAL用来计算通信的控制数据的缓冲区

uint32_t aControlBuffer[0xF];



/********************/

/* Target Descriptor */

/********************/

TargetDesc_TypeDef TargetDesc1 = { "TARGET_ID1",

DEVICE_ID1, 0x0000000000000000, 0x00,

TARGET1_DYN_ADDR, };



/********************/

/* Target Descriptor */

/********************/

TargetDesc_TypeDef TargetDesc2 = { "TARGET_ID2",

DEVICE_ID2, 0x0000000000000000, 0x00,

TARGET2_DYN_ADDR, };



// 目标描述符数组

TargetDesc_TypeDef *aTargetDesc[2] = { &TargetDesc1, /* DEVICE_ID1 */

&TargetDesc2 /* DEVICE_ID2 */

};



/* Variable to catch HotJoin event */

__IO uint32_t uwHotJoinRequested = 0;



/* Buffer that contain payload data, mean PID, BCR, DCR */

uint8_t aPayloadBuffer[64 * COUNTOF(aTargetDesc)];



// 设置CCC关联数据的数组

uint8_t aDISEC_data[1] = { 0x08 };



/* Variable to display reading data */

uint32_t uwDisplayDelay = 0U;

int16_t Temperature = 0;

int16_t aGyroscope[3] = { 0 };

int16_t aAccelerometer[3] = { 0 };



// 广播用CCC的描述符

I3C_CCCTypeDef aBroadcast_CCC[] = {

// 目标地址      CCC Value           CCC data + defbyte pointer  CCC size + defbyte    Direction        */

        { 0, Broadcast_DISEC, { aDISEC_data, 1 }, LL_I3C_DIRECTION_WRITE }, { 0,

                Broadcast_RSTDAA, { NULL, 0 }, LL_I3C_DIRECTION_WRITE }, };



UART_HandleTypeDef huart1;



void SystemClock_Config(void);

static void MX_GPIO_Init(void);

static void MX_I3C1_Init(void);

static void MX_I3C2_Init(void);

static void MX_USART1_UART_Init(void);

static void MX_TIM2_Init(void);

static void EXTI13_IRQHandler_Config(void);

void checkI3CDevice(void);



/**

 * @brief  The application entry point.

 * @retval int

 */

uint8_t flag = 0;



// 设备是否发出过I3C申请信号

uint8_t send_flag = 0;

int main(void) {

    // 复位所有外设,初始化Flash接口和Systick。

    HAL_Init();



    // 设置系统时钟

    SystemClock_Config();



    // 初始化相关外设

    MX_GPIO_Init();

    MX_I3C1_Init();

    MX_I3C2_Init();

    MX_USART1_UART_Init();

    MX_TIM2_Init();

    EXTI13_IRQHandler_Config();



    // 初始化OLED并显示信息

    OLED_Init();

    OLED_Clear(0);

    GUI_ShowString(0, 0, (uint8_t*) "Test STM32H533 I3C", 8, 1);



    HAL_Delay(100);



    // 允许hi3c1接受其他设备的动态连接请求(中断方式)

    if (HAL_I3C_ActivateNotification(&hi3c1, NULL, HAL_I3C_IT_HJIE) != HAL_OK) {

        /* Error_Handler() function is called when error occurs. */

        Error_Handler();

    }



    while (1) {

        checkI3CDevice();



    }

}



// 检查是否存在I3C设备(由子设备发出请求,主设备响应后,分发地址)

void checkI3CDevice(void) {

    // 等待目标连接上

    while (uwHotJoinRequested == 0U) {

        // 为热连接启动监听

        if (send_flag == 0) {

            // 检查用户按钮是否按下

            if (HAL_GPIO_ReadPin(USER_BUTTON_GPIO_Port, USER_BUTTON_Pin) == 1) {

                // 由I3C2发出连接请求

                if (HAL_I3C_Tgt_HotJoinReq_IT(&hi3c2) != HAL_OK) {

                    Error_Handler();

                } else {

                    send_flag = 1;

                }

            }

        }

    }



    // 分配动态地址

    if (HAL_I3C_Ctrl_DynAddrAssign_IT(&hi3c1, I3C_ONLY_ENTDAA) != HAL_OK) {

        Error_Handler();

    }



    // 获取状态

    while (HAL_I3C_GetState(&hi3c1) != HAL_I3C_STATE_LISTEN) {



    }



    // 复位,等待捕捉其它I3C设备

    uwHotJoinRequested = 0;

}



/**

 * @brief System Clock Configuration

 * @retval None

 */

void SystemClock_Config(void) {

    RCC_OscInitTypeDef RCC_OscInitStruct = { 0 };

    RCC_ClkInitTypeDef RCC_ClkInitStruct = { 0 };



    /** Configure the main internal regulator output voltage

     */

    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);



    while (!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {

    }



    /** Initializes the RCC Oscillators according to the specified parameters

     * in the RCC_OscInitTypeDef structure.

     */

    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_CSI;

    RCC_OscInitStruct.CSIState = RCC_CSI_ON;

    RCC_OscInitStruct.CSICalibrationValue = RCC_CSICALIBRATION_DEFAULT;

    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;

    RCC_OscInitStruct.PLL.PLLSource = RCC_PLL1_SOURCE_CSI;

    RCC_OscInitStruct.PLL.PLLM = 1;

    RCC_OscInitStruct.PLL.PLLN = 50;

    RCC_OscInitStruct.PLL.PLLP = 2;

    RCC_OscInitStruct.PLL.PLLQ = 2;

    RCC_OscInitStruct.PLL.PLLR = 2;

    RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1_VCIRANGE_2;

    RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1_VCORANGE_WIDE;

    RCC_OscInitStruct.PLL.PLLFRACN = 0;

    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {

        Error_Handler();

    }



    /** Initializes the CPU, AHB and APB buses clocks

     */

    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK

            | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2 | RCC_CLOCKTYPE_PCLK3;

    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;

    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;

    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;

    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

    RCC_ClkInitStruct.APB3CLKDivider = RCC_HCLK_DIV1;



    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) {

        Error_Handler();

    }

}



/**

 * @brief I3C1 Initialization Function

 * @param None

 * @retval None

 */

static void MX_I3C1_Init(void) {



    I3C_FifoConfTypeDef sFifoConfig = { 0 };

    I3C_CtrlConfTypeDef sCtrlConfig = { 0 };



    hi3c1.Instance = I3C1;

    hi3c1.Mode = HAL_I3C_MODE_CONTROLLER;

    hi3c1.Init.CtrlBusCharacteristic.SDAHoldTime = HAL_I3C_SDA_HOLD_TIME_1_5;

    hi3c1.Init.CtrlBusCharacteristic.WaitTime = HAL_I3C_OWN_ACTIVITY_STATE_0;

    hi3c1.Init.CtrlBusCharacteristic.SCLPPLowDuration = 0x09;

    hi3c1.Init.CtrlBusCharacteristic.SCLI3CHighDuration = 0x09;

    hi3c1.Init.CtrlBusCharacteristic.SCLODLowDuration = 0x59;

    hi3c1.Init.CtrlBusCharacteristic.SCLI2CHighDuration = 0x00;

    hi3c1.Init.CtrlBusCharacteristic.BusFreeDuration = 0x32;

    hi3c1.Init.CtrlBusCharacteristic.BusIdleDuration = 0xf8;

    if (HAL_I3C_Init(&hi3c1) != HAL_OK) {

        Error_Handler();

    }



    /** Configure FIFO

     */

    sFifoConfig.RxFifoThreshold = HAL_I3C_RXFIFO_THRESHOLD_1_4;

    sFifoConfig.TxFifoThreshold = HAL_I3C_TXFIFO_THRESHOLD_1_4;

    sFifoConfig.ControlFifo = HAL_I3C_CONTROLFIFO_DISABLE;

    sFifoConfig.StatusFifo = HAL_I3C_STATUSFIFO_DISABLE;

    if (HAL_I3C_SetConfigFifo(&hi3c1, &sFifoConfig) != HAL_OK) {

        Error_Handler();

    }



    /** Configure controller

     */

    sCtrlConfig.DynamicAddr = 0;

    sCtrlConfig.StallTime = 0x00;

    sCtrlConfig.HotJoinAllowed = ENABLE;

    sCtrlConfig.ACKStallState = DISABLE;

    sCtrlConfig.CCCStallState = DISABLE;

    sCtrlConfig.TxStallState = DISABLE;

    sCtrlConfig.RxStallState = DISABLE;

    sCtrlConfig.HighKeeperSDA = DISABLE;

    if (HAL_I3C_Ctrl_Config(&hi3c1, &sCtrlConfig) != HAL_OK) {

        Error_Handler();

    }

}



/**

 * @brief I3C2 Initialization Function

 * @param None

 * @retval None

 */

static void MX_I3C2_Init(void) {



    I3C_FifoConfTypeDef sFifoConfig = { 0 };

    I3C_TgtConfTypeDef sTgtConfig = { 0 };



    hi3c2.Instance = I3C2;

    hi3c2.Mode = HAL_I3C_MODE_TARGET;

    hi3c2.Init.TgtBusCharacteristic.BusAvailableDuration = 0xf8;

    if (HAL_I3C_Init(&hi3c2) != HAL_OK) {

        Error_Handler();

    }



    /** Configure FIFO

     */

    sFifoConfig.RxFifoThreshold = HAL_I3C_RXFIFO_THRESHOLD_1_4;

    sFifoConfig.TxFifoThreshold = HAL_I3C_TXFIFO_THRESHOLD_1_4;

    sFifoConfig.ControlFifo = HAL_I3C_CONTROLFIFO_DISABLE;

    sFifoConfig.StatusFifo = HAL_I3C_STATUSFIFO_DISABLE;



    if (HAL_I3C_SetConfigFifo(&hi3c2, &sFifoConfig) != HAL_OK) {

        Error_Handler();

    }



    /** Configure Target

     */

    sTgtConfig.Identifier = 0xC7;

    sTgtConfig.MIPIIdentifier = DEVICE_ID2;

    sTgtConfig.CtrlRoleRequest = DISABLE;

    sTgtConfig.HotJoinRequest = ENABLE;

    sTgtConfig.IBIRequest = DISABLE;

    sTgtConfig.IBIPayload = DISABLE;

    sTgtConfig.IBIPayloadSize = HAL_I3C_PAYLOAD_EMPTY;

    sTgtConfig.MaxReadDataSize = 0xFF;

    sTgtConfig.MaxWriteDataSize = 0xFF;

    sTgtConfig.CtrlCapability = DISABLE;

    sTgtConfig.GroupAddrCapability = DISABLE;

    sTgtConfig.DataTurnAroundDuration = HAL_I3C_TURNAROUND_TIME_TSCO_LESS_12NS;

    sTgtConfig.MaxReadTurnAround = 0;

    sTgtConfig.MaxDataSpeed = HAL_I3C_GETMXDS_FORMAT_1;

    sTgtConfig.MaxSpeedLimitation = DISABLE;

    sTgtConfig.HandOffActivityState = HAL_I3C_HANDOFF_ACTIVITY_STATE_0;

    sTgtConfig.HandOffDelay = DISABLE;

    sTgtConfig.PendingReadMDB = DISABLE;

    if (HAL_I3C_Tgt_Config(&hi3c2, &sTgtConfig) != HAL_OK) {

        Error_Handler();

    }



}



/**

 * @brief TIM2 Initialization Function

 * @param None

 * @retval None

 */

static void MX_TIM2_Init(void) {



    TIM_ClockConfigTypeDef sClockSourceConfig = { 0 };

    TIM_MasterConfigTypeDef sMasterConfig = { 0 };



    /* USER CODE BEGIN TIM2_Init 1 */



    /* USER CODE END TIM2_Init 1 */

    htim2.Instance = TIM2;

    htim2.Init.Prescaler = 0;

    htim2.Init.CounterMode = TIM_COUNTERMODE_UP;

    htim2.Init.Period = 100000;   // 100MHz:1mS



    htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

    htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;

    if (HAL_TIM_Base_Init(&htim2) != HAL_OK) {

        Error_Handler();

    }

    sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;

    if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) {

        Error_Handler();

    }

    sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;

    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE;

    if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig)

            != HAL_OK) {

        Error_Handler();

    }



    // 允许Timer2中断

    HAL_TIM_Base_Start_IT(&htim2);



    HAL_NVIC_EnableIRQ(TIM2_IRQn);



}

/**

 * @brief USART1 Initialization Function

 * @param None

 * @retval None

 */

static void MX_USART1_UART_Init(void) {



    huart1.Instance = USART1;

    huart1.Init.BaudRate = 115200;

    huart1.Init.WordLength = UART_WORDLENGTH_8B;

    huart1.Init.StopBits = UART_STOPBITS_1;

    huart1.Init.Parity = UART_PARITY_NONE;

    huart1.Init.Mode = UART_MODE_TX_RX;

    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;

    huart1.Init.OverSampling = UART_OVERSAMPLING_16;

    huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;

    huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;

    huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;

    if (HAL_UART_Init(&huart1) != HAL_OK) {

        Error_Handler();

    }

    if (HAL_UARTEx_SetTxFifoThreshold(&huart1, UART_TXFIFO_THRESHOLD_1_8)

            != HAL_OK) {

        Error_Handler();

    }

    if (HAL_UARTEx_SetRxFifoThreshold(&huart1, UART_RXFIFO_THRESHOLD_1_8)

            != HAL_OK) {

        Error_Handler();

    }

    if (HAL_UARTEx_DisableFifoMode(&huart1) != HAL_OK) {

        Error_Handler();

    }

}



/**

 * @brief GPIO Initialization Function

 * @param None

 * @retval None

 */

static void MX_GPIO_Init(void) {

    GPIO_InitTypeDef GPIO_InitStruct = { 0 };



    /* GPIO Ports Clock Enable */

    __HAL_RCC_GPIOC_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();

    __HAL_RCC_GPIOB_CLK_ENABLE();



    /*Configure GPIO pin Output Level */

    HAL_GPIO_WritePin(USER_LED_GPIO_Port, USER_LED_Pin, GPIO_PIN_RESET);



    /*Configure GPIO pin Output Level */

    HAL_GPIO_WritePin(GPIOA, OLED_SCL_Pin | OLED_SDA_Pin, GPIO_PIN_SET);



    // 设置用户按钮使用的GPIO口

    GPIO_InitStruct.Pin = USER_BUTTON_Pin;

    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;

    GPIO_InitStruct.Pull = GPIO_NOPULL;

    HAL_GPIO_Init(USER_BUTTON_GPIO_Port, &GPIO_InitStruct);



    // 设置用户LED按钮使用的GPIO口

    GPIO_InitStruct.Pin = USER_LED_Pin;

    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

    GPIO_InitStruct.Pull = GPIO_NOPULL;

    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

    HAL_GPIO_Init(USER_LED_GPIO_Port, &GPIO_InitStruct);



    // 设置OLED使用的接口(模拟方式)

    GPIO_InitStruct.Pin = OLED_SCL_Pin | OLED_SDA_Pin;

    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

    GPIO_InitStruct.Pull = GPIO_PULLUP;

    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);



}



/**

 * @brief 从机请求地址分配的回调函数

 * @par Called functions

 * - HAL_I3C_TgtReqDynamicAddrCallback()

 * - HAL_I3C_Ctrl_SetDynamicAddress()

 * @retval None

 */

void HAL_I3C_TgtReqDynamicAddrCallback(I3C_HandleTypeDef *hi3c,

        uint64_t targetPayload) {

    printf("从机请求地址分配。");

    GUI_ShowString(0, 16, (uint8_t*) "ReqAddr", 8, 1);



    /* Update Payload on aTargetDesc */

    aTargetDesc[uwTargetCount]->TARGET_BCR_DCR_PID = targetPayload;



    /* Send associated dynamic address */

    HAL_I3C_Ctrl_SetDynAddr(hi3c, aTargetDesc[uwTargetCount++]->DYNAMIC_ADDR);

}



/**

 * @brief  控制器完成动态地址的分配的回调函数

 * @param  hi3c : [IN] 包含配置信息的结构体.

 * @retval None

 */

void HAL_I3C_CtrlDAACpltCallback(I3C_HandleTypeDef *hi3c) {

    printf("完成动态地址的分配。");

    GUI_ShowString(60, 16, (uint8_t*) "Addr OK", 8, 1);

}



/**

 * @brief 收到连接请求后代额回调函数.

 * @par Called functions

 * - HAL_I3C_NotifyCallback()

 * @retval None

 */

void HAL_I3C_NotifyCallback(I3C_HandleTypeDef *hi3c, uint32_t eventId) {

    if ((eventId & EVENT_ID_HJ) == EVENT_ID_HJ) {

        HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);



        // 建立收到连接请求的标志

        printf("收到连接请求!");

        GUI_ShowString(0, 8, (uint8_t*) "Notify", 8, 1);

        uwHotJoinRequested = 1;



    }

}



/**

 * @brief 从机(I3C2)连接成功的回调函数.

 *        函数目的是为了检查热连接过程是否完成

 * @par Called functions

 * - HAL_I3C_TgtHotJoinCallback()

 * @retval None

 */

void HAL_I3C_TgtHotJoinCallback(I3C_HandleTypeDef *hi3c, uint8_t dynamicAddress) {

    // 从机连上

    GUI_ShowString(0, 24, (uint8_t*) "Target Addr=", 8, 1);

    GUI_ShowNum(100, 24, dynamicAddress, 2, 8, 1);

    printf("Slave is OK! Address=%d", dynamicAddress);

}



/**

 * @brief  This function is executed in case of error occurrence.

 * @retval None

 */

void Error_Handler(void) {

    /* USER CODE BEGIN Error_Handler_Debug */

    /* User can add his own implementation to report the HAL error return state */

    __disable_irq();

    while (1) {

    }

    /* USER CODE END Error_Handler_Debug */

}



// 定时器2的溢出中断回调函数

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {

    BSP_LED_Toggle(LED2);

}



/* USER CODE BEGIN 4 */

/**

 * @brief  Configures EXTI line 13 (connected to PC.13 pin) in interrupt mode

 * @param  None

 * @retval None

 */

static void EXTI13_IRQHandler_Config(void) {

    GPIO_InitTypeDef GPIO_InitStructure;



    /* Enable GPIOC clock */

    __HAL_RCC_GPIOC_CLK_ENABLE();



    /* Configure PC.13 pin as input floating */

    GPIO_InitStructure.Mode = GPIO_MODE_IT_RISING_FALLING; //GPIO_MODE_IT_FALLING;



    GPIO_InitStructure.Pull = GPIO_NOPULL;

    GPIO_InitStructure.Pin = BUTTON_USER_PIN;

    HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);



    /* Enable and set line 13 Interrupt to the lowest priority */

    HAL_NVIC_SetPriority(EXTI13_IRQn, 2, 0);

    HAL_NVIC_EnableIRQ(EXTI13_IRQn);

}



void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin) {

    // 判断是不是来自PC13的

    if (GPIO_Pin == BUTTON_USER_PIN) {

        /* Toggle LED2 */

        BSP_LED_On(LED2);

    }

}



void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin) {

    // 判断是不是来自PC13的

    if (GPIO_Pin == BUTTON_USER_PIN) {

        /* Toggle LED2 */

        BSP_LED_Off(LED2);

    }

}



#ifdef  USE_FULL_ASSERT

/**

  * @brief  Reports the name of the source file and the source line number

  *         where the assert_param error has occurred.

  * @param  file: pointer to the source file name

  * @param  line: assert_param error line source number

  * @retval None

  */

void assert_failed(uint8_t *file, uint32_t line)

{

  /* USER CODE BEGIN 6 */

  /* User can add his own implementation to report the file name and line number,

     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  /* USER CODE END 6 */

}

#endif /* USE_FULL_ASSERT */


---------------------
作者:suncat0504
链接:https://bbs.21ic.com/icview-3392508-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值